//// //// //// //// //// **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 `