pub const ELEMENTS_JS: &str = "// The built-in view elements.\n//\n// These are the only elements a program can use until user-defined\n// components land (spec \u{a7}14D). Each is a thin mapping onto DOM structure\n// plus a small amount of default styling, so that a program with no style\n// declarations still renders as something a person would recognise.\n//\n// Input elements bind two-way, and only to `client`-placed signals \u{2014} a\n// keystroke must not silently become a network write (spec \u{a7}14B.5). The\n// compiler enforces the placement rule; the runtime just wires the event.\n//\n// THE DIRECTORY OF THE VOCABULARY IS THE EXPORT LIST, and there is no\n// object holding one property per element. There was: `BUILTINS`, which\n// nothing in the runtime or the compiler read, whose one consumer was a\n// test asserting it existed. It was removed rather than kept, because it\n// had a measured cost and no benefit. `boa`, the engine both parity\n// suites run this file in, aborts the *process* with a Rust-level\n// `BorrowMutError` inside its own `Set` builtin once a context crosses an\n// allocation threshold \u{2014} the defect BENCHMARKS.md records as making\n// signal fan-out unmeasurable here \u{2014} and this file sat on that threshold.\n// Building the object on demand instead of at load bought about a dozen\n// elements and then stopped working too, because the function itself is\n// an object holding a reference per element.\n//\n// Nothing is lost. `element_parity.rs` calls each name in this file\n// directly, once per built-in, so an element the compiler knows and this\n// file does not export fails there with the name in the message.\n\nimport { el, safeUrl, text, variant } from \'./dom.js\';\nimport { effect } from \'./signal.js\';\nimport { markup } from \'./markup.js\';\n\n// Base styling is a CLASS NAME, not an inline style object (spec \u{a7}16.2 R6).\n// \u{a7}6 already specifies that styles compile to static CSS with generated\n// scoped class names and zero runtime cost; an inline style object costs one\n// effect and one `setProperty` per declaration, which is seven of each for a\n// `Column` and a `Row` that can never change. The declarations themselves\n// live in `base.css`, which `zdc build` copies into `styles.css`.\nconst BASE = {\n column: \'zd-col\',\n row: \'zd-row\',\n error: \'zd-err\',\n prose: \'zd-prose\',\n preformatted: \'zd-pre\',\n};\n\n/**\n * Put a base class in front of whatever class the program asked for.\n *\n * The program\'s `class` may be a getter, so the join has to stay reactive\n * rather than stringifying a function into the attribute.\n */\nfunction withBase(p, base) {\n const given = p.class;\n if (given === undefined) {\n p.class = base;\n } else if (typeof given === \'function\') {\n p.class = () => `${base} ${given()}`;\n } else {\n p.class = `${base} ${given}`;\n }\n return p;\n}\n\n/**\n * A `Truth` as the word an ARIA state attribute is spelled with.\n *\n * Reactive when it has to be: the program\'s value may be a getter, and\n * stringifying the function itself would write `aria-selected=\"() => \u{2026}\"`.\n */\nfunction word(value) {\n return typeof value === \'function\' ? () => String(value()) : String(value);\n}\n\n/** Split ZDeceptron element arguments into DOM props. */\nfunction props(args = {}) {\n const out = {};\n const style = {};\n for (const [name, value] of Object.entries(args)) {\n switch (name) {\n case \'padding\':\n style.padding = typeof value === \'function\' ? () => `${value()}px` : `${value}px`;\n break;\n case \'weight\':\n style[\'font-weight\'] = value;\n break;\n case \'hint\':\n out.placeholder = value;\n break;\n // The ZDeceptron spelling of `src`. Filtered, not merely renamed:\n // an image source is a request the browser issues to whatever host\n // the value names (spec \u{a7}16.3.5, corrected).\n case \'source\':\n out.src = typeof value === \'function\' ? () => safeUrl(value()) : safeUrl(value);\n break;\n // The still a video shows before it plays: a request the browser\n // issues at once, so it is filtered exactly as `source` is.\n case \'poster\':\n out.poster = typeof value === \'function\' ? () => safeUrl(value()) : safeUrl(value);\n break;\n case \'src\':\n case \'href\':\n out[name] = typeof value === \'function\' ? () => safeUrl(value()) : safeUrl(value);\n break;\n case \'exact\':\n out.datetime = value;\n break;\n // What the letters stand for. It is `title` in the DOM, and the\n // compiler requires it, because an `abbr` with no expansion is an\n // acronym with nothing behind it.\n case \'expansion\':\n out.title = value;\n break;\n // What this element operates, by `id`. `Label` renames it to `for`\n // itself, below, because that is the only element that has one.\n case \'controls\':\n out[\'aria-controls\'] = value;\n break;\n // The element that explains this one, and the element that names\n // it. Both are an `id` and neither translates.\n case \'describedBy\':\n out[\'aria-describedby\'] = value;\n break;\n case \'labelledBy\':\n out[\'aria-labelledby\'] = value;\n break;\n // Which of a set you are looking at, and how urgently a region\n // interrupts. Both are one word from a closed set the compiler\n // checks; nothing is translated, so both pass straight through.\n case \'current\':\n out[\'aria-current\'] = value;\n break;\n case \'live\':\n out[\'aria-live\'] = value;\n break;\n // The ARIA states, and the one thing about them that is not a\n // rename. `setAttribute` in `dom.js` implements HTML\'s boolean\n // attributes \u{2014} `false` removes, `true` sets the empty string \u{2014} and\n // an `aria-*` state is not one of those. Its value is the *word*\n // `true` or the word `false`, and an unselected tab carrying no\n // `aria-selected` announces a tablist with nothing chosen. So each\n // of these is stringified here, reactively when it is a getter.\n case \'selected\':\n case \'expanded\':\n case \'pressed\':\n case \'checked\':\n out[`aria-${name}`] = word(value);\n break;\n case \'disabled\':\n out[\'aria-disabled\'] = word(value);\n break;\n // `aria-hidden`, named for the only thing it is ever right for.\n // It hides nothing: the element stays where it was and a screen\n // reader stops reading it.\n case \'decorative\':\n out[\'aria-hidden\'] = word(value);\n break;\n // What this control is called when no text beside it says so.\n // `Checkbox` and `Radio` never reach here \u{2014} they read `label`\n // themselves and wrap their box in a `<label>` holding it.\n case \'label\':\n out[\'aria-label\'] = value;\n break;\n // The ends and the landmarks of a measured range, in English.\n case \'least\':\n out.min = value;\n break;\n case \'most\':\n out.max = value;\n break;\n case \'best\':\n out.optimum = value;\n break;\n case \'message\':\n break; // consumed by the element itself, never an attribute\n case \'class\':\n out.class = value;\n break;\n default:\n out[name] = value;\n }\n }\n if (Object.keys(style).length > 0) out.style = style;\n return out;\n}\n\n/**\n * The two layout containers.\n *\n * Both take an optional leading text slot, ratified in \u{a7}4.4: `Row item.name`\n * is one text node followed by the row\'s children, exactly as `Button`\n * already is. A row with nothing to say of its own passes `undefined`,\n * which is what a source program with no leading argument compiles to.\n */\nexport function Column(value, args = {}, children = []) {\n return el(\n \'div\',\n withBase(props(args), BASE.column),\n value === undefined ? children : [text(value), ...children],\n );\n}\n\nexport function Row(value, args = {}, children = []) {\n return el(\n \'div\',\n withBase(props(args), BASE.row),\n value === undefined ? children : [text(value), ...children],\n );\n}\n\nexport function Text(value, args = {}) {\n return el(\'span\', props(args), [text(value)]);\n}\n\n/**\n * A heading, at the level its nesting says.\n *\n * The compiler chooses the tag from how many sectioning elements enclose\n * the heading, so `h1` is what a heading at the top of a document is. This\n * reference implementation has no enclosing context to consult, so it\n * renders the top level, which is the case the parity test compares.\n */\nexport function Heading(value, args = {}) {\n return el(\'h1\', props(args), [text(value)]);\n}\n\nexport function Button(label, args = {}, children = []) {\n return el(\'button\', { type: \'button\', ...props(args) }, [text(label), ...children]);\n}\n\n/**\n * A text input bound two-way to a client signal.\n *\n * `binding` is the [read, write] pair the compiler emits for a `client`\n * signal. Passing a server or durable signal here is a compile error\n * (\u{a7}14B.5), so the runtime can assume the write is local and synchronous.\n */\nexport function Input(binding, args = {}) {\n const [get, set] = binding;\n return el(\'input\', {\n type: \'text\',\n value: get,\n onInput: (e) => set(e.target.value),\n ...props(args),\n });\n}\n\n/**\n * A multi-line field, bound the way `Input` is.\n *\n * A `textarea` holds its value as a property rather than as an attribute,\n * which `setAttribute` in `dom.js` already knows; nothing here is special\n * about the binding except the tag.\n */\nexport function TextArea(binding, args = {}) {\n const [get, set] = binding;\n return el(\'textarea\', {\n value: get,\n onInput: (e) => set(e.target.value),\n ...props(args),\n });\n}\n\n/**\n * A masked field.\n *\n * The three baked attributes are the whole of what the browser gives a\n * password field and nothing else does. What the *compiler* adds is a rule\n * about where the bound signal may appear, which has no counterpart here\n * because this file builds nodes and does not read programs; `elements.rs`\n * states the decision and `view.rs` enforces it.\n */\nexport function PasswordInput(binding, args = {}) {\n const [get, set] = binding;\n return el(\'input\', {\n type: \'password\',\n autocomplete: \'current-password\',\n spellcheck: \'false\',\n value: get,\n onInput: (e) => set(e.target.value),\n ...props(args),\n });\n}\n\n/**\n * A number, typed. And a date, picked, which is the same control with a\n * different `type` and a different reading of the same number.\n *\n * # Both bind an `Option`, and both bind through `valueAsNumber`\n *\n * A `Slider` always has a number, because a track always has a thumb on\n * it. A box a person types in does not: empty, a lone `-` and a\n * half-written `1e` all report `valueAsNumber` `NaN`, which is not a\n * value ZDeceptron has. So the read is `None` or `Some n`.\n *\n * The write is `valueAsNumber` and not `value`. A number field runs\n * HTML\'s value sanitisation, so `value` is the empty string while a\n * reader is part way through `1.`; comparing text would rewrite the box\n * on every keystroke and a decimal point could never be typed at all.\n *\n * A date field\'s `valueAsNumber` is defined by HTML as the moment at\n * midnight UTC on the chosen day, which is what `prelude/time.zd` means\n * by a moment. So the browser renders `YYYY-MM-DD` from the number and\n * reads the number back, and no calendar is written here.\n *\n * # Why the two rules are spelled here rather than imported\n *\n * The compiler emits them into a program\'s own preamble\n * (`intrinsics.rs`\'s `$optionalNumber` and `$numberField`) rather than\n * exporting them from `dom.js`, because the shipped runtime is against\n * the size gate `zdc-bench` holds it to. This file is a reference\n * implementation and is never shipped, so it says the same two things in\n * its own words \u{2014} which is what this file is *for*: `element_parity.rs`\n * compares the node against the compiler\'s, and `vocabulary.rs` drives\n * the behaviour.\n */\nexport function NumberInput(binding, args = {}) {\n return numericField(\'number\', binding, args);\n}\n\nexport function DateInput(binding, args = {}) {\n return numericField(\'date\', binding, args);\n}\n\nfunction numericField(type, [get, set], args) {\n const node = el(\'input\', {\n type,\n onInput: (e) => {\n const read = e.target.valueAsNumber;\n // `Number.isNaN`, not the coercing global: `isNaN(\'\')` is `false`.\n set(Number.isNaN(read) ? variant(\'None\') : variant(\'Some\', read));\n },\n ...props(args),\n });\n effect(() => {\n const held = get();\n // `NaN` empties the box, which is what `None` looks like and where a\n // non-finite number has to go too: the setter throws on an infinity.\n const shown =\n held.tag === \'Some\' && Number.isFinite(held.fields[0]) ? held.fields[0] : NaN;\n if (!Object.is(node.valueAsNumber, shown)) node.valueAsNumber = shown;\n });\n return node;\n}\n\n/**\n * A bounded number, dragged.\n *\n * The listener reads `valueAsNumber` and not `value`: the signal holds a\n * number, and `value` is the text of one, so a `Whole` given `\'55\'` would\n * render `551` the moment anything added to it.\n */\nexport function Slider(binding, args = {}) {\n const [get, set] = binding;\n return el(\'input\', {\n type: \'range\',\n value: get,\n onInput: (e) => set(e.target.valueAsNumber),\n ...props(args),\n });\n}\n\n/**\n * One variant of a `choice`, picked from a list.\n *\n * `variants` is the choice\'s own arms, in declaration order, which the\n * compiler writes from the declaration. The value on the wire is the\n * variant\'s tag, because an option\'s value is one string.\n */\nexport function Select(binding, variants = [], args = {}) {\n const [get, set] = binding;\n return el(\n \'select\',\n {\n value: () => get().tag,\n onChange: (e) => set(variant(e.target.value)),\n ...props(args),\n },\n variants.map((name) => el(\'option\', { value: name }, [name])),\n );\n}\n\n/**\n * One radio of a group.\n *\n * `option` is the variant\'s tag, which the compiler writes down: it is\n * this button\'s value in the markup and the tag the binding compares\n * against. The group is the signal, named by `group`, so the browser\n * clears the others when one is picked.\n */\nexport function Radio(binding, group, option, args = {}) {\n const [get, set] = binding;\n const button = el(\'input\', {\n type: \'radio\',\n name: group,\n checked: () => get().tag === option,\n onChange: () => set(variant(option)),\n });\n // The attribute, not the property. A radio\'s value never changes, so it\n // is markup on both sides: the compiler bakes it into the template, and\n // routing it through `el` here would set the property instead and the\n // two trees would differ by exactly that.\n button.setAttribute(\'value\', option);\n if (args.label === undefined) return button;\n return el(\'label\', { class: BASE.row }, [button, text(args.label)]);\n}\n\nexport function Checkbox(binding, args = {}) {\n const [get, set] = binding;\n const box = el(\'input\', {\n type: \'checkbox\',\n checked: get,\n onChange: (e) => set(e.target.checked),\n });\n if (args.label === undefined) return box;\n return el(\'label\', { class: BASE.row }, [box, text(args.label)]);\n}\n\n/**\n * Completion toward a goal, bound one way.\n *\n * The leading argument is the value, and nothing writes back: this is a\n * report rather than a control, so there is no listener.\n */\nexport function Progress(value, args = {}) {\n return el(\'progress\', { value, ...props(args) });\n}\n\n/** A value inside a range, with the landmarks a browser colours it by. */\nexport function Meter(value, args = {}) {\n return el(\'meter\', { value, ...props(args) });\n}\n\nexport function Spinner(args = {}) {\n return el(\'span\', { \'aria-busy\': \'true\', ...props(args) }, [\'\u{2026}\']);\n}\n\nexport function ErrorBar(args = {}) {\n return el(\'div\', withBase({ role: \'alert\', ...props(args) }, BASE.error), [\n text(args.message ?? \'\'),\n ]);\n}\n\n// --- structure, text, lists and media --------------------------------------\n//\n// These carry no base class and no baked-in attribute: they are the\n// language\'s semantic vocabulary, and what they mean is the tag itself.\n// Each is written out rather than generated from a table, because the whole\n// value of this file is being an *independent* statement of the DOM shape\n// that `element_parity.rs` checks the compiler\'s table against. A table\n// here would be the compiler\'s table again, in JavaScript.\n\n/** A container: everything it shows is nested inside it. */\nfunction group(tag) {\n return (args = {}, children = []) => el(tag, props(args), children);\n}\n\n/** An element whose leading argument is one text node, before children. */\nfunction shown(tag) {\n return (value, args = {}, children = []) =>\n el(tag, props(args), value === undefined ? children : [text(value), ...children]);\n}\n\n/** An element with no children at all. */\nfunction empty(tag) {\n return (args = {}) => el(tag, props(args));\n}\n\nexport const Main = group(\'main\');\nexport const Section = group(\'section\');\nexport const Article = group(\'article\');\nexport const Aside = group(\'aside\');\nexport const Navigation = group(\'nav\');\nexport const Header = group(\'header\');\nexport const Footer = group(\'footer\');\nexport const Address = group(\'address\');\nexport const Quote = group(\'blockquote\');\nexport const List = group(\'ul\');\nexport const NumberedList = group(\'ol\');\nexport const Terms = group(\'dl\');\nexport const HeaderRow = group(\'tr\');\nexport const TableRow = group(\'tr\');\nexport const Figure = group(\'figure\');\nexport const Form = group(\'form\');\nexport const Fieldset = group(\'fieldset\');\nexport const Details = group(\'details\');\n\nexport const Paragraph = shown(\'p\');\nexport const Emphasis = shown(\'em\');\nexport const Strong = shown(\'strong\');\nexport const Code = shown(\'code\');\nexport const CodeBlock = shown(\'pre\');\nexport const Key = shown(\'kbd\');\nexport const Time = shown(\'time\');\nexport const Small = shown(\'small\');\nexport const Mark = shown(\'mark\');\nexport const Abbreviation = shown(\'abbr\');\n/**\n * The name of a control, tied to it by `id`.\n *\n * The one element where `controls` is not `aria-controls`. A `label` has\n * HTML\'s own `for`, which is what clicking the label acts on and what the\n * accessible-name computation reads there, so the same word reaches the\n * browser by the route that works \u{2014} exactly as `label` itself does, going\n * to `aria-label` here and into a wrapping `<label>` on a `Checkbox`. The\n * compiler\'s table makes the same split, keyed on the element.\n */\nexport function Label(value, args = {}, children = []) {\n const p = props(args);\n if (\'aria-controls\' in p) {\n p.for = p[\'aria-controls\'];\n delete p[\'aria-controls\'];\n }\n return el(\'label\', p, value === undefined ? children : [text(value), ...children]);\n}\nexport const Legend = shown(\'legend\');\nexport const Summary = shown(\'summary\');\nexport const Superscript = shown(\'sup\');\nexport const Subscript = shown(\'sub\');\nexport const Item = shown(\'li\');\nexport const Term = shown(\'dt\');\nexport const Description = shown(\'dd\');\nexport const Caption = shown(\'figcaption\');\nexport const Cell = shown(\'td\');\n\n/**\n * A table, whose rows sit in a row group this function writes.\n *\n * The parser inserts a `tbody` of its own around any `tr` found directly\n * inside a `table`, so a table built without one here and cloned from a\n * template there would be two different trees.\n */\nexport function Table(args = {}, children = []) {\n return el(\'table\', props(args), [el(\'tbody\', {}, children)]);\n}\n\n/** A column heading, which says so: a `th` that heads its column. */\nexport function HeaderCell(value, args = {}, children = []) {\n return el(\n \'th\',\n { scope: \'col\', ...props(args) },\n value === undefined ? children : [text(value), ...children],\n );\n}\n\n/**\n * A rendered document: markup, parsed as markup.\n *\n * The one built-in whose content is parsed rather than assigned as a text\n * node. It is safe for the reason `dom.js`\'s `markup` is safe and for no\n * other: its argument\'s type is `Markup`, the compiler admits nothing else\n * there, and the only producer of a `Markup` is `build markdown`, which\n * escapes raw HTML and rewrites script-bearing URLs before it returns.\n */\nexport function Prose(value, args = {}) {\n const p = props(args);\n withBase(p, BASE.prose);\n const node = el(\'div\', p);\n markup(node, typeof value === \'function\' ? value() : value);\n return node;\n}\n\nexport const Divider = empty(\'hr\');\nexport const Break = empty(\'br\');\nexport const Canvas = empty(\'canvas\');\n\n/**\n * Preserved whitespace that is not code.\n *\n * A `pre`, as `CodeBlock` is, and told apart by its class: `zd-pre` takes\n * the document\'s own typeface and lets long lines wrap, which is what a\n * poem or an address block wants and what a listing must not have.\n */\nexport function Preformatted(value, args = {}, children = []) {\n return el(\n \'pre\',\n withBase(props(args), BASE.preformatted),\n value === undefined ? children : [text(value), ...children],\n );\n}\n\n/** An image. `source` and `alt` are required by the compiler, not here. */\nexport function Image(args = {}) {\n return el(\'img\', props(args));\n}\n\n/**\n * A video. `controls` is baked rather than offered: a media element with\n * no controls can be operated by a pointer and by nothing else.\n */\nexport function Video(args = {}) {\n return el(\'video\', { controls: \'\', ...props(args) });\n}\n\n/** Audio, on the same terms as `Video`. */\nexport function Audio(args = {}) {\n return el(\'audio\', { controls: \'\', ...props(args) });\n}\n\n/**\n * An embedded document, sandboxed to nothing.\n *\n * The empty `sandbox` grants no capability at all: no script, no form, no\n * top-level navigation, no popup, and an opaque origin, so the framed\n * document can read nothing of the page that embedded it. There is no\n * argument that widens it; `elements.rs` states why.\n */\nexport function Frame(args = {}) {\n return el(\'iframe\', {\n sandbox: \'\',\n referrerpolicy: \'no-referrer\',\n loading: \'lazy\',\n ...props(args),\n });\n}\n\n/**\n * A hyperlink, and routing\'s one element (spec \u{a7}14G.2 revision 1).\n *\n * The leading argument is where it goes \u{2014} \u{a7}14G.2 writes `Link Home` with\n * the destination first and the content nested under it \u{2014} and it is\n * filtered, because `setAttribute(\'href\', \'javascript:\u{2026}\')` is script\n * execution that no amount of HTML escaping would have caught.\n *\n * A real anchor with a real `href`, because that is the whole argument:\n * clicking one is a browser navigation, so every navigation is crawlable,\n * works with a middle click, and needs no runtime at all. When the\n * destination is one of the program\'s routes the compiler has already\n * rendered the URL; nothing here parses a path or matches a pattern.\n */\nexport function Link(destination, args = {}, children = []) {\n const href =\n typeof destination === \'function\' ? () => safeUrl(destination()) : safeUrl(destination);\n return el(\'a\', { href, ...props(args) }, children);\n}\n";Expand description
The built-in view elements.