map : Sub(a), (a -> b) -> Sub(b)
Re-target a subscription to a parent message type. Note the mapped callback is a new box each render, which is fine: sub identity comes from the variant's parameters, never the callback.
:= [
Every({ ms : U32, on_tick : Box(I64 -> Box(msg)) }),
Keyboard({ event : Str, keys : List(Str), prevent_default : Bool, on_key : Box(KeyEvent -> Box(msg)) }),
PortListen({ name : Str, on_value : Box(Str -> Box(msg)) }),
UrlChanged({ on_change : Box(Str -> Box(msg)) }),
]
A subscription: a recurring event source declared as *data*, returned from
subscriptions and managed by the host. While a subscription stays in the
returned list it keeps firing; leaving it out of the list stops it, so
cancellation is by omission and nothing leaks. The callback is a real typed
function, boxed so the host can store and call it without knowing the app's
Msg layout.
Identity is the variant plus its parameters (for Every the interval, for
PortListen the port name). A model change that alters the parameters
stops the old source and starts a fresh one; re-declaring the same
identity keeps the running source and only swaps in the new callbacks
(which may capture new model state). Two subscriptions with identical
parameters share one underlying source (timer, document listener, port
registration), and each firing delivers every declared callback's message,
in declaration order.
Apps normally use the constructors in Time, Keyboard, Port and DOM
rather than these variants directly. Payloads are records so the host
reads named fields.
map : Sub(a), (a -> b) -> Sub(b)
Re-target a subscription to a parent message type. Note the mapped callback is a new box each render, which is fine: sub identity comes from the variant's parameters, never the callback.
port_listen : Str, (Str -> msg) -> Sub(msg)
url_changed : (Str -> msg) -> Sub(msg)
KeyEvent : {
key : Str,
code : Str,
ctrl : Bool,
shift : Bool,
alt : Bool,
meta : Bool,
repeat : Bool,
is_composing : Bool,
}
The keyboard event record delivered to key handlers, document-level
(the Keyboard module) and element-level (Attribute.on_key and
friends) alike; annotate handlers as Sub.KeyEvent. key is the
logical key ("a", "Enter", "Escape", ...): it follows the active
layout and modifiers, so Shift makes "a" arrive as "A". code is the
physical key ("KeyA", "Space", "ControlLeft", ...): it ignores both,
which is what layout-independent controls (say, WASD movement) want.
repeat is true on the auto-repeated firings of a held key; skip
those to react once per press. The four modifier flags say whether
that modifier was held when the event fired, so a Ctrl+S shortcut is
if e.ctrl and e.key == "s". is_composing is true while an IME
composition session is in progress (the browser reports such keydowns
as key "Process"); skip those to ignore the intermediate keystrokes
international text input is assembled from.