aboutsummaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/lustre.ffi.mjs290
-rw-r--r--src/lustre.gleam43
-rw-r--r--src/lustre/attribute.gleam44
-rw-r--r--src/lustre/cmd.gleam32
-rw-r--r--src/lustre/element.gleam20
-rw-r--r--src/lustre/event.gleam158
-rw-r--r--src/runtime.ffi.mjs1300
7 files changed, 1535 insertions, 352 deletions
diff --git a/src/lustre.ffi.mjs b/src/lustre.ffi.mjs
index b39db16..74923d1 100644
--- a/src/lustre.ffi.mjs
+++ b/src/lustre.ffi.mjs
@@ -1,201 +1,127 @@
-import * as Cmd from "./lustre/cmd.mjs";
-import * as React from "react";
-import * as ReactDOM from "react-dom/client";
-
-const Dispatcher = React.createContext(null);
-
-export const mount = (app, selector) => {
- const el = document.querySelector(selector);
-
- if (!el) {
- console.warn(
- [
- "[lustre] Oops, it looks like I couldnt find an element on the ",
- 'page matching the selector "' + selector + '".',
- "",
- "Hint: make sure you arent running your script before the rest of ",
- "the HTML document has been parsed! you can add the `defer` attribute ",
- "to your script tag to make sure that cant happen.",
- ].join("\n")
- );
-
- return Promise.reject();
+import { innerHTML, createTree } from "./runtime.ffi.mjs";
+import { Ok, Error, List } from "./gleam.mjs";
+import { Some, Option } from "../gleam_stdlib/gleam/option.mjs";
+
+// RUNTIME ---------------------------------------------------------------------
+
+///
+///
+export class App {
+ #root = null;
+ #state = null;
+ #queue = [];
+ #commands = [];
+ #willUpdate = false;
+ #didUpdate = false;
+
+ // These are the three functions that the user provides to the runtime.
+ #__init;
+ #__update;
+ #__render;
+
+ constructor(init, update, render) {
+ this.#__init = init;
+ this.#__update = update;
+ this.#__render = render;
}
- let dispatchRef = null;
- let dispatchPromise = new Promise((resolve) => (dispatchRef = resolve));
-
- ReactDOM.createRoot(el).render(
- React.createElement(
- React.StrictMode,
- null,
- React.createElement(
- React.forwardRef((_, ref) => {
- // When wrapped in `<React.StrictMode />` and when in development
- // mode, React will run effects (and some other hooks) twice to
- // help us debug potential issues that arise from impurity.
- //
- // This is a problem for our cmds because they are intentionally
- // impure. We can/should expect user code to be pure, but we want
- // to allow top-level impurity in the form of cmds.
- //
- // So we can keep the benefits of strict mode, we add an additional
- // bit of state to track whether we need to run the cmds we have or
- // not.
- const [shouldRunCmds, setShouldRunCmds] = React.useState(true);
- const [[state, cmds], dispatch] = React.useReducer(
- ([state, _], msg) => {
- // Every time we call the user's update function we'll get back a
- // new lot of cmds to run, so we need to set this flag to true to
- // let our `useEffect` know it can run them!
- setShouldRunCmds(true);
- return app.update(state, msg);
- },
- app.init
- );
-
- React.useImperativeHandle(ref, () => dispatch, [dispatch]);
- React.useEffect(() => {
- if (shouldRunCmds && cmds) {
- for (const cmd of Cmd.to_list(cmds)) {
- cmd(dispatch);
- }
-
- // Once we've performed the side effects, we'll toggle this flag
- // back to false so we don't run them again on subsequent renders
- // or during development.
- setShouldRunCmds(false);
- }
- }, [cmds, shouldRunCmds]);
-
- return React.createElement(
- Dispatcher.Provider,
- { value: dispatch },
- React.createElement(({ state }) => app.render(state), { state })
- );
- }),
- { ref: dispatchRef }
- )
- )
- );
-
- return dispatchPromise;
-};
+ start(selector = "body") {
+ if (this.#root) return this;
-// ELEMENTS --------------------------------------------------------------------
-
-//
-export const node = (tag, attributes, children) => {
- const dispatch = React.useContext(Dispatcher);
- const props = to_props(attributes, dispatch);
-
- try {
- return React.createElement(tag, props, ...children.toArray());
- } catch (_) {
- console.warn([
- "[lustre] Something went wrong while trying to render a node with the ",
- 'tag "' + tag + "\". To prevent a runtime crash, I'm going to render an ",
- "empty text node instead.",
- "",
- "Hint: make sure you arent trying to render a node with a tag that ",
- "is compatible with the renderer you are using. For example, you can't ",
- 'render a "div" node with the terminal renderer.',
- "",
- "If you think this might be a bug, please open an issue at ",
- "https://github.com/hayleigh-dot-dev/gleam-lustre/issues",
- ]);
- return "";
- }
-};
+ try {
+ this.#root = document.querySelector(selector);
+ } catch (_) {
+ return new Error(undefined);
+ }
-//
-export const stateful = (init, render) => {
- const [state, setState] = React.useState(init);
+ const [next, cmds] = this.#__init();
+ this.#state = next;
+ this.#commands = cmds[0].toArray();
+ this.#didUpdate = true;
- return React.createElement(() => render(state, setState));
-};
+ window.requestAnimationFrame(this.#tick.bind(this));
+ return new Ok((msg) => this.dispatch(msg));
+ }
-//
-export const text = (content) => content;
+ dispatch(msg) {
+ if (!this.#willUpdate) window.requestAnimationFrame(this.#tick.bind(this));
-//
-export const fragment = (children) => {
- return React.createElement(React.Fragment, {}, ...children.toArray());
-};
+ this.#queue.push(msg);
+ this.#willUpdate = true;
+ }
-//
-export const map = (element, f) =>
- React.createElement(() => {
- const dispatch = React.useContext(Dispatcher);
- const mappedDispatch = React.useCallback(
- (msg) => dispatch(f(msg)),
- [dispatch]
+ #render() {
+ const node = this.#__render(this.#state);
+ const tree = createTree(
+ map(node, (msg) => {
+ if (msg instanceof Some) this.dispatch(msg[0]);
+ })
);
- return React.createElement(
- Dispatcher.Provider,
- { value: mappedDispatch },
- React.createElement(element)
- );
- });
+ innerHTML(this.#root, tree);
+ }
-// HOOKS -----------------------------------------------------------------------
+ #tick() {
+ this.#flush();
+ this.#didUpdate && this.#render();
+ this.#willUpdate = false;
+ }
-export const useLustreInternalDispatch = () => {
- return React.useContext(Dispatcher);
-};
+ #flush(times = 0) {
+ if (this.#queue.length) {
+ while (this.#queue.length) {
+ const [next, cmds] = this.#__update(this.#state, this.#queue.shift());
-// UTILS -----------------------------------------------------------------------
-
-// This function takes a Gleam `List` of key/value pairs (in the form of a Gleam
-// tuple, which is in turn a JavaScript array) and converts it into a normal
-// JavaScript object.
-//
-export const to_object = (entries) => Object.fromEntries(entries.toArray());
-
-const capitalise = (s = "") => s[0].toUpperCase() + s.slice(1);
-const to_props = (attributes, dispatch) => {
- return attributes.toArray().reduce((props, attr) => {
- // The constructors for the `Attribute` type are not public in the
- // gleam source to prevent users from constructing them directly.
- // This has the unfortunate side effect of not letting us `instanceof`
- // the constructors to pattern match on them and instead we have to
- // rely on the structure to work out what kind of attribute it is.
- //
- if ("name" in attr && "value" in attr) {
- const prop =
- attr.name in props && typeof props[attr.name] === "string"
- ? props[attr.name] + " " + attr.value
- : attr.value;
-
- return { ...props, [attr.name]: prop };
+ this.#state = next;
+ this.#commands.concat(cmds[0].toArray());
+ }
+
+ this.#didUpdate = true;
}
- // This case handles `Event` variants.
- else if ("name" in attr && "handler" in attr) {
- const name = "on" + capitalise(attr.name);
- const handler = (e) => attr.handler(e, dispatch);
+ // Each update can produce commands which must now be executed.
+ while (this.#commands.length) this.#commands.shift()(this.dispatch);
- return { ...props, [name]: handler };
+ // Synchronous commands will immediately queue a message to be processed. If
+ // it is reasonable, we can process those updates too before proceeding to
+ // the next render.
+ if (this.#queue.length) {
+ times >= 5 ? console.warn(tooManyUpdates) : this.#flush(++times);
}
+ }
+}
- // This should Never Happen™️ but if it does we don't want everything
- // to explode, so we'll print a friendly error, ignore the attribute
- // and carry on as normal.
- //
- else {
- console.warn(
- [
- "[lustre] Oops, I'm not sure how to handle attributes with ",
- 'the type "' + attr.constructor.name + '". Did you try calling ',
- "this function from JavaScript by mistake?",
- "",
- "If not, it might be an error in lustre itself. Please open ",
- "an issue at https://github.com/hayleigh-dot-dev/gleam-lustre/issues",
- ].join("\n")
- );
-
- return props;
- }
- }, {});
+export const setup = (init, update, render) => new App(init, update, render);
+export const start = (app, selector = "body") => app.start(selector);
+
+// VDOM ------------------------------------------------------------------------
+
+export const node = (tag, attrs, children) =>
+ createTree(tag, Object.fromEntries(attrs.toArray()), children.toArray());
+export const text = (content) => content;
+export const attr = (key, value) => {
+ if (value instanceof List) return [key, value.toArray()];
+ if (value instanceof Option) return [key, value?.[0]];
+
+ return [key, value];
};
+export const on = (event, handler) => [`on${event}`, handler];
+export const map = (node, f) => ({
+ ...node,
+ attributes: Object.entries(node.attributes).reduce((attrs, [key, value]) => {
+ // It's safe to mutate the `attrs` object here because we created it at
+ // the start of the reduce: it's not shared with any other code.
+
+ // If the attribute is an event handler, wrap it in a function that
+ // transforms
+ if (key.startsWith("on") && typeof value === "function") {
+ attrs[key] = (e) => f(value(e));
+ } else {
+ attrs[key] = value;
+ }
+
+ return attrs;
+ }, {}),
+ childNodes: node.childNodes.map((child) => map(child, f)),
+});
+export const styles = (list) => Object.fromEntries(list.toArray());
diff --git a/src/lustre.gleam b/src/lustre.gleam
index 54f6c55..073d03b 100644
--- a/src/lustre.gleam
+++ b/src/lustre.gleam
@@ -2,9 +2,9 @@
// IMPORTS ---------------------------------------------------------------------
+import gleam/result
import lustre/cmd.{Cmd}
import lustre/element.{Element}
-import gleam/javascript/promise.{Promise}
// TYPES -----------------------------------------------------------------------
@@ -49,13 +49,7 @@ import gleam/javascript/promise.{Promise}
/// <small>Someone please PR the Gleam docs generator to fix the monospace font,
/// thanks! 💖</small>
///
-pub opaque type App(model, msg) {
- App(
- init: #(model, Cmd(msg)),
- update: Update(model, msg),
- render: Render(model, msg),
- )
-}
+pub external type App(model, msg)
pub type Error {
ElementNotFound
@@ -100,11 +94,11 @@ type Render(model, msg) =
/// ```
///
pub fn element(element: Element(msg)) -> App(Nil, msg) {
- let init = #(Nil, cmd.none())
+ let init = fn() { #(Nil, cmd.none()) }
let update = fn(_, _) { #(Nil, cmd.none()) }
let render = fn(_) { element }
- App(init, update, render)
+ application(init, update, render)
}
/// If you start off with a simple `[element`](#element) app, you may find
@@ -157,14 +151,14 @@ pub fn element(element: Element(msg)) -> App(Nil, msg) {
/// ```
///
pub fn simple(
- init: model,
+ init: fn() -> model,
update: fn(model, msg) -> model,
render: fn(model) -> Element(msg),
) -> App(model, msg) {
- let init = #(init, cmd.none())
+ let init = fn() { #(init(), cmd.none()) }
let update = fn(model, msg) { #(update(model, msg), cmd.none()) }
- App(init, update, render)
+ application(init, update, render)
}
/// An evolution of a [`simple`](#simple) app that allows you to return a
@@ -208,13 +202,12 @@ pub fn simple(
/// external fn set_timeout (f: fn () -> a, delay: Int) -> Nil
/// = "" "window.setTimeout"
///```
-pub fn application(
- init: #(model, Cmd(msg)),
+pub external fn application(
+ init: fn() -> #(model, Cmd(msg)),
update: Update(model, msg),
render: Render(model, msg),
-) -> App(model, msg) {
- App(init, update, render)
-}
+) -> App(model, msg) =
+ "./lustre.ffi.mjs" "setup"
// EFFECTS ---------------------------------------------------------------------
@@ -242,12 +235,16 @@ pub fn application(
/// function from your `main` (or elsewhere) you can get events into your Lustre
/// app from the outside world.
///
-pub fn start(app: App(model, msg), selector: String) -> Promise(fn(msg) -> Nil) {
- mount(app, selector)
+pub fn start(
+ app: App(model, msg),
+ selector: String,
+) -> Result(fn(msg) -> Nil, Error) {
+ start_(app, selector)
+ |> result.replace_error(ElementNotFound)
}
-external fn mount(
+external fn start_(
app: App(model, msg),
selector: String,
-) -> Promise(fn(msg) -> Nil) =
- "./lustre.ffi.mjs" "mount"
+) -> Result(fn(msg) -> Nil, Nil) =
+ "./lustre.ffi.mjs" "start"
diff --git a/src/lustre/attribute.gleam b/src/lustre/attribute.gleam
index bac3b0c..898e543 100644
--- a/src/lustre/attribute.gleam
+++ b/src/lustre/attribute.gleam
@@ -3,7 +3,6 @@
import gleam/dynamic.{Dynamic}
import gleam/int
import gleam/list
-import gleam/pair
import gleam/string
// TYPES -----------------------------------------------------------------------
@@ -11,48 +10,47 @@ import gleam/string
/// Attributes are attached to specific elements. They're either key/value pairs
/// or event handlers.
///
-pub opaque type Attribute(msg) {
- Attribute(name: String, value: Dynamic)
- Event(name: String, handler: fn(Dynamic, fn(msg) -> Nil) -> Nil)
-}
+pub external type Attribute(msg)
// CONSTRUCTORS ----------------------------------------------------------------
///
-pub fn attribute(name: String, value: any) -> Attribute(msg) {
- Attribute(name, dynamic.from(value))
-}
-
-///
-pub fn event(
- name: String,
- handler: fn(Dynamic, fn(msg) -> Nil) -> Nil,
-) -> Attribute(msg) {
- Event(name, handler)
-}
+/// Lustre does some work internally to convert common Gleam values into ones that
+/// make sense for JavaScript. Here are the types that are converted:
+///
+/// - `List(a)` -> `Array(a)`
+/// - `Some(a)` -> `a`
+/// - `None` -> `undefined`
+///
+pub external fn attribute(name: String, value: any) -> Attribute(msg) =
+ "../lustre.ffi.mjs" "attr"
// COMMON ATTRIBUTES -----------------------------------------------------------
///
pub fn style(properties: List(#(String, String))) -> Attribute(msg) {
- attribute("style", style_object(properties))
+ attribute("style", styles(properties))
}
-external fn style_object(properties: List(#(String, String))) -> Dynamic =
- "../lustre.ffi.mjs" "to_object"
+external fn styles(properties: List(#(String, String))) -> Dynamic =
+ "../lustre.ffi.mjs" "styles"
///
pub fn class(name: String) -> Attribute(msg) {
- attribute("className", name)
+ attribute("class", name)
}
///
pub fn classes(names: List(#(String, Bool))) -> Attribute(msg) {
attribute(
- "className",
+ "class",
names
- |> list.filter(pair.second)
- |> list.map(pair.first)
+ |> list.filter_map(fn(class) {
+ case class.1 {
+ True -> Ok(class.0)
+ False -> Error(Nil)
+ }
+ })
|> string.join(" "),
)
}
diff --git a/src/lustre/cmd.gleam b/src/lustre/cmd.gleam
index 2c1b019..251908f 100644
--- a/src/lustre/cmd.gleam
+++ b/src/lustre/cmd.gleam
@@ -9,8 +9,7 @@ import gleam/list
/// get information back into your program.
///
pub opaque type Cmd(action) {
- Cmd(fn(fn(action) -> Nil) -> Nil, Cmd(action))
- None
+ Cmd(List(fn(fn(action) -> Nil) -> Nil))
}
// CONSTRUCTORS ----------------------------------------------------------------
@@ -37,7 +36,7 @@ pub opaque type Cmd(action) {
/// ```
///
pub fn from(cmd: fn(fn(action) -> Nil) -> Nil) -> Cmd(action) {
- Cmd(cmd, None)
+ Cmd([cmd])
}
/// Typically our app's `update` function needs to return a tuple of
@@ -45,7 +44,7 @@ pub fn from(cmd: fn(fn(action) -> Nil) -> Nil) -> Cmd(action) {
/// can just return `none()`!
///
pub fn none() -> Cmd(action) {
- None
+ Cmd([])
}
// MANIPULATIONS ---------------------------------------------------------------
@@ -53,26 +52,13 @@ pub fn none() -> Cmd(action) {
///
///
pub fn batch(cmds: List(Cmd(action))) -> Cmd(action) {
- cmds
- |> list.flat_map(to_list)
- |> list.fold_right(None, fn(rest, cmd) { Cmd(cmd, rest) })
+ Cmd({
+ use b, Cmd(a) <- list.fold(cmds, [])
+ list.append(b, a)
+ })
}
pub fn map(cmd: Cmd(a), f: fn(a) -> b) -> Cmd(b) {
- case cmd {
- Cmd(cmd, next) ->
- Cmd(fn(dispatch) { cmd(fn(a) { dispatch(f(a)) }) }, map(next, f))
-
- None -> None
- }
-}
-
-// CONVERSIONS -----------------------------------------------------------------
-
-pub fn to_list(cmd: Cmd(action)) -> List(fn(fn(action) -> Nil) -> Nil) {
- case cmd {
- Cmd(cmd, next) -> [cmd, ..to_list(next)]
-
- None -> []
- }
+ let Cmd(l) = cmd
+ Cmd(list.map(l, fn(cmd) { fn(dispatch) { cmd(fn(a) { dispatch(f(a)) }) } }))
}
diff --git a/src/lustre/element.gleam b/src/lustre/element.gleam
index 85c6852..7a0cae7 100644
--- a/src/lustre/element.gleam
+++ b/src/lustre/element.gleam
@@ -23,6 +23,15 @@ pub external fn node(
) -> Element(msg) =
"../lustre.ffi.mjs" "node"
+// pub external fn stateful(
+// init: state,
+// render: fn(state, fn(state) -> Nil) -> Element(msg),
+// ) -> Element(msg) =
+// "../lustre.ffi.mjs" "stateful"
+
+// pub external fn fragment(children: List(Element(msg))) -> Element(msg) =
+// "../lustre.ffi.mjs" "fragment"
+
/// A stateful element is exactly what it sounds like: an element with local
/// encapsulated state! The `render` function we must provide is called with the
/// element's current state as well as a function to set a new state. Whenever
@@ -62,18 +71,9 @@ pub external fn node(
/// elements don't necessarily produce messages: calling `set_state` is a side
/// effect.
///
-pub external fn stateful(
- init: state,
- render: fn(state, fn(state) -> Nil) -> Element(msg),
-) -> Element(msg) =
- "../lustre.ffi.mjs" "stateful"
-
/// A fragment doesn't appear in the DOM, but allows us to treat a list of elements
/// as if it were a single one.
///
-pub external fn fragment(children: List(Element(msg))) -> Element(msg) =
- "../lustre.ffi.mjs" "fragment"
-
/// Render a Gleam string as an HTML text node.
///
pub external fn text(content: String) -> Element(msg) =
@@ -177,7 +177,7 @@ pub external fn text(content: String) -> Element(msg) =
/// If this feels like a lt of work... sometimes it is! Take a look at the docs
/// for [`stateful`](#stateful) elements to see how all this can be encapsulated.
///
-pub external fn map(element: fn() -> Element(a), f: fn(a) -> b) -> Element(b) =
+pub external fn map(element: Element(a), f: fn(a) -> b) -> Element(b) =
"../lustre.ffi.mjs" "map"
// CONSTRUCTING NODES ----------------------------------------------------------
diff --git a/src/lustre/event.gleam b/src/lustre/event.gleam
index 251b92a..0853c16 100644
--- a/src/lustre/event.gleam
+++ b/src/lustre/event.gleam
@@ -3,6 +3,7 @@
// IMPORTS ---------------------------------------------------------------------
import gleam/dynamic.{DecodeError, Dynamic}
+import gleam/option.{None, Option, Some}
import gleam/result
import lustre/attribute.{Attribute}
@@ -18,19 +19,19 @@ type Decoded(a) =
/// check those out first.
///
/// If you need to handle an event that isn't covered by the helper functions,
-/// then you can use `on` to attach a custom event handler. The callback receives
-/// a `Dynamic` representing the JavaScript event object, and a dispatch function
-/// you can use to send messages to the Lustre runtime.
+/// then you can use `on` to attach a custom event handler. The callback is given
+/// the event object as a `Dynamic`.
///
/// As a simple example, you can implement `on_click` like so:
///
/// ```gleam
+/// import gleam/option.{Some}
/// import lustre/attribute.{Attribute}
/// import lustre/event
///
/// pub fn on_click(msg: msg) -> Attribute(msg) {
-/// use _, dispatch <- event.on("click")
-/// dispatch(msg)
+/// use _ <- event.on("click")
+/// Some(msg)
/// }
/// ```
///
@@ -39,18 +40,19 @@ type Decoded(a) =
///
/// ```gleam
/// import gleam/dynamic
+/// import gleam/option.{None, Some}
+/// import gleam/result
/// import lustre/attribute.{Attribute}
/// import lustre/event
///
/// pub fn on_input(msg: fn(String) -> msg) -> Attribute(msg) {
/// use event, dispatch <- on("input")
-/// let decode_value = dynamic.field("target", dynamic.field("value", dynamic.string))
-/// let emit_value = fn(value) { dispatch(msg(value)) }
+/// let decode = dynamic.field("target", dynamic.field("value", dynamic.string))
///
-/// event
-/// |> decode_value
-/// |> result.map(emit_value)
-/// |> result.unwrap(Nil)
+/// case decode(event) {
+/// Ok(value) -> Some(msg(value))
+/// Error(_) -> None
+/// }
/// }
/// ```
///
@@ -61,93 +63,72 @@ type Decoded(a) =
/// Unlike the helpers in the rest of this module, it is possible to simply ignore
/// the dispatch function and not dispatch a message at all. In fact, we saw this
/// with the `on_input` example above: if we can't decode the event object, we
-/// simply return `Nil` and do nothing.
+/// simply return `None` and emit nothing.
///
-/// Beyond error handling, this can be used to perform side effects we don't need
+/// Beyond ignoring errors, this can be used to perform side effects we don't need
/// to observe in our main application loop, such as logging...
///
/// ```gleam
/// import gleam/io
+/// import gleam/option.{None}
/// import lustre/attribute.{Attribute}
/// import lustre/event
///
/// pub fn log_on_click(msg: String) -> Attribute(msg) {
-/// use _, _ <- event.on("click")
+/// use _ <- event.on("click")
/// io.println(msg)
+/// None
/// }
/// ```
///
-/// ...or calling `set_state` from a `stateful` Lustre element:
-///
-/// ```gleam
-/// import gleam/int
-/// import lustre/attribute.{Attribute}
-/// import lustre/element.{Element}
-/// import lustre/event
-///
-/// pub fn counter() -> Element(msg) {
-/// use state, set_state = lustre.stateful(0)
-///
-/// let decr = event.on("click", fn(_, _) { set_state(state - 1) })
-/// let incr = event.on("click", fn(_, _) { set_state(state + 1) })
-///
-/// element.div([], [
-/// element.button([decr], [element.text("-")]),
-/// element.text(int.to_string(state)),
-/// element.button([incr], [element.text("+")]),
-/// ])
-/// }
-/// ```
-///
-pub fn on(
+pub external fn on(
name: String,
- handler: fn(Dynamic, fn(msg) -> Nil) -> Nil,
-) -> Attribute(msg) {
- attribute.event(name, handler)
-}
+ handler: fn(Dynamic) -> Option(msg),
+) -> Attribute(msg) =
+ "../lustre.ffi.mjs" "on"
// MOUSE EVENTS ----------------------------------------------------------------
///
pub fn on_click(msg: msg) -> Attribute(msg) {
- use _, dispatch <- on("click")
- dispatch(msg)
+ use _ <- on("click")
+ Some(msg)
}
///
pub fn on_mouse_down(msg: msg) -> Attribute(msg) {
- use _, dispatch <- on("mouseDown")
- dispatch(msg)
+ use _ <- on("mousedown")
+ Some(msg)
}
///
pub fn on_mouse_up(msg: msg) -> Attribute(msg) {
- use _, dispatch <- on("mouseUp")
- dispatch(msg)
+ use _ <- on("mouseup")
+ Some(msg)
}
///
pub fn on_mouse_enter(msg: msg) -> Attribute(msg) {
- use _, dispatch <- on("mouseEnter")
- dispatch(msg)
+ use _ <- on("mouseenter")
+ Some(msg)
}
///
pub fn on_mouse_leave(msg: msg) -> Attribute(msg) {
- use _, dispatch <- on("mouseLeave")
- dispatch(msg)
+ use _ <- on("mouseleave")
+ Some(msg)
}
///
pub fn on_mouse_over(msg: msg) -> Attribute(msg) {
- use _, dispatch <- on("mouseOver")
- dispatch(msg)
+ use _ <- on("mouseover")
+ Some(msg)
}
///
pub fn on_mouse_out(msg: msg) -> Attribute(msg) {
- use _, dispatch <- on("mouseOut")
- dispatch(msg)
+ use _ <- on("mouseout")
+ Some(msg)
}
// KEYBOARD EVENTS -------------------------------------------------------------
@@ -156,79 +137,74 @@ pub fn on_mouse_out(msg: msg) -> Attribute(msg) {
/// current key being pressed.
///
pub fn on_keypress(msg: fn(String) -> msg) -> Attribute(msg) {
- use event, dispatch <- on("keyPress")
+ use event <- on("keypress")
- event
- |> dynamic.field("key", dynamic.string)
- |> result.map(msg)
- |> result.map(dispatch)
- |> result.unwrap(Nil)
+ case dynamic.field("key", dynamic.string)(event) {
+ Ok(key) -> Some(msg(key))
+ Error(_) -> None
+ }
}
/// Listens for key dow events on an element, and dispatches a message with the
/// current key being pressed.
///
pub fn on_keydown(msg: fn(String) -> msg) -> Attribute(msg) {
- use event, dispatch <- on("keyDown")
+ use event <- on("keydown")
- event
- |> dynamic.field("key", dynamic.string)
- |> result.map(msg)
- |> result.map(dispatch)
- |> result.unwrap(Nil)
+ case dynamic.field("key", dynamic.string)(event) {
+ Ok(key) -> Some(msg(key))
+ Error(_) -> None
+ }
}
/// Listens for key up events on an element, and dispatches a message with the
/// current key being released.
///
pub fn on_keyup(msg: fn(String) -> msg) -> Attribute(msg) {
- use event, dispatch <- on("keyUp")
+ use event <- on("keyup")
- event
- |> dynamic.field("key", dynamic.string)
- |> result.map(msg)
- |> result.map(dispatch)
- |> result.unwrap(Nil)
+ case dynamic.field("key", dynamic.string)(event) {
+ Ok(key) -> Some(msg(key))
+ Error(_) -> None
+ }
}
// FORM EVENTS -----------------------------------------------------------------
///
pub fn on_input(msg: fn(String) -> msg) -> Attribute(msg) {
- use event, dispatch <- on("change")
+ use event <- on("input")
- event
- |> value
- |> result.map(msg)
- |> result.map(dispatch)
- |> result.unwrap(Nil)
+ case value(event) {
+ Ok(val) -> Some(msg(val))
+ Error(_) -> None
+ }
}
pub fn on_check(msg: fn(Bool) -> msg) -> Attribute(msg) {
- use event, dispatch <- on("change")
+ use event <- on("change")
- event
- |> dynamic.field("target", dynamic.field("checked", dynamic.bool))
- |> result.map(msg)
- |> result.map(dispatch)
- |> result.unwrap(Nil)
+ case checked(event) {
+ Ok(val) -> Some(msg(val))
+ Error(_) -> None
+ }
}
pub fn on_submit(msg: msg) -> Attribute(msg) {
- use _, dispatch <- on("submit")
- dispatch(msg)
+ use _ <- on("submit")
+ Some(msg)
}
// FOCUS EVENTS ----------------------------------------------------------------
pub fn on_focus(msg: msg) -> Attribute(msg) {
- use _, dispatch <- on("focus")
- dispatch(msg)
+ use _ <- on("focus")
+ Some(msg)
}
pub fn on_blur(msg: msg) -> Attribute(msg) {
- use _, dispatch <- on("blur")
- dispatch(msg)
+ use _ <- on("blur")
+ Some(msg)
}
// DECODERS --------------------------------------------------------------------
diff --git a/src/runtime.ffi.mjs b/src/runtime.ffi.mjs
new file mode 100644
index 0000000..f4cf0d1
--- /dev/null
+++ b/src/runtime.ffi.mjs
@@ -0,0 +1,1300 @@
+// This module is vendored and lightly modified from the original diffhtml source
+// available at:
+//
+// https://github.com/tbranyen/diffhtml/
+//
+// You can read a copy of the original license, unchanged, at:
+//
+// https://github.com/tbranyen/diffhtml/blob/master/LICENSE
+//
+
+function t(e, t) {
+ var n = Object.keys(e);
+ if (Object.getOwnPropertySymbols) {
+ var r = Object.getOwnPropertySymbols(e);
+ t &&
+ (r = r.filter(function (t) {
+ return Object.getOwnPropertyDescriptor(e, t).enumerable;
+ })),
+ n.push.apply(n, r);
+ }
+ return n;
+}
+function n(e) {
+ for (var n = 1; n < arguments.length; n++) {
+ var r = null != arguments[n] ? arguments[n] : {};
+ n % 2
+ ? t(Object(r), !0).forEach(function (t) {
+ i(e, t, r[t]);
+ })
+ : Object.getOwnPropertyDescriptors
+ ? Object.defineProperties(e, Object.getOwnPropertyDescriptors(r))
+ : t(Object(r)).forEach(function (t) {
+ Object.defineProperty(e, t, Object.getOwnPropertyDescriptor(r, t));
+ });
+ }
+ return e;
+}
+function r(e, t) {
+ if (!(e instanceof t))
+ throw new TypeError("Cannot call a class as a function");
+}
+function a(e, t) {
+ for (var n = 0; n < t.length; n++) {
+ var r = t[n];
+ (r.enumerable = r.enumerable || !1),
+ (r.configurable = !0),
+ "value" in r && (r.writable = !0),
+ Object.defineProperty(e, r.key, r);
+ }
+}
+function o(e, t, n) {
+ return (
+ t && a(e.prototype, t),
+ n && a(e, n),
+ Object.defineProperty(e, "prototype", { writable: !1 }),
+ e
+ );
+}
+function i(e, t, n) {
+ return (
+ t in e
+ ? Object.defineProperty(e, t, {
+ value: n,
+ enumerable: !0,
+ configurable: !0,
+ writable: !0,
+ })
+ : (e[t] = n),
+ e
+ );
+}
+function s(e) {
+ return c(e) || d(e) || l(e) || f();
+}
+function c(e) {
+ if (Array.isArray(e)) return u(e);
+}
+function d(e) {
+ if (
+ ("undefined" != typeof Symbol && null != e[Symbol.iterator]) ||
+ null != e["@@iterator"]
+ )
+ return Array.from(e);
+}
+function l(e, t) {
+ if (e) {
+ if ("string" == typeof e) return u(e, t);
+ var n = Object.prototype.toString.call(e).slice(8, -1);
+ return (
+ "Object" === n && e.constructor && (n = e.constructor.name),
+ "Map" === n || "Set" === n
+ ? Array.from(e)
+ : "Arguments" === n ||
+ /^(?:Ui|I)nt(?:8|16|32)(?:Clamped)?Array$/.test(n)
+ ? u(e, t)
+ : void 0
+ );
+ }
+}
+function u(e, t) {
+ (null == t || t > e.length) && (t = e.length);
+ for (var n = 0, r = new Array(t); n < t; n++) r[n] = e[n];
+ return r;
+}
+function f() {
+ throw new TypeError(
+ "Invalid attempt to spread non-iterable instance.\nIn order to be iterable, non-array objects must have a [Symbol.iterator]() method."
+ );
+}
+function h(e, t) {
+ var n = String(e);
+ switch (t) {
+ case "boolean":
+ return "false" !== n;
+ case "string":
+ return n;
+ case "number":
+ return te(n, 10);
+ case "object":
+ return ne(n);
+ }
+}
+function v(e, t) {
+ var n =
+ arguments.length > 2 && void 0 !== arguments[2] ? arguments[2] : typeof t,
+ r = arguments.length > 3 ? arguments[3] : void 0,
+ a = ee.location,
+ o = ee.URLSearchParams,
+ i = void 0 !== o,
+ s = void 0 !== a,
+ c = i && s,
+ d = W.env;
+ if (r && e in r) return r[e];
+ var l = "DIFF_".concat(e.replace(/[^a-zA-Z0-9]/, ""));
+ if (c) {
+ var u = new o(a.search),
+ f = l.toLowerCase();
+ if (u.has(f)) return h(decodeURIComponent(String(u.get(f))), n);
+ }
+ var v = l.toUpperCase();
+ return d && v in W.env ? h(W.env[v.toUpperCase()], n) : t;
+}
+function p(e) {
+ for (
+ var t = arguments.length > 1 && void 0 !== arguments[1] ? arguments[1] : [],
+ n = 0;
+ n < e.length;
+ n++
+ ) {
+ var r = e[n];
+ r && r.rawNodeName === ve ? p(r.childNodes, t) : r && t.push(r);
+ }
+ return t;
+}
+function m(e, t, r) {
+ var a = null;
+ if (he.protected.has(e) || he.allocated.has(e)) a = e;
+ else if (!e || fe(e)) {
+ var o = e ? e.length : 0;
+ r = [];
+ for (var i = 0; i < o; i++) {
+ var c = e && !e[i];
+ c || (e && r.push(e[i]));
+ }
+ a = m(ve, null, r);
+ }
+ if (a) return a;
+ var d = "object" == typeof e,
+ l = e;
+ if (e && d && "ownerDocument" in l) {
+ if (l.nodeType === B.TEXT) {
+ var u = m(pe, l.nodeValue);
+ return X.set(u, l), u;
+ }
+ (t = {}), (r = []);
+ var f = l.attributes;
+ if (l.nodeType === B.ELEMENT && f && f.length)
+ for (var h = 0; h < f.length; h++) {
+ var v = f[h],
+ T = v.name,
+ g = v.value;
+ g === U.STR && T in l ? (t[T] = e[T]) : (t[T] = g);
+ }
+ if (l.nodeType === B.ELEMENT || l.nodeType === B.FRAGMENT) {
+ r = [];
+ for (var b = 0; b < l.childNodes.length; b++) {
+ var N = l.childNodes[b];
+ r.push(m(N));
+ }
+ }
+ return (
+ X.forEach(function (t, n) {
+ t === e && (a = n);
+ }),
+ (a = a || m(l.nodeName, t, r)),
+ (a.attributes = n(n({}, a.attributes), t)),
+ (a.childNodes = r),
+ X.set(a, l),
+ a
+ );
+ }
+ if (d) {
+ var y = e.rawNodeName,
+ E = e.nodeName,
+ w = e.nodeValue,
+ S = e.attributes,
+ O = e.childNodes,
+ k = e.children,
+ R = y || E,
+ C = m(R, S || null, k || O);
+ return w && (C.nodeValue = w), C;
+ }
+ for (
+ var M = arguments.length, A = new Array(M > 3 ? M - 3 : 0), x = 3;
+ x < M;
+ x++
+ )
+ A[x - 3] = arguments[x];
+ A.length && (r = [r].concat(A)), (a = ue.get());
+ var L = e === pe;
+ "string" == typeof e
+ ? ((a.rawNodeName = e), (a.nodeName = a.rawNodeName.toLowerCase()))
+ : ((a.rawNodeName = e), (a.nodeName = ve)),
+ (a.nodeValue = U.STR),
+ (a.key = U.STR),
+ (a.childNodes.length = 0),
+ (a.attributes = {});
+ var D = fe(t) || "object" != typeof t,
+ I = D ? t : r,
+ V = p(fe(I) ? I : [I]);
+ if (L) {
+ var j = V.join(U.STR);
+ return (a.nodeType = B.TEXT), (a.nodeValue = String(j)), a;
+ }
+ if (
+ (a.nodeName === ve
+ ? (a.nodeType = B.FRAGMENT)
+ : (a.nodeType = "#comment" === e ? B.COMMENT : B.ELEMENT),
+ I && V.length && (!t || !t.childNodes))
+ )
+ for (var _ = 0; _ < V.length; _++) {
+ var P = V[_];
+ if (fe(P)) {
+ var H;
+ (H = a.childNodes).push.apply(H, s(P));
+ } else {
+ if (!P) continue;
+ if (P.nodeType === B.FRAGMENT && "string" == typeof P.rawNodeName) {
+ var F;
+ (F = a.childNodes).push.apply(F, s(P.childNodes));
+ } else
+ P && "object" == typeof P
+ ? a.childNodes.push(m(P))
+ : a.childNodes.push(m(pe, null, P));
+ }
+ }
+ if (
+ t &&
+ "object" == typeof t &&
+ !fe(t) &&
+ ((a.attributes = n({}, t)), t.childNodes)
+ ) {
+ var z = "object" == typeof t.childNodes;
+ a.childNodes.push(z ? m(t.childNodes) : m("#text", t.childNodes));
+ }
+ return (
+ "script" === a.nodeName &&
+ a.attributes.src &&
+ (a.key = String(a.attributes.src)),
+ a.attributes && "key" in a.attributes && (a.key = String(a.attributes.key)),
+ Y.size &&
+ Y.forEach(function (e, t) {
+ (t = e(a)) && (a = m(t));
+ }),
+ a
+ );
+}
+function T(e) {
+ var t = e.mount,
+ n = e.input,
+ r = n,
+ a = ge++;
+ return v("collectMetrics", !1)
+ ? function (e) {
+ e = "[".concat(a, "] ").concat(e);
+ var n = t.host;
+ t && n
+ ? (e = "".concat(n.constructor.name, " ").concat(e))
+ : r &&
+ "function" == typeof r.rawNodeName &&
+ (e = "".concat(r.rawNodeName.name, " ").concat(e));
+ var o = "".concat(e, "-end");
+ if (Te.has(e)) {
+ var i = Te.get(e) || 0,
+ s = (performance.now() - i).toFixed(3);
+ Te.delete(e),
+ performance.mark(o),
+ performance.measure(
+ "".concat(me, " ").concat(e, " (").concat(s, "ms)"),
+ e,
+ o
+ );
+ } else Te.set(e, performance.now()), performance.mark(e);
+ }
+ : U.FUN;
+}
+function g(e) {
+ if ((be(e), e.childNodes.length))
+ for (var t = 0; t < e.childNodes.length; t++) g(e.childNodes[t]);
+}
+function b(e) {
+ if (e.childNodes.length)
+ for (var t = 0; t < e.childNodes.length; t++) b(e.childNodes[t]);
+ X.delete(e), Ne(e);
+}
+function N() {
+ ye.allocated.forEach(function (e) {
+ (e.attributes = {}),
+ (e.childNodes.length = 0),
+ ye.free.add(e),
+ ye.allocated.delete(e),
+ X.delete(e);
+ });
+}
+function y(e) {
+ var t = e.state,
+ n = e.state.isRendering;
+ t.measure("schedule"),
+ G.forEach(function (r) {
+ var a = r.activeTransaction && r.activeTransaction.mount,
+ o = e.mount;
+ a &&
+ o &&
+ r.isRendering &&
+ ((a.contains && a.contains(o)) || (o.contains && o.contains(a))
+ ? ((t = r), (n = !0))
+ : a === o && ((t = r), (n = !0)));
+ });
+ var r = t,
+ a = r.activeTransaction,
+ o = r.nextTransaction;
+ if (n) {
+ var i = e.tasks;
+ (t.nextTransaction = e), e.abort();
+ var s = (o && o.promise) || a.promise || Promise.resolve();
+ return (e.promise = s.then(function () {
+ return (
+ (e.aborted = !1),
+ (e.state.isRendering = !0),
+ (e.state.activeTransaction = e),
+ t.measure("schedule"),
+ Je.flow(e, i.slice(1))
+ );
+ }));
+ }
+ (t.isRendering = !0), (t.activeTransaction = e), t.measure("schedule");
+}
+function E(e) {
+ var t = e.mount,
+ n = e.input,
+ r = e.state.measure,
+ a = e.config,
+ o = a.inner ? "innerHTML" : "outerHTML";
+ r("should update");
+ var i = t;
+ if ("string" == typeof n && i[o] === n) return e.abort(!0);
+ r("should update");
+}
+function w(e) {
+ if (G.has(e)) {
+ var t = G.get(e),
+ n = t.mutationObserver,
+ r = t.oldTree;
+ n && n.disconnect(),
+ r &&
+ !X.has(r) &&
+ (K.forEach(function (e) {
+ return e(r);
+ }),
+ b(r)),
+ G.delete(e);
+ }
+ if (e) {
+ var a = e;
+ if (a.childNodes && a.childNodes.length)
+ for (var o = 0; o < a.childNodes.length; o++) w(a.childNodes[o]);
+ a.shadowRoot && w(a.shadowRoot),
+ X.forEach(function (e, t) {
+ e === a &&
+ (K.forEach(function (e) {
+ return e(t);
+ }),
+ b(t));
+ }),
+ ke(Se),
+ (Se = Oe(N));
+ }
+}
+function S(e) {
+ var t = e.state,
+ n = e.mount,
+ r = e.input,
+ a = e.config,
+ o = a.inner,
+ i = n;
+ t.mutationObserver && !t.isDirty
+ ? (t.isDirty = Boolean(t.mutationObserver.takeRecords().length))
+ : t.mutationObserver || (t.isDirty = !1),
+ (!t.isDirty && t.oldTree) ||
+ (w(i),
+ i.ownerDocument &&
+ t.mutationObserver &&
+ t.mutationObserver.observe(i, {
+ subtree: !0,
+ childList: !0,
+ attributes: !0,
+ characterData: !0,
+ }),
+ (t.oldTree = m(i)),
+ g(t.oldTree),
+ G.set(n, t));
+ var s = t.oldTree,
+ c = s.nodeName,
+ d = s.attributes;
+ e.newTree || (e.newTree = m(r));
+ var l = e.newTree;
+ if (!o && l.nodeType === B.FRAGMENT && t.oldTree.nodeType !== B.FRAGMENT) {
+ for (var u = [], f = 0; f < l.childNodes.length; f++) {
+ var h = l.childNodes[f];
+ (h.nodeType === B.TEXT && !h.nodeValue.trim()) || u.push(h);
+ }
+ 1 === u.length
+ ? (e.newTree = u[0])
+ : u.length > 1 && (e.newTree = m(l.childNodes));
+ }
+ e.oldTree = t.oldTree;
+ var v = e.oldTree,
+ p = e.newTree;
+ if (o && v && p) {
+ var T = "string" != typeof p.rawNodeName,
+ b = p.nodeType === B.FRAGMENT,
+ N = b && !T ? p.childNodes : p;
+ e.newTree = m(c, d, N);
+ }
+}
+function O(e, t) {
+ var n = arguments.length > 2 && void 0 !== arguments[2] ? arguments[2] : [],
+ r = arguments.length > 3 && void 0 !== arguments[3] ? arguments[3] : {},
+ a = arguments.length > 4 && void 0 !== arguments[4] ? arguments[4] : U.OBJ,
+ o = arguments.length > 5 ? arguments[5] : void 0;
+ e || (e = U.OBJ), t || (t = U.OBJ);
+ var i = r.svgElements,
+ s = void 0 === i ? new Set() : i,
+ c = e.nodeName,
+ d = t.nodeName,
+ l = e === U.OBJ || o,
+ u = "svg" === d || s.has(t),
+ f = null;
+ if (
+ ($.size &&
+ $.forEach(function (r) {
+ var o = r(e, t, a);
+ o && o === e ? (f = n) : !1 === o ? (f = !1) : o && (t = o);
+ }),
+ null !== f || !t)
+ )
+ return f;
+ if (d === Me) {
+ if (c === Me && e.nodeValue !== t.nodeValue)
+ return (
+ n.push(F.NODE_VALUE, e, t.nodeValue, e.nodeValue),
+ (e.nodeValue = t.nodeValue),
+ n
+ );
+ if (l) return n.push(F.NODE_VALUE, t, t.nodeValue, null), n;
+ }
+ var h = t.childNodes || [];
+ if (t.nodeType === B.ELEMENT) {
+ var v = l ? U.OBJ : e.attributes,
+ p = t.attributes || {};
+ for (var m in p) {
+ var T = p[m];
+ (m in v && v[m] === p[m]) ||
+ (l || (v[m] = T),
+ ((e && "script" === e.nodeName) ||
+ "script" !== t.nodeName ||
+ "type" !== m) &&
+ n.push(F.SET_ATTRIBUTE, l ? t : e, m, T));
+ }
+ if (!l)
+ for (var g in v)
+ g in p || (n.push(F.REMOVE_ATTRIBUTE, e, g), delete v[g]);
+ }
+ if (o) {
+ for (var b = 0; b < h.length; b++)
+ u && s.add(h[b]), O(null, h[b], n, r, a, !0);
+ return n;
+ }
+ for (var N = { old: new Map(), new: new Map() }, y = 0; y < Ce.length; y++) {
+ var E = Ce[y],
+ w = N[E],
+ S = arguments[y],
+ k = S && S.childNodes;
+ if (k && k.length)
+ for (var R = 0; R < k.length; R++) {
+ var C = k[R];
+ C.key && w.set(C.key, C);
+ }
+ }
+ for (
+ var M = e.childNodes || [], A = Re(h.length, M.length), x = 0;
+ x < A;
+ x++
+ ) {
+ var L = M && M[x],
+ D = h[x];
+ if (((u || (D && "svg" === D.nodeName)) && s.add(D), D))
+ if (L) {
+ var I = D.key,
+ V = L.key,
+ j = N.new.has(V),
+ _ = N.old.has(I);
+ if (V || I) {
+ if (!j && !_) {
+ M.splice(M.indexOf(L), 1, D),
+ O(null, D, n, r, a, !0),
+ n.push(F.REPLACE_CHILD, D, L),
+ (x -= 1);
+ continue;
+ }
+ if (!j) {
+ n.push(F.REMOVE_CHILD, L), M.splice(M.indexOf(L), 1), (x -= 1);
+ continue;
+ }
+ if (I !== V) {
+ var P = D;
+ I && _ ? ((P = N.old.get(I)), M.splice(M.indexOf(P), 1)) : (P = D),
+ O(null, P, n, r, a, !0),
+ n.push(F.INSERT_BEFORE, e, P, L),
+ M.splice(x, 0, P);
+ continue;
+ }
+ }
+ var H = L.nodeName === D.nodeName,
+ z = O(L, D, n, r, a, !H);
+ if (!1 !== z) {
+ if (!H) {
+ M[x] = D;
+ var J = M.lastIndexOf(D);
+ J > x && M.splice(J, 1), n.push(F.REPLACE_CHILD, D, L);
+ }
+ } else h.splice(x, 0, L), (A += 1);
+ } else
+ M.push(D), O(null, D, n, r, a, !0), n.push(F.INSERT_BEFORE, e, D, null);
+ else !1 === O(L, null, n, r, a, !0) && h.splice(x, 0, L);
+ }
+ if (M.length !== h.length) {
+ for (var G = h.length; G < M.length; G++) n.push(F.REMOVE_CHILD, M[G]);
+ M.length = h.length;
+ }
+ return n;
+}
+function k(e) {
+ var t =
+ arguments.length > 1 && void 0 !== arguments[1]
+ ? arguments[1]
+ : ee.document,
+ n = arguments.length > 2 ? arguments[2] : void 0,
+ r = m(e),
+ a = X.get(r);
+ if (a) return a;
+ var o = r.nodeName,
+ i = r.rawNodeName,
+ s = void 0 === i ? o : i,
+ c = r.childNodes,
+ d = void 0 === c ? [] : c;
+ n = n || "svg" === o;
+ var l = null,
+ u = null;
+ if (
+ (Z.forEach(function (e) {
+ (u = e(r)) && (l = u);
+ }),
+ !t)
+ )
+ return l;
+ var f = l;
+ f ||
+ ((f =
+ "#text" === o
+ ? t.createTextNode(r.nodeValue || U.STR)
+ : "#document-fragment" === o
+ ? t.createDocumentFragment()
+ : n
+ ? t.createElementNS(Ae, s)
+ : t.createElement(s)),
+ "script" === o && (f.type = "no-execute")),
+ X.set(r, f);
+ for (var h = 0; h < d.length; h++) {
+ var v = k(d[h], t, n);
+ f && v && f.appendChild(v);
+ }
+ return f;
+}
+function R(e) {
+ var t = e.state,
+ n = e.state.measure,
+ r = e.oldTree,
+ a = e.newTree,
+ o = e.mount;
+ if (
+ (n("sync trees"),
+ r && a && r.nodeName !== a.nodeName && a.nodeType !== B.FRAGMENT)
+ ) {
+ (e.patches = [F.REPLACE_CHILD, a, r]), (e.oldTree = t.oldTree = a);
+ var i = k(a);
+ G.delete(o),
+ G.set(i, t),
+ (e.mount = i),
+ "script" === a.nodeName &&
+ t.scriptsToExecute.set(a, a.attributes.type || U.STR);
+ } else e.patches = O(r || null, a || null, [], t, e);
+ n("sync trees");
+}
+function C(e, t) {
+ var n;
+ null === (n = J.get(e)) || void 0 === n || n.add(t);
+}
+function M(e, t) {
+ if (!t && e) {
+ var n;
+ null === (n = J.get(e)) || void 0 === n || n.clear();
+ } else if (e && t) {
+ var r;
+ null === (r = J.get(e)) || void 0 === r || r.delete(t);
+ } else
+ for (var a = 0; a < z.length; a++) {
+ var o;
+ null === (o = J.get(z[a])) || void 0 === o || o.clear();
+ }
+}
+function A(e) {
+ for (
+ var t = arguments.length, n = new Array(t > 1 ? t - 1 : 0), r = 1;
+ r < t;
+ r++
+ )
+ n[r - 1] = arguments[r];
+ var a = J.get(e),
+ o = [];
+ if (!a) return o;
+ var i = n[0],
+ c = i.nodeType === B.ELEMENT;
+ return !a.size || ("textChanged" !== e && !c)
+ ? o
+ : (a.forEach(function (e) {
+ var t = n.map(function (e) {
+ return X.get(e) || e;
+ }),
+ r = e.apply(void 0, s(t));
+ "object" == typeof r && r.then && o.push(r);
+ }),
+ ("attached" !== e && "detached" !== e) ||
+ i.childNodes.forEach(function (t) {
+ o.push.apply(o, s(A.apply(void 0, [e, t].concat(s(n.slice(1))))));
+ }),
+ o);
+}
+function x(e) {
+ return xe && e && e.indexOf && e.includes("&")
+ ? ((xe.innerHTML = e), xe.textContent || U.STR)
+ : e;
+}
+function L(e) {
+ for (
+ var t =
+ arguments.length > 1 && void 0 !== arguments[1] ? arguments[1] : U.OBJ,
+ n = [],
+ r = t.ownerDocument,
+ a = t.svgElements,
+ o = void 0 === a ? new Set() : a,
+ i = e.length,
+ c = 0;
+ ;
+
+ ) {
+ var d = e[c];
+ if (c === i) break;
+ switch (d) {
+ case F.REMOVE_ATTRIBUTE:
+ case F.SET_ATTRIBUTE:
+ if (
+ "break" ===
+ (function () {
+ var t = d === F.SET_ATTRIBUTE,
+ a = e[c + 1],
+ i = e[c + 2],
+ l = t ? x(e[c + 3]) : null;
+ c += t ? 4 : 3;
+ var u = o.has(a),
+ f = k(a, r, u),
+ h = f.getAttribute(i),
+ v = A("attributeChanged", a, i, h, l);
+ g(a);
+ var p = t ? _e : Pe;
+ return (
+ v.length
+ ? (Promise.all(v).then(function () {
+ return p(a, f, i, l);
+ }),
+ n.push.apply(n, s(v)))
+ : p(a, f, i, l),
+ "break"
+ );
+ })()
+ )
+ break;
+ case F.NODE_VALUE:
+ if (
+ "break" ===
+ (function () {
+ var t = e[c + 1],
+ a = e[c + 2],
+ i = e[c + 3],
+ d = o.has(t);
+ c += 4;
+ var l = k(t, r, d);
+ g(t);
+ var u = A("textChanged", t, i, a);
+ return (
+ u.length
+ ? (Promise.all(u).then(function () {
+ return He(l, a);
+ }),
+ n.push.apply(n, s(u)))
+ : He(l, a),
+ "break"
+ );
+ })()
+ )
+ break;
+ case F.INSERT_BEFORE:
+ var l = e[c + 1],
+ u = e[c + 2],
+ f = e[c + 3];
+ if (((c += 4), !X.has(l) && l !== Le)) continue;
+ var h = X.get(l);
+ if (l === Le) {
+ var v = X.get(f);
+ v && ((h = v.parentNode), (f = v.nextSibling ? v.nextSibling : null));
+ }
+ var p = o.has(u);
+ g(u);
+ var m = f && k(f, r, p),
+ T = k(u, r, p);
+ h.insertBefore(T, m || null), n.push.apply(n, s(A("attached", u)));
+ break;
+ case F.REPLACE_CHILD:
+ if (
+ "break" ===
+ (function () {
+ var t,
+ a,
+ i,
+ d = e[c + 1],
+ l = e[c + 2];
+ c += 3;
+ var u = o.has(d),
+ f = X.get(l),
+ h = k(d, r, u);
+ if (!f || !f.parentNode) return "break";
+ g(d);
+ var v =
+ null === (t = J.get("attached")) || void 0 === t
+ ? void 0
+ : t.size,
+ p =
+ null === (a = J.get("detached")) || void 0 === a
+ ? void 0
+ : a.size,
+ m =
+ null === (i = J.get("replaced")) || void 0 === i
+ ? void 0
+ : i.size;
+ if (!v && !p && !m)
+ return f.parentNode.replaceChild(h, f), b(l), "break";
+ f.parentNode.insertBefore(h, f);
+ var T = [].concat(
+ s((v && A("attached", d)) || U.ARR),
+ s((p && A("detached", l)) || U.ARR),
+ s((m && A("replaced", l, d)) || U.ARR)
+ );
+ return (
+ T.length
+ ? (Promise.all(T).then(function () {
+ f.parentNode && f.parentNode.removeChild(f), b(l);
+ }),
+ n.push.apply(n, s(T)))
+ : (f.parentNode.removeChild(f), b(l)),
+ "break"
+ );
+ })()
+ )
+ break;
+ case F.REMOVE_CHILD:
+ if (
+ "break" ===
+ (function () {
+ var t = e[c + 1];
+ c += 2;
+ var r = X.get(t);
+ if (!r || !r.parentNode) return "break";
+ var a = A("detached", t);
+ return (
+ a.length
+ ? (Promise.all(a).then(function () {
+ r.parentNode && r.parentNode.removeChild(r), b(t);
+ }),
+ n.push.apply(n, s(a)))
+ : (r.parentNode.removeChild(r), b(t)),
+ "break"
+ );
+ })()
+ )
+ break;
+ }
+ }
+ return n;
+}
+function D(e) {
+ var t = e.mount,
+ n = e.state,
+ r = e.patches,
+ a = n.mutationObserver,
+ o = n.measure,
+ i = n.scriptsToExecute;
+ o("patch node");
+ var c = t.ownerDocument,
+ d = e.promises || [];
+ (n.ownerDocument = c || ee.document), a && a.disconnect();
+ var l = function (e) {
+ "script" === e.nodeName && i.set(e, e.attributes.type);
+ };
+ Z.add(l),
+ n.ownerDocument && d.push.apply(d, s(L(r, n))),
+ Z.delete(l),
+ (e.promises = d),
+ o("patch node");
+}
+function I(e) {
+ var t = e.promises;
+ return t && t.length
+ ? (e.promise = Promise.all(t).then(function () {
+ return e.end();
+ }))
+ : (e.promise = Promise.resolve(e.end()));
+}
+function V() {
+ return Boolean(Be && "noModule" in Be);
+}
+function j(e) {
+ return e.replace(/[&<>]/g, function (e) {
+ return "&#".concat(e.charCodeAt(0), ";");
+ });
+}
+function _(e) {
+ var t =
+ arguments.length > 1 && void 0 !== arguments[1] ? arguments[1] : U.STR,
+ n = arguments.length > 2 && void 0 !== arguments[2] ? arguments[2] : {};
+ return (
+ (n.inner = !0),
+ (n.executeScripts = !("executeScripts" in n) || n.executeScripts),
+ (n.tasks = n.tasks || Fe),
+ Je.create(e, t, n).start()
+ );
+}
+function P(e) {
+ var t =
+ arguments.length > 1 && void 0 !== arguments[1] ? arguments[1] : U.STR,
+ n = arguments.length > 2 && void 0 !== arguments[2] ? arguments[2] : {};
+ return (
+ (n.inner = !1),
+ (n.executeScripts = !("executeScripts" in n) || n.executeScripts),
+ (n.tasks = n.tasks || Fe),
+ Je.create(e, t, n).start()
+ );
+}
+function H(e) {
+ var t = "function" == typeof e,
+ n = e.subscribe,
+ r = e.unsubscribe,
+ a = e.createTreeHook,
+ o = e.createNodeHook,
+ i = e.syncTreeHook,
+ s = e.releaseHook,
+ c = e.parseHook;
+ return (
+ t && q.add(e),
+ n && n(Xe),
+ a && Y.add(a),
+ o && Z.add(o),
+ i && $.add(i),
+ s && K.add(s),
+ c && Q.add(c),
+ function () {
+ t && q.delete(e),
+ r && r(Xe),
+ a && Y.delete(a),
+ o && Z.delete(o),
+ i && $.delete(i),
+ s && K.delete(s),
+ c && Q.delete(c);
+ }
+ );
+}
+var B = { ELEMENT: 1, ATTR: 2, TEXT: 3, COMMENT: 8, FRAGMENT: 11 },
+ U = {
+ STR: "",
+ NUM: 1,
+ OBJ: {},
+ ARR: [],
+ MAP: new Map(),
+ SET: new Set(),
+ DOM: {},
+ FUN: function () {},
+ },
+ F = {
+ SET_ATTRIBUTE: 0,
+ REMOVE_ATTRIBUTE: 1,
+ NODE_VALUE: 2,
+ INSERT_BEFORE: 3,
+ REPLACE_CHILD: 4,
+ REMOVE_CHILD: 5,
+ },
+ z = ["attached", "detached", "replaced", "attributeChanged", "textChanged"],
+ J = new Map([
+ ["attached", new Set()],
+ ["detached", new Set()],
+ ["replaced", new Set()],
+ ["attributeChanged", new Set()],
+ ["textChanged", new Set()],
+ ]),
+ G = new Map(),
+ X = new Map(),
+ q = new Set(),
+ Y = new Set(),
+ Z = new Set(),
+ $ = new Set(),
+ K = new Set(),
+ Q = new Set(),
+ W = { env: { NODE_ENV: "production" } },
+ ee =
+ "object" == typeof global
+ ? global
+ : ("object" == typeof window ? window : self) || {},
+ te = Number.parseInt,
+ ne = JSON.parse,
+ re = { collectMetrics: !0, executeScripts: !0 },
+ ae = v("initialPoolSize", 5e3),
+ oe = new Set(),
+ ie = new Set(),
+ se = new Set(),
+ ce = function () {
+ return {
+ rawNodeName: U.STR,
+ nodeName: U.STR,
+ nodeValue: U.STR,
+ nodeType: B.ELEMENT,
+ key: U.STR,
+ childNodes: [],
+ attributes: {},
+ };
+ },
+ de = { free: oe, allocated: ie, protected: se },
+ le = oe.values(),
+ ue = {
+ size: ae,
+ memory: de,
+ fill: function () {
+ for (var e = this, t = oe.size; t < this.size; t++) oe.add(ce());
+ this.size < oe.size &&
+ oe.forEach(function (t) {
+ oe.size !== e.size && oe.delete(t);
+ });
+ },
+ get: function () {
+ var e = le.next(),
+ t = e.value,
+ n = void 0 === t ? ce() : t;
+ return e.done && (le = oe.values()), oe.delete(n), ie.add(n), n;
+ },
+ protect: function (e) {
+ ie.delete(e), se.add(e);
+ },
+ unprotect: function (e) {
+ (se.has(e) || ie.has(e)) && (se.delete(e), ie.delete(e), oe.add(e));
+ },
+ };
+ue.fill();
+var fe = Array.isArray,
+ he = ue.memory,
+ ve = "#document-fragment",
+ pe = "#text",
+ me = "diffHTML",
+ Te = new Map(),
+ ge = 0,
+ be = ue.protect,
+ Ne = ue.unprotect,
+ ye = ue.memory,
+ Ee = Object.freeze({
+ __proto__: null,
+ protectVTree: g,
+ unprotectVTree: b,
+ gc: N,
+ }),
+ we = "undefined" != typeof requestIdleCallback,
+ Se = -1,
+ Oe = function (e) {
+ return (we ? requestIdleCallback : setTimeout)(e);
+ },
+ ke = function (e) {
+ return (we ? cancelIdleCallback : clearTimeout)(e);
+ },
+ Re = Math.max,
+ Ce = ["old", "new"],
+ Me = "#text",
+ Ae = "http://www.w3.org/2000/svg",
+ xe = ee.document ? document.createElement("div") : null,
+ Le = Symbol.for("diff.after"),
+ De = Symbol.for("diffHTML"),
+ Ie = Object.keys,
+ Ve = new Set(),
+ je = new Set(),
+ _e = function (e, t, n, r) {
+ var a = "object" == typeof r && r,
+ o = "function" == typeof r,
+ i = "symbol" == typeof r,
+ s = 0 === n.indexOf("on"),
+ c = t,
+ d = s ? n.toLowerCase() : n,
+ l = "s-" + e.nodeName + "-" + d,
+ u = t;
+ if (je.has(l)) c[d] = r;
+ else if (!Ve.has(l))
+ try {
+ (c[d] = r), je.add(l);
+ } catch (e) {
+ Ve.add(l);
+ }
+ if (a || o || i) {
+ if (a && "style" === d)
+ for (var f = Ie(r), h = 0; h < f.length; h++) u.style[f[h]] = r[f[h]];
+ } else {
+ var v = null === r || void 0 === r || !0 === r;
+ u.setAttribute(d, v ? U.STR : r);
+ }
+ },
+ Pe = function (e, t, n) {
+ var r = "r-" + e.nodeName + "-" + n,
+ a = t;
+ if (je.has(r)) (a[n] = void 0), delete a[n];
+ else if (!Ve.has(r))
+ try {
+ (a[n] = void 0), delete a[n], je.add(r);
+ } catch (e) {
+ Ve.add(r);
+ }
+ t.removeAttribute(n);
+ },
+ He = function (e, t) {
+ var n = e;
+ t.includes("&") ? (n.nodeValue = x(t)) : (n.nodeValue = t);
+ },
+ Be = ee.document ? document.createElement("script") : null,
+ Ue = Object.assign,
+ Fe = [y, E, S, R, D, I],
+ ze = {
+ schedule: y,
+ shouldUpdate: E,
+ reconcileTrees: S,
+ syncTrees: R,
+ patchNode: D,
+ endAsPromise: I,
+ },
+ Je = (function () {
+ function e(t, n, a) {
+ r(this, e),
+ i(this, "state", U.OBJ),
+ i(this, "mount", U.OBJ),
+ i(this, "input", U.OBJ),
+ i(this, "oldTree", void 0),
+ i(this, "newTree", void 0),
+ i(this, "promise", void 0),
+ i(this, "promises", void 0),
+ i(this, "tasks", []),
+ i(this, "patches", []),
+ (this.mount = t),
+ (this.input = n),
+ (this.config = a);
+ var o =
+ !a.disableMutationObserver &&
+ "MutationObserver" in (ee.window || U.OBJ);
+ (this.state = G.get(t) || {
+ measure: T(this),
+ svgElements: new Set(),
+ scriptsToExecute: new Map(),
+ activeTransaction: this,
+ mutationObserver: o && new ee.window.MutationObserver(U.FUN),
+ }),
+ (this.tasks = v("tasks", Fe, void 0, a).slice()),
+ (this.endedCallbacks = new Set()),
+ G.set(t, this.state);
+ }
+ return (
+ o(
+ e,
+ [
+ {
+ key: "start",
+ value: function () {
+ var t = this.state.measure,
+ n = this.tasks,
+ r = n.pop();
+ return (
+ t("render"),
+ (this.aborted = !1),
+ e.invokeMiddleware(this),
+ r && n.push(r),
+ e.flow(this, n)
+ );
+ },
+ },
+ {
+ key: "abort",
+ value: function (e) {
+ if (((this.aborted = !0), e))
+ return this.tasks[this.tasks.length - 1](this);
+ },
+ },
+ {
+ key: "end",
+ value: function () {
+ var e = this,
+ t = this.state,
+ n = this.config,
+ r = this.mount,
+ a = t.mutationObserver,
+ o = t.measure,
+ i = t.svgElements,
+ s = t.scriptsToExecute,
+ c = r;
+ return (
+ o("finalize"),
+ (this.completed = !0),
+ i.clear(),
+ (t.isRendering = !1),
+ (t.isDirty = !1),
+ c.ownerDocument && a
+ ? a.observe(c, {
+ subtree: !0,
+ childList: !0,
+ attributes: !0,
+ characterData: !0,
+ })
+ : (t.isDirty = !0),
+ s.forEach(function (e, r) {
+ var a = X.get(r);
+ if (
+ ((a.type = e),
+ n.executeScripts && (!V() || "nomodule" !== e))
+ ) {
+ var o = Ue(a.ownerDocument.createElement("script"), a);
+ for (var i in r.attributes) {
+ var s = r.attributes[i];
+ o.setAttribute(i, s);
+ }
+ (o.textContent = a.textContent),
+ G.has(a) && (w(a), G.set(o, t)),
+ X.set(r, o),
+ a.parentNode && a.parentNode.replaceChild(o, a);
+ }
+ }),
+ s.clear(),
+ this.endedCallbacks.forEach(function (t) {
+ return t(e);
+ }),
+ this.endedCallbacks.clear(),
+ o("finalize"),
+ o("render"),
+ t.oldTree && g(t.oldTree),
+ this
+ );
+ },
+ },
+ {
+ key: "onceEnded",
+ value: function (e) {
+ this.endedCallbacks.add(e);
+ },
+ },
+ ],
+ [
+ {
+ key: "create",
+ value: function (t, n, r) {
+ return new e(t, n, r);
+ },
+ },
+ {
+ key: "flow",
+ value: function (e, t) {
+ for (var n = e, r = 0; r < t.length; r++) {
+ if (e.aborted) return n;
+ if (void 0 !== (n = t[r](e)) && n !== e) return n;
+ }
+ return n;
+ },
+ },
+ { key: "assert", value: function (e) {} },
+ {
+ key: "invokeMiddleware",
+ value: function (e) {
+ var t = e.state.measure,
+ n = e.tasks;
+ q.forEach(function (r) {
+ var a = "invoke ".concat(r.name || "anon");
+ t(a);
+ var o = r(e);
+ o && n.push(o), t(a);
+ });
+ },
+ },
+ ]
+ ),
+ e
+ );
+ })(),
+ Ge = {
+ StateCache: G,
+ NodeCache: X,
+ TransitionCache: J,
+ MiddlewareCache: q,
+ CreateTreeHookCache: Y,
+ CreateNodeHookCache: Z,
+ SyncTreeHookCache: $,
+ ReleaseHookCache: K,
+ ParseHookCache: Q,
+ },
+ Xe = n(
+ {
+ decodeEntities: x,
+ escape: j,
+ makeMeasure: T,
+ memory: Ee,
+ Pool: ue,
+ process: W,
+ PATCH_TYPE: F,
+ globalConfig: re,
+ createNode: k,
+ syncTree: O,
+ Transaction: Je,
+ defaultTasks: Fe,
+ tasks: ze,
+ },
+ Ge
+ ),
+ qe = Object.assign,
+ Ye = "".concat("1.0.0-beta.29", "-lite");
+qe(Xe, { VERSION: Ye });
+var $e = ee;
+if (De in ee) {
+ var Ke = $e[De];
+ Ye !== Ke.VERSION &&
+ console.log("Loaded ".concat(Ye, " after ").concat(Ke.VERSION));
+}
+$e.devTools && ($e.unsubscribeDevTools = H($e.devTools(Xe)));
+
+export const Internals = Xe;
+export const VERSION = Ye;
+export const addTransitionState = C;
+export const createTree = m;
+export const html = m;
+export const innerHTML = _;
+export const outerHTML = P;
+export const release = w;
+export const removeTransitionState = M;
+export const use = H;
+
+export default {
+ VERSION: Ye,
+ addTransitionState: C,
+ removeTransitionState: M,
+ release: w,
+ createTree: m,
+ use: H,
+ outerHTML: P,
+ innerHTML: _,
+ html: m,
+ Internals: Xe,
+};