@davidsouther/jiffies 2026.4.1 → 2026.24.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +0 -3
- package/lib/esm/assert.d.ts +26 -0
- package/lib/esm/assert.js +38 -0
- package/lib/esm/awaitable.js +1 -0
- package/lib/esm/case.d.ts +1 -0
- package/lib/esm/case.js +5 -0
- package/lib/esm/components/accordion.d.ts +5 -0
- package/lib/esm/components/accordion.js +9 -0
- package/lib/esm/components/alert.d.ts +7 -0
- package/lib/esm/components/alert.js +31 -0
- package/lib/esm/components/button_bar.d.ts +8 -0
- package/lib/esm/components/button_bar.js +25 -0
- package/lib/esm/components/card.d.ts +8 -0
- package/lib/esm/components/card.js +31 -0
- package/lib/esm/components/children.d.ts +2 -0
- package/lib/esm/components/children.js +7 -0
- package/lib/esm/components/form.d.ts +5 -0
- package/lib/esm/components/form.js +13 -0
- package/lib/esm/components/index.d.ts +9 -0
- package/lib/esm/components/index.js +10 -0
- package/lib/esm/components/inline_edit.d.ts +12 -0
- package/lib/esm/components/inline_edit.js +48 -0
- package/lib/esm/components/link.d.ts +5 -0
- package/lib/esm/components/link.js +11 -0
- package/lib/esm/components/logger.d.ts +6 -0
- package/lib/esm/components/logger.js +22 -0
- package/lib/esm/components/modal.d.ts +2 -0
- package/lib/esm/components/modal.js +10 -0
- package/lib/esm/components/nav.d.ts +11 -0
- package/lib/esm/components/nav.js +27 -0
- package/lib/esm/components/property.d.ts +9 -0
- package/lib/esm/components/property.js +16 -0
- package/lib/esm/components/select.d.ts +10 -0
- package/lib/esm/components/select.js +3 -0
- package/lib/esm/components/tabs.d.ts +20 -0
- package/lib/esm/components/tabs.js +45 -0
- package/lib/esm/components/virtual_scroll.d.ts +42 -0
- package/lib/esm/components/virtual_scroll.js +94 -0
- package/lib/esm/debounce.d.ts +1 -0
- package/lib/esm/debounce.js +11 -0
- package/lib/esm/diff.d.ts +15 -0
- package/lib/esm/diff.js +50 -0
- package/lib/esm/display.d.ts +5 -0
- package/lib/esm/display.js +11 -0
- package/lib/esm/dom/css/border.d.ts +11 -0
- package/lib/esm/dom/css/border.js +27 -0
- package/lib/esm/dom/css/constants.d.ts +31 -0
- package/lib/esm/dom/css/constants.js +28 -0
- package/lib/esm/dom/css/core.d.ts +5 -0
- package/lib/esm/dom/css/core.js +24 -0
- package/lib/esm/dom/css/fstyle.d.ts +5 -0
- package/lib/esm/dom/css/fstyle.js +32 -0
- package/lib/esm/dom/css/sizing.d.ts +5 -0
- package/lib/esm/dom/css/sizing.js +10 -0
- package/lib/esm/dom/dom.d.ts +36 -0
- package/lib/esm/dom/dom.js +217 -0
- package/lib/esm/dom/fc.d.ts +10 -0
- package/lib/esm/dom/fc.js +32 -0
- package/lib/esm/dom/form/form.app.d.ts +1 -0
- package/lib/esm/dom/form/form.app.js +19 -0
- package/lib/esm/dom/form/form.d.ts +27 -0
- package/lib/esm/dom/form/form.js +65 -0
- package/lib/esm/dom/html.d.ts +112 -0
- package/{src/dom/html.ts → lib/esm/dom/html.js} +2 -14
- package/lib/esm/dom/hydrate.d.ts +39 -0
- package/lib/esm/dom/hydrate.js +187 -0
- package/lib/esm/dom/index.js +2 -0
- package/lib/esm/dom/navigation/index.d.ts +76 -0
- package/lib/esm/dom/navigation/index.js +292 -0
- package/lib/esm/dom/observable.d.ts +2 -0
- package/lib/esm/dom/observable.js +6 -0
- package/lib/esm/dom/provide.d.ts +3 -0
- package/lib/esm/dom/provide.js +7 -0
- package/lib/esm/dom/render.d.ts +8 -0
- package/lib/esm/dom/render.js +28 -0
- package/lib/esm/dom/router/link.d.ts +6 -0
- package/lib/esm/dom/router/link.js +3 -0
- package/lib/esm/dom/router/router.d.ts +13 -0
- package/lib/esm/dom/router/router.js +52 -0
- package/lib/esm/dom/svg.d.ts +64 -0
- package/{src/dom/svg.ts → lib/esm/dom/svg.js} +2 -15
- package/lib/esm/dom/types/css.d.ts +6590 -0
- package/lib/esm/dom/types/css.js +1 -0
- package/lib/esm/dom/types/dom.js +1 -0
- package/lib/esm/dom/types/html.d.ts +614 -0
- package/lib/esm/dom/types/html.js +1 -0
- package/lib/esm/dom/xml.d.ts +1 -0
- package/lib/esm/dom/xml.js +4 -0
- package/lib/esm/equal.d.ts +11 -0
- package/lib/esm/equal.js +43 -0
- package/lib/esm/fs.d.ts +72 -0
- package/lib/esm/fs.js +227 -0
- package/lib/esm/fs_node.d.ts +15 -0
- package/lib/esm/fs_node.js +45 -0
- package/lib/esm/generator.d.ts +1 -0
- package/lib/esm/generator.js +10 -0
- package/lib/esm/lock.d.ts +1 -0
- package/lib/esm/lock.js +23 -0
- package/lib/esm/log.d.ts +69 -0
- package/lib/esm/log.js +211 -0
- package/lib/esm/observable/event.d.ts +35 -0
- package/lib/esm/observable/event.js +46 -0
- package/lib/esm/observable/observable.d.ts +134 -0
- package/lib/esm/observable/observable.js +349 -0
- package/lib/esm/range.d.ts +1 -0
- package/lib/esm/range.js +7 -0
- package/lib/esm/result.d.ts +31 -0
- package/lib/esm/result.js +66 -0
- package/lib/esm/safe.d.ts +1 -0
- package/lib/esm/safe.js +10 -0
- package/lib/esm/server/http/apps.d.ts +5 -0
- package/lib/esm/server/http/apps.js +23 -0
- package/lib/esm/server/http/css.d.ts +5 -0
- package/lib/esm/server/http/css.js +43 -0
- package/lib/esm/server/http/index.d.ts +16 -0
- package/lib/esm/server/http/index.js +78 -0
- package/lib/esm/server/http/response.d.ts +4 -0
- package/lib/esm/server/http/response.js +43 -0
- package/lib/esm/server/http/sitemap.d.ts +2 -0
- package/lib/esm/server/http/sitemap.js +22 -0
- package/lib/esm/server/http/static.d.ts +2 -0
- package/lib/esm/server/http/static.js +22 -0
- package/lib/esm/server/http/typescript.d.ts +5 -0
- package/lib/esm/server/http/typescript.js +40 -0
- package/lib/esm/server/live-reload.d.ts +46 -0
- package/lib/esm/server/live-reload.js +161 -0
- package/lib/esm/server/main.d.ts +2 -0
- package/lib/esm/server/main.js +23 -0
- package/lib/esm/server/ws/frame.d.ts +2 -0
- package/lib/esm/server/ws/frame.js +35 -0
- package/lib/esm/server/ws/handshake.d.ts +4 -0
- package/lib/esm/server/ws/handshake.js +32 -0
- package/lib/esm/server/ws/index.d.ts +14 -0
- package/lib/esm/server/ws/index.js +68 -0
- package/lib/esm/ssg/bundle.d.ts +14 -0
- package/lib/esm/ssg/bundle.js +73 -0
- package/lib/esm/ssg/copy-public.d.ts +6 -0
- package/lib/esm/ssg/copy-public.js +34 -0
- package/lib/esm/ssg/discover.d.ts +15 -0
- package/lib/esm/ssg/discover.js +117 -0
- package/lib/esm/ssg/main.d.ts +2 -0
- package/lib/esm/ssg/main.js +122 -0
- package/lib/esm/ssg/rewrite.d.ts +9 -0
- package/lib/esm/ssg/rewrite.js +15 -0
- package/lib/esm/ssg/ssg.d.ts +26 -0
- package/lib/esm/ssg/ssg.js +84 -0
- package/lib/esm/transpile.d.mts +3 -0
- package/lib/esm/transpile.mjs +12 -0
- package/package.json +19 -10
- package/src/404.html +0 -14
- package/src/assert.ts +0 -56
- package/src/case.ts +0 -5
- package/src/components/_notes +0 -33
- package/src/components/button_bar.ts +0 -42
- package/src/components/inline_edit.ts +0 -78
- package/src/components/logger.ts +0 -35
- package/src/components/select.ts +0 -22
- package/src/components/test.ts +0 -5
- package/src/components/virtual_scroll.test.ts +0 -30
- package/src/components/virtual_scroll.ts +0 -199
- package/src/context.test.ts +0 -58
- package/src/context.ts +0 -67
- package/src/debounce.ts +0 -14
- package/src/diff.test.ts +0 -48
- package/src/diff.ts +0 -82
- package/src/display.ts +0 -18
- package/src/dom/README.md +0 -102
- package/src/dom/css/border.ts +0 -47
- package/src/dom/css/constants.ts +0 -34
- package/src/dom/css/core.ts +0 -28
- package/src/dom/css/fstyle.ts +0 -42
- package/src/dom/css/sizing.ts +0 -11
- package/src/dom/dom.ts +0 -183
- package/src/dom/fc.test.ts +0 -43
- package/src/dom/fc.ts +0 -80
- package/src/dom/form/form.app.ts +0 -50
- package/src/dom/form/form.ts +0 -82
- package/src/dom/form/index.html +0 -15
- package/src/dom/html.test.ts +0 -74
- package/src/dom/observable.test.ts +0 -43
- package/src/dom/observable.ts +0 -11
- package/src/dom/provide.ts +0 -11
- package/src/dom/router/link.ts +0 -14
- package/src/dom/router/router.ts +0 -72
- package/src/dom/test.ts +0 -11
- package/src/dom/types/css.ts +0 -10088
- package/src/dom/types/dom.ts +0 -0
- package/src/dom/types/html.ts +0 -629
- package/src/dom/xml.ts +0 -11
- package/src/equal.test.ts +0 -23
- package/src/equal.ts +0 -66
- package/src/favicon.ico +0 -0
- package/src/flags.test.ts +0 -43
- package/src/flags.ts +0 -53
- package/src/fs.test.ts +0 -106
- package/src/fs.ts +0 -300
- package/src/fs_node.ts +0 -57
- package/src/fs_win.test.ts +0 -11
- package/src/generator.test.ts +0 -27
- package/src/generator.ts +0 -12
- package/src/hooks/_notes +0 -6
- package/src/index.html +0 -82
- package/src/is_browser.js +0 -1
- package/src/lock.test.ts +0 -17
- package/src/lock.ts +0 -23
- package/src/log.ts +0 -155
- package/src/observable/_notes +0 -26
- package/src/observable/event.ts +0 -93
- package/src/observable/observable.test.ts +0 -73
- package/src/observable/observable.ts +0 -484
- package/src/pico/_variables.scss +0 -66
- package/src/pico/components/_accordion.scss +0 -112
- package/src/pico/components/_button-group.scss +0 -51
- package/src/pico/components/_card.scss +0 -47
- package/src/pico/components/_dropdown.scss +0 -203
- package/src/pico/components/_modal.scss +0 -181
- package/src/pico/components/_nav.scss +0 -79
- package/src/pico/components/_progress.scss +0 -70
- package/src/pico/components/_property.scss +0 -34
- package/src/pico/content/_button.scss +0 -152
- package/src/pico/content/_code.scss +0 -63
- package/src/pico/content/_embedded.scss +0 -0
- package/src/pico/content/_form-alt.scss +0 -276
- package/src/pico/content/_form.scss +0 -259
- package/src/pico/content/_misc.scss +0 -0
- package/src/pico/content/_table.scss +0 -28
- package/src/pico/content/_toggle.scss +0 -132
- package/src/pico/content/_typography.scss +0 -232
- package/src/pico/layout/_container.scss +0 -40
- package/src/pico/layout/_document.scss +0 -0
- package/src/pico/layout/_flex.scss +0 -46
- package/src/pico/layout/_grid.scss +0 -24
- package/src/pico/layout/_scroller.scss +0 -16
- package/src/pico/layout/_section.scss +0 -8
- package/src/pico/layout/_sectioning.scss +0 -55
- package/src/pico/pico.scss +0 -60
- package/src/pico/reset/_accessibility.scss +0 -34
- package/src/pico/reset/_button.scss +0 -17
- package/src/pico/reset/_code.scss +0 -15
- package/src/pico/reset/_document.scss +0 -48
- package/src/pico/reset/_embedded.scss +0 -39
- package/src/pico/reset/_form.scss +0 -97
- package/src/pico/reset/_misc.scss +0 -23
- package/src/pico/reset/_nav.scss +0 -5
- package/src/pico/reset/_progress.scss +0 -4
- package/src/pico/reset/_table.scss +0 -8
- package/src/pico/reset/_typography.scss +0 -25
- package/src/pico/themes/default/_colors.scss +0 -65
- package/src/pico/themes/default/_dark.scss +0 -148
- package/src/pico/themes/default/_light.scss +0 -149
- package/src/pico/themes/default/_styles.scss +0 -272
- package/src/pico/themes/default.scss +0 -34
- package/src/pico/utilities/_accessibility.scss +0 -3
- package/src/pico/utilities/_loading.scss +0 -52
- package/src/pico/utilities/_reduce-motion.scss +0 -27
- package/src/pico/utilities/_tooltip.scss +0 -101
- package/src/range.ts +0 -7
- package/src/result.test.ts +0 -101
- package/src/result.ts +0 -107
- package/src/safe.ts +0 -12
- package/src/scope/describe.ts +0 -81
- package/src/scope/display/console.ts +0 -26
- package/src/scope/display/dom.ts +0 -36
- package/src/scope/display/junit.ts +0 -64
- package/src/scope/execute.ts +0 -110
- package/src/scope/expect.ts +0 -169
- package/src/scope/fix.ts +0 -30
- package/src/scope/index.ts +0 -11
- package/src/scope/scope.ts +0 -21
- package/src/scope/state.ts +0 -13
- package/src/server/http/apps.ts +0 -26
- package/src/server/http/css.ts +0 -49
- package/src/server/http/index.ts +0 -127
- package/src/server/http/response.ts +0 -57
- package/src/server/http/sitemap.ts +0 -48
- package/src/server/http/static.ts +0 -30
- package/src/server/http/typescript.ts +0 -46
- package/src/server/main.ts +0 -23
- package/src/test.mjs +0 -33
- package/src/test_all.ts +0 -35
- package/src/transpile.mjs +0 -16
- package/src/zip/spec.txt +0 -3260
- package/tsconfig.json +0 -34
- /package/{src/awaitable.ts → lib/esm/awaitable.d.ts} +0 -0
- /package/{src/dom/index.ts → lib/esm/dom/index.d.ts} +0 -0
- /package/{src/dom/form/form.test.ts → lib/esm/dom/types/dom.d.ts} +0 -0
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
import { CLEAR, normalizeArguments, reconcileChildren, update, } from "./dom.js";
|
|
2
|
+
export const State = Symbol();
|
|
3
|
+
export function FC(name, component) {
|
|
4
|
+
class FCImpl extends HTMLElement {
|
|
5
|
+
[State] = {};
|
|
6
|
+
#attrs = {};
|
|
7
|
+
#children = [];
|
|
8
|
+
update(attrs, ...children) {
|
|
9
|
+
[attrs, children] = normalizeArguments(attrs, children);
|
|
10
|
+
if (children[0] === CLEAR) {
|
|
11
|
+
this.#children = [];
|
|
12
|
+
}
|
|
13
|
+
else if (children.length > 0) {
|
|
14
|
+
this.#children = children;
|
|
15
|
+
}
|
|
16
|
+
this.#attrs = { ...this.#attrs, ...attrs };
|
|
17
|
+
// Apply updates from the attrs to the dom node itself
|
|
18
|
+
update(this, this.#attrs, []);
|
|
19
|
+
// Re-run the component function using new element, attrs, and children.
|
|
20
|
+
const rendered = [component(this, this.#attrs, this.#children)];
|
|
21
|
+
reconcileChildren(this, rendered.flat());
|
|
22
|
+
return this;
|
|
23
|
+
}
|
|
24
|
+
}
|
|
25
|
+
customElements.define(name, FCImpl);
|
|
26
|
+
const ctor = (attrs, ...children) => {
|
|
27
|
+
const element = window.document.createElement(name);
|
|
28
|
+
element.update(attrs, ...children);
|
|
29
|
+
return element;
|
|
30
|
+
};
|
|
31
|
+
return ctor;
|
|
32
|
+
}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export declare const App: () => HTMLElement;
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
import { button, div, main, small } from "../html.js";
|
|
2
|
+
import { Form, Input } from "./form.js";
|
|
3
|
+
export const App = () => main(Form({
|
|
4
|
+
events: {
|
|
5
|
+
submit(event) {
|
|
6
|
+
console.log("Should see fields for firstname, lastname, email, etc");
|
|
7
|
+
console.log(event);
|
|
8
|
+
},
|
|
9
|
+
},
|
|
10
|
+
}, div({ class: "grid" }, Input({ id: "firstname", placeholder: "First name" }), Input({ id: "lastname", placeholder: "Last name" })), Input({
|
|
11
|
+
id: "email",
|
|
12
|
+
type: "email",
|
|
13
|
+
placeholder: "Email address",
|
|
14
|
+
required: true,
|
|
15
|
+
}, small("We will never share your email with anyone.")), button({ type: "submit" }, "Submit"), div({ class: "grid" }, Input({ id: "valid", placeholder: "Valid", "aria-invalid": "false" }), Input({
|
|
16
|
+
id: "invalid",
|
|
17
|
+
placeholder: "Invalid",
|
|
18
|
+
"aria-invalid": "true",
|
|
19
|
+
}), Input({ id: "disabled", placeholder: "Disabled", disabled: true }), Input({ id: "readonly", value: "Readonly", readOnly: true }))));
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
import type { DenormChildren } from "../dom.ts";
|
|
2
|
+
import type { FormAttributes, InputAttributes, LabelAttributes, OptionAttributes, SelectAttributes } from "../types/html";
|
|
3
|
+
export declare const Form: (attrs: FormAttributes, ...children: DenormChildren[]) => HTMLFormElement;
|
|
4
|
+
export declare const Input: (attrs: InputAttributes, ...children: DenormChildren[]) => HTMLLabelElement;
|
|
5
|
+
export declare const Select: (attrs: {
|
|
6
|
+
options: string[] | object;
|
|
7
|
+
selected?: string;
|
|
8
|
+
} & SelectAttributes & LabelAttributes) => HTMLLabelElement;
|
|
9
|
+
export type ButtonVariant = "secondary" | "contrast" | "outline";
|
|
10
|
+
export declare const Button: (variant?: ButtonVariant, ...children: DenormChildren[]) => HTMLButtonElement;
|
|
11
|
+
declare const prepareOptions: (attrs: string[] | Record<string, string | {
|
|
12
|
+
label: string;
|
|
13
|
+
disabled?: boolean;
|
|
14
|
+
selected?: boolean;
|
|
15
|
+
}>, selected?: string) => Parameters<typeof Option>[0][];
|
|
16
|
+
export declare const Option: (attrs: OptionAttributes) => HTMLOptionElement;
|
|
17
|
+
export declare const Dropdown: (attrs: SelectAttributes | {
|
|
18
|
+
selected?: string;
|
|
19
|
+
}, ...options: Parameters<typeof prepareOptions>[0][]) => HTMLLabelElement;
|
|
20
|
+
export type ChoiceOptions = Record<string, string>;
|
|
21
|
+
export declare const Radios: (legendText: string, options: ChoiceOptions) => HTMLFieldSetElement;
|
|
22
|
+
export declare const Checks: (legendText: string, options: ChoiceOptions) => HTMLFieldSetElement;
|
|
23
|
+
export declare const Switches: (legendText: string, options: ChoiceOptions) => HTMLFieldSetElement;
|
|
24
|
+
export declare const Radio: (labelText: string, attrs?: Omit<InputAttributes, "type">) => HTMLLabelElement;
|
|
25
|
+
export declare const Checkbox: (labelText: string, attrs?: Omit<InputAttributes, "type">) => HTMLLabelElement;
|
|
26
|
+
export declare const Switch: (labelText: string, attrs?: Omit<InputAttributes, "type" | "role">) => HTMLLabelElement;
|
|
27
|
+
export {};
|
|
@@ -0,0 +1,65 @@
|
|
|
1
|
+
import { button, fieldset, form, input, label, legend, option, select, } from "../html.js";
|
|
2
|
+
export const Form = (attrs, ...children) => {
|
|
3
|
+
if (attrs.events?.submit) {
|
|
4
|
+
const submit = attrs.events.submit;
|
|
5
|
+
attrs.events.submit = (event) => {
|
|
6
|
+
event.preventDefault();
|
|
7
|
+
submit(event);
|
|
8
|
+
};
|
|
9
|
+
}
|
|
10
|
+
return form(attrs, ...children);
|
|
11
|
+
};
|
|
12
|
+
export const Input = (attrs, ...children) => label(input(
|
|
13
|
+
// @ts-expect-error
|
|
14
|
+
attrs), ...children);
|
|
15
|
+
export const Select = (attrs) => label({ style: attrs.style ?? {} }, select({ events: attrs.events ?? {} }, ...prepareOptions(attrs.options, attrs.selected).map(Option)));
|
|
16
|
+
// Button emits button[type=button] so it never accidentally submits a form. The
|
|
17
|
+
// optional variant maps to the matching sanctioned jiffies-css class.
|
|
18
|
+
export const Button = (variant, ...children) => button(variant ? { type: "button", class: variant } : { type: "button" }, ...children);
|
|
19
|
+
const prepareOptions = (attrs, selected) => Array.isArray(attrs)
|
|
20
|
+
? attrs.map((value) => ({
|
|
21
|
+
value,
|
|
22
|
+
label: value,
|
|
23
|
+
selected: selected === value,
|
|
24
|
+
}))
|
|
25
|
+
: Object.entries(attrs).map(([value, label]) => typeof label === "string"
|
|
26
|
+
? { value, label, selected: selected === value }
|
|
27
|
+
: { value, ...label });
|
|
28
|
+
export const Option = (attrs) => option(attrs);
|
|
29
|
+
export const Dropdown = (attrs, ...options) => Select({
|
|
30
|
+
...attrs,
|
|
31
|
+
options: typeof options[0] === "string" ? options : options[0],
|
|
32
|
+
});
|
|
33
|
+
// Derive a stable name/id stem from the legend text.
|
|
34
|
+
const slug = (text) => text
|
|
35
|
+
.toLowerCase()
|
|
36
|
+
.replace(/[^a-z0-9]+/g, "-")
|
|
37
|
+
.replace(/^-+|-+$/g, "");
|
|
38
|
+
// Shared builder for Radios/Checks/Switches: fieldset[role=group] > legend +
|
|
39
|
+
// (input[type] + label[for])* — the jiffies-css grouped-controls structure. The
|
|
40
|
+
// shared name groups the inputs; id/for pairs each input to its label.
|
|
41
|
+
const choiceGroup = (type, legendText, options, role) => {
|
|
42
|
+
const name = slug(legendText);
|
|
43
|
+
const children = [legend(legendText)];
|
|
44
|
+
for (const [value, labelText] of Object.entries(options)) {
|
|
45
|
+
const id = `${name}-${value}`;
|
|
46
|
+
const box = input({ type, name, id, value });
|
|
47
|
+
if (role) {
|
|
48
|
+
box.setAttribute("role", role);
|
|
49
|
+
}
|
|
50
|
+
const lbl = label(labelText);
|
|
51
|
+
lbl.setAttribute("for", id);
|
|
52
|
+
children.push(box, lbl);
|
|
53
|
+
}
|
|
54
|
+
const group = fieldset(...children);
|
|
55
|
+
group.setAttribute("role", "group");
|
|
56
|
+
return group;
|
|
57
|
+
};
|
|
58
|
+
export const Radios = (legendText, options) => choiceGroup("radio", legendText, options);
|
|
59
|
+
export const Checks = (legendText, options) => choiceGroup("checkbox", legendText, options);
|
|
60
|
+
export const Switches = (legendText, options) => choiceGroup("checkbox", legendText, options, "switch");
|
|
61
|
+
// Single-item controls wrap the input in its label (label > input + text), the
|
|
62
|
+
// jiffies-css labelled-control pattern. type and role are fixed per variant.
|
|
63
|
+
export const Radio = (labelText, attrs = {}) => Input({ ...attrs, type: "radio" }, labelText);
|
|
64
|
+
export const Checkbox = (labelText, attrs = {}) => Input({ ...attrs, type: "checkbox" }, labelText);
|
|
65
|
+
export const Switch = (labelText, attrs = {}) => Input({ ...attrs, type: "checkbox", role: "switch" }, labelText);
|
|
@@ -0,0 +1,112 @@
|
|
|
1
|
+
import { type DenormAttrs, type DenormChildren } from "./dom.ts";
|
|
2
|
+
export declare const a: (attrs?: DenormAttrs<HTMLAnchorElement>, ...children: DenormChildren[]) => HTMLAnchorElement;
|
|
3
|
+
export declare const abbr: (attrs?: DenormAttrs<HTMLElement>, ...children: DenormChildren[]) => HTMLElement;
|
|
4
|
+
export declare const address: (attrs?: DenormAttrs<HTMLElement>, ...children: DenormChildren[]) => HTMLElement;
|
|
5
|
+
export declare const area: (attrs?: DenormAttrs<HTMLAreaElement>, ...children: DenormChildren[]) => HTMLAreaElement;
|
|
6
|
+
export declare const article: (attrs?: DenormAttrs<HTMLElement>, ...children: DenormChildren[]) => HTMLElement;
|
|
7
|
+
export declare const aside: (attrs?: DenormAttrs<HTMLElement>, ...children: DenormChildren[]) => HTMLElement;
|
|
8
|
+
export declare const audio: (attrs?: DenormAttrs<HTMLAudioElement>, ...children: DenormChildren[]) => HTMLAudioElement;
|
|
9
|
+
export declare const b: (attrs?: DenormAttrs<HTMLElement>, ...children: DenormChildren[]) => HTMLElement;
|
|
10
|
+
export declare const base: (attrs?: DenormAttrs<HTMLBaseElement>, ...children: DenormChildren[]) => HTMLBaseElement;
|
|
11
|
+
export declare const bdi: (attrs?: DenormAttrs<HTMLElement>, ...children: DenormChildren[]) => HTMLElement;
|
|
12
|
+
export declare const bdo: (attrs?: DenormAttrs<HTMLElement>, ...children: DenormChildren[]) => HTMLElement;
|
|
13
|
+
export declare const blockquote: (attrs?: DenormAttrs<HTMLQuoteElement>, ...children: DenormChildren[]) => HTMLQuoteElement;
|
|
14
|
+
export declare const body: (attrs?: DenormAttrs<HTMLBodyElement>, ...children: DenormChildren[]) => HTMLBodyElement;
|
|
15
|
+
export declare const br: (attrs?: DenormAttrs<HTMLBRElement>, ...children: DenormChildren[]) => HTMLBRElement;
|
|
16
|
+
export declare const button: (attrs?: DenormAttrs<HTMLButtonElement>, ...children: DenormChildren[]) => HTMLButtonElement;
|
|
17
|
+
export declare const canvas: (attrs?: DenormAttrs<HTMLCanvasElement>, ...children: DenormChildren[]) => HTMLCanvasElement;
|
|
18
|
+
export declare const caption: (attrs?: DenormAttrs<HTMLTableCaptionElement>, ...children: DenormChildren[]) => HTMLTableCaptionElement;
|
|
19
|
+
export declare const cite: (attrs?: DenormAttrs<HTMLElement>, ...children: DenormChildren[]) => HTMLElement;
|
|
20
|
+
export declare const code: (attrs?: DenormAttrs<HTMLElement>, ...children: DenormChildren[]) => HTMLElement;
|
|
21
|
+
export declare const col: (attrs?: DenormAttrs<HTMLTableColElement>, ...children: DenormChildren[]) => HTMLTableColElement;
|
|
22
|
+
export declare const colgroup: (attrs?: DenormAttrs<HTMLTableColElement>, ...children: DenormChildren[]) => HTMLTableColElement;
|
|
23
|
+
export declare const data: (attrs?: DenormAttrs<HTMLDataElement>, ...children: DenormChildren[]) => HTMLDataElement;
|
|
24
|
+
export declare const datalist: (attrs?: DenormAttrs<HTMLDataListElement>, ...children: DenormChildren[]) => HTMLDataListElement;
|
|
25
|
+
export declare const dd: (attrs?: DenormAttrs<HTMLElement>, ...children: DenormChildren[]) => HTMLElement;
|
|
26
|
+
export declare const del: (attrs?: DenormAttrs<HTMLModElement>, ...children: DenormChildren[]) => HTMLModElement;
|
|
27
|
+
export declare const details: (attrs?: DenormAttrs<HTMLDetailsElement>, ...children: DenormChildren[]) => HTMLDetailsElement;
|
|
28
|
+
export declare const dfn: (attrs?: DenormAttrs<HTMLElement>, ...children: DenormChildren[]) => HTMLElement;
|
|
29
|
+
export declare const dialog: (attrs?: DenormAttrs<HTMLDialogElement>, ...children: DenormChildren[]) => HTMLDialogElement;
|
|
30
|
+
export declare const div: (attrs?: DenormAttrs<HTMLDivElement>, ...children: DenormChildren[]) => HTMLDivElement;
|
|
31
|
+
export declare const dl: (attrs?: DenormAttrs<HTMLDListElement>, ...children: DenormChildren[]) => HTMLDListElement;
|
|
32
|
+
export declare const dt: (attrs?: DenormAttrs<HTMLElement>, ...children: DenormChildren[]) => HTMLElement;
|
|
33
|
+
export declare const em: (attrs?: DenormAttrs<HTMLElement>, ...children: DenormChildren[]) => HTMLElement;
|
|
34
|
+
export declare const embed: (attrs?: DenormAttrs<HTMLEmbedElement>, ...children: DenormChildren[]) => HTMLEmbedElement;
|
|
35
|
+
export declare const fieldset: (attrs?: DenormAttrs<HTMLFieldSetElement>, ...children: DenormChildren[]) => HTMLFieldSetElement;
|
|
36
|
+
export declare const figcaption: (attrs?: DenormAttrs<HTMLElement>, ...children: DenormChildren[]) => HTMLElement;
|
|
37
|
+
export declare const figure: (attrs?: DenormAttrs<HTMLElement>, ...children: DenormChildren[]) => HTMLElement;
|
|
38
|
+
export declare const footer: (attrs?: DenormAttrs<HTMLElement>, ...children: DenormChildren[]) => HTMLElement;
|
|
39
|
+
export declare const form: (attrs?: DenormAttrs<HTMLFormElement>, ...children: DenormChildren[]) => HTMLFormElement;
|
|
40
|
+
export declare const h1: (attrs?: DenormAttrs<HTMLHeadingElement>, ...children: DenormChildren[]) => HTMLHeadingElement;
|
|
41
|
+
export declare const h2: (attrs?: DenormAttrs<HTMLHeadingElement>, ...children: DenormChildren[]) => HTMLHeadingElement;
|
|
42
|
+
export declare const h3: (attrs?: DenormAttrs<HTMLHeadingElement>, ...children: DenormChildren[]) => HTMLHeadingElement;
|
|
43
|
+
export declare const h4: (attrs?: DenormAttrs<HTMLHeadingElement>, ...children: DenormChildren[]) => HTMLHeadingElement;
|
|
44
|
+
export declare const h5: (attrs?: DenormAttrs<HTMLHeadingElement>, ...children: DenormChildren[]) => HTMLHeadingElement;
|
|
45
|
+
export declare const h6: (attrs?: DenormAttrs<HTMLHeadingElement>, ...children: DenormChildren[]) => HTMLHeadingElement;
|
|
46
|
+
export declare const head: (attrs?: DenormAttrs<HTMLHeadElement>, ...children: DenormChildren[]) => HTMLHeadElement;
|
|
47
|
+
export declare const header: (attrs?: DenormAttrs<HTMLElement>, ...children: DenormChildren[]) => HTMLElement;
|
|
48
|
+
export declare const hgroup: (attrs?: DenormAttrs<HTMLElement>, ...children: DenormChildren[]) => HTMLElement;
|
|
49
|
+
export declare const hr: (attrs?: DenormAttrs<HTMLHRElement>, ...children: DenormChildren[]) => HTMLHRElement;
|
|
50
|
+
export declare const html: (attrs?: DenormAttrs<HTMLHtmlElement>, ...children: DenormChildren[]) => HTMLHtmlElement;
|
|
51
|
+
export declare const i: (attrs?: DenormAttrs<HTMLElement>, ...children: DenormChildren[]) => HTMLElement;
|
|
52
|
+
export declare const iframe: (attrs?: DenormAttrs<HTMLIFrameElement>, ...children: DenormChildren[]) => HTMLIFrameElement;
|
|
53
|
+
export declare const img: (attrs?: DenormAttrs<HTMLImageElement>, ...children: DenormChildren[]) => HTMLImageElement;
|
|
54
|
+
export declare const input: (attrs?: DenormAttrs<HTMLInputElement>, ...children: DenormChildren[]) => HTMLInputElement;
|
|
55
|
+
export declare const ins: (attrs?: DenormAttrs<HTMLModElement>, ...children: DenormChildren[]) => HTMLModElement;
|
|
56
|
+
export declare const kbd: (attrs?: DenormAttrs<HTMLElement>, ...children: DenormChildren[]) => HTMLElement;
|
|
57
|
+
export declare const label: (attrs?: DenormAttrs<HTMLLabelElement>, ...children: DenormChildren[]) => HTMLLabelElement;
|
|
58
|
+
export declare const legend: (attrs?: DenormAttrs<HTMLLegendElement>, ...children: DenormChildren[]) => HTMLLegendElement;
|
|
59
|
+
export declare const li: (attrs?: DenormAttrs<HTMLLIElement>, ...children: DenormChildren[]) => HTMLLIElement;
|
|
60
|
+
export declare const link: (attrs?: DenormAttrs<HTMLLinkElement>, ...children: DenormChildren[]) => HTMLLinkElement;
|
|
61
|
+
export declare const main: (attrs?: DenormAttrs<HTMLElement>, ...children: DenormChildren[]) => HTMLElement;
|
|
62
|
+
export declare const map: (attrs?: DenormAttrs<HTMLMapElement>, ...children: DenormChildren[]) => HTMLMapElement;
|
|
63
|
+
export declare const mark: (attrs?: DenormAttrs<HTMLElement>, ...children: DenormChildren[]) => HTMLElement;
|
|
64
|
+
export declare const menu: (attrs?: DenormAttrs<HTMLMenuElement>, ...children: DenormChildren[]) => HTMLMenuElement;
|
|
65
|
+
export declare const meta: (attrs?: DenormAttrs<HTMLMetaElement>, ...children: DenormChildren[]) => HTMLMetaElement;
|
|
66
|
+
export declare const meter: (attrs?: DenormAttrs<HTMLMeterElement>, ...children: DenormChildren[]) => HTMLMeterElement;
|
|
67
|
+
export declare const nav: (attrs?: DenormAttrs<HTMLElement>, ...children: DenormChildren[]) => HTMLElement;
|
|
68
|
+
export declare const noscript: (attrs?: DenormAttrs<HTMLElement>, ...children: DenormChildren[]) => HTMLElement;
|
|
69
|
+
export declare const object: (attrs?: DenormAttrs<HTMLObjectElement>, ...children: DenormChildren[]) => HTMLObjectElement;
|
|
70
|
+
export declare const ol: (attrs?: DenormAttrs<HTMLOListElement>, ...children: DenormChildren[]) => HTMLOListElement;
|
|
71
|
+
export declare const optgroup: (attrs?: DenormAttrs<HTMLOptGroupElement>, ...children: DenormChildren[]) => HTMLOptGroupElement;
|
|
72
|
+
export declare const option: (attrs?: DenormAttrs<HTMLOptionElement>, ...children: DenormChildren[]) => HTMLOptionElement;
|
|
73
|
+
export declare const output: (attrs?: DenormAttrs<HTMLOutputElement>, ...children: DenormChildren[]) => HTMLOutputElement;
|
|
74
|
+
export declare const p: (attrs?: DenormAttrs<HTMLParagraphElement>, ...children: DenormChildren[]) => HTMLParagraphElement;
|
|
75
|
+
export declare const picture: (attrs?: DenormAttrs<HTMLPictureElement>, ...children: DenormChildren[]) => HTMLPictureElement;
|
|
76
|
+
export declare const pre: (attrs?: DenormAttrs<HTMLPreElement>, ...children: DenormChildren[]) => HTMLPreElement;
|
|
77
|
+
export declare const progress: (attrs?: DenormAttrs<HTMLProgressElement>, ...children: DenormChildren[]) => HTMLProgressElement;
|
|
78
|
+
export declare const q: (attrs?: DenormAttrs<HTMLQuoteElement>, ...children: DenormChildren[]) => HTMLQuoteElement;
|
|
79
|
+
export declare const rp: (attrs?: DenormAttrs<HTMLElement>, ...children: DenormChildren[]) => HTMLElement;
|
|
80
|
+
export declare const rt: (attrs?: DenormAttrs<HTMLElement>, ...children: DenormChildren[]) => HTMLElement;
|
|
81
|
+
export declare const ruby: (attrs?: DenormAttrs<HTMLElement>, ...children: DenormChildren[]) => HTMLElement;
|
|
82
|
+
export declare const s: (attrs?: DenormAttrs<HTMLElement>, ...children: DenormChildren[]) => HTMLElement;
|
|
83
|
+
export declare const samp: (attrs?: DenormAttrs<HTMLElement>, ...children: DenormChildren[]) => HTMLElement;
|
|
84
|
+
export declare const script: (attrs?: DenormAttrs<HTMLScriptElement>, ...children: DenormChildren[]) => HTMLScriptElement;
|
|
85
|
+
export declare const section: (attrs?: DenormAttrs<HTMLElement>, ...children: DenormChildren[]) => HTMLElement;
|
|
86
|
+
export declare const select: (attrs?: DenormAttrs<HTMLSelectElement>, ...children: DenormChildren[]) => HTMLSelectElement;
|
|
87
|
+
export declare const slot: (attrs?: DenormAttrs<HTMLSlotElement>, ...children: DenormChildren[]) => HTMLSlotElement;
|
|
88
|
+
export declare const small: (attrs?: DenormAttrs<HTMLElement>, ...children: DenormChildren[]) => HTMLElement;
|
|
89
|
+
export declare const source: (attrs?: DenormAttrs<HTMLSourceElement>, ...children: DenormChildren[]) => HTMLSourceElement;
|
|
90
|
+
export declare const span: (attrs?: DenormAttrs<HTMLSpanElement>, ...children: DenormChildren[]) => HTMLSpanElement;
|
|
91
|
+
export declare const strong: (attrs?: DenormAttrs<HTMLElement>, ...children: DenormChildren[]) => HTMLElement;
|
|
92
|
+
export declare const style: (attrs?: DenormAttrs<HTMLStyleElement>, ...children: DenormChildren[]) => HTMLStyleElement;
|
|
93
|
+
export declare const sub: (attrs?: DenormAttrs<HTMLElement>, ...children: DenormChildren[]) => HTMLElement;
|
|
94
|
+
export declare const summary: (attrs?: DenormAttrs<HTMLElement>, ...children: DenormChildren[]) => HTMLElement;
|
|
95
|
+
export declare const sup: (attrs?: DenormAttrs<HTMLElement>, ...children: DenormChildren[]) => HTMLElement;
|
|
96
|
+
export declare const table: (attrs?: DenormAttrs<HTMLTableElement>, ...children: DenormChildren[]) => HTMLTableElement;
|
|
97
|
+
export declare const tbody: (attrs?: DenormAttrs<HTMLTableSectionElement>, ...children: DenormChildren[]) => HTMLTableSectionElement;
|
|
98
|
+
export declare const td: (attrs?: DenormAttrs<HTMLTableCellElement>, ...children: DenormChildren[]) => HTMLTableCellElement;
|
|
99
|
+
export declare const template: (attrs?: DenormAttrs<HTMLTemplateElement>, ...children: DenormChildren[]) => HTMLTemplateElement;
|
|
100
|
+
export declare const textarea: (attrs?: DenormAttrs<HTMLTextAreaElement>, ...children: DenormChildren[]) => HTMLTextAreaElement;
|
|
101
|
+
export declare const tfoot: (attrs?: DenormAttrs<HTMLTableSectionElement>, ...children: DenormChildren[]) => HTMLTableSectionElement;
|
|
102
|
+
export declare const th: (attrs?: DenormAttrs<HTMLTableCellElement>, ...children: DenormChildren[]) => HTMLTableCellElement;
|
|
103
|
+
export declare const thead: (attrs?: DenormAttrs<HTMLTableSectionElement>, ...children: DenormChildren[]) => HTMLTableSectionElement;
|
|
104
|
+
export declare const time: (attrs?: DenormAttrs<HTMLTimeElement>, ...children: DenormChildren[]) => HTMLTimeElement;
|
|
105
|
+
export declare const title: (attrs?: DenormAttrs<HTMLTitleElement>, ...children: DenormChildren[]) => HTMLTitleElement;
|
|
106
|
+
export declare const tr: (attrs?: DenormAttrs<HTMLTableRowElement>, ...children: DenormChildren[]) => HTMLTableRowElement;
|
|
107
|
+
export declare const track: (attrs?: DenormAttrs<HTMLTrackElement>, ...children: DenormChildren[]) => HTMLTrackElement;
|
|
108
|
+
export declare const u: (attrs?: DenormAttrs<HTMLElement>, ...children: DenormChildren[]) => HTMLElement;
|
|
109
|
+
export declare const ul: (attrs?: DenormAttrs<HTMLUListElement>, ...children: DenormChildren[]) => HTMLUListElement;
|
|
110
|
+
export declare const htmlvar: (attrs?: DenormAttrs<HTMLElement>, ...children: DenormChildren[]) => HTMLElement;
|
|
111
|
+
export declare const video: (attrs?: DenormAttrs<HTMLVideoElement>, ...children: DenormChildren[]) => HTMLVideoElement;
|
|
112
|
+
export declare const wbr: (attrs?: DenormAttrs<HTMLElement>, ...children: DenormChildren[]) => HTMLElement;
|
|
@@ -1,17 +1,5 @@
|
|
|
1
|
-
import {
|
|
2
|
-
|
|
3
|
-
const makeHTMLElement =
|
|
4
|
-
<K extends keyof HTMLElementTagNameMap>(name: K) =>
|
|
5
|
-
(
|
|
6
|
-
attrs?: DenormAttrs<HTMLElementTagNameMap[K]>,
|
|
7
|
-
...children: DenormChildren[]
|
|
8
|
-
) =>
|
|
9
|
-
up(
|
|
10
|
-
window.document.createElement(name),
|
|
11
|
-
attrs,
|
|
12
|
-
...children,
|
|
13
|
-
) as HTMLElementTagNameMap[K];
|
|
14
|
-
|
|
1
|
+
import { up } from "./dom.js";
|
|
2
|
+
const makeHTMLElement = (name) => (attrs, ...children) => up(window.document.createElement(name), attrs, ...children);
|
|
15
3
|
export const a = makeHTMLElement("a");
|
|
16
4
|
export const abbr = makeHTMLElement("abbr");
|
|
17
5
|
export const address = makeHTMLElement("address");
|
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Self-contained IIFE source for the capture stub. Embedded inline by the SSG
|
|
3
|
+
* build pass so events fired before the client bundle loads are queued in
|
|
4
|
+
* window.__hydrateQueue and replayed after hydration. No external references.
|
|
5
|
+
*/
|
|
6
|
+
export declare const captureStubSource = "(function(){\n window.__hydrateQueue = window.__hydrateQueue || [];\n var queue = window.__hydrateQueue;\n var handler = function(event) {\n var path = event.composedPath();\n var unitEl = null;\n for (var i = 0; i < path.length; i++) {\n var node = path[i];\n if (node instanceof Element && customElements.get(node.localName)) {\n unitEl = node;\n break;\n }\n }\n if (!unitEl) return;\n var target = event.target;\n var targetPath = [];\n var cur = target;\n while (cur !== unitEl) {\n var parent = cur.parentNode;\n var siblings = Array.from(parent.childNodes);\n targetPath.unshift(siblings.indexOf(cur));\n cur = parent;\n }\n queue.push({ unitEl: unitEl, type: event.type, targetPath: targetPath, init: { bubbles: event.bubbles, cancelable: event.cancelable } });\n };\n var types = [\"click\",\"input\",\"change\",\"submit\",\"keydown\"];\n for (var t = 0; t < types.length; t++) {\n document.addEventListener(types[t], handler, true);\n }\n})()";
|
|
7
|
+
/**
|
|
8
|
+
* Serialize `units` to a JSON string safe for embedding in an HTML script tag
|
|
9
|
+
* (angle brackets and ampersands are Unicode-escaped).
|
|
10
|
+
*/
|
|
11
|
+
export declare function buildPayload(units: Record<string, unknown>[]): string;
|
|
12
|
+
/**
|
|
13
|
+
* Read the hydration payload from the `#__hydration` script element embedded
|
|
14
|
+
* by the SSG build step. Returns an empty array when the element is absent.
|
|
15
|
+
*/
|
|
16
|
+
export declare function readPayload(): Record<string, unknown>[];
|
|
17
|
+
/**
|
|
18
|
+
* Scan `root` for registered custom elements and schedule each for hydration.
|
|
19
|
+
* `customElements.whenDefined` resolves as a microtask even when the element
|
|
20
|
+
* is already defined. The callback clears server-rendered children then runs
|
|
21
|
+
* `el.update()`, which re-executes the element's render function and rebuilds
|
|
22
|
+
* its subtree. `root` defaults to `window.document.body`.
|
|
23
|
+
*/
|
|
24
|
+
export declare function start(root?: ParentNode): void;
|
|
25
|
+
/**
|
|
26
|
+
* Install capture-phase listeners on `document` that intercept events
|
|
27
|
+
* targeting nodes inside un-hydrated custom elements and push descriptors into
|
|
28
|
+
* `window.__hydrateQueue`. `start()` drains the queue for each element after
|
|
29
|
+
* `el.update()` runs by calling `drainQueue`.
|
|
30
|
+
*/
|
|
31
|
+
export declare function installCaptureStub(): void;
|
|
32
|
+
/**
|
|
33
|
+
* Hydrate a server-rendered page: call `render` once, reconcile the result
|
|
34
|
+
* into `mount` without replacing existing DOM nodes, and graft event handlers
|
|
35
|
+
* onto kept server nodes. Custom-element boundaries are left for each element
|
|
36
|
+
* to hydrate itself. Use this instead of `start` when the full page tree is
|
|
37
|
+
* produced by a single render function rather than independent custom elements.
|
|
38
|
+
*/
|
|
39
|
+
export declare function hydrateRoot(mount: Element, render: () => Node | Node[]): void;
|
|
@@ -0,0 +1,187 @@
|
|
|
1
|
+
"use client"; // Hydrate runs entirely client side.
|
|
2
|
+
import { reconcileChildren } from "./dom.js";
|
|
3
|
+
/**
|
|
4
|
+
* Self-contained IIFE source for the capture stub. Embedded inline by the SSG
|
|
5
|
+
* build pass so events fired before the client bundle loads are queued in
|
|
6
|
+
* window.__hydrateQueue and replayed after hydration. No external references.
|
|
7
|
+
*/
|
|
8
|
+
export const captureStubSource = `(function(){
|
|
9
|
+
window.__hydrateQueue = window.__hydrateQueue || [];
|
|
10
|
+
var queue = window.__hydrateQueue;
|
|
11
|
+
var handler = function(event) {
|
|
12
|
+
var path = event.composedPath();
|
|
13
|
+
var unitEl = null;
|
|
14
|
+
for (var i = 0; i < path.length; i++) {
|
|
15
|
+
var node = path[i];
|
|
16
|
+
if (node instanceof Element && customElements.get(node.localName)) {
|
|
17
|
+
unitEl = node;
|
|
18
|
+
break;
|
|
19
|
+
}
|
|
20
|
+
}
|
|
21
|
+
if (!unitEl) return;
|
|
22
|
+
var target = event.target;
|
|
23
|
+
var targetPath = [];
|
|
24
|
+
var cur = target;
|
|
25
|
+
while (cur !== unitEl) {
|
|
26
|
+
var parent = cur.parentNode;
|
|
27
|
+
var siblings = Array.from(parent.childNodes);
|
|
28
|
+
targetPath.unshift(siblings.indexOf(cur));
|
|
29
|
+
cur = parent;
|
|
30
|
+
}
|
|
31
|
+
queue.push({ unitEl: unitEl, type: event.type, targetPath: targetPath, init: { bubbles: event.bubbles, cancelable: event.cancelable } });
|
|
32
|
+
};
|
|
33
|
+
var types = ["click","input","change","submit","keydown"];
|
|
34
|
+
for (var t = 0; t < types.length; t++) {
|
|
35
|
+
document.addEventListener(types[t], handler, true);
|
|
36
|
+
}
|
|
37
|
+
})()`;
|
|
38
|
+
/**
|
|
39
|
+
* Serialize `units` to a JSON string safe for embedding in an HTML script tag
|
|
40
|
+
* (angle brackets and ampersands are Unicode-escaped).
|
|
41
|
+
*/
|
|
42
|
+
export function buildPayload(units) {
|
|
43
|
+
return JSON.stringify(units)
|
|
44
|
+
.replace(/&/g, "\\u0026")
|
|
45
|
+
.replace(/</g, "\\u003c")
|
|
46
|
+
.replace(/>/g, "\\u003e");
|
|
47
|
+
}
|
|
48
|
+
/**
|
|
49
|
+
* Read the hydration payload from the `#__hydration` script element embedded
|
|
50
|
+
* by the SSG build step. Returns an empty array when the element is absent.
|
|
51
|
+
*/
|
|
52
|
+
export function readPayload() {
|
|
53
|
+
const el = window.document.getElementById("__hydration");
|
|
54
|
+
if (!el)
|
|
55
|
+
return [];
|
|
56
|
+
return JSON.parse(el.textContent ?? "[]");
|
|
57
|
+
}
|
|
58
|
+
/**
|
|
59
|
+
* Walk `root` depth-first, returning every element whose localName is a
|
|
60
|
+
* defined custom element. Does NOT descend into matched elements — each custom
|
|
61
|
+
* element owns its own subtree; inner elements will be reached by their
|
|
62
|
+
* parent's `el.update()` call, not by `start()`.
|
|
63
|
+
*/
|
|
64
|
+
function scanUnits(root) {
|
|
65
|
+
const results = [];
|
|
66
|
+
const stack = [...root.children].reverse();
|
|
67
|
+
while (stack.length > 0) {
|
|
68
|
+
const el = stack.pop();
|
|
69
|
+
if (customElements.get(el.localName)) {
|
|
70
|
+
results.push(el);
|
|
71
|
+
}
|
|
72
|
+
else {
|
|
73
|
+
for (let i = el.children.length - 1; i >= 0; i--) {
|
|
74
|
+
stack.push(el.children[i]);
|
|
75
|
+
}
|
|
76
|
+
}
|
|
77
|
+
}
|
|
78
|
+
return results;
|
|
79
|
+
}
|
|
80
|
+
/**
|
|
81
|
+
* Scan `root` for registered custom elements and schedule each for hydration.
|
|
82
|
+
* `customElements.whenDefined` resolves as a microtask even when the element
|
|
83
|
+
* is already defined. The callback clears server-rendered children then runs
|
|
84
|
+
* `el.update()`, which re-executes the element's render function and rebuilds
|
|
85
|
+
* its subtree. `root` defaults to `window.document.body`.
|
|
86
|
+
*/
|
|
87
|
+
export function start(root) {
|
|
88
|
+
const r = root ?? window.document.body;
|
|
89
|
+
const units = scanUnits(r);
|
|
90
|
+
const payload = readPayload();
|
|
91
|
+
units.forEach((el, index) => {
|
|
92
|
+
customElements.whenDefined(el.localName).then(() => {
|
|
93
|
+
el.replaceChildren();
|
|
94
|
+
el.update(payload[index]);
|
|
95
|
+
drainQueue(el);
|
|
96
|
+
});
|
|
97
|
+
});
|
|
98
|
+
}
|
|
99
|
+
// Hydrate custom elements inside `root` without clearing their server-rendered
|
|
100
|
+
// children first. `el.update()` reconciles onto the existing DOM so attributes
|
|
101
|
+
// and listeners are grafted in place. Recurses after each element hydrates so
|
|
102
|
+
// parents are always processed before their nested custom elements.
|
|
103
|
+
function startHydrate(root) {
|
|
104
|
+
for (const el of scanUnits(root)) {
|
|
105
|
+
customElements.whenDefined(el.localName).then(() => {
|
|
106
|
+
el.update();
|
|
107
|
+
startHydrate(el);
|
|
108
|
+
});
|
|
109
|
+
}
|
|
110
|
+
}
|
|
111
|
+
function getHydrateQueue() {
|
|
112
|
+
const w = window;
|
|
113
|
+
w.__hydrateQueue ??= [];
|
|
114
|
+
return w.__hydrateQueue;
|
|
115
|
+
}
|
|
116
|
+
/**
|
|
117
|
+
* Install capture-phase listeners on `document` that intercept events
|
|
118
|
+
* targeting nodes inside un-hydrated custom elements and push descriptors into
|
|
119
|
+
* `window.__hydrateQueue`. `start()` drains the queue for each element after
|
|
120
|
+
* `el.update()` runs by calling `drainQueue`.
|
|
121
|
+
*/
|
|
122
|
+
export function installCaptureStub() {
|
|
123
|
+
const queue = getHydrateQueue();
|
|
124
|
+
const handler = (event) => {
|
|
125
|
+
const path = event.composedPath();
|
|
126
|
+
let unitEl = null;
|
|
127
|
+
for (const node of path) {
|
|
128
|
+
if (node instanceof Element && customElements.get(node.localName)) {
|
|
129
|
+
unitEl = node;
|
|
130
|
+
break;
|
|
131
|
+
}
|
|
132
|
+
}
|
|
133
|
+
if (!unitEl)
|
|
134
|
+
return;
|
|
135
|
+
const target = event.target;
|
|
136
|
+
const targetPath = [];
|
|
137
|
+
let cur = target;
|
|
138
|
+
while (cur !== unitEl) {
|
|
139
|
+
const parent = cur.parentNode;
|
|
140
|
+
targetPath.unshift(Array.from(parent.childNodes).indexOf(cur));
|
|
141
|
+
cur = parent;
|
|
142
|
+
}
|
|
143
|
+
queue.push({
|
|
144
|
+
unitEl,
|
|
145
|
+
type: event.type,
|
|
146
|
+
targetPath,
|
|
147
|
+
init: { bubbles: event.bubbles, cancelable: event.cancelable },
|
|
148
|
+
});
|
|
149
|
+
};
|
|
150
|
+
for (const type of ["click", "input", "change", "submit", "keydown"]) {
|
|
151
|
+
window.document.addEventListener(type, handler, true);
|
|
152
|
+
}
|
|
153
|
+
}
|
|
154
|
+
function drainQueue(el) {
|
|
155
|
+
const w = window;
|
|
156
|
+
const allEntries = (w.__hydrateQueue ?? []);
|
|
157
|
+
const mine = allEntries.filter((e) => e.unitEl === el);
|
|
158
|
+
w.__hydrateQueue = allEntries.filter((e) => e.unitEl !== el);
|
|
159
|
+
for (const entry of mine) {
|
|
160
|
+
let node = el;
|
|
161
|
+
let resolved = true;
|
|
162
|
+
for (const idx of entry.targetPath) {
|
|
163
|
+
const child = node.childNodes[idx];
|
|
164
|
+
if (!child) {
|
|
165
|
+
console.warn(`hydrateQueue: path index ${idx} out of range, dropping queued ${entry.type}`);
|
|
166
|
+
resolved = false;
|
|
167
|
+
break;
|
|
168
|
+
}
|
|
169
|
+
node = child;
|
|
170
|
+
}
|
|
171
|
+
if (resolved) {
|
|
172
|
+
node.dispatchEvent(new Event(entry.type, entry.init));
|
|
173
|
+
}
|
|
174
|
+
}
|
|
175
|
+
}
|
|
176
|
+
/**
|
|
177
|
+
* Hydrate a server-rendered page: call `render` once, reconcile the result
|
|
178
|
+
* into `mount` without replacing existing DOM nodes, and graft event handlers
|
|
179
|
+
* onto kept server nodes. Custom-element boundaries are left for each element
|
|
180
|
+
* to hydrate itself. Use this instead of `start` when the full page tree is
|
|
181
|
+
* produced by a single render function rather than independent custom elements.
|
|
182
|
+
*/
|
|
183
|
+
export function hydrateRoot(mount, render) {
|
|
184
|
+
const fresh = [render()].flat();
|
|
185
|
+
reconcileChildren(mount, fresh);
|
|
186
|
+
startHydrate(mount);
|
|
187
|
+
}
|
|
@@ -0,0 +1,76 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Context describing a completed navigation, handed to every `onNavigate` hook
|
|
3
|
+
* (e.g. an analytics pageview). Built by `navigate()` after the head reconcile,
|
|
4
|
+
* so `title` reflects the destination and `url` is absolute.
|
|
5
|
+
*/
|
|
6
|
+
export interface NavigationContext {
|
|
7
|
+
/** Absolute destination URL of the navigation. */
|
|
8
|
+
url: URL;
|
|
9
|
+
/** document.title after the head reconcile for this navigation. */
|
|
10
|
+
title: string;
|
|
11
|
+
/**
|
|
12
|
+
* "first" on initial load; otherwise the navigation's entry kind —
|
|
13
|
+
* "push" | "traverse" | "replace" — mirrored from the NavigateEvent on the
|
|
14
|
+
* interception path. A direct `navigate(url)` with no event, and a "reload",
|
|
15
|
+
* both report "push".
|
|
16
|
+
*/
|
|
17
|
+
type: "first" | "push" | "traverse" | "replace";
|
|
18
|
+
}
|
|
19
|
+
/** A hook registered through `onNavigate`, run once per completed navigation. */
|
|
20
|
+
type NavigateCallback = (ctx: NavigationContext) => void;
|
|
21
|
+
/**
|
|
22
|
+
* Register `cb` to run after every in-app navigation completes (body swapped and
|
|
23
|
+
* hydration scheduled). Invariant: callbacks fire exactly once per navigation,
|
|
24
|
+
* in registration order, with the navigation's `NavigationContext`. Used by
|
|
25
|
+
* shell code such as a GA `page_view`.
|
|
26
|
+
*/
|
|
27
|
+
export declare function onNavigate(cb: NavigateCallback): void;
|
|
28
|
+
/** A hook registered through `onFirstLoad`, run once when the initial page hydrates. */
|
|
29
|
+
type FirstLoadCallback = (ctx: NavigationContext) => void;
|
|
30
|
+
/**
|
|
31
|
+
* Register `cb` to run once, when the initial page hydrates on first document load.
|
|
32
|
+
* Invariant: if registered BEFORE bootstrap, `cb` is queued and fired during
|
|
33
|
+
* bootstrap with the first-load context (`type: "first"`). If registered AFTER first
|
|
34
|
+
* load, `cb` is invoked immediately with the retained context, so a late
|
|
35
|
+
* registration never drops the initial event (design §1). Registering installs no
|
|
36
|
+
* listeners and touches no DOM (import-side-effect-free invariant).
|
|
37
|
+
*/
|
|
38
|
+
export declare function onFirstLoad(cb: FirstLoadCallback): void;
|
|
39
|
+
/**
|
|
40
|
+
* Same-document transition hints the interceptor lifts off the `NavigateEvent`
|
|
41
|
+
* and threads into `navigate()` — the View-Transition guard reads a field only
|
|
42
|
+
* the interception path sees. `hasUAVisualTransition` is true when the browser
|
|
43
|
+
* already ran its own visual transition for this navigation (a cross- to
|
|
44
|
+
* same-document hand-off), so the runtime must NOT start a second one;
|
|
45
|
+
* `navigationType` is the entry kind, reported on the `NavigationContext`. A
|
|
46
|
+
* direct `navigate(url)` (no event) passes neither.
|
|
47
|
+
*/
|
|
48
|
+
interface NavigateOptions {
|
|
49
|
+
hasUAVisualTransition?: boolean;
|
|
50
|
+
navigationType?: "push" | "replace" | "traverse" | "reload";
|
|
51
|
+
}
|
|
52
|
+
/**
|
|
53
|
+
* The shared same-document core the Navigation API interceptor funnels into
|
|
54
|
+
* (design §2). Fetches the destination's built HTML, reconciles `<head>`, swaps
|
|
55
|
+
* `<body>` — inside a View Transition when one is available — imports the
|
|
56
|
+
* destination's page modules, hydrates, then fires `onNavigate`. Resolves when
|
|
57
|
+
* hydration has been scheduled and hooks have fired. If `fetchDocument` fell back
|
|
58
|
+
* to a full load (non-2xx or network error), it returns `null` and this aborts
|
|
59
|
+
* without reconciling, swapping, or firing hooks.
|
|
60
|
+
*/
|
|
61
|
+
export declare function navigate(url: string | URL, options?: NavigateOptions): Promise<void>;
|
|
62
|
+
/**
|
|
63
|
+
* Bootstrap route hydration for the initial document. Explicit entry — NOT run at
|
|
64
|
+
* import time (the module stays side-effect-free; tests and the M3 injected entry
|
|
65
|
+
* decide when this runs). On call it:
|
|
66
|
+
* 1. `start(window.document.body)` — hydrate the server-rendered initial islands
|
|
67
|
+
* in place (reads the initial `#__hydration` payload already in <head>).
|
|
68
|
+
* 2. `installInterceptor()` — register the Navigation API `navigate` listener to
|
|
69
|
+
* capture subsequent in-app navigations, between `start()` and `onFirstLoad`.
|
|
70
|
+
* 3. Build the first-load `NavigationContext`: `url` from `window.location.href`,
|
|
71
|
+
* `title` from `document.title`, `type: "first"`. Store it in `firstLoadContext`.
|
|
72
|
+
* 4. Fire every queued `onFirstLoad` callback once, in registration order.
|
|
73
|
+
* Invariant: `onFirstLoad` fires exactly once per bootstrap.
|
|
74
|
+
*/
|
|
75
|
+
export declare function bootstrap(): Promise<void>;
|
|
76
|
+
export {};
|