////
////
////
////
//// **Tip:** Hover the links for short summaries!
////
//// #### Starting apps
//// [application](#application "Create a Lustre application with subscriptions"),
//// [component](#component "Create a Lustre component with subscriptions"),
//// [script](#script "Inline the server component runtime as a script tag")
////
//// #### Making subscriptions
//// [none](#none "A subscription that never fires"),
//// [from](#from "Build a subscription from an arbitrary setup callback"),
//// [element](#element "Build a subscription with access to the root element"),
//// [batch](#batch "Combine multiple subscriptions into one"),
//// [dep](#dep "Wrap a value as a subscription dependency"),
//// [map](#map "Transform the messages a subscription dispatches"),
//// [watch](#watch "Run a side effect whenever dependencies change")
////
//// #### Keyboard
//// [on_key_press](#on_key_press "Subscribe to keypress events"),
//// [on_key_down](#on_key_down "Subscribe to keydown events"),
//// [on_key_up](#on_key_up "Subscribe to keyup events")
////
//// #### Pointer
//// [on_click](#on_click "Subscribe to click events"),
//// [on_pointer_move](#on_pointer_move "Subscribe to pointer move events"),
//// [on_pointer_down](#on_pointer_down "Subscribe to pointer down events"),
//// [on_pointer_up](#on_pointer_up "Subscribe to pointer up events"),
//// [on_pointer_cancel](#on_pointer_cancel "Subscribe to pointer cancel events"),
//// [on_wheel](#on_wheel "Subscribe to wheel events")
////
//// #### Browser
//// [window_size](#window_size "Dispatch the current window size"),
//// [screen_orientation](#screen_orientation "Dispatch the current screen orientation"),
//// [window_scroll](#window_scroll "Dispatch the current scroll position"),
//// [scroll_to](#scroll_to "Scroll the window to a position"),
//// [page_state](#page_state "Dispatch the current page lifecycle state"),
//// [window_hover](#window_hover "Dispatch the current window hover state"),
//// [title](#title "Update the document title"),
//// [meta](#meta "Upsert a document meta tag"),
//// [body_class](#body_class "Set a class on the body tag"),
//// [prevent_unload](#prevent_unload "Block the browser unload dialog")
////
//// #### DOM
//// [element_size](#element_size "Dispatch element dimensions on resize"),
//// [element_scroll](#element_scroll "Dispatch element scroll position"),
//// [element_scroll_to](#element_scroll_to "Scroll an element to a position"),
//// [scroll_into_view](#scroll_into_view "Scroll an element into view"),
//// [element_visible](#element_visible "Dispatch element viewport visibility")
//// [focus](#focus "Focus an element by CSS selector"),
//// [blur](#blur "Blur the currently focused element"),
//// [on](#on "Subscribe to a DOM event on a target element")
////
//// #### Component
//// [aria](#aria "Sync an ARIA property on the component host"),
//// [pseudo_state](#pseudo_state "Sync a CSS custom state on the component host"),
//// [form_value](#form_value "Sync the form-associated element value")
////
//// #### Preferences
//// [colour_scheme](#colour_scheme "Dispatch the current color scheme preference"),
//// [contrast](#contrast "Dispatch the current contrast preference"),
//// [reduced_motion](#reduced_motion "Dispatch the current motion preference"),
//// [breakpoints](#breakpoints "Dispatch the active breakpoint from a list"),
//// [tailwind_breakpoints](#tailwind_breakpoints "Dispatch the active breakpoint using the Tailwind definitions"),
//// [language](#language "Dispatch the current navigator language"),
//// [local_storage](#local_storage "Dispatch a local storage value and its changes"),
//// [session_storage](#session_storage "Dispatch a session storage value and its changes"),
//// [set_local_storage](#set_local_storage "Write a localStorage key"),
//// [set_session_storage](#set_session_storage "Write a sessionStorage key")
////
//// #### Time
//// [now](#now "Dispatch the current timestamp"),
//// [here](#here "Dispatch the current browser timezone offset"),
//// [after](#after "Dispatch a message after a delay"),
//// [every](#every "Dispatch a message on a repeating interval"),
//// [on_idle](#on_idle "Dispatch a message when the user stops interacting with the page for some time")
////
//// #### Connections
//// [online](#online "Dispatch the current network status"),
//// [server_sent_events](#server_sent_events "Subscribe to a Server-Sent Events stream"),
//// [websocket](#websocket "Subscribe to a WebSocket connection"),
//// [websocket_send](#websocket_send "Send a frame over a WebSocket connection")
////
//// #### Advanced
//// [init](#init "Run the application init function and start subscriptions"),
//// [update](#update "Handle a message in the subscription runtime"),
//// [view](#view "Render the application view with the subscription runtime")
//// [remote](#remote "Build a subscription that runs on the server component client"),
//// [command](#command "Dispatch a browser command via the off_topic client runtime"),
//// [watching](#watching "Add dependencies to a subscription"),
//// [including](#including "Specify which event fields to include in a remote subscription"),
//// [throttle](#throttle "Limit how often a subscription fires"),
//// [delay](#delay "Delay dispatching after the last event in a burst"),
//// [root](#root "CSS selector for the component mount point")
import gleam/bool
import gleam/dynamic/decode.{type Decoder, type Dynamic}
import gleam/float
import gleam/int
import gleam/json.{type Json}
import gleam/list
import gleam/option.{type Option, None, Some}
import gleam/time/duration.{type Duration}
import gleam/time/timestamp.{type Timestamp}
import lustre.{type App}
import lustre/attribute
import lustre/effect.{type Effect}
import lustre/element.{type Element}
import lustre/element/html
import off_topic/component
import off_topic/internal/commands
import off_topic/internal/runtime
import off_topic/internal/subscriptions
// -- FUNDAMENTALS ------------------------------------------------------------
/// An active listener that dispatches messages to your Lustre application.
///
/// Build subscriptions with the functions in this module and return them from
/// your application's `subscriptions` callback. Use [batch](#batch) to combine
/// multiple subscriptions, and [none](#none) to return an empty one.
pub type Subscription(message) =
runtime.Subscription(message)
/// An opaque value off_topic uses to detect when a subscription's inputs have
/// changed and it needs to be restarted.
///
/// Create one with [dep](#dep).
pub type Dependency =
runtime.Dependency
/// The subscription runtime's wrapper around your application model.
///
/// Use with [init](#init), [update](#update), and [view](#view) when wiring
/// up off_topic manually instead of through [application](#application).
pub type Model(model, message) =
runtime.Model(model, message)
/// The subscription runtime's wrapper around your application message type.
///
/// Use with [init](#init), [update](#update), and [view](#view) when wiring
/// up off_topic manually instead of through [application](#application).
pub type Message(message) =
runtime.Message(message)
/// CSS selector for the component mount point.
///
/// Pass `root` as the `selector` argument to any element-scoped subscription
/// to target the Lustre component mount element.
///
/// See also: [target](#target), [element_size](#element_size),
/// [element_scroll](#element_scroll), [element_visible](#element_visible)
pub const root = ":scope"
// -- STARTING APPS -----------------------------------------------------------
/// Create a Lustre application with subscription support.
///
/// A drop-in replacement for `lustre.application` that adds a `subscriptions`
/// callback. The returned `App` is passed directly to `lustre.start` or
/// `lustre.start_server_component`.
///
/// See also: [component](#component), [init](#init), [update](#update), [view](#view)
pub fn application(
init init: fn(flags) -> #(model, Effect(message)),
update update: fn(model, message) -> #(model, Effect(message)),
subscriptions subscriptions: fn(model) -> Subscription(message),
view view: fn(model) -> Element(message),
) -> App(flags, Model(model, message), Message(message)) {
runtime.application(init, update, subscriptions, view)
}
/// Create a Lustre [component](https://hexdocs.pm/lustre/lustre/component.html)
/// that runs the off_topic subscription runtime. This is the component
/// equivalent of [application](#application).
///
/// If you're using component options, swap your import to `off_topic/component`,
/// offering the same API.
///
/// See also: [application](#application)
pub fn component(
init init: fn(Nil) -> #(model, Effect(message)),
update update: fn(model, message) -> #(model, Effect(message)),
subscriptions subscriptions: fn(model) -> Subscription(message),
view view: fn(model) -> Element(message),
options options: List(component.Option(message)),
) -> App(Nil, Model(model, message), Message(message)) {
runtime.component(init, update, subscriptions, view, options)
}
/// Inline the server component runtime as a `