diff options
author | Hayleigh Thompson <me@hayleigh.dev> | 2024-04-16 19:27:19 +0100 |
---|---|---|
committer | Hayleigh Thompson <me@hayleigh.dev> | 2024-04-16 19:27:19 +0100 |
commit | 3714226d7a0ad4a78e381d9767c3e64d12d6605a (patch) | |
tree | ad971a72e5590a1ec868a89d096ebdce751c63c7 /examples | |
parent | 0d30e9c35329e2ad4a6277a2b5f4d5115fb4d274 (diff) | |
download | lustre-3714226d7a0ad4a78e381d9767c3e64d12d6605a.tar.gz lustre-3714226d7a0ad4a78e381d9767c3e64d12d6605a.zip |
:heavy_plus_sign: Update examples to work with latest lustre_dev_tools release.
Diffstat (limited to 'examples')
28 files changed, 14140 insertions, 104 deletions
diff --git a/examples/01-hello-world/index.html b/examples/01-hello-world/index.html new file mode 100644 index 0000000..36ddf10 --- /dev/null +++ b/examples/01-hello-world/index.html @@ -0,0 +1,19 @@ +<!doctype html> +<html lang="en"> + <head> + <meta charset="UTF-8" /> + <meta name="viewport" content="width=device-width, initial-scale=1.0" /> + + <title>🚧 app</title> + + <link + rel="stylesheet" + href="./build/dev/javascript/lustre_ui/priv/static/lustre-ui.css" + /> + <script type="module" src="./priv/static/app.mjs"></script> + </head> + + <body> + <div id="app"></div> + </body> +</html> diff --git a/examples/01-hello-world/manifest.toml b/examples/01-hello-world/manifest.toml index 7f82909..c0d1211 100644 --- a/examples/01-hello-world/manifest.toml +++ b/examples/01-hello-world/manifest.toml @@ -3,26 +3,39 @@ packages = [ { name = "argv", version = "1.0.2", build_tools = ["gleam"], requirements = [], otp_app = "argv", source = "hex", outer_checksum = "BA1FF0929525DEBA1CE67256E5ADF77A7CDDFE729E3E3F57A5BDCAA031DED09D" }, + { name = "birl", version = "1.6.1", build_tools = ["gleam"], requirements = ["gleam_stdlib", "ranger"], otp_app = "birl", source = "hex", outer_checksum = "976CFF85D34D50F7775896615A71745FBE0C325E50399787088F941B539A0497" }, + { name = "exception", version = "2.0.0", build_tools = ["gleam"], requirements = ["gleam_stdlib"], otp_app = "exception", source = "hex", outer_checksum = "F5580D584F16A20B7FCDCABF9E9BE9A2C1F6AC4F9176FA6DD0B63E3B20D450AA" }, { name = "filepath", version = "1.0.0", build_tools = ["gleam"], requirements = ["gleam_stdlib"], otp_app = "filepath", source = "hex", outer_checksum = "EFB6FF65C98B2A16378ABC3EE2B14124168C0CE5201553DE652E2644DCFDB594" }, + { name = "filespy", version = "0.3.0", build_tools = ["gleam"], requirements = ["fs", "gleam_erlang", "gleam_otp", "gleam_stdlib"], otp_app = "filespy", source = "hex", outer_checksum = "75F5910B31A528681D25316AAAE6C91CD3E977BD2492946564B7242FF941FB7A" }, + { name = "fs", version = "8.6.1", build_tools = ["rebar3"], requirements = [], otp_app = "fs", source = "hex", outer_checksum = "61EA2BDAEDAE4E2024D0D25C63E44DCCF65622D4402DB4A2DF12868D1546503F" }, { name = "gleam_community_ansi", version = "1.4.0", build_tools = ["gleam"], requirements = ["gleam_community_colour", "gleam_stdlib"], otp_app = "gleam_community_ansi", source = "hex", outer_checksum = "FE79E08BF97009729259B6357EC058315B6FBB916FAD1C2FF9355115FEB0D3A4" }, { name = "gleam_community_colour", version = "1.4.0", build_tools = ["gleam"], requirements = ["gleam_json", "gleam_stdlib"], otp_app = "gleam_community_colour", source = "hex", outer_checksum = "795964217EBEDB3DA656F5EB8F67D7AD22872EB95182042D3E7AFEF32D3FD2FE" }, + { name = "gleam_crypto", version = "1.3.0", build_tools = ["gleam"], requirements = ["gleam_stdlib"], otp_app = "gleam_crypto", source = "hex", outer_checksum = "ADD058DEDE8F0341F1ADE3AAC492A224F15700829D9A3A3F9ADF370F875C51B7" }, { name = "gleam_erlang", version = "0.25.0", build_tools = ["gleam"], requirements = ["gleam_stdlib"], otp_app = "gleam_erlang", source = "hex", outer_checksum = "054D571A7092D2A9727B3E5D183B7507DAB0DA41556EC9133606F09C15497373" }, + { name = "gleam_http", version = "3.6.0", build_tools = ["gleam"], requirements = ["gleam_stdlib"], otp_app = "gleam_http", source = "hex", outer_checksum = "8C07DF9DF8CC7F054C650839A51C30A7D3C26482AC241C899C1CEA86B22DBE51" }, { name = "gleam_json", version = "1.0.0", build_tools = ["gleam"], requirements = ["gleam_stdlib", "thoas"], otp_app = "gleam_json", source = "hex", outer_checksum = "8B197DD5D578EA6AC2C0D4BDC634C71A5BCA8E7DB5F47091C263ECB411A60DF3" }, { name = "gleam_otp", version = "0.10.0", build_tools = ["gleam"], requirements = ["gleam_erlang", "gleam_stdlib"], otp_app = "gleam_otp", source = "hex", outer_checksum = "0B04FE915ACECE539B317F9652CAADBBC0F000184D586AAAF2D94C100945D72B" }, { name = "gleam_package_interface", version = "1.0.0", build_tools = ["gleam"], requirements = ["gleam_json", "gleam_stdlib"], otp_app = "gleam_package_interface", source = "hex", outer_checksum = "52A721BCA972C8099BB881195D821AAA64B9F2655BECC102165D5A1097731F01" }, { name = "gleam_stdlib", version = "0.36.0", build_tools = ["gleam"], requirements = [], otp_app = "gleam_stdlib", source = "hex", outer_checksum = "C0D14D807FEC6F8A08A7C9EF8DFDE6AE5C10E40E21325B2B29365965D82EB3D4" }, { name = "glearray", version = "0.2.1", build_tools = ["gleam"], requirements = ["gleam_stdlib"], otp_app = "glearray", source = "hex", outer_checksum = "908154F695D330E06A37FAB2C04119E8F315D643206F8F32B6A6C14A8709FFF4" }, - { name = "gleeunit", version = "1.0.2", build_tools = ["gleam"], requirements = ["gleam_stdlib"], otp_app = "gleeunit", source = "hex", outer_checksum = "D364C87AFEB26BDB4FB8A5ABDE67D635DC9FA52D6AB68416044C35B096C6882D" }, + { name = "gleeunit", version = "1.1.2", build_tools = ["gleam"], requirements = ["gleam_stdlib"], otp_app = "gleeunit", source = "hex", outer_checksum = "72CDC3D3F719478F26C4E2C5FED3E657AC81EC14A47D2D2DEBB8693CA3220C3B" }, { name = "glint", version = "0.18.0", build_tools = ["gleam"], requirements = ["gleam_community_ansi", "gleam_community_colour", "gleam_stdlib", "snag"], otp_app = "glint", source = "hex", outer_checksum = "BB0F14643CC51C069A5DC6E9082EAFCD9967AFD1C9CC408803D1A40A3FD43B54" }, - { name = "lustre", version = "4.0.0", build_tools = ["gleam"], requirements = ["gleam_erlang", "gleam_json", "gleam_otp", "gleam_stdlib"], otp_app = "lustre", source = "hex", outer_checksum = "1D40C1378279F7015687F8C9DB739D6880BB0B843F4428B85C61EDDA8BF21FC6" }, - { name = "lustre_dev_tools", version = "1.0.0", build_tools = ["gleam"], requirements = ["argv", "filepath", "gleam_community_ansi", "gleam_erlang", "gleam_json", "gleam_otp", "gleam_package_interface", "gleam_stdlib", "glint", "simplifile", "spinner", "tom"], otp_app = "lustre_dev_tools", source = "hex", outer_checksum = "66142ADDCA3D6C63A89E016CF6C21E07D06D6DC92479325182A07C360BD026D3" }, - { name = "lustre_ui", version = "0.5.0", build_tools = ["gleam"], requirements = ["gleam_community_colour", "gleam_json", "gleam_stdlib", "lustre"], otp_app = "lustre_ui", source = "hex", outer_checksum = "7ECB5414BE926082401891C62FAAA21221FC0B7A2F0568A492349F48DC2B02A0" }, + { name = "glisten", version = "2.0.0", build_tools = ["gleam"], requirements = ["gleam_erlang", "gleam_otp", "gleam_stdlib"], otp_app = "glisten", source = "hex", outer_checksum = "CF3A9383E9BA4A8CBAF2F7B799716290D02F2AC34E7A77556B49376B662B9314" }, + { name = "hpack_erl", version = "0.3.0", build_tools = ["rebar3"], requirements = [], otp_app = "hpack", source = "hex", outer_checksum = "D6137D7079169D8C485C6962DFE261AF5B9EF60FBC557344511C1E65E3D95FB0" }, + { name = "logging", version = "1.0.1", build_tools = ["gleam"], requirements = ["gleam_stdlib"], otp_app = "logging", source = "hex", outer_checksum = "82C112ED9B6C30C1772A6FE2613B94B13F62EA35F5869A2630D13948D297BD39" }, + { name = "lustre", version = "4.1.7", build_tools = ["gleam"], requirements = ["gleam_erlang", "gleam_json", "gleam_otp", "gleam_stdlib"], otp_app = "lustre", source = "hex", outer_checksum = "64F5D7E4DF51280185F70296ACB7D3DCC9B5DA09EFC5257F0E5601846DFBEF23" }, + { name = "lustre_dev_tools", version = "1.2.1", build_tools = ["gleam"], requirements = ["argv", "filepath", "filespy", "fs", "gleam_community_ansi", "gleam_erlang", "gleam_http", "gleam_json", "gleam_otp", "gleam_package_interface", "gleam_stdlib", "glint", "glisten", "mist", "simplifile", "spinner", "tom", "wisp"], otp_app = "lustre_dev_tools", source = "hex", outer_checksum = "930BBE8C4E92A16857C31B7B12616651433E1643304696FB93B69D659CE3ADC2" }, + { name = "lustre_ui", version = "0.6.0", build_tools = ["gleam"], requirements = ["gleam_community_colour", "gleam_json", "gleam_stdlib", "lustre"], otp_app = "lustre_ui", source = "hex", outer_checksum = "FA1F9E89D89CDD5DF376ED86ABA8A38441CB2E664CD4D402F22A49DA4D7BB56D" }, + { name = "marceau", version = "1.1.0", build_tools = ["gleam"], requirements = [], otp_app = "marceau", source = "hex", outer_checksum = "1AAD727A30BE0F95562C3403BB9B27C823797AD90037714255EEBF617B1CDA81" }, + { name = "mist", version = "1.0.0", build_tools = ["gleam"], requirements = ["birl", "gleam_erlang", "gleam_http", "gleam_otp", "gleam_stdlib", "glisten", "hpack_erl", "logging"], otp_app = "mist", source = "hex", outer_checksum = "7765E53DCC9ACCACF217B8E0CA3DE7E848C783BFAE5118B75011E81C2C80385C" }, + { name = "ranger", version = "1.2.0", build_tools = ["gleam"], requirements = ["gleam_stdlib"], otp_app = "ranger", source = "hex", outer_checksum = "1566C272B1D141B3BBA38B25CB761EF56E312E79EC0E2DFD4D3C19FB0CC1F98C" }, { name = "repeatedly", version = "2.1.1", build_tools = ["gleam"], requirements = [], otp_app = "repeatedly", source = "hex", outer_checksum = "38808C3EC382B0CD981336D5879C24ECB37FCB9C1D1BD128F7A80B0F74404D79" }, - { name = "simplifile", version = "1.5.1", build_tools = ["gleam"], requirements = ["gleam_stdlib"], otp_app = "simplifile", source = "hex", outer_checksum = "C44DB387524F90DC42142699C78C850003289D32C7C99C7D32873792A299CDF7" }, + { name = "simplifile", version = "1.7.0", build_tools = ["gleam"], requirements = ["filepath", "gleam_stdlib"], otp_app = "simplifile", source = "hex", outer_checksum = "1D5DFA3A2F9319EC85825F6ED88B8E449F381B0D55A62F5E61424E748E7DDEB0" }, { name = "snag", version = "0.3.0", build_tools = ["gleam"], requirements = ["gleam_stdlib"], otp_app = "snag", source = "hex", outer_checksum = "54D32E16E33655346AA3E66CBA7E191DE0A8793D2C05284E3EFB90AD2CE92BCC" }, { name = "spinner", version = "1.1.0", build_tools = ["gleam"], requirements = ["gleam_community_ansi", "gleam_erlang", "gleam_stdlib", "glearray", "repeatedly"], otp_app = "spinner", source = "hex", outer_checksum = "200BA3D4A04D468898E63C0D316E23F526E02514BC46454091975CB5BAE41E8F" }, { name = "thoas", version = "0.4.1", build_tools = ["rebar3"], requirements = [], otp_app = "thoas", source = "hex", outer_checksum = "4918D50026C073C4AB1388437132C77A6F6F7C8AC43C60C13758CC0ADCE2134E" }, { name = "tom", version = "0.3.0", build_tools = ["gleam"], requirements = ["gleam_stdlib"], otp_app = "tom", source = "hex", outer_checksum = "0831C73E45405A2153091226BF98FB485ED16376988602CC01A5FD086B82D577" }, + { name = "wisp", version = "0.14.0", build_tools = ["gleam"], requirements = ["exception", "gleam_crypto", "gleam_erlang", "gleam_http", "gleam_json", "gleam_stdlib", "logging", "marceau", "mist", "simplifile"], otp_app = "wisp", source = "hex", outer_checksum = "9F5453AF1F9275E6F8707BC815D6A6A9DF41551921B16FBDBA52883773BAE684" }, ] [requirements] diff --git a/examples/01-hello-world/priv/static/app.mjs b/examples/01-hello-world/priv/static/app.mjs new file mode 100644 index 0000000..60d0114 --- /dev/null +++ b/examples/01-hello-world/priv/static/app.mjs @@ -0,0 +1,960 @@ +// build/dev/javascript/prelude.mjs +var CustomType = class { + withFields(fields) { + let properties = Object.keys(this).map( + (label2) => label2 in fields ? fields[label2] : this[label2] + ); + return new this.constructor(...properties); + } +}; +var List = class { + static fromArray(array3, tail) { + let t = tail || new Empty(); + for (let i = array3.length - 1; i >= 0; --i) { + t = new NonEmpty(array3[i], t); + } + return t; + } + [Symbol.iterator]() { + return new ListIterator(this); + } + toArray() { + return [...this]; + } + // @internal + atLeastLength(desired) { + for (let _ of this) { + if (desired <= 0) + return true; + desired--; + } + return desired <= 0; + } + // @internal + hasLength(desired) { + for (let _ of this) { + if (desired <= 0) + return false; + desired--; + } + return desired === 0; + } + countLength() { + let length2 = 0; + for (let _ of this) + length2++; + return length2; + } +}; +function prepend(element3, tail) { + return new NonEmpty(element3, tail); +} +function toList(elements, tail) { + return List.fromArray(elements, tail); +} +var ListIterator = class { + #current; + constructor(current) { + this.#current = current; + } + next() { + if (this.#current instanceof Empty) { + return { done: true }; + } else { + let { head, tail } = this.#current; + this.#current = tail; + return { value: head, done: false }; + } + } +}; +var Empty = class extends List { +}; +var NonEmpty = class extends List { + constructor(head, tail) { + super(); + this.head = head; + this.tail = tail; + } +}; +var Result = class _Result extends CustomType { + // @internal + static isResult(data) { + return data instanceof _Result; + } +}; +var Ok = class extends Result { + constructor(value) { + super(); + this[0] = value; + } + // @internal + isOk() { + return true; + } +}; +var Error = class extends Result { + constructor(detail) { + super(); + this[0] = detail; + } + // @internal + isOk() { + return false; + } +}; +function isEqual(x, y) { + let values = [x, y]; + while (values.length) { + let a = values.pop(); + let b = values.pop(); + if (a === b) + continue; + if (!isObject(a) || !isObject(b)) + return false; + let unequal = !structurallyCompatibleObjects(a, b) || unequalDates(a, b) || unequalBuffers(a, b) || unequalArrays(a, b) || unequalMaps(a, b) || unequalSets(a, b) || unequalRegExps(a, b); + if (unequal) + return false; + const proto = Object.getPrototypeOf(a); + if (proto !== null && typeof proto.equals === "function") { + try { + if (a.equals(b)) + continue; + else + return false; + } catch { + } + } + let [keys2, get2] = getters(a); + for (let k of keys2(a)) { + values.push(get2(a, k), get2(b, k)); + } + } + return true; +} +function getters(object3) { + if (object3 instanceof Map) { + return [(x) => x.keys(), (x, y) => x.get(y)]; + } else { + let extra = object3 instanceof globalThis.Error ? ["message"] : []; + return [(x) => [...extra, ...Object.keys(x)], (x, y) => x[y]]; + } +} +function unequalDates(a, b) { + return a instanceof Date && (a > b || a < b); +} +function unequalBuffers(a, b) { + return a.buffer instanceof ArrayBuffer && a.BYTES_PER_ELEMENT && !(a.byteLength === b.byteLength && a.every((n, i) => n === b[i])); +} +function unequalArrays(a, b) { + return Array.isArray(a) && a.length !== b.length; +} +function unequalMaps(a, b) { + return a instanceof Map && a.size !== b.size; +} +function unequalSets(a, b) { + return a instanceof Set && (a.size != b.size || [...a].some((e) => !b.has(e))); +} +function unequalRegExps(a, b) { + return a instanceof RegExp && (a.source !== b.source || a.flags !== b.flags); +} +function isObject(a) { + return typeof a === "object" && a !== null; +} +function structurallyCompatibleObjects(a, b) { + if (typeof a !== "object" && typeof b !== "object" && (!a || !b)) + return false; + let nonstructural = [Promise, WeakSet, WeakMap, Function]; + if (nonstructural.some((c) => a instanceof c)) + return false; + return a.constructor === b.constructor; +} +function makeError(variant, module, line, fn, message, extra) { + let error = new globalThis.Error(message); + error.gleam_error = variant; + error.module = module; + error.line = line; + error.fn = fn; + for (let k in extra) + error[k] = extra[k]; + return error; +} + +// build/dev/javascript/gleam_stdlib/gleam/option.mjs +var None = class extends CustomType { +}; + +// build/dev/javascript/gleam_stdlib/dict.mjs +var tempDataView = new DataView(new ArrayBuffer(8)); +var SHIFT = 5; +var BUCKET_SIZE = Math.pow(2, SHIFT); +var MASK = BUCKET_SIZE - 1; +var MAX_INDEX_NODE = BUCKET_SIZE / 2; +var MIN_ARRAY_NODE = BUCKET_SIZE / 4; + +// build/dev/javascript/gleam_stdlib/gleam_stdlib.mjs +function identity(x) { + return x; +} + +// build/dev/javascript/gleam_stdlib/gleam/list.mjs +function fold(loop$list, loop$initial, loop$fun) { + while (true) { + let list = loop$list; + let initial = loop$initial; + let fun = loop$fun; + if (list.hasLength(0)) { + return initial; + } else { + let x = list.head; + let rest$1 = list.tail; + loop$list = rest$1; + loop$initial = fun(initial, x); + loop$fun = fun; + } + } +} + +// build/dev/javascript/gleam_stdlib/gleam/dynamic.mjs +function from(a) { + return identity(a); +} + +// build/dev/javascript/gleam_stdlib/gleam/bool.mjs +function guard(requirement, consequence, alternative) { + if (requirement) { + return consequence; + } else { + return alternative(); + } +} + +// build/dev/javascript/lustre/lustre/effect.mjs +var Effect = class extends CustomType { + constructor(all) { + super(); + this.all = all; + } +}; +function none() { + return new Effect(toList([])); +} + +// build/dev/javascript/lustre/lustre/internals/vdom.mjs +var Text = class extends CustomType { + constructor(content) { + super(); + this.content = content; + } +}; +var Element = class extends CustomType { + constructor(key, namespace, tag2, attrs, children, self_closing, void$) { + super(); + this.key = key; + this.namespace = namespace; + this.tag = tag2; + this.attrs = attrs; + this.children = children; + this.self_closing = self_closing; + this.void = void$; + } +}; +var Attribute = class extends CustomType { + constructor(x0, x1, as_property) { + super(); + this[0] = x0; + this[1] = x1; + this.as_property = as_property; + } +}; + +// build/dev/javascript/lustre/lustre/attribute.mjs +function attribute(name, value) { + return new Attribute(name, from(value), false); +} +function style(properties) { + return attribute( + "style", + fold( + properties, + "", + (styles, _use1) => { + let name$1 = _use1[0]; + let value$1 = _use1[1]; + return styles + name$1 + ":" + value$1 + ";"; + } + ) + ); +} +function class$(name) { + return attribute("class", name); +} + +// build/dev/javascript/lustre/lustre/element.mjs +function element(tag2, attrs, children) { + if (tag2 === "area") { + return new Element("", "", tag2, attrs, toList([]), false, true); + } else if (tag2 === "base") { + return new Element("", "", tag2, attrs, toList([]), false, true); + } else if (tag2 === "br") { + return new Element("", "", tag2, attrs, toList([]), false, true); + } else if (tag2 === "col") { + return new Element("", "", tag2, attrs, toList([]), false, true); + } else if (tag2 === "embed") { + return new Element("", "", tag2, attrs, toList([]), false, true); + } else if (tag2 === "hr") { + return new Element("", "", tag2, attrs, toList([]), false, true); + } else if (tag2 === "img") { + return new Element("", "", tag2, attrs, toList([]), false, true); + } else if (tag2 === "input") { + return new Element("", "", tag2, attrs, toList([]), false, true); + } else if (tag2 === "link") { + return new Element("", "", tag2, attrs, toList([]), false, true); + } else if (tag2 === "meta") { + return new Element("", "", tag2, attrs, toList([]), false, true); + } else if (tag2 === "param") { + return new Element("", "", tag2, attrs, toList([]), false, true); + } else if (tag2 === "source") { + return new Element("", "", tag2, attrs, toList([]), false, true); + } else if (tag2 === "track") { + return new Element("", "", tag2, attrs, toList([]), false, true); + } else if (tag2 === "wbr") { + return new Element("", "", tag2, attrs, toList([]), false, true); + } else { + return new Element("", "", tag2, attrs, children, false, false); + } +} +function text(content) { + return new Text(content); +} + +// build/dev/javascript/lustre/lustre/internals/runtime.mjs +var Dispatch = class extends CustomType { + constructor(x0) { + super(); + this[0] = x0; + } +}; +var Shutdown = class extends CustomType { +}; + +// build/dev/javascript/lustre/vdom.ffi.mjs +function morph(prev, next, dispatch, isComponent = false) { + let out; + let stack2 = [{ prev, next, parent: prev.parentNode }]; + while (stack2.length) { + let { prev: prev2, next: next2, parent } = stack2.pop(); + if (next2.subtree !== void 0) + next2 = next2.subtree(); + if (next2.content !== void 0) { + if (!prev2) { + const created = document.createTextNode(next2.content); + parent.appendChild(created); + out ??= created; + } else if (prev2.nodeType === Node.TEXT_NODE) { + if (prev2.textContent !== next2.content) + prev2.textContent = next2.content; + out ??= prev2; + } else { + const created = document.createTextNode(next2.content); + parent.replaceChild(created, prev2); + out ??= created; + } + } else if (next2.tag !== void 0) { + const created = createElementNode({ + prev: prev2, + next: next2, + dispatch, + stack: stack2, + isComponent + }); + if (!prev2) { + parent.appendChild(created); + } else if (prev2 !== created) { + parent.replaceChild(created, prev2); + } + out ??= created; + } + } + return out; +} +function createElementNode({ prev, next, dispatch, stack: stack2 }) { + const namespace = next.namespace || "http://www.w3.org/1999/xhtml"; + const canMorph = prev && prev.nodeType === Node.ELEMENT_NODE && prev.localName === next.tag && prev.namespaceURI === (next.namespace || "http://www.w3.org/1999/xhtml"); + const el2 = canMorph ? prev : namespace ? document.createElementNS(namespace, next.tag) : document.createElement(next.tag); + let handlersForEl; + if (!registeredHandlers.has(el2)) { + const emptyHandlers = /* @__PURE__ */ new Map(); + registeredHandlers.set(el2, emptyHandlers); + handlersForEl = emptyHandlers; + } else { + handlersForEl = registeredHandlers.get(el2); + } + const prevHandlers = canMorph ? new Set(handlersForEl.keys()) : null; + const prevAttributes = canMorph ? new Set(Array.from(prev.attributes, (a) => a.name)) : null; + let className = null; + let style2 = null; + let innerHTML = null; + for (const attr of next.attrs) { + const name = attr[0]; + const value = attr[1]; + const isProperty = attr[2]; + if (isProperty) { + el2[name] = value; + } else if (name.startsWith("on")) { + const eventName = name.slice(2); + const callback = dispatch(value); + if (!handlersForEl.has(eventName)) { + el2.addEventListener(eventName, lustreGenericEventHandler); + } + handlersForEl.set(eventName, callback); + if (canMorph) + prevHandlers.delete(eventName); + } else if (name.startsWith("data-lustre-on-")) { + const eventName = name.slice(15); + const callback = dispatch(lustreServerEventHandler); + if (!handlersForEl.has(eventName)) { + el2.addEventListener(eventName, lustreGenericEventHandler); + } + handlersForEl.set(eventName, callback); + el2.setAttribute(name, value); + } else if (name === "class") { + className = className === null ? value : className + " " + value; + } else if (name === "style") { + style2 = style2 === null ? value : style2 + value; + } else if (name === "dangerous-unescaped-html") { + innerHTML = value; + } else { + el2.setAttribute(name, value); + if (name === "value") + el2[name] = value; + if (canMorph) + prevAttributes.delete(name); + } + } + if (className !== null) { + el2.setAttribute("class", className); + if (canMorph) + prevAttributes.delete("class"); + } + if (style2 !== null) { + el2.setAttribute("style", style2); + if (canMorph) + prevAttributes.delete("style"); + } + if (canMorph) { + for (const attr of prevAttributes) { + el2.removeAttribute(attr); + } + for (const eventName of prevHandlers) { + handlersForEl.delete(eventName); + el2.removeEventListener(eventName, lustreGenericEventHandler); + } + } + if (next.key !== void 0 && next.key !== "") { + el2.setAttribute("data-lustre-key", next.key); + } else if (innerHTML !== null) { + el2.innerHTML = innerHTML; + return el2; + } + let prevChild = el2.firstChild; + let seenKeys = null; + let keyedChildren = null; + let incomingKeyedChildren = null; + let firstChild = next.children[Symbol.iterator]().next().value; + if (canMorph && firstChild !== void 0 && // Explicit checks are more verbose but truthy checks force a bunch of comparisons + // we don't care about: it's never gonna be a number etc. + firstChild.key !== void 0 && firstChild.key !== "") { + seenKeys = /* @__PURE__ */ new Set(); + keyedChildren = getKeyedChildren(prev); + incomingKeyedChildren = getKeyedChildren(next); + } + for (const child of next.children) { + if (child.key !== void 0 && seenKeys !== null) { + while (prevChild && !incomingKeyedChildren.has(prevChild.getAttribute("data-lustre-key"))) { + const nextChild = prevChild.nextSibling; + el2.removeChild(prevChild); + prevChild = nextChild; + } + if (keyedChildren.size === 0) { + stack2.unshift({ prev: prevChild, next: child, parent: el2 }); + prevChild = prevChild?.nextSibling; + continue; + } + if (seenKeys.has(child.key)) { + console.warn(`Duplicate key found in Lustre vnode: ${child.key}`); + stack2.unshift({ prev: null, next: child, parent: el2 }); + continue; + } + seenKeys.add(child.key); + const keyedChild = keyedChildren.get(child.key); + if (!keyedChild && !prevChild) { + stack2.unshift({ prev: null, next: child, parent: el2 }); + continue; + } + if (!keyedChild && prevChild !== null) { + const placeholder = document.createTextNode(""); + el2.insertBefore(placeholder, prevChild); + stack2.unshift({ prev: placeholder, next: child, parent: el2 }); + continue; + } + if (!keyedChild || keyedChild === prevChild) { + stack2.unshift({ prev: prevChild, next: child, parent: el2 }); + prevChild = prevChild?.nextSibling; + continue; + } + el2.insertBefore(keyedChild, prevChild); + stack2.unshift({ prev: keyedChild, next: child, parent: el2 }); + } else { + stack2.unshift({ prev: prevChild, next: child, parent: el2 }); + prevChild = prevChild?.nextSibling; + } + } + while (prevChild) { + const next2 = prevChild.nextSibling; + el2.removeChild(prevChild); + prevChild = next2; + } + return el2; +} +var registeredHandlers = /* @__PURE__ */ new WeakMap(); +function lustreGenericEventHandler(event) { + const target = event.currentTarget; + if (!registeredHandlers.has(target)) { + target.removeEventListener(event.type, lustreGenericEventHandler); + return; + } + const handlersForEventTarget = registeredHandlers.get(target); + if (!handlersForEventTarget.has(event.type)) { + target.removeEventListener(event.type, lustreGenericEventHandler); + return; + } + handlersForEventTarget.get(event.type)(event); +} +function lustreServerEventHandler(event) { + const el2 = event.target; + const tag2 = el2.getAttribute(`data-lustre-on-${event.type}`); + const data = JSON.parse(el2.getAttribute("data-lustre-data") || "{}"); + const include = JSON.parse(el2.getAttribute("data-lustre-include") || "[]"); + switch (event.type) { + case "input": + case "change": + include.push("target.value"); + break; + } + return { + tag: tag2, + data: include.reduce( + (data2, property) => { + const path = property.split("."); + for (let i = 0, o = data2, e = event; i < path.length; i++) { + if (i === path.length - 1) { + o[path[i]] = e[path[i]]; + } else { + o[path[i]] ??= {}; + e = e[path[i]]; + o = o[path[i]]; + } + } + return data2; + }, + { data } + ) + }; +} +function getKeyedChildren(el2) { + const keyedChildren = /* @__PURE__ */ new Map(); + if (el2) { + for (const child of el2.children) { + const key = child.key || child?.getAttribute("data-lustre-key"); + if (key) + keyedChildren.set(key, child); + } + } + return keyedChildren; +} + +// build/dev/javascript/lustre/client-runtime.ffi.mjs +var LustreClientApplication2 = class _LustreClientApplication { + #root = null; + #queue = []; + #effects = []; + #didUpdate = false; + #isComponent = false; + #model = null; + #update = null; + #view = null; + static start(flags, selector, init2, update2, view) { + if (!is_browser()) + return new Error(new NotABrowser()); + const root2 = selector instanceof HTMLElement ? selector : document.querySelector(selector); + if (!root2) + return new Error(new ElementNotFound(selector)); + const app = new _LustreClientApplication(init2(flags), update2, view, root2); + return new Ok((msg) => app.send(msg)); + } + constructor([model, effects], update2, view, root2 = document.body, isComponent = false) { + this.#model = model; + this.#update = update2; + this.#view = view; + this.#root = root2; + this.#effects = effects.all.toArray(); + this.#didUpdate = true; + this.#isComponent = isComponent; + window.requestAnimationFrame(() => this.#tick()); + } + send(action) { + switch (true) { + case action instanceof Dispatch: { + this.#queue.push(action[0]); + this.#tick(); + return; + } + case action instanceof Shutdown: { + this.#shutdown(); + return; + } + default: + return; + } + } + emit(event, data) { + this.#root.dispatchEvent( + new CustomEvent(event, { + bubbles: true, + detail: data, + composed: true + }) + ); + } + #tick() { + this.#flush_queue(); + const vdom = this.#view(this.#model); + const dispatch = (handler) => (e) => { + const result = handler(e); + if (result instanceof Ok) { + this.send(new Dispatch(result[0])); + } + }; + this.#didUpdate = false; + this.#root = morph(this.#root, vdom, dispatch, this.#isComponent); + } + #flush_queue(iterations = 0) { + while (this.#queue.length) { + const [next, effects] = this.#update(this.#model, this.#queue.shift()); + this.#didUpdate ||= !isEqual(this.#model, next); + this.#model = next; + this.#effects = this.#effects.concat(effects.all.toArray()); + } + while (this.#effects.length) { + this.#effects.shift()( + (msg) => this.send(new Dispatch(msg)), + (event, data) => this.emit(event, data) + ); + } + if (this.#queue.length) { + if (iterations < 5) { + this.#flush_queue(++iterations); + } else { + window.requestAnimationFrame(() => this.#tick()); + } + } + } + #shutdown() { + this.#root.remove(); + this.#root = null; + this.#model = null; + this.#queue = []; + this.#effects = []; + this.#didUpdate = false; + this.#update = () => { + }; + this.#view = () => { + }; + } +}; +var start = (app, selector, flags) => LustreClientApplication2.start( + flags, + selector, + app.init, + app.update, + app.view +); +var is_browser = () => window && window.document; + +// build/dev/javascript/lustre/lustre.mjs +var App = class extends CustomType { + constructor(init2, update2, view, on_attribute_change) { + super(); + this.init = init2; + this.update = update2; + this.view = view; + this.on_attribute_change = on_attribute_change; + } +}; +var ElementNotFound = class extends CustomType { + constructor(selector) { + super(); + this.selector = selector; + } +}; +var NotABrowser = class extends CustomType { +}; +function application(init2, update2, view) { + return new App(init2, update2, view, new None()); +} +function element2(html) { + let init2 = (_) => { + return [void 0, none()]; + }; + let update2 = (_, _1) => { + return [void 0, none()]; + }; + let view = (_) => { + return html; + }; + return application(init2, update2, view); +} +function start3(app, selector, flags) { + return guard( + !is_browser(), + new Error(new NotABrowser()), + () => { + return start(app, selector, flags); + } + ); +} + +// build/dev/javascript/lustre/lustre/element/html.mjs +function h1(attrs, children) { + return element("h1", attrs, children); +} +function h2(attrs, children) { + return element("h2", attrs, children); +} +function div(attrs, children) { + return element("div", attrs, children); +} + +// build/dev/javascript/lustre_ui/lustre/ui/layout/centre.mjs +function of2(element3, attributes, children) { + return element3( + prepend(class$("lustre-ui-centre"), attributes), + toList([children]) + ); +} +function centre(attributes, children) { + return of2(div, attributes, children); +} + +// build/dev/javascript/gleam_community_colour/gleam_community/colour.mjs +var Rgba = class extends CustomType { + constructor(r, g, b, a) { + super(); + this.r = r; + this.g = g; + this.b = b; + this.a = a; + } +}; +var light_red = new Rgba( + 0.9372549019607843, + 0.1607843137254902, + 0.1607843137254902, + 1 +); +var red = new Rgba(0.8, 0, 0, 1); +var dark_red = new Rgba(0.6431372549019608, 0, 0, 1); +var light_orange = new Rgba( + 0.9882352941176471, + 0.6862745098039216, + 0.24313725490196078, + 1 +); +var orange = new Rgba(0.9607843137254902, 0.4745098039215686, 0, 1); +var dark_orange = new Rgba( + 0.807843137254902, + 0.3607843137254902, + 0, + 1 +); +var light_yellow = new Rgba( + 1, + 0.9137254901960784, + 0.30980392156862746, + 1 +); +var yellow = new Rgba(0.9294117647058824, 0.8313725490196079, 0, 1); +var dark_yellow = new Rgba( + 0.7686274509803922, + 0.6274509803921569, + 0, + 1 +); +var light_green = new Rgba( + 0.5411764705882353, + 0.8862745098039215, + 0.20392156862745098, + 1 +); +var green = new Rgba( + 0.45098039215686275, + 0.8235294117647058, + 0.08627450980392157, + 1 +); +var dark_green = new Rgba( + 0.3058823529411765, + 0.6039215686274509, + 0.023529411764705882, + 1 +); +var light_blue = new Rgba( + 0.4470588235294118, + 0.6235294117647059, + 0.8117647058823529, + 1 +); +var blue = new Rgba( + 0.20392156862745098, + 0.396078431372549, + 0.6431372549019608, + 1 +); +var dark_blue = new Rgba( + 0.12549019607843137, + 0.2901960784313726, + 0.5294117647058824, + 1 +); +var light_purple = new Rgba( + 0.6784313725490196, + 0.4980392156862745, + 0.6588235294117647, + 1 +); +var purple = new Rgba( + 0.4588235294117647, + 0.3137254901960784, + 0.4823529411764706, + 1 +); +var dark_purple = new Rgba( + 0.3607843137254902, + 0.20784313725490197, + 0.4, + 1 +); +var light_brown = new Rgba( + 0.9137254901960784, + 0.7254901960784313, + 0.43137254901960786, + 1 +); +var brown = new Rgba( + 0.7568627450980392, + 0.49019607843137253, + 0.06666666666666667, + 1 +); +var dark_brown = new Rgba( + 0.5607843137254902, + 0.34901960784313724, + 0.00784313725490196, + 1 +); +var black = new Rgba(0, 0, 0, 1); +var white = new Rgba(1, 1, 1, 1); +var light_grey = new Rgba( + 0.9333333333333333, + 0.9333333333333333, + 0.9254901960784314, + 1 +); +var grey = new Rgba( + 0.8274509803921568, + 0.8431372549019608, + 0.8117647058823529, + 1 +); +var dark_grey = new Rgba( + 0.7294117647058823, + 0.7411764705882353, + 0.7137254901960784, + 1 +); +var light_gray = new Rgba( + 0.9333333333333333, + 0.9333333333333333, + 0.9254901960784314, + 1 +); +var gray = new Rgba( + 0.8274509803921568, + 0.8431372549019608, + 0.8117647058823529, + 1 +); +var dark_gray = new Rgba( + 0.7294117647058823, + 0.7411764705882353, + 0.7137254901960784, + 1 +); +var light_charcoal = new Rgba( + 0.5333333333333333, + 0.5411764705882353, + 0.5215686274509804, + 1 +); +var charcoal = new Rgba( + 0.3333333333333333, + 0.3411764705882353, + 0.3254901960784314, + 1 +); +var dark_charcoal = new Rgba( + 0.1803921568627451, + 0.20392156862745098, + 0.21176470588235294, + 1 +); +var pink = new Rgba(1, 0.6862745098039216, 0.9529411764705882, 1); + +// build/dev/javascript/lustre_ui/lustre/ui.mjs +var centre2 = centre; + +// build/dev/javascript/app/app.mjs +function main() { + let styles = toList([ + ["width", "100vw"], + ["height", "100vh"], + ["padding", "1rem"] + ]); + let app = element2( + centre2( + toList([style(styles)]), + div( + toList([]), + toList([ + h1(toList([]), toList([text("Hello, world.")])), + h2(toList([]), toList([text("Welcome to Lustre.")])) + ]) + ) + ) + ); + let $ = start3(app, "#app", void 0); + if (!$.isOk()) { + throw makeError( + "assignment_no_match", + "app", + 17, + "main", + "Assignment pattern did not match", + { value: $ } + ); + } + return void 0; +} + +// build/.lustre/entry.mjs +main(); diff --git a/examples/01-hello-world/src/app.gleam b/examples/01-hello-world/src/app.gleam index 38c1f68..57b9492 100644 --- a/examples/01-hello-world/src/app.gleam +++ b/examples/01-hello-world/src/app.gleam @@ -2,24 +2,19 @@ import lustre import lustre/attribute import lustre/element import lustre/element/html -// These examples are written with `lustre/ui` in mind. They'll work regardless, -// but to see what `lustre/ui` can do make sure to run each of these examples with -// the `--use-example-styles` flag: -// -// $ gleam run -m lustre/dev start --use-example-styles -// -// In your own apps, make sure to add the `lustre/ui` dependency and include the -// stylesheet somewhere. import lustre/ui pub fn main() { let styles = [#("width", "100vw"), #("height", "100vh"), #("padding", "1rem")] + let app = + lustre.element(ui.centre( + [attribute.style(styles)], + html.div([], [ + html.h1([], [element.text("Hello, world.")]), + html.h2([], [element.text("Welcome to Lustre.")]), + ]), + )) + let assert Ok(_) = lustre.start(app, "#app", Nil) - lustre.element(ui.centre( - [attribute.style(styles)], - html.div([], [ - html.h1([], [element.text("Hello, world.")]), - html.h2([], [element.text("Welcome to Lustre.")]), - ]), - )) + Nil } diff --git a/examples/02-interactivity/index.html b/examples/02-interactivity/index.html new file mode 100644 index 0000000..36ddf10 --- /dev/null +++ b/examples/02-interactivity/index.html @@ -0,0 +1,19 @@ +<!doctype html> +<html lang="en"> + <head> + <meta charset="UTF-8" /> + <meta name="viewport" content="width=device-width, initial-scale=1.0" /> + + <title>🚧 app</title> + + <link + rel="stylesheet" + href="./build/dev/javascript/lustre_ui/priv/static/lustre-ui.css" + /> + <script type="module" src="./priv/static/app.mjs"></script> + </head> + + <body> + <div id="app"></div> + </body> +</html> diff --git a/examples/02-interactivity/manifest.toml b/examples/02-interactivity/manifest.toml index 7f82909..c0d1211 100644 --- a/examples/02-interactivity/manifest.toml +++ b/examples/02-interactivity/manifest.toml @@ -3,26 +3,39 @@ packages = [ { name = "argv", version = "1.0.2", build_tools = ["gleam"], requirements = [], otp_app = "argv", source = "hex", outer_checksum = "BA1FF0929525DEBA1CE67256E5ADF77A7CDDFE729E3E3F57A5BDCAA031DED09D" }, + { name = "birl", version = "1.6.1", build_tools = ["gleam"], requirements = ["gleam_stdlib", "ranger"], otp_app = "birl", source = "hex", outer_checksum = "976CFF85D34D50F7775896615A71745FBE0C325E50399787088F941B539A0497" }, + { name = "exception", version = "2.0.0", build_tools = ["gleam"], requirements = ["gleam_stdlib"], otp_app = "exception", source = "hex", outer_checksum = "F5580D584F16A20B7FCDCABF9E9BE9A2C1F6AC4F9176FA6DD0B63E3B20D450AA" }, { name = "filepath", version = "1.0.0", build_tools = ["gleam"], requirements = ["gleam_stdlib"], otp_app = "filepath", source = "hex", outer_checksum = "EFB6FF65C98B2A16378ABC3EE2B14124168C0CE5201553DE652E2644DCFDB594" }, + { name = "filespy", version = "0.3.0", build_tools = ["gleam"], requirements = ["fs", "gleam_erlang", "gleam_otp", "gleam_stdlib"], otp_app = "filespy", source = "hex", outer_checksum = "75F5910B31A528681D25316AAAE6C91CD3E977BD2492946564B7242FF941FB7A" }, + { name = "fs", version = "8.6.1", build_tools = ["rebar3"], requirements = [], otp_app = "fs", source = "hex", outer_checksum = "61EA2BDAEDAE4E2024D0D25C63E44DCCF65622D4402DB4A2DF12868D1546503F" }, { name = "gleam_community_ansi", version = "1.4.0", build_tools = ["gleam"], requirements = ["gleam_community_colour", "gleam_stdlib"], otp_app = "gleam_community_ansi", source = "hex", outer_checksum = "FE79E08BF97009729259B6357EC058315B6FBB916FAD1C2FF9355115FEB0D3A4" }, { name = "gleam_community_colour", version = "1.4.0", build_tools = ["gleam"], requirements = ["gleam_json", "gleam_stdlib"], otp_app = "gleam_community_colour", source = "hex", outer_checksum = "795964217EBEDB3DA656F5EB8F67D7AD22872EB95182042D3E7AFEF32D3FD2FE" }, + { name = "gleam_crypto", version = "1.3.0", build_tools = ["gleam"], requirements = ["gleam_stdlib"], otp_app = "gleam_crypto", source = "hex", outer_checksum = "ADD058DEDE8F0341F1ADE3AAC492A224F15700829D9A3A3F9ADF370F875C51B7" }, { name = "gleam_erlang", version = "0.25.0", build_tools = ["gleam"], requirements = ["gleam_stdlib"], otp_app = "gleam_erlang", source = "hex", outer_checksum = "054D571A7092D2A9727B3E5D183B7507DAB0DA41556EC9133606F09C15497373" }, + { name = "gleam_http", version = "3.6.0", build_tools = ["gleam"], requirements = ["gleam_stdlib"], otp_app = "gleam_http", source = "hex", outer_checksum = "8C07DF9DF8CC7F054C650839A51C30A7D3C26482AC241C899C1CEA86B22DBE51" }, { name = "gleam_json", version = "1.0.0", build_tools = ["gleam"], requirements = ["gleam_stdlib", "thoas"], otp_app = "gleam_json", source = "hex", outer_checksum = "8B197DD5D578EA6AC2C0D4BDC634C71A5BCA8E7DB5F47091C263ECB411A60DF3" }, { name = "gleam_otp", version = "0.10.0", build_tools = ["gleam"], requirements = ["gleam_erlang", "gleam_stdlib"], otp_app = "gleam_otp", source = "hex", outer_checksum = "0B04FE915ACECE539B317F9652CAADBBC0F000184D586AAAF2D94C100945D72B" }, { name = "gleam_package_interface", version = "1.0.0", build_tools = ["gleam"], requirements = ["gleam_json", "gleam_stdlib"], otp_app = "gleam_package_interface", source = "hex", outer_checksum = "52A721BCA972C8099BB881195D821AAA64B9F2655BECC102165D5A1097731F01" }, { name = "gleam_stdlib", version = "0.36.0", build_tools = ["gleam"], requirements = [], otp_app = "gleam_stdlib", source = "hex", outer_checksum = "C0D14D807FEC6F8A08A7C9EF8DFDE6AE5C10E40E21325B2B29365965D82EB3D4" }, { name = "glearray", version = "0.2.1", build_tools = ["gleam"], requirements = ["gleam_stdlib"], otp_app = "glearray", source = "hex", outer_checksum = "908154F695D330E06A37FAB2C04119E8F315D643206F8F32B6A6C14A8709FFF4" }, - { name = "gleeunit", version = "1.0.2", build_tools = ["gleam"], requirements = ["gleam_stdlib"], otp_app = "gleeunit", source = "hex", outer_checksum = "D364C87AFEB26BDB4FB8A5ABDE67D635DC9FA52D6AB68416044C35B096C6882D" }, + { name = "gleeunit", version = "1.1.2", build_tools = ["gleam"], requirements = ["gleam_stdlib"], otp_app = "gleeunit", source = "hex", outer_checksum = "72CDC3D3F719478F26C4E2C5FED3E657AC81EC14A47D2D2DEBB8693CA3220C3B" }, { name = "glint", version = "0.18.0", build_tools = ["gleam"], requirements = ["gleam_community_ansi", "gleam_community_colour", "gleam_stdlib", "snag"], otp_app = "glint", source = "hex", outer_checksum = "BB0F14643CC51C069A5DC6E9082EAFCD9967AFD1C9CC408803D1A40A3FD43B54" }, - { name = "lustre", version = "4.0.0", build_tools = ["gleam"], requirements = ["gleam_erlang", "gleam_json", "gleam_otp", "gleam_stdlib"], otp_app = "lustre", source = "hex", outer_checksum = "1D40C1378279F7015687F8C9DB739D6880BB0B843F4428B85C61EDDA8BF21FC6" }, - { name = "lustre_dev_tools", version = "1.0.0", build_tools = ["gleam"], requirements = ["argv", "filepath", "gleam_community_ansi", "gleam_erlang", "gleam_json", "gleam_otp", "gleam_package_interface", "gleam_stdlib", "glint", "simplifile", "spinner", "tom"], otp_app = "lustre_dev_tools", source = "hex", outer_checksum = "66142ADDCA3D6C63A89E016CF6C21E07D06D6DC92479325182A07C360BD026D3" }, - { name = "lustre_ui", version = "0.5.0", build_tools = ["gleam"], requirements = ["gleam_community_colour", "gleam_json", "gleam_stdlib", "lustre"], otp_app = "lustre_ui", source = "hex", outer_checksum = "7ECB5414BE926082401891C62FAAA21221FC0B7A2F0568A492349F48DC2B02A0" }, + { name = "glisten", version = "2.0.0", build_tools = ["gleam"], requirements = ["gleam_erlang", "gleam_otp", "gleam_stdlib"], otp_app = "glisten", source = "hex", outer_checksum = "CF3A9383E9BA4A8CBAF2F7B799716290D02F2AC34E7A77556B49376B662B9314" }, + { name = "hpack_erl", version = "0.3.0", build_tools = ["rebar3"], requirements = [], otp_app = "hpack", source = "hex", outer_checksum = "D6137D7079169D8C485C6962DFE261AF5B9EF60FBC557344511C1E65E3D95FB0" }, + { name = "logging", version = "1.0.1", build_tools = ["gleam"], requirements = ["gleam_stdlib"], otp_app = "logging", source = "hex", outer_checksum = "82C112ED9B6C30C1772A6FE2613B94B13F62EA35F5869A2630D13948D297BD39" }, + { name = "lustre", version = "4.1.7", build_tools = ["gleam"], requirements = ["gleam_erlang", "gleam_json", "gleam_otp", "gleam_stdlib"], otp_app = "lustre", source = "hex", outer_checksum = "64F5D7E4DF51280185F70296ACB7D3DCC9B5DA09EFC5257F0E5601846DFBEF23" }, + { name = "lustre_dev_tools", version = "1.2.1", build_tools = ["gleam"], requirements = ["argv", "filepath", "filespy", "fs", "gleam_community_ansi", "gleam_erlang", "gleam_http", "gleam_json", "gleam_otp", "gleam_package_interface", "gleam_stdlib", "glint", "glisten", "mist", "simplifile", "spinner", "tom", "wisp"], otp_app = "lustre_dev_tools", source = "hex", outer_checksum = "930BBE8C4E92A16857C31B7B12616651433E1643304696FB93B69D659CE3ADC2" }, + { name = "lustre_ui", version = "0.6.0", build_tools = ["gleam"], requirements = ["gleam_community_colour", "gleam_json", "gleam_stdlib", "lustre"], otp_app = "lustre_ui", source = "hex", outer_checksum = "FA1F9E89D89CDD5DF376ED86ABA8A38441CB2E664CD4D402F22A49DA4D7BB56D" }, + { name = "marceau", version = "1.1.0", build_tools = ["gleam"], requirements = [], otp_app = "marceau", source = "hex", outer_checksum = "1AAD727A30BE0F95562C3403BB9B27C823797AD90037714255EEBF617B1CDA81" }, + { name = "mist", version = "1.0.0", build_tools = ["gleam"], requirements = ["birl", "gleam_erlang", "gleam_http", "gleam_otp", "gleam_stdlib", "glisten", "hpack_erl", "logging"], otp_app = "mist", source = "hex", outer_checksum = "7765E53DCC9ACCACF217B8E0CA3DE7E848C783BFAE5118B75011E81C2C80385C" }, + { name = "ranger", version = "1.2.0", build_tools = ["gleam"], requirements = ["gleam_stdlib"], otp_app = "ranger", source = "hex", outer_checksum = "1566C272B1D141B3BBA38B25CB761EF56E312E79EC0E2DFD4D3C19FB0CC1F98C" }, { name = "repeatedly", version = "2.1.1", build_tools = ["gleam"], requirements = [], otp_app = "repeatedly", source = "hex", outer_checksum = "38808C3EC382B0CD981336D5879C24ECB37FCB9C1D1BD128F7A80B0F74404D79" }, - { name = "simplifile", version = "1.5.1", build_tools = ["gleam"], requirements = ["gleam_stdlib"], otp_app = "simplifile", source = "hex", outer_checksum = "C44DB387524F90DC42142699C78C850003289D32C7C99C7D32873792A299CDF7" }, + { name = "simplifile", version = "1.7.0", build_tools = ["gleam"], requirements = ["filepath", "gleam_stdlib"], otp_app = "simplifile", source = "hex", outer_checksum = "1D5DFA3A2F9319EC85825F6ED88B8E449F381B0D55A62F5E61424E748E7DDEB0" }, { name = "snag", version = "0.3.0", build_tools = ["gleam"], requirements = ["gleam_stdlib"], otp_app = "snag", source = "hex", outer_checksum = "54D32E16E33655346AA3E66CBA7E191DE0A8793D2C05284E3EFB90AD2CE92BCC" }, { name = "spinner", version = "1.1.0", build_tools = ["gleam"], requirements = ["gleam_community_ansi", "gleam_erlang", "gleam_stdlib", "glearray", "repeatedly"], otp_app = "spinner", source = "hex", outer_checksum = "200BA3D4A04D468898E63C0D316E23F526E02514BC46454091975CB5BAE41E8F" }, { name = "thoas", version = "0.4.1", build_tools = ["rebar3"], requirements = [], otp_app = "thoas", source = "hex", outer_checksum = "4918D50026C073C4AB1388437132C77A6F6F7C8AC43C60C13758CC0ADCE2134E" }, { name = "tom", version = "0.3.0", build_tools = ["gleam"], requirements = ["gleam_stdlib"], otp_app = "tom", source = "hex", outer_checksum = "0831C73E45405A2153091226BF98FB485ED16376988602CC01A5FD086B82D577" }, + { name = "wisp", version = "0.14.0", build_tools = ["gleam"], requirements = ["exception", "gleam_crypto", "gleam_erlang", "gleam_http", "gleam_json", "gleam_stdlib", "logging", "marceau", "mist", "simplifile"], otp_app = "wisp", source = "hex", outer_checksum = "9F5453AF1F9275E6F8707BC815D6A6A9DF41551921B16FBDBA52883773BAE684" }, ] [requirements] diff --git a/examples/02-interactivity/priv/static/app.mjs b/examples/02-interactivity/priv/static/app.mjs new file mode 100644 index 0000000..f47edcd --- /dev/null +++ b/examples/02-interactivity/priv/static/app.mjs @@ -0,0 +1,1043 @@ +// build/dev/javascript/prelude.mjs +var CustomType = class { + withFields(fields) { + let properties = Object.keys(this).map( + (label2) => label2 in fields ? fields[label2] : this[label2] + ); + return new this.constructor(...properties); + } +}; +var List = class { + static fromArray(array3, tail) { + let t = tail || new Empty(); + for (let i = array3.length - 1; i >= 0; --i) { + t = new NonEmpty(array3[i], t); + } + return t; + } + [Symbol.iterator]() { + return new ListIterator(this); + } + toArray() { + return [...this]; + } + // @internal + atLeastLength(desired) { + for (let _ of this) { + if (desired <= 0) + return true; + desired--; + } + return desired <= 0; + } + // @internal + hasLength(desired) { + for (let _ of this) { + if (desired <= 0) + return false; + desired--; + } + return desired === 0; + } + countLength() { + let length2 = 0; + for (let _ of this) + length2++; + return length2; + } +}; +function prepend(element2, tail) { + return new NonEmpty(element2, tail); +} +function toList(elements, tail) { + return List.fromArray(elements, tail); +} +var ListIterator = class { + #current; + constructor(current) { + this.#current = current; + } + next() { + if (this.#current instanceof Empty) { + return { done: true }; + } else { + let { head, tail } = this.#current; + this.#current = tail; + return { value: head, done: false }; + } + } +}; +var Empty = class extends List { +}; +var NonEmpty = class extends List { + constructor(head, tail) { + super(); + this.head = head; + this.tail = tail; + } +}; +var Result = class _Result extends CustomType { + // @internal + static isResult(data) { + return data instanceof _Result; + } +}; +var Ok = class extends Result { + constructor(value) { + super(); + this[0] = value; + } + // @internal + isOk() { + return true; + } +}; +var Error = class extends Result { + constructor(detail) { + super(); + this[0] = detail; + } + // @internal + isOk() { + return false; + } +}; +function isEqual(x, y) { + let values = [x, y]; + while (values.length) { + let a = values.pop(); + let b = values.pop(); + if (a === b) + continue; + if (!isObject(a) || !isObject(b)) + return false; + let unequal = !structurallyCompatibleObjects(a, b) || unequalDates(a, b) || unequalBuffers(a, b) || unequalArrays(a, b) || unequalMaps(a, b) || unequalSets(a, b) || unequalRegExps(a, b); + if (unequal) + return false; + const proto = Object.getPrototypeOf(a); + if (proto !== null && typeof proto.equals === "function") { + try { + if (a.equals(b)) + continue; + else + return false; + } catch { + } + } + let [keys2, get2] = getters(a); + for (let k of keys2(a)) { + values.push(get2(a, k), get2(b, k)); + } + } + return true; +} +function getters(object3) { + if (object3 instanceof Map) { + return [(x) => x.keys(), (x, y) => x.get(y)]; + } else { + let extra = object3 instanceof globalThis.Error ? ["message"] : []; + return [(x) => [...extra, ...Object.keys(x)], (x, y) => x[y]]; + } +} +function unequalDates(a, b) { + return a instanceof Date && (a > b || a < b); +} +function unequalBuffers(a, b) { + return a.buffer instanceof ArrayBuffer && a.BYTES_PER_ELEMENT && !(a.byteLength === b.byteLength && a.every((n, i) => n === b[i])); +} +function unequalArrays(a, b) { + return Array.isArray(a) && a.length !== b.length; +} +function unequalMaps(a, b) { + return a instanceof Map && a.size !== b.size; +} +function unequalSets(a, b) { + return a instanceof Set && (a.size != b.size || [...a].some((e) => !b.has(e))); +} +function unequalRegExps(a, b) { + return a instanceof RegExp && (a.source !== b.source || a.flags !== b.flags); +} +function isObject(a) { + return typeof a === "object" && a !== null; +} +function structurallyCompatibleObjects(a, b) { + if (typeof a !== "object" && typeof b !== "object" && (!a || !b)) + return false; + let nonstructural = [Promise, WeakSet, WeakMap, Function]; + if (nonstructural.some((c) => a instanceof c)) + return false; + return a.constructor === b.constructor; +} +function makeError(variant, module, line, fn, message, extra) { + let error = new globalThis.Error(message); + error.gleam_error = variant; + error.module = module; + error.line = line; + error.fn = fn; + for (let k in extra) + error[k] = extra[k]; + return error; +} + +// build/dev/javascript/gleam_stdlib/gleam/option.mjs +var None = class extends CustomType { +}; + +// build/dev/javascript/gleam_stdlib/gleam/list.mjs +function fold(loop$list, loop$initial, loop$fun) { + while (true) { + let list = loop$list; + let initial = loop$initial; + let fun = loop$fun; + if (list.hasLength(0)) { + return initial; + } else { + let x = list.head; + let rest$1 = list.tail; + loop$list = rest$1; + loop$initial = fun(initial, x); + loop$fun = fun; + } + } +} + +// build/dev/javascript/gleam_stdlib/gleam/dynamic.mjs +function from(a) { + return identity(a); +} + +// build/dev/javascript/gleam_stdlib/dict.mjs +var tempDataView = new DataView(new ArrayBuffer(8)); +var SHIFT = 5; +var BUCKET_SIZE = Math.pow(2, SHIFT); +var MASK = BUCKET_SIZE - 1; +var MAX_INDEX_NODE = BUCKET_SIZE / 2; +var MIN_ARRAY_NODE = BUCKET_SIZE / 4; + +// build/dev/javascript/gleam_stdlib/gleam_stdlib.mjs +function identity(x) { + return x; +} +function to_string3(term) { + return term.toString(); +} + +// build/dev/javascript/gleam_stdlib/gleam/int.mjs +function to_string(x) { + return to_string3(x); +} + +// build/dev/javascript/gleam_stdlib/gleam/bool.mjs +function guard(requirement, consequence, alternative) { + if (requirement) { + return consequence; + } else { + return alternative(); + } +} + +// build/dev/javascript/lustre/lustre/effect.mjs +var Effect = class extends CustomType { + constructor(all) { + super(); + this.all = all; + } +}; +function none() { + return new Effect(toList([])); +} + +// build/dev/javascript/lustre/lustre/internals/vdom.mjs +var Text = class extends CustomType { + constructor(content) { + super(); + this.content = content; + } +}; +var Element = class extends CustomType { + constructor(key, namespace, tag2, attrs, children, self_closing, void$) { + super(); + this.key = key; + this.namespace = namespace; + this.tag = tag2; + this.attrs = attrs; + this.children = children; + this.self_closing = self_closing; + this.void = void$; + } +}; +var Attribute = class extends CustomType { + constructor(x0, x1, as_property) { + super(); + this[0] = x0; + this[1] = x1; + this.as_property = as_property; + } +}; +var Event = class extends CustomType { + constructor(x0, x1) { + super(); + this[0] = x0; + this[1] = x1; + } +}; + +// build/dev/javascript/lustre/lustre/attribute.mjs +function attribute(name, value) { + return new Attribute(name, from(value), false); +} +function on(name, handler) { + return new Event("on" + name, handler); +} +function style(properties) { + return attribute( + "style", + fold( + properties, + "", + (styles, _use1) => { + let name$1 = _use1[0]; + let value$1 = _use1[1]; + return styles + name$1 + ":" + value$1 + ";"; + } + ) + ); +} +function class$(name) { + return attribute("class", name); +} +function type_(name) { + return attribute("type", name); +} + +// build/dev/javascript/lustre/lustre/element.mjs +function element(tag2, attrs, children) { + if (tag2 === "area") { + return new Element("", "", tag2, attrs, toList([]), false, true); + } else if (tag2 === "base") { + return new Element("", "", tag2, attrs, toList([]), false, true); + } else if (tag2 === "br") { + return new Element("", "", tag2, attrs, toList([]), false, true); + } else if (tag2 === "col") { + return new Element("", "", tag2, attrs, toList([]), false, true); + } else if (tag2 === "embed") { + return new Element("", "", tag2, attrs, toList([]), false, true); + } else if (tag2 === "hr") { + return new Element("", "", tag2, attrs, toList([]), false, true); + } else if (tag2 === "img") { + return new Element("", "", tag2, attrs, toList([]), false, true); + } else if (tag2 === "input") { + return new Element("", "", tag2, attrs, toList([]), false, true); + } else if (tag2 === "link") { + return new Element("", "", tag2, attrs, toList([]), false, true); + } else if (tag2 === "meta") { + return new Element("", "", tag2, attrs, toList([]), false, true); + } else if (tag2 === "param") { + return new Element("", "", tag2, attrs, toList([]), false, true); + } else if (tag2 === "source") { + return new Element("", "", tag2, attrs, toList([]), false, true); + } else if (tag2 === "track") { + return new Element("", "", tag2, attrs, toList([]), false, true); + } else if (tag2 === "wbr") { + return new Element("", "", tag2, attrs, toList([]), false, true); + } else { + return new Element("", "", tag2, attrs, children, false, false); + } +} +function text(content) { + return new Text(content); +} + +// build/dev/javascript/lustre/lustre/internals/runtime.mjs +var Dispatch = class extends CustomType { + constructor(x0) { + super(); + this[0] = x0; + } +}; +var Shutdown = class extends CustomType { +}; + +// build/dev/javascript/lustre/vdom.ffi.mjs +function morph(prev, next, dispatch, isComponent = false) { + let out; + let stack3 = [{ prev, next, parent: prev.parentNode }]; + while (stack3.length) { + let { prev: prev2, next: next2, parent } = stack3.pop(); + if (next2.subtree !== void 0) + next2 = next2.subtree(); + if (next2.content !== void 0) { + if (!prev2) { + const created = document.createTextNode(next2.content); + parent.appendChild(created); + out ??= created; + } else if (prev2.nodeType === Node.TEXT_NODE) { + if (prev2.textContent !== next2.content) + prev2.textContent = next2.content; + out ??= prev2; + } else { + const created = document.createTextNode(next2.content); + parent.replaceChild(created, prev2); + out ??= created; + } + } else if (next2.tag !== void 0) { + const created = createElementNode({ + prev: prev2, + next: next2, + dispatch, + stack: stack3, + isComponent + }); + if (!prev2) { + parent.appendChild(created); + } else if (prev2 !== created) { + parent.replaceChild(created, prev2); + } + out ??= created; + } + } + return out; +} +function createElementNode({ prev, next, dispatch, stack: stack3 }) { + const namespace = next.namespace || "http://www.w3.org/1999/xhtml"; + const canMorph = prev && prev.nodeType === Node.ELEMENT_NODE && prev.localName === next.tag && prev.namespaceURI === (next.namespace || "http://www.w3.org/1999/xhtml"); + const el2 = canMorph ? prev : namespace ? document.createElementNS(namespace, next.tag) : document.createElement(next.tag); + let handlersForEl; + if (!registeredHandlers.has(el2)) { + const emptyHandlers = /* @__PURE__ */ new Map(); + registeredHandlers.set(el2, emptyHandlers); + handlersForEl = emptyHandlers; + } else { + handlersForEl = registeredHandlers.get(el2); + } + const prevHandlers = canMorph ? new Set(handlersForEl.keys()) : null; + const prevAttributes = canMorph ? new Set(Array.from(prev.attributes, (a) => a.name)) : null; + let className = null; + let style2 = null; + let innerHTML = null; + for (const attr of next.attrs) { + const name = attr[0]; + const value = attr[1]; + const isProperty = attr[2]; + if (isProperty) { + el2[name] = value; + } else if (name.startsWith("on")) { + const eventName = name.slice(2); + const callback = dispatch(value); + if (!handlersForEl.has(eventName)) { + el2.addEventListener(eventName, lustreGenericEventHandler); + } + handlersForEl.set(eventName, callback); + if (canMorph) + prevHandlers.delete(eventName); + } else if (name.startsWith("data-lustre-on-")) { + const eventName = name.slice(15); + const callback = dispatch(lustreServerEventHandler); + if (!handlersForEl.has(eventName)) { + el2.addEventListener(eventName, lustreGenericEventHandler); + } + handlersForEl.set(eventName, callback); + el2.setAttribute(name, value); + } else if (name === "class") { + className = className === null ? value : className + " " + value; + } else if (name === "style") { + style2 = style2 === null ? value : style2 + value; + } else if (name === "dangerous-unescaped-html") { + innerHTML = value; + } else { + el2.setAttribute(name, value); + if (name === "value") + el2[name] = value; + if (canMorph) + prevAttributes.delete(name); + } + } + if (className !== null) { + el2.setAttribute("class", className); + if (canMorph) + prevAttributes.delete("class"); + } + if (style2 !== null) { + el2.setAttribute("style", style2); + if (canMorph) + prevAttributes.delete("style"); + } + if (canMorph) { + for (const attr of prevAttributes) { + el2.removeAttribute(attr); + } + for (const eventName of prevHandlers) { + handlersForEl.delete(eventName); + el2.removeEventListener(eventName, lustreGenericEventHandler); + } + } + if (next.key !== void 0 && next.key !== "") { + el2.setAttribute("data-lustre-key", next.key); + } else if (innerHTML !== null) { + el2.innerHTML = innerHTML; + return el2; + } + let prevChild = el2.firstChild; + let seenKeys = null; + let keyedChildren = null; + let incomingKeyedChildren = null; + let firstChild = next.children[Symbol.iterator]().next().value; + if (canMorph && firstChild !== void 0 && // Explicit checks are more verbose but truthy checks force a bunch of comparisons + // we don't care about: it's never gonna be a number etc. + firstChild.key !== void 0 && firstChild.key !== "") { + seenKeys = /* @__PURE__ */ new Set(); + keyedChildren = getKeyedChildren(prev); + incomingKeyedChildren = getKeyedChildren(next); + } + for (const child of next.children) { + if (child.key !== void 0 && seenKeys !== null) { + while (prevChild && !incomingKeyedChildren.has(prevChild.getAttribute("data-lustre-key"))) { + const nextChild = prevChild.nextSibling; + el2.removeChild(prevChild); + prevChild = nextChild; + } + if (keyedChildren.size === 0) { + stack3.unshift({ prev: prevChild, next: child, parent: el2 }); + prevChild = prevChild?.nextSibling; + continue; + } + if (seenKeys.has(child.key)) { + console.warn(`Duplicate key found in Lustre vnode: ${child.key}`); + stack3.unshift({ prev: null, next: child, parent: el2 }); + continue; + } + seenKeys.add(child.key); + const keyedChild = keyedChildren.get(child.key); + if (!keyedChild && !prevChild) { + stack3.unshift({ prev: null, next: child, parent: el2 }); + continue; + } + if (!keyedChild && prevChild !== null) { + const placeholder = document.createTextNode(""); + el2.insertBefore(placeholder, prevChild); + stack3.unshift({ prev: placeholder, next: child, parent: el2 }); + continue; + } + if (!keyedChild || keyedChild === prevChild) { + stack3.unshift({ prev: prevChild, next: child, parent: el2 }); + prevChild = prevChild?.nextSibling; + continue; + } + el2.insertBefore(keyedChild, prevChild); + stack3.unshift({ prev: keyedChild, next: child, parent: el2 }); + } else { + stack3.unshift({ prev: prevChild, next: child, parent: el2 }); + prevChild = prevChild?.nextSibling; + } + } + while (prevChild) { + const next2 = prevChild.nextSibling; + el2.removeChild(prevChild); + prevChild = next2; + } + return el2; +} +var registeredHandlers = /* @__PURE__ */ new WeakMap(); +function lustreGenericEventHandler(event2) { + const target = event2.currentTarget; + if (!registeredHandlers.has(target)) { + target.removeEventListener(event2.type, lustreGenericEventHandler); + return; + } + const handlersForEventTarget = registeredHandlers.get(target); + if (!handlersForEventTarget.has(event2.type)) { + target.removeEventListener(event2.type, lustreGenericEventHandler); + return; + } + handlersForEventTarget.get(event2.type)(event2); +} +function lustreServerEventHandler(event2) { + const el2 = event2.target; + const tag2 = el2.getAttribute(`data-lustre-on-${event2.type}`); + const data = JSON.parse(el2.getAttribute("data-lustre-data") || "{}"); + const include = JSON.parse(el2.getAttribute("data-lustre-include") || "[]"); + switch (event2.type) { + case "input": + case "change": + include.push("target.value"); + break; + } + return { + tag: tag2, + data: include.reduce( + (data2, property) => { + const path = property.split("."); + for (let i = 0, o = data2, e = event2; i < path.length; i++) { + if (i === path.length - 1) { + o[path[i]] = e[path[i]]; + } else { + o[path[i]] ??= {}; + e = e[path[i]]; + o = o[path[i]]; + } + } + return data2; + }, + { data } + ) + }; +} +function getKeyedChildren(el2) { + const keyedChildren = /* @__PURE__ */ new Map(); + if (el2) { + for (const child of el2.children) { + const key = child.key || child?.getAttribute("data-lustre-key"); + if (key) + keyedChildren.set(key, child); + } + } + return keyedChildren; +} + +// build/dev/javascript/lustre/client-runtime.ffi.mjs +var LustreClientApplication2 = class _LustreClientApplication { + #root = null; + #queue = []; + #effects = []; + #didUpdate = false; + #isComponent = false; + #model = null; + #update = null; + #view = null; + static start(flags, selector, init3, update3, view2) { + if (!is_browser()) + return new Error(new NotABrowser()); + const root2 = selector instanceof HTMLElement ? selector : document.querySelector(selector); + if (!root2) + return new Error(new ElementNotFound(selector)); + const app = new _LustreClientApplication(init3(flags), update3, view2, root2); + return new Ok((msg) => app.send(msg)); + } + constructor([model, effects], update3, view2, root2 = document.body, isComponent = false) { + this.#model = model; + this.#update = update3; + this.#view = view2; + this.#root = root2; + this.#effects = effects.all.toArray(); + this.#didUpdate = true; + this.#isComponent = isComponent; + window.requestAnimationFrame(() => this.#tick()); + } + send(action) { + switch (true) { + case action instanceof Dispatch: { + this.#queue.push(action[0]); + this.#tick(); + return; + } + case action instanceof Shutdown: { + this.#shutdown(); + return; + } + default: + return; + } + } + emit(event2, data) { + this.#root.dispatchEvent( + new CustomEvent(event2, { + bubbles: true, + detail: data, + composed: true + }) + ); + } + #tick() { + this.#flush_queue(); + const vdom = this.#view(this.#model); + const dispatch = (handler) => (e) => { + const result = handler(e); + if (result instanceof Ok) { + this.send(new Dispatch(result[0])); + } + }; + this.#didUpdate = false; + this.#root = morph(this.#root, vdom, dispatch, this.#isComponent); + } + #flush_queue(iterations = 0) { + while (this.#queue.length) { + const [next, effects] = this.#update(this.#model, this.#queue.shift()); + this.#didUpdate ||= !isEqual(this.#model, next); + this.#model = next; + this.#effects = this.#effects.concat(effects.all.toArray()); + } + while (this.#effects.length) { + this.#effects.shift()( + (msg) => this.send(new Dispatch(msg)), + (event2, data) => this.emit(event2, data) + ); + } + if (this.#queue.length) { + if (iterations < 5) { + this.#flush_queue(++iterations); + } else { + window.requestAnimationFrame(() => this.#tick()); + } + } + } + #shutdown() { + this.#root.remove(); + this.#root = null; + this.#model = null; + this.#queue = []; + this.#effects = []; + this.#didUpdate = false; + this.#update = () => { + }; + this.#view = () => { + }; + } +}; +var start = (app, selector, flags) => LustreClientApplication2.start( + flags, + selector, + app.init, + app.update, + app.view +); +var is_browser = () => window && window.document; + +// build/dev/javascript/lustre/lustre.mjs +var App = class extends CustomType { + constructor(init3, update3, view2, on_attribute_change) { + super(); + this.init = init3; + this.update = update3; + this.view = view2; + this.on_attribute_change = on_attribute_change; + } +}; +var ElementNotFound = class extends CustomType { + constructor(selector) { + super(); + this.selector = selector; + } +}; +var NotABrowser = class extends CustomType { +}; +function application(init3, update3, view2) { + return new App(init3, update3, view2, new None()); +} +function simple(init3, update3, view2) { + let init$1 = (flags) => { + return [init3(flags), none()]; + }; + let update$1 = (model, msg) => { + return [update3(model, msg), none()]; + }; + return application(init$1, update$1, view2); +} +function start3(app, selector, flags) { + return guard( + !is_browser(), + new Error(new NotABrowser()), + () => { + return start(app, selector, flags); + } + ); +} + +// build/dev/javascript/lustre/lustre/element/html.mjs +function div(attrs, children) { + return element("div", attrs, children); +} +function p(attrs, children) { + return element("p", attrs, children); +} +function button(attrs, children) { + return element("button", attrs, children); +} + +// build/dev/javascript/lustre/lustre/event.mjs +function on2(name, handler) { + return on(name, handler); +} +function on_click(msg) { + return on2("click", (_) => { + return new Ok(msg); + }); +} + +// build/dev/javascript/lustre_ui/lustre/ui/button.mjs +function button2(attributes, children) { + return button( + prepend( + class$("lustre-ui-button"), + prepend(type_("button"), attributes) + ), + children + ); +} + +// build/dev/javascript/lustre_ui/lustre/ui/layout/stack.mjs +function of(element2, attributes, children) { + return element2( + prepend(class$("lustre-ui-stack"), attributes), + children + ); +} +function stack(attributes, children) { + return of(div, attributes, children); +} + +// build/dev/javascript/lustre_ui/lustre/ui/layout/centre.mjs +function of2(element2, attributes, children) { + return element2( + prepend(class$("lustre-ui-centre"), attributes), + toList([children]) + ); +} +function centre(attributes, children) { + return of2(div, attributes, children); +} + +// build/dev/javascript/gleam_community_colour/gleam_community/colour.mjs +var Rgba = class extends CustomType { + constructor(r, g, b, a) { + super(); + this.r = r; + this.g = g; + this.b = b; + this.a = a; + } +}; +var light_red = new Rgba( + 0.9372549019607843, + 0.1607843137254902, + 0.1607843137254902, + 1 +); +var red = new Rgba(0.8, 0, 0, 1); +var dark_red = new Rgba(0.6431372549019608, 0, 0, 1); +var light_orange = new Rgba( + 0.9882352941176471, + 0.6862745098039216, + 0.24313725490196078, + 1 +); +var orange = new Rgba(0.9607843137254902, 0.4745098039215686, 0, 1); +var dark_orange = new Rgba( + 0.807843137254902, + 0.3607843137254902, + 0, + 1 +); +var light_yellow = new Rgba( + 1, + 0.9137254901960784, + 0.30980392156862746, + 1 +); +var yellow = new Rgba(0.9294117647058824, 0.8313725490196079, 0, 1); +var dark_yellow = new Rgba( + 0.7686274509803922, + 0.6274509803921569, + 0, + 1 +); +var light_green = new Rgba( + 0.5411764705882353, + 0.8862745098039215, + 0.20392156862745098, + 1 +); +var green = new Rgba( + 0.45098039215686275, + 0.8235294117647058, + 0.08627450980392157, + 1 +); +var dark_green = new Rgba( + 0.3058823529411765, + 0.6039215686274509, + 0.023529411764705882, + 1 +); +var light_blue = new Rgba( + 0.4470588235294118, + 0.6235294117647059, + 0.8117647058823529, + 1 +); +var blue = new Rgba( + 0.20392156862745098, + 0.396078431372549, + 0.6431372549019608, + 1 +); +var dark_blue = new Rgba( + 0.12549019607843137, + 0.2901960784313726, + 0.5294117647058824, + 1 +); +var light_purple = new Rgba( + 0.6784313725490196, + 0.4980392156862745, + 0.6588235294117647, + 1 +); +var purple = new Rgba( + 0.4588235294117647, + 0.3137254901960784, + 0.4823529411764706, + 1 +); +var dark_purple = new Rgba( + 0.3607843137254902, + 0.20784313725490197, + 0.4, + 1 +); +var light_brown = new Rgba( + 0.9137254901960784, + 0.7254901960784313, + 0.43137254901960786, + 1 +); +var brown = new Rgba( + 0.7568627450980392, + 0.49019607843137253, + 0.06666666666666667, + 1 +); +var dark_brown = new Rgba( + 0.5607843137254902, + 0.34901960784313724, + 0.00784313725490196, + 1 +); +var black = new Rgba(0, 0, 0, 1); +var white = new Rgba(1, 1, 1, 1); +var light_grey = new Rgba( + 0.9333333333333333, + 0.9333333333333333, + 0.9254901960784314, + 1 +); +var grey = new Rgba( + 0.8274509803921568, + 0.8431372549019608, + 0.8117647058823529, + 1 +); +var dark_grey = new Rgba( + 0.7294117647058823, + 0.7411764705882353, + 0.7137254901960784, + 1 +); +var light_gray = new Rgba( + 0.9333333333333333, + 0.9333333333333333, + 0.9254901960784314, + 1 +); +var gray = new Rgba( + 0.8274509803921568, + 0.8431372549019608, + 0.8117647058823529, + 1 +); +var dark_gray = new Rgba( + 0.7294117647058823, + 0.7411764705882353, + 0.7137254901960784, + 1 +); +var light_charcoal = new Rgba( + 0.5333333333333333, + 0.5411764705882353, + 0.5215686274509804, + 1 +); +var charcoal = new Rgba( + 0.3333333333333333, + 0.3411764705882353, + 0.3254901960784314, + 1 +); +var dark_charcoal = new Rgba( + 0.1803921568627451, + 0.20392156862745098, + 0.21176470588235294, + 1 +); +var pink = new Rgba(1, 0.6862745098039216, 0.9529411764705882, 1); + +// build/dev/javascript/lustre_ui/lustre/ui.mjs +var button3 = button2; +var centre2 = centre; +var stack2 = stack; + +// build/dev/javascript/app/app.mjs +var Incr = class extends CustomType { +}; +var Decr = class extends CustomType { +}; +function init2(initial_count) { + let $ = initial_count < 0; + if ($) { + return 0; + } else { + return initial_count; + } +} +function update2(model, msg) { + if (msg instanceof Incr) { + return model + 1; + } else { + return model - 1; + } +} +function view(model) { + let styles = toList([ + ["width", "100vw"], + ["height", "100vh"], + ["padding", "1rem"] + ]); + let count = to_string(model); + return centre2( + toList([style(styles)]), + stack2( + toList([]), + toList([ + button3( + toList([on_click(new Incr())]), + toList([text("+")]) + ), + p( + toList([style(toList([["text-align", "center"]]))]), + toList([text(count)]) + ), + button3( + toList([on_click(new Decr())]), + toList([text("-")]) + ) + ]) + ) + ); +} +function main() { + let app = simple(init2, update2, view); + let $ = start3(app, "#app", 0); + if (!$.isOk()) { + throw makeError( + "assignment_no_match", + "app", + 13, + "main", + "Assignment pattern did not match", + { value: $ } + ); + } + return void 0; +} + +// build/.lustre/entry.mjs +main(); diff --git a/examples/02-interactivity/src/app.gleam b/examples/02-interactivity/src/app.gleam index 7bf9c25..6e69048 100644 --- a/examples/02-interactivity/src/app.gleam +++ b/examples/02-interactivity/src/app.gleam @@ -4,14 +4,6 @@ import lustre/attribute import lustre/element.{type Element} import lustre/element/html import lustre/event -// These examples are written with `lustre/ui` in mind. They'll work regardless, -// but to see what `lustre/ui` can do make sure to run each of these examples with -// the `--use-example-styles` flag: -// -// $ gleam run -m lustre/dev start --use-example-styles -// -// In your own apps, make sure to add the `lustre/ui` dependency and include the -// stylesheet somewhere. import lustre/ui // MAIN ------------------------------------------------------------------------ @@ -19,6 +11,8 @@ import lustre/ui pub fn main() { let app = lustre.simple(init, update, view) let assert Ok(_) = lustre.start(app, "#app", 0) + + Nil } // MODEL ----------------------------------------------------------------------- diff --git a/examples/03-controlled-inputs/index.html b/examples/03-controlled-inputs/index.html new file mode 100644 index 0000000..36ddf10 --- /dev/null +++ b/examples/03-controlled-inputs/index.html @@ -0,0 +1,19 @@ +<!doctype html> +<html lang="en"> + <head> + <meta charset="UTF-8" /> + <meta name="viewport" content="width=device-width, initial-scale=1.0" /> + + <title>🚧 app</title> + + <link + rel="stylesheet" + href="./build/dev/javascript/lustre_ui/priv/static/lustre-ui.css" + /> + <script type="module" src="./priv/static/app.mjs"></script> + </head> + + <body> + <div id="app"></div> + </body> +</html> diff --git a/examples/03-controlled-inputs/manifest.toml b/examples/03-controlled-inputs/manifest.toml index 7f82909..c0d1211 100644 --- a/examples/03-controlled-inputs/manifest.toml +++ b/examples/03-controlled-inputs/manifest.toml @@ -3,26 +3,39 @@ packages = [ { name = "argv", version = "1.0.2", build_tools = ["gleam"], requirements = [], otp_app = "argv", source = "hex", outer_checksum = "BA1FF0929525DEBA1CE67256E5ADF77A7CDDFE729E3E3F57A5BDCAA031DED09D" }, + { name = "birl", version = "1.6.1", build_tools = ["gleam"], requirements = ["gleam_stdlib", "ranger"], otp_app = "birl", source = "hex", outer_checksum = "976CFF85D34D50F7775896615A71745FBE0C325E50399787088F941B539A0497" }, + { name = "exception", version = "2.0.0", build_tools = ["gleam"], requirements = ["gleam_stdlib"], otp_app = "exception", source = "hex", outer_checksum = "F5580D584F16A20B7FCDCABF9E9BE9A2C1F6AC4F9176FA6DD0B63E3B20D450AA" }, { name = "filepath", version = "1.0.0", build_tools = ["gleam"], requirements = ["gleam_stdlib"], otp_app = "filepath", source = "hex", outer_checksum = "EFB6FF65C98B2A16378ABC3EE2B14124168C0CE5201553DE652E2644DCFDB594" }, + { name = "filespy", version = "0.3.0", build_tools = ["gleam"], requirements = ["fs", "gleam_erlang", "gleam_otp", "gleam_stdlib"], otp_app = "filespy", source = "hex", outer_checksum = "75F5910B31A528681D25316AAAE6C91CD3E977BD2492946564B7242FF941FB7A" }, + { name = "fs", version = "8.6.1", build_tools = ["rebar3"], requirements = [], otp_app = "fs", source = "hex", outer_checksum = "61EA2BDAEDAE4E2024D0D25C63E44DCCF65622D4402DB4A2DF12868D1546503F" }, { name = "gleam_community_ansi", version = "1.4.0", build_tools = ["gleam"], requirements = ["gleam_community_colour", "gleam_stdlib"], otp_app = "gleam_community_ansi", source = "hex", outer_checksum = "FE79E08BF97009729259B6357EC058315B6FBB916FAD1C2FF9355115FEB0D3A4" }, { name = "gleam_community_colour", version = "1.4.0", build_tools = ["gleam"], requirements = ["gleam_json", "gleam_stdlib"], otp_app = "gleam_community_colour", source = "hex", outer_checksum = "795964217EBEDB3DA656F5EB8F67D7AD22872EB95182042D3E7AFEF32D3FD2FE" }, + { name = "gleam_crypto", version = "1.3.0", build_tools = ["gleam"], requirements = ["gleam_stdlib"], otp_app = "gleam_crypto", source = "hex", outer_checksum = "ADD058DEDE8F0341F1ADE3AAC492A224F15700829D9A3A3F9ADF370F875C51B7" }, { name = "gleam_erlang", version = "0.25.0", build_tools = ["gleam"], requirements = ["gleam_stdlib"], otp_app = "gleam_erlang", source = "hex", outer_checksum = "054D571A7092D2A9727B3E5D183B7507DAB0DA41556EC9133606F09C15497373" }, + { name = "gleam_http", version = "3.6.0", build_tools = ["gleam"], requirements = ["gleam_stdlib"], otp_app = "gleam_http", source = "hex", outer_checksum = "8C07DF9DF8CC7F054C650839A51C30A7D3C26482AC241C899C1CEA86B22DBE51" }, { name = "gleam_json", version = "1.0.0", build_tools = ["gleam"], requirements = ["gleam_stdlib", "thoas"], otp_app = "gleam_json", source = "hex", outer_checksum = "8B197DD5D578EA6AC2C0D4BDC634C71A5BCA8E7DB5F47091C263ECB411A60DF3" }, { name = "gleam_otp", version = "0.10.0", build_tools = ["gleam"], requirements = ["gleam_erlang", "gleam_stdlib"], otp_app = "gleam_otp", source = "hex", outer_checksum = "0B04FE915ACECE539B317F9652CAADBBC0F000184D586AAAF2D94C100945D72B" }, { name = "gleam_package_interface", version = "1.0.0", build_tools = ["gleam"], requirements = ["gleam_json", "gleam_stdlib"], otp_app = "gleam_package_interface", source = "hex", outer_checksum = "52A721BCA972C8099BB881195D821AAA64B9F2655BECC102165D5A1097731F01" }, { name = "gleam_stdlib", version = "0.36.0", build_tools = ["gleam"], requirements = [], otp_app = "gleam_stdlib", source = "hex", outer_checksum = "C0D14D807FEC6F8A08A7C9EF8DFDE6AE5C10E40E21325B2B29365965D82EB3D4" }, { name = "glearray", version = "0.2.1", build_tools = ["gleam"], requirements = ["gleam_stdlib"], otp_app = "glearray", source = "hex", outer_checksum = "908154F695D330E06A37FAB2C04119E8F315D643206F8F32B6A6C14A8709FFF4" }, - { name = "gleeunit", version = "1.0.2", build_tools = ["gleam"], requirements = ["gleam_stdlib"], otp_app = "gleeunit", source = "hex", outer_checksum = "D364C87AFEB26BDB4FB8A5ABDE67D635DC9FA52D6AB68416044C35B096C6882D" }, + { name = "gleeunit", version = "1.1.2", build_tools = ["gleam"], requirements = ["gleam_stdlib"], otp_app = "gleeunit", source = "hex", outer_checksum = "72CDC3D3F719478F26C4E2C5FED3E657AC81EC14A47D2D2DEBB8693CA3220C3B" }, { name = "glint", version = "0.18.0", build_tools = ["gleam"], requirements = ["gleam_community_ansi", "gleam_community_colour", "gleam_stdlib", "snag"], otp_app = "glint", source = "hex", outer_checksum = "BB0F14643CC51C069A5DC6E9082EAFCD9967AFD1C9CC408803D1A40A3FD43B54" }, - { name = "lustre", version = "4.0.0", build_tools = ["gleam"], requirements = ["gleam_erlang", "gleam_json", "gleam_otp", "gleam_stdlib"], otp_app = "lustre", source = "hex", outer_checksum = "1D40C1378279F7015687F8C9DB739D6880BB0B843F4428B85C61EDDA8BF21FC6" }, - { name = "lustre_dev_tools", version = "1.0.0", build_tools = ["gleam"], requirements = ["argv", "filepath", "gleam_community_ansi", "gleam_erlang", "gleam_json", "gleam_otp", "gleam_package_interface", "gleam_stdlib", "glint", "simplifile", "spinner", "tom"], otp_app = "lustre_dev_tools", source = "hex", outer_checksum = "66142ADDCA3D6C63A89E016CF6C21E07D06D6DC92479325182A07C360BD026D3" }, - { name = "lustre_ui", version = "0.5.0", build_tools = ["gleam"], requirements = ["gleam_community_colour", "gleam_json", "gleam_stdlib", "lustre"], otp_app = "lustre_ui", source = "hex", outer_checksum = "7ECB5414BE926082401891C62FAAA21221FC0B7A2F0568A492349F48DC2B02A0" }, + { name = "glisten", version = "2.0.0", build_tools = ["gleam"], requirements = ["gleam_erlang", "gleam_otp", "gleam_stdlib"], otp_app = "glisten", source = "hex", outer_checksum = "CF3A9383E9BA4A8CBAF2F7B799716290D02F2AC34E7A77556B49376B662B9314" }, + { name = "hpack_erl", version = "0.3.0", build_tools = ["rebar3"], requirements = [], otp_app = "hpack", source = "hex", outer_checksum = "D6137D7079169D8C485C6962DFE261AF5B9EF60FBC557344511C1E65E3D95FB0" }, + { name = "logging", version = "1.0.1", build_tools = ["gleam"], requirements = ["gleam_stdlib"], otp_app = "logging", source = "hex", outer_checksum = "82C112ED9B6C30C1772A6FE2613B94B13F62EA35F5869A2630D13948D297BD39" }, + { name = "lustre", version = "4.1.7", build_tools = ["gleam"], requirements = ["gleam_erlang", "gleam_json", "gleam_otp", "gleam_stdlib"], otp_app = "lustre", source = "hex", outer_checksum = "64F5D7E4DF51280185F70296ACB7D3DCC9B5DA09EFC5257F0E5601846DFBEF23" }, + { name = "lustre_dev_tools", version = "1.2.1", build_tools = ["gleam"], requirements = ["argv", "filepath", "filespy", "fs", "gleam_community_ansi", "gleam_erlang", "gleam_http", "gleam_json", "gleam_otp", "gleam_package_interface", "gleam_stdlib", "glint", "glisten", "mist", "simplifile", "spinner", "tom", "wisp"], otp_app = "lustre_dev_tools", source = "hex", outer_checksum = "930BBE8C4E92A16857C31B7B12616651433E1643304696FB93B69D659CE3ADC2" }, + { name = "lustre_ui", version = "0.6.0", build_tools = ["gleam"], requirements = ["gleam_community_colour", "gleam_json", "gleam_stdlib", "lustre"], otp_app = "lustre_ui", source = "hex", outer_checksum = "FA1F9E89D89CDD5DF376ED86ABA8A38441CB2E664CD4D402F22A49DA4D7BB56D" }, + { name = "marceau", version = "1.1.0", build_tools = ["gleam"], requirements = [], otp_app = "marceau", source = "hex", outer_checksum = "1AAD727A30BE0F95562C3403BB9B27C823797AD90037714255EEBF617B1CDA81" }, + { name = "mist", version = "1.0.0", build_tools = ["gleam"], requirements = ["birl", "gleam_erlang", "gleam_http", "gleam_otp", "gleam_stdlib", "glisten", "hpack_erl", "logging"], otp_app = "mist", source = "hex", outer_checksum = "7765E53DCC9ACCACF217B8E0CA3DE7E848C783BFAE5118B75011E81C2C80385C" }, + { name = "ranger", version = "1.2.0", build_tools = ["gleam"], requirements = ["gleam_stdlib"], otp_app = "ranger", source = "hex", outer_checksum = "1566C272B1D141B3BBA38B25CB761EF56E312E79EC0E2DFD4D3C19FB0CC1F98C" }, { name = "repeatedly", version = "2.1.1", build_tools = ["gleam"], requirements = [], otp_app = "repeatedly", source = "hex", outer_checksum = "38808C3EC382B0CD981336D5879C24ECB37FCB9C1D1BD128F7A80B0F74404D79" }, - { name = "simplifile", version = "1.5.1", build_tools = ["gleam"], requirements = ["gleam_stdlib"], otp_app = "simplifile", source = "hex", outer_checksum = "C44DB387524F90DC42142699C78C850003289D32C7C99C7D32873792A299CDF7" }, + { name = "simplifile", version = "1.7.0", build_tools = ["gleam"], requirements = ["filepath", "gleam_stdlib"], otp_app = "simplifile", source = "hex", outer_checksum = "1D5DFA3A2F9319EC85825F6ED88B8E449F381B0D55A62F5E61424E748E7DDEB0" }, { name = "snag", version = "0.3.0", build_tools = ["gleam"], requirements = ["gleam_stdlib"], otp_app = "snag", source = "hex", outer_checksum = "54D32E16E33655346AA3E66CBA7E191DE0A8793D2C05284E3EFB90AD2CE92BCC" }, { name = "spinner", version = "1.1.0", build_tools = ["gleam"], requirements = ["gleam_community_ansi", "gleam_erlang", "gleam_stdlib", "glearray", "repeatedly"], otp_app = "spinner", source = "hex", outer_checksum = "200BA3D4A04D468898E63C0D316E23F526E02514BC46454091975CB5BAE41E8F" }, { name = "thoas", version = "0.4.1", build_tools = ["rebar3"], requirements = [], otp_app = "thoas", source = "hex", outer_checksum = "4918D50026C073C4AB1388437132C77A6F6F7C8AC43C60C13758CC0ADCE2134E" }, { name = "tom", version = "0.3.0", build_tools = ["gleam"], requirements = ["gleam_stdlib"], otp_app = "tom", source = "hex", outer_checksum = "0831C73E45405A2153091226BF98FB485ED16376988602CC01A5FD086B82D577" }, + { name = "wisp", version = "0.14.0", build_tools = ["gleam"], requirements = ["exception", "gleam_crypto", "gleam_erlang", "gleam_http", "gleam_json", "gleam_stdlib", "logging", "marceau", "mist", "simplifile"], otp_app = "wisp", source = "hex", outer_checksum = "9F5453AF1F9275E6F8707BC815D6A6A9DF41551921B16FBDBA52883773BAE684" }, ] [requirements] diff --git a/examples/03-controlled-inputs/priv/static/app.mjs b/examples/03-controlled-inputs/priv/static/app.mjs new file mode 100644 index 0000000..9fdf4b2 --- /dev/null +++ b/examples/03-controlled-inputs/priv/static/app.mjs @@ -0,0 +1,2139 @@ +// build/dev/javascript/prelude.mjs +var CustomType = class { + withFields(fields) { + let properties = Object.keys(this).map( + (label2) => label2 in fields ? fields[label2] : this[label2] + ); + return new this.constructor(...properties); + } +}; +var List = class { + static fromArray(array3, tail) { + let t = tail || new Empty(); + for (let i = array3.length - 1; i >= 0; --i) { + t = new NonEmpty(array3[i], t); + } + return t; + } + [Symbol.iterator]() { + return new ListIterator(this); + } + toArray() { + return [...this]; + } + // @internal + atLeastLength(desired) { + for (let _ of this) { + if (desired <= 0) + return true; + desired--; + } + return desired <= 0; + } + // @internal + hasLength(desired) { + for (let _ of this) { + if (desired <= 0) + return false; + desired--; + } + return desired === 0; + } + countLength() { + let length3 = 0; + for (let _ of this) + length3++; + return length3; + } +}; +function prepend(element2, tail) { + return new NonEmpty(element2, tail); +} +function toList(elements, tail) { + return List.fromArray(elements, tail); +} +var ListIterator = class { + #current; + constructor(current) { + this.#current = current; + } + next() { + if (this.#current instanceof Empty) { + return { done: true }; + } else { + let { head, tail } = this.#current; + this.#current = tail; + return { value: head, done: false }; + } + } +}; +var Empty = class extends List { +}; +var NonEmpty = class extends List { + constructor(head, tail) { + super(); + this.head = head; + this.tail = tail; + } +}; +var BitArray = class _BitArray { + constructor(buffer) { + if (!(buffer instanceof Uint8Array)) { + throw "BitArray can only be constructed from a Uint8Array"; + } + this.buffer = buffer; + } + // @internal + get length() { + return this.buffer.length; + } + // @internal + byteAt(index2) { + return this.buffer[index2]; + } + // @internal + floatAt(index2) { + return byteArrayToFloat(this.buffer.slice(index2, index2 + 8)); + } + // @internal + intFromSlice(start4, end) { + return byteArrayToInt(this.buffer.slice(start4, end)); + } + // @internal + binaryFromSlice(start4, end) { + return new _BitArray(this.buffer.slice(start4, end)); + } + // @internal + sliceAfter(index2) { + return new _BitArray(this.buffer.slice(index2)); + } +}; +function byteArrayToInt(byteArray) { + byteArray = byteArray.reverse(); + let value3 = 0; + for (let i = byteArray.length - 1; i >= 0; i--) { + value3 = value3 * 256 + byteArray[i]; + } + return value3; +} +function byteArrayToFloat(byteArray) { + return new Float64Array(byteArray.reverse().buffer)[0]; +} +var Result = class _Result extends CustomType { + // @internal + static isResult(data) { + return data instanceof _Result; + } +}; +var Ok = class extends Result { + constructor(value3) { + super(); + this[0] = value3; + } + // @internal + isOk() { + return true; + } +}; +var Error = class extends Result { + constructor(detail) { + super(); + this[0] = detail; + } + // @internal + isOk() { + return false; + } +}; +function isEqual(x, y) { + let values = [x, y]; + while (values.length) { + let a = values.pop(); + let b = values.pop(); + if (a === b) + continue; + if (!isObject(a) || !isObject(b)) + return false; + let unequal = !structurallyCompatibleObjects(a, b) || unequalDates(a, b) || unequalBuffers(a, b) || unequalArrays(a, b) || unequalMaps(a, b) || unequalSets(a, b) || unequalRegExps(a, b); + if (unequal) + return false; + const proto = Object.getPrototypeOf(a); + if (proto !== null && typeof proto.equals === "function") { + try { + if (a.equals(b)) + continue; + else + return false; + } catch { + } + } + let [keys2, get2] = getters(a); + for (let k of keys2(a)) { + values.push(get2(a, k), get2(b, k)); + } + } + return true; +} +function getters(object3) { + if (object3 instanceof Map) { + return [(x) => x.keys(), (x, y) => x.get(y)]; + } else { + let extra = object3 instanceof globalThis.Error ? ["message"] : []; + return [(x) => [...extra, ...Object.keys(x)], (x, y) => x[y]]; + } +} +function unequalDates(a, b) { + return a instanceof Date && (a > b || a < b); +} +function unequalBuffers(a, b) { + return a.buffer instanceof ArrayBuffer && a.BYTES_PER_ELEMENT && !(a.byteLength === b.byteLength && a.every((n, i) => n === b[i])); +} +function unequalArrays(a, b) { + return Array.isArray(a) && a.length !== b.length; +} +function unequalMaps(a, b) { + return a instanceof Map && a.size !== b.size; +} +function unequalSets(a, b) { + return a instanceof Set && (a.size != b.size || [...a].some((e) => !b.has(e))); +} +function unequalRegExps(a, b) { + return a instanceof RegExp && (a.source !== b.source || a.flags !== b.flags); +} +function isObject(a) { + return typeof a === "object" && a !== null; +} +function structurallyCompatibleObjects(a, b) { + if (typeof a !== "object" && typeof b !== "object" && (!a || !b)) + return false; + let nonstructural = [Promise, WeakSet, WeakMap, Function]; + if (nonstructural.some((c) => a instanceof c)) + return false; + return a.constructor === b.constructor; +} +function makeError(variant, module, line, fn, message, extra) { + let error = new globalThis.Error(message); + error.gleam_error = variant; + error.module = module; + error.line = line; + error.fn = fn; + for (let k in extra) + error[k] = extra[k]; + return error; +} + +// build/dev/javascript/gleam_stdlib/gleam/option.mjs +var Some = class extends CustomType { + constructor(x0) { + super(); + this[0] = x0; + } +}; +var None = class extends CustomType { +}; +function to_result(option, e) { + if (option instanceof Some) { + let a = option[0]; + return new Ok(a); + } else { + return new Error(e); + } +} + +// build/dev/javascript/gleam_stdlib/gleam/list.mjs +function do_reverse_acc(loop$remaining, loop$accumulator) { + while (true) { + let remaining = loop$remaining; + let accumulator = loop$accumulator; + if (remaining.hasLength(0)) { + return accumulator; + } else { + let item = remaining.head; + let rest$1 = remaining.tail; + loop$remaining = rest$1; + loop$accumulator = prepend(item, accumulator); + } + } +} +function do_reverse(list) { + return do_reverse_acc(list, toList([])); +} +function reverse(xs) { + return do_reverse(xs); +} +function do_map(loop$list, loop$fun, loop$acc) { + while (true) { + let list = loop$list; + let fun = loop$fun; + let acc = loop$acc; + if (list.hasLength(0)) { + return reverse(acc); + } else { + let x = list.head; + let xs = list.tail; + loop$list = xs; + loop$fun = fun; + loop$acc = prepend(fun(x), acc); + } + } +} +function map(list, fun) { + return do_map(list, fun, toList([])); +} +function fold(loop$list, loop$initial, loop$fun) { + while (true) { + let list = loop$list; + let initial = loop$initial; + let fun = loop$fun; + if (list.hasLength(0)) { + return initial; + } else { + let x = list.head; + let rest$1 = list.tail; + loop$list = rest$1; + loop$initial = fun(initial, x); + loop$fun = fun; + } + } +} + +// build/dev/javascript/gleam_stdlib/gleam/result.mjs +function map2(result, fun) { + if (result.isOk()) { + let x = result[0]; + return new Ok(fun(x)); + } else { + let e = result[0]; + return new Error(e); + } +} +function map_error(result, fun) { + if (result.isOk()) { + let x = result[0]; + return new Ok(x); + } else { + let error = result[0]; + return new Error(fun(error)); + } +} +function try$(result, fun) { + if (result.isOk()) { + let x = result[0]; + return fun(x); + } else { + let e = result[0]; + return new Error(e); + } +} + +// build/dev/javascript/gleam_stdlib/gleam/string_builder.mjs +function from_strings(strings) { + return concat(strings); +} +function to_string(builder) { + return identity(builder); +} + +// build/dev/javascript/gleam_stdlib/gleam/dynamic.mjs +var DecodeError = class extends CustomType { + constructor(expected, found, path) { + super(); + this.expected = expected; + this.found = found; + this.path = path; + } +}; +function from(a) { + return identity(a); +} +function string(data) { + return decode_string(data); +} +function classify(data) { + return classify_dynamic(data); +} +function int(data) { + return decode_int(data); +} +function any(decoders) { + return (data) => { + if (decoders.hasLength(0)) { + return new Error( + toList([new DecodeError("another type", classify(data), toList([]))]) + ); + } else { + let decoder2 = decoders.head; + let decoders$1 = decoders.tail; + let $ = decoder2(data); + if ($.isOk()) { + let decoded = $[0]; + return new Ok(decoded); + } else { + return any(decoders$1)(data); + } + } + }; +} +function push_path(error, name) { + let name$1 = from(name); + let decoder2 = any( + toList([string, (x) => { + return map2(int(x), to_string2); + }]) + ); + let name$2 = (() => { + let $ = decoder2(name$1); + if ($.isOk()) { + let name$22 = $[0]; + return name$22; + } else { + let _pipe = toList(["<", classify(name$1), ">"]); + let _pipe$1 = from_strings(_pipe); + return to_string(_pipe$1); + } + })(); + return error.withFields({ path: prepend(name$2, error.path) }); +} +function map_errors(result, f) { + return map_error( + result, + (_capture) => { + return map(_capture, f); + } + ); +} +function field(name, inner_type) { + return (value3) => { + let missing_field_error = new DecodeError("field", "nothing", toList([])); + return try$( + decode_field(value3, name), + (maybe_inner) => { + let _pipe = maybe_inner; + let _pipe$1 = to_result(_pipe, toList([missing_field_error])); + let _pipe$2 = try$(_pipe$1, inner_type); + return map_errors( + _pipe$2, + (_capture) => { + return push_path(_capture, name); + } + ); + } + ); + }; +} + +// build/dev/javascript/gleam_stdlib/dict.mjs +var referenceMap = /* @__PURE__ */ new WeakMap(); +var tempDataView = new DataView(new ArrayBuffer(8)); +var referenceUID = 0; +function hashByReference(o) { + const known = referenceMap.get(o); + if (known !== void 0) { + return known; + } + const hash = referenceUID++; + if (referenceUID === 2147483647) { + referenceUID = 0; + } + referenceMap.set(o, hash); + return hash; +} +function hashMerge(a, b) { + return a ^ b + 2654435769 + (a << 6) + (a >> 2) | 0; +} +function hashString(s) { + let hash = 0; + const len = s.length; + for (let i = 0; i < len; i++) { + hash = Math.imul(31, hash) + s.charCodeAt(i) | 0; + } + return hash; +} +function hashNumber(n) { + tempDataView.setFloat64(0, n); + const i = tempDataView.getInt32(0); + const j = tempDataView.getInt32(4); + return Math.imul(73244475, i >> 16 ^ i) ^ j; +} +function hashBigInt(n) { + return hashString(n.toString()); +} +function hashObject(o) { + const proto = Object.getPrototypeOf(o); + if (proto !== null && typeof proto.hashCode === "function") { + try { + const code = o.hashCode(o); + if (typeof code === "number") { + return code; + } + } catch { + } + } + if (o instanceof Promise || o instanceof WeakSet || o instanceof WeakMap) { + return hashByReference(o); + } + if (o instanceof Date) { + return hashNumber(o.getTime()); + } + let h = 0; + if (o instanceof ArrayBuffer) { + o = new Uint8Array(o); + } + if (Array.isArray(o) || o instanceof Uint8Array) { + for (let i = 0; i < o.length; i++) { + h = Math.imul(31, h) + getHash(o[i]) | 0; + } + } else if (o instanceof Set) { + o.forEach((v) => { + h = h + getHash(v) | 0; + }); + } else if (o instanceof Map) { + o.forEach((v, k) => { + h = h + hashMerge(getHash(v), getHash(k)) | 0; + }); + } else { + const keys2 = Object.keys(o); + for (let i = 0; i < keys2.length; i++) { + const k = keys2[i]; + const v = o[k]; + h = h + hashMerge(getHash(v), hashString(k)) | 0; + } + } + return h; +} +function getHash(u) { + if (u === null) + return 1108378658; + if (u === void 0) + return 1108378659; + if (u === true) + return 1108378657; + if (u === false) + return 1108378656; + switch (typeof u) { + case "number": + return hashNumber(u); + case "string": + return hashString(u); + case "bigint": + return hashBigInt(u); + case "object": + return hashObject(u); + case "symbol": + return hashByReference(u); + case "function": + return hashByReference(u); + default: + return 0; + } +} +var SHIFT = 5; +var BUCKET_SIZE = Math.pow(2, SHIFT); +var MASK = BUCKET_SIZE - 1; +var MAX_INDEX_NODE = BUCKET_SIZE / 2; +var MIN_ARRAY_NODE = BUCKET_SIZE / 4; +var ENTRY = 0; +var ARRAY_NODE = 1; +var INDEX_NODE = 2; +var COLLISION_NODE = 3; +var EMPTY = { + type: INDEX_NODE, + bitmap: 0, + array: [] +}; +function mask(hash, shift) { + return hash >>> shift & MASK; +} +function bitpos(hash, shift) { + return 1 << mask(hash, shift); +} +function bitcount(x) { + x -= x >> 1 & 1431655765; + x = (x & 858993459) + (x >> 2 & 858993459); + x = x + (x >> 4) & 252645135; + x += x >> 8; + x += x >> 16; + return x & 127; +} +function index(bitmap, bit) { + return bitcount(bitmap & bit - 1); +} +function cloneAndSet(arr, at, val) { + const len = arr.length; + const out = new Array(len); + for (let i = 0; i < len; ++i) { + out[i] = arr[i]; + } + out[at] = val; + return out; +} +function spliceIn(arr, at, val) { + const len = arr.length; + const out = new Array(len + 1); + let i = 0; + let g = 0; + while (i < at) { + out[g++] = arr[i++]; + } + out[g++] = val; + while (i < len) { + out[g++] = arr[i++]; + } + return out; +} +function spliceOut(arr, at) { + const len = arr.length; + const out = new Array(len - 1); + let i = 0; + let g = 0; + while (i < at) { + out[g++] = arr[i++]; + } + ++i; + while (i < len) { + out[g++] = arr[i++]; + } + return out; +} +function createNode(shift, key1, val1, key2hash, key2, val2) { + const key1hash = getHash(key1); + if (key1hash === key2hash) { + return { + type: COLLISION_NODE, + hash: key1hash, + array: [ + { type: ENTRY, k: key1, v: val1 }, + { type: ENTRY, k: key2, v: val2 } + ] + }; + } + const addedLeaf = { val: false }; + return assoc( + assocIndex(EMPTY, shift, key1hash, key1, val1, addedLeaf), + shift, + key2hash, + key2, + val2, + addedLeaf + ); +} +function assoc(root2, shift, hash, key, val, addedLeaf) { + switch (root2.type) { + case ARRAY_NODE: + return assocArray(root2, shift, hash, key, val, addedLeaf); + case INDEX_NODE: + return assocIndex(root2, shift, hash, key, val, addedLeaf); + case COLLISION_NODE: + return assocCollision(root2, shift, hash, key, val, addedLeaf); + } +} +function assocArray(root2, shift, hash, key, val, addedLeaf) { + const idx = mask(hash, shift); + const node = root2.array[idx]; + if (node === void 0) { + addedLeaf.val = true; + return { + type: ARRAY_NODE, + size: root2.size + 1, + array: cloneAndSet(root2.array, idx, { type: ENTRY, k: key, v: val }) + }; + } + if (node.type === ENTRY) { + if (isEqual(key, node.k)) { + if (val === node.v) { + return root2; + } + return { + type: ARRAY_NODE, + size: root2.size, + array: cloneAndSet(root2.array, idx, { + type: ENTRY, + k: key, + v: val + }) + }; + } + addedLeaf.val = true; + return { + type: ARRAY_NODE, + size: root2.size, + array: cloneAndSet( + root2.array, + idx, + createNode(shift + SHIFT, node.k, node.v, hash, key, val) + ) + }; + } + const n = assoc(node, shift + SHIFT, hash, key, val, addedLeaf); + if (n === node) { + return root2; + } + return { + type: ARRAY_NODE, + size: root2.size, + array: cloneAndSet(root2.array, idx, n) + }; +} +function assocIndex(root2, shift, hash, key, val, addedLeaf) { + const bit = bitpos(hash, shift); + const idx = index(root2.bitmap, bit); + if ((root2.bitmap & bit) !== 0) { + const node = root2.array[idx]; + if (node.type !== ENTRY) { + const n = assoc(node, shift + SHIFT, hash, key, val, addedLeaf); + if (n === node) { + return root2; + } + return { + type: INDEX_NODE, + bitmap: root2.bitmap, + array: cloneAndSet(root2.array, idx, n) + }; + } + const nodeKey = node.k; + if (isEqual(key, nodeKey)) { + if (val === node.v) { + return root2; + } + return { + type: INDEX_NODE, + bitmap: root2.bitmap, + array: cloneAndSet(root2.array, idx, { + type: ENTRY, + k: key, + v: val + }) + }; + } + addedLeaf.val = true; + return { + type: INDEX_NODE, + bitmap: root2.bitmap, + array: cloneAndSet( + root2.array, + idx, + createNode(shift + SHIFT, nodeKey, node.v, hash, key, val) + ) + }; + } else { + const n = root2.array.length; + if (n >= MAX_INDEX_NODE) { + const nodes = new Array(32); + const jdx = mask(hash, shift); + nodes[jdx] = assocIndex(EMPTY, shift + SHIFT, hash, key, val, addedLeaf); + let j = 0; + let bitmap = root2.bitmap; + for (let i = 0; i < 32; i++) { + if ((bitmap & 1) !== 0) { + const node = root2.array[j++]; + nodes[i] = node; + } + bitmap = bitmap >>> 1; + } + return { + type: ARRAY_NODE, + size: n + 1, + array: nodes + }; + } else { + const newArray = spliceIn(root2.array, idx, { + type: ENTRY, + k: key, + v: val + }); + addedLeaf.val = true; + return { + type: INDEX_NODE, + bitmap: root2.bitmap | bit, + array: newArray + }; + } + } +} +function assocCollision(root2, shift, hash, key, val, addedLeaf) { + if (hash === root2.hash) { + const idx = collisionIndexOf(root2, key); + if (idx !== -1) { + const entry = root2.array[idx]; + if (entry.v === val) { + return root2; + } + return { + type: COLLISION_NODE, + hash, + array: cloneAndSet(root2.array, idx, { type: ENTRY, k: key, v: val }) + }; + } + const size = root2.array.length; + addedLeaf.val = true; + return { + type: COLLISION_NODE, + hash, + array: cloneAndSet(root2.array, size, { type: ENTRY, k: key, v: val }) + }; + } + return assoc( + { + type: INDEX_NODE, + bitmap: bitpos(root2.hash, shift), + array: [root2] + }, + shift, + hash, + key, + val, + addedLeaf + ); +} +function collisionIndexOf(root2, key) { + const size = root2.array.length; + for (let i = 0; i < size; i++) { + if (isEqual(key, root2.array[i].k)) { + return i; + } + } + return -1; +} +function find(root2, shift, hash, key) { + switch (root2.type) { + case ARRAY_NODE: + return findArray(root2, shift, hash, key); + case INDEX_NODE: + return findIndex(root2, shift, hash, key); + case COLLISION_NODE: + return findCollision(root2, key); + } +} +function findArray(root2, shift, hash, key) { + const idx = mask(hash, shift); + const node = root2.array[idx]; + if (node === void 0) { + return void 0; + } + if (node.type !== ENTRY) { + return find(node, shift + SHIFT, hash, key); + } + if (isEqual(key, node.k)) { + return node; + } + return void 0; +} +function findIndex(root2, shift, hash, key) { + const bit = bitpos(hash, shift); + if ((root2.bitmap & bit) === 0) { + return void 0; + } + const idx = index(root2.bitmap, bit); + const node = root2.array[idx]; + if (node.type !== ENTRY) { + return find(node, shift + SHIFT, hash, key); + } + if (isEqual(key, node.k)) { + return node; + } + return void 0; +} +function findCollision(root2, key) { + const idx = collisionIndexOf(root2, key); + if (idx < 0) { + return void 0; + } + return root2.array[idx]; +} +function without(root2, shift, hash, key) { + switch (root2.type) { + case ARRAY_NODE: + return withoutArray(root2, shift, hash, key); + case INDEX_NODE: + return withoutIndex(root2, shift, hash, key); + case COLLISION_NODE: + return withoutCollision(root2, key); + } +} +function withoutArray(root2, shift, hash, key) { + const idx = mask(hash, shift); + const node = root2.array[idx]; + if (node === void 0) { + return root2; + } + let n = void 0; + if (node.type === ENTRY) { + if (!isEqual(node.k, key)) { + return root2; + } + } else { + n = without(node, shift + SHIFT, hash, key); + if (n === node) { + return root2; + } + } + if (n === void 0) { + if (root2.size <= MIN_ARRAY_NODE) { + const arr = root2.array; + const out = new Array(root2.size - 1); + let i = 0; + let j = 0; + let bitmap = 0; + while (i < idx) { + const nv = arr[i]; + if (nv !== void 0) { + out[j] = nv; + bitmap |= 1 << i; + ++j; + } + ++i; + } + ++i; + while (i < arr.length) { + const nv = arr[i]; + if (nv !== void 0) { + out[j] = nv; + bitmap |= 1 << i; + ++j; + } + ++i; + } + return { + type: INDEX_NODE, + bitmap, + array: out + }; + } + return { + type: ARRAY_NODE, + size: root2.size - 1, + array: cloneAndSet(root2.array, idx, n) + }; + } + return { + type: ARRAY_NODE, + size: root2.size, + array: cloneAndSet(root2.array, idx, n) + }; +} +function withoutIndex(root2, shift, hash, key) { + const bit = bitpos(hash, shift); + if ((root2.bitmap & bit) === 0) { + return root2; + } + const idx = index(root2.bitmap, bit); + const node = root2.array[idx]; + if (node.type !== ENTRY) { + const n = without(node, shift + SHIFT, hash, key); + if (n === node) { + return root2; + } + if (n !== void 0) { + return { + type: INDEX_NODE, + bitmap: root2.bitmap, + array: cloneAndSet(root2.array, idx, n) + }; + } + if (root2.bitmap === bit) { + return void 0; + } + return { + type: INDEX_NODE, + bitmap: root2.bitmap ^ bit, + array: spliceOut(root2.array, idx) + }; + } + if (isEqual(key, node.k)) { + if (root2.bitmap === bit) { + return void 0; + } + return { + type: INDEX_NODE, + bitmap: root2.bitmap ^ bit, + array: spliceOut(root2.array, idx) + }; + } + return root2; +} +function withoutCollision(root2, key) { + const idx = collisionIndexOf(root2, key); + if (idx < 0) { + return root2; + } + if (root2.array.length === 1) { + return void 0; + } + return { + type: COLLISION_NODE, + hash: root2.hash, + array: spliceOut(root2.array, idx) + }; +} +function forEach(root2, fn) { + if (root2 === void 0) { + return; + } + const items = root2.array; + const size = items.length; + for (let i = 0; i < size; i++) { + const item = items[i]; + if (item === void 0) { + continue; + } + if (item.type === ENTRY) { + fn(item.v, item.k); + continue; + } + forEach(item, fn); + } +} +var Dict = class _Dict { + /** + * @template V + * @param {Record<string,V>} o + * @returns {Dict<string,V>} + */ + static fromObject(o) { + const keys2 = Object.keys(o); + let m = _Dict.new(); + for (let i = 0; i < keys2.length; i++) { + const k = keys2[i]; + m = m.set(k, o[k]); + } + return m; + } + /** + * @template K,V + * @param {Map<K,V>} o + * @returns {Dict<K,V>} + */ + static fromMap(o) { + let m = _Dict.new(); + o.forEach((v, k) => { + m = m.set(k, v); + }); + return m; + } + static new() { + return new _Dict(void 0, 0); + } + /** + * @param {undefined | Node<K,V>} root + * @param {number} size + */ + constructor(root2, size) { + this.root = root2; + this.size = size; + } + /** + * @template NotFound + * @param {K} key + * @param {NotFound} notFound + * @returns {NotFound | V} + */ + get(key, notFound) { + if (this.root === void 0) { + return notFound; + } + const found = find(this.root, 0, getHash(key), key); + if (found === void 0) { + return notFound; + } + return found.v; + } + /** + * @param {K} key + * @param {V} val + * @returns {Dict<K,V>} + */ + set(key, val) { + const addedLeaf = { val: false }; + const root2 = this.root === void 0 ? EMPTY : this.root; + const newRoot = assoc(root2, 0, getHash(key), key, val, addedLeaf); + if (newRoot === this.root) { + return this; + } + return new _Dict(newRoot, addedLeaf.val ? this.size + 1 : this.size); + } + /** + * @param {K} key + * @returns {Dict<K,V>} + */ + delete(key) { + if (this.root === void 0) { + return this; + } + const newRoot = without(this.root, 0, getHash(key), key); + if (newRoot === this.root) { + return this; + } + if (newRoot === void 0) { + return _Dict.new(); + } + return new _Dict(newRoot, this.size - 1); + } + /** + * @param {K} key + * @returns {boolean} + */ + has(key) { + if (this.root === void 0) { + return false; + } + return find(this.root, 0, getHash(key), key) !== void 0; + } + /** + * @returns {[K,V][]} + */ + entries() { + if (this.root === void 0) { + return []; + } + const result = []; + this.forEach((v, k) => result.push([k, v])); + return result; + } + /** + * + * @param {(val:V,key:K)=>void} fn + */ + forEach(fn) { + forEach(this.root, fn); + } + hashCode() { + let h = 0; + this.forEach((v, k) => { + h = h + hashMerge(getHash(v), getHash(k)) | 0; + }); + return h; + } + /** + * @param {unknown} o + * @returns {boolean} + */ + equals(o) { + if (!(o instanceof _Dict) || this.size !== o.size) { + return false; + } + let equal2 = true; + this.forEach((v, k) => { + equal2 = equal2 && isEqual(o.get(k, !v), v); + }); + return equal2; + } +}; + +// build/dev/javascript/gleam_stdlib/gleam_stdlib.mjs +var Nil = void 0; +var NOT_FOUND = {}; +function identity(x) { + return x; +} +function to_string3(term) { + return term.toString(); +} +function string_length(string3) { + if (string3 === "") { + return 0; + } + const iterator = graphemes_iterator(string3); + if (iterator) { + let i = 0; + for (const _ of iterator) { + i++; + } + return i; + } else { + return string3.match(/./gsu).length; + } +} +function graphemes_iterator(string3) { + if (Intl && Intl.Segmenter) { + return new Intl.Segmenter().segment(string3)[Symbol.iterator](); + } +} +function concat(xs) { + let result = ""; + for (const x of xs) { + result = result + x; + } + return result; +} +function map_get(map4, key) { + const value3 = map4.get(key, NOT_FOUND); + if (value3 === NOT_FOUND) { + return new Error(Nil); + } + return new Ok(value3); +} +function classify_dynamic(data) { + if (typeof data === "string") { + return "String"; + } else if (data instanceof Result) { + return "Result"; + } else if (data instanceof List) { + return "List"; + } else if (data instanceof BitArray) { + return "BitArray"; + } else if (data instanceof Dict) { + return "Dict"; + } else if (Number.isInteger(data)) { + return "Int"; + } else if (Array.isArray(data)) { + return `Tuple of ${data.length} elements`; + } else if (typeof data === "number") { + return "Float"; + } else if (data === null) { + return "Null"; + } else if (data === void 0) { + return "Nil"; + } else { + const type = typeof data; + return type.charAt(0).toUpperCase() + type.slice(1); + } +} +function decoder_error(expected, got) { + return decoder_error_no_classify(expected, classify_dynamic(got)); +} +function decoder_error_no_classify(expected, got) { + return new Error( + List.fromArray([new DecodeError(expected, got, List.fromArray([]))]) + ); +} +function decode_string(data) { + return typeof data === "string" ? new Ok(data) : decoder_error("String", data); +} +function decode_int(data) { + return Number.isInteger(data) ? new Ok(data) : decoder_error("Int", data); +} +function decode_field(value3, name) { + const not_a_map_error = () => decoder_error("Dict", value3); + if (value3 instanceof Dict || value3 instanceof WeakMap || value3 instanceof Map) { + const entry = map_get(value3, name); + return new Ok(entry.isOk() ? new Some(entry[0]) : new None()); + } else if (value3 === null) { + return not_a_map_error(); + } else if (Object.getPrototypeOf(value3) == Object.prototype) { + return try_get_field(value3, name, () => new Ok(new None())); + } else { + return try_get_field(value3, name, not_a_map_error); + } +} +function try_get_field(value3, field4, or_else) { + try { + return field4 in value3 ? new Ok(new Some(value3[field4])) : or_else(); + } catch { + return or_else(); + } +} + +// build/dev/javascript/gleam_stdlib/gleam/int.mjs +function to_string2(x) { + return to_string3(x); +} + +// build/dev/javascript/gleam_stdlib/gleam/string.mjs +function length2(string3) { + return string_length(string3); +} + +// build/dev/javascript/gleam_stdlib/gleam/bool.mjs +function guard(requirement, consequence, alternative) { + if (requirement) { + return consequence; + } else { + return alternative(); + } +} + +// build/dev/javascript/lustre/lustre/effect.mjs +var Effect = class extends CustomType { + constructor(all) { + super(); + this.all = all; + } +}; +function none() { + return new Effect(toList([])); +} + +// build/dev/javascript/lustre/lustre/internals/vdom.mjs +var Text = class extends CustomType { + constructor(content) { + super(); + this.content = content; + } +}; +var Element = class extends CustomType { + constructor(key, namespace, tag2, attrs, children, self_closing, void$) { + super(); + this.key = key; + this.namespace = namespace; + this.tag = tag2; + this.attrs = attrs; + this.children = children; + this.self_closing = self_closing; + this.void = void$; + } +}; +var Attribute = class extends CustomType { + constructor(x0, x1, as_property) { + super(); + this[0] = x0; + this[1] = x1; + this.as_property = as_property; + } +}; +var Event = class extends CustomType { + constructor(x0, x1) { + super(); + this[0] = x0; + this[1] = x1; + } +}; + +// build/dev/javascript/lustre/lustre/attribute.mjs +function attribute(name, value3) { + return new Attribute(name, from(value3), false); +} +function property(name, value3) { + return new Attribute(name, from(value3), true); +} +function on(name, handler) { + return new Event("on" + name, handler); +} +function style(properties) { + return attribute( + "style", + fold( + properties, + "", + (styles, _use1) => { + let name$1 = _use1[0]; + let value$1 = _use1[1]; + return styles + name$1 + ":" + value$1 + ";"; + } + ) + ); +} +function class$(name) { + return attribute("class", name); +} +function type_(name) { + return attribute("type", name); +} +function value(val) { + return property("value", from(val)); +} + +// build/dev/javascript/lustre/lustre/element.mjs +function element(tag2, attrs, children) { + if (tag2 === "area") { + return new Element("", "", tag2, attrs, toList([]), false, true); + } else if (tag2 === "base") { + return new Element("", "", tag2, attrs, toList([]), false, true); + } else if (tag2 === "br") { + return new Element("", "", tag2, attrs, toList([]), false, true); + } else if (tag2 === "col") { + return new Element("", "", tag2, attrs, toList([]), false, true); + } else if (tag2 === "embed") { + return new Element("", "", tag2, attrs, toList([]), false, true); + } else if (tag2 === "hr") { + return new Element("", "", tag2, attrs, toList([]), false, true); + } else if (tag2 === "img") { + return new Element("", "", tag2, attrs, toList([]), false, true); + } else if (tag2 === "input") { + return new Element("", "", tag2, attrs, toList([]), false, true); + } else if (tag2 === "link") { + return new Element("", "", tag2, attrs, toList([]), false, true); + } else if (tag2 === "meta") { + return new Element("", "", tag2, attrs, toList([]), false, true); + } else if (tag2 === "param") { + return new Element("", "", tag2, attrs, toList([]), false, true); + } else if (tag2 === "source") { + return new Element("", "", tag2, attrs, toList([]), false, true); + } else if (tag2 === "track") { + return new Element("", "", tag2, attrs, toList([]), false, true); + } else if (tag2 === "wbr") { + return new Element("", "", tag2, attrs, toList([]), false, true); + } else { + return new Element("", "", tag2, attrs, children, false, false); + } +} +function text(content) { + return new Text(content); +} + +// build/dev/javascript/lustre/lustre/internals/runtime.mjs +var Dispatch = class extends CustomType { + constructor(x0) { + super(); + this[0] = x0; + } +}; +var Shutdown = class extends CustomType { +}; + +// build/dev/javascript/lustre/vdom.ffi.mjs +function morph(prev, next, dispatch, isComponent = false) { + let out; + let stack2 = [{ prev, next, parent: prev.parentNode }]; + while (stack2.length) { + let { prev: prev2, next: next2, parent } = stack2.pop(); + if (next2.subtree !== void 0) + next2 = next2.subtree(); + if (next2.content !== void 0) { + if (!prev2) { + const created = document.createTextNode(next2.content); + parent.appendChild(created); + out ??= created; + } else if (prev2.nodeType === Node.TEXT_NODE) { + if (prev2.textContent !== next2.content) + prev2.textContent = next2.content; + out ??= prev2; + } else { + const created = document.createTextNode(next2.content); + parent.replaceChild(created, prev2); + out ??= created; + } + } else if (next2.tag !== void 0) { + const created = createElementNode({ + prev: prev2, + next: next2, + dispatch, + stack: stack2, + isComponent + }); + if (!prev2) { + parent.appendChild(created); + } else if (prev2 !== created) { + parent.replaceChild(created, prev2); + } + out ??= created; + } + } + return out; +} +function createElementNode({ prev, next, dispatch, stack: stack2 }) { + const namespace = next.namespace || "http://www.w3.org/1999/xhtml"; + const canMorph = prev && prev.nodeType === Node.ELEMENT_NODE && prev.localName === next.tag && prev.namespaceURI === (next.namespace || "http://www.w3.org/1999/xhtml"); + const el2 = canMorph ? prev : namespace ? document.createElementNS(namespace, next.tag) : document.createElement(next.tag); + let handlersForEl; + if (!registeredHandlers.has(el2)) { + const emptyHandlers = /* @__PURE__ */ new Map(); + registeredHandlers.set(el2, emptyHandlers); + handlersForEl = emptyHandlers; + } else { + handlersForEl = registeredHandlers.get(el2); + } + const prevHandlers = canMorph ? new Set(handlersForEl.keys()) : null; + const prevAttributes = canMorph ? new Set(Array.from(prev.attributes, (a) => a.name)) : null; + let className = null; + let style2 = null; + let innerHTML = null; + for (const attr of next.attrs) { + const name = attr[0]; + const value3 = attr[1]; + const isProperty = attr[2]; + if (isProperty) { + el2[name] = value3; + } else if (name.startsWith("on")) { + const eventName = name.slice(2); + const callback = dispatch(value3); + if (!handlersForEl.has(eventName)) { + el2.addEventListener(eventName, lustreGenericEventHandler); + } + handlersForEl.set(eventName, callback); + if (canMorph) + prevHandlers.delete(eventName); + } else if (name.startsWith("data-lustre-on-")) { + const eventName = name.slice(15); + const callback = dispatch(lustreServerEventHandler); + if (!handlersForEl.has(eventName)) { + el2.addEventListener(eventName, lustreGenericEventHandler); + } + handlersForEl.set(eventName, callback); + el2.setAttribute(name, value3); + } else if (name === "class") { + className = className === null ? value3 : className + " " + value3; + } else if (name === "style") { + style2 = style2 === null ? value3 : style2 + value3; + } else if (name === "dangerous-unescaped-html") { + innerHTML = value3; + } else { + el2.setAttribute(name, value3); + if (name === "value") + el2[name] = value3; + if (canMorph) + prevAttributes.delete(name); + } + } + if (className !== null) { + el2.setAttribute("class", className); + if (canMorph) + prevAttributes.delete("class"); + } + if (style2 !== null) { + el2.setAttribute("style", style2); + if (canMorph) + prevAttributes.delete("style"); + } + if (canMorph) { + for (const attr of prevAttributes) { + el2.removeAttribute(attr); + } + for (const eventName of prevHandlers) { + handlersForEl.delete(eventName); + el2.removeEventListener(eventName, lustreGenericEventHandler); + } + } + if (next.key !== void 0 && next.key !== "") { + el2.setAttribute("data-lustre-key", next.key); + } else if (innerHTML !== null) { + el2.innerHTML = innerHTML; + return el2; + } + let prevChild = el2.firstChild; + let seenKeys = null; + let keyedChildren = null; + let incomingKeyedChildren = null; + let firstChild = next.children[Symbol.iterator]().next().value; + if (canMorph && firstChild !== void 0 && // Explicit checks are more verbose but truthy checks force a bunch of comparisons + // we don't care about: it's never gonna be a number etc. + firstChild.key !== void 0 && firstChild.key !== "") { + seenKeys = /* @__PURE__ */ new Set(); + keyedChildren = getKeyedChildren(prev); + incomingKeyedChildren = getKeyedChildren(next); + } + for (const child of next.children) { + if (child.key !== void 0 && seenKeys !== null) { + while (prevChild && !incomingKeyedChildren.has(prevChild.getAttribute("data-lustre-key"))) { + const nextChild = prevChild.nextSibling; + el2.removeChild(prevChild); + prevChild = nextChild; + } + if (keyedChildren.size === 0) { + stack2.unshift({ prev: prevChild, next: child, parent: el2 }); + prevChild = prevChild?.nextSibling; + continue; + } + if (seenKeys.has(child.key)) { + console.warn(`Duplicate key found in Lustre vnode: ${child.key}`); + stack2.unshift({ prev: null, next: child, parent: el2 }); + continue; + } + seenKeys.add(child.key); + const keyedChild = keyedChildren.get(child.key); + if (!keyedChild && !prevChild) { + stack2.unshift({ prev: null, next: child, parent: el2 }); + continue; + } + if (!keyedChild && prevChild !== null) { + const placeholder = document.createTextNode(""); + el2.insertBefore(placeholder, prevChild); + stack2.unshift({ prev: placeholder, next: child, parent: el2 }); + continue; + } + if (!keyedChild || keyedChild === prevChild) { + stack2.unshift({ prev: prevChild, next: child, parent: el2 }); + prevChild = prevChild?.nextSibling; + continue; + } + el2.insertBefore(keyedChild, prevChild); + stack2.unshift({ prev: keyedChild, next: child, parent: el2 }); + } else { + stack2.unshift({ prev: prevChild, next: child, parent: el2 }); + prevChild = prevChild?.nextSibling; + } + } + while (prevChild) { + const next2 = prevChild.nextSibling; + el2.removeChild(prevChild); + prevChild = next2; + } + return el2; +} +var registeredHandlers = /* @__PURE__ */ new WeakMap(); +function lustreGenericEventHandler(event2) { + const target = event2.currentTarget; + if (!registeredHandlers.has(target)) { + target.removeEventListener(event2.type, lustreGenericEventHandler); + return; + } + const handlersForEventTarget = registeredHandlers.get(target); + if (!handlersForEventTarget.has(event2.type)) { + target.removeEventListener(event2.type, lustreGenericEventHandler); + return; + } + handlersForEventTarget.get(event2.type)(event2); +} +function lustreServerEventHandler(event2) { + const el2 = event2.target; + const tag2 = el2.getAttribute(`data-lustre-on-${event2.type}`); + const data = JSON.parse(el2.getAttribute("data-lustre-data") || "{}"); + const include = JSON.parse(el2.getAttribute("data-lustre-include") || "[]"); + switch (event2.type) { + case "input": + case "change": + include.push("target.value"); + break; + } + return { + tag: tag2, + data: include.reduce( + (data2, property2) => { + const path = property2.split("."); + for (let i = 0, o = data2, e = event2; i < path.length; i++) { + if (i === path.length - 1) { + o[path[i]] = e[path[i]]; + } else { + o[path[i]] ??= {}; + e = e[path[i]]; + o = o[path[i]]; + } + } + return data2; + }, + { data } + ) + }; +} +function getKeyedChildren(el2) { + const keyedChildren = /* @__PURE__ */ new Map(); + if (el2) { + for (const child of el2.children) { + const key = child.key || child?.getAttribute("data-lustre-key"); + if (key) + keyedChildren.set(key, child); + } + } + return keyedChildren; +} + +// build/dev/javascript/lustre/client-runtime.ffi.mjs +var LustreClientApplication2 = class _LustreClientApplication { + #root = null; + #queue = []; + #effects = []; + #didUpdate = false; + #isComponent = false; + #model = null; + #update = null; + #view = null; + static start(flags, selector, init3, update3, view2) { + if (!is_browser()) + return new Error(new NotABrowser()); + const root2 = selector instanceof HTMLElement ? selector : document.querySelector(selector); + if (!root2) + return new Error(new ElementNotFound(selector)); + const app = new _LustreClientApplication(init3(flags), update3, view2, root2); + return new Ok((msg) => app.send(msg)); + } + constructor([model, effects], update3, view2, root2 = document.body, isComponent = false) { + this.#model = model; + this.#update = update3; + this.#view = view2; + this.#root = root2; + this.#effects = effects.all.toArray(); + this.#didUpdate = true; + this.#isComponent = isComponent; + window.requestAnimationFrame(() => this.#tick()); + } + send(action) { + switch (true) { + case action instanceof Dispatch: { + this.#queue.push(action[0]); + this.#tick(); + return; + } + case action instanceof Shutdown: { + this.#shutdown(); + return; + } + default: + return; + } + } + emit(event2, data) { + this.#root.dispatchEvent( + new CustomEvent(event2, { + bubbles: true, + detail: data, + composed: true + }) + ); + } + #tick() { + this.#flush_queue(); + const vdom = this.#view(this.#model); + const dispatch = (handler) => (e) => { + const result = handler(e); + if (result instanceof Ok) { + this.send(new Dispatch(result[0])); + } + }; + this.#didUpdate = false; + this.#root = morph(this.#root, vdom, dispatch, this.#isComponent); + } + #flush_queue(iterations = 0) { + while (this.#queue.length) { + const [next, effects] = this.#update(this.#model, this.#queue.shift()); + this.#didUpdate ||= !isEqual(this.#model, next); + this.#model = next; + this.#effects = this.#effects.concat(effects.all.toArray()); + } + while (this.#effects.length) { + this.#effects.shift()( + (msg) => this.send(new Dispatch(msg)), + (event2, data) => this.emit(event2, data) + ); + } + if (this.#queue.length) { + if (iterations < 5) { + this.#flush_queue(++iterations); + } else { + window.requestAnimationFrame(() => this.#tick()); + } + } + } + #shutdown() { + this.#root.remove(); + this.#root = null; + this.#model = null; + this.#queue = []; + this.#effects = []; + this.#didUpdate = false; + this.#update = () => { + }; + this.#view = () => { + }; + } +}; +var start = (app, selector, flags) => LustreClientApplication2.start( + flags, + selector, + app.init, + app.update, + app.view +); +var is_browser = () => window && window.document; + +// build/dev/javascript/lustre/lustre.mjs +var App = class extends CustomType { + constructor(init3, update3, view2, on_attribute_change) { + super(); + this.init = init3; + this.update = update3; + this.view = view2; + this.on_attribute_change = on_attribute_change; + } +}; +var ElementNotFound = class extends CustomType { + constructor(selector) { + super(); + this.selector = selector; + } +}; +var NotABrowser = class extends CustomType { +}; +function application(init3, update3, view2) { + return new App(init3, update3, view2, new None()); +} +function simple(init3, update3, view2) { + let init$1 = (flags) => { + return [init3(flags), none()]; + }; + let update$1 = (model, msg) => { + return [update3(model, msg), none()]; + }; + return application(init$1, update$1, view2); +} +function start3(app, selector, flags) { + return guard( + !is_browser(), + new Error(new NotABrowser()), + () => { + return start(app, selector, flags); + } + ); +} + +// build/dev/javascript/lustre/lustre/event.mjs +function on2(name, handler) { + return on(name, handler); +} +function on_click(msg) { + return on2("click", (_) => { + return new Ok(msg); + }); +} +function value2(event2) { + let _pipe = event2; + return field("target", field("value", string))( + _pipe + ); +} +function on_input(msg) { + return on2( + "input", + (event2) => { + let _pipe = value2(event2); + return map2(_pipe, msg); + } + ); +} + +// build/dev/javascript/lustre/lustre/element/html.mjs +function div(attrs, children) { + return element("div", attrs, children); +} +function span(attrs, children) { + return element("span", attrs, children); +} +function button(attrs, children) { + return element("button", attrs, children); +} +function input(attrs) { + return element("input", attrs, toList([])); +} +function label(attrs, children) { + return element("label", attrs, children); +} + +// build/dev/javascript/lustre_ui/lustre/ui/button.mjs +function button2(attributes, children) { + return button( + prepend( + class$("lustre-ui-button"), + prepend(type_("button"), attributes) + ), + children + ); +} + +// build/dev/javascript/lustre_ui/lustre/ui/layout/stack.mjs +function of(element2, attributes, children) { + return element2( + prepend(class$("lustre-ui-stack"), attributes), + children + ); +} +function packed() { + return class$("packed"); +} + +// build/dev/javascript/lustre_ui/lustre/ui/field.mjs +function of2(element2, attributes, label2, input4, message) { + return of( + element2, + prepend( + class$("lustre-ui-field"), + prepend(packed(), attributes) + ), + toList([ + span(toList([class$("label")]), label2), + input4, + span(toList([class$("message")]), message) + ]) + ); +} +function field2(attributes, label2, input4, message) { + return of2(label, attributes, label2, input4, message); +} + +// build/dev/javascript/lustre_ui/lustre/ui/input.mjs +function input2(attributes) { + return input( + prepend(class$("lustre-ui-input"), attributes) + ); +} + +// build/dev/javascript/lustre_ui/lustre/ui/layout/aside.mjs +function of3(element2, attributes, side, main2) { + return element2( + prepend(class$("lustre-ui-aside"), attributes), + toList([side, main2]) + ); +} +function aside(attributes, side, main2) { + return of3(div, attributes, side, main2); +} +function content_first() { + return class$("content-first"); +} +function align_centre() { + return class$("align-centre"); +} + +// build/dev/javascript/lustre_ui/lustre/ui/layout/centre.mjs +function of4(element2, attributes, children) { + return element2( + prepend(class$("lustre-ui-centre"), attributes), + toList([children]) + ); +} +function centre(attributes, children) { + return of4(div, attributes, children); +} + +// build/dev/javascript/gleam_community_colour/gleam_community/colour.mjs +var Rgba = class extends CustomType { + constructor(r, g, b, a) { + super(); + this.r = r; + this.g = g; + this.b = b; + this.a = a; + } +}; +var light_red = new Rgba( + 0.9372549019607843, + 0.1607843137254902, + 0.1607843137254902, + 1 +); +var red = new Rgba(0.8, 0, 0, 1); +var dark_red = new Rgba(0.6431372549019608, 0, 0, 1); +var light_orange = new Rgba( + 0.9882352941176471, + 0.6862745098039216, + 0.24313725490196078, + 1 +); +var orange = new Rgba(0.9607843137254902, 0.4745098039215686, 0, 1); +var dark_orange = new Rgba( + 0.807843137254902, + 0.3607843137254902, + 0, + 1 +); +var light_yellow = new Rgba( + 1, + 0.9137254901960784, + 0.30980392156862746, + 1 +); +var yellow = new Rgba(0.9294117647058824, 0.8313725490196079, 0, 1); +var dark_yellow = new Rgba( + 0.7686274509803922, + 0.6274509803921569, + 0, + 1 +); +var light_green = new Rgba( + 0.5411764705882353, + 0.8862745098039215, + 0.20392156862745098, + 1 +); +var green = new Rgba( + 0.45098039215686275, + 0.8235294117647058, + 0.08627450980392157, + 1 +); +var dark_green = new Rgba( + 0.3058823529411765, + 0.6039215686274509, + 0.023529411764705882, + 1 +); +var light_blue = new Rgba( + 0.4470588235294118, + 0.6235294117647059, + 0.8117647058823529, + 1 +); +var blue = new Rgba( + 0.20392156862745098, + 0.396078431372549, + 0.6431372549019608, + 1 +); +var dark_blue = new Rgba( + 0.12549019607843137, + 0.2901960784313726, + 0.5294117647058824, + 1 +); +var light_purple = new Rgba( + 0.6784313725490196, + 0.4980392156862745, + 0.6588235294117647, + 1 +); +var purple = new Rgba( + 0.4588235294117647, + 0.3137254901960784, + 0.4823529411764706, + 1 +); +var dark_purple = new Rgba( + 0.3607843137254902, + 0.20784313725490197, + 0.4, + 1 +); +var light_brown = new Rgba( + 0.9137254901960784, + 0.7254901960784313, + 0.43137254901960786, + 1 +); +var brown = new Rgba( + 0.7568627450980392, + 0.49019607843137253, + 0.06666666666666667, + 1 +); +var dark_brown = new Rgba( + 0.5607843137254902, + 0.34901960784313724, + 0.00784313725490196, + 1 +); +var black = new Rgba(0, 0, 0, 1); +var white = new Rgba(1, 1, 1, 1); +var light_grey = new Rgba( + 0.9333333333333333, + 0.9333333333333333, + 0.9254901960784314, + 1 +); +var grey = new Rgba( + 0.8274509803921568, + 0.8431372549019608, + 0.8117647058823529, + 1 +); +var dark_grey = new Rgba( + 0.7294117647058823, + 0.7411764705882353, + 0.7137254901960784, + 1 +); +var light_gray = new Rgba( + 0.9333333333333333, + 0.9333333333333333, + 0.9254901960784314, + 1 +); +var gray = new Rgba( + 0.8274509803921568, + 0.8431372549019608, + 0.8117647058823529, + 1 +); +var dark_gray = new Rgba( + 0.7294117647058823, + 0.7411764705882353, + 0.7137254901960784, + 1 +); +var light_charcoal = new Rgba( + 0.5333333333333333, + 0.5411764705882353, + 0.5215686274509804, + 1 +); +var charcoal = new Rgba( + 0.3333333333333333, + 0.3411764705882353, + 0.3254901960784314, + 1 +); +var dark_charcoal = new Rgba( + 0.1803921568627451, + 0.20392156862745098, + 0.21176470588235294, + 1 +); +var pink = new Rgba(1, 0.6862745098039216, 0.9529411764705882, 1); + +// build/dev/javascript/lustre_ui/lustre/ui.mjs +var aside2 = aside; +var button3 = button2; +var centre2 = centre; +var field3 = field2; +var input3 = input2; + +// build/dev/javascript/app/app.mjs +var Model = class extends CustomType { + constructor(value3, length3, max2) { + super(); + this.value = value3; + this.length = length3; + this.max = max2; + } +}; +var UserUpdatedMessage = class extends CustomType { + constructor(value3) { + super(); + this.value = value3; + } +}; +var UserResetMessage = class extends CustomType { +}; +function init2(_) { + return new Model("", 0, 10); +} +function update2(model, msg) { + if (msg instanceof UserUpdatedMessage) { + let value3 = msg.value; + let length3 = length2(value3); + let $ = length3 <= model.max; + if ($) { + return model.withFields({ value: value3, length: length3 }); + } else { + return model; + } + } else { + return model.withFields({ value: "", length: 0 }); + } +} +function view(model) { + let styles = toList([ + ["width", "100vw"], + ["height", "100vh"], + ["padding", "1rem"] + ]); + let length3 = to_string2(model.length); + let max2 = to_string2(model.max); + return centre2( + toList([style(styles)]), + aside2( + toList([content_first(), align_centre()]), + field3( + toList([]), + toList([text("Write a message:")]), + input3( + toList([ + value(model.value), + on_input((var0) => { + return new UserUpdatedMessage(var0); + }) + ]) + ), + toList([text(length3 + "/" + max2)]) + ), + button3( + toList([on_click(new UserResetMessage())]), + toList([text("Reset")]) + ) + ) + ); +} +function main() { + let app = simple(init2, update2, view); + let $ = start3(app, "#app", void 0); + if (!$.isOk()) { + throw makeError( + "assignment_no_match", + "app", + 14, + "main", + "Assignment pattern did not match", + { value: $ } + ); + } + return $; +} + +// build/.lustre/entry.mjs +main(); diff --git a/examples/03-controlled-inputs/src/app.gleam b/examples/03-controlled-inputs/src/app.gleam index b4a29c2..d44e1ae 100644 --- a/examples/03-controlled-inputs/src/app.gleam +++ b/examples/03-controlled-inputs/src/app.gleam @@ -4,16 +4,8 @@ import lustre import lustre/attribute import lustre/element.{type Element} import lustre/event -// These examples are written with `lustre/ui` in mind. They'll work regardless, -// but to see what `lustre/ui` can do make sure to run each of these examples with -// the `--use-example-styles` flag: -// -// $ gleam run -m lustre/dev start --use-example-styles -// -// In your own apps, make sure to add the `lustre/ui` dependency and include the -// stylesheet somewhere. import lustre/ui -import lustre/ui/aside +import lustre/ui/layout/aside // MAIN ------------------------------------------------------------------------ diff --git a/examples/04-custom-event-handlers/index.html b/examples/04-custom-event-handlers/index.html new file mode 100644 index 0000000..36ddf10 --- /dev/null +++ b/examples/04-custom-event-handlers/index.html @@ -0,0 +1,19 @@ +<!doctype html> +<html lang="en"> + <head> + <meta charset="UTF-8" /> + <meta name="viewport" content="width=device-width, initial-scale=1.0" /> + + <title>🚧 app</title> + + <link + rel="stylesheet" + href="./build/dev/javascript/lustre_ui/priv/static/lustre-ui.css" + /> + <script type="module" src="./priv/static/app.mjs"></script> + </head> + + <body> + <div id="app"></div> + </body> +</html> diff --git a/examples/04-custom-event-handlers/manifest.toml b/examples/04-custom-event-handlers/manifest.toml index 7f82909..c0d1211 100644 --- a/examples/04-custom-event-handlers/manifest.toml +++ b/examples/04-custom-event-handlers/manifest.toml @@ -3,26 +3,39 @@ packages = [ { name = "argv", version = "1.0.2", build_tools = ["gleam"], requirements = [], otp_app = "argv", source = "hex", outer_checksum = "BA1FF0929525DEBA1CE67256E5ADF77A7CDDFE729E3E3F57A5BDCAA031DED09D" }, + { name = "birl", version = "1.6.1", build_tools = ["gleam"], requirements = ["gleam_stdlib", "ranger"], otp_app = "birl", source = "hex", outer_checksum = "976CFF85D34D50F7775896615A71745FBE0C325E50399787088F941B539A0497" }, + { name = "exception", version = "2.0.0", build_tools = ["gleam"], requirements = ["gleam_stdlib"], otp_app = "exception", source = "hex", outer_checksum = "F5580D584F16A20B7FCDCABF9E9BE9A2C1F6AC4F9176FA6DD0B63E3B20D450AA" }, { name = "filepath", version = "1.0.0", build_tools = ["gleam"], requirements = ["gleam_stdlib"], otp_app = "filepath", source = "hex", outer_checksum = "EFB6FF65C98B2A16378ABC3EE2B14124168C0CE5201553DE652E2644DCFDB594" }, + { name = "filespy", version = "0.3.0", build_tools = ["gleam"], requirements = ["fs", "gleam_erlang", "gleam_otp", "gleam_stdlib"], otp_app = "filespy", source = "hex", outer_checksum = "75F5910B31A528681D25316AAAE6C91CD3E977BD2492946564B7242FF941FB7A" }, + { name = "fs", version = "8.6.1", build_tools = ["rebar3"], requirements = [], otp_app = "fs", source = "hex", outer_checksum = "61EA2BDAEDAE4E2024D0D25C63E44DCCF65622D4402DB4A2DF12868D1546503F" }, { name = "gleam_community_ansi", version = "1.4.0", build_tools = ["gleam"], requirements = ["gleam_community_colour", "gleam_stdlib"], otp_app = "gleam_community_ansi", source = "hex", outer_checksum = "FE79E08BF97009729259B6357EC058315B6FBB916FAD1C2FF9355115FEB0D3A4" }, { name = "gleam_community_colour", version = "1.4.0", build_tools = ["gleam"], requirements = ["gleam_json", "gleam_stdlib"], otp_app = "gleam_community_colour", source = "hex", outer_checksum = "795964217EBEDB3DA656F5EB8F67D7AD22872EB95182042D3E7AFEF32D3FD2FE" }, + { name = "gleam_crypto", version = "1.3.0", build_tools = ["gleam"], requirements = ["gleam_stdlib"], otp_app = "gleam_crypto", source = "hex", outer_checksum = "ADD058DEDE8F0341F1ADE3AAC492A224F15700829D9A3A3F9ADF370F875C51B7" }, { name = "gleam_erlang", version = "0.25.0", build_tools = ["gleam"], requirements = ["gleam_stdlib"], otp_app = "gleam_erlang", source = "hex", outer_checksum = "054D571A7092D2A9727B3E5D183B7507DAB0DA41556EC9133606F09C15497373" }, + { name = "gleam_http", version = "3.6.0", build_tools = ["gleam"], requirements = ["gleam_stdlib"], otp_app = "gleam_http", source = "hex", outer_checksum = "8C07DF9DF8CC7F054C650839A51C30A7D3C26482AC241C899C1CEA86B22DBE51" }, { name = "gleam_json", version = "1.0.0", build_tools = ["gleam"], requirements = ["gleam_stdlib", "thoas"], otp_app = "gleam_json", source = "hex", outer_checksum = "8B197DD5D578EA6AC2C0D4BDC634C71A5BCA8E7DB5F47091C263ECB411A60DF3" }, { name = "gleam_otp", version = "0.10.0", build_tools = ["gleam"], requirements = ["gleam_erlang", "gleam_stdlib"], otp_app = "gleam_otp", source = "hex", outer_checksum = "0B04FE915ACECE539B317F9652CAADBBC0F000184D586AAAF2D94C100945D72B" }, { name = "gleam_package_interface", version = "1.0.0", build_tools = ["gleam"], requirements = ["gleam_json", "gleam_stdlib"], otp_app = "gleam_package_interface", source = "hex", outer_checksum = "52A721BCA972C8099BB881195D821AAA64B9F2655BECC102165D5A1097731F01" }, { name = "gleam_stdlib", version = "0.36.0", build_tools = ["gleam"], requirements = [], otp_app = "gleam_stdlib", source = "hex", outer_checksum = "C0D14D807FEC6F8A08A7C9EF8DFDE6AE5C10E40E21325B2B29365965D82EB3D4" }, { name = "glearray", version = "0.2.1", build_tools = ["gleam"], requirements = ["gleam_stdlib"], otp_app = "glearray", source = "hex", outer_checksum = "908154F695D330E06A37FAB2C04119E8F315D643206F8F32B6A6C14A8709FFF4" }, - { name = "gleeunit", version = "1.0.2", build_tools = ["gleam"], requirements = ["gleam_stdlib"], otp_app = "gleeunit", source = "hex", outer_checksum = "D364C87AFEB26BDB4FB8A5ABDE67D635DC9FA52D6AB68416044C35B096C6882D" }, + { name = "gleeunit", version = "1.1.2", build_tools = ["gleam"], requirements = ["gleam_stdlib"], otp_app = "gleeunit", source = "hex", outer_checksum = "72CDC3D3F719478F26C4E2C5FED3E657AC81EC14A47D2D2DEBB8693CA3220C3B" }, { name = "glint", version = "0.18.0", build_tools = ["gleam"], requirements = ["gleam_community_ansi", "gleam_community_colour", "gleam_stdlib", "snag"], otp_app = "glint", source = "hex", outer_checksum = "BB0F14643CC51C069A5DC6E9082EAFCD9967AFD1C9CC408803D1A40A3FD43B54" }, - { name = "lustre", version = "4.0.0", build_tools = ["gleam"], requirements = ["gleam_erlang", "gleam_json", "gleam_otp", "gleam_stdlib"], otp_app = "lustre", source = "hex", outer_checksum = "1D40C1378279F7015687F8C9DB739D6880BB0B843F4428B85C61EDDA8BF21FC6" }, - { name = "lustre_dev_tools", version = "1.0.0", build_tools = ["gleam"], requirements = ["argv", "filepath", "gleam_community_ansi", "gleam_erlang", "gleam_json", "gleam_otp", "gleam_package_interface", "gleam_stdlib", "glint", "simplifile", "spinner", "tom"], otp_app = "lustre_dev_tools", source = "hex", outer_checksum = "66142ADDCA3D6C63A89E016CF6C21E07D06D6DC92479325182A07C360BD026D3" }, - { name = "lustre_ui", version = "0.5.0", build_tools = ["gleam"], requirements = ["gleam_community_colour", "gleam_json", "gleam_stdlib", "lustre"], otp_app = "lustre_ui", source = "hex", outer_checksum = "7ECB5414BE926082401891C62FAAA21221FC0B7A2F0568A492349F48DC2B02A0" }, + { name = "glisten", version = "2.0.0", build_tools = ["gleam"], requirements = ["gleam_erlang", "gleam_otp", "gleam_stdlib"], otp_app = "glisten", source = "hex", outer_checksum = "CF3A9383E9BA4A8CBAF2F7B799716290D02F2AC34E7A77556B49376B662B9314" }, + { name = "hpack_erl", version = "0.3.0", build_tools = ["rebar3"], requirements = [], otp_app = "hpack", source = "hex", outer_checksum = "D6137D7079169D8C485C6962DFE261AF5B9EF60FBC557344511C1E65E3D95FB0" }, + { name = "logging", version = "1.0.1", build_tools = ["gleam"], requirements = ["gleam_stdlib"], otp_app = "logging", source = "hex", outer_checksum = "82C112ED9B6C30C1772A6FE2613B94B13F62EA35F5869A2630D13948D297BD39" }, + { name = "lustre", version = "4.1.7", build_tools = ["gleam"], requirements = ["gleam_erlang", "gleam_json", "gleam_otp", "gleam_stdlib"], otp_app = "lustre", source = "hex", outer_checksum = "64F5D7E4DF51280185F70296ACB7D3DCC9B5DA09EFC5257F0E5601846DFBEF23" }, + { name = "lustre_dev_tools", version = "1.2.1", build_tools = ["gleam"], requirements = ["argv", "filepath", "filespy", "fs", "gleam_community_ansi", "gleam_erlang", "gleam_http", "gleam_json", "gleam_otp", "gleam_package_interface", "gleam_stdlib", "glint", "glisten", "mist", "simplifile", "spinner", "tom", "wisp"], otp_app = "lustre_dev_tools", source = "hex", outer_checksum = "930BBE8C4E92A16857C31B7B12616651433E1643304696FB93B69D659CE3ADC2" }, + { name = "lustre_ui", version = "0.6.0", build_tools = ["gleam"], requirements = ["gleam_community_colour", "gleam_json", "gleam_stdlib", "lustre"], otp_app = "lustre_ui", source = "hex", outer_checksum = "FA1F9E89D89CDD5DF376ED86ABA8A38441CB2E664CD4D402F22A49DA4D7BB56D" }, + { name = "marceau", version = "1.1.0", build_tools = ["gleam"], requirements = [], otp_app = "marceau", source = "hex", outer_checksum = "1AAD727A30BE0F95562C3403BB9B27C823797AD90037714255EEBF617B1CDA81" }, + { name = "mist", version = "1.0.0", build_tools = ["gleam"], requirements = ["birl", "gleam_erlang", "gleam_http", "gleam_otp", "gleam_stdlib", "glisten", "hpack_erl", "logging"], otp_app = "mist", source = "hex", outer_checksum = "7765E53DCC9ACCACF217B8E0CA3DE7E848C783BFAE5118B75011E81C2C80385C" }, + { name = "ranger", version = "1.2.0", build_tools = ["gleam"], requirements = ["gleam_stdlib"], otp_app = "ranger", source = "hex", outer_checksum = "1566C272B1D141B3BBA38B25CB761EF56E312E79EC0E2DFD4D3C19FB0CC1F98C" }, { name = "repeatedly", version = "2.1.1", build_tools = ["gleam"], requirements = [], otp_app = "repeatedly", source = "hex", outer_checksum = "38808C3EC382B0CD981336D5879C24ECB37FCB9C1D1BD128F7A80B0F74404D79" }, - { name = "simplifile", version = "1.5.1", build_tools = ["gleam"], requirements = ["gleam_stdlib"], otp_app = "simplifile", source = "hex", outer_checksum = "C44DB387524F90DC42142699C78C850003289D32C7C99C7D32873792A299CDF7" }, + { name = "simplifile", version = "1.7.0", build_tools = ["gleam"], requirements = ["filepath", "gleam_stdlib"], otp_app = "simplifile", source = "hex", outer_checksum = "1D5DFA3A2F9319EC85825F6ED88B8E449F381B0D55A62F5E61424E748E7DDEB0" }, { name = "snag", version = "0.3.0", build_tools = ["gleam"], requirements = ["gleam_stdlib"], otp_app = "snag", source = "hex", outer_checksum = "54D32E16E33655346AA3E66CBA7E191DE0A8793D2C05284E3EFB90AD2CE92BCC" }, { name = "spinner", version = "1.1.0", build_tools = ["gleam"], requirements = ["gleam_community_ansi", "gleam_erlang", "gleam_stdlib", "glearray", "repeatedly"], otp_app = "spinner", source = "hex", outer_checksum = "200BA3D4A04D468898E63C0D316E23F526E02514BC46454091975CB5BAE41E8F" }, { name = "thoas", version = "0.4.1", build_tools = ["rebar3"], requirements = [], otp_app = "thoas", source = "hex", outer_checksum = "4918D50026C073C4AB1388437132C77A6F6F7C8AC43C60C13758CC0ADCE2134E" }, { name = "tom", version = "0.3.0", build_tools = ["gleam"], requirements = ["gleam_stdlib"], otp_app = "tom", source = "hex", outer_checksum = "0831C73E45405A2153091226BF98FB485ED16376988602CC01A5FD086B82D577" }, + { name = "wisp", version = "0.14.0", build_tools = ["gleam"], requirements = ["exception", "gleam_crypto", "gleam_erlang", "gleam_http", "gleam_json", "gleam_stdlib", "logging", "marceau", "mist", "simplifile"], otp_app = "wisp", source = "hex", outer_checksum = "9F5453AF1F9275E6F8707BC815D6A6A9DF41551921B16FBDBA52883773BAE684" }, ] [requirements] diff --git a/examples/04-custom-event-handlers/priv/static/app.mjs b/examples/04-custom-event-handlers/priv/static/app.mjs new file mode 100644 index 0000000..cf43821 --- /dev/null +++ b/examples/04-custom-event-handlers/priv/static/app.mjs @@ -0,0 +1,2145 @@ +// build/dev/javascript/prelude.mjs +var CustomType = class { + withFields(fields) { + let properties = Object.keys(this).map( + (label2) => label2 in fields ? fields[label2] : this[label2] + ); + return new this.constructor(...properties); + } +}; +var List = class { + static fromArray(array3, tail) { + let t = tail || new Empty(); + for (let i = array3.length - 1; i >= 0; --i) { + t = new NonEmpty(array3[i], t); + } + return t; + } + [Symbol.iterator]() { + return new ListIterator(this); + } + toArray() { + return [...this]; + } + // @internal + atLeastLength(desired) { + for (let _ of this) { + if (desired <= 0) + return true; + desired--; + } + return desired <= 0; + } + // @internal + hasLength(desired) { + for (let _ of this) { + if (desired <= 0) + return false; + desired--; + } + return desired === 0; + } + countLength() { + let length3 = 0; + for (let _ of this) + length3++; + return length3; + } +}; +function prepend(element2, tail) { + return new NonEmpty(element2, tail); +} +function toList(elements, tail) { + return List.fromArray(elements, tail); +} +var ListIterator = class { + #current; + constructor(current) { + this.#current = current; + } + next() { + if (this.#current instanceof Empty) { + return { done: true }; + } else { + let { head, tail } = this.#current; + this.#current = tail; + return { value: head, done: false }; + } + } +}; +var Empty = class extends List { +}; +var NonEmpty = class extends List { + constructor(head, tail) { + super(); + this.head = head; + this.tail = tail; + } +}; +var BitArray = class _BitArray { + constructor(buffer) { + if (!(buffer instanceof Uint8Array)) { + throw "BitArray can only be constructed from a Uint8Array"; + } + this.buffer = buffer; + } + // @internal + get length() { + return this.buffer.length; + } + // @internal + byteAt(index2) { + return this.buffer[index2]; + } + // @internal + floatAt(index2) { + return byteArrayToFloat(this.buffer.slice(index2, index2 + 8)); + } + // @internal + intFromSlice(start4, end) { + return byteArrayToInt(this.buffer.slice(start4, end)); + } + // @internal + binaryFromSlice(start4, end) { + return new _BitArray(this.buffer.slice(start4, end)); + } + // @internal + sliceAfter(index2) { + return new _BitArray(this.buffer.slice(index2)); + } +}; +function byteArrayToInt(byteArray) { + byteArray = byteArray.reverse(); + let value2 = 0; + for (let i = byteArray.length - 1; i >= 0; i--) { + value2 = value2 * 256 + byteArray[i]; + } + return value2; +} +function byteArrayToFloat(byteArray) { + return new Float64Array(byteArray.reverse().buffer)[0]; +} +var Result = class _Result extends CustomType { + // @internal + static isResult(data) { + return data instanceof _Result; + } +}; +var Ok = class extends Result { + constructor(value2) { + super(); + this[0] = value2; + } + // @internal + isOk() { + return true; + } +}; +var Error = class extends Result { + constructor(detail) { + super(); + this[0] = detail; + } + // @internal + isOk() { + return false; + } +}; +function isEqual(x, y) { + let values = [x, y]; + while (values.length) { + let a = values.pop(); + let b = values.pop(); + if (a === b) + continue; + if (!isObject(a) || !isObject(b)) + return false; + let unequal = !structurallyCompatibleObjects(a, b) || unequalDates(a, b) || unequalBuffers(a, b) || unequalArrays(a, b) || unequalMaps(a, b) || unequalSets(a, b) || unequalRegExps(a, b); + if (unequal) + return false; + const proto = Object.getPrototypeOf(a); + if (proto !== null && typeof proto.equals === "function") { + try { + if (a.equals(b)) + continue; + else + return false; + } catch { + } + } + let [keys2, get2] = getters(a); + for (let k of keys2(a)) { + values.push(get2(a, k), get2(b, k)); + } + } + return true; +} +function getters(object3) { + if (object3 instanceof Map) { + return [(x) => x.keys(), (x, y) => x.get(y)]; + } else { + let extra = object3 instanceof globalThis.Error ? ["message"] : []; + return [(x) => [...extra, ...Object.keys(x)], (x, y) => x[y]]; + } +} +function unequalDates(a, b) { + return a instanceof Date && (a > b || a < b); +} +function unequalBuffers(a, b) { + return a.buffer instanceof ArrayBuffer && a.BYTES_PER_ELEMENT && !(a.byteLength === b.byteLength && a.every((n, i) => n === b[i])); +} +function unequalArrays(a, b) { + return Array.isArray(a) && a.length !== b.length; +} +function unequalMaps(a, b) { + return a instanceof Map && a.size !== b.size; +} +function unequalSets(a, b) { + return a instanceof Set && (a.size != b.size || [...a].some((e) => !b.has(e))); +} +function unequalRegExps(a, b) { + return a instanceof RegExp && (a.source !== b.source || a.flags !== b.flags); +} +function isObject(a) { + return typeof a === "object" && a !== null; +} +function structurallyCompatibleObjects(a, b) { + if (typeof a !== "object" && typeof b !== "object" && (!a || !b)) + return false; + let nonstructural = [Promise, WeakSet, WeakMap, Function]; + if (nonstructural.some((c) => a instanceof c)) + return false; + return a.constructor === b.constructor; +} +function makeError(variant, module, line, fn, message, extra) { + let error = new globalThis.Error(message); + error.gleam_error = variant; + error.module = module; + error.line = line; + error.fn = fn; + for (let k in extra) + error[k] = extra[k]; + return error; +} + +// build/dev/javascript/gleam_stdlib/gleam/option.mjs +var Some = class extends CustomType { + constructor(x0) { + super(); + this[0] = x0; + } +}; +var None = class extends CustomType { +}; +function to_result(option, e) { + if (option instanceof Some) { + let a = option[0]; + return new Ok(a); + } else { + return new Error(e); + } +} + +// build/dev/javascript/gleam_stdlib/dict.mjs +var referenceMap = /* @__PURE__ */ new WeakMap(); +var tempDataView = new DataView(new ArrayBuffer(8)); +var referenceUID = 0; +function hashByReference(o) { + const known = referenceMap.get(o); + if (known !== void 0) { + return known; + } + const hash = referenceUID++; + if (referenceUID === 2147483647) { + referenceUID = 0; + } + referenceMap.set(o, hash); + return hash; +} +function hashMerge(a, b) { + return a ^ b + 2654435769 + (a << 6) + (a >> 2) | 0; +} +function hashString(s) { + let hash = 0; + const len = s.length; + for (let i = 0; i < len; i++) { + hash = Math.imul(31, hash) + s.charCodeAt(i) | 0; + } + return hash; +} +function hashNumber(n) { + tempDataView.setFloat64(0, n); + const i = tempDataView.getInt32(0); + const j = tempDataView.getInt32(4); + return Math.imul(73244475, i >> 16 ^ i) ^ j; +} +function hashBigInt(n) { + return hashString(n.toString()); +} +function hashObject(o) { + const proto = Object.getPrototypeOf(o); + if (proto !== null && typeof proto.hashCode === "function") { + try { + const code = o.hashCode(o); + if (typeof code === "number") { + return code; + } + } catch { + } + } + if (o instanceof Promise || o instanceof WeakSet || o instanceof WeakMap) { + return hashByReference(o); + } + if (o instanceof Date) { + return hashNumber(o.getTime()); + } + let h = 0; + if (o instanceof ArrayBuffer) { + o = new Uint8Array(o); + } + if (Array.isArray(o) || o instanceof Uint8Array) { + for (let i = 0; i < o.length; i++) { + h = Math.imul(31, h) + getHash(o[i]) | 0; + } + } else if (o instanceof Set) { + o.forEach((v) => { + h = h + getHash(v) | 0; + }); + } else if (o instanceof Map) { + o.forEach((v, k) => { + h = h + hashMerge(getHash(v), getHash(k)) | 0; + }); + } else { + const keys2 = Object.keys(o); + for (let i = 0; i < keys2.length; i++) { + const k = keys2[i]; + const v = o[k]; + h = h + hashMerge(getHash(v), hashString(k)) | 0; + } + } + return h; +} +function getHash(u) { + if (u === null) + return 1108378658; + if (u === void 0) + return 1108378659; + if (u === true) + return 1108378657; + if (u === false) + return 1108378656; + switch (typeof u) { + case "number": + return hashNumber(u); + case "string": + return hashString(u); + case "bigint": + return hashBigInt(u); + case "object": + return hashObject(u); + case "symbol": + return hashByReference(u); + case "function": + return hashByReference(u); + default: + return 0; + } +} +var SHIFT = 5; +var BUCKET_SIZE = Math.pow(2, SHIFT); +var MASK = BUCKET_SIZE - 1; +var MAX_INDEX_NODE = BUCKET_SIZE / 2; +var MIN_ARRAY_NODE = BUCKET_SIZE / 4; +var ENTRY = 0; +var ARRAY_NODE = 1; +var INDEX_NODE = 2; +var COLLISION_NODE = 3; +var EMPTY = { + type: INDEX_NODE, + bitmap: 0, + array: [] +}; +function mask(hash, shift) { + return hash >>> shift & MASK; +} +function bitpos(hash, shift) { + return 1 << mask(hash, shift); +} +function bitcount(x) { + x -= x >> 1 & 1431655765; + x = (x & 858993459) + (x >> 2 & 858993459); + x = x + (x >> 4) & 252645135; + x += x >> 8; + x += x >> 16; + return x & 127; +} +function index(bitmap, bit) { + return bitcount(bitmap & bit - 1); +} +function cloneAndSet(arr, at, val) { + const len = arr.length; + const out = new Array(len); + for (let i = 0; i < len; ++i) { + out[i] = arr[i]; + } + out[at] = val; + return out; +} +function spliceIn(arr, at, val) { + const len = arr.length; + const out = new Array(len + 1); + let i = 0; + let g = 0; + while (i < at) { + out[g++] = arr[i++]; + } + out[g++] = val; + while (i < len) { + out[g++] = arr[i++]; + } + return out; +} +function spliceOut(arr, at) { + const len = arr.length; + const out = new Array(len - 1); + let i = 0; + let g = 0; + while (i < at) { + out[g++] = arr[i++]; + } + ++i; + while (i < len) { + out[g++] = arr[i++]; + } + return out; +} +function createNode(shift, key1, val1, key2hash, key2, val2) { + const key1hash = getHash(key1); + if (key1hash === key2hash) { + return { + type: COLLISION_NODE, + hash: key1hash, + array: [ + { type: ENTRY, k: key1, v: val1 }, + { type: ENTRY, k: key2, v: val2 } + ] + }; + } + const addedLeaf = { val: false }; + return assoc( + assocIndex(EMPTY, shift, key1hash, key1, val1, addedLeaf), + shift, + key2hash, + key2, + val2, + addedLeaf + ); +} +function assoc(root2, shift, hash, key, val, addedLeaf) { + switch (root2.type) { + case ARRAY_NODE: + return assocArray(root2, shift, hash, key, val, addedLeaf); + case INDEX_NODE: + return assocIndex(root2, shift, hash, key, val, addedLeaf); + case COLLISION_NODE: + return assocCollision(root2, shift, hash, key, val, addedLeaf); + } +} +function assocArray(root2, shift, hash, key, val, addedLeaf) { + const idx = mask(hash, shift); + const node = root2.array[idx]; + if (node === void 0) { + addedLeaf.val = true; + return { + type: ARRAY_NODE, + size: root2.size + 1, + array: cloneAndSet(root2.array, idx, { type: ENTRY, k: key, v: val }) + }; + } + if (node.type === ENTRY) { + if (isEqual(key, node.k)) { + if (val === node.v) { + return root2; + } + return { + type: ARRAY_NODE, + size: root2.size, + array: cloneAndSet(root2.array, idx, { + type: ENTRY, + k: key, + v: val + }) + }; + } + addedLeaf.val = true; + return { + type: ARRAY_NODE, + size: root2.size, + array: cloneAndSet( + root2.array, + idx, + createNode(shift + SHIFT, node.k, node.v, hash, key, val) + ) + }; + } + const n = assoc(node, shift + SHIFT, hash, key, val, addedLeaf); + if (n === node) { + return root2; + } + return { + type: ARRAY_NODE, + size: root2.size, + array: cloneAndSet(root2.array, idx, n) + }; +} +function assocIndex(root2, shift, hash, key, val, addedLeaf) { + const bit = bitpos(hash, shift); + const idx = index(root2.bitmap, bit); + if ((root2.bitmap & bit) !== 0) { + const node = root2.array[idx]; + if (node.type !== ENTRY) { + const n = assoc(node, shift + SHIFT, hash, key, val, addedLeaf); + if (n === node) { + return root2; + } + return { + type: INDEX_NODE, + bitmap: root2.bitmap, + array: cloneAndSet(root2.array, idx, n) + }; + } + const nodeKey = node.k; + if (isEqual(key, nodeKey)) { + if (val === node.v) { + return root2; + } + return { + type: INDEX_NODE, + bitmap: root2.bitmap, + array: cloneAndSet(root2.array, idx, { + type: ENTRY, + k: key, + v: val + }) + }; + } + addedLeaf.val = true; + return { + type: INDEX_NODE, + bitmap: root2.bitmap, + array: cloneAndSet( + root2.array, + idx, + createNode(shift + SHIFT, nodeKey, node.v, hash, key, val) + ) + }; + } else { + const n = root2.array.length; + if (n >= MAX_INDEX_NODE) { + const nodes = new Array(32); + const jdx = mask(hash, shift); + nodes[jdx] = assocIndex(EMPTY, shift + SHIFT, hash, key, val, addedLeaf); + let j = 0; + let bitmap = root2.bitmap; + for (let i = 0; i < 32; i++) { + if ((bitmap & 1) !== 0) { + const node = root2.array[j++]; + nodes[i] = node; + } + bitmap = bitmap >>> 1; + } + return { + type: ARRAY_NODE, + size: n + 1, + array: nodes + }; + } else { + const newArray = spliceIn(root2.array, idx, { + type: ENTRY, + k: key, + v: val + }); + addedLeaf.val = true; + return { + type: INDEX_NODE, + bitmap: root2.bitmap | bit, + array: newArray + }; + } + } +} +function assocCollision(root2, shift, hash, key, val, addedLeaf) { + if (hash === root2.hash) { + const idx = collisionIndexOf(root2, key); + if (idx !== -1) { + const entry = root2.array[idx]; + if (entry.v === val) { + return root2; + } + return { + type: COLLISION_NODE, + hash, + array: cloneAndSet(root2.array, idx, { type: ENTRY, k: key, v: val }) + }; + } + const size = root2.array.length; + addedLeaf.val = true; + return { + type: COLLISION_NODE, + hash, + array: cloneAndSet(root2.array, size, { type: ENTRY, k: key, v: val }) + }; + } + return assoc( + { + type: INDEX_NODE, + bitmap: bitpos(root2.hash, shift), + array: [root2] + }, + shift, + hash, + key, + val, + addedLeaf + ); +} +function collisionIndexOf(root2, key) { + const size = root2.array.length; + for (let i = 0; i < size; i++) { + if (isEqual(key, root2.array[i].k)) { + return i; + } + } + return -1; +} +function find(root2, shift, hash, key) { + switch (root2.type) { + case ARRAY_NODE: + return findArray(root2, shift, hash, key); + case INDEX_NODE: + return findIndex(root2, shift, hash, key); + case COLLISION_NODE: + return findCollision(root2, key); + } +} +function findArray(root2, shift, hash, key) { + const idx = mask(hash, shift); + const node = root2.array[idx]; + if (node === void 0) { + return void 0; + } + if (node.type !== ENTRY) { + return find(node, shift + SHIFT, hash, key); + } + if (isEqual(key, node.k)) { + return node; + } + return void 0; +} +function findIndex(root2, shift, hash, key) { + const bit = bitpos(hash, shift); + if ((root2.bitmap & bit) === 0) { + return void 0; + } + const idx = index(root2.bitmap, bit); + const node = root2.array[idx]; + if (node.type !== ENTRY) { + return find(node, shift + SHIFT, hash, key); + } + if (isEqual(key, node.k)) { + return node; + } + return void 0; +} +function findCollision(root2, key) { + const idx = collisionIndexOf(root2, key); + if (idx < 0) { + return void 0; + } + return root2.array[idx]; +} +function without(root2, shift, hash, key) { + switch (root2.type) { + case ARRAY_NODE: + return withoutArray(root2, shift, hash, key); + case INDEX_NODE: + return withoutIndex(root2, shift, hash, key); + case COLLISION_NODE: + return withoutCollision(root2, key); + } +} +function withoutArray(root2, shift, hash, key) { + const idx = mask(hash, shift); + const node = root2.array[idx]; + if (node === void 0) { + return root2; + } + let n = void 0; + if (node.type === ENTRY) { + if (!isEqual(node.k, key)) { + return root2; + } + } else { + n = without(node, shift + SHIFT, hash, key); + if (n === node) { + return root2; + } + } + if (n === void 0) { + if (root2.size <= MIN_ARRAY_NODE) { + const arr = root2.array; + const out = new Array(root2.size - 1); + let i = 0; + let j = 0; + let bitmap = 0; + while (i < idx) { + const nv = arr[i]; + if (nv !== void 0) { + out[j] = nv; + bitmap |= 1 << i; + ++j; + } + ++i; + } + ++i; + while (i < arr.length) { + const nv = arr[i]; + if (nv !== void 0) { + out[j] = nv; + bitmap |= 1 << i; + ++j; + } + ++i; + } + return { + type: INDEX_NODE, + bitmap, + array: out + }; + } + return { + type: ARRAY_NODE, + size: root2.size - 1, + array: cloneAndSet(root2.array, idx, n) + }; + } + return { + type: ARRAY_NODE, + size: root2.size, + array: cloneAndSet(root2.array, idx, n) + }; +} +function withoutIndex(root2, shift, hash, key) { + const bit = bitpos(hash, shift); + if ((root2.bitmap & bit) === 0) { + return root2; + } + const idx = index(root2.bitmap, bit); + const node = root2.array[idx]; + if (node.type !== ENTRY) { + const n = without(node, shift + SHIFT, hash, key); + if (n === node) { + return root2; + } + if (n !== void 0) { + return { + type: INDEX_NODE, + bitmap: root2.bitmap, + array: cloneAndSet(root2.array, idx, n) + }; + } + if (root2.bitmap === bit) { + return void 0; + } + return { + type: INDEX_NODE, + bitmap: root2.bitmap ^ bit, + array: spliceOut(root2.array, idx) + }; + } + if (isEqual(key, node.k)) { + if (root2.bitmap === bit) { + return void 0; + } + return { + type: INDEX_NODE, + bitmap: root2.bitmap ^ bit, + array: spliceOut(root2.array, idx) + }; + } + return root2; +} +function withoutCollision(root2, key) { + const idx = collisionIndexOf(root2, key); + if (idx < 0) { + return root2; + } + if (root2.array.length === 1) { + return void 0; + } + return { + type: COLLISION_NODE, + hash: root2.hash, + array: spliceOut(root2.array, idx) + }; +} +function forEach(root2, fn) { + if (root2 === void 0) { + return; + } + const items = root2.array; + const size = items.length; + for (let i = 0; i < size; i++) { + const item = items[i]; + if (item === void 0) { + continue; + } + if (item.type === ENTRY) { + fn(item.v, item.k); + continue; + } + forEach(item, fn); + } +} +var Dict = class _Dict { + /** + * @template V + * @param {Record<string,V>} o + * @returns {Dict<string,V>} + */ + static fromObject(o) { + const keys2 = Object.keys(o); + let m = _Dict.new(); + for (let i = 0; i < keys2.length; i++) { + const k = keys2[i]; + m = m.set(k, o[k]); + } + return m; + } + /** + * @template K,V + * @param {Map<K,V>} o + * @returns {Dict<K,V>} + */ + static fromMap(o) { + let m = _Dict.new(); + o.forEach((v, k) => { + m = m.set(k, v); + }); + return m; + } + static new() { + return new _Dict(void 0, 0); + } + /** + * @param {undefined | Node<K,V>} root + * @param {number} size + */ + constructor(root2, size) { + this.root = root2; + this.size = size; + } + /** + * @template NotFound + * @param {K} key + * @param {NotFound} notFound + * @returns {NotFound | V} + */ + get(key, notFound) { + if (this.root === void 0) { + return notFound; + } + const found = find(this.root, 0, getHash(key), key); + if (found === void 0) { + return notFound; + } + return found.v; + } + /** + * @param {K} key + * @param {V} val + * @returns {Dict<K,V>} + */ + set(key, val) { + const addedLeaf = { val: false }; + const root2 = this.root === void 0 ? EMPTY : this.root; + const newRoot = assoc(root2, 0, getHash(key), key, val, addedLeaf); + if (newRoot === this.root) { + return this; + } + return new _Dict(newRoot, addedLeaf.val ? this.size + 1 : this.size); + } + /** + * @param {K} key + * @returns {Dict<K,V>} + */ + delete(key) { + if (this.root === void 0) { + return this; + } + const newRoot = without(this.root, 0, getHash(key), key); + if (newRoot === this.root) { + return this; + } + if (newRoot === void 0) { + return _Dict.new(); + } + return new _Dict(newRoot, this.size - 1); + } + /** + * @param {K} key + * @returns {boolean} + */ + has(key) { + if (this.root === void 0) { + return false; + } + return find(this.root, 0, getHash(key), key) !== void 0; + } + /** + * @returns {[K,V][]} + */ + entries() { + if (this.root === void 0) { + return []; + } + const result = []; + this.forEach((v, k) => result.push([k, v])); + return result; + } + /** + * + * @param {(val:V,key:K)=>void} fn + */ + forEach(fn) { + forEach(this.root, fn); + } + hashCode() { + let h = 0; + this.forEach((v, k) => { + h = h + hashMerge(getHash(v), getHash(k)) | 0; + }); + return h; + } + /** + * @param {unknown} o + * @returns {boolean} + */ + equals(o) { + if (!(o instanceof _Dict) || this.size !== o.size) { + return false; + } + let equal2 = true; + this.forEach((v, k) => { + equal2 = equal2 && isEqual(o.get(k, !v), v); + }); + return equal2; + } +}; + +// build/dev/javascript/gleam_stdlib/gleam_stdlib.mjs +var Nil = void 0; +var NOT_FOUND = {}; +function identity(x) { + return x; +} +function to_string(term) { + return term.toString(); +} +function string_length(string3) { + if (string3 === "") { + return 0; + } + const iterator = graphemes_iterator(string3); + if (iterator) { + let i = 0; + for (const _ of iterator) { + i++; + } + return i; + } else { + return string3.match(/./gsu).length; + } +} +function graphemes_iterator(string3) { + if (Intl && Intl.Segmenter) { + return new Intl.Segmenter().segment(string3)[Symbol.iterator](); + } +} +function uppercase(string3) { + return string3.toUpperCase(); +} +function concat(xs) { + let result = ""; + for (const x of xs) { + result = result + x; + } + return result; +} +function map_get(map4, key) { + const value2 = map4.get(key, NOT_FOUND); + if (value2 === NOT_FOUND) { + return new Error(Nil); + } + return new Ok(value2); +} +function classify_dynamic(data) { + if (typeof data === "string") { + return "String"; + } else if (data instanceof Result) { + return "Result"; + } else if (data instanceof List) { + return "List"; + } else if (data instanceof BitArray) { + return "BitArray"; + } else if (data instanceof Dict) { + return "Dict"; + } else if (Number.isInteger(data)) { + return "Int"; + } else if (Array.isArray(data)) { + return `Tuple of ${data.length} elements`; + } else if (typeof data === "number") { + return "Float"; + } else if (data === null) { + return "Null"; + } else if (data === void 0) { + return "Nil"; + } else { + const type = typeof data; + return type.charAt(0).toUpperCase() + type.slice(1); + } +} +function decoder_error(expected, got) { + return decoder_error_no_classify(expected, classify_dynamic(got)); +} +function decoder_error_no_classify(expected, got) { + return new Error( + List.fromArray([new DecodeError(expected, got, List.fromArray([]))]) + ); +} +function decode_string(data) { + return typeof data === "string" ? new Ok(data) : decoder_error("String", data); +} +function decode_int(data) { + return Number.isInteger(data) ? new Ok(data) : decoder_error("Int", data); +} +function decode_field(value2, name) { + const not_a_map_error = () => decoder_error("Dict", value2); + if (value2 instanceof Dict || value2 instanceof WeakMap || value2 instanceof Map) { + const entry = map_get(value2, name); + return new Ok(entry.isOk() ? new Some(entry[0]) : new None()); + } else if (value2 === null) { + return not_a_map_error(); + } else if (Object.getPrototypeOf(value2) == Object.prototype) { + return try_get_field(value2, name, () => new Ok(new None())); + } else { + return try_get_field(value2, name, not_a_map_error); + } +} +function try_get_field(value2, field4, or_else) { + try { + return field4 in value2 ? new Ok(new Some(value2[field4])) : or_else(); + } catch { + return or_else(); + } +} + +// build/dev/javascript/gleam_stdlib/gleam/int.mjs +function to_string2(x) { + return to_string(x); +} + +// build/dev/javascript/gleam_stdlib/gleam/list.mjs +function do_reverse_acc(loop$remaining, loop$accumulator) { + while (true) { + let remaining = loop$remaining; + let accumulator = loop$accumulator; + if (remaining.hasLength(0)) { + return accumulator; + } else { + let item = remaining.head; + let rest$1 = remaining.tail; + loop$remaining = rest$1; + loop$accumulator = prepend(item, accumulator); + } + } +} +function do_reverse(list) { + return do_reverse_acc(list, toList([])); +} +function reverse(xs) { + return do_reverse(xs); +} +function do_map(loop$list, loop$fun, loop$acc) { + while (true) { + let list = loop$list; + let fun = loop$fun; + let acc = loop$acc; + if (list.hasLength(0)) { + return reverse(acc); + } else { + let x = list.head; + let xs = list.tail; + loop$list = xs; + loop$fun = fun; + loop$acc = prepend(fun(x), acc); + } + } +} +function map(list, fun) { + return do_map(list, fun, toList([])); +} +function fold(loop$list, loop$initial, loop$fun) { + while (true) { + let list = loop$list; + let initial = loop$initial; + let fun = loop$fun; + if (list.hasLength(0)) { + return initial; + } else { + let x = list.head; + let rest$1 = list.tail; + loop$list = rest$1; + loop$initial = fun(initial, x); + loop$fun = fun; + } + } +} + +// build/dev/javascript/gleam_stdlib/gleam/result.mjs +function map2(result, fun) { + if (result.isOk()) { + let x = result[0]; + return new Ok(fun(x)); + } else { + let e = result[0]; + return new Error(e); + } +} +function map_error(result, fun) { + if (result.isOk()) { + let x = result[0]; + return new Ok(x); + } else { + let error = result[0]; + return new Error(fun(error)); + } +} +function try$(result, fun) { + if (result.isOk()) { + let x = result[0]; + return fun(x); + } else { + let e = result[0]; + return new Error(e); + } +} + +// build/dev/javascript/gleam_stdlib/gleam/string_builder.mjs +function from_strings(strings) { + return concat(strings); +} +function to_string3(builder) { + return identity(builder); +} + +// build/dev/javascript/gleam_stdlib/gleam/dynamic.mjs +var DecodeError = class extends CustomType { + constructor(expected, found, path) { + super(); + this.expected = expected; + this.found = found; + this.path = path; + } +}; +function from(a) { + return identity(a); +} +function dynamic(value2) { + return new Ok(value2); +} +function string(data) { + return decode_string(data); +} +function classify(data) { + return classify_dynamic(data); +} +function int(data) { + return decode_int(data); +} +function any(decoders) { + return (data) => { + if (decoders.hasLength(0)) { + return new Error( + toList([new DecodeError("another type", classify(data), toList([]))]) + ); + } else { + let decoder2 = decoders.head; + let decoders$1 = decoders.tail; + let $ = decoder2(data); + if ($.isOk()) { + let decoded = $[0]; + return new Ok(decoded); + } else { + return any(decoders$1)(data); + } + } + }; +} +function push_path(error, name) { + let name$1 = from(name); + let decoder2 = any( + toList([string, (x) => { + return map2(int(x), to_string2); + }]) + ); + let name$2 = (() => { + let $ = decoder2(name$1); + if ($.isOk()) { + let name$22 = $[0]; + return name$22; + } else { + let _pipe = toList(["<", classify(name$1), ">"]); + let _pipe$1 = from_strings(_pipe); + return to_string3(_pipe$1); + } + })(); + return error.withFields({ path: prepend(name$2, error.path) }); +} +function map_errors(result, f) { + return map_error( + result, + (_capture) => { + return map(_capture, f); + } + ); +} +function field(name, inner_type) { + return (value2) => { + let missing_field_error = new DecodeError("field", "nothing", toList([])); + return try$( + decode_field(value2, name), + (maybe_inner) => { + let _pipe = maybe_inner; + let _pipe$1 = to_result(_pipe, toList([missing_field_error])); + let _pipe$2 = try$(_pipe$1, inner_type); + return map_errors( + _pipe$2, + (_capture) => { + return push_path(_capture, name); + } + ); + } + ); + }; +} + +// build/dev/javascript/gleam_stdlib/gleam/string.mjs +function length2(string3) { + return string_length(string3); +} +function uppercase2(string3) { + return uppercase(string3); +} + +// build/dev/javascript/gleam_stdlib/gleam/bool.mjs +function guard(requirement, consequence, alternative) { + if (requirement) { + return consequence; + } else { + return alternative(); + } +} + +// build/dev/javascript/lustre/lustre/effect.mjs +var Effect = class extends CustomType { + constructor(all) { + super(); + this.all = all; + } +}; +function none() { + return new Effect(toList([])); +} + +// build/dev/javascript/lustre/lustre/internals/vdom.mjs +var Text = class extends CustomType { + constructor(content) { + super(); + this.content = content; + } +}; +var Element = class extends CustomType { + constructor(key, namespace, tag2, attrs, children, self_closing, void$) { + super(); + this.key = key; + this.namespace = namespace; + this.tag = tag2; + this.attrs = attrs; + this.children = children; + this.self_closing = self_closing; + this.void = void$; + } +}; +var Attribute = class extends CustomType { + constructor(x0, x1, as_property) { + super(); + this[0] = x0; + this[1] = x1; + this.as_property = as_property; + } +}; +var Event = class extends CustomType { + constructor(x0, x1) { + super(); + this[0] = x0; + this[1] = x1; + } +}; + +// build/dev/javascript/lustre/lustre/attribute.mjs +function attribute(name, value2) { + return new Attribute(name, from(value2), false); +} +function property(name, value2) { + return new Attribute(name, from(value2), true); +} +function on(name, handler) { + return new Event("on" + name, handler); +} +function style(properties) { + return attribute( + "style", + fold( + properties, + "", + (styles, _use1) => { + let name$1 = _use1[0]; + let value$1 = _use1[1]; + return styles + name$1 + ":" + value$1 + ";"; + } + ) + ); +} +function class$(name) { + return attribute("class", name); +} +function type_(name) { + return attribute("type", name); +} +function value(val) { + return property("value", from(val)); +} + +// build/dev/javascript/lustre/lustre/element.mjs +function element(tag2, attrs, children) { + if (tag2 === "area") { + return new Element("", "", tag2, attrs, toList([]), false, true); + } else if (tag2 === "base") { + return new Element("", "", tag2, attrs, toList([]), false, true); + } else if (tag2 === "br") { + return new Element("", "", tag2, attrs, toList([]), false, true); + } else if (tag2 === "col") { + return new Element("", "", tag2, attrs, toList([]), false, true); + } else if (tag2 === "embed") { + return new Element("", "", tag2, attrs, toList([]), false, true); + } else if (tag2 === "hr") { + return new Element("", "", tag2, attrs, toList([]), false, true); + } else if (tag2 === "img") { + return new Element("", "", tag2, attrs, toList([]), false, true); + } else if (tag2 === "input") { + return new Element("", "", tag2, attrs, toList([]), false, true); + } else if (tag2 === "link") { + return new Element("", "", tag2, attrs, toList([]), false, true); + } else if (tag2 === "meta") { + return new Element("", "", tag2, attrs, toList([]), false, true); + } else if (tag2 === "param") { + return new Element("", "", tag2, attrs, toList([]), false, true); + } else if (tag2 === "source") { + return new Element("", "", tag2, attrs, toList([]), false, true); + } else if (tag2 === "track") { + return new Element("", "", tag2, attrs, toList([]), false, true); + } else if (tag2 === "wbr") { + return new Element("", "", tag2, attrs, toList([]), false, true); + } else { + return new Element("", "", tag2, attrs, children, false, false); + } +} +function text(content) { + return new Text(content); +} + +// build/dev/javascript/lustre/lustre/internals/runtime.mjs +var Dispatch = class extends CustomType { + constructor(x0) { + super(); + this[0] = x0; + } +}; +var Shutdown = class extends CustomType { +}; + +// build/dev/javascript/lustre/vdom.ffi.mjs +function morph(prev, next, dispatch, isComponent = false) { + let out; + let stack2 = [{ prev, next, parent: prev.parentNode }]; + while (stack2.length) { + let { prev: prev2, next: next2, parent } = stack2.pop(); + if (next2.subtree !== void 0) + next2 = next2.subtree(); + if (next2.content !== void 0) { + if (!prev2) { + const created = document.createTextNode(next2.content); + parent.appendChild(created); + out ??= created; + } else if (prev2.nodeType === Node.TEXT_NODE) { + if (prev2.textContent !== next2.content) + prev2.textContent = next2.content; + out ??= prev2; + } else { + const created = document.createTextNode(next2.content); + parent.replaceChild(created, prev2); + out ??= created; + } + } else if (next2.tag !== void 0) { + const created = createElementNode({ + prev: prev2, + next: next2, + dispatch, + stack: stack2, + isComponent + }); + if (!prev2) { + parent.appendChild(created); + } else if (prev2 !== created) { + parent.replaceChild(created, prev2); + } + out ??= created; + } + } + return out; +} +function createElementNode({ prev, next, dispatch, stack: stack2 }) { + const namespace = next.namespace || "http://www.w3.org/1999/xhtml"; + const canMorph = prev && prev.nodeType === Node.ELEMENT_NODE && prev.localName === next.tag && prev.namespaceURI === (next.namespace || "http://www.w3.org/1999/xhtml"); + const el2 = canMorph ? prev : namespace ? document.createElementNS(namespace, next.tag) : document.createElement(next.tag); + let handlersForEl; + if (!registeredHandlers.has(el2)) { + const emptyHandlers = /* @__PURE__ */ new Map(); + registeredHandlers.set(el2, emptyHandlers); + handlersForEl = emptyHandlers; + } else { + handlersForEl = registeredHandlers.get(el2); + } + const prevHandlers = canMorph ? new Set(handlersForEl.keys()) : null; + const prevAttributes = canMorph ? new Set(Array.from(prev.attributes, (a) => a.name)) : null; + let className = null; + let style2 = null; + let innerHTML = null; + for (const attr of next.attrs) { + const name = attr[0]; + const value2 = attr[1]; + const isProperty = attr[2]; + if (isProperty) { + el2[name] = value2; + } else if (name.startsWith("on")) { + const eventName = name.slice(2); + const callback = dispatch(value2); + if (!handlersForEl.has(eventName)) { + el2.addEventListener(eventName, lustreGenericEventHandler); + } + handlersForEl.set(eventName, callback); + if (canMorph) + prevHandlers.delete(eventName); + } else if (name.startsWith("data-lustre-on-")) { + const eventName = name.slice(15); + const callback = dispatch(lustreServerEventHandler); + if (!handlersForEl.has(eventName)) { + el2.addEventListener(eventName, lustreGenericEventHandler); + } + handlersForEl.set(eventName, callback); + el2.setAttribute(name, value2); + } else if (name === "class") { + className = className === null ? value2 : className + " " + value2; + } else if (name === "style") { + style2 = style2 === null ? value2 : style2 + value2; + } else if (name === "dangerous-unescaped-html") { + innerHTML = value2; + } else { + el2.setAttribute(name, value2); + if (name === "value") + el2[name] = value2; + if (canMorph) + prevAttributes.delete(name); + } + } + if (className !== null) { + el2.setAttribute("class", className); + if (canMorph) + prevAttributes.delete("class"); + } + if (style2 !== null) { + el2.setAttribute("style", style2); + if (canMorph) + prevAttributes.delete("style"); + } + if (canMorph) { + for (const attr of prevAttributes) { + el2.removeAttribute(attr); + } + for (const eventName of prevHandlers) { + handlersForEl.delete(eventName); + el2.removeEventListener(eventName, lustreGenericEventHandler); + } + } + if (next.key !== void 0 && next.key !== "") { + el2.setAttribute("data-lustre-key", next.key); + } else if (innerHTML !== null) { + el2.innerHTML = innerHTML; + return el2; + } + let prevChild = el2.firstChild; + let seenKeys = null; + let keyedChildren = null; + let incomingKeyedChildren = null; + let firstChild = next.children[Symbol.iterator]().next().value; + if (canMorph && firstChild !== void 0 && // Explicit checks are more verbose but truthy checks force a bunch of comparisons + // we don't care about: it's never gonna be a number etc. + firstChild.key !== void 0 && firstChild.key !== "") { + seenKeys = /* @__PURE__ */ new Set(); + keyedChildren = getKeyedChildren(prev); + incomingKeyedChildren = getKeyedChildren(next); + } + for (const child of next.children) { + if (child.key !== void 0 && seenKeys !== null) { + while (prevChild && !incomingKeyedChildren.has(prevChild.getAttribute("data-lustre-key"))) { + const nextChild = prevChild.nextSibling; + el2.removeChild(prevChild); + prevChild = nextChild; + } + if (keyedChildren.size === 0) { + stack2.unshift({ prev: prevChild, next: child, parent: el2 }); + prevChild = prevChild?.nextSibling; + continue; + } + if (seenKeys.has(child.key)) { + console.warn(`Duplicate key found in Lustre vnode: ${child.key}`); + stack2.unshift({ prev: null, next: child, parent: el2 }); + continue; + } + seenKeys.add(child.key); + const keyedChild = keyedChildren.get(child.key); + if (!keyedChild && !prevChild) { + stack2.unshift({ prev: null, next: child, parent: el2 }); + continue; + } + if (!keyedChild && prevChild !== null) { + const placeholder = document.createTextNode(""); + el2.insertBefore(placeholder, prevChild); + stack2.unshift({ prev: placeholder, next: child, parent: el2 }); + continue; + } + if (!keyedChild || keyedChild === prevChild) { + stack2.unshift({ prev: prevChild, next: child, parent: el2 }); + prevChild = prevChild?.nextSibling; + continue; + } + el2.insertBefore(keyedChild, prevChild); + stack2.unshift({ prev: keyedChild, next: child, parent: el2 }); + } else { + stack2.unshift({ prev: prevChild, next: child, parent: el2 }); + prevChild = prevChild?.nextSibling; + } + } + while (prevChild) { + const next2 = prevChild.nextSibling; + el2.removeChild(prevChild); + prevChild = next2; + } + return el2; +} +var registeredHandlers = /* @__PURE__ */ new WeakMap(); +function lustreGenericEventHandler(event2) { + const target = event2.currentTarget; + if (!registeredHandlers.has(target)) { + target.removeEventListener(event2.type, lustreGenericEventHandler); + return; + } + const handlersForEventTarget = registeredHandlers.get(target); + if (!handlersForEventTarget.has(event2.type)) { + target.removeEventListener(event2.type, lustreGenericEventHandler); + return; + } + handlersForEventTarget.get(event2.type)(event2); +} +function lustreServerEventHandler(event2) { + const el2 = event2.target; + const tag2 = el2.getAttribute(`data-lustre-on-${event2.type}`); + const data = JSON.parse(el2.getAttribute("data-lustre-data") || "{}"); + const include = JSON.parse(el2.getAttribute("data-lustre-include") || "[]"); + switch (event2.type) { + case "input": + case "change": + include.push("target.value"); + break; + } + return { + tag: tag2, + data: include.reduce( + (data2, property2) => { + const path = property2.split("."); + for (let i = 0, o = data2, e = event2; i < path.length; i++) { + if (i === path.length - 1) { + o[path[i]] = e[path[i]]; + } else { + o[path[i]] ??= {}; + e = e[path[i]]; + o = o[path[i]]; + } + } + return data2; + }, + { data } + ) + }; +} +function getKeyedChildren(el2) { + const keyedChildren = /* @__PURE__ */ new Map(); + if (el2) { + for (const child of el2.children) { + const key = child.key || child?.getAttribute("data-lustre-key"); + if (key) + keyedChildren.set(key, child); + } + } + return keyedChildren; +} + +// build/dev/javascript/lustre/client-runtime.ffi.mjs +var LustreClientApplication2 = class _LustreClientApplication { + #root = null; + #queue = []; + #effects = []; + #didUpdate = false; + #isComponent = false; + #model = null; + #update = null; + #view = null; + static start(flags, selector, init3, update3, view2) { + if (!is_browser()) + return new Error(new NotABrowser()); + const root2 = selector instanceof HTMLElement ? selector : document.querySelector(selector); + if (!root2) + return new Error(new ElementNotFound(selector)); + const app = new _LustreClientApplication(init3(flags), update3, view2, root2); + return new Ok((msg) => app.send(msg)); + } + constructor([model, effects], update3, view2, root2 = document.body, isComponent = false) { + this.#model = model; + this.#update = update3; + this.#view = view2; + this.#root = root2; + this.#effects = effects.all.toArray(); + this.#didUpdate = true; + this.#isComponent = isComponent; + window.requestAnimationFrame(() => this.#tick()); + } + send(action) { + switch (true) { + case action instanceof Dispatch: { + this.#queue.push(action[0]); + this.#tick(); + return; + } + case action instanceof Shutdown: { + this.#shutdown(); + return; + } + default: + return; + } + } + emit(event2, data) { + this.#root.dispatchEvent( + new CustomEvent(event2, { + bubbles: true, + detail: data, + composed: true + }) + ); + } + #tick() { + this.#flush_queue(); + const vdom = this.#view(this.#model); + const dispatch = (handler) => (e) => { + const result = handler(e); + if (result instanceof Ok) { + this.send(new Dispatch(result[0])); + } + }; + this.#didUpdate = false; + this.#root = morph(this.#root, vdom, dispatch, this.#isComponent); + } + #flush_queue(iterations = 0) { + while (this.#queue.length) { + const [next, effects] = this.#update(this.#model, this.#queue.shift()); + this.#didUpdate ||= !isEqual(this.#model, next); + this.#model = next; + this.#effects = this.#effects.concat(effects.all.toArray()); + } + while (this.#effects.length) { + this.#effects.shift()( + (msg) => this.send(new Dispatch(msg)), + (event2, data) => this.emit(event2, data) + ); + } + if (this.#queue.length) { + if (iterations < 5) { + this.#flush_queue(++iterations); + } else { + window.requestAnimationFrame(() => this.#tick()); + } + } + } + #shutdown() { + this.#root.remove(); + this.#root = null; + this.#model = null; + this.#queue = []; + this.#effects = []; + this.#didUpdate = false; + this.#update = () => { + }; + this.#view = () => { + }; + } +}; +var start = (app, selector, flags) => LustreClientApplication2.start( + flags, + selector, + app.init, + app.update, + app.view +); +var is_browser = () => window && window.document; + +// build/dev/javascript/lustre/lustre.mjs +var App = class extends CustomType { + constructor(init3, update3, view2, on_attribute_change) { + super(); + this.init = init3; + this.update = update3; + this.view = view2; + this.on_attribute_change = on_attribute_change; + } +}; +var ElementNotFound = class extends CustomType { + constructor(selector) { + super(); + this.selector = selector; + } +}; +var NotABrowser = class extends CustomType { +}; +function application(init3, update3, view2) { + return new App(init3, update3, view2, new None()); +} +function simple(init3, update3, view2) { + let init$1 = (flags) => { + return [init3(flags), none()]; + }; + let update$1 = (model, msg) => { + return [update3(model, msg), none()]; + }; + return application(init$1, update$1, view2); +} +function start3(app, selector, flags) { + return guard( + !is_browser(), + new Error(new NotABrowser()), + () => { + return start(app, selector, flags); + } + ); +} + +// build/dev/javascript/lustre/lustre/event.mjs +function on2(name, handler) { + return on(name, handler); +} +function on_click(msg) { + return on2("click", (_) => { + return new Ok(msg); + }); +} + +// build/dev/javascript/lustre/lustre/element/html.mjs +function div(attrs, children) { + return element("div", attrs, children); +} +function span(attrs, children) { + return element("span", attrs, children); +} +function button(attrs, children) { + return element("button", attrs, children); +} +function input(attrs) { + return element("input", attrs, toList([])); +} +function label(attrs, children) { + return element("label", attrs, children); +} + +// build/dev/javascript/lustre_ui/lustre/ui/button.mjs +function button2(attributes, children) { + return button( + prepend( + class$("lustre-ui-button"), + prepend(type_("button"), attributes) + ), + children + ); +} + +// build/dev/javascript/lustre_ui/lustre/ui/layout/stack.mjs +function of(element2, attributes, children) { + return element2( + prepend(class$("lustre-ui-stack"), attributes), + children + ); +} +function packed() { + return class$("packed"); +} + +// build/dev/javascript/lustre_ui/lustre/ui/field.mjs +function of2(element2, attributes, label2, input4, message) { + return of( + element2, + prepend( + class$("lustre-ui-field"), + prepend(packed(), attributes) + ), + toList([ + span(toList([class$("label")]), label2), + input4, + span(toList([class$("message")]), message) + ]) + ); +} +function field2(attributes, label2, input4, message) { + return of2(label, attributes, label2, input4, message); +} + +// build/dev/javascript/lustre_ui/lustre/ui/input.mjs +function input2(attributes) { + return input( + prepend(class$("lustre-ui-input"), attributes) + ); +} + +// build/dev/javascript/lustre_ui/lustre/ui/layout/aside.mjs +function of3(element2, attributes, side, main2) { + return element2( + prepend(class$("lustre-ui-aside"), attributes), + toList([side, main2]) + ); +} +function aside(attributes, side, main2) { + return of3(div, attributes, side, main2); +} +function content_first() { + return class$("content-first"); +} +function align_centre() { + return class$("align-centre"); +} + +// build/dev/javascript/lustre_ui/lustre/ui/layout/centre.mjs +function of4(element2, attributes, children) { + return element2( + prepend(class$("lustre-ui-centre"), attributes), + toList([children]) + ); +} +function centre(attributes, children) { + return of4(div, attributes, children); +} + +// build/dev/javascript/gleam_community_colour/gleam_community/colour.mjs +var Rgba = class extends CustomType { + constructor(r, g, b, a) { + super(); + this.r = r; + this.g = g; + this.b = b; + this.a = a; + } +}; +var light_red = new Rgba( + 0.9372549019607843, + 0.1607843137254902, + 0.1607843137254902, + 1 +); +var red = new Rgba(0.8, 0, 0, 1); +var dark_red = new Rgba(0.6431372549019608, 0, 0, 1); +var light_orange = new Rgba( + 0.9882352941176471, + 0.6862745098039216, + 0.24313725490196078, + 1 +); +var orange = new Rgba(0.9607843137254902, 0.4745098039215686, 0, 1); +var dark_orange = new Rgba( + 0.807843137254902, + 0.3607843137254902, + 0, + 1 +); +var light_yellow = new Rgba( + 1, + 0.9137254901960784, + 0.30980392156862746, + 1 +); +var yellow = new Rgba(0.9294117647058824, 0.8313725490196079, 0, 1); +var dark_yellow = new Rgba( + 0.7686274509803922, + 0.6274509803921569, + 0, + 1 +); +var light_green = new Rgba( + 0.5411764705882353, + 0.8862745098039215, + 0.20392156862745098, + 1 +); +var green = new Rgba( + 0.45098039215686275, + 0.8235294117647058, + 0.08627450980392157, + 1 +); +var dark_green = new Rgba( + 0.3058823529411765, + 0.6039215686274509, + 0.023529411764705882, + 1 +); +var light_blue = new Rgba( + 0.4470588235294118, + 0.6235294117647059, + 0.8117647058823529, + 1 +); +var blue = new Rgba( + 0.20392156862745098, + 0.396078431372549, + 0.6431372549019608, + 1 +); +var dark_blue = new Rgba( + 0.12549019607843137, + 0.2901960784313726, + 0.5294117647058824, + 1 +); +var light_purple = new Rgba( + 0.6784313725490196, + 0.4980392156862745, + 0.6588235294117647, + 1 +); +var purple = new Rgba( + 0.4588235294117647, + 0.3137254901960784, + 0.4823529411764706, + 1 +); +var dark_purple = new Rgba( + 0.3607843137254902, + 0.20784313725490197, + 0.4, + 1 +); +var light_brown = new Rgba( + 0.9137254901960784, + 0.7254901960784313, + 0.43137254901960786, + 1 +); +var brown = new Rgba( + 0.7568627450980392, + 0.49019607843137253, + 0.06666666666666667, + 1 +); +var dark_brown = new Rgba( + 0.5607843137254902, + 0.34901960784313724, + 0.00784313725490196, + 1 +); +var black = new Rgba(0, 0, 0, 1); +var white = new Rgba(1, 1, 1, 1); +var light_grey = new Rgba( + 0.9333333333333333, + 0.9333333333333333, + 0.9254901960784314, + 1 +); +var grey = new Rgba( + 0.8274509803921568, + 0.8431372549019608, + 0.8117647058823529, + 1 +); +var dark_grey = new Rgba( + 0.7294117647058823, + 0.7411764705882353, + 0.7137254901960784, + 1 +); +var light_gray = new Rgba( + 0.9333333333333333, + 0.9333333333333333, + 0.9254901960784314, + 1 +); +var gray = new Rgba( + 0.8274509803921568, + 0.8431372549019608, + 0.8117647058823529, + 1 +); +var dark_gray = new Rgba( + 0.7294117647058823, + 0.7411764705882353, + 0.7137254901960784, + 1 +); +var light_charcoal = new Rgba( + 0.5333333333333333, + 0.5411764705882353, + 0.5215686274509804, + 1 +); +var charcoal = new Rgba( + 0.3333333333333333, + 0.3411764705882353, + 0.3254901960784314, + 1 +); +var dark_charcoal = new Rgba( + 0.1803921568627451, + 0.20392156862745098, + 0.21176470588235294, + 1 +); +var pink = new Rgba(1, 0.6862745098039216, 0.9529411764705882, 1); + +// build/dev/javascript/lustre_ui/lustre/ui.mjs +var aside2 = aside; +var button3 = button2; +var centre2 = centre; +var field3 = field2; +var input3 = input2; + +// build/dev/javascript/app/app.mjs +var Model = class extends CustomType { + constructor(value2, length3, max2) { + super(); + this.value = value2; + this.length = length3; + this.max = max2; + } +}; +var UserUpdatedMessage = class extends CustomType { + constructor(value2) { + super(); + this.value = value2; + } +}; +var UserResetMessage = class extends CustomType { +}; +function init2(_) { + return new Model("", 0, 10); +} +function update2(model, msg) { + if (msg instanceof UserUpdatedMessage) { + let value2 = msg.value; + let length3 = length2(value2); + let $ = length3 <= model.max; + if ($) { + return model.withFields({ value: value2, length: length3 }); + } else { + return model; + } + } else { + return model.withFields({ value: "", length: 0 }); + } +} +function view(model) { + let styles = toList([ + ["width", "100vw"], + ["height", "100vh"], + ["padding", "1rem"] + ]); + let length3 = to_string2(model.length); + let max2 = to_string2(model.max); + let make_it_loud = (event2) => { + return try$( + field("target", dynamic)(event2), + (target) => { + return try$( + field("value", string)(target), + (value2) => { + let loud = uppercase2(value2); + return new Ok(new UserUpdatedMessage(loud)); + } + ); + } + ); + }; + return centre2( + toList([style(styles)]), + aside2( + toList([content_first(), align_centre()]), + field3( + toList([]), + toList([text("Write a LOUD message:")]), + input3( + toList([ + value(model.value), + on2("input", make_it_loud) + ]) + ), + toList([text(length3 + "/" + max2)]) + ), + button3( + toList([on_click(new UserResetMessage())]), + toList([text("Reset")]) + ) + ) + ); +} +function main() { + let app = simple(init2, update2, view); + let $ = start3(app, "#app", void 0); + if (!$.isOk()) { + throw makeError( + "assignment_no_match", + "app", + 16, + "main", + "Assignment pattern did not match", + { value: $ } + ); + } + return $; +} + +// build/.lustre/entry.mjs +main(); diff --git a/examples/04-custom-event-handlers/src/app.gleam b/examples/04-custom-event-handlers/src/app.gleam index e5d7fe1..725b04b 100644 --- a/examples/04-custom-event-handlers/src/app.gleam +++ b/examples/04-custom-event-handlers/src/app.gleam @@ -6,16 +6,8 @@ import lustre import lustre/attribute import lustre/element.{type Element} import lustre/event -// These examples are written with `lustre/ui` in mind. They'll work regardless, -// but to see what `lustre/ui` can do make sure to run each of these examples with -// the `--use-example-styles` flag: -// -// $ gleam run -m lustre/dev start --use-example-styles -// -// In your own apps, make sure to add the `lustre/ui` dependency and include the -// stylesheet somewhere. import lustre/ui -import lustre/ui/aside +import lustre/ui/layout/aside // MAIN ------------------------------------------------------------------------ diff --git a/examples/05-http-requests/index.html b/examples/05-http-requests/index.html new file mode 100644 index 0000000..36ddf10 --- /dev/null +++ b/examples/05-http-requests/index.html @@ -0,0 +1,19 @@ +<!doctype html> +<html lang="en"> + <head> + <meta charset="UTF-8" /> + <meta name="viewport" content="width=device-width, initial-scale=1.0" /> + + <title>🚧 app</title> + + <link + rel="stylesheet" + href="./build/dev/javascript/lustre_ui/priv/static/lustre-ui.css" + /> + <script type="module" src="./priv/static/app.mjs"></script> + </head> + + <body> + <div id="app"></div> + </body> +</html> diff --git a/examples/05-http-requests/manifest.toml b/examples/05-http-requests/manifest.toml index 2054952..48643f2 100644 --- a/examples/05-http-requests/manifest.toml +++ b/examples/05-http-requests/manifest.toml @@ -3,9 +3,14 @@ packages = [ { name = "argv", version = "1.0.2", build_tools = ["gleam"], requirements = [], otp_app = "argv", source = "hex", outer_checksum = "BA1FF0929525DEBA1CE67256E5ADF77A7CDDFE729E3E3F57A5BDCAA031DED09D" }, + { name = "birl", version = "1.6.1", build_tools = ["gleam"], requirements = ["gleam_stdlib", "ranger"], otp_app = "birl", source = "hex", outer_checksum = "976CFF85D34D50F7775896615A71745FBE0C325E50399787088F941B539A0497" }, + { name = "exception", version = "2.0.0", build_tools = ["gleam"], requirements = ["gleam_stdlib"], otp_app = "exception", source = "hex", outer_checksum = "F5580D584F16A20B7FCDCABF9E9BE9A2C1F6AC4F9176FA6DD0B63E3B20D450AA" }, { name = "filepath", version = "1.0.0", build_tools = ["gleam"], requirements = ["gleam_stdlib"], otp_app = "filepath", source = "hex", outer_checksum = "EFB6FF65C98B2A16378ABC3EE2B14124168C0CE5201553DE652E2644DCFDB594" }, + { name = "filespy", version = "0.3.0", build_tools = ["gleam"], requirements = ["fs", "gleam_erlang", "gleam_otp", "gleam_stdlib"], otp_app = "filespy", source = "hex", outer_checksum = "75F5910B31A528681D25316AAAE6C91CD3E977BD2492946564B7242FF941FB7A" }, + { name = "fs", version = "8.6.1", build_tools = ["rebar3"], requirements = [], otp_app = "fs", source = "hex", outer_checksum = "61EA2BDAEDAE4E2024D0D25C63E44DCCF65622D4402DB4A2DF12868D1546503F" }, { name = "gleam_community_ansi", version = "1.4.0", build_tools = ["gleam"], requirements = ["gleam_community_colour", "gleam_stdlib"], otp_app = "gleam_community_ansi", source = "hex", outer_checksum = "FE79E08BF97009729259B6357EC058315B6FBB916FAD1C2FF9355115FEB0D3A4" }, { name = "gleam_community_colour", version = "1.4.0", build_tools = ["gleam"], requirements = ["gleam_json", "gleam_stdlib"], otp_app = "gleam_community_colour", source = "hex", outer_checksum = "795964217EBEDB3DA656F5EB8F67D7AD22872EB95182042D3E7AFEF32D3FD2FE" }, + { name = "gleam_crypto", version = "1.3.0", build_tools = ["gleam"], requirements = ["gleam_stdlib"], otp_app = "gleam_crypto", source = "hex", outer_checksum = "ADD058DEDE8F0341F1ADE3AAC492A224F15700829D9A3A3F9ADF370F875C51B7" }, { name = "gleam_erlang", version = "0.25.0", build_tools = ["gleam"], requirements = ["gleam_stdlib"], otp_app = "gleam_erlang", source = "hex", outer_checksum = "054D571A7092D2A9727B3E5D183B7507DAB0DA41556EC9133606F09C15497373" }, { name = "gleam_fetch", version = "0.4.0", build_tools = ["gleam"], requirements = ["gleam_http", "gleam_javascript", "gleam_stdlib"], otp_app = "gleam_fetch", source = "hex", outer_checksum = "7446410A44A1D1328F5BC1FF4FC9CBD1570479EA69349237B3F82E34521CCC10" }, { name = "gleam_http", version = "3.6.0", build_tools = ["gleam"], requirements = ["gleam_stdlib"], otp_app = "gleam_http", source = "hex", outer_checksum = "8C07DF9DF8CC7F054C650839A51C30A7D3C26482AC241C899C1CEA86B22DBE51" }, @@ -15,18 +20,25 @@ packages = [ { name = "gleam_package_interface", version = "1.0.0", build_tools = ["gleam"], requirements = ["gleam_json", "gleam_stdlib"], otp_app = "gleam_package_interface", source = "hex", outer_checksum = "52A721BCA972C8099BB881195D821AAA64B9F2655BECC102165D5A1097731F01" }, { name = "gleam_stdlib", version = "0.36.0", build_tools = ["gleam"], requirements = [], otp_app = "gleam_stdlib", source = "hex", outer_checksum = "C0D14D807FEC6F8A08A7C9EF8DFDE6AE5C10E40E21325B2B29365965D82EB3D4" }, { name = "glearray", version = "0.2.1", build_tools = ["gleam"], requirements = ["gleam_stdlib"], otp_app = "glearray", source = "hex", outer_checksum = "908154F695D330E06A37FAB2C04119E8F315D643206F8F32B6A6C14A8709FFF4" }, - { name = "gleeunit", version = "1.0.2", build_tools = ["gleam"], requirements = ["gleam_stdlib"], otp_app = "gleeunit", source = "hex", outer_checksum = "D364C87AFEB26BDB4FB8A5ABDE67D635DC9FA52D6AB68416044C35B096C6882D" }, + { name = "gleeunit", version = "1.1.2", build_tools = ["gleam"], requirements = ["gleam_stdlib"], otp_app = "gleeunit", source = "hex", outer_checksum = "72CDC3D3F719478F26C4E2C5FED3E657AC81EC14A47D2D2DEBB8693CA3220C3B" }, { name = "glint", version = "0.18.0", build_tools = ["gleam"], requirements = ["gleam_community_ansi", "gleam_community_colour", "gleam_stdlib", "snag"], otp_app = "glint", source = "hex", outer_checksum = "BB0F14643CC51C069A5DC6E9082EAFCD9967AFD1C9CC408803D1A40A3FD43B54" }, - { name = "lustre", version = "4.0.0", build_tools = ["gleam"], requirements = ["gleam_erlang", "gleam_json", "gleam_otp", "gleam_stdlib"], otp_app = "lustre", source = "hex", outer_checksum = "1D40C1378279F7015687F8C9DB739D6880BB0B843F4428B85C61EDDA8BF21FC6" }, - { name = "lustre_dev_tools", version = "1.0.0", build_tools = ["gleam"], requirements = ["argv", "filepath", "gleam_community_ansi", "gleam_erlang", "gleam_json", "gleam_otp", "gleam_package_interface", "gleam_stdlib", "glint", "simplifile", "spinner", "tom"], otp_app = "lustre_dev_tools", source = "hex", outer_checksum = "66142ADDCA3D6C63A89E016CF6C21E07D06D6DC92479325182A07C360BD026D3" }, + { name = "glisten", version = "2.0.0", build_tools = ["gleam"], requirements = ["gleam_erlang", "gleam_otp", "gleam_stdlib"], otp_app = "glisten", source = "hex", outer_checksum = "CF3A9383E9BA4A8CBAF2F7B799716290D02F2AC34E7A77556B49376B662B9314" }, + { name = "hpack_erl", version = "0.3.0", build_tools = ["rebar3"], requirements = [], otp_app = "hpack", source = "hex", outer_checksum = "D6137D7079169D8C485C6962DFE261AF5B9EF60FBC557344511C1E65E3D95FB0" }, + { name = "logging", version = "1.0.1", build_tools = ["gleam"], requirements = ["gleam_stdlib"], otp_app = "logging", source = "hex", outer_checksum = "82C112ED9B6C30C1772A6FE2613B94B13F62EA35F5869A2630D13948D297BD39" }, + { name = "lustre", version = "4.1.7", build_tools = ["gleam"], requirements = ["gleam_erlang", "gleam_json", "gleam_otp", "gleam_stdlib"], otp_app = "lustre", source = "hex", outer_checksum = "64F5D7E4DF51280185F70296ACB7D3DCC9B5DA09EFC5257F0E5601846DFBEF23" }, + { name = "lustre_dev_tools", version = "1.2.1", build_tools = ["gleam"], requirements = ["argv", "filepath", "filespy", "fs", "gleam_community_ansi", "gleam_erlang", "gleam_http", "gleam_json", "gleam_otp", "gleam_package_interface", "gleam_stdlib", "glint", "glisten", "mist", "simplifile", "spinner", "tom", "wisp"], otp_app = "lustre_dev_tools", source = "hex", outer_checksum = "930BBE8C4E92A16857C31B7B12616651433E1643304696FB93B69D659CE3ADC2" }, { name = "lustre_http", version = "0.5.2", build_tools = ["gleam"], requirements = ["gleam_fetch", "gleam_http", "gleam_javascript", "gleam_json", "gleam_stdlib", "lustre"], otp_app = "lustre_http", source = "hex", outer_checksum = "FB0478CBFA6B16DBE8ECA326DAE2EC15645E04900595EF2C4F039ABFA0512ABA" }, - { name = "lustre_ui", version = "0.5.0", build_tools = ["gleam"], requirements = ["gleam_community_colour", "gleam_json", "gleam_stdlib", "lustre"], otp_app = "lustre_ui", source = "hex", outer_checksum = "7ECB5414BE926082401891C62FAAA21221FC0B7A2F0568A492349F48DC2B02A0" }, + { name = "lustre_ui", version = "0.6.0", build_tools = ["gleam"], requirements = ["gleam_community_colour", "gleam_json", "gleam_stdlib", "lustre"], otp_app = "lustre_ui", source = "hex", outer_checksum = "FA1F9E89D89CDD5DF376ED86ABA8A38441CB2E664CD4D402F22A49DA4D7BB56D" }, + { name = "marceau", version = "1.1.0", build_tools = ["gleam"], requirements = [], otp_app = "marceau", source = "hex", outer_checksum = "1AAD727A30BE0F95562C3403BB9B27C823797AD90037714255EEBF617B1CDA81" }, + { name = "mist", version = "1.0.0", build_tools = ["gleam"], requirements = ["birl", "gleam_erlang", "gleam_http", "gleam_otp", "gleam_stdlib", "glisten", "hpack_erl", "logging"], otp_app = "mist", source = "hex", outer_checksum = "7765E53DCC9ACCACF217B8E0CA3DE7E848C783BFAE5118B75011E81C2C80385C" }, + { name = "ranger", version = "1.2.0", build_tools = ["gleam"], requirements = ["gleam_stdlib"], otp_app = "ranger", source = "hex", outer_checksum = "1566C272B1D141B3BBA38B25CB761EF56E312E79EC0E2DFD4D3C19FB0CC1F98C" }, { name = "repeatedly", version = "2.1.1", build_tools = ["gleam"], requirements = [], otp_app = "repeatedly", source = "hex", outer_checksum = "38808C3EC382B0CD981336D5879C24ECB37FCB9C1D1BD128F7A80B0F74404D79" }, - { name = "simplifile", version = "1.5.1", build_tools = ["gleam"], requirements = ["gleam_stdlib"], otp_app = "simplifile", source = "hex", outer_checksum = "C44DB387524F90DC42142699C78C850003289D32C7C99C7D32873792A299CDF7" }, + { name = "simplifile", version = "1.7.0", build_tools = ["gleam"], requirements = ["filepath", "gleam_stdlib"], otp_app = "simplifile", source = "hex", outer_checksum = "1D5DFA3A2F9319EC85825F6ED88B8E449F381B0D55A62F5E61424E748E7DDEB0" }, { name = "snag", version = "0.3.0", build_tools = ["gleam"], requirements = ["gleam_stdlib"], otp_app = "snag", source = "hex", outer_checksum = "54D32E16E33655346AA3E66CBA7E191DE0A8793D2C05284E3EFB90AD2CE92BCC" }, { name = "spinner", version = "1.1.0", build_tools = ["gleam"], requirements = ["gleam_community_ansi", "gleam_erlang", "gleam_stdlib", "glearray", "repeatedly"], otp_app = "spinner", source = "hex", outer_checksum = "200BA3D4A04D468898E63C0D316E23F526E02514BC46454091975CB5BAE41E8F" }, { name = "thoas", version = "0.4.1", build_tools = ["rebar3"], requirements = [], otp_app = "thoas", source = "hex", outer_checksum = "4918D50026C073C4AB1388437132C77A6F6F7C8AC43C60C13758CC0ADCE2134E" }, { name = "tom", version = "0.3.0", build_tools = ["gleam"], requirements = ["gleam_stdlib"], otp_app = "tom", source = "hex", outer_checksum = "0831C73E45405A2153091226BF98FB485ED16376988602CC01A5FD086B82D577" }, + { name = "wisp", version = "0.14.0", build_tools = ["gleam"], requirements = ["exception", "gleam_crypto", "gleam_erlang", "gleam_http", "gleam_json", "gleam_stdlib", "logging", "marceau", "mist", "simplifile"], otp_app = "wisp", source = "hex", outer_checksum = "9F5453AF1F9275E6F8707BC815D6A6A9DF41551921B16FBDBA52883773BAE684" }, ] [requirements] diff --git a/examples/05-http-requests/priv/static/app.mjs b/examples/05-http-requests/priv/static/app.mjs new file mode 100644 index 0000000..ff806b3 --- /dev/null +++ b/examples/05-http-requests/priv/static/app.mjs @@ -0,0 +1,3072 @@ +// build/dev/javascript/prelude.mjs +var CustomType = class { + withFields(fields) { + let properties = Object.keys(this).map( + (label2) => label2 in fields ? fields[label2] : this[label2] + ); + return new this.constructor(...properties); + } +}; +var List = class { + static fromArray(array3, tail) { + let t = tail || new Empty(); + for (let i = array3.length - 1; i >= 0; --i) { + t = new NonEmpty(array3[i], t); + } + return t; + } + [Symbol.iterator]() { + return new ListIterator(this); + } + toArray() { + return [...this]; + } + // @internal + atLeastLength(desired) { + for (let _ of this) { + if (desired <= 0) + return true; + desired--; + } + return desired <= 0; + } + // @internal + hasLength(desired) { + for (let _ of this) { + if (desired <= 0) + return false; + desired--; + } + return desired === 0; + } + countLength() { + let length4 = 0; + for (let _ of this) + length4++; + return length4; + } +}; +function prepend(element2, tail) { + return new NonEmpty(element2, tail); +} +function toList(elements, tail) { + return List.fromArray(elements, tail); +} +var ListIterator = class { + #current; + constructor(current) { + this.#current = current; + } + next() { + if (this.#current instanceof Empty) { + return { done: true }; + } else { + let { head, tail } = this.#current; + this.#current = tail; + return { value: head, done: false }; + } + } +}; +var Empty = class extends List { +}; +var NonEmpty = class extends List { + constructor(head, tail) { + super(); + this.head = head; + this.tail = tail; + } +}; +var BitArray = class _BitArray { + constructor(buffer) { + if (!(buffer instanceof Uint8Array)) { + throw "BitArray can only be constructed from a Uint8Array"; + } + this.buffer = buffer; + } + // @internal + get length() { + return this.buffer.length; + } + // @internal + byteAt(index3) { + return this.buffer[index3]; + } + // @internal + floatAt(index3) { + return byteArrayToFloat(this.buffer.slice(index3, index3 + 8)); + } + // @internal + intFromSlice(start4, end) { + return byteArrayToInt(this.buffer.slice(start4, end)); + } + // @internal + binaryFromSlice(start4, end) { + return new _BitArray(this.buffer.slice(start4, end)); + } + // @internal + sliceAfter(index3) { + return new _BitArray(this.buffer.slice(index3)); + } +}; +function byteArrayToInt(byteArray) { + byteArray = byteArray.reverse(); + let value = 0; + for (let i = byteArray.length - 1; i >= 0; i--) { + value = value * 256 + byteArray[i]; + } + return value; +} +function byteArrayToFloat(byteArray) { + return new Float64Array(byteArray.reverse().buffer)[0]; +} +var Result = class _Result extends CustomType { + // @internal + static isResult(data) { + return data instanceof _Result; + } +}; +var Ok = class extends Result { + constructor(value) { + super(); + this[0] = value; + } + // @internal + isOk() { + return true; + } +}; +var Error = class extends Result { + constructor(detail) { + super(); + this[0] = detail; + } + // @internal + isOk() { + return false; + } +}; +function isEqual(x, y) { + let values = [x, y]; + while (values.length) { + let a = values.pop(); + let b = values.pop(); + if (a === b) + continue; + if (!isObject(a) || !isObject(b)) + return false; + let unequal = !structurallyCompatibleObjects(a, b) || unequalDates(a, b) || unequalBuffers(a, b) || unequalArrays(a, b) || unequalMaps(a, b) || unequalSets(a, b) || unequalRegExps(a, b); + if (unequal) + return false; + const proto = Object.getPrototypeOf(a); + if (proto !== null && typeof proto.equals === "function") { + try { + if (a.equals(b)) + continue; + else + return false; + } catch { + } + } + let [keys2, get3] = getters(a); + for (let k of keys2(a)) { + values.push(get3(a, k), get3(b, k)); + } + } + return true; +} +function getters(object3) { + if (object3 instanceof Map) { + return [(x) => x.keys(), (x, y) => x.get(y)]; + } else { + let extra = object3 instanceof globalThis.Error ? ["message"] : []; + return [(x) => [...extra, ...Object.keys(x)], (x, y) => x[y]]; + } +} +function unequalDates(a, b) { + return a instanceof Date && (a > b || a < b); +} +function unequalBuffers(a, b) { + return a.buffer instanceof ArrayBuffer && a.BYTES_PER_ELEMENT && !(a.byteLength === b.byteLength && a.every((n, i) => n === b[i])); +} +function unequalArrays(a, b) { + return Array.isArray(a) && a.length !== b.length; +} +function unequalMaps(a, b) { + return a instanceof Map && a.size !== b.size; +} +function unequalSets(a, b) { + return a instanceof Set && (a.size != b.size || [...a].some((e) => !b.has(e))); +} +function unequalRegExps(a, b) { + return a instanceof RegExp && (a.source !== b.source || a.flags !== b.flags); +} +function isObject(a) { + return typeof a === "object" && a !== null; +} +function structurallyCompatibleObjects(a, b) { + if (typeof a !== "object" && typeof b !== "object" && (!a || !b)) + return false; + let nonstructural = [Promise, WeakSet, WeakMap, Function]; + if (nonstructural.some((c) => a instanceof c)) + return false; + return a.constructor === b.constructor; +} +function makeError(variant, module, line, fn, message, extra) { + let error = new globalThis.Error(message); + error.gleam_error = variant; + error.module = module; + error.line = line; + error.fn = fn; + for (let k in extra) + error[k] = extra[k]; + return error; +} + +// build/dev/javascript/gleam_stdlib/gleam/option.mjs +var Some = class extends CustomType { + constructor(x0) { + super(); + this[0] = x0; + } +}; +var None = class extends CustomType { +}; +function to_result(option, e) { + if (option instanceof Some) { + let a = option[0]; + return new Ok(a); + } else { + return new Error(e); + } +} +function from_result(result) { + if (result.isOk()) { + let a = result[0]; + return new Some(a); + } else { + return new None(); + } +} +function unwrap(option, default$) { + if (option instanceof Some) { + let x = option[0]; + return x; + } else { + return default$; + } +} +function map(option, fun) { + if (option instanceof Some) { + let x = option[0]; + return new Some(fun(x)); + } else { + return new None(); + } +} + +// build/dev/javascript/gleam_stdlib/gleam/regex.mjs +var Match = class extends CustomType { + constructor(content, submatches) { + super(); + this.content = content; + this.submatches = submatches; + } +}; +var CompileError = class extends CustomType { + constructor(error, byte_index) { + super(); + this.error = error; + this.byte_index = byte_index; + } +}; +var Options = class extends CustomType { + constructor(case_insensitive, multi_line) { + super(); + this.case_insensitive = case_insensitive; + this.multi_line = multi_line; + } +}; +function compile(pattern, options) { + return compile_regex(pattern, options); +} +function scan(regex, string3) { + return regex_scan(regex, string3); +} + +// build/dev/javascript/gleam_stdlib/dict.mjs +var referenceMap = /* @__PURE__ */ new WeakMap(); +var tempDataView = new DataView(new ArrayBuffer(8)); +var referenceUID = 0; +function hashByReference(o) { + const known = referenceMap.get(o); + if (known !== void 0) { + return known; + } + const hash = referenceUID++; + if (referenceUID === 2147483647) { + referenceUID = 0; + } + referenceMap.set(o, hash); + return hash; +} +function hashMerge(a, b) { + return a ^ b + 2654435769 + (a << 6) + (a >> 2) | 0; +} +function hashString(s) { + let hash = 0; + const len = s.length; + for (let i = 0; i < len; i++) { + hash = Math.imul(31, hash) + s.charCodeAt(i) | 0; + } + return hash; +} +function hashNumber(n) { + tempDataView.setFloat64(0, n); + const i = tempDataView.getInt32(0); + const j = tempDataView.getInt32(4); + return Math.imul(73244475, i >> 16 ^ i) ^ j; +} +function hashBigInt(n) { + return hashString(n.toString()); +} +function hashObject(o) { + const proto = Object.getPrototypeOf(o); + if (proto !== null && typeof proto.hashCode === "function") { + try { + const code = o.hashCode(o); + if (typeof code === "number") { + return code; + } + } catch { + } + } + if (o instanceof Promise || o instanceof WeakSet || o instanceof WeakMap) { + return hashByReference(o); + } + if (o instanceof Date) { + return hashNumber(o.getTime()); + } + let h = 0; + if (o instanceof ArrayBuffer) { + o = new Uint8Array(o); + } + if (Array.isArray(o) || o instanceof Uint8Array) { + for (let i = 0; i < o.length; i++) { + h = Math.imul(31, h) + getHash(o[i]) | 0; + } + } else if (o instanceof Set) { + o.forEach((v) => { + h = h + getHash(v) | 0; + }); + } else if (o instanceof Map) { + o.forEach((v, k) => { + h = h + hashMerge(getHash(v), getHash(k)) | 0; + }); + } else { + const keys2 = Object.keys(o); + for (let i = 0; i < keys2.length; i++) { + const k = keys2[i]; + const v = o[k]; + h = h + hashMerge(getHash(v), hashString(k)) | 0; + } + } + return h; +} +function getHash(u) { + if (u === null) + return 1108378658; + if (u === void 0) + return 1108378659; + if (u === true) + return 1108378657; + if (u === false) + return 1108378656; + switch (typeof u) { + case "number": + return hashNumber(u); + case "string": + return hashString(u); + case "bigint": + return hashBigInt(u); + case "object": + return hashObject(u); + case "symbol": + return hashByReference(u); + case "function": + return hashByReference(u); + default: + return 0; + } +} +var SHIFT = 5; +var BUCKET_SIZE = Math.pow(2, SHIFT); +var MASK = BUCKET_SIZE - 1; +var MAX_INDEX_NODE = BUCKET_SIZE / 2; +var MIN_ARRAY_NODE = BUCKET_SIZE / 4; +var ENTRY = 0; +var ARRAY_NODE = 1; +var INDEX_NODE = 2; +var COLLISION_NODE = 3; +var EMPTY = { + type: INDEX_NODE, + bitmap: 0, + array: [] +}; +function mask(hash, shift) { + return hash >>> shift & MASK; +} +function bitpos(hash, shift) { + return 1 << mask(hash, shift); +} +function bitcount(x) { + x -= x >> 1 & 1431655765; + x = (x & 858993459) + (x >> 2 & 858993459); + x = x + (x >> 4) & 252645135; + x += x >> 8; + x += x >> 16; + return x & 127; +} +function index(bitmap, bit) { + return bitcount(bitmap & bit - 1); +} +function cloneAndSet(arr, at, val) { + const len = arr.length; + const out = new Array(len); + for (let i = 0; i < len; ++i) { + out[i] = arr[i]; + } + out[at] = val; + return out; +} +function spliceIn(arr, at, val) { + const len = arr.length; + const out = new Array(len + 1); + let i = 0; + let g = 0; + while (i < at) { + out[g++] = arr[i++]; + } + out[g++] = val; + while (i < len) { + out[g++] = arr[i++]; + } + return out; +} +function spliceOut(arr, at) { + const len = arr.length; + const out = new Array(len - 1); + let i = 0; + let g = 0; + while (i < at) { + out[g++] = arr[i++]; + } + ++i; + while (i < len) { + out[g++] = arr[i++]; + } + return out; +} +function createNode(shift, key1, val1, key2hash, key2, val2) { + const key1hash = getHash(key1); + if (key1hash === key2hash) { + return { + type: COLLISION_NODE, + hash: key1hash, + array: [ + { type: ENTRY, k: key1, v: val1 }, + { type: ENTRY, k: key2, v: val2 } + ] + }; + } + const addedLeaf = { val: false }; + return assoc( + assocIndex(EMPTY, shift, key1hash, key1, val1, addedLeaf), + shift, + key2hash, + key2, + val2, + addedLeaf + ); +} +function assoc(root2, shift, hash, key, val, addedLeaf) { + switch (root2.type) { + case ARRAY_NODE: + return assocArray(root2, shift, hash, key, val, addedLeaf); + case INDEX_NODE: + return assocIndex(root2, shift, hash, key, val, addedLeaf); + case COLLISION_NODE: + return assocCollision(root2, shift, hash, key, val, addedLeaf); + } +} +function assocArray(root2, shift, hash, key, val, addedLeaf) { + const idx = mask(hash, shift); + const node = root2.array[idx]; + if (node === void 0) { + addedLeaf.val = true; + return { + type: ARRAY_NODE, + size: root2.size + 1, + array: cloneAndSet(root2.array, idx, { type: ENTRY, k: key, v: val }) + }; + } + if (node.type === ENTRY) { + if (isEqual(key, node.k)) { + if (val === node.v) { + return root2; + } + return { + type: ARRAY_NODE, + size: root2.size, + array: cloneAndSet(root2.array, idx, { + type: ENTRY, + k: key, + v: val + }) + }; + } + addedLeaf.val = true; + return { + type: ARRAY_NODE, + size: root2.size, + array: cloneAndSet( + root2.array, + idx, + createNode(shift + SHIFT, node.k, node.v, hash, key, val) + ) + }; + } + const n = assoc(node, shift + SHIFT, hash, key, val, addedLeaf); + if (n === node) { + return root2; + } + return { + type: ARRAY_NODE, + size: root2.size, + array: cloneAndSet(root2.array, idx, n) + }; +} +function assocIndex(root2, shift, hash, key, val, addedLeaf) { + const bit = bitpos(hash, shift); + const idx = index(root2.bitmap, bit); + if ((root2.bitmap & bit) !== 0) { + const node = root2.array[idx]; + if (node.type !== ENTRY) { + const n = assoc(node, shift + SHIFT, hash, key, val, addedLeaf); + if (n === node) { + return root2; + } + return { + type: INDEX_NODE, + bitmap: root2.bitmap, + array: cloneAndSet(root2.array, idx, n) + }; + } + const nodeKey = node.k; + if (isEqual(key, nodeKey)) { + if (val === node.v) { + return root2; + } + return { + type: INDEX_NODE, + bitmap: root2.bitmap, + array: cloneAndSet(root2.array, idx, { + type: ENTRY, + k: key, + v: val + }) + }; + } + addedLeaf.val = true; + return { + type: INDEX_NODE, + bitmap: root2.bitmap, + array: cloneAndSet( + root2.array, + idx, + createNode(shift + SHIFT, nodeKey, node.v, hash, key, val) + ) + }; + } else { + const n = root2.array.length; + if (n >= MAX_INDEX_NODE) { + const nodes = new Array(32); + const jdx = mask(hash, shift); + nodes[jdx] = assocIndex(EMPTY, shift + SHIFT, hash, key, val, addedLeaf); + let j = 0; + let bitmap = root2.bitmap; + for (let i = 0; i < 32; i++) { + if ((bitmap & 1) !== 0) { + const node = root2.array[j++]; + nodes[i] = node; + } + bitmap = bitmap >>> 1; + } + return { + type: ARRAY_NODE, + size: n + 1, + array: nodes + }; + } else { + const newArray = spliceIn(root2.array, idx, { + type: ENTRY, + k: key, + v: val + }); + addedLeaf.val = true; + return { + type: INDEX_NODE, + bitmap: root2.bitmap | bit, + array: newArray + }; + } + } +} +function assocCollision(root2, shift, hash, key, val, addedLeaf) { + if (hash === root2.hash) { + const idx = collisionIndexOf(root2, key); + if (idx !== -1) { + const entry = root2.array[idx]; + if (entry.v === val) { + return root2; + } + return { + type: COLLISION_NODE, + hash, + array: cloneAndSet(root2.array, idx, { type: ENTRY, k: key, v: val }) + }; + } + const size = root2.array.length; + addedLeaf.val = true; + return { + type: COLLISION_NODE, + hash, + array: cloneAndSet(root2.array, size, { type: ENTRY, k: key, v: val }) + }; + } + return assoc( + { + type: INDEX_NODE, + bitmap: bitpos(root2.hash, shift), + array: [root2] + }, + shift, + hash, + key, + val, + addedLeaf + ); +} +function collisionIndexOf(root2, key) { + const size = root2.array.length; + for (let i = 0; i < size; i++) { + if (isEqual(key, root2.array[i].k)) { + return i; + } + } + return -1; +} +function find(root2, shift, hash, key) { + switch (root2.type) { + case ARRAY_NODE: + return findArray(root2, shift, hash, key); + case INDEX_NODE: + return findIndex(root2, shift, hash, key); + case COLLISION_NODE: + return findCollision(root2, key); + } +} +function findArray(root2, shift, hash, key) { + const idx = mask(hash, shift); + const node = root2.array[idx]; + if (node === void 0) { + return void 0; + } + if (node.type !== ENTRY) { + return find(node, shift + SHIFT, hash, key); + } + if (isEqual(key, node.k)) { + return node; + } + return void 0; +} +function findIndex(root2, shift, hash, key) { + const bit = bitpos(hash, shift); + if ((root2.bitmap & bit) === 0) { + return void 0; + } + const idx = index(root2.bitmap, bit); + const node = root2.array[idx]; + if (node.type !== ENTRY) { + return find(node, shift + SHIFT, hash, key); + } + if (isEqual(key, node.k)) { + return node; + } + return void 0; +} +function findCollision(root2, key) { + const idx = collisionIndexOf(root2, key); + if (idx < 0) { + return void 0; + } + return root2.array[idx]; +} +function without(root2, shift, hash, key) { + switch (root2.type) { + case ARRAY_NODE: + return withoutArray(root2, shift, hash, key); + case INDEX_NODE: + return withoutIndex(root2, shift, hash, key); + case COLLISION_NODE: + return withoutCollision(root2, key); + } +} +function withoutArray(root2, shift, hash, key) { + const idx = mask(hash, shift); + const node = root2.array[idx]; + if (node === void 0) { + return root2; + } + let n = void 0; + if (node.type === ENTRY) { + if (!isEqual(node.k, key)) { + return root2; + } + } else { + n = without(node, shift + SHIFT, hash, key); + if (n === node) { + return root2; + } + } + if (n === void 0) { + if (root2.size <= MIN_ARRAY_NODE) { + const arr = root2.array; + const out = new Array(root2.size - 1); + let i = 0; + let j = 0; + let bitmap = 0; + while (i < idx) { + const nv = arr[i]; + if (nv !== void 0) { + out[j] = nv; + bitmap |= 1 << i; + ++j; + } + ++i; + } + ++i; + while (i < arr.length) { + const nv = arr[i]; + if (nv !== void 0) { + out[j] = nv; + bitmap |= 1 << i; + ++j; + } + ++i; + } + return { + type: INDEX_NODE, + bitmap, + array: out + }; + } + return { + type: ARRAY_NODE, + size: root2.size - 1, + array: cloneAndSet(root2.array, idx, n) + }; + } + return { + type: ARRAY_NODE, + size: root2.size, + array: cloneAndSet(root2.array, idx, n) + }; +} +function withoutIndex(root2, shift, hash, key) { + const bit = bitpos(hash, shift); + if ((root2.bitmap & bit) === 0) { + return root2; + } + const idx = index(root2.bitmap, bit); + const node = root2.array[idx]; + if (node.type !== ENTRY) { + const n = without(node, shift + SHIFT, hash, key); + if (n === node) { + return root2; + } + if (n !== void 0) { + return { + type: INDEX_NODE, + bitmap: root2.bitmap, + array: cloneAndSet(root2.array, idx, n) + }; + } + if (root2.bitmap === bit) { + return void 0; + } + return { + type: INDEX_NODE, + bitmap: root2.bitmap ^ bit, + array: spliceOut(root2.array, idx) + }; + } + if (isEqual(key, node.k)) { + if (root2.bitmap === bit) { + return void 0; + } + return { + type: INDEX_NODE, + bitmap: root2.bitmap ^ bit, + array: spliceOut(root2.array, idx) + }; + } + return root2; +} +function withoutCollision(root2, key) { + const idx = collisionIndexOf(root2, key); + if (idx < 0) { + return root2; + } + if (root2.array.length === 1) { + return void 0; + } + return { + type: COLLISION_NODE, + hash: root2.hash, + array: spliceOut(root2.array, idx) + }; +} +function forEach(root2, fn) { + if (root2 === void 0) { + return; + } + const items = root2.array; + const size = items.length; + for (let i = 0; i < size; i++) { + const item = items[i]; + if (item === void 0) { + continue; + } + if (item.type === ENTRY) { + fn(item.v, item.k); + continue; + } + forEach(item, fn); + } +} +var Dict = class _Dict { + /** + * @template V + * @param {Record<string,V>} o + * @returns {Dict<string,V>} + */ + static fromObject(o) { + const keys2 = Object.keys(o); + let m = _Dict.new(); + for (let i = 0; i < keys2.length; i++) { + const k = keys2[i]; + m = m.set(k, o[k]); + } + return m; + } + /** + * @template K,V + * @param {Map<K,V>} o + * @returns {Dict<K,V>} + */ + static fromMap(o) { + let m = _Dict.new(); + o.forEach((v, k) => { + m = m.set(k, v); + }); + return m; + } + static new() { + return new _Dict(void 0, 0); + } + /** + * @param {undefined | Node<K,V>} root + * @param {number} size + */ + constructor(root2, size) { + this.root = root2; + this.size = size; + } + /** + * @template NotFound + * @param {K} key + * @param {NotFound} notFound + * @returns {NotFound | V} + */ + get(key, notFound) { + if (this.root === void 0) { + return notFound; + } + const found = find(this.root, 0, getHash(key), key); + if (found === void 0) { + return notFound; + } + return found.v; + } + /** + * @param {K} key + * @param {V} val + * @returns {Dict<K,V>} + */ + set(key, val) { + const addedLeaf = { val: false }; + const root2 = this.root === void 0 ? EMPTY : this.root; + const newRoot = assoc(root2, 0, getHash(key), key, val, addedLeaf); + if (newRoot === this.root) { + return this; + } + return new _Dict(newRoot, addedLeaf.val ? this.size + 1 : this.size); + } + /** + * @param {K} key + * @returns {Dict<K,V>} + */ + delete(key) { + if (this.root === void 0) { + return this; + } + const newRoot = without(this.root, 0, getHash(key), key); + if (newRoot === this.root) { + return this; + } + if (newRoot === void 0) { + return _Dict.new(); + } + return new _Dict(newRoot, this.size - 1); + } + /** + * @param {K} key + * @returns {boolean} + */ + has(key) { + if (this.root === void 0) { + return false; + } + return find(this.root, 0, getHash(key), key) !== void 0; + } + /** + * @returns {[K,V][]} + */ + entries() { + if (this.root === void 0) { + return []; + } + const result = []; + this.forEach((v, k) => result.push([k, v])); + return result; + } + /** + * + * @param {(val:V,key:K)=>void} fn + */ + forEach(fn) { + forEach(this.root, fn); + } + hashCode() { + let h = 0; + this.forEach((v, k) => { + h = h + hashMerge(getHash(v), getHash(k)) | 0; + }); + return h; + } + /** + * @param {unknown} o + * @returns {boolean} + */ + equals(o) { + if (!(o instanceof _Dict) || this.size !== o.size) { + return false; + } + let equal2 = true; + this.forEach((v, k) => { + equal2 = equal2 && isEqual(o.get(k, !v), v); + }); + return equal2; + } +}; + +// build/dev/javascript/gleam_stdlib/gleam_stdlib.mjs +var Nil = void 0; +var NOT_FOUND = {}; +function identity(x) { + return x; +} +function parse_int(value) { + if (/^[-+]?(\d+)$/.test(value)) { + return new Ok(parseInt(value)); + } else { + return new Error(Nil); + } +} +function to_string(term) { + return term.toString(); +} +function graphemes_iterator(string3) { + if (Intl && Intl.Segmenter) { + return new Intl.Segmenter().segment(string3)[Symbol.iterator](); + } +} +function pop_grapheme(string3) { + let first2; + const iterator = graphemes_iterator(string3); + if (iterator) { + first2 = iterator.next().value?.segment; + } else { + first2 = string3.match(/./su)?.[0]; + } + if (first2) { + return new Ok([first2, string3.slice(first2.length)]); + } else { + return new Error(Nil); + } +} +function lowercase(string3) { + return string3.toLowerCase(); +} +function concat(xs) { + let result = ""; + for (const x of xs) { + result = result + x; + } + return result; +} +function starts_with(haystack, needle) { + return haystack.startsWith(needle); +} +function compile_regex(pattern, options) { + try { + let flags = "gu"; + if (options.case_insensitive) + flags += "i"; + if (options.multi_line) + flags += "m"; + return new Ok(new RegExp(pattern, flags)); + } catch (error) { + const number = (error.columnNumber || 0) | 0; + return new Error(new CompileError(error.message, number)); + } +} +function regex_scan(regex, string3) { + const matches = Array.from(string3.matchAll(regex)).map((match) => { + const content = match[0]; + const submatches = []; + for (let n = match.length - 1; n > 0; n--) { + if (match[n]) { + submatches[n - 1] = new Some(match[n]); + continue; + } + if (submatches.length > 0) { + submatches[n - 1] = new None(); + } + } + return new Match(content, List.fromArray(submatches)); + }); + return List.fromArray(matches); +} +function map_get(map6, key) { + const value = map6.get(key, NOT_FOUND); + if (value === NOT_FOUND) { + return new Error(Nil); + } + return new Ok(value); +} +function classify_dynamic(data) { + if (typeof data === "string") { + return "String"; + } else if (data instanceof Result) { + return "Result"; + } else if (data instanceof List) { + return "List"; + } else if (data instanceof BitArray) { + return "BitArray"; + } else if (data instanceof Dict) { + return "Dict"; + } else if (Number.isInteger(data)) { + return "Int"; + } else if (Array.isArray(data)) { + return `Tuple of ${data.length} elements`; + } else if (typeof data === "number") { + return "Float"; + } else if (data === null) { + return "Null"; + } else if (data === void 0) { + return "Nil"; + } else { + const type = typeof data; + return type.charAt(0).toUpperCase() + type.slice(1); + } +} +function decoder_error(expected, got) { + return decoder_error_no_classify(expected, classify_dynamic(got)); +} +function decoder_error_no_classify(expected, got) { + return new Error( + List.fromArray([new DecodeError(expected, got, List.fromArray([]))]) + ); +} +function decode_string(data) { + return typeof data === "string" ? new Ok(data) : decoder_error("String", data); +} +function decode_int(data) { + return Number.isInteger(data) ? new Ok(data) : decoder_error("Int", data); +} +function decode_field(value, name) { + const not_a_map_error = () => decoder_error("Dict", value); + if (value instanceof Dict || value instanceof WeakMap || value instanceof Map) { + const entry = map_get(value, name); + return new Ok(entry.isOk() ? new Some(entry[0]) : new None()); + } else if (value === null) { + return not_a_map_error(); + } else if (Object.getPrototypeOf(value) == Object.prototype) { + return try_get_field(value, name, () => new Ok(new None())); + } else { + return try_get_field(value, name, not_a_map_error); + } +} +function try_get_field(value, field3, or_else) { + try { + return field3 in value ? new Ok(new Some(value[field3])) : or_else(); + } catch { + return or_else(); + } +} + +// build/dev/javascript/gleam_stdlib/gleam/int.mjs +function parse(string3) { + return parse_int(string3); +} +function to_string2(x) { + return to_string(x); +} + +// build/dev/javascript/gleam_stdlib/gleam/pair.mjs +function second(pair) { + let a = pair[1]; + return a; +} + +// build/dev/javascript/gleam_stdlib/gleam/list.mjs +function do_reverse_acc(loop$remaining, loop$accumulator) { + while (true) { + let remaining = loop$remaining; + let accumulator = loop$accumulator; + if (remaining.hasLength(0)) { + return accumulator; + } else { + let item = remaining.head; + let rest$1 = remaining.tail; + loop$remaining = rest$1; + loop$accumulator = prepend(item, accumulator); + } + } +} +function do_reverse(list) { + return do_reverse_acc(list, toList([])); +} +function reverse(xs) { + return do_reverse(xs); +} +function first(list) { + if (list.hasLength(0)) { + return new Error(void 0); + } else { + let x = list.head; + return new Ok(x); + } +} +function do_map(loop$list, loop$fun, loop$acc) { + while (true) { + let list = loop$list; + let fun = loop$fun; + let acc = loop$acc; + if (list.hasLength(0)) { + return reverse(acc); + } else { + let x = list.head; + let xs = list.tail; + loop$list = xs; + loop$fun = fun; + loop$acc = prepend(fun(x), acc); + } + } +} +function map2(list, fun) { + return do_map(list, fun, toList([])); +} +function do_append_acc(loop$first, loop$second) { + while (true) { + let first2 = loop$first; + let second2 = loop$second; + if (first2.hasLength(0)) { + return second2; + } else { + let item = first2.head; + let rest$1 = first2.tail; + loop$first = rest$1; + loop$second = prepend(item, second2); + } + } +} +function do_append(first2, second2) { + return do_append_acc(reverse(first2), second2); +} +function append(first2, second2) { + return do_append(first2, second2); +} +function reverse_and_prepend(loop$prefix, loop$suffix) { + while (true) { + let prefix = loop$prefix; + let suffix = loop$suffix; + if (prefix.hasLength(0)) { + return suffix; + } else { + let first$1 = prefix.head; + let rest$1 = prefix.tail; + loop$prefix = rest$1; + loop$suffix = prepend(first$1, suffix); + } + } +} +function do_concat(loop$lists, loop$acc) { + while (true) { + let lists = loop$lists; + let acc = loop$acc; + if (lists.hasLength(0)) { + return reverse(acc); + } else { + let list = lists.head; + let further_lists = lists.tail; + loop$lists = further_lists; + loop$acc = reverse_and_prepend(list, acc); + } + } +} +function concat2(lists) { + return do_concat(lists, toList([])); +} +function fold(loop$list, loop$initial, loop$fun) { + while (true) { + let list = loop$list; + let initial = loop$initial; + let fun = loop$fun; + if (list.hasLength(0)) { + return initial; + } else { + let x = list.head; + let rest$1 = list.tail; + loop$list = rest$1; + loop$initial = fun(initial, x); + loop$fun = fun; + } + } +} +function do_repeat(loop$a, loop$times, loop$acc) { + while (true) { + let a = loop$a; + let times = loop$times; + let acc = loop$acc; + let $ = times <= 0; + if ($) { + return acc; + } else { + loop$a = a; + loop$times = times - 1; + loop$acc = prepend(a, acc); + } + } +} +function repeat(a, times) { + return do_repeat(a, times, toList([])); +} + +// build/dev/javascript/gleam_stdlib/gleam/result.mjs +function map3(result, fun) { + if (result.isOk()) { + let x = result[0]; + return new Ok(fun(x)); + } else { + let e = result[0]; + return new Error(e); + } +} +function map_error(result, fun) { + if (result.isOk()) { + let x = result[0]; + return new Ok(x); + } else { + let error = result[0]; + return new Error(fun(error)); + } +} +function try$(result, fun) { + if (result.isOk()) { + let x = result[0]; + return fun(x); + } else { + let e = result[0]; + return new Error(e); + } +} +function then$(result, fun) { + return try$(result, fun); +} +function unwrap2(result, default$) { + if (result.isOk()) { + let v = result[0]; + return v; + } else { + return default$; + } +} +function nil_error(result) { + return map_error(result, (_) => { + return void 0; + }); +} + +// build/dev/javascript/gleam_stdlib/gleam/string_builder.mjs +function from_strings(strings) { + return concat(strings); +} +function to_string3(builder) { + return identity(builder); +} + +// build/dev/javascript/gleam_stdlib/gleam/dynamic.mjs +var DecodeError = class extends CustomType { + constructor(expected, found, path) { + super(); + this.expected = expected; + this.found = found; + this.path = path; + } +}; +function from(a) { + return identity(a); +} +function string(data) { + return decode_string(data); +} +function classify(data) { + return classify_dynamic(data); +} +function int(data) { + return decode_int(data); +} +function any(decoders) { + return (data) => { + if (decoders.hasLength(0)) { + return new Error( + toList([new DecodeError("another type", classify(data), toList([]))]) + ); + } else { + let decoder2 = decoders.head; + let decoders$1 = decoders.tail; + let $ = decoder2(data); + if ($.isOk()) { + let decoded = $[0]; + return new Ok(decoded); + } else { + return any(decoders$1)(data); + } + } + }; +} +function all_errors(result) { + if (result.isOk()) { + return toList([]); + } else { + let errors = result[0]; + return errors; + } +} +function push_path(error, name) { + let name$1 = from(name); + let decoder2 = any( + toList([string, (x) => { + return map3(int(x), to_string2); + }]) + ); + let name$2 = (() => { + let $ = decoder2(name$1); + if ($.isOk()) { + let name$22 = $[0]; + return name$22; + } else { + let _pipe = toList(["<", classify(name$1), ">"]); + let _pipe$1 = from_strings(_pipe); + return to_string3(_pipe$1); + } + })(); + return error.withFields({ path: prepend(name$2, error.path) }); +} +function map_errors(result, f) { + return map_error( + result, + (_capture) => { + return map2(_capture, f); + } + ); +} +function field(name, inner_type) { + return (value) => { + let missing_field_error = new DecodeError("field", "nothing", toList([])); + return try$( + decode_field(value, name), + (maybe_inner) => { + let _pipe = maybe_inner; + let _pipe$1 = to_result(_pipe, toList([missing_field_error])); + let _pipe$2 = try$(_pipe$1, inner_type); + return map_errors( + _pipe$2, + (_capture) => { + return push_path(_capture, name); + } + ); + } + ); + }; +} +function decode2(constructor, t1, t2) { + return (value) => { + let $ = t1(value); + let $1 = t2(value); + if ($.isOk() && $1.isOk()) { + let a = $[0]; + let b = $1[0]; + return new Ok(constructor(a, b)); + } else { + let a = $; + let b = $1; + return new Error(concat2(toList([all_errors(a), all_errors(b)]))); + } + }; +} + +// build/dev/javascript/gleam_stdlib/gleam/string.mjs +function lowercase2(string3) { + return lowercase(string3); +} +function starts_with2(string3, prefix) { + return starts_with(string3, prefix); +} +function concat3(strings) { + let _pipe = strings; + let _pipe$1 = from_strings(_pipe); + return to_string3(_pipe$1); +} +function pop_grapheme2(string3) { + return pop_grapheme(string3); +} + +// build/dev/javascript/gleam_stdlib/gleam/bool.mjs +function guard(requirement, consequence, alternative) { + if (requirement) { + return consequence; + } else { + return alternative(); + } +} + +// build/dev/javascript/gleam_json/gleam_json_ffi.mjs +function decode(string3) { + try { + const result = JSON.parse(string3); + return new Ok(result); + } catch (err) { + return new Error(getJsonDecodeError(err, string3)); + } +} +function getJsonDecodeError(stdErr, json) { + if (isUnexpectedEndOfInput(stdErr)) + return new UnexpectedEndOfInput(); + return toUnexpectedByteError(stdErr, json); +} +function isUnexpectedEndOfInput(err) { + const unexpectedEndOfInputRegex = /((unexpected (end|eof))|(end of data)|(unterminated string)|(json( parse error|\.parse)\: expected '(\:|\}|\])'))/i; + return unexpectedEndOfInputRegex.test(err.message); +} +function toUnexpectedByteError(err, json) { + let converters = [ + v8UnexpectedByteError, + oldV8UnexpectedByteError, + jsCoreUnexpectedByteError, + spidermonkeyUnexpectedByteError + ]; + for (let converter of converters) { + let result = converter(err, json); + if (result) + return result; + } + return new UnexpectedByte("", 0); +} +function v8UnexpectedByteError(err) { + const regex = /unexpected token '(.)', ".+" is not valid JSON/i; + const match = regex.exec(err.message); + if (!match) + return null; + const byte = toHex(match[1]); + return new UnexpectedByte(byte, -1); +} +function oldV8UnexpectedByteError(err) { + const regex = /unexpected token (.) in JSON at position (\d+)/i; + const match = regex.exec(err.message); + if (!match) + return null; + const byte = toHex(match[1]); + const position = Number(match[2]); + return new UnexpectedByte(byte, position); +} +function spidermonkeyUnexpectedByteError(err, json) { + const regex = /(unexpected character|expected .*) at line (\d+) column (\d+)/i; + const match = regex.exec(err.message); + if (!match) + return null; + const line = Number(match[2]); + const column = Number(match[3]); + const position = getPositionFromMultiline(line, column, json); + const byte = toHex(json[position]); + return new UnexpectedByte(byte, position); +} +function jsCoreUnexpectedByteError(err) { + const regex = /unexpected (identifier|token) "(.)"/i; + const match = regex.exec(err.message); + if (!match) + return null; + const byte = toHex(match[2]); + return new UnexpectedByte(byte, 0); +} +function toHex(char) { + return "0x" + char.charCodeAt(0).toString(16).toUpperCase(); +} +function getPositionFromMultiline(line, column, string3) { + if (line === 1) + return column - 1; + let currentLn = 1; + let position = 0; + string3.split("").find((char, idx) => { + if (char === "\n") + currentLn += 1; + if (currentLn === line) { + position = idx + column; + return true; + } + return false; + }); + return position; +} + +// build/dev/javascript/gleam_json/gleam/json.mjs +var UnexpectedEndOfInput = class extends CustomType { +}; +var UnexpectedByte = class extends CustomType { + constructor(byte, position) { + super(); + this.byte = byte; + this.position = position; + } +}; +var UnexpectedFormat = class extends CustomType { + constructor(x0) { + super(); + this[0] = x0; + } +}; +function do_decode(json, decoder2) { + return then$( + decode(json), + (dynamic_value) => { + let _pipe = decoder2(dynamic_value); + return map_error( + _pipe, + (var0) => { + return new UnexpectedFormat(var0); + } + ); + } + ); +} +function decode3(json, decoder2) { + return do_decode(json, decoder2); +} + +// build/dev/javascript/lustre/lustre/effect.mjs +var Effect = class extends CustomType { + constructor(all) { + super(); + this.all = all; + } +}; +function from2(effect) { + return new Effect(toList([(dispatch, _) => { + return effect(dispatch); + }])); +} +function none() { + return new Effect(toList([])); +} + +// build/dev/javascript/lustre/lustre/internals/vdom.mjs +var Text = class extends CustomType { + constructor(content) { + super(); + this.content = content; + } +}; +var Element = class extends CustomType { + constructor(key, namespace, tag2, attrs, children, self_closing, void$) { + super(); + this.key = key; + this.namespace = namespace; + this.tag = tag2; + this.attrs = attrs; + this.children = children; + this.self_closing = self_closing; + this.void = void$; + } +}; +var Attribute = class extends CustomType { + constructor(x0, x1, as_property) { + super(); + this[0] = x0; + this[1] = x1; + this.as_property = as_property; + } +}; +var Event = class extends CustomType { + constructor(x0, x1) { + super(); + this[0] = x0; + this[1] = x1; + } +}; + +// build/dev/javascript/lustre/lustre/attribute.mjs +function attribute(name, value) { + return new Attribute(name, from(value), false); +} +function on(name, handler) { + return new Event("on" + name, handler); +} +function style(properties) { + return attribute( + "style", + fold( + properties, + "", + (styles, _use1) => { + let name$1 = _use1[0]; + let value$1 = _use1[1]; + return styles + name$1 + ":" + value$1 + ";"; + } + ) + ); +} +function class$(name) { + return attribute("class", name); +} +function type_(name) { + return attribute("type", name); +} + +// build/dev/javascript/lustre/lustre/element.mjs +function element(tag2, attrs, children) { + if (tag2 === "area") { + return new Element("", "", tag2, attrs, toList([]), false, true); + } else if (tag2 === "base") { + return new Element("", "", tag2, attrs, toList([]), false, true); + } else if (tag2 === "br") { + return new Element("", "", tag2, attrs, toList([]), false, true); + } else if (tag2 === "col") { + return new Element("", "", tag2, attrs, toList([]), false, true); + } else if (tag2 === "embed") { + return new Element("", "", tag2, attrs, toList([]), false, true); + } else if (tag2 === "hr") { + return new Element("", "", tag2, attrs, toList([]), false, true); + } else if (tag2 === "img") { + return new Element("", "", tag2, attrs, toList([]), false, true); + } else if (tag2 === "input") { + return new Element("", "", tag2, attrs, toList([]), false, true); + } else if (tag2 === "link") { + return new Element("", "", tag2, attrs, toList([]), false, true); + } else if (tag2 === "meta") { + return new Element("", "", tag2, attrs, toList([]), false, true); + } else if (tag2 === "param") { + return new Element("", "", tag2, attrs, toList([]), false, true); + } else if (tag2 === "source") { + return new Element("", "", tag2, attrs, toList([]), false, true); + } else if (tag2 === "track") { + return new Element("", "", tag2, attrs, toList([]), false, true); + } else if (tag2 === "wbr") { + return new Element("", "", tag2, attrs, toList([]), false, true); + } else { + return new Element("", "", tag2, attrs, children, false, false); + } +} +function text(content) { + return new Text(content); +} + +// build/dev/javascript/lustre/lustre/internals/runtime.mjs +var Dispatch = class extends CustomType { + constructor(x0) { + super(); + this[0] = x0; + } +}; +var Shutdown = class extends CustomType { +}; + +// build/dev/javascript/lustre/vdom.ffi.mjs +function morph(prev, next, dispatch, isComponent = false) { + let out; + let stack3 = [{ prev, next, parent: prev.parentNode }]; + while (stack3.length) { + let { prev: prev2, next: next2, parent } = stack3.pop(); + if (next2.subtree !== void 0) + next2 = next2.subtree(); + if (next2.content !== void 0) { + if (!prev2) { + const created = document.createTextNode(next2.content); + parent.appendChild(created); + out ??= created; + } else if (prev2.nodeType === Node.TEXT_NODE) { + if (prev2.textContent !== next2.content) + prev2.textContent = next2.content; + out ??= prev2; + } else { + const created = document.createTextNode(next2.content); + parent.replaceChild(created, prev2); + out ??= created; + } + } else if (next2.tag !== void 0) { + const created = createElementNode({ + prev: prev2, + next: next2, + dispatch, + stack: stack3, + isComponent + }); + if (!prev2) { + parent.appendChild(created); + } else if (prev2 !== created) { + parent.replaceChild(created, prev2); + } + out ??= created; + } + } + return out; +} +function createElementNode({ prev, next, dispatch, stack: stack3 }) { + const namespace = next.namespace || "http://www.w3.org/1999/xhtml"; + const canMorph = prev && prev.nodeType === Node.ELEMENT_NODE && prev.localName === next.tag && prev.namespaceURI === (next.namespace || "http://www.w3.org/1999/xhtml"); + const el2 = canMorph ? prev : namespace ? document.createElementNS(namespace, next.tag) : document.createElement(next.tag); + let handlersForEl; + if (!registeredHandlers.has(el2)) { + const emptyHandlers = /* @__PURE__ */ new Map(); + registeredHandlers.set(el2, emptyHandlers); + handlersForEl = emptyHandlers; + } else { + handlersForEl = registeredHandlers.get(el2); + } + const prevHandlers = canMorph ? new Set(handlersForEl.keys()) : null; + const prevAttributes = canMorph ? new Set(Array.from(prev.attributes, (a) => a.name)) : null; + let className = null; + let style2 = null; + let innerHTML = null; + for (const attr of next.attrs) { + const name = attr[0]; + const value = attr[1]; + const isProperty = attr[2]; + if (isProperty) { + el2[name] = value; + } else if (name.startsWith("on")) { + const eventName = name.slice(2); + const callback = dispatch(value); + if (!handlersForEl.has(eventName)) { + el2.addEventListener(eventName, lustreGenericEventHandler); + } + handlersForEl.set(eventName, callback); + if (canMorph) + prevHandlers.delete(eventName); + } else if (name.startsWith("data-lustre-on-")) { + const eventName = name.slice(15); + const callback = dispatch(lustreServerEventHandler); + if (!handlersForEl.has(eventName)) { + el2.addEventListener(eventName, lustreGenericEventHandler); + } + handlersForEl.set(eventName, callback); + el2.setAttribute(name, value); + } else if (name === "class") { + className = className === null ? value : className + " " + value; + } else if (name === "style") { + style2 = style2 === null ? value : style2 + value; + } else if (name === "dangerous-unescaped-html") { + innerHTML = value; + } else { + el2.setAttribute(name, value); + if (name === "value") + el2[name] = value; + if (canMorph) + prevAttributes.delete(name); + } + } + if (className !== null) { + el2.setAttribute("class", className); + if (canMorph) + prevAttributes.delete("class"); + } + if (style2 !== null) { + el2.setAttribute("style", style2); + if (canMorph) + prevAttributes.delete("style"); + } + if (canMorph) { + for (const attr of prevAttributes) { + el2.removeAttribute(attr); + } + for (const eventName of prevHandlers) { + handlersForEl.delete(eventName); + el2.removeEventListener(eventName, lustreGenericEventHandler); + } + } + if (next.key !== void 0 && next.key !== "") { + el2.setAttribute("data-lustre-key", next.key); + } else if (innerHTML !== null) { + el2.innerHTML = innerHTML; + return el2; + } + let prevChild = el2.firstChild; + let seenKeys = null; + let keyedChildren = null; + let incomingKeyedChildren = null; + let firstChild = next.children[Symbol.iterator]().next().value; + if (canMorph && firstChild !== void 0 && // Explicit checks are more verbose but truthy checks force a bunch of comparisons + // we don't care about: it's never gonna be a number etc. + firstChild.key !== void 0 && firstChild.key !== "") { + seenKeys = /* @__PURE__ */ new Set(); + keyedChildren = getKeyedChildren(prev); + incomingKeyedChildren = getKeyedChildren(next); + } + for (const child of next.children) { + if (child.key !== void 0 && seenKeys !== null) { + while (prevChild && !incomingKeyedChildren.has(prevChild.getAttribute("data-lustre-key"))) { + const nextChild = prevChild.nextSibling; + el2.removeChild(prevChild); + prevChild = nextChild; + } + if (keyedChildren.size === 0) { + stack3.unshift({ prev: prevChild, next: child, parent: el2 }); + prevChild = prevChild?.nextSibling; + continue; + } + if (seenKeys.has(child.key)) { + console.warn(`Duplicate key found in Lustre vnode: ${child.key}`); + stack3.unshift({ prev: null, next: child, parent: el2 }); + continue; + } + seenKeys.add(child.key); + const keyedChild = keyedChildren.get(child.key); + if (!keyedChild && !prevChild) { + stack3.unshift({ prev: null, next: child, parent: el2 }); + continue; + } + if (!keyedChild && prevChild !== null) { + const placeholder = document.createTextNode(""); + el2.insertBefore(placeholder, prevChild); + stack3.unshift({ prev: placeholder, next: child, parent: el2 }); + continue; + } + if (!keyedChild || keyedChild === prevChild) { + stack3.unshift({ prev: prevChild, next: child, parent: el2 }); + prevChild = prevChild?.nextSibling; + continue; + } + el2.insertBefore(keyedChild, prevChild); + stack3.unshift({ prev: keyedChild, next: child, parent: el2 }); + } else { + stack3.unshift({ prev: prevChild, next: child, parent: el2 }); + prevChild = prevChild?.nextSibling; + } + } + while (prevChild) { + const next2 = prevChild.nextSibling; + el2.removeChild(prevChild); + prevChild = next2; + } + return el2; +} +var registeredHandlers = /* @__PURE__ */ new WeakMap(); +function lustreGenericEventHandler(event2) { + const target = event2.currentTarget; + if (!registeredHandlers.has(target)) { + target.removeEventListener(event2.type, lustreGenericEventHandler); + return; + } + const handlersForEventTarget = registeredHandlers.get(target); + if (!handlersForEventTarget.has(event2.type)) { + target.removeEventListener(event2.type, lustreGenericEventHandler); + return; + } + handlersForEventTarget.get(event2.type)(event2); +} +function lustreServerEventHandler(event2) { + const el2 = event2.target; + const tag2 = el2.getAttribute(`data-lustre-on-${event2.type}`); + const data = JSON.parse(el2.getAttribute("data-lustre-data") || "{}"); + const include = JSON.parse(el2.getAttribute("data-lustre-include") || "[]"); + switch (event2.type) { + case "input": + case "change": + include.push("target.value"); + break; + } + return { + tag: tag2, + data: include.reduce( + (data2, property) => { + const path = property.split("."); + for (let i = 0, o = data2, e = event2; i < path.length; i++) { + if (i === path.length - 1) { + o[path[i]] = e[path[i]]; + } else { + o[path[i]] ??= {}; + e = e[path[i]]; + o = o[path[i]]; + } + } + return data2; + }, + { data } + ) + }; +} +function getKeyedChildren(el2) { + const keyedChildren = /* @__PURE__ */ new Map(); + if (el2) { + for (const child of el2.children) { + const key = child.key || child?.getAttribute("data-lustre-key"); + if (key) + keyedChildren.set(key, child); + } + } + return keyedChildren; +} + +// build/dev/javascript/lustre/client-runtime.ffi.mjs +var LustreClientApplication2 = class _LustreClientApplication { + #root = null; + #queue = []; + #effects = []; + #didUpdate = false; + #isComponent = false; + #model = null; + #update = null; + #view = null; + static start(flags, selector, init3, update3, view2) { + if (!is_browser()) + return new Error(new NotABrowser()); + const root2 = selector instanceof HTMLElement ? selector : document.querySelector(selector); + if (!root2) + return new Error(new ElementNotFound(selector)); + const app = new _LustreClientApplication(init3(flags), update3, view2, root2); + return new Ok((msg) => app.send(msg)); + } + constructor([model, effects], update3, view2, root2 = document.body, isComponent = false) { + this.#model = model; + this.#update = update3; + this.#view = view2; + this.#root = root2; + this.#effects = effects.all.toArray(); + this.#didUpdate = true; + this.#isComponent = isComponent; + window.requestAnimationFrame(() => this.#tick()); + } + send(action) { + switch (true) { + case action instanceof Dispatch: { + this.#queue.push(action[0]); + this.#tick(); + return; + } + case action instanceof Shutdown: { + this.#shutdown(); + return; + } + default: + return; + } + } + emit(event2, data) { + this.#root.dispatchEvent( + new CustomEvent(event2, { + bubbles: true, + detail: data, + composed: true + }) + ); + } + #tick() { + this.#flush_queue(); + const vdom = this.#view(this.#model); + const dispatch = (handler) => (e) => { + const result = handler(e); + if (result instanceof Ok) { + this.send(new Dispatch(result[0])); + } + }; + this.#didUpdate = false; + this.#root = morph(this.#root, vdom, dispatch, this.#isComponent); + } + #flush_queue(iterations = 0) { + while (this.#queue.length) { + const [next, effects] = this.#update(this.#model, this.#queue.shift()); + this.#didUpdate ||= !isEqual(this.#model, next); + this.#model = next; + this.#effects = this.#effects.concat(effects.all.toArray()); + } + while (this.#effects.length) { + this.#effects.shift()( + (msg) => this.send(new Dispatch(msg)), + (event2, data) => this.emit(event2, data) + ); + } + if (this.#queue.length) { + if (iterations < 5) { + this.#flush_queue(++iterations); + } else { + window.requestAnimationFrame(() => this.#tick()); + } + } + } + #shutdown() { + this.#root.remove(); + this.#root = null; + this.#model = null; + this.#queue = []; + this.#effects = []; + this.#didUpdate = false; + this.#update = () => { + }; + this.#view = () => { + }; + } +}; +var start = (app, selector, flags) => LustreClientApplication2.start( + flags, + selector, + app.init, + app.update, + app.view +); +var is_browser = () => window && window.document; + +// build/dev/javascript/lustre/lustre.mjs +var App = class extends CustomType { + constructor(init3, update3, view2, on_attribute_change) { + super(); + this.init = init3; + this.update = update3; + this.view = view2; + this.on_attribute_change = on_attribute_change; + } +}; +var ElementNotFound = class extends CustomType { + constructor(selector) { + super(); + this.selector = selector; + } +}; +var NotABrowser = class extends CustomType { +}; +function application(init3, update3, view2) { + return new App(init3, update3, view2, new None()); +} +function start3(app, selector, flags) { + return guard( + !is_browser(), + new Error(new NotABrowser()), + () => { + return start(app, selector, flags); + } + ); +} + +// build/dev/javascript/lustre/lustre/element/html.mjs +function div(attrs, children) { + return element("div", attrs, children); +} +function p(attrs, children) { + return element("p", attrs, children); +} +function button(attrs, children) { + return element("button", attrs, children); +} + +// build/dev/javascript/lustre/lustre/event.mjs +function on2(name, handler) { + return on(name, handler); +} +function on_click(msg) { + return on2("click", (_) => { + return new Ok(msg); + }); +} + +// build/dev/javascript/gleam_stdlib/gleam/uri.mjs +var Uri = class extends CustomType { + constructor(scheme, userinfo, host, port, path, query, fragment) { + super(); + this.scheme = scheme; + this.userinfo = userinfo; + this.host = host; + this.port = port; + this.path = path; + this.query = query; + this.fragment = fragment; + } +}; +function regex_submatches(pattern, string3) { + let _pipe = pattern; + let _pipe$1 = compile(_pipe, new Options(true, false)); + let _pipe$2 = nil_error(_pipe$1); + let _pipe$3 = map3( + _pipe$2, + (_capture) => { + return scan(_capture, string3); + } + ); + let _pipe$4 = try$(_pipe$3, first); + let _pipe$5 = map3(_pipe$4, (m) => { + return m.submatches; + }); + return unwrap2(_pipe$5, toList([])); +} +function noneify_query(x) { + if (x instanceof None) { + return new None(); + } else { + let x$1 = x[0]; + let $ = pop_grapheme2(x$1); + if ($.isOk() && $[0][0] === "?") { + let query = $[0][1]; + return new Some(query); + } else { + return new None(); + } + } +} +function noneify_empty_string(x) { + if (x instanceof Some && x[0] === "") { + return new None(); + } else if (x instanceof None) { + return new None(); + } else { + return x; + } +} +function extra_required(loop$list, loop$remaining) { + while (true) { + let list = loop$list; + let remaining = loop$remaining; + if (remaining === 0) { + return 0; + } else if (list.hasLength(0)) { + return remaining; + } else { + let xs = list.tail; + loop$list = xs; + loop$remaining = remaining - 1; + } + } +} +function pad_list(list, size) { + let _pipe = list; + return append( + _pipe, + repeat(new None(), extra_required(list, size)) + ); +} +function split_authority(authority) { + let $ = unwrap(authority, ""); + if ($ === "") { + return [new None(), new None(), new None()]; + } else if ($ === "//") { + return [new None(), new Some(""), new None()]; + } else { + let authority$1 = $; + let matches = (() => { + let _pipe = "^(//)?((.*)@)?(\\[[a-zA-Z0-9:.]*\\]|[^:]*)(:(\\d*))?"; + let _pipe$1 = regex_submatches(_pipe, authority$1); + return pad_list(_pipe$1, 6); + })(); + if (matches.hasLength(6)) { + let userinfo = matches.tail.tail.head; + let host = matches.tail.tail.tail.head; + let port = matches.tail.tail.tail.tail.tail.head; + let userinfo$1 = noneify_empty_string(userinfo); + let host$1 = noneify_empty_string(host); + let port$1 = (() => { + let _pipe = port; + let _pipe$1 = unwrap(_pipe, ""); + let _pipe$2 = parse(_pipe$1); + return from_result(_pipe$2); + })(); + return [userinfo$1, host$1, port$1]; + } else { + return [new None(), new None(), new None()]; + } + } +} +function do_parse(uri_string) { + let pattern = "^(([a-z][a-z0-9\\+\\-\\.]*):)?(//([^/?#]*))?([^?#]*)(\\?([^#]*))?(#.*)?"; + let matches = (() => { + let _pipe = pattern; + let _pipe$1 = regex_submatches(_pipe, uri_string); + return pad_list(_pipe$1, 8); + })(); + let $ = (() => { + if (matches.hasLength(8)) { + let scheme2 = matches.tail.head; + let authority_with_slashes = matches.tail.tail.head; + let path2 = matches.tail.tail.tail.tail.head; + let query_with_question_mark = matches.tail.tail.tail.tail.tail.head; + let fragment2 = matches.tail.tail.tail.tail.tail.tail.tail.head; + return [ + scheme2, + authority_with_slashes, + path2, + query_with_question_mark, + fragment2 + ]; + } else { + return [new None(), new None(), new None(), new None(), new None()]; + } + })(); + let scheme = $[0]; + let authority = $[1]; + let path = $[2]; + let query = $[3]; + let fragment = $[4]; + let scheme$1 = noneify_empty_string(scheme); + let path$1 = unwrap(path, ""); + let query$1 = noneify_query(query); + let $1 = split_authority(authority); + let userinfo = $1[0]; + let host = $1[1]; + let port = $1[2]; + let fragment$1 = (() => { + let _pipe = fragment; + let _pipe$1 = to_result(_pipe, void 0); + let _pipe$2 = try$(_pipe$1, pop_grapheme2); + let _pipe$3 = map3(_pipe$2, second); + return from_result(_pipe$3); + })(); + let scheme$2 = (() => { + let _pipe = scheme$1; + let _pipe$1 = noneify_empty_string(_pipe); + return map(_pipe$1, lowercase2); + })(); + return new Ok( + new Uri(scheme$2, userinfo, host, port, path$1, query$1, fragment$1) + ); +} +function parse2(uri_string) { + return do_parse(uri_string); +} +function to_string5(uri) { + let parts = (() => { + let $ = uri.fragment; + if ($ instanceof Some) { + let fragment = $[0]; + return toList(["#", fragment]); + } else { + return toList([]); + } + })(); + let parts$1 = (() => { + let $ = uri.query; + if ($ instanceof Some) { + let query = $[0]; + return prepend("?", prepend(query, parts)); + } else { + return parts; + } + })(); + let parts$2 = prepend(uri.path, parts$1); + let parts$3 = (() => { + let $ = uri.host; + let $1 = starts_with2(uri.path, "/"); + if ($ instanceof Some && !$1 && $[0] !== "") { + let host = $[0]; + return prepend("/", parts$2); + } else { + return parts$2; + } + })(); + let parts$4 = (() => { + let $ = uri.host; + let $1 = uri.port; + if ($ instanceof Some && $1 instanceof Some) { + let port = $1[0]; + return prepend(":", prepend(to_string2(port), parts$3)); + } else { + return parts$3; + } + })(); + let parts$5 = (() => { + let $ = uri.scheme; + let $1 = uri.userinfo; + let $2 = uri.host; + if ($ instanceof Some && $1 instanceof Some && $2 instanceof Some) { + let s = $[0]; + let u = $1[0]; + let h = $2[0]; + return prepend( + s, + prepend( + "://", + prepend(u, prepend("@", prepend(h, parts$4))) + ) + ); + } else if ($ instanceof Some && $1 instanceof None && $2 instanceof Some) { + let s = $[0]; + let h = $2[0]; + return prepend(s, prepend("://", prepend(h, parts$4))); + } else if ($ instanceof Some && $1 instanceof Some && $2 instanceof None) { + let s = $[0]; + return prepend(s, prepend(":", parts$4)); + } else if ($ instanceof Some && $1 instanceof None && $2 instanceof None) { + let s = $[0]; + return prepend(s, prepend(":", parts$4)); + } else if ($ instanceof None && $1 instanceof None && $2 instanceof Some) { + let h = $2[0]; + return prepend("//", prepend(h, parts$4)); + } else { + return parts$4; + } + })(); + return concat3(parts$5); +} + +// build/dev/javascript/gleam_http/gleam/http.mjs +var Get = class extends CustomType { +}; +var Post = class extends CustomType { +}; +var Head = class extends CustomType { +}; +var Put = class extends CustomType { +}; +var Delete = class extends CustomType { +}; +var Trace = class extends CustomType { +}; +var Connect = class extends CustomType { +}; +var Options2 = class extends CustomType { +}; +var Patch = class extends CustomType { +}; +var Http = class extends CustomType { +}; +var Https = class extends CustomType { +}; +function method_to_string(method) { + if (method instanceof Connect) { + return "connect"; + } else if (method instanceof Delete) { + return "delete"; + } else if (method instanceof Get) { + return "get"; + } else if (method instanceof Head) { + return "head"; + } else if (method instanceof Options2) { + return "options"; + } else if (method instanceof Patch) { + return "patch"; + } else if (method instanceof Post) { + return "post"; + } else if (method instanceof Put) { + return "put"; + } else if (method instanceof Trace) { + return "trace"; + } else { + let s = method[0]; + return s; + } +} +function scheme_to_string(scheme) { + if (scheme instanceof Http) { + return "http"; + } else { + return "https"; + } +} +function scheme_from_string(scheme) { + let $ = lowercase2(scheme); + if ($ === "http") { + return new Ok(new Http()); + } else if ($ === "https") { + return new Ok(new Https()); + } else { + return new Error(void 0); + } +} + +// build/dev/javascript/gleam_http/gleam/http/request.mjs +var Request = class extends CustomType { + constructor(method, headers, body, scheme, host, port, path, query) { + super(); + this.method = method; + this.headers = headers; + this.body = body; + this.scheme = scheme; + this.host = host; + this.port = port; + this.path = path; + this.query = query; + } +}; +function to_uri(request) { + return new Uri( + new Some(scheme_to_string(request.scheme)), + new None(), + new Some(request.host), + request.port, + request.path, + request.query, + new None() + ); +} +function from_uri(uri) { + return then$( + (() => { + let _pipe = uri.scheme; + let _pipe$1 = unwrap(_pipe, ""); + return scheme_from_string(_pipe$1); + })(), + (scheme) => { + return then$( + (() => { + let _pipe = uri.host; + return to_result(_pipe, void 0); + })(), + (host) => { + let req = new Request( + new Get(), + toList([]), + "", + scheme, + host, + uri.port, + uri.path, + uri.query + ); + return new Ok(req); + } + ); + } + ); +} +function to(url) { + let _pipe = url; + let _pipe$1 = parse2(_pipe); + return then$(_pipe$1, from_uri); +} + +// build/dev/javascript/gleam_http/gleam/http/response.mjs +var Response = class extends CustomType { + constructor(status, headers, body) { + super(); + this.status = status; + this.headers = headers; + this.body = body; + } +}; + +// build/dev/javascript/gleam_javascript/ffi.mjs +var PromiseLayer = class _PromiseLayer { + constructor(promise) { + this.promise = promise; + } + static wrap(value) { + return value instanceof Promise ? new _PromiseLayer(value) : value; + } + static unwrap(value) { + return value instanceof _PromiseLayer ? value.promise : value; + } +}; +function resolve(value) { + return Promise.resolve(PromiseLayer.wrap(value)); +} +function then(promise, fn) { + return promise.then((value) => fn(PromiseLayer.unwrap(value))); +} +function map_promise(promise, fn) { + return promise.then( + (value) => PromiseLayer.wrap(fn(PromiseLayer.unwrap(value))) + ); +} +function rescue(promise, fn) { + return promise.catch((error) => fn(error)); +} + +// build/dev/javascript/gleam_javascript/gleam/javascript/promise.mjs +function tap(promise, callback) { + let _pipe = promise; + return map_promise( + _pipe, + (a) => { + callback(a); + return a; + } + ); +} +function try_await(promise, callback) { + let _pipe = promise; + return then( + _pipe, + (result) => { + if (result.isOk()) { + let a = result[0]; + return callback(a); + } else { + let e = result[0]; + return resolve(new Error(e)); + } + } + ); +} + +// build/dev/javascript/gleam_fetch/ffi.mjs +async function raw_send(request) { + try { + return new Ok(await fetch(request)); + } catch (error) { + return new Error(new NetworkError(error.toString())); + } +} +function from_fetch_response(response) { + return new Response( + response.status, + List.fromArray([...response.headers]), + response + ); +} +function to_fetch_request(request) { + let url = to_string5(to_uri(request)); + let method = method_to_string(request.method).toUpperCase(); + let options = { + headers: make_headers(request.headers), + method + }; + if (method !== "GET" && method !== "HEAD") + options.body = request.body; + return new globalThis.Request(url, options); +} +function make_headers(headersList) { + let headers = new globalThis.Headers(); + for (let [k, v] of headersList) + headers.append(k.toLowerCase(), v); + return headers; +} +async function read_text_body(response) { + let body; + try { + body = await response.body.text(); + } catch (error) { + return new Error(new UnableToReadBody()); + } + return new Ok(response.withFields({ body })); +} + +// build/dev/javascript/gleam_fetch/gleam/fetch.mjs +var NetworkError = class extends CustomType { + constructor(x0) { + super(); + this[0] = x0; + } +}; +var UnableToReadBody = class extends CustomType { +}; +function send(request) { + let _pipe = request; + let _pipe$1 = to_fetch_request(_pipe); + let _pipe$2 = raw_send(_pipe$1); + return try_await( + _pipe$2, + (resp) => { + return resolve(new Ok(from_fetch_response(resp))); + } + ); +} + +// build/dev/javascript/lustre_http/lustre_http.mjs +var BadUrl = class extends CustomType { + constructor(x0) { + super(); + this[0] = x0; + } +}; +var InternalServerError = class extends CustomType { + constructor(x0) { + super(); + this[0] = x0; + } +}; +var JsonError = class extends CustomType { + constructor(x0) { + super(); + this[0] = x0; + } +}; +var NetworkError2 = class extends CustomType { +}; +var NotFound = class extends CustomType { +}; +var OtherError = class extends CustomType { + constructor(x0, x1) { + super(); + this[0] = x0; + this[1] = x1; + } +}; +var Unauthorized = class extends CustomType { +}; +var ExpectTextResponse = class extends CustomType { + constructor(run) { + super(); + this.run = run; + } +}; +function do_send(req, expect, dispatch) { + let _pipe = send(req); + let _pipe$1 = try_await(_pipe, read_text_body); + let _pipe$2 = map_promise( + _pipe$1, + (response) => { + if (response.isOk()) { + let res = response[0]; + return expect.run(new Ok(res)); + } else { + return expect.run(new Error(new NetworkError2())); + } + } + ); + let _pipe$3 = rescue( + _pipe$2, + (_) => { + return expect.run(new Error(new NetworkError2())); + } + ); + tap(_pipe$3, dispatch); + return void 0; +} +function get2(url, expect) { + return from2( + (dispatch) => { + let $ = to(url); + if ($.isOk()) { + let req = $[0]; + return do_send(req, expect, dispatch); + } else { + return dispatch(expect.run(new Error(new BadUrl(url)))); + } + } + ); +} +function response_to_result(response) { + if (response instanceof Response && (200 <= response.status && response.status <= 299)) { + let status = response.status; + let body = response.body; + return new Ok(body); + } else if (response instanceof Response && response.status === 401) { + return new Error(new Unauthorized()); + } else if (response instanceof Response && response.status === 404) { + return new Error(new NotFound()); + } else if (response instanceof Response && response.status === 500) { + let body = response.body; + return new Error(new InternalServerError(body)); + } else { + let code = response.status; + let body = response.body; + return new Error(new OtherError(code, body)); + } +} +function expect_json(decoder2, to_msg) { + return new ExpectTextResponse( + (response) => { + let _pipe = response; + let _pipe$1 = then$(_pipe, response_to_result); + let _pipe$2 = then$( + _pipe$1, + (body) => { + let $ = decode3(body, decoder2); + if ($.isOk()) { + let json = $[0]; + return new Ok(json); + } else { + let json_error = $[0]; + return new Error(new JsonError(json_error)); + } + } + ); + return to_msg(_pipe$2); + } + ); +} + +// build/dev/javascript/lustre_ui/lustre/ui/button.mjs +function button2(attributes, children) { + return button( + prepend( + class$("lustre-ui-button"), + prepend(type_("button"), attributes) + ), + children + ); +} + +// build/dev/javascript/lustre_ui/lustre/ui/layout/stack.mjs +function of(element2, attributes, children) { + return element2( + prepend(class$("lustre-ui-stack"), attributes), + children + ); +} +function stack(attributes, children) { + return of(div, attributes, children); +} + +// build/dev/javascript/lustre_ui/lustre/ui/layout/aside.mjs +function of2(element2, attributes, side, main2) { + return element2( + prepend(class$("lustre-ui-aside"), attributes), + toList([side, main2]) + ); +} +function aside(attributes, side, main2) { + return of2(div, attributes, side, main2); +} +function min_width(width) { + let $ = width < 10; + let $1 = width > 90; + if ($) { + return style(toList([["--min", "10%"]])); + } else if (!$ && !$1) { + return style(toList([["--min", to_string2(width) + "%"]])); + } else { + return style(toList([["--min", "90%"]])); + } +} + +// build/dev/javascript/lustre_ui/lustre/ui/layout/centre.mjs +function of3(element2, attributes, children) { + return element2( + prepend(class$("lustre-ui-centre"), attributes), + toList([children]) + ); +} +function centre(attributes, children) { + return of3(div, attributes, children); +} + +// build/dev/javascript/gleam_community_colour/gleam_community/colour.mjs +var Rgba = class extends CustomType { + constructor(r, g, b, a) { + super(); + this.r = r; + this.g = g; + this.b = b; + this.a = a; + } +}; +var light_red = new Rgba( + 0.9372549019607843, + 0.1607843137254902, + 0.1607843137254902, + 1 +); +var red = new Rgba(0.8, 0, 0, 1); +var dark_red = new Rgba(0.6431372549019608, 0, 0, 1); +var light_orange = new Rgba( + 0.9882352941176471, + 0.6862745098039216, + 0.24313725490196078, + 1 +); +var orange = new Rgba(0.9607843137254902, 0.4745098039215686, 0, 1); +var dark_orange = new Rgba( + 0.807843137254902, + 0.3607843137254902, + 0, + 1 +); +var light_yellow = new Rgba( + 1, + 0.9137254901960784, + 0.30980392156862746, + 1 +); +var yellow = new Rgba(0.9294117647058824, 0.8313725490196079, 0, 1); +var dark_yellow = new Rgba( + 0.7686274509803922, + 0.6274509803921569, + 0, + 1 +); +var light_green = new Rgba( + 0.5411764705882353, + 0.8862745098039215, + 0.20392156862745098, + 1 +); +var green = new Rgba( + 0.45098039215686275, + 0.8235294117647058, + 0.08627450980392157, + 1 +); +var dark_green = new Rgba( + 0.3058823529411765, + 0.6039215686274509, + 0.023529411764705882, + 1 +); +var light_blue = new Rgba( + 0.4470588235294118, + 0.6235294117647059, + 0.8117647058823529, + 1 +); +var blue = new Rgba( + 0.20392156862745098, + 0.396078431372549, + 0.6431372549019608, + 1 +); +var dark_blue = new Rgba( + 0.12549019607843137, + 0.2901960784313726, + 0.5294117647058824, + 1 +); +var light_purple = new Rgba( + 0.6784313725490196, + 0.4980392156862745, + 0.6588235294117647, + 1 +); +var purple = new Rgba( + 0.4588235294117647, + 0.3137254901960784, + 0.4823529411764706, + 1 +); +var dark_purple = new Rgba( + 0.3607843137254902, + 0.20784313725490197, + 0.4, + 1 +); +var light_brown = new Rgba( + 0.9137254901960784, + 0.7254901960784313, + 0.43137254901960786, + 1 +); +var brown = new Rgba( + 0.7568627450980392, + 0.49019607843137253, + 0.06666666666666667, + 1 +); +var dark_brown = new Rgba( + 0.5607843137254902, + 0.34901960784313724, + 0.00784313725490196, + 1 +); +var black = new Rgba(0, 0, 0, 1); +var white = new Rgba(1, 1, 1, 1); +var light_grey = new Rgba( + 0.9333333333333333, + 0.9333333333333333, + 0.9254901960784314, + 1 +); +var grey = new Rgba( + 0.8274509803921568, + 0.8431372549019608, + 0.8117647058823529, + 1 +); +var dark_grey = new Rgba( + 0.7294117647058823, + 0.7411764705882353, + 0.7137254901960784, + 1 +); +var light_gray = new Rgba( + 0.9333333333333333, + 0.9333333333333333, + 0.9254901960784314, + 1 +); +var gray = new Rgba( + 0.8274509803921568, + 0.8431372549019608, + 0.8117647058823529, + 1 +); +var dark_gray = new Rgba( + 0.7294117647058823, + 0.7411764705882353, + 0.7137254901960784, + 1 +); +var light_charcoal = new Rgba( + 0.5333333333333333, + 0.5411764705882353, + 0.5215686274509804, + 1 +); +var charcoal = new Rgba( + 0.3333333333333333, + 0.3411764705882353, + 0.3254901960784314, + 1 +); +var dark_charcoal = new Rgba( + 0.1803921568627451, + 0.20392156862745098, + 0.21176470588235294, + 1 +); +var pink = new Rgba(1, 0.6862745098039216, 0.9529411764705882, 1); + +// build/dev/javascript/lustre_ui/lustre/ui.mjs +var aside2 = aside; +var button3 = button2; +var centre2 = centre; +var stack2 = stack; + +// build/dev/javascript/app/app.mjs +var Model = class extends CustomType { + constructor(quote) { + super(); + this.quote = quote; + } +}; +var Quote = class extends CustomType { + constructor(author, content) { + super(); + this.author = author; + this.content = content; + } +}; +var UserClickedRefresh = class extends CustomType { +}; +var ApiUpdatedQuote = class extends CustomType { + constructor(x0) { + super(); + this[0] = x0; + } +}; +function init2(_) { + return [new Model(new None()), none()]; +} +function get_quote() { + let url = "https://api.quotable.io/random"; + let decoder2 = decode2( + (var0, var1) => { + return new Quote(var0, var1); + }, + field("author", string), + field("content", string) + ); + return get2( + url, + expect_json( + decoder2, + (var0) => { + return new ApiUpdatedQuote(var0); + } + ) + ); +} +function update2(model, msg) { + if (msg instanceof UserClickedRefresh) { + return [model, get_quote()]; + } else if (msg instanceof ApiUpdatedQuote && msg[0].isOk()) { + let quote = msg[0][0]; + return [new Model(new Some(quote)), none()]; + } else { + return [model, none()]; + } +} +function view_quote(quote) { + if (quote instanceof Some) { + let quote$1 = quote[0]; + return stack2( + toList([]), + toList([ + text(quote$1.author + " once said..."), + p( + toList([style(toList([["font-style", "italic"]]))]), + toList([text(quote$1.content)]) + ) + ]) + ); + } else { + return p( + toList([]), + toList([text("Click the button to get a quote!")]) + ); + } +} +function view(model) { + let styles = toList([ + ["width", "100vw"], + ["height", "100vh"], + ["padding", "1rem"] + ]); + return centre2( + toList([style(styles)]), + aside2( + toList([ + min_width(70), + style(toList([["width", "60ch"]])) + ]), + view_quote(model.quote), + button3( + toList([on_click(new UserClickedRefresh())]), + toList([text("New quote")]) + ) + ) + ); +} +function main() { + let app = application(init2, update2, view); + let $ = start3(app, "#app", void 0); + if (!$.isOk()) { + throw makeError( + "assignment_no_match", + "app", + 21, + "main", + "Assignment pattern did not match", + { value: $ } + ); + } + return $; +} + +// build/.lustre/entry.mjs +main(); diff --git a/examples/05-http-requests/src/app.gleam b/examples/05-http-requests/src/app.gleam index 5e0df3e..acd5fcc 100644 --- a/examples/05-http-requests/src/app.gleam +++ b/examples/05-http-requests/src/app.gleam @@ -6,20 +6,13 @@ import lustre/effect.{type Effect} import lustre/element.{type Element} import lustre/element/html import lustre/event + // Lustre_http is a community package that provides a simple API for making // HTTP requests from your update function. You can find the docs for the package // here: https://hexdocs.pm/lustre_http/index.html -import lustre_http.{type HttpError} -// These examples are written with `lustre/ui` in mind. They'll work regardless, -// but to see what `lustre/ui` can do make sure to run each of these examples with -// the `--use-example-styles` flag: -// -// $ gleam run -m lustre/dev start --use-example-styles -// -// In your own apps, make sure to add the `lustre/ui` dependency and include the -// stylesheet somewhere. import lustre/ui -import lustre/ui/aside +import lustre/ui/layout/aside +import lustre_http.{type HttpError} // MAIN ------------------------------------------------------------------------ diff --git a/examples/06-custom-effects/index.html b/examples/06-custom-effects/index.html new file mode 100644 index 0000000..36ddf10 --- /dev/null +++ b/examples/06-custom-effects/index.html @@ -0,0 +1,19 @@ +<!doctype html> +<html lang="en"> + <head> + <meta charset="UTF-8" /> + <meta name="viewport" content="width=device-width, initial-scale=1.0" /> + + <title>🚧 app</title> + + <link + rel="stylesheet" + href="./build/dev/javascript/lustre_ui/priv/static/lustre-ui.css" + /> + <script type="module" src="./priv/static/app.mjs"></script> + </head> + + <body> + <div id="app"></div> + </body> +</html> diff --git a/examples/06-custom-effects/manifest.toml b/examples/06-custom-effects/manifest.toml index 807e05c..0e5b3a3 100644 --- a/examples/06-custom-effects/manifest.toml +++ b/examples/06-custom-effects/manifest.toml @@ -3,9 +3,14 @@ packages = [ { name = "argv", version = "1.0.2", build_tools = ["gleam"], requirements = [], otp_app = "argv", source = "hex", outer_checksum = "BA1FF0929525DEBA1CE67256E5ADF77A7CDDFE729E3E3F57A5BDCAA031DED09D" }, + { name = "birl", version = "1.6.1", build_tools = ["gleam"], requirements = ["gleam_stdlib", "ranger"], otp_app = "birl", source = "hex", outer_checksum = "976CFF85D34D50F7775896615A71745FBE0C325E50399787088F941B539A0497" }, + { name = "exception", version = "2.0.0", build_tools = ["gleam"], requirements = ["gleam_stdlib"], otp_app = "exception", source = "hex", outer_checksum = "F5580D584F16A20B7FCDCABF9E9BE9A2C1F6AC4F9176FA6DD0B63E3B20D450AA" }, { name = "filepath", version = "1.0.0", build_tools = ["gleam"], requirements = ["gleam_stdlib"], otp_app = "filepath", source = "hex", outer_checksum = "EFB6FF65C98B2A16378ABC3EE2B14124168C0CE5201553DE652E2644DCFDB594" }, + { name = "filespy", version = "0.3.0", build_tools = ["gleam"], requirements = ["fs", "gleam_erlang", "gleam_otp", "gleam_stdlib"], otp_app = "filespy", source = "hex", outer_checksum = "75F5910B31A528681D25316AAAE6C91CD3E977BD2492946564B7242FF941FB7A" }, + { name = "fs", version = "8.6.1", build_tools = ["rebar3"], requirements = [], otp_app = "fs", source = "hex", outer_checksum = "61EA2BDAEDAE4E2024D0D25C63E44DCCF65622D4402DB4A2DF12868D1546503F" }, { name = "gleam_community_ansi", version = "1.4.0", build_tools = ["gleam"], requirements = ["gleam_community_colour", "gleam_stdlib"], otp_app = "gleam_community_ansi", source = "hex", outer_checksum = "FE79E08BF97009729259B6357EC058315B6FBB916FAD1C2FF9355115FEB0D3A4" }, { name = "gleam_community_colour", version = "1.4.0", build_tools = ["gleam"], requirements = ["gleam_json", "gleam_stdlib"], otp_app = "gleam_community_colour", source = "hex", outer_checksum = "795964217EBEDB3DA656F5EB8F67D7AD22872EB95182042D3E7AFEF32D3FD2FE" }, + { name = "gleam_crypto", version = "1.3.0", build_tools = ["gleam"], requirements = ["gleam_stdlib"], otp_app = "gleam_crypto", source = "hex", outer_checksum = "ADD058DEDE8F0341F1ADE3AAC492A224F15700829D9A3A3F9ADF370F875C51B7" }, { name = "gleam_erlang", version = "0.25.0", build_tools = ["gleam"], requirements = ["gleam_stdlib"], otp_app = "gleam_erlang", source = "hex", outer_checksum = "054D571A7092D2A9727B3E5D183B7507DAB0DA41556EC9133606F09C15497373" }, { name = "gleam_fetch", version = "0.4.0", build_tools = ["gleam"], requirements = ["gleam_http", "gleam_javascript", "gleam_stdlib"], otp_app = "gleam_fetch", source = "hex", outer_checksum = "7446410A44A1D1328F5BC1FF4FC9CBD1570479EA69349237B3F82E34521CCC10" }, { name = "gleam_http", version = "3.6.0", build_tools = ["gleam"], requirements = ["gleam_stdlib"], otp_app = "gleam_http", source = "hex", outer_checksum = "8C07DF9DF8CC7F054C650839A51C30A7D3C26482AC241C899C1CEA86B22DBE51" }, @@ -15,18 +20,25 @@ packages = [ { name = "gleam_package_interface", version = "1.0.0", build_tools = ["gleam"], requirements = ["gleam_json", "gleam_stdlib"], otp_app = "gleam_package_interface", source = "hex", outer_checksum = "52A721BCA972C8099BB881195D821AAA64B9F2655BECC102165D5A1097731F01" }, { name = "gleam_stdlib", version = "0.36.0", build_tools = ["gleam"], requirements = [], otp_app = "gleam_stdlib", source = "hex", outer_checksum = "C0D14D807FEC6F8A08A7C9EF8DFDE6AE5C10E40E21325B2B29365965D82EB3D4" }, { name = "glearray", version = "0.2.1", build_tools = ["gleam"], requirements = ["gleam_stdlib"], otp_app = "glearray", source = "hex", outer_checksum = "908154F695D330E06A37FAB2C04119E8F315D643206F8F32B6A6C14A8709FFF4" }, - { name = "gleeunit", version = "1.0.2", build_tools = ["gleam"], requirements = ["gleam_stdlib"], otp_app = "gleeunit", source = "hex", outer_checksum = "D364C87AFEB26BDB4FB8A5ABDE67D635DC9FA52D6AB68416044C35B096C6882D" }, + { name = "gleeunit", version = "1.1.2", build_tools = ["gleam"], requirements = ["gleam_stdlib"], otp_app = "gleeunit", source = "hex", outer_checksum = "72CDC3D3F719478F26C4E2C5FED3E657AC81EC14A47D2D2DEBB8693CA3220C3B" }, { name = "glint", version = "0.18.0", build_tools = ["gleam"], requirements = ["gleam_community_ansi", "gleam_community_colour", "gleam_stdlib", "snag"], otp_app = "glint", source = "hex", outer_checksum = "BB0F14643CC51C069A5DC6E9082EAFCD9967AFD1C9CC408803D1A40A3FD43B54" }, - { name = "lustre", version = "4.0.0", build_tools = ["gleam"], requirements = ["gleam_erlang", "gleam_json", "gleam_otp", "gleam_stdlib"], otp_app = "lustre", source = "hex", outer_checksum = "1D40C1378279F7015687F8C9DB739D6880BB0B843F4428B85C61EDDA8BF21FC6" }, - { name = "lustre_dev_tools", version = "1.0.0", build_tools = ["gleam"], requirements = ["argv", "filepath", "gleam_community_ansi", "gleam_erlang", "gleam_json", "gleam_otp", "gleam_package_interface", "gleam_stdlib", "glint", "simplifile", "spinner", "tom"], otp_app = "lustre_dev_tools", source = "hex", outer_checksum = "66142ADDCA3D6C63A89E016CF6C21E07D06D6DC92479325182A07C360BD026D3" }, + { name = "glisten", version = "2.0.0", build_tools = ["gleam"], requirements = ["gleam_erlang", "gleam_otp", "gleam_stdlib"], otp_app = "glisten", source = "hex", outer_checksum = "CF3A9383E9BA4A8CBAF2F7B799716290D02F2AC34E7A77556B49376B662B9314" }, + { name = "hpack_erl", version = "0.3.0", build_tools = ["rebar3"], requirements = [], otp_app = "hpack", source = "hex", outer_checksum = "D6137D7079169D8C485C6962DFE261AF5B9EF60FBC557344511C1E65E3D95FB0" }, + { name = "logging", version = "1.0.1", build_tools = ["gleam"], requirements = ["gleam_stdlib"], otp_app = "logging", source = "hex", outer_checksum = "82C112ED9B6C30C1772A6FE2613B94B13F62EA35F5869A2630D13948D297BD39" }, + { name = "lustre", version = "4.1.7", build_tools = ["gleam"], requirements = ["gleam_erlang", "gleam_json", "gleam_otp", "gleam_stdlib"], otp_app = "lustre", source = "hex", outer_checksum = "64F5D7E4DF51280185F70296ACB7D3DCC9B5DA09EFC5257F0E5601846DFBEF23" }, + { name = "lustre_dev_tools", version = "1.2.1", build_tools = ["gleam"], requirements = ["argv", "filepath", "filespy", "fs", "gleam_community_ansi", "gleam_erlang", "gleam_http", "gleam_json", "gleam_otp", "gleam_package_interface", "gleam_stdlib", "glint", "glisten", "mist", "simplifile", "spinner", "tom", "wisp"], otp_app = "lustre_dev_tools", source = "hex", outer_checksum = "930BBE8C4E92A16857C31B7B12616651433E1643304696FB93B69D659CE3ADC2" }, { name = "lustre_http", version = "0.5.2", build_tools = ["gleam"], requirements = ["gleam_fetch", "gleam_http", "gleam_javascript", "gleam_json", "gleam_stdlib", "lustre"], otp_app = "lustre_http", source = "hex", outer_checksum = "FB0478CBFA6B16DBE8ECA326DAE2EC15645E04900595EF2C4F039ABFA0512ABA" }, - { name = "lustre_ui", version = "0.5.0", build_tools = ["gleam"], requirements = ["gleam_community_colour", "gleam_json", "gleam_stdlib", "lustre"], otp_app = "lustre_ui", source = "hex", outer_checksum = "7ECB5414BE926082401891C62FAAA21221FC0B7A2F0568A492349F48DC2B02A0" }, + { name = "lustre_ui", version = "0.6.0", build_tools = ["gleam"], requirements = ["gleam_community_colour", "gleam_json", "gleam_stdlib", "lustre"], otp_app = "lustre_ui", source = "hex", outer_checksum = "FA1F9E89D89CDD5DF376ED86ABA8A38441CB2E664CD4D402F22A49DA4D7BB56D" }, + { name = "marceau", version = "1.1.0", build_tools = ["gleam"], requirements = [], otp_app = "marceau", source = "hex", outer_checksum = "1AAD727A30BE0F95562C3403BB9B27C823797AD90037714255EEBF617B1CDA81" }, + { name = "mist", version = "1.0.0", build_tools = ["gleam"], requirements = ["birl", "gleam_erlang", "gleam_http", "gleam_otp", "gleam_stdlib", "glisten", "hpack_erl", "logging"], otp_app = "mist", source = "hex", outer_checksum = "7765E53DCC9ACCACF217B8E0CA3DE7E848C783BFAE5118B75011E81C2C80385C" }, + { name = "ranger", version = "1.2.0", build_tools = ["gleam"], requirements = ["gleam_stdlib"], otp_app = "ranger", source = "hex", outer_checksum = "1566C272B1D141B3BBA38B25CB761EF56E312E79EC0E2DFD4D3C19FB0CC1F98C" }, { name = "repeatedly", version = "2.1.1", build_tools = ["gleam"], requirements = [], otp_app = "repeatedly", source = "hex", outer_checksum = "38808C3EC382B0CD981336D5879C24ECB37FCB9C1D1BD128F7A80B0F74404D79" }, - { name = "simplifile", version = "1.5.1", build_tools = ["gleam"], requirements = ["gleam_stdlib"], otp_app = "simplifile", source = "hex", outer_checksum = "C44DB387524F90DC42142699C78C850003289D32C7C99C7D32873792A299CDF7" }, + { name = "simplifile", version = "1.7.0", build_tools = ["gleam"], requirements = ["filepath", "gleam_stdlib"], otp_app = "simplifile", source = "hex", outer_checksum = "1D5DFA3A2F9319EC85825F6ED88B8E449F381B0D55A62F5E61424E748E7DDEB0" }, { name = "snag", version = "0.3.0", build_tools = ["gleam"], requirements = ["gleam_stdlib"], otp_app = "snag", source = "hex", outer_checksum = "54D32E16E33655346AA3E66CBA7E191DE0A8793D2C05284E3EFB90AD2CE92BCC" }, { name = "spinner", version = "1.1.0", build_tools = ["gleam"], requirements = ["gleam_community_ansi", "gleam_erlang", "gleam_stdlib", "glearray", "repeatedly"], otp_app = "spinner", source = "hex", outer_checksum = "200BA3D4A04D468898E63C0D316E23F526E02514BC46454091975CB5BAE41E8F" }, { name = "thoas", version = "0.4.1", build_tools = ["rebar3"], requirements = [], otp_app = "thoas", source = "hex", outer_checksum = "4918D50026C073C4AB1388437132C77A6F6F7C8AC43C60C13758CC0ADCE2134E" }, { name = "tom", version = "0.3.0", build_tools = ["gleam"], requirements = ["gleam_stdlib"], otp_app = "tom", source = "hex", outer_checksum = "0831C73E45405A2153091226BF98FB485ED16376988602CC01A5FD086B82D577" }, + { name = "wisp", version = "0.14.0", build_tools = ["gleam"], requirements = ["exception", "gleam_crypto", "gleam_erlang", "gleam_http", "gleam_json", "gleam_stdlib", "logging", "marceau", "mist", "simplifile"], otp_app = "wisp", source = "hex", outer_checksum = "9F5453AF1F9275E6F8707BC815D6A6A9DF41551921B16FBDBA52883773BAE684" }, ] [requirements] diff --git a/examples/06-custom-effects/priv/static/app.mjs b/examples/06-custom-effects/priv/static/app.mjs new file mode 100644 index 0000000..15fc5a2 --- /dev/null +++ b/examples/06-custom-effects/priv/static/app.mjs @@ -0,0 +1,2087 @@ +// build/dev/javascript/prelude.mjs +var CustomType = class { + withFields(fields) { + let properties = Object.keys(this).map( + (label2) => label2 in fields ? fields[label2] : this[label2] + ); + return new this.constructor(...properties); + } +}; +var List = class { + static fromArray(array3, tail) { + let t = tail || new Empty(); + for (let i = array3.length - 1; i >= 0; --i) { + t = new NonEmpty(array3[i], t); + } + return t; + } + [Symbol.iterator]() { + return new ListIterator(this); + } + toArray() { + return [...this]; + } + // @internal + atLeastLength(desired) { + for (let _ of this) { + if (desired <= 0) + return true; + desired--; + } + return desired <= 0; + } + // @internal + hasLength(desired) { + for (let _ of this) { + if (desired <= 0) + return false; + desired--; + } + return desired === 0; + } + countLength() { + let length2 = 0; + for (let _ of this) + length2++; + return length2; + } +}; +function prepend(element2, tail) { + return new NonEmpty(element2, tail); +} +function toList(elements, tail) { + return List.fromArray(elements, tail); +} +var ListIterator = class { + #current; + constructor(current) { + this.#current = current; + } + next() { + if (this.#current instanceof Empty) { + return { done: true }; + } else { + let { head, tail } = this.#current; + this.#current = tail; + return { value: head, done: false }; + } + } +}; +var Empty = class extends List { +}; +var NonEmpty = class extends List { + constructor(head, tail) { + super(); + this.head = head; + this.tail = tail; + } +}; +var BitArray = class _BitArray { + constructor(buffer) { + if (!(buffer instanceof Uint8Array)) { + throw "BitArray can only be constructed from a Uint8Array"; + } + this.buffer = buffer; + } + // @internal + get length() { + return this.buffer.length; + } + // @internal + byteAt(index2) { + return this.buffer[index2]; + } + // @internal + floatAt(index2) { + return byteArrayToFloat(this.buffer.slice(index2, index2 + 8)); + } + // @internal + intFromSlice(start4, end) { + return byteArrayToInt(this.buffer.slice(start4, end)); + } + // @internal + binaryFromSlice(start4, end) { + return new _BitArray(this.buffer.slice(start4, end)); + } + // @internal + sliceAfter(index2) { + return new _BitArray(this.buffer.slice(index2)); + } +}; +function byteArrayToInt(byteArray) { + byteArray = byteArray.reverse(); + let value3 = 0; + for (let i = byteArray.length - 1; i >= 0; i--) { + value3 = value3 * 256 + byteArray[i]; + } + return value3; +} +function byteArrayToFloat(byteArray) { + return new Float64Array(byteArray.reverse().buffer)[0]; +} +var Result = class _Result extends CustomType { + // @internal + static isResult(data) { + return data instanceof _Result; + } +}; +var Ok = class extends Result { + constructor(value3) { + super(); + this[0] = value3; + } + // @internal + isOk() { + return true; + } +}; +var Error = class extends Result { + constructor(detail) { + super(); + this[0] = detail; + } + // @internal + isOk() { + return false; + } +}; +function isEqual(x, y) { + let values = [x, y]; + while (values.length) { + let a = values.pop(); + let b = values.pop(); + if (a === b) + continue; + if (!isObject(a) || !isObject(b)) + return false; + let unequal = !structurallyCompatibleObjects(a, b) || unequalDates(a, b) || unequalBuffers(a, b) || unequalArrays(a, b) || unequalMaps(a, b) || unequalSets(a, b) || unequalRegExps(a, b); + if (unequal) + return false; + const proto = Object.getPrototypeOf(a); + if (proto !== null && typeof proto.equals === "function") { + try { + if (a.equals(b)) + continue; + else + return false; + } catch { + } + } + let [keys2, get2] = getters(a); + for (let k of keys2(a)) { + values.push(get2(a, k), get2(b, k)); + } + } + return true; +} +function getters(object3) { + if (object3 instanceof Map) { + return [(x) => x.keys(), (x, y) => x.get(y)]; + } else { + let extra = object3 instanceof globalThis.Error ? ["message"] : []; + return [(x) => [...extra, ...Object.keys(x)], (x, y) => x[y]]; + } +} +function unequalDates(a, b) { + return a instanceof Date && (a > b || a < b); +} +function unequalBuffers(a, b) { + return a.buffer instanceof ArrayBuffer && a.BYTES_PER_ELEMENT && !(a.byteLength === b.byteLength && a.every((n, i) => n === b[i])); +} +function unequalArrays(a, b) { + return Array.isArray(a) && a.length !== b.length; +} +function unequalMaps(a, b) { + return a instanceof Map && a.size !== b.size; +} +function unequalSets(a, b) { + return a instanceof Set && (a.size != b.size || [...a].some((e) => !b.has(e))); +} +function unequalRegExps(a, b) { + return a instanceof RegExp && (a.source !== b.source || a.flags !== b.flags); +} +function isObject(a) { + return typeof a === "object" && a !== null; +} +function structurallyCompatibleObjects(a, b) { + if (typeof a !== "object" && typeof b !== "object" && (!a || !b)) + return false; + let nonstructural = [Promise, WeakSet, WeakMap, Function]; + if (nonstructural.some((c) => a instanceof c)) + return false; + return a.constructor === b.constructor; +} +function makeError(variant, module, line, fn, message, extra) { + let error = new globalThis.Error(message); + error.gleam_error = variant; + error.module = module; + error.line = line; + error.fn = fn; + for (let k in extra) + error[k] = extra[k]; + return error; +} + +// build/dev/javascript/gleam_stdlib/gleam/option.mjs +var Some = class extends CustomType { + constructor(x0) { + super(); + this[0] = x0; + } +}; +var None = class extends CustomType { +}; +function to_result(option, e) { + if (option instanceof Some) { + let a = option[0]; + return new Ok(a); + } else { + return new Error(e); + } +} +function unwrap(option, default$) { + if (option instanceof Some) { + let x = option[0]; + return x; + } else { + return default$; + } +} + +// build/dev/javascript/gleam_stdlib/dict.mjs +var referenceMap = /* @__PURE__ */ new WeakMap(); +var tempDataView = new DataView(new ArrayBuffer(8)); +var referenceUID = 0; +function hashByReference(o) { + const known = referenceMap.get(o); + if (known !== void 0) { + return known; + } + const hash = referenceUID++; + if (referenceUID === 2147483647) { + referenceUID = 0; + } + referenceMap.set(o, hash); + return hash; +} +function hashMerge(a, b) { + return a ^ b + 2654435769 + (a << 6) + (a >> 2) | 0; +} +function hashString(s) { + let hash = 0; + const len = s.length; + for (let i = 0; i < len; i++) { + hash = Math.imul(31, hash) + s.charCodeAt(i) | 0; + } + return hash; +} +function hashNumber(n) { + tempDataView.setFloat64(0, n); + const i = tempDataView.getInt32(0); + const j = tempDataView.getInt32(4); + return Math.imul(73244475, i >> 16 ^ i) ^ j; +} +function hashBigInt(n) { + return hashString(n.toString()); +} +function hashObject(o) { + const proto = Object.getPrototypeOf(o); + if (proto !== null && typeof proto.hashCode === "function") { + try { + const code = o.hashCode(o); + if (typeof code === "number") { + return code; + } + } catch { + } + } + if (o instanceof Promise || o instanceof WeakSet || o instanceof WeakMap) { + return hashByReference(o); + } + if (o instanceof Date) { + return hashNumber(o.getTime()); + } + let h = 0; + if (o instanceof ArrayBuffer) { + o = new Uint8Array(o); + } + if (Array.isArray(o) || o instanceof Uint8Array) { + for (let i = 0; i < o.length; i++) { + h = Math.imul(31, h) + getHash(o[i]) | 0; + } + } else if (o instanceof Set) { + o.forEach((v) => { + h = h + getHash(v) | 0; + }); + } else if (o instanceof Map) { + o.forEach((v, k) => { + h = h + hashMerge(getHash(v), getHash(k)) | 0; + }); + } else { + const keys2 = Object.keys(o); + for (let i = 0; i < keys2.length; i++) { + const k = keys2[i]; + const v = o[k]; + h = h + hashMerge(getHash(v), hashString(k)) | 0; + } + } + return h; +} +function getHash(u) { + if (u === null) + return 1108378658; + if (u === void 0) + return 1108378659; + if (u === true) + return 1108378657; + if (u === false) + return 1108378656; + switch (typeof u) { + case "number": + return hashNumber(u); + case "string": + return hashString(u); + case "bigint": + return hashBigInt(u); + case "object": + return hashObject(u); + case "symbol": + return hashByReference(u); + case "function": + return hashByReference(u); + default: + return 0; + } +} +var SHIFT = 5; +var BUCKET_SIZE = Math.pow(2, SHIFT); +var MASK = BUCKET_SIZE - 1; +var MAX_INDEX_NODE = BUCKET_SIZE / 2; +var MIN_ARRAY_NODE = BUCKET_SIZE / 4; +var ENTRY = 0; +var ARRAY_NODE = 1; +var INDEX_NODE = 2; +var COLLISION_NODE = 3; +var EMPTY = { + type: INDEX_NODE, + bitmap: 0, + array: [] +}; +function mask(hash, shift) { + return hash >>> shift & MASK; +} +function bitpos(hash, shift) { + return 1 << mask(hash, shift); +} +function bitcount(x) { + x -= x >> 1 & 1431655765; + x = (x & 858993459) + (x >> 2 & 858993459); + x = x + (x >> 4) & 252645135; + x += x >> 8; + x += x >> 16; + return x & 127; +} +function index(bitmap, bit) { + return bitcount(bitmap & bit - 1); +} +function cloneAndSet(arr, at, val) { + const len = arr.length; + const out = new Array(len); + for (let i = 0; i < len; ++i) { + out[i] = arr[i]; + } + out[at] = val; + return out; +} +function spliceIn(arr, at, val) { + const len = arr.length; + const out = new Array(len + 1); + let i = 0; + let g = 0; + while (i < at) { + out[g++] = arr[i++]; + } + out[g++] = val; + while (i < len) { + out[g++] = arr[i++]; + } + return out; +} +function spliceOut(arr, at) { + const len = arr.length; + const out = new Array(len - 1); + let i = 0; + let g = 0; + while (i < at) { + out[g++] = arr[i++]; + } + ++i; + while (i < len) { + out[g++] = arr[i++]; + } + return out; +} +function createNode(shift, key1, val1, key2hash, key2, val2) { + const key1hash = getHash(key1); + if (key1hash === key2hash) { + return { + type: COLLISION_NODE, + hash: key1hash, + array: [ + { type: ENTRY, k: key1, v: val1 }, + { type: ENTRY, k: key2, v: val2 } + ] + }; + } + const addedLeaf = { val: false }; + return assoc( + assocIndex(EMPTY, shift, key1hash, key1, val1, addedLeaf), + shift, + key2hash, + key2, + val2, + addedLeaf + ); +} +function assoc(root2, shift, hash, key, val, addedLeaf) { + switch (root2.type) { + case ARRAY_NODE: + return assocArray(root2, shift, hash, key, val, addedLeaf); + case INDEX_NODE: + return assocIndex(root2, shift, hash, key, val, addedLeaf); + case COLLISION_NODE: + return assocCollision(root2, shift, hash, key, val, addedLeaf); + } +} +function assocArray(root2, shift, hash, key, val, addedLeaf) { + const idx = mask(hash, shift); + const node = root2.array[idx]; + if (node === void 0) { + addedLeaf.val = true; + return { + type: ARRAY_NODE, + size: root2.size + 1, + array: cloneAndSet(root2.array, idx, { type: ENTRY, k: key, v: val }) + }; + } + if (node.type === ENTRY) { + if (isEqual(key, node.k)) { + if (val === node.v) { + return root2; + } + return { + type: ARRAY_NODE, + size: root2.size, + array: cloneAndSet(root2.array, idx, { + type: ENTRY, + k: key, + v: val + }) + }; + } + addedLeaf.val = true; + return { + type: ARRAY_NODE, + size: root2.size, + array: cloneAndSet( + root2.array, + idx, + createNode(shift + SHIFT, node.k, node.v, hash, key, val) + ) + }; + } + const n = assoc(node, shift + SHIFT, hash, key, val, addedLeaf); + if (n === node) { + return root2; + } + return { + type: ARRAY_NODE, + size: root2.size, + array: cloneAndSet(root2.array, idx, n) + }; +} +function assocIndex(root2, shift, hash, key, val, addedLeaf) { + const bit = bitpos(hash, shift); + const idx = index(root2.bitmap, bit); + if ((root2.bitmap & bit) !== 0) { + const node = root2.array[idx]; + if (node.type !== ENTRY) { + const n = assoc(node, shift + SHIFT, hash, key, val, addedLeaf); + if (n === node) { + return root2; + } + return { + type: INDEX_NODE, + bitmap: root2.bitmap, + array: cloneAndSet(root2.array, idx, n) + }; + } + const nodeKey = node.k; + if (isEqual(key, nodeKey)) { + if (val === node.v) { + return root2; + } + return { + type: INDEX_NODE, + bitmap: root2.bitmap, + array: cloneAndSet(root2.array, idx, { + type: ENTRY, + k: key, + v: val + }) + }; + } + addedLeaf.val = true; + return { + type: INDEX_NODE, + bitmap: root2.bitmap, + array: cloneAndSet( + root2.array, + idx, + createNode(shift + SHIFT, nodeKey, node.v, hash, key, val) + ) + }; + } else { + const n = root2.array.length; + if (n >= MAX_INDEX_NODE) { + const nodes = new Array(32); + const jdx = mask(hash, shift); + nodes[jdx] = assocIndex(EMPTY, shift + SHIFT, hash, key, val, addedLeaf); + let j = 0; + let bitmap = root2.bitmap; + for (let i = 0; i < 32; i++) { + if ((bitmap & 1) !== 0) { + const node = root2.array[j++]; + nodes[i] = node; + } + bitmap = bitmap >>> 1; + } + return { + type: ARRAY_NODE, + size: n + 1, + array: nodes + }; + } else { + const newArray = spliceIn(root2.array, idx, { + type: ENTRY, + k: key, + v: val + }); + addedLeaf.val = true; + return { + type: INDEX_NODE, + bitmap: root2.bitmap | bit, + array: newArray + }; + } + } +} +function assocCollision(root2, shift, hash, key, val, addedLeaf) { + if (hash === root2.hash) { + const idx = collisionIndexOf(root2, key); + if (idx !== -1) { + const entry = root2.array[idx]; + if (entry.v === val) { + return root2; + } + return { + type: COLLISION_NODE, + hash, + array: cloneAndSet(root2.array, idx, { type: ENTRY, k: key, v: val }) + }; + } + const size = root2.array.length; + addedLeaf.val = true; + return { + type: COLLISION_NODE, + hash, + array: cloneAndSet(root2.array, size, { type: ENTRY, k: key, v: val }) + }; + } + return assoc( + { + type: INDEX_NODE, + bitmap: bitpos(root2.hash, shift), + array: [root2] + }, + shift, + hash, + key, + val, + addedLeaf + ); +} +function collisionIndexOf(root2, key) { + const size = root2.array.length; + for (let i = 0; i < size; i++) { + if (isEqual(key, root2.array[i].k)) { + return i; + } + } + return -1; +} +function find(root2, shift, hash, key) { + switch (root2.type) { + case ARRAY_NODE: + return findArray(root2, shift, hash, key); + case INDEX_NODE: + return findIndex(root2, shift, hash, key); + case COLLISION_NODE: + return findCollision(root2, key); + } +} +function findArray(root2, shift, hash, key) { + const idx = mask(hash, shift); + const node = root2.array[idx]; + if (node === void 0) { + return void 0; + } + if (node.type !== ENTRY) { + return find(node, shift + SHIFT, hash, key); + } + if (isEqual(key, node.k)) { + return node; + } + return void 0; +} +function findIndex(root2, shift, hash, key) { + const bit = bitpos(hash, shift); + if ((root2.bitmap & bit) === 0) { + return void 0; + } + const idx = index(root2.bitmap, bit); + const node = root2.array[idx]; + if (node.type !== ENTRY) { + return find(node, shift + SHIFT, hash, key); + } + if (isEqual(key, node.k)) { + return node; + } + return void 0; +} +function findCollision(root2, key) { + const idx = collisionIndexOf(root2, key); + if (idx < 0) { + return void 0; + } + return root2.array[idx]; +} +function without(root2, shift, hash, key) { + switch (root2.type) { + case ARRAY_NODE: + return withoutArray(root2, shift, hash, key); + case INDEX_NODE: + return withoutIndex(root2, shift, hash, key); + case COLLISION_NODE: + return withoutCollision(root2, key); + } +} +function withoutArray(root2, shift, hash, key) { + const idx = mask(hash, shift); + const node = root2.array[idx]; + if (node === void 0) { + return root2; + } + let n = void 0; + if (node.type === ENTRY) { + if (!isEqual(node.k, key)) { + return root2; + } + } else { + n = without(node, shift + SHIFT, hash, key); + if (n === node) { + return root2; + } + } + if (n === void 0) { + if (root2.size <= MIN_ARRAY_NODE) { + const arr = root2.array; + const out = new Array(root2.size - 1); + let i = 0; + let j = 0; + let bitmap = 0; + while (i < idx) { + const nv = arr[i]; + if (nv !== void 0) { + out[j] = nv; + bitmap |= 1 << i; + ++j; + } + ++i; + } + ++i; + while (i < arr.length) { + const nv = arr[i]; + if (nv !== void 0) { + out[j] = nv; + bitmap |= 1 << i; + ++j; + } + ++i; + } + return { + type: INDEX_NODE, + bitmap, + array: out + }; + } + return { + type: ARRAY_NODE, + size: root2.size - 1, + array: cloneAndSet(root2.array, idx, n) + }; + } + return { + type: ARRAY_NODE, + size: root2.size, + array: cloneAndSet(root2.array, idx, n) + }; +} +function withoutIndex(root2, shift, hash, key) { + const bit = bitpos(hash, shift); + if ((root2.bitmap & bit) === 0) { + return root2; + } + const idx = index(root2.bitmap, bit); + const node = root2.array[idx]; + if (node.type !== ENTRY) { + const n = without(node, shift + SHIFT, hash, key); + if (n === node) { + return root2; + } + if (n !== void 0) { + return { + type: INDEX_NODE, + bitmap: root2.bitmap, + array: cloneAndSet(root2.array, idx, n) + }; + } + if (root2.bitmap === bit) { + return void 0; + } + return { + type: INDEX_NODE, + bitmap: root2.bitmap ^ bit, + array: spliceOut(root2.array, idx) + }; + } + if (isEqual(key, node.k)) { + if (root2.bitmap === bit) { + return void 0; + } + return { + type: INDEX_NODE, + bitmap: root2.bitmap ^ bit, + array: spliceOut(root2.array, idx) + }; + } + return root2; +} +function withoutCollision(root2, key) { + const idx = collisionIndexOf(root2, key); + if (idx < 0) { + return root2; + } + if (root2.array.length === 1) { + return void 0; + } + return { + type: COLLISION_NODE, + hash: root2.hash, + array: spliceOut(root2.array, idx) + }; +} +function forEach(root2, fn) { + if (root2 === void 0) { + return; + } + const items = root2.array; + const size = items.length; + for (let i = 0; i < size; i++) { + const item = items[i]; + if (item === void 0) { + continue; + } + if (item.type === ENTRY) { + fn(item.v, item.k); + continue; + } + forEach(item, fn); + } +} +var Dict = class _Dict { + /** + * @template V + * @param {Record<string,V>} o + * @returns {Dict<string,V>} + */ + static fromObject(o) { + const keys2 = Object.keys(o); + let m = _Dict.new(); + for (let i = 0; i < keys2.length; i++) { + const k = keys2[i]; + m = m.set(k, o[k]); + } + return m; + } + /** + * @template K,V + * @param {Map<K,V>} o + * @returns {Dict<K,V>} + */ + static fromMap(o) { + let m = _Dict.new(); + o.forEach((v, k) => { + m = m.set(k, v); + }); + return m; + } + static new() { + return new _Dict(void 0, 0); + } + /** + * @param {undefined | Node<K,V>} root + * @param {number} size + */ + constructor(root2, size) { + this.root = root2; + this.size = size; + } + /** + * @template NotFound + * @param {K} key + * @param {NotFound} notFound + * @returns {NotFound | V} + */ + get(key, notFound) { + if (this.root === void 0) { + return notFound; + } + const found = find(this.root, 0, getHash(key), key); + if (found === void 0) { + return notFound; + } + return found.v; + } + /** + * @param {K} key + * @param {V} val + * @returns {Dict<K,V>} + */ + set(key, val) { + const addedLeaf = { val: false }; + const root2 = this.root === void 0 ? EMPTY : this.root; + const newRoot = assoc(root2, 0, getHash(key), key, val, addedLeaf); + if (newRoot === this.root) { + return this; + } + return new _Dict(newRoot, addedLeaf.val ? this.size + 1 : this.size); + } + /** + * @param {K} key + * @returns {Dict<K,V>} + */ + delete(key) { + if (this.root === void 0) { + return this; + } + const newRoot = without(this.root, 0, getHash(key), key); + if (newRoot === this.root) { + return this; + } + if (newRoot === void 0) { + return _Dict.new(); + } + return new _Dict(newRoot, this.size - 1); + } + /** + * @param {K} key + * @returns {boolean} + */ + has(key) { + if (this.root === void 0) { + return false; + } + return find(this.root, 0, getHash(key), key) !== void 0; + } + /** + * @returns {[K,V][]} + */ + entries() { + if (this.root === void 0) { + return []; + } + const result = []; + this.forEach((v, k) => result.push([k, v])); + return result; + } + /** + * + * @param {(val:V,key:K)=>void} fn + */ + forEach(fn) { + forEach(this.root, fn); + } + hashCode() { + let h = 0; + this.forEach((v, k) => { + h = h + hashMerge(getHash(v), getHash(k)) | 0; + }); + return h; + } + /** + * @param {unknown} o + * @returns {boolean} + */ + equals(o) { + if (!(o instanceof _Dict) || this.size !== o.size) { + return false; + } + let equal2 = true; + this.forEach((v, k) => { + equal2 = equal2 && isEqual(o.get(k, !v), v); + }); + return equal2; + } +}; + +// build/dev/javascript/gleam_stdlib/gleam_stdlib.mjs +var Nil = void 0; +var NOT_FOUND = {}; +function identity(x) { + return x; +} +function to_string(term) { + return term.toString(); +} +function concat(xs) { + let result = ""; + for (const x of xs) { + result = result + x; + } + return result; +} +function map_get(map4, key) { + const value3 = map4.get(key, NOT_FOUND); + if (value3 === NOT_FOUND) { + return new Error(Nil); + } + return new Ok(value3); +} +function classify_dynamic(data) { + if (typeof data === "string") { + return "String"; + } else if (data instanceof Result) { + return "Result"; + } else if (data instanceof List) { + return "List"; + } else if (data instanceof BitArray) { + return "BitArray"; + } else if (data instanceof Dict) { + return "Dict"; + } else if (Number.isInteger(data)) { + return "Int"; + } else if (Array.isArray(data)) { + return `Tuple of ${data.length} elements`; + } else if (typeof data === "number") { + return "Float"; + } else if (data === null) { + return "Null"; + } else if (data === void 0) { + return "Nil"; + } else { + const type = typeof data; + return type.charAt(0).toUpperCase() + type.slice(1); + } +} +function decoder_error(expected, got) { + return decoder_error_no_classify(expected, classify_dynamic(got)); +} +function decoder_error_no_classify(expected, got) { + return new Error( + List.fromArray([new DecodeError(expected, got, List.fromArray([]))]) + ); +} +function decode_string(data) { + return typeof data === "string" ? new Ok(data) : decoder_error("String", data); +} +function decode_int(data) { + return Number.isInteger(data) ? new Ok(data) : decoder_error("Int", data); +} +function decode_field(value3, name) { + const not_a_map_error = () => decoder_error("Dict", value3); + if (value3 instanceof Dict || value3 instanceof WeakMap || value3 instanceof Map) { + const entry = map_get(value3, name); + return new Ok(entry.isOk() ? new Some(entry[0]) : new None()); + } else if (value3 === null) { + return not_a_map_error(); + } else if (Object.getPrototypeOf(value3) == Object.prototype) { + return try_get_field(value3, name, () => new Ok(new None())); + } else { + return try_get_field(value3, name, not_a_map_error); + } +} +function try_get_field(value3, field4, or_else) { + try { + return field4 in value3 ? new Ok(new Some(value3[field4])) : or_else(); + } catch { + return or_else(); + } +} + +// build/dev/javascript/gleam_stdlib/gleam/int.mjs +function to_string2(x) { + return to_string(x); +} + +// build/dev/javascript/gleam_stdlib/gleam/list.mjs +function do_reverse_acc(loop$remaining, loop$accumulator) { + while (true) { + let remaining = loop$remaining; + let accumulator = loop$accumulator; + if (remaining.hasLength(0)) { + return accumulator; + } else { + let item = remaining.head; + let rest$1 = remaining.tail; + loop$remaining = rest$1; + loop$accumulator = prepend(item, accumulator); + } + } +} +function do_reverse(list) { + return do_reverse_acc(list, toList([])); +} +function reverse(xs) { + return do_reverse(xs); +} +function do_map(loop$list, loop$fun, loop$acc) { + while (true) { + let list = loop$list; + let fun = loop$fun; + let acc = loop$acc; + if (list.hasLength(0)) { + return reverse(acc); + } else { + let x = list.head; + let xs = list.tail; + loop$list = xs; + loop$fun = fun; + loop$acc = prepend(fun(x), acc); + } + } +} +function map(list, fun) { + return do_map(list, fun, toList([])); +} +function fold(loop$list, loop$initial, loop$fun) { + while (true) { + let list = loop$list; + let initial = loop$initial; + let fun = loop$fun; + if (list.hasLength(0)) { + return initial; + } else { + let x = list.head; + let rest$1 = list.tail; + loop$list = rest$1; + loop$initial = fun(initial, x); + loop$fun = fun; + } + } +} + +// build/dev/javascript/gleam_stdlib/gleam/result.mjs +function map2(result, fun) { + if (result.isOk()) { + let x = result[0]; + return new Ok(fun(x)); + } else { + let e = result[0]; + return new Error(e); + } +} +function map_error(result, fun) { + if (result.isOk()) { + let x = result[0]; + return new Ok(x); + } else { + let error = result[0]; + return new Error(fun(error)); + } +} +function try$(result, fun) { + if (result.isOk()) { + let x = result[0]; + return fun(x); + } else { + let e = result[0]; + return new Error(e); + } +} + +// build/dev/javascript/gleam_stdlib/gleam/string_builder.mjs +function from_strings(strings) { + return concat(strings); +} +function to_string3(builder) { + return identity(builder); +} + +// build/dev/javascript/gleam_stdlib/gleam/dynamic.mjs +var DecodeError = class extends CustomType { + constructor(expected, found, path) { + super(); + this.expected = expected; + this.found = found; + this.path = path; + } +}; +function from(a) { + return identity(a); +} +function string(data) { + return decode_string(data); +} +function classify(data) { + return classify_dynamic(data); +} +function int(data) { + return decode_int(data); +} +function any(decoders) { + return (data) => { + if (decoders.hasLength(0)) { + return new Error( + toList([new DecodeError("another type", classify(data), toList([]))]) + ); + } else { + let decoder2 = decoders.head; + let decoders$1 = decoders.tail; + let $ = decoder2(data); + if ($.isOk()) { + let decoded = $[0]; + return new Ok(decoded); + } else { + return any(decoders$1)(data); + } + } + }; +} +function push_path(error, name) { + let name$1 = from(name); + let decoder2 = any( + toList([string, (x) => { + return map2(int(x), to_string2); + }]) + ); + let name$2 = (() => { + let $ = decoder2(name$1); + if ($.isOk()) { + let name$22 = $[0]; + return name$22; + } else { + let _pipe = toList(["<", classify(name$1), ">"]); + let _pipe$1 = from_strings(_pipe); + return to_string3(_pipe$1); + } + })(); + return error.withFields({ path: prepend(name$2, error.path) }); +} +function map_errors(result, f) { + return map_error( + result, + (_capture) => { + return map(_capture, f); + } + ); +} +function field(name, inner_type) { + return (value3) => { + let missing_field_error = new DecodeError("field", "nothing", toList([])); + return try$( + decode_field(value3, name), + (maybe_inner) => { + let _pipe = maybe_inner; + let _pipe$1 = to_result(_pipe, toList([missing_field_error])); + let _pipe$2 = try$(_pipe$1, inner_type); + return map_errors( + _pipe$2, + (_capture) => { + return push_path(_capture, name); + } + ); + } + ); + }; +} + +// build/dev/javascript/gleam_stdlib/gleam/bool.mjs +function guard(requirement, consequence, alternative) { + if (requirement) { + return consequence; + } else { + return alternative(); + } +} + +// build/dev/javascript/lustre/lustre/effect.mjs +var Effect = class extends CustomType { + constructor(all) { + super(); + this.all = all; + } +}; +function from2(effect) { + return new Effect(toList([(dispatch, _) => { + return effect(dispatch); + }])); +} +function none() { + return new Effect(toList([])); +} + +// build/dev/javascript/lustre/lustre/internals/vdom.mjs +var Text = class extends CustomType { + constructor(content) { + super(); + this.content = content; + } +}; +var Element = class extends CustomType { + constructor(key, namespace, tag2, attrs, children, self_closing, void$) { + super(); + this.key = key; + this.namespace = namespace; + this.tag = tag2; + this.attrs = attrs; + this.children = children; + this.self_closing = self_closing; + this.void = void$; + } +}; +var Attribute = class extends CustomType { + constructor(x0, x1, as_property) { + super(); + this[0] = x0; + this[1] = x1; + this.as_property = as_property; + } +}; +var Event = class extends CustomType { + constructor(x0, x1) { + super(); + this[0] = x0; + this[1] = x1; + } +}; + +// build/dev/javascript/lustre/lustre/attribute.mjs +function attribute(name, value3) { + return new Attribute(name, from(value3), false); +} +function property(name, value3) { + return new Attribute(name, from(value3), true); +} +function on(name, handler) { + return new Event("on" + name, handler); +} +function style(properties) { + return attribute( + "style", + fold( + properties, + "", + (styles, _use1) => { + let name$1 = _use1[0]; + let value$1 = _use1[1]; + return styles + name$1 + ":" + value$1 + ";"; + } + ) + ); +} +function class$(name) { + return attribute("class", name); +} +function value(val) { + return property("value", from(val)); +} + +// build/dev/javascript/lustre/lustre/element.mjs +function element(tag2, attrs, children) { + if (tag2 === "area") { + return new Element("", "", tag2, attrs, toList([]), false, true); + } else if (tag2 === "base") { + return new Element("", "", tag2, attrs, toList([]), false, true); + } else if (tag2 === "br") { + return new Element("", "", tag2, attrs, toList([]), false, true); + } else if (tag2 === "col") { + return new Element("", "", tag2, attrs, toList([]), false, true); + } else if (tag2 === "embed") { + return new Element("", "", tag2, attrs, toList([]), false, true); + } else if (tag2 === "hr") { + return new Element("", "", tag2, attrs, toList([]), false, true); + } else if (tag2 === "img") { + return new Element("", "", tag2, attrs, toList([]), false, true); + } else if (tag2 === "input") { + return new Element("", "", tag2, attrs, toList([]), false, true); + } else if (tag2 === "link") { + return new Element("", "", tag2, attrs, toList([]), false, true); + } else if (tag2 === "meta") { + return new Element("", "", tag2, attrs, toList([]), false, true); + } else if (tag2 === "param") { + return new Element("", "", tag2, attrs, toList([]), false, true); + } else if (tag2 === "source") { + return new Element("", "", tag2, attrs, toList([]), false, true); + } else if (tag2 === "track") { + return new Element("", "", tag2, attrs, toList([]), false, true); + } else if (tag2 === "wbr") { + return new Element("", "", tag2, attrs, toList([]), false, true); + } else { + return new Element("", "", tag2, attrs, children, false, false); + } +} +function text(content) { + return new Text(content); +} + +// build/dev/javascript/lustre/lustre/internals/runtime.mjs +var Dispatch = class extends CustomType { + constructor(x0) { + super(); + this[0] = x0; + } +}; +var Shutdown = class extends CustomType { +}; + +// build/dev/javascript/lustre/vdom.ffi.mjs +function morph(prev, next, dispatch, isComponent = false) { + let out; + let stack2 = [{ prev, next, parent: prev.parentNode }]; + while (stack2.length) { + let { prev: prev2, next: next2, parent } = stack2.pop(); + if (next2.subtree !== void 0) + next2 = next2.subtree(); + if (next2.content !== void 0) { + if (!prev2) { + const created = document.createTextNode(next2.content); + parent.appendChild(created); + out ??= created; + } else if (prev2.nodeType === Node.TEXT_NODE) { + if (prev2.textContent !== next2.content) + prev2.textContent = next2.content; + out ??= prev2; + } else { + const created = document.createTextNode(next2.content); + parent.replaceChild(created, prev2); + out ??= created; + } + } else if (next2.tag !== void 0) { + const created = createElementNode({ + prev: prev2, + next: next2, + dispatch, + stack: stack2, + isComponent + }); + if (!prev2) { + parent.appendChild(created); + } else if (prev2 !== created) { + parent.replaceChild(created, prev2); + } + out ??= created; + } + } + return out; +} +function createElementNode({ prev, next, dispatch, stack: stack2 }) { + const namespace = next.namespace || "http://www.w3.org/1999/xhtml"; + const canMorph = prev && prev.nodeType === Node.ELEMENT_NODE && prev.localName === next.tag && prev.namespaceURI === (next.namespace || "http://www.w3.org/1999/xhtml"); + const el2 = canMorph ? prev : namespace ? document.createElementNS(namespace, next.tag) : document.createElement(next.tag); + let handlersForEl; + if (!registeredHandlers.has(el2)) { + const emptyHandlers = /* @__PURE__ */ new Map(); + registeredHandlers.set(el2, emptyHandlers); + handlersForEl = emptyHandlers; + } else { + handlersForEl = registeredHandlers.get(el2); + } + const prevHandlers = canMorph ? new Set(handlersForEl.keys()) : null; + const prevAttributes = canMorph ? new Set(Array.from(prev.attributes, (a) => a.name)) : null; + let className = null; + let style2 = null; + let innerHTML = null; + for (const attr of next.attrs) { + const name = attr[0]; + const value3 = attr[1]; + const isProperty = attr[2]; + if (isProperty) { + el2[name] = value3; + } else if (name.startsWith("on")) { + const eventName = name.slice(2); + const callback = dispatch(value3); + if (!handlersForEl.has(eventName)) { + el2.addEventListener(eventName, lustreGenericEventHandler); + } + handlersForEl.set(eventName, callback); + if (canMorph) + prevHandlers.delete(eventName); + } else if (name.startsWith("data-lustre-on-")) { + const eventName = name.slice(15); + const callback = dispatch(lustreServerEventHandler); + if (!handlersForEl.has(eventName)) { + el2.addEventListener(eventName, lustreGenericEventHandler); + } + handlersForEl.set(eventName, callback); + el2.setAttribute(name, value3); + } else if (name === "class") { + className = className === null ? value3 : className + " " + value3; + } else if (name === "style") { + style2 = style2 === null ? value3 : style2 + value3; + } else if (name === "dangerous-unescaped-html") { + innerHTML = value3; + } else { + el2.setAttribute(name, value3); + if (name === "value") + el2[name] = value3; + if (canMorph) + prevAttributes.delete(name); + } + } + if (className !== null) { + el2.setAttribute("class", className); + if (canMorph) + prevAttributes.delete("class"); + } + if (style2 !== null) { + el2.setAttribute("style", style2); + if (canMorph) + prevAttributes.delete("style"); + } + if (canMorph) { + for (const attr of prevAttributes) { + el2.removeAttribute(attr); + } + for (const eventName of prevHandlers) { + handlersForEl.delete(eventName); + el2.removeEventListener(eventName, lustreGenericEventHandler); + } + } + if (next.key !== void 0 && next.key !== "") { + el2.setAttribute("data-lustre-key", next.key); + } else if (innerHTML !== null) { + el2.innerHTML = innerHTML; + return el2; + } + let prevChild = el2.firstChild; + let seenKeys = null; + let keyedChildren = null; + let incomingKeyedChildren = null; + let firstChild = next.children[Symbol.iterator]().next().value; + if (canMorph && firstChild !== void 0 && // Explicit checks are more verbose but truthy checks force a bunch of comparisons + // we don't care about: it's never gonna be a number etc. + firstChild.key !== void 0 && firstChild.key !== "") { + seenKeys = /* @__PURE__ */ new Set(); + keyedChildren = getKeyedChildren(prev); + incomingKeyedChildren = getKeyedChildren(next); + } + for (const child of next.children) { + if (child.key !== void 0 && seenKeys !== null) { + while (prevChild && !incomingKeyedChildren.has(prevChild.getAttribute("data-lustre-key"))) { + const nextChild = prevChild.nextSibling; + el2.removeChild(prevChild); + prevChild = nextChild; + } + if (keyedChildren.size === 0) { + stack2.unshift({ prev: prevChild, next: child, parent: el2 }); + prevChild = prevChild?.nextSibling; + continue; + } + if (seenKeys.has(child.key)) { + console.warn(`Duplicate key found in Lustre vnode: ${child.key}`); + stack2.unshift({ prev: null, next: child, parent: el2 }); + continue; + } + seenKeys.add(child.key); + const keyedChild = keyedChildren.get(child.key); + if (!keyedChild && !prevChild) { + stack2.unshift({ prev: null, next: child, parent: el2 }); + continue; + } + if (!keyedChild && prevChild !== null) { + const placeholder = document.createTextNode(""); + el2.insertBefore(placeholder, prevChild); + stack2.unshift({ prev: placeholder, next: child, parent: el2 }); + continue; + } + if (!keyedChild || keyedChild === prevChild) { + stack2.unshift({ prev: prevChild, next: child, parent: el2 }); + prevChild = prevChild?.nextSibling; + continue; + } + el2.insertBefore(keyedChild, prevChild); + stack2.unshift({ prev: keyedChild, next: child, parent: el2 }); + } else { + stack2.unshift({ prev: prevChild, next: child, parent: el2 }); + prevChild = prevChild?.nextSibling; + } + } + while (prevChild) { + const next2 = prevChild.nextSibling; + el2.removeChild(prevChild); + prevChild = next2; + } + return el2; +} +var registeredHandlers = /* @__PURE__ */ new WeakMap(); +function lustreGenericEventHandler(event2) { + const target = event2.currentTarget; + if (!registeredHandlers.has(target)) { + target.removeEventListener(event2.type, lustreGenericEventHandler); + return; + } + const handlersForEventTarget = registeredHandlers.get(target); + if (!handlersForEventTarget.has(event2.type)) { + target.removeEventListener(event2.type, lustreGenericEventHandler); + return; + } + handlersForEventTarget.get(event2.type)(event2); +} +function lustreServerEventHandler(event2) { + const el2 = event2.target; + const tag2 = el2.getAttribute(`data-lustre-on-${event2.type}`); + const data = JSON.parse(el2.getAttribute("data-lustre-data") || "{}"); + const include = JSON.parse(el2.getAttribute("data-lustre-include") || "[]"); + switch (event2.type) { + case "input": + case "change": + include.push("target.value"); + break; + } + return { + tag: tag2, + data: include.reduce( + (data2, property2) => { + const path = property2.split("."); + for (let i = 0, o = data2, e = event2; i < path.length; i++) { + if (i === path.length - 1) { + o[path[i]] = e[path[i]]; + } else { + o[path[i]] ??= {}; + e = e[path[i]]; + o = o[path[i]]; + } + } + return data2; + }, + { data } + ) + }; +} +function getKeyedChildren(el2) { + const keyedChildren = /* @__PURE__ */ new Map(); + if (el2) { + for (const child of el2.children) { + const key = child.key || child?.getAttribute("data-lustre-key"); + if (key) + keyedChildren.set(key, child); + } + } + return keyedChildren; +} + +// build/dev/javascript/lustre/client-runtime.ffi.mjs +var LustreClientApplication2 = class _LustreClientApplication { + #root = null; + #queue = []; + #effects = []; + #didUpdate = false; + #isComponent = false; + #model = null; + #update = null; + #view = null; + static start(flags, selector, init3, update3, view2) { + if (!is_browser()) + return new Error(new NotABrowser()); + const root2 = selector instanceof HTMLElement ? selector : document.querySelector(selector); + if (!root2) + return new Error(new ElementNotFound(selector)); + const app = new _LustreClientApplication(init3(flags), update3, view2, root2); + return new Ok((msg) => app.send(msg)); + } + constructor([model, effects], update3, view2, root2 = document.body, isComponent = false) { + this.#model = model; + this.#update = update3; + this.#view = view2; + this.#root = root2; + this.#effects = effects.all.toArray(); + this.#didUpdate = true; + this.#isComponent = isComponent; + window.requestAnimationFrame(() => this.#tick()); + } + send(action) { + switch (true) { + case action instanceof Dispatch: { + this.#queue.push(action[0]); + this.#tick(); + return; + } + case action instanceof Shutdown: { + this.#shutdown(); + return; + } + default: + return; + } + } + emit(event2, data) { + this.#root.dispatchEvent( + new CustomEvent(event2, { + bubbles: true, + detail: data, + composed: true + }) + ); + } + #tick() { + this.#flush_queue(); + const vdom = this.#view(this.#model); + const dispatch = (handler) => (e) => { + const result = handler(e); + if (result instanceof Ok) { + this.send(new Dispatch(result[0])); + } + }; + this.#didUpdate = false; + this.#root = morph(this.#root, vdom, dispatch, this.#isComponent); + } + #flush_queue(iterations = 0) { + while (this.#queue.length) { + const [next, effects] = this.#update(this.#model, this.#queue.shift()); + this.#didUpdate ||= !isEqual(this.#model, next); + this.#model = next; + this.#effects = this.#effects.concat(effects.all.toArray()); + } + while (this.#effects.length) { + this.#effects.shift()( + (msg) => this.send(new Dispatch(msg)), + (event2, data) => this.emit(event2, data) + ); + } + if (this.#queue.length) { + if (iterations < 5) { + this.#flush_queue(++iterations); + } else { + window.requestAnimationFrame(() => this.#tick()); + } + } + } + #shutdown() { + this.#root.remove(); + this.#root = null; + this.#model = null; + this.#queue = []; + this.#effects = []; + this.#didUpdate = false; + this.#update = () => { + }; + this.#view = () => { + }; + } +}; +var start = (app, selector, flags) => LustreClientApplication2.start( + flags, + selector, + app.init, + app.update, + app.view +); +var is_browser = () => window && window.document; + +// build/dev/javascript/lustre/lustre.mjs +var App = class extends CustomType { + constructor(init3, update3, view2, on_attribute_change) { + super(); + this.init = init3; + this.update = update3; + this.view = view2; + this.on_attribute_change = on_attribute_change; + } +}; +var ElementNotFound = class extends CustomType { + constructor(selector) { + super(); + this.selector = selector; + } +}; +var NotABrowser = class extends CustomType { +}; +function application(init3, update3, view2) { + return new App(init3, update3, view2, new None()); +} +function start3(app, selector, flags) { + return guard( + !is_browser(), + new Error(new NotABrowser()), + () => { + return start(app, selector, flags); + } + ); +} + +// build/dev/javascript/lustre/lustre/event.mjs +function on2(name, handler) { + return on(name, handler); +} +function value2(event2) { + let _pipe = event2; + return field("target", field("value", string))( + _pipe + ); +} +function on_input(msg) { + return on2( + "input", + (event2) => { + let _pipe = value2(event2); + return map2(_pipe, msg); + } + ); +} + +// build/dev/javascript/lustre/lustre/element/html.mjs +function div(attrs, children) { + return element("div", attrs, children); +} +function span(attrs, children) { + return element("span", attrs, children); +} +function input(attrs) { + return element("input", attrs, toList([])); +} +function label(attrs, children) { + return element("label", attrs, children); +} + +// build/dev/javascript/lustre_ui/lustre/ui/layout/stack.mjs +function of(element2, attributes, children) { + return element2( + prepend(class$("lustre-ui-stack"), attributes), + children + ); +} +function packed() { + return class$("packed"); +} + +// build/dev/javascript/lustre_ui/lustre/ui/field.mjs +function of2(element2, attributes, label2, input4, message) { + return of( + element2, + prepend( + class$("lustre-ui-field"), + prepend(packed(), attributes) + ), + toList([ + span(toList([class$("label")]), label2), + input4, + span(toList([class$("message")]), message) + ]) + ); +} +function field2(attributes, label2, input4, message) { + return of2(label, attributes, label2, input4, message); +} + +// build/dev/javascript/lustre_ui/lustre/ui/input.mjs +function input2(attributes) { + return input( + prepend(class$("lustre-ui-input"), attributes) + ); +} + +// build/dev/javascript/lustre_ui/lustre/ui/layout/centre.mjs +function of3(element2, attributes, children) { + return element2( + prepend(class$("lustre-ui-centre"), attributes), + toList([children]) + ); +} +function centre(attributes, children) { + return of3(div, attributes, children); +} + +// build/dev/javascript/gleam_community_colour/gleam_community/colour.mjs +var Rgba = class extends CustomType { + constructor(r, g, b, a) { + super(); + this.r = r; + this.g = g; + this.b = b; + this.a = a; + } +}; +var light_red = new Rgba( + 0.9372549019607843, + 0.1607843137254902, + 0.1607843137254902, + 1 +); +var red = new Rgba(0.8, 0, 0, 1); +var dark_red = new Rgba(0.6431372549019608, 0, 0, 1); +var light_orange = new Rgba( + 0.9882352941176471, + 0.6862745098039216, + 0.24313725490196078, + 1 +); +var orange = new Rgba(0.9607843137254902, 0.4745098039215686, 0, 1); +var dark_orange = new Rgba( + 0.807843137254902, + 0.3607843137254902, + 0, + 1 +); +var light_yellow = new Rgba( + 1, + 0.9137254901960784, + 0.30980392156862746, + 1 +); +var yellow = new Rgba(0.9294117647058824, 0.8313725490196079, 0, 1); +var dark_yellow = new Rgba( + 0.7686274509803922, + 0.6274509803921569, + 0, + 1 +); +var light_green = new Rgba( + 0.5411764705882353, + 0.8862745098039215, + 0.20392156862745098, + 1 +); +var green = new Rgba( + 0.45098039215686275, + 0.8235294117647058, + 0.08627450980392157, + 1 +); +var dark_green = new Rgba( + 0.3058823529411765, + 0.6039215686274509, + 0.023529411764705882, + 1 +); +var light_blue = new Rgba( + 0.4470588235294118, + 0.6235294117647059, + 0.8117647058823529, + 1 +); +var blue = new Rgba( + 0.20392156862745098, + 0.396078431372549, + 0.6431372549019608, + 1 +); +var dark_blue = new Rgba( + 0.12549019607843137, + 0.2901960784313726, + 0.5294117647058824, + 1 +); +var light_purple = new Rgba( + 0.6784313725490196, + 0.4980392156862745, + 0.6588235294117647, + 1 +); +var purple = new Rgba( + 0.4588235294117647, + 0.3137254901960784, + 0.4823529411764706, + 1 +); +var dark_purple = new Rgba( + 0.3607843137254902, + 0.20784313725490197, + 0.4, + 1 +); +var light_brown = new Rgba( + 0.9137254901960784, + 0.7254901960784313, + 0.43137254901960786, + 1 +); +var brown = new Rgba( + 0.7568627450980392, + 0.49019607843137253, + 0.06666666666666667, + 1 +); +var dark_brown = new Rgba( + 0.5607843137254902, + 0.34901960784313724, + 0.00784313725490196, + 1 +); +var black = new Rgba(0, 0, 0, 1); +var white = new Rgba(1, 1, 1, 1); +var light_grey = new Rgba( + 0.9333333333333333, + 0.9333333333333333, + 0.9254901960784314, + 1 +); +var grey = new Rgba( + 0.8274509803921568, + 0.8431372549019608, + 0.8117647058823529, + 1 +); +var dark_grey = new Rgba( + 0.7294117647058823, + 0.7411764705882353, + 0.7137254901960784, + 1 +); +var light_gray = new Rgba( + 0.9333333333333333, + 0.9333333333333333, + 0.9254901960784314, + 1 +); +var gray = new Rgba( + 0.8274509803921568, + 0.8431372549019608, + 0.8117647058823529, + 1 +); +var dark_gray = new Rgba( + 0.7294117647058823, + 0.7411764705882353, + 0.7137254901960784, + 1 +); +var light_charcoal = new Rgba( + 0.5333333333333333, + 0.5411764705882353, + 0.5215686274509804, + 1 +); +var charcoal = new Rgba( + 0.3333333333333333, + 0.3411764705882353, + 0.3254901960784314, + 1 +); +var dark_charcoal = new Rgba( + 0.1803921568627451, + 0.20392156862745098, + 0.21176470588235294, + 1 +); +var pink = new Rgba(1, 0.6862745098039216, 0.9529411764705882, 1); + +// build/dev/javascript/lustre_ui/lustre/ui.mjs +var centre2 = centre; +var field3 = field2; +var input3 = input2; + +// build/dev/javascript/app/app.ffi.mjs +function read_localstorage(key) { + const value3 = window.localStorage.getItem(key); + return value3 ? new Ok(value3) : new Error(void 0); +} +function write_localstorage(key, value3) { + window.localStorage.setItem(key, value3); +} + +// build/dev/javascript/app/app.mjs +var Model = class extends CustomType { + constructor(message) { + super(); + this.message = message; + } +}; +var UserUpdatedMessage = class extends CustomType { + constructor(x0) { + super(); + this[0] = x0; + } +}; +var CacheUpdatedMessage = class extends CustomType { + constructor(x0) { + super(); + this[0] = x0; + } +}; +function read_localstorage2(key) { + return from2( + (dispatch) => { + let _pipe = read_localstorage(key); + let _pipe$1 = new CacheUpdatedMessage(_pipe); + return dispatch(_pipe$1); + } + ); +} +function init2(_) { + return [new Model(new None()), read_localstorage2("message")]; +} +function write_localstorage2(key, value3) { + return from2((_) => { + return write_localstorage(key, value3); + }); +} +function update2(model, msg) { + if (msg instanceof UserUpdatedMessage) { + let input4 = msg[0]; + return [new Model(new Some(input4)), write_localstorage2("message", input4)]; + } else if (msg instanceof CacheUpdatedMessage && msg[0].isOk()) { + let message = msg[0][0]; + return [new Model(new Some(message)), none()]; + } else { + return [model, none()]; + } +} +function view(model) { + let styles = toList([["width", "100vw"], ["height", "100vh"]]); + let message = unwrap(model.message, ""); + return centre2( + toList([style(styles)]), + field3( + toList([]), + toList([]), + input3( + toList([ + value(message), + on_input((var0) => { + return new UserUpdatedMessage(var0); + }) + ]) + ), + toList([text("Type a message and refresh the page")]) + ) + ); +} +function main() { + let app = application(init2, update2, view); + let $ = start3(app, "#app", void 0); + if (!$.isOk()) { + throw makeError( + "assignment_no_match", + "app", + 13, + "main", + "Assignment pattern did not match", + { value: $ } + ); + } + return $; +} + +// build/.lustre/entry.mjs +main(); diff --git a/examples/06-custom-effects/src/app.gleam b/examples/06-custom-effects/src/app.gleam index 4771bfd..a6c668e 100644 --- a/examples/06-custom-effects/src/app.gleam +++ b/examples/06-custom-effects/src/app.gleam @@ -4,14 +4,6 @@ import lustre/attribute import lustre/effect.{type Effect} import lustre/element.{type Element} import lustre/event -// These examples are written with `lustre/ui` in mind. They'll work regardless, -// but to see what `lustre/ui` can do make sure to run each of these examples with -// the `--use-example-styles` flag: -// -// $ gleam run -m lustre/dev start --use-example-styles -// -// In your own apps, make sure to add the `lustre/ui` dependency and include the -// stylesheet somewhere. import lustre/ui // MAIN ------------------------------------------------------------------------ diff --git a/examples/07-routing/index.html b/examples/07-routing/index.html new file mode 100644 index 0000000..36ddf10 --- /dev/null +++ b/examples/07-routing/index.html @@ -0,0 +1,19 @@ +<!doctype html> +<html lang="en"> + <head> + <meta charset="UTF-8" /> + <meta name="viewport" content="width=device-width, initial-scale=1.0" /> + + <title>🚧 app</title> + + <link + rel="stylesheet" + href="./build/dev/javascript/lustre_ui/priv/static/lustre-ui.css" + /> + <script type="module" src="./priv/static/app.mjs"></script> + </head> + + <body> + <div id="app"></div> + </body> +</html> diff --git a/examples/07-routing/manifest.toml b/examples/07-routing/manifest.toml index 6000b9b..2935100 100644 --- a/examples/07-routing/manifest.toml +++ b/examples/07-routing/manifest.toml @@ -3,9 +3,14 @@ packages = [ { name = "argv", version = "1.0.2", build_tools = ["gleam"], requirements = [], otp_app = "argv", source = "hex", outer_checksum = "BA1FF0929525DEBA1CE67256E5ADF77A7CDDFE729E3E3F57A5BDCAA031DED09D" }, + { name = "birl", version = "1.6.1", build_tools = ["gleam"], requirements = ["gleam_stdlib", "ranger"], otp_app = "birl", source = "hex", outer_checksum = "976CFF85D34D50F7775896615A71745FBE0C325E50399787088F941B539A0497" }, + { name = "exception", version = "2.0.0", build_tools = ["gleam"], requirements = ["gleam_stdlib"], otp_app = "exception", source = "hex", outer_checksum = "F5580D584F16A20B7FCDCABF9E9BE9A2C1F6AC4F9176FA6DD0B63E3B20D450AA" }, { name = "filepath", version = "1.0.0", build_tools = ["gleam"], requirements = ["gleam_stdlib"], otp_app = "filepath", source = "hex", outer_checksum = "EFB6FF65C98B2A16378ABC3EE2B14124168C0CE5201553DE652E2644DCFDB594" }, + { name = "filespy", version = "0.3.0", build_tools = ["gleam"], requirements = ["fs", "gleam_erlang", "gleam_otp", "gleam_stdlib"], otp_app = "filespy", source = "hex", outer_checksum = "75F5910B31A528681D25316AAAE6C91CD3E977BD2492946564B7242FF941FB7A" }, + { name = "fs", version = "8.6.1", build_tools = ["rebar3"], requirements = [], otp_app = "fs", source = "hex", outer_checksum = "61EA2BDAEDAE4E2024D0D25C63E44DCCF65622D4402DB4A2DF12868D1546503F" }, { name = "gleam_community_ansi", version = "1.4.0", build_tools = ["gleam"], requirements = ["gleam_community_colour", "gleam_stdlib"], otp_app = "gleam_community_ansi", source = "hex", outer_checksum = "FE79E08BF97009729259B6357EC058315B6FBB916FAD1C2FF9355115FEB0D3A4" }, { name = "gleam_community_colour", version = "1.4.0", build_tools = ["gleam"], requirements = ["gleam_json", "gleam_stdlib"], otp_app = "gleam_community_colour", source = "hex", outer_checksum = "795964217EBEDB3DA656F5EB8F67D7AD22872EB95182042D3E7AFEF32D3FD2FE" }, + { name = "gleam_crypto", version = "1.3.0", build_tools = ["gleam"], requirements = ["gleam_stdlib"], otp_app = "gleam_crypto", source = "hex", outer_checksum = "ADD058DEDE8F0341F1ADE3AAC492A224F15700829D9A3A3F9ADF370F875C51B7" }, { name = "gleam_erlang", version = "0.25.0", build_tools = ["gleam"], requirements = ["gleam_stdlib"], otp_app = "gleam_erlang", source = "hex", outer_checksum = "054D571A7092D2A9727B3E5D183B7507DAB0DA41556EC9133606F09C15497373" }, { name = "gleam_fetch", version = "0.4.0", build_tools = ["gleam"], requirements = ["gleam_http", "gleam_javascript", "gleam_stdlib"], otp_app = "gleam_fetch", source = "hex", outer_checksum = "7446410A44A1D1328F5BC1FF4FC9CBD1570479EA69349237B3F82E34521CCC10" }, { name = "gleam_http", version = "3.6.0", build_tools = ["gleam"], requirements = ["gleam_stdlib"], otp_app = "gleam_http", source = "hex", outer_checksum = "8C07DF9DF8CC7F054C650839A51C30A7D3C26482AC241C899C1CEA86B22DBE51" }, @@ -17,17 +22,24 @@ packages = [ { name = "glearray", version = "0.2.1", build_tools = ["gleam"], requirements = ["gleam_stdlib"], otp_app = "glearray", source = "hex", outer_checksum = "908154F695D330E06A37FAB2C04119E8F315D643206F8F32B6A6C14A8709FFF4" }, { name = "gleeunit", version = "1.1.2", build_tools = ["gleam"], requirements = ["gleam_stdlib"], otp_app = "gleeunit", source = "hex", outer_checksum = "72CDC3D3F719478F26C4E2C5FED3E657AC81EC14A47D2D2DEBB8693CA3220C3B" }, { name = "glint", version = "0.18.0", build_tools = ["gleam"], requirements = ["gleam_community_ansi", "gleam_community_colour", "gleam_stdlib", "snag"], otp_app = "glint", source = "hex", outer_checksum = "BB0F14643CC51C069A5DC6E9082EAFCD9967AFD1C9CC408803D1A40A3FD43B54" }, - { name = "lustre", version = "4.1.4", build_tools = ["gleam"], requirements = ["gleam_erlang", "gleam_json", "gleam_otp", "gleam_stdlib"], otp_app = "lustre", source = "hex", outer_checksum = "BA9ED993187B0BB721FFBB1F01F6CCA14548F68873C55567B77918D33D0D9ECB" }, - { name = "lustre_dev_tools", version = "1.1.1", build_tools = ["gleam"], requirements = ["argv", "filepath", "gleam_community_ansi", "gleam_erlang", "gleam_json", "gleam_otp", "gleam_package_interface", "gleam_stdlib", "glint", "simplifile", "spinner", "tom"], otp_app = "lustre_dev_tools", source = "hex", outer_checksum = "16E34D9441FFCA0F5A4E13EAA910228275867F88971EC79ECD3F802375EA82BE" }, + { name = "glisten", version = "2.0.0", build_tools = ["gleam"], requirements = ["gleam_erlang", "gleam_otp", "gleam_stdlib"], otp_app = "glisten", source = "hex", outer_checksum = "CF3A9383E9BA4A8CBAF2F7B799716290D02F2AC34E7A77556B49376B662B9314" }, + { name = "hpack_erl", version = "0.3.0", build_tools = ["rebar3"], requirements = [], otp_app = "hpack", source = "hex", outer_checksum = "D6137D7079169D8C485C6962DFE261AF5B9EF60FBC557344511C1E65E3D95FB0" }, + { name = "logging", version = "1.0.1", build_tools = ["gleam"], requirements = ["gleam_stdlib"], otp_app = "logging", source = "hex", outer_checksum = "82C112ED9B6C30C1772A6FE2613B94B13F62EA35F5869A2630D13948D297BD39" }, + { name = "lustre", version = "4.1.7", build_tools = ["gleam"], requirements = ["gleam_erlang", "gleam_json", "gleam_otp", "gleam_stdlib"], otp_app = "lustre", source = "hex", outer_checksum = "64F5D7E4DF51280185F70296ACB7D3DCC9B5DA09EFC5257F0E5601846DFBEF23" }, + { name = "lustre_dev_tools", version = "1.2.1", build_tools = ["gleam"], requirements = ["argv", "filepath", "filespy", "fs", "gleam_community_ansi", "gleam_erlang", "gleam_http", "gleam_json", "gleam_otp", "gleam_package_interface", "gleam_stdlib", "glint", "glisten", "mist", "simplifile", "spinner", "tom", "wisp"], otp_app = "lustre_dev_tools", source = "hex", outer_checksum = "930BBE8C4E92A16857C31B7B12616651433E1643304696FB93B69D659CE3ADC2" }, { name = "lustre_http", version = "0.5.2", build_tools = ["gleam"], requirements = ["gleam_fetch", "gleam_http", "gleam_javascript", "gleam_json", "gleam_stdlib", "lustre"], otp_app = "lustre_http", source = "hex", outer_checksum = "FB0478CBFA6B16DBE8ECA326DAE2EC15645E04900595EF2C4F039ABFA0512ABA" }, { name = "lustre_ui", version = "0.6.0", build_tools = ["gleam"], requirements = ["gleam_community_colour", "gleam_json", "gleam_stdlib", "lustre"], otp_app = "lustre_ui", source = "hex", outer_checksum = "FA1F9E89D89CDD5DF376ED86ABA8A38441CB2E664CD4D402F22A49DA4D7BB56D" }, + { name = "marceau", version = "1.1.0", build_tools = ["gleam"], requirements = [], otp_app = "marceau", source = "hex", outer_checksum = "1AAD727A30BE0F95562C3403BB9B27C823797AD90037714255EEBF617B1CDA81" }, + { name = "mist", version = "1.0.0", build_tools = ["gleam"], requirements = ["birl", "gleam_erlang", "gleam_http", "gleam_otp", "gleam_stdlib", "glisten", "hpack_erl", "logging"], otp_app = "mist", source = "hex", outer_checksum = "7765E53DCC9ACCACF217B8E0CA3DE7E848C783BFAE5118B75011E81C2C80385C" }, { name = "modem", version = "1.0.0", build_tools = ["gleam"], requirements = ["gleam_stdlib", "lustre"], otp_app = "modem", source = "hex", outer_checksum = "584897B281E86458C513D9FB0D00C143507FA684042616A87BD4A4695B272FDE" }, + { name = "ranger", version = "1.2.0", build_tools = ["gleam"], requirements = ["gleam_stdlib"], otp_app = "ranger", source = "hex", outer_checksum = "1566C272B1D141B3BBA38B25CB761EF56E312E79EC0E2DFD4D3C19FB0CC1F98C" }, { name = "repeatedly", version = "2.1.1", build_tools = ["gleam"], requirements = [], otp_app = "repeatedly", source = "hex", outer_checksum = "38808C3EC382B0CD981336D5879C24ECB37FCB9C1D1BD128F7A80B0F74404D79" }, - { name = "simplifile", version = "1.6.1", build_tools = ["gleam"], requirements = ["filepath", "gleam_stdlib"], otp_app = "simplifile", source = "hex", outer_checksum = "B75D3C64E526D9D7EDEED5F3BA31DAAF5F2B4D80A4183FE17FDB02ED526E4E96" }, + { name = "simplifile", version = "1.7.0", build_tools = ["gleam"], requirements = ["filepath", "gleam_stdlib"], otp_app = "simplifile", source = "hex", outer_checksum = "1D5DFA3A2F9319EC85825F6ED88B8E449F381B0D55A62F5E61424E748E7DDEB0" }, { name = "snag", version = "0.3.0", build_tools = ["gleam"], requirements = ["gleam_stdlib"], otp_app = "snag", source = "hex", outer_checksum = "54D32E16E33655346AA3E66CBA7E191DE0A8793D2C05284E3EFB90AD2CE92BCC" }, { name = "spinner", version = "1.1.0", build_tools = ["gleam"], requirements = ["gleam_community_ansi", "gleam_erlang", "gleam_stdlib", "glearray", "repeatedly"], otp_app = "spinner", source = "hex", outer_checksum = "200BA3D4A04D468898E63C0D316E23F526E02514BC46454091975CB5BAE41E8F" }, { name = "thoas", version = "0.4.1", build_tools = ["rebar3"], requirements = [], otp_app = "thoas", source = "hex", outer_checksum = "4918D50026C073C4AB1388437132C77A6F6F7C8AC43C60C13758CC0ADCE2134E" }, { name = "tom", version = "0.3.0", build_tools = ["gleam"], requirements = ["gleam_stdlib"], otp_app = "tom", source = "hex", outer_checksum = "0831C73E45405A2153091226BF98FB485ED16376988602CC01A5FD086B82D577" }, + { name = "wisp", version = "0.14.0", build_tools = ["gleam"], requirements = ["exception", "gleam_crypto", "gleam_erlang", "gleam_http", "gleam_json", "gleam_stdlib", "logging", "marceau", "mist", "simplifile"], otp_app = "wisp", source = "hex", outer_checksum = "9F5453AF1F9275E6F8707BC815D6A6A9DF41551921B16FBDBA52883773BAE684" }, ] [requirements] diff --git a/examples/07-routing/priv/static/app.mjs b/examples/07-routing/priv/static/app.mjs new file mode 100644 index 0000000..d76fbad --- /dev/null +++ b/examples/07-routing/priv/static/app.mjs @@ -0,0 +1,2419 @@ +// build/dev/javascript/prelude.mjs +var CustomType = class { + withFields(fields) { + let properties = Object.keys(this).map( + (label2) => label2 in fields ? fields[label2] : this[label2] + ); + return new this.constructor(...properties); + } +}; +var List = class { + static fromArray(array3, tail) { + let t = tail || new Empty(); + for (let i = array3.length - 1; i >= 0; --i) { + t = new NonEmpty(array3[i], t); + } + return t; + } + [Symbol.iterator]() { + return new ListIterator(this); + } + toArray() { + return [...this]; + } + // @internal + atLeastLength(desired) { + for (let _ of this) { + if (desired <= 0) + return true; + desired--; + } + return desired <= 0; + } + // @internal + hasLength(desired) { + for (let _ of this) { + if (desired <= 0) + return false; + desired--; + } + return desired === 0; + } + countLength() { + let length3 = 0; + for (let _ of this) + length3++; + return length3; + } +}; +function prepend(element2, tail) { + return new NonEmpty(element2, tail); +} +function toList(elements, tail) { + return List.fromArray(elements, tail); +} +var ListIterator = class { + #current; + constructor(current) { + this.#current = current; + } + next() { + if (this.#current instanceof Empty) { + return { done: true }; + } else { + let { head, tail } = this.#current; + this.#current = tail; + return { value: head, done: false }; + } + } +}; +var Empty = class extends List { +}; +var NonEmpty = class extends List { + constructor(head, tail) { + super(); + this.head = head; + this.tail = tail; + } +}; +var BitArray = class _BitArray { + constructor(buffer) { + if (!(buffer instanceof Uint8Array)) { + throw "BitArray can only be constructed from a Uint8Array"; + } + this.buffer = buffer; + } + // @internal + get length() { + return this.buffer.length; + } + // @internal + byteAt(index2) { + return this.buffer[index2]; + } + // @internal + floatAt(index2) { + return byteArrayToFloat(this.buffer.slice(index2, index2 + 8)); + } + // @internal + intFromSlice(start4, end) { + return byteArrayToInt(this.buffer.slice(start4, end)); + } + // @internal + binaryFromSlice(start4, end) { + return new _BitArray(this.buffer.slice(start4, end)); + } + // @internal + sliceAfter(index2) { + return new _BitArray(this.buffer.slice(index2)); + } +}; +function byteArrayToInt(byteArray) { + byteArray = byteArray.reverse(); + let value3 = 0; + for (let i = byteArray.length - 1; i >= 0; i--) { + value3 = value3 * 256 + byteArray[i]; + } + return value3; +} +function byteArrayToFloat(byteArray) { + return new Float64Array(byteArray.reverse().buffer)[0]; +} +var Result = class _Result extends CustomType { + // @internal + static isResult(data) { + return data instanceof _Result; + } +}; +var Ok = class extends Result { + constructor(value3) { + super(); + this[0] = value3; + } + // @internal + isOk() { + return true; + } +}; +var Error = class extends Result { + constructor(detail) { + super(); + this[0] = detail; + } + // @internal + isOk() { + return false; + } +}; +function isEqual(x, y) { + let values = [x, y]; + while (values.length) { + let a2 = values.pop(); + let b = values.pop(); + if (a2 === b) + continue; + if (!isObject(a2) || !isObject(b)) + return false; + let unequal = !structurallyCompatibleObjects(a2, b) || unequalDates(a2, b) || unequalBuffers(a2, b) || unequalArrays(a2, b) || unequalMaps(a2, b) || unequalSets(a2, b) || unequalRegExps(a2, b); + if (unequal) + return false; + const proto = Object.getPrototypeOf(a2); + if (proto !== null && typeof proto.equals === "function") { + try { + if (a2.equals(b)) + continue; + else + return false; + } catch { + } + } + let [keys2, get2] = getters(a2); + for (let k of keys2(a2)) { + values.push(get2(a2, k), get2(b, k)); + } + } + return true; +} +function getters(object3) { + if (object3 instanceof Map) { + return [(x) => x.keys(), (x, y) => x.get(y)]; + } else { + let extra = object3 instanceof globalThis.Error ? ["message"] : []; + return [(x) => [...extra, ...Object.keys(x)], (x, y) => x[y]]; + } +} +function unequalDates(a2, b) { + return a2 instanceof Date && (a2 > b || a2 < b); +} +function unequalBuffers(a2, b) { + return a2.buffer instanceof ArrayBuffer && a2.BYTES_PER_ELEMENT && !(a2.byteLength === b.byteLength && a2.every((n, i) => n === b[i])); +} +function unequalArrays(a2, b) { + return Array.isArray(a2) && a2.length !== b.length; +} +function unequalMaps(a2, b) { + return a2 instanceof Map && a2.size !== b.size; +} +function unequalSets(a2, b) { + return a2 instanceof Set && (a2.size != b.size || [...a2].some((e) => !b.has(e))); +} +function unequalRegExps(a2, b) { + return a2 instanceof RegExp && (a2.source !== b.source || a2.flags !== b.flags); +} +function isObject(a2) { + return typeof a2 === "object" && a2 !== null; +} +function structurallyCompatibleObjects(a2, b) { + if (typeof a2 !== "object" && typeof b !== "object" && (!a2 || !b)) + return false; + let nonstructural = [Promise, WeakSet, WeakMap, Function]; + if (nonstructural.some((c) => a2 instanceof c)) + return false; + return a2.constructor === b.constructor; +} +function makeError(variant, module, line, fn, message, extra) { + let error = new globalThis.Error(message); + error.gleam_error = variant; + error.module = module; + error.line = line; + error.fn = fn; + for (let k in extra) + error[k] = extra[k]; + return error; +} + +// build/dev/javascript/gleam_stdlib/gleam/option.mjs +var Some = class extends CustomType { + constructor(x0) { + super(); + this[0] = x0; + } +}; +var None = class extends CustomType { +}; +function to_result(option, e) { + if (option instanceof Some) { + let a2 = option[0]; + return new Ok(a2); + } else { + return new Error(e); + } +} + +// build/dev/javascript/gleam_stdlib/dict.mjs +var referenceMap = /* @__PURE__ */ new WeakMap(); +var tempDataView = new DataView(new ArrayBuffer(8)); +var referenceUID = 0; +function hashByReference(o) { + const known = referenceMap.get(o); + if (known !== void 0) { + return known; + } + const hash = referenceUID++; + if (referenceUID === 2147483647) { + referenceUID = 0; + } + referenceMap.set(o, hash); + return hash; +} +function hashMerge(a2, b) { + return a2 ^ b + 2654435769 + (a2 << 6) + (a2 >> 2) | 0; +} +function hashString(s) { + let hash = 0; + const len = s.length; + for (let i = 0; i < len; i++) { + hash = Math.imul(31, hash) + s.charCodeAt(i) | 0; + } + return hash; +} +function hashNumber(n) { + tempDataView.setFloat64(0, n); + const i = tempDataView.getInt32(0); + const j = tempDataView.getInt32(4); + return Math.imul(73244475, i >> 16 ^ i) ^ j; +} +function hashBigInt(n) { + return hashString(n.toString()); +} +function hashObject(o) { + const proto = Object.getPrototypeOf(o); + if (proto !== null && typeof proto.hashCode === "function") { + try { + const code = o.hashCode(o); + if (typeof code === "number") { + return code; + } + } catch { + } + } + if (o instanceof Promise || o instanceof WeakSet || o instanceof WeakMap) { + return hashByReference(o); + } + if (o instanceof Date) { + return hashNumber(o.getTime()); + } + let h = 0; + if (o instanceof ArrayBuffer) { + o = new Uint8Array(o); + } + if (Array.isArray(o) || o instanceof Uint8Array) { + for (let i = 0; i < o.length; i++) { + h = Math.imul(31, h) + getHash(o[i]) | 0; + } + } else if (o instanceof Set) { + o.forEach((v) => { + h = h + getHash(v) | 0; + }); + } else if (o instanceof Map) { + o.forEach((v, k) => { + h = h + hashMerge(getHash(v), getHash(k)) | 0; + }); + } else { + const keys2 = Object.keys(o); + for (let i = 0; i < keys2.length; i++) { + const k = keys2[i]; + const v = o[k]; + h = h + hashMerge(getHash(v), hashString(k)) | 0; + } + } + return h; +} +function getHash(u) { + if (u === null) + return 1108378658; + if (u === void 0) + return 1108378659; + if (u === true) + return 1108378657; + if (u === false) + return 1108378656; + switch (typeof u) { + case "number": + return hashNumber(u); + case "string": + return hashString(u); + case "bigint": + return hashBigInt(u); + case "object": + return hashObject(u); + case "symbol": + return hashByReference(u); + case "function": + return hashByReference(u); + default: + return 0; + } +} +var SHIFT = 5; +var BUCKET_SIZE = Math.pow(2, SHIFT); +var MASK = BUCKET_SIZE - 1; +var MAX_INDEX_NODE = BUCKET_SIZE / 2; +var MIN_ARRAY_NODE = BUCKET_SIZE / 4; +var ENTRY = 0; +var ARRAY_NODE = 1; +var INDEX_NODE = 2; +var COLLISION_NODE = 3; +var EMPTY = { + type: INDEX_NODE, + bitmap: 0, + array: [] +}; +function mask(hash, shift) { + return hash >>> shift & MASK; +} +function bitpos(hash, shift) { + return 1 << mask(hash, shift); +} +function bitcount(x) { + x -= x >> 1 & 1431655765; + x = (x & 858993459) + (x >> 2 & 858993459); + x = x + (x >> 4) & 252645135; + x += x >> 8; + x += x >> 16; + return x & 127; +} +function index(bitmap, bit) { + return bitcount(bitmap & bit - 1); +} +function cloneAndSet(arr, at, val) { + const len = arr.length; + const out = new Array(len); + for (let i = 0; i < len; ++i) { + out[i] = arr[i]; + } + out[at] = val; + return out; +} +function spliceIn(arr, at, val) { + const len = arr.length; + const out = new Array(len + 1); + let i = 0; + let g = 0; + while (i < at) { + out[g++] = arr[i++]; + } + out[g++] = val; + while (i < len) { + out[g++] = arr[i++]; + } + return out; +} +function spliceOut(arr, at) { + const len = arr.length; + const out = new Array(len - 1); + let i = 0; + let g = 0; + while (i < at) { + out[g++] = arr[i++]; + } + ++i; + while (i < len) { + out[g++] = arr[i++]; + } + return out; +} +function createNode(shift, key1, val1, key2hash, key2, val2) { + const key1hash = getHash(key1); + if (key1hash === key2hash) { + return { + type: COLLISION_NODE, + hash: key1hash, + array: [ + { type: ENTRY, k: key1, v: val1 }, + { type: ENTRY, k: key2, v: val2 } + ] + }; + } + const addedLeaf = { val: false }; + return assoc( + assocIndex(EMPTY, shift, key1hash, key1, val1, addedLeaf), + shift, + key2hash, + key2, + val2, + addedLeaf + ); +} +function assoc(root2, shift, hash, key, val, addedLeaf) { + switch (root2.type) { + case ARRAY_NODE: + return assocArray(root2, shift, hash, key, val, addedLeaf); + case INDEX_NODE: + return assocIndex(root2, shift, hash, key, val, addedLeaf); + case COLLISION_NODE: + return assocCollision(root2, shift, hash, key, val, addedLeaf); + } +} +function assocArray(root2, shift, hash, key, val, addedLeaf) { + const idx = mask(hash, shift); + const node = root2.array[idx]; + if (node === void 0) { + addedLeaf.val = true; + return { + type: ARRAY_NODE, + size: root2.size + 1, + array: cloneAndSet(root2.array, idx, { type: ENTRY, k: key, v: val }) + }; + } + if (node.type === ENTRY) { + if (isEqual(key, node.k)) { + if (val === node.v) { + return root2; + } + return { + type: ARRAY_NODE, + size: root2.size, + array: cloneAndSet(root2.array, idx, { + type: ENTRY, + k: key, + v: val + }) + }; + } + addedLeaf.val = true; + return { + type: ARRAY_NODE, + size: root2.size, + array: cloneAndSet( + root2.array, + idx, + createNode(shift + SHIFT, node.k, node.v, hash, key, val) + ) + }; + } + const n = assoc(node, shift + SHIFT, hash, key, val, addedLeaf); + if (n === node) { + return root2; + } + return { + type: ARRAY_NODE, + size: root2.size, + array: cloneAndSet(root2.array, idx, n) + }; +} +function assocIndex(root2, shift, hash, key, val, addedLeaf) { + const bit = bitpos(hash, shift); + const idx = index(root2.bitmap, bit); + if ((root2.bitmap & bit) !== 0) { + const node = root2.array[idx]; + if (node.type !== ENTRY) { + const n = assoc(node, shift + SHIFT, hash, key, val, addedLeaf); + if (n === node) { + return root2; + } + return { + type: INDEX_NODE, + bitmap: root2.bitmap, + array: cloneAndSet(root2.array, idx, n) + }; + } + const nodeKey = node.k; + if (isEqual(key, nodeKey)) { + if (val === node.v) { + return root2; + } + return { + type: INDEX_NODE, + bitmap: root2.bitmap, + array: cloneAndSet(root2.array, idx, { + type: ENTRY, + k: key, + v: val + }) + }; + } + addedLeaf.val = true; + return { + type: INDEX_NODE, + bitmap: root2.bitmap, + array: cloneAndSet( + root2.array, + idx, + createNode(shift + SHIFT, nodeKey, node.v, hash, key, val) + ) + }; + } else { + const n = root2.array.length; + if (n >= MAX_INDEX_NODE) { + const nodes = new Array(32); + const jdx = mask(hash, shift); + nodes[jdx] = assocIndex(EMPTY, shift + SHIFT, hash, key, val, addedLeaf); + let j = 0; + let bitmap = root2.bitmap; + for (let i = 0; i < 32; i++) { + if ((bitmap & 1) !== 0) { + const node = root2.array[j++]; + nodes[i] = node; + } + bitmap = bitmap >>> 1; + } + return { + type: ARRAY_NODE, + size: n + 1, + array: nodes + }; + } else { + const newArray = spliceIn(root2.array, idx, { + type: ENTRY, + k: key, + v: val + }); + addedLeaf.val = true; + return { + type: INDEX_NODE, + bitmap: root2.bitmap | bit, + array: newArray + }; + } + } +} +function assocCollision(root2, shift, hash, key, val, addedLeaf) { + if (hash === root2.hash) { + const idx = collisionIndexOf(root2, key); + if (idx !== -1) { + const entry = root2.array[idx]; + if (entry.v === val) { + return root2; + } + return { + type: COLLISION_NODE, + hash, + array: cloneAndSet(root2.array, idx, { type: ENTRY, k: key, v: val }) + }; + } + const size = root2.array.length; + addedLeaf.val = true; + return { + type: COLLISION_NODE, + hash, + array: cloneAndSet(root2.array, size, { type: ENTRY, k: key, v: val }) + }; + } + return assoc( + { + type: INDEX_NODE, + bitmap: bitpos(root2.hash, shift), + array: [root2] + }, + shift, + hash, + key, + val, + addedLeaf + ); +} +function collisionIndexOf(root2, key) { + const size = root2.array.length; + for (let i = 0; i < size; i++) { + if (isEqual(key, root2.array[i].k)) { + return i; + } + } + return -1; +} +function find(root2, shift, hash, key) { + switch (root2.type) { + case ARRAY_NODE: + return findArray(root2, shift, hash, key); + case INDEX_NODE: + return findIndex(root2, shift, hash, key); + case COLLISION_NODE: + return findCollision(root2, key); + } +} +function findArray(root2, shift, hash, key) { + const idx = mask(hash, shift); + const node = root2.array[idx]; + if (node === void 0) { + return void 0; + } + if (node.type !== ENTRY) { + return find(node, shift + SHIFT, hash, key); + } + if (isEqual(key, node.k)) { + return node; + } + return void 0; +} +function findIndex(root2, shift, hash, key) { + const bit = bitpos(hash, shift); + if ((root2.bitmap & bit) === 0) { + return void 0; + } + const idx = index(root2.bitmap, bit); + const node = root2.array[idx]; + if (node.type !== ENTRY) { + return find(node, shift + SHIFT, hash, key); + } + if (isEqual(key, node.k)) { + return node; + } + return void 0; +} +function findCollision(root2, key) { + const idx = collisionIndexOf(root2, key); + if (idx < 0) { + return void 0; + } + return root2.array[idx]; +} +function without(root2, shift, hash, key) { + switch (root2.type) { + case ARRAY_NODE: + return withoutArray(root2, shift, hash, key); + case INDEX_NODE: + return withoutIndex(root2, shift, hash, key); + case COLLISION_NODE: + return withoutCollision(root2, key); + } +} +function withoutArray(root2, shift, hash, key) { + const idx = mask(hash, shift); + const node = root2.array[idx]; + if (node === void 0) { + return root2; + } + let n = void 0; + if (node.type === ENTRY) { + if (!isEqual(node.k, key)) { + return root2; + } + } else { + n = without(node, shift + SHIFT, hash, key); + if (n === node) { + return root2; + } + } + if (n === void 0) { + if (root2.size <= MIN_ARRAY_NODE) { + const arr = root2.array; + const out = new Array(root2.size - 1); + let i = 0; + let j = 0; + let bitmap = 0; + while (i < idx) { + const nv = arr[i]; + if (nv !== void 0) { + out[j] = nv; + bitmap |= 1 << i; + ++j; + } + ++i; + } + ++i; + while (i < arr.length) { + const nv = arr[i]; + if (nv !== void 0) { + out[j] = nv; + bitmap |= 1 << i; + ++j; + } + ++i; + } + return { + type: INDEX_NODE, + bitmap, + array: out + }; + } + return { + type: ARRAY_NODE, + size: root2.size - 1, + array: cloneAndSet(root2.array, idx, n) + }; + } + return { + type: ARRAY_NODE, + size: root2.size, + array: cloneAndSet(root2.array, idx, n) + }; +} +function withoutIndex(root2, shift, hash, key) { + const bit = bitpos(hash, shift); + if ((root2.bitmap & bit) === 0) { + return root2; + } + const idx = index(root2.bitmap, bit); + const node = root2.array[idx]; + if (node.type !== ENTRY) { + const n = without(node, shift + SHIFT, hash, key); + if (n === node) { + return root2; + } + if (n !== void 0) { + return { + type: INDEX_NODE, + bitmap: root2.bitmap, + array: cloneAndSet(root2.array, idx, n) + }; + } + if (root2.bitmap === bit) { + return void 0; + } + return { + type: INDEX_NODE, + bitmap: root2.bitmap ^ bit, + array: spliceOut(root2.array, idx) + }; + } + if (isEqual(key, node.k)) { + if (root2.bitmap === bit) { + return void 0; + } + return { + type: INDEX_NODE, + bitmap: root2.bitmap ^ bit, + array: spliceOut(root2.array, idx) + }; + } + return root2; +} +function withoutCollision(root2, key) { + const idx = collisionIndexOf(root2, key); + if (idx < 0) { + return root2; + } + if (root2.array.length === 1) { + return void 0; + } + return { + type: COLLISION_NODE, + hash: root2.hash, + array: spliceOut(root2.array, idx) + }; +} +function forEach(root2, fn) { + if (root2 === void 0) { + return; + } + const items = root2.array; + const size = items.length; + for (let i = 0; i < size; i++) { + const item = items[i]; + if (item === void 0) { + continue; + } + if (item.type === ENTRY) { + fn(item.v, item.k); + continue; + } + forEach(item, fn); + } +} +var Dict = class _Dict { + /** + * @template V + * @param {Record<string,V>} o + * @returns {Dict<string,V>} + */ + static fromObject(o) { + const keys2 = Object.keys(o); + let m = _Dict.new(); + for (let i = 0; i < keys2.length; i++) { + const k = keys2[i]; + m = m.set(k, o[k]); + } + return m; + } + /** + * @template K,V + * @param {Map<K,V>} o + * @returns {Dict<K,V>} + */ + static fromMap(o) { + let m = _Dict.new(); + o.forEach((v, k) => { + m = m.set(k, v); + }); + return m; + } + static new() { + return new _Dict(void 0, 0); + } + /** + * @param {undefined | Node<K,V>} root + * @param {number} size + */ + constructor(root2, size) { + this.root = root2; + this.size = size; + } + /** + * @template NotFound + * @param {K} key + * @param {NotFound} notFound + * @returns {NotFound | V} + */ + get(key, notFound) { + if (this.root === void 0) { + return notFound; + } + const found = find(this.root, 0, getHash(key), key); + if (found === void 0) { + return notFound; + } + return found.v; + } + /** + * @param {K} key + * @param {V} val + * @returns {Dict<K,V>} + */ + set(key, val) { + const addedLeaf = { val: false }; + const root2 = this.root === void 0 ? EMPTY : this.root; + const newRoot = assoc(root2, 0, getHash(key), key, val, addedLeaf); + if (newRoot === this.root) { + return this; + } + return new _Dict(newRoot, addedLeaf.val ? this.size + 1 : this.size); + } + /** + * @param {K} key + * @returns {Dict<K,V>} + */ + delete(key) { + if (this.root === void 0) { + return this; + } + const newRoot = without(this.root, 0, getHash(key), key); + if (newRoot === this.root) { + return this; + } + if (newRoot === void 0) { + return _Dict.new(); + } + return new _Dict(newRoot, this.size - 1); + } + /** + * @param {K} key + * @returns {boolean} + */ + has(key) { + if (this.root === void 0) { + return false; + } + return find(this.root, 0, getHash(key), key) !== void 0; + } + /** + * @returns {[K,V][]} + */ + entries() { + if (this.root === void 0) { + return []; + } + const result = []; + this.forEach((v, k) => result.push([k, v])); + return result; + } + /** + * + * @param {(val:V,key:K)=>void} fn + */ + forEach(fn) { + forEach(this.root, fn); + } + hashCode() { + let h = 0; + this.forEach((v, k) => { + h = h + hashMerge(getHash(v), getHash(k)) | 0; + }); + return h; + } + /** + * @param {unknown} o + * @returns {boolean} + */ + equals(o) { + if (!(o instanceof _Dict) || this.size !== o.size) { + return false; + } + let equal2 = true; + this.forEach((v, k) => { + equal2 = equal2 && isEqual(o.get(k, !v), v); + }); + return equal2; + } +}; + +// build/dev/javascript/gleam_stdlib/gleam_stdlib.mjs +var Nil = void 0; +var NOT_FOUND = {}; +function identity(x) { + return x; +} +function to_string(term) { + return term.toString(); +} +function string_replace(string3, target, substitute) { + if (typeof string3.replaceAll !== "undefined") { + return string3.replaceAll(target, substitute); + } + return string3.replace( + // $& means the whole matched string + new RegExp(target.replace(/[.*+?^${}()|[\]\\]/g, "\\$&"), "g"), + substitute + ); +} +function graphemes(string3) { + const iterator = graphemes_iterator(string3); + if (iterator) { + return List.fromArray(Array.from(iterator).map((item) => item.segment)); + } else { + return List.fromArray(string3.match(/./gsu)); + } +} +function graphemes_iterator(string3) { + if (Intl && Intl.Segmenter) { + return new Intl.Segmenter().segment(string3)[Symbol.iterator](); + } +} +function lowercase(string3) { + return string3.toLowerCase(); +} +function split(xs, pattern) { + return List.fromArray(xs.split(pattern)); +} +function concat(xs) { + let result = ""; + for (const x of xs) { + result = result + x; + } + return result; +} +function map_get(map5, key) { + const value3 = map5.get(key, NOT_FOUND); + if (value3 === NOT_FOUND) { + return new Error(Nil); + } + return new Ok(value3); +} +function classify_dynamic(data) { + if (typeof data === "string") { + return "String"; + } else if (data instanceof Result) { + return "Result"; + } else if (data instanceof List) { + return "List"; + } else if (data instanceof BitArray) { + return "BitArray"; + } else if (data instanceof Dict) { + return "Dict"; + } else if (Number.isInteger(data)) { + return "Int"; + } else if (Array.isArray(data)) { + return `Tuple of ${data.length} elements`; + } else if (typeof data === "number") { + return "Float"; + } else if (data === null) { + return "Null"; + } else if (data === void 0) { + return "Nil"; + } else { + const type = typeof data; + return type.charAt(0).toUpperCase() + type.slice(1); + } +} +function decoder_error(expected, got) { + return decoder_error_no_classify(expected, classify_dynamic(got)); +} +function decoder_error_no_classify(expected, got) { + return new Error( + List.fromArray([new DecodeError(expected, got, List.fromArray([]))]) + ); +} +function decode_string(data) { + return typeof data === "string" ? new Ok(data) : decoder_error("String", data); +} +function decode_int(data) { + return Number.isInteger(data) ? new Ok(data) : decoder_error("Int", data); +} +function decode_field(value3, name) { + const not_a_map_error = () => decoder_error("Dict", value3); + if (value3 instanceof Dict || value3 instanceof WeakMap || value3 instanceof Map) { + const entry = map_get(value3, name); + return new Ok(entry.isOk() ? new Some(entry[0]) : new None()); + } else if (value3 === null) { + return not_a_map_error(); + } else if (Object.getPrototypeOf(value3) == Object.prototype) { + return try_get_field(value3, name, () => new Ok(new None())); + } else { + return try_get_field(value3, name, not_a_map_error); + } +} +function try_get_field(value3, field3, or_else) { + try { + return field3 in value3 ? new Ok(new Some(value3[field3])) : or_else(); + } catch { + return or_else(); + } +} + +// build/dev/javascript/gleam_stdlib/gleam/int.mjs +function to_string2(x) { + return to_string(x); +} + +// build/dev/javascript/gleam_stdlib/gleam/list.mjs +function do_reverse_acc(loop$remaining, loop$accumulator) { + while (true) { + let remaining = loop$remaining; + let accumulator = loop$accumulator; + if (remaining.hasLength(0)) { + return accumulator; + } else { + let item = remaining.head; + let rest$1 = remaining.tail; + loop$remaining = rest$1; + loop$accumulator = prepend(item, accumulator); + } + } +} +function do_reverse(list) { + return do_reverse_acc(list, toList([])); +} +function reverse(xs) { + return do_reverse(xs); +} +function do_map(loop$list, loop$fun, loop$acc) { + while (true) { + let list = loop$list; + let fun = loop$fun; + let acc = loop$acc; + if (list.hasLength(0)) { + return reverse(acc); + } else { + let x = list.head; + let xs = list.tail; + loop$list = xs; + loop$fun = fun; + loop$acc = prepend(fun(x), acc); + } + } +} +function map(list, fun) { + return do_map(list, fun, toList([])); +} +function do_append_acc(loop$first, loop$second) { + while (true) { + let first2 = loop$first; + let second2 = loop$second; + if (first2.hasLength(0)) { + return second2; + } else { + let item = first2.head; + let rest$1 = first2.tail; + loop$first = rest$1; + loop$second = prepend(item, second2); + } + } +} +function do_append(first2, second2) { + return do_append_acc(reverse(first2), second2); +} +function append(first2, second2) { + return do_append(first2, second2); +} +function fold(loop$list, loop$initial, loop$fun) { + while (true) { + let list = loop$list; + let initial = loop$initial; + let fun = loop$fun; + if (list.hasLength(0)) { + return initial; + } else { + let x = list.head; + let rest$1 = list.tail; + loop$list = rest$1; + loop$initial = fun(initial, x); + loop$fun = fun; + } + } +} +function find2(loop$haystack, loop$is_desired) { + while (true) { + let haystack = loop$haystack; + let is_desired = loop$is_desired; + if (haystack.hasLength(0)) { + return new Error(void 0); + } else { + let x = haystack.head; + let rest$1 = haystack.tail; + let $ = is_desired(x); + if ($) { + return new Ok(x); + } else { + loop$haystack = rest$1; + loop$is_desired = is_desired; + } + } + } +} + +// build/dev/javascript/gleam_stdlib/gleam/result.mjs +function map2(result, fun) { + if (result.isOk()) { + let x = result[0]; + return new Ok(fun(x)); + } else { + let e = result[0]; + return new Error(e); + } +} +function map_error(result, fun) { + if (result.isOk()) { + let x = result[0]; + return new Ok(x); + } else { + let error = result[0]; + return new Error(fun(error)); + } +} +function try$(result, fun) { + if (result.isOk()) { + let x = result[0]; + return fun(x); + } else { + let e = result[0]; + return new Error(e); + } +} + +// build/dev/javascript/gleam_stdlib/gleam/string_builder.mjs +function from_strings(strings) { + return concat(strings); +} +function from_string(string3) { + return identity(string3); +} +function to_string3(builder) { + return identity(builder); +} +function split2(iodata, pattern) { + return split(iodata, pattern); +} +function replace(builder, pattern, substitute) { + return string_replace(builder, pattern, substitute); +} + +// build/dev/javascript/gleam_stdlib/gleam/dynamic.mjs +var DecodeError = class extends CustomType { + constructor(expected, found, path) { + super(); + this.expected = expected; + this.found = found; + this.path = path; + } +}; +function from(a2) { + return identity(a2); +} +function string(data) { + return decode_string(data); +} +function classify(data) { + return classify_dynamic(data); +} +function int(data) { + return decode_int(data); +} +function any(decoders) { + return (data) => { + if (decoders.hasLength(0)) { + return new Error( + toList([new DecodeError("another type", classify(data), toList([]))]) + ); + } else { + let decoder2 = decoders.head; + let decoders$1 = decoders.tail; + let $ = decoder2(data); + if ($.isOk()) { + let decoded = $[0]; + return new Ok(decoded); + } else { + return any(decoders$1)(data); + } + } + }; +} +function push_path(error, name) { + let name$1 = from(name); + let decoder2 = any( + toList([string, (x) => { + return map2(int(x), to_string2); + }]) + ); + let name$2 = (() => { + let $ = decoder2(name$1); + if ($.isOk()) { + let name$22 = $[0]; + return name$22; + } else { + let _pipe = toList(["<", classify(name$1), ">"]); + let _pipe$1 = from_strings(_pipe); + return to_string3(_pipe$1); + } + })(); + return error.withFields({ path: prepend(name$2, error.path) }); +} +function map_errors(result, f) { + return map_error( + result, + (_capture) => { + return map(_capture, f); + } + ); +} +function field(name, inner_type) { + return (value3) => { + let missing_field_error = new DecodeError("field", "nothing", toList([])); + return try$( + decode_field(value3, name), + (maybe_inner) => { + let _pipe = maybe_inner; + let _pipe$1 = to_result(_pipe, toList([missing_field_error])); + let _pipe$2 = try$(_pipe$1, inner_type); + return map_errors( + _pipe$2, + (_capture) => { + return push_path(_capture, name); + } + ); + } + ); + }; +} + +// build/dev/javascript/gleam_stdlib/gleam/string.mjs +function replace2(string3, pattern, substitute) { + let _pipe = string3; + let _pipe$1 = from_string(_pipe); + let _pipe$2 = replace(_pipe$1, pattern, substitute); + return to_string3(_pipe$2); +} +function lowercase2(string3) { + return lowercase(string3); +} +function split3(x, substring) { + if (substring === "") { + return graphemes(x); + } else { + let _pipe = x; + let _pipe$1 = from_string(_pipe); + let _pipe$2 = split2(_pipe$1, substring); + return map(_pipe$2, to_string3); + } +} + +// build/dev/javascript/gleam_stdlib/gleam/uri.mjs +var Uri = class extends CustomType { + constructor(scheme, userinfo, host, port, path, query, fragment) { + super(); + this.scheme = scheme; + this.userinfo = userinfo; + this.host = host; + this.port = port; + this.path = path; + this.query = query; + this.fragment = fragment; + } +}; +function do_remove_dot_segments(loop$input, loop$accumulator) { + while (true) { + let input4 = loop$input; + let accumulator = loop$accumulator; + if (input4.hasLength(0)) { + return reverse(accumulator); + } else { + let segment = input4.head; + let rest = input4.tail; + let accumulator$1 = (() => { + if (segment === "") { + let accumulator$12 = accumulator; + return accumulator$12; + } else if (segment === ".") { + let accumulator$12 = accumulator; + return accumulator$12; + } else if (segment === ".." && accumulator.hasLength(0)) { + return toList([]); + } else if (segment === ".." && accumulator.atLeastLength(1)) { + let accumulator$12 = accumulator.tail; + return accumulator$12; + } else { + let segment$1 = segment; + let accumulator$12 = accumulator; + return prepend(segment$1, accumulator$12); + } + })(); + loop$input = rest; + loop$accumulator = accumulator$1; + } + } +} +function remove_dot_segments(input4) { + return do_remove_dot_segments(input4, toList([])); +} +function path_segments(path) { + return remove_dot_segments(split3(path, "/")); +} + +// build/dev/javascript/gleam_stdlib/gleam/bool.mjs +function guard(requirement, consequence, alternative) { + if (requirement) { + return consequence; + } else { + return alternative(); + } +} + +// build/dev/javascript/lustre/lustre/effect.mjs +var Effect = class extends CustomType { + constructor(all) { + super(); + this.all = all; + } +}; +function from2(effect) { + return new Effect(toList([(dispatch, _) => { + return effect(dispatch); + }])); +} +function none() { + return new Effect(toList([])); +} + +// build/dev/javascript/lustre/lustre/internals/vdom.mjs +var Text = class extends CustomType { + constructor(content) { + super(); + this.content = content; + } +}; +var Element = class extends CustomType { + constructor(key, namespace, tag2, attrs, children, self_closing, void$) { + super(); + this.key = key; + this.namespace = namespace; + this.tag = tag2; + this.attrs = attrs; + this.children = children; + this.self_closing = self_closing; + this.void = void$; + } +}; +var Attribute = class extends CustomType { + constructor(x0, x1, as_property) { + super(); + this[0] = x0; + this[1] = x1; + this.as_property = as_property; + } +}; +var Event = class extends CustomType { + constructor(x0, x1) { + super(); + this[0] = x0; + this[1] = x1; + } +}; + +// build/dev/javascript/lustre/lustre/attribute.mjs +function attribute(name, value3) { + return new Attribute(name, from(value3), false); +} +function property(name, value3) { + return new Attribute(name, from(value3), true); +} +function on(name, handler) { + return new Event("on" + name, handler); +} +function style(properties) { + return attribute( + "style", + fold( + properties, + "", + (styles, _use1) => { + let name$1 = _use1[0]; + let value$1 = _use1[1]; + return styles + name$1 + ":" + value$1 + ";"; + } + ) + ); +} +function class$(name) { + return attribute("class", name); +} +function value(val) { + return property("value", from(val)); +} +function href(uri) { + return attribute("href", uri); +} + +// build/dev/javascript/lustre/lustre/element.mjs +function element(tag2, attrs, children) { + if (tag2 === "area") { + return new Element("", "", tag2, attrs, toList([]), false, true); + } else if (tag2 === "base") { + return new Element("", "", tag2, attrs, toList([]), false, true); + } else if (tag2 === "br") { + return new Element("", "", tag2, attrs, toList([]), false, true); + } else if (tag2 === "col") { + return new Element("", "", tag2, attrs, toList([]), false, true); + } else if (tag2 === "embed") { + return new Element("", "", tag2, attrs, toList([]), false, true); + } else if (tag2 === "hr") { + return new Element("", "", tag2, attrs, toList([]), false, true); + } else if (tag2 === "img") { + return new Element("", "", tag2, attrs, toList([]), false, true); + } else if (tag2 === "input") { + return new Element("", "", tag2, attrs, toList([]), false, true); + } else if (tag2 === "link") { + return new Element("", "", tag2, attrs, toList([]), false, true); + } else if (tag2 === "meta") { + return new Element("", "", tag2, attrs, toList([]), false, true); + } else if (tag2 === "param") { + return new Element("", "", tag2, attrs, toList([]), false, true); + } else if (tag2 === "source") { + return new Element("", "", tag2, attrs, toList([]), false, true); + } else if (tag2 === "track") { + return new Element("", "", tag2, attrs, toList([]), false, true); + } else if (tag2 === "wbr") { + return new Element("", "", tag2, attrs, toList([]), false, true); + } else { + return new Element("", "", tag2, attrs, children, false, false); + } +} +function text(content) { + return new Text(content); +} + +// build/dev/javascript/lustre/lustre/internals/runtime.mjs +var Dispatch = class extends CustomType { + constructor(x0) { + super(); + this[0] = x0; + } +}; +var Shutdown = class extends CustomType { +}; + +// build/dev/javascript/lustre/vdom.ffi.mjs +function morph(prev, next, dispatch, isComponent = false) { + let out; + let stack3 = [{ prev, next, parent: prev.parentNode }]; + while (stack3.length) { + let { prev: prev2, next: next2, parent } = stack3.pop(); + if (next2.subtree !== void 0) + next2 = next2.subtree(); + if (next2.content !== void 0) { + if (!prev2) { + const created = document.createTextNode(next2.content); + parent.appendChild(created); + out ??= created; + } else if (prev2.nodeType === Node.TEXT_NODE) { + if (prev2.textContent !== next2.content) + prev2.textContent = next2.content; + out ??= prev2; + } else { + const created = document.createTextNode(next2.content); + parent.replaceChild(created, prev2); + out ??= created; + } + } else if (next2.tag !== void 0) { + const created = createElementNode({ + prev: prev2, + next: next2, + dispatch, + stack: stack3, + isComponent + }); + if (!prev2) { + parent.appendChild(created); + } else if (prev2 !== created) { + parent.replaceChild(created, prev2); + } + out ??= created; + } + } + return out; +} +function createElementNode({ prev, next, dispatch, stack: stack3 }) { + const namespace = next.namespace || "http://www.w3.org/1999/xhtml"; + const canMorph = prev && prev.nodeType === Node.ELEMENT_NODE && prev.localName === next.tag && prev.namespaceURI === (next.namespace || "http://www.w3.org/1999/xhtml"); + const el2 = canMorph ? prev : namespace ? document.createElementNS(namespace, next.tag) : document.createElement(next.tag); + let handlersForEl; + if (!registeredHandlers.has(el2)) { + const emptyHandlers = /* @__PURE__ */ new Map(); + registeredHandlers.set(el2, emptyHandlers); + handlersForEl = emptyHandlers; + } else { + handlersForEl = registeredHandlers.get(el2); + } + const prevHandlers = canMorph ? new Set(handlersForEl.keys()) : null; + const prevAttributes = canMorph ? new Set(Array.from(prev.attributes, (a2) => a2.name)) : null; + let className = null; + let style2 = null; + let innerHTML = null; + for (const attr of next.attrs) { + const name = attr[0]; + const value3 = attr[1]; + const isProperty = attr[2]; + if (isProperty) { + el2[name] = value3; + } else if (name.startsWith("on")) { + const eventName = name.slice(2); + const callback = dispatch(value3); + if (!handlersForEl.has(eventName)) { + el2.addEventListener(eventName, lustreGenericEventHandler); + } + handlersForEl.set(eventName, callback); + if (canMorph) + prevHandlers.delete(eventName); + } else if (name.startsWith("data-lustre-on-")) { + const eventName = name.slice(15); + const callback = dispatch(lustreServerEventHandler); + if (!handlersForEl.has(eventName)) { + el2.addEventListener(eventName, lustreGenericEventHandler); + } + handlersForEl.set(eventName, callback); + el2.setAttribute(name, value3); + } else if (name === "class") { + className = className === null ? value3 : className + " " + value3; + } else if (name === "style") { + style2 = style2 === null ? value3 : style2 + value3; + } else if (name === "dangerous-unescaped-html") { + innerHTML = value3; + } else { + el2.setAttribute(name, value3); + if (name === "value") + el2[name] = value3; + if (canMorph) + prevAttributes.delete(name); + } + } + if (className !== null) { + el2.setAttribute("class", className); + if (canMorph) + prevAttributes.delete("class"); + } + if (style2 !== null) { + el2.setAttribute("style", style2); + if (canMorph) + prevAttributes.delete("style"); + } + if (canMorph) { + for (const attr of prevAttributes) { + el2.removeAttribute(attr); + } + for (const eventName of prevHandlers) { + handlersForEl.delete(eventName); + el2.removeEventListener(eventName, lustreGenericEventHandler); + } + } + if (next.key !== void 0 && next.key !== "") { + el2.setAttribute("data-lustre-key", next.key); + } else if (innerHTML !== null) { + el2.innerHTML = innerHTML; + return el2; + } + let prevChild = el2.firstChild; + let seenKeys = null; + let keyedChildren = null; + let incomingKeyedChildren = null; + let firstChild = next.children[Symbol.iterator]().next().value; + if (canMorph && firstChild !== void 0 && // Explicit checks are more verbose but truthy checks force a bunch of comparisons + // we don't care about: it's never gonna be a number etc. + firstChild.key !== void 0 && firstChild.key !== "") { + seenKeys = /* @__PURE__ */ new Set(); + keyedChildren = getKeyedChildren(prev); + incomingKeyedChildren = getKeyedChildren(next); + } + for (const child of next.children) { + if (child.key !== void 0 && seenKeys !== null) { + while (prevChild && !incomingKeyedChildren.has(prevChild.getAttribute("data-lustre-key"))) { + const nextChild = prevChild.nextSibling; + el2.removeChild(prevChild); + prevChild = nextChild; + } + if (keyedChildren.size === 0) { + stack3.unshift({ prev: prevChild, next: child, parent: el2 }); + prevChild = prevChild?.nextSibling; + continue; + } + if (seenKeys.has(child.key)) { + console.warn(`Duplicate key found in Lustre vnode: ${child.key}`); + stack3.unshift({ prev: null, next: child, parent: el2 }); + continue; + } + seenKeys.add(child.key); + const keyedChild = keyedChildren.get(child.key); + if (!keyedChild && !prevChild) { + stack3.unshift({ prev: null, next: child, parent: el2 }); + continue; + } + if (!keyedChild && prevChild !== null) { + const placeholder = document.createTextNode(""); + el2.insertBefore(placeholder, prevChild); + stack3.unshift({ prev: placeholder, next: child, parent: el2 }); + continue; + } + if (!keyedChild || keyedChild === prevChild) { + stack3.unshift({ prev: prevChild, next: child, parent: el2 }); + prevChild = prevChild?.nextSibling; + continue; + } + el2.insertBefore(keyedChild, prevChild); + stack3.unshift({ prev: keyedChild, next: child, parent: el2 }); + } else { + stack3.unshift({ prev: prevChild, next: child, parent: el2 }); + prevChild = prevChild?.nextSibling; + } + } + while (prevChild) { + const next2 = prevChild.nextSibling; + el2.removeChild(prevChild); + prevChild = next2; + } + return el2; +} +var registeredHandlers = /* @__PURE__ */ new WeakMap(); +function lustreGenericEventHandler(event2) { + const target = event2.currentTarget; + if (!registeredHandlers.has(target)) { + target.removeEventListener(event2.type, lustreGenericEventHandler); + return; + } + const handlersForEventTarget = registeredHandlers.get(target); + if (!handlersForEventTarget.has(event2.type)) { + target.removeEventListener(event2.type, lustreGenericEventHandler); + return; + } + handlersForEventTarget.get(event2.type)(event2); +} +function lustreServerEventHandler(event2) { + const el2 = event2.target; + const tag2 = el2.getAttribute(`data-lustre-on-${event2.type}`); + const data = JSON.parse(el2.getAttribute("data-lustre-data") || "{}"); + const include = JSON.parse(el2.getAttribute("data-lustre-include") || "[]"); + switch (event2.type) { + case "input": + case "change": + include.push("target.value"); + break; + } + return { + tag: tag2, + data: include.reduce( + (data2, property2) => { + const path = property2.split("."); + for (let i = 0, o = data2, e = event2; i < path.length; i++) { + if (i === path.length - 1) { + o[path[i]] = e[path[i]]; + } else { + o[path[i]] ??= {}; + e = e[path[i]]; + o = o[path[i]]; + } + } + return data2; + }, + { data } + ) + }; +} +function getKeyedChildren(el2) { + const keyedChildren = /* @__PURE__ */ new Map(); + if (el2) { + for (const child of el2.children) { + const key = child.key || child?.getAttribute("data-lustre-key"); + if (key) + keyedChildren.set(key, child); + } + } + return keyedChildren; +} + +// build/dev/javascript/lustre/client-runtime.ffi.mjs +var LustreClientApplication2 = class _LustreClientApplication { + #root = null; + #queue = []; + #effects = []; + #didUpdate = false; + #isComponent = false; + #model = null; + #update = null; + #view = null; + static start(flags, selector, init4, update3, view2) { + if (!is_browser()) + return new Error(new NotABrowser()); + const root2 = selector instanceof HTMLElement ? selector : document.querySelector(selector); + if (!root2) + return new Error(new ElementNotFound(selector)); + const app = new _LustreClientApplication(init4(flags), update3, view2, root2); + return new Ok((msg) => app.send(msg)); + } + constructor([model, effects], update3, view2, root2 = document.body, isComponent = false) { + this.#model = model; + this.#update = update3; + this.#view = view2; + this.#root = root2; + this.#effects = effects.all.toArray(); + this.#didUpdate = true; + this.#isComponent = isComponent; + window.requestAnimationFrame(() => this.#tick()); + } + send(action) { + switch (true) { + case action instanceof Dispatch: { + this.#queue.push(action[0]); + this.#tick(); + return; + } + case action instanceof Shutdown: { + this.#shutdown(); + return; + } + default: + return; + } + } + emit(event2, data) { + this.#root.dispatchEvent( + new CustomEvent(event2, { + bubbles: true, + detail: data, + composed: true + }) + ); + } + #tick() { + this.#flush_queue(); + const vdom = this.#view(this.#model); + const dispatch = (handler) => (e) => { + const result = handler(e); + if (result instanceof Ok) { + this.send(new Dispatch(result[0])); + } + }; + this.#didUpdate = false; + this.#root = morph(this.#root, vdom, dispatch, this.#isComponent); + } + #flush_queue(iterations = 0) { + while (this.#queue.length) { + const [next, effects] = this.#update(this.#model, this.#queue.shift()); + this.#didUpdate ||= !isEqual(this.#model, next); + this.#model = next; + this.#effects = this.#effects.concat(effects.all.toArray()); + } + while (this.#effects.length) { + this.#effects.shift()( + (msg) => this.send(new Dispatch(msg)), + (event2, data) => this.emit(event2, data) + ); + } + if (this.#queue.length) { + if (iterations < 5) { + this.#flush_queue(++iterations); + } else { + window.requestAnimationFrame(() => this.#tick()); + } + } + } + #shutdown() { + this.#root.remove(); + this.#root = null; + this.#model = null; + this.#queue = []; + this.#effects = []; + this.#didUpdate = false; + this.#update = () => { + }; + this.#view = () => { + }; + } +}; +var start = (app, selector, flags) => LustreClientApplication2.start( + flags, + selector, + app.init, + app.update, + app.view +); +var is_browser = () => window && window.document; + +// build/dev/javascript/lustre/lustre.mjs +var App = class extends CustomType { + constructor(init4, update3, view2, on_attribute_change) { + super(); + this.init = init4; + this.update = update3; + this.view = view2; + this.on_attribute_change = on_attribute_change; + } +}; +var ElementNotFound = class extends CustomType { + constructor(selector) { + super(); + this.selector = selector; + } +}; +var NotABrowser = class extends CustomType { +}; +function application(init4, update3, view2) { + return new App(init4, update3, view2, new None()); +} +function start3(app, selector, flags) { + return guard( + !is_browser(), + new Error(new NotABrowser()), + () => { + return start(app, selector, flags); + } + ); +} + +// build/dev/javascript/lustre/lustre/element/html.mjs +function h1(attrs, children) { + return element("h1", attrs, children); +} +function nav(attrs, children) { + return element("nav", attrs, children); +} +function div(attrs, children) { + return element("div", attrs, children); +} +function p(attrs, children) { + return element("p", attrs, children); +} +function a(attrs, children) { + return element("a", attrs, children); +} +function input(attrs) { + return element("input", attrs, toList([])); +} + +// build/dev/javascript/lustre/lustre/event.mjs +function on2(name, handler) { + return on(name, handler); +} +function value2(event2) { + let _pipe = event2; + return field("target", field("value", string))( + _pipe + ); +} + +// build/dev/javascript/lustre_ui/lustre/ui/layout/stack.mjs +function of(element2, attributes, children) { + return element2( + prepend(class$("lustre-ui-stack"), attributes), + children + ); +} +function stack(attributes, children) { + return of(div, attributes, children); +} + +// build/dev/javascript/lustre_ui/lustre/ui/input.mjs +function input2(attributes) { + return input( + prepend(class$("lustre-ui-input"), attributes) + ); +} + +// build/dev/javascript/lustre_ui/lustre/ui/layout/centre.mjs +function of2(element2, attributes, children) { + return element2( + prepend(class$("lustre-ui-centre"), attributes), + toList([children]) + ); +} +function centre(attributes, children) { + return of2(div, attributes, children); +} + +// build/dev/javascript/lustre_ui/lustre/ui/layout/cluster.mjs +function of3(element2, attributes, children) { + return element2( + prepend(class$("lustre-ui-cluster"), attributes), + children + ); +} + +// build/dev/javascript/gleam_community_colour/gleam_community/colour.mjs +var Rgba = class extends CustomType { + constructor(r, g, b, a2) { + super(); + this.r = r; + this.g = g; + this.b = b; + this.a = a2; + } +}; +var light_red = new Rgba( + 0.9372549019607843, + 0.1607843137254902, + 0.1607843137254902, + 1 +); +var red = new Rgba(0.8, 0, 0, 1); +var dark_red = new Rgba(0.6431372549019608, 0, 0, 1); +var light_orange = new Rgba( + 0.9882352941176471, + 0.6862745098039216, + 0.24313725490196078, + 1 +); +var orange = new Rgba(0.9607843137254902, 0.4745098039215686, 0, 1); +var dark_orange = new Rgba( + 0.807843137254902, + 0.3607843137254902, + 0, + 1 +); +var light_yellow = new Rgba( + 1, + 0.9137254901960784, + 0.30980392156862746, + 1 +); +var yellow = new Rgba(0.9294117647058824, 0.8313725490196079, 0, 1); +var dark_yellow = new Rgba( + 0.7686274509803922, + 0.6274509803921569, + 0, + 1 +); +var light_green = new Rgba( + 0.5411764705882353, + 0.8862745098039215, + 0.20392156862745098, + 1 +); +var green = new Rgba( + 0.45098039215686275, + 0.8235294117647058, + 0.08627450980392157, + 1 +); +var dark_green = new Rgba( + 0.3058823529411765, + 0.6039215686274509, + 0.023529411764705882, + 1 +); +var light_blue = new Rgba( + 0.4470588235294118, + 0.6235294117647059, + 0.8117647058823529, + 1 +); +var blue = new Rgba( + 0.20392156862745098, + 0.396078431372549, + 0.6431372549019608, + 1 +); +var dark_blue = new Rgba( + 0.12549019607843137, + 0.2901960784313726, + 0.5294117647058824, + 1 +); +var light_purple = new Rgba( + 0.6784313725490196, + 0.4980392156862745, + 0.6588235294117647, + 1 +); +var purple = new Rgba( + 0.4588235294117647, + 0.3137254901960784, + 0.4823529411764706, + 1 +); +var dark_purple = new Rgba( + 0.3607843137254902, + 0.20784313725490197, + 0.4, + 1 +); +var light_brown = new Rgba( + 0.9137254901960784, + 0.7254901960784313, + 0.43137254901960786, + 1 +); +var brown = new Rgba( + 0.7568627450980392, + 0.49019607843137253, + 0.06666666666666667, + 1 +); +var dark_brown = new Rgba( + 0.5607843137254902, + 0.34901960784313724, + 0.00784313725490196, + 1 +); +var black = new Rgba(0, 0, 0, 1); +var white = new Rgba(1, 1, 1, 1); +var light_grey = new Rgba( + 0.9333333333333333, + 0.9333333333333333, + 0.9254901960784314, + 1 +); +var grey = new Rgba( + 0.8274509803921568, + 0.8431372549019608, + 0.8117647058823529, + 1 +); +var dark_grey = new Rgba( + 0.7294117647058823, + 0.7411764705882353, + 0.7137254901960784, + 1 +); +var light_gray = new Rgba( + 0.9333333333333333, + 0.9333333333333333, + 0.9254901960784314, + 1 +); +var gray = new Rgba( + 0.8274509803921568, + 0.8431372549019608, + 0.8117647058823529, + 1 +); +var dark_gray = new Rgba( + 0.7294117647058823, + 0.7411764705882353, + 0.7137254901960784, + 1 +); +var light_charcoal = new Rgba( + 0.5333333333333333, + 0.5411764705882353, + 0.5215686274509804, + 1 +); +var charcoal = new Rgba( + 0.3333333333333333, + 0.3411764705882353, + 0.3254901960784314, + 1 +); +var dark_charcoal = new Rgba( + 0.1803921568627451, + 0.20392156862745098, + 0.21176470588235294, + 1 +); +var pink = new Rgba(1, 0.6862745098039216, 0.9529411764705882, 1); + +// build/dev/javascript/lustre_ui/lustre/ui.mjs +var centre2 = centre; +var input3 = input2; +var stack2 = stack; + +// build/dev/javascript/lustre_ui/lustre/ui/util/cn.mjs +function text_xl() { + return class$("text-xl"); +} +function mt_xl() { + return class$("mt-xl"); +} + +// build/dev/javascript/modem/modem.ffi.mjs +var defaults = { + handle_external_links: false, + handle_internal_links: true +}; +var do_init = (dispatch, options = defaults) => { + document.body.addEventListener("click", (event2) => { + const a2 = find_anchor(event2.target); + if (!a2) + return; + try { + const url = new URL(a2.href); + const uri = uri_from_url(url); + const is_external = url.host !== window.location.host; + if (!options.handle_external_links && is_external) + return; + if (!options.handle_internal_links && !is_external) + return; + event2.preventDefault(); + if (!is_external) { + window.history.pushState({}, "", a2.href); + window.requestAnimationFrame(() => { + if (url.hash) { + document.getElementById(url.hash.slice(1))?.scrollIntoView(); + } + }); + } + return dispatch(uri); + } catch { + return; + } + }); + window.addEventListener("popstate", (e) => { + e.preventDefault(); + const url = new URL(window.location.href); + const uri = uri_from_url(url); + window.requestAnimationFrame(() => { + if (url.hash) { + document.getElementById(url.hash.slice(1))?.scrollIntoView(); + } + }); + dispatch(uri); + }); +}; +var find_anchor = (el2) => { + if (el2.tagName === "BODY") { + return null; + } else if (el2.tagName === "A") { + return el2; + } else { + return find_anchor(el2.parentElement); + } +}; +var uri_from_url = (url) => { + return new Uri( + /* scheme */ + new (url.protocol ? Some : None)(url.protocol), + /* userinfo */ + new None(), + /* host */ + new (url.host ? Some : None)(url.host), + /* port */ + new (url.port ? Some : None)(url.port), + /* path */ + url.pathname, + /* query */ + new (url.search ? Some : None)(url.search), + /* fragment */ + new (url.hash ? Some : None)(url.hash.slice(1)) + ); +}; + +// build/dev/javascript/modem/modem.mjs +function init2(handler) { + return from2( + (dispatch) => { + return do_init( + (uri) => { + let _pipe = uri; + let _pipe$1 = handler(_pipe); + return dispatch(_pipe$1); + } + ); + } + ); +} + +// build/dev/javascript/app/app.mjs +var Model = class extends CustomType { + constructor(current_route, guests, new_guest_name) { + super(); + this.current_route = current_route; + this.guests = guests; + this.new_guest_name = new_guest_name; + } +}; +var Home = class extends CustomType { +}; +var WelcomeGuest = class extends CustomType { + constructor(value3) { + super(); + this.value = value3; + } +}; +var Guest = class extends CustomType { + constructor(slug, name) { + super(); + this.slug = slug; + this.name = name; + } +}; +var OnRouteChange = class extends CustomType { + constructor(x0) { + super(); + this[0] = x0; + } +}; +var UserUpdatedNewGuestName = class extends CustomType { + constructor(x0) { + super(); + this[0] = x0; + } +}; +var UserAddedNewGuest = class extends CustomType { + constructor(x0) { + super(); + this[0] = x0; + } +}; +function on_route_change(uri) { + let $ = path_segments(uri.path); + if ($.hasLength(2) && $.head === "welcome") { + let guest = $.tail.head; + return new OnRouteChange(new WelcomeGuest(guest)); + } else { + return new OnRouteChange(new Home()); + } +} +function init3(_) { + return [ + new Model( + new Home(), + toList([new Guest("chihiro", "Chihiro"), new Guest("totoro", "Totoro")]), + "" + ), + init2(on_route_change) + ]; +} +function update2(model, msg) { + if (msg instanceof OnRouteChange) { + let route = msg[0]; + return [model.withFields({ current_route: route }), none()]; + } else if (msg instanceof UserUpdatedNewGuestName) { + let name = msg[0]; + return [model.withFields({ new_guest_name: name }), none()]; + } else { + let guest = msg[0]; + return [ + model.withFields({ + guests: append(model.guests, toList([guest])), + new_guest_name: "" + }), + none() + ]; + } +} +function view_nav(model) { + let item_styles = toList([["text-decoration", "underline"]]); + let view_nav_item = (path, text2) => { + return a( + toList([href("/" + path), style(item_styles)]), + toList([text(text2)]) + ); + }; + let guest_nav_items = (() => { + let _pipe = model.guests; + return map( + _pipe, + (guest) => { + return view_nav_item("welcome/" + guest.slug, guest.name); + } + ); + })(); + return of3( + nav, + toList([]), + prepend(view_nav_item("", "Home"), guest_nav_items) + ); +} +function view_body(children) { + return centre2(toList([mt_xl()]), stack2(toList([]), children)); +} +function view_title(text2) { + return h1(toList([text_xl()]), toList([text(text2)])); +} +function view_home(model) { + let new_guest_input = (event2) => { + return try$( + field("key", string)(event2), + (key_code) => { + if (key_code === "Enter") { + let guest_slug = (() => { + let _pipe = model.new_guest_name; + let _pipe$1 = replace2(_pipe, " ", "-"); + return lowercase2(_pipe$1); + })(); + return new Ok( + new UserAddedNewGuest(new Guest(guest_slug, model.new_guest_name)) + ); + } else { + return try$( + value2(event2), + (value3) => { + return new Ok(new UserUpdatedNewGuestName(value3)); + } + ); + } + } + ); + }; + return view_body( + toList([ + view_title("Welcome to the Party \u{1F3E1}"), + p( + toList([]), + toList([text("Please sign the guest book:")]) + ), + input3( + toList([ + on2("keyup", new_guest_input), + value(model.new_guest_name) + ]) + ) + ]) + ); +} +function view_welcome(model, slug) { + let guest = (() => { + let _pipe = model.guests; + return find2(_pipe, (guest2) => { + return guest2.slug === slug; + }); + })(); + let title = (() => { + if (guest.isOk()) { + let guest$1 = guest[0]; + return view_title("Hello, " + guest$1.name + "! \u{1F389}"); + } else { + return view_title("Sorry ... didn't quite catch that."); + } + })(); + return view_body(toList([title])); +} +function view(model) { + let styles = toList([["margin", "15vh"]]); + let page = (() => { + let $ = model.current_route; + if ($ instanceof Home) { + return view_home(model); + } else { + let name = $.value; + return view_welcome(model, name); + } + })(); + return stack2( + toList([style(styles)]), + toList([view_nav(model), page]) + ); +} +function main() { + let app = application(init3, update2, view); + let $ = start3(app, "#app", void 0); + if (!$.isOk()) { + throw makeError( + "assignment_no_match", + "app", + 21, + "main", + "Assignment pattern did not match", + { value: $ } + ); + } + return $; +} + +// build/.lustre/entry.mjs +main(); diff --git a/examples/07-routing/src/app.gleam b/examples/07-routing/src/app.gleam index fbdc786..5b65d51 100644 --- a/examples/07-routing/src/app.gleam +++ b/examples/07-routing/src/app.gleam @@ -1,26 +1,18 @@ -import gleam/uri.{type Uri} +import gleam/dynamic import gleam/list -import gleam/string import gleam/result -import gleam/dynamic +import gleam/string +import gleam/uri.{type Uri} import lustre import lustre/attribute import lustre/effect.{type Effect} import lustre/element.{type Element} import lustre/element/html import lustre/event -import modem -// These examples are written with `lustre/ui` in mind. They'll work regardless, -// but to see what `lustre/ui` can do make sure to run each of these examples with -// the `--use-example-styles` flag: -// -// $ gleam run -m lustre/dev start --use-example-styles -// -// In your own apps, make sure to add the `lustre/ui` dependency and include the -// stylesheet somewhere. import lustre/ui import lustre/ui/layout/cluster import lustre/ui/util/cn +import modem // MAIN ------------------------------------------------------------------------ |