diff options
author | Hayleigh Thompson <me@hayleigh.dev> | 2023-07-10 23:11:32 +0100 |
---|---|---|
committer | GitHub <noreply@github.com> | 2023-07-10 23:11:32 +0100 |
commit | f350db196bcab490b8a6b67f9536f0b9b7322073 (patch) | |
tree | 59664ca671be2cfdb473424ca1bf737cf12622e8 /src | |
parent | 6d314230346336ba5b452b1df39b908ffa666f45 (diff) | |
download | lustre-f350db196bcab490b8a6b67f9536f0b9b7322073.tar.gz lustre-f350db196bcab490b8a6b67f9536f0b9b7322073.zip |
♻️ Replace React with diffhtml (#10)
* :wrench: Remove react dependency, add vite for running examples.
* :heavy_plus_sign: Update stdlib version to 0.29
* :fire: Remove old examples.
* :sparkles: Vendor diffhtml and update runtime ffi code to replace react.
* :recycle: Refactor all the things now react is gone.
* :memo: Remove references to react in the readme.
* :sparkles: Create a simple counter example.
Diffstat (limited to 'src')
-rw-r--r-- | src/lustre.ffi.mjs | 290 | ||||
-rw-r--r-- | src/lustre.gleam | 43 | ||||
-rw-r--r-- | src/lustre/attribute.gleam | 44 | ||||
-rw-r--r-- | src/lustre/cmd.gleam | 32 | ||||
-rw-r--r-- | src/lustre/element.gleam | 20 | ||||
-rw-r--r-- | src/lustre/event.gleam | 158 | ||||
-rw-r--r-- | src/runtime.ffi.mjs | 1300 |
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, +}; |