@gyral/core 0.0.0 → 0.1.0
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/CHANGELOG.md +7 -0
- package/NOTICE +11 -0
- package/README.md +45 -5
- package/dist/accessible-name.d.ts +19 -0
- package/dist/accessible-name.js +56 -0
- package/dist/accessible-name.js.map +1 -0
- package/dist/children.d.ts +37 -0
- package/dist/children.js +49 -0
- package/dist/children.js.map +1 -0
- package/dist/command.d.ts +63 -0
- package/dist/command.js +26 -0
- package/dist/command.js.map +1 -0
- package/dist/define.d.ts +9 -0
- package/dist/define.js +345 -0
- package/dist/define.js.map +1 -0
- package/dist/devtools-events.d.ts +51 -0
- package/dist/devtools-events.js +3 -0
- package/dist/devtools-events.js.map +1 -0
- package/dist/devtools-off.d.ts +9 -0
- package/dist/devtools-off.js +10 -0
- package/dist/devtools-off.js.map +1 -0
- package/dist/devtools.d.ts +13 -0
- package/dist/devtools.js +66 -0
- package/dist/devtools.js.map +1 -0
- package/dist/drivers-scope.d.ts +15 -0
- package/dist/drivers-scope.js +48 -0
- package/dist/drivers-scope.js.map +1 -0
- package/dist/element-directive.d.ts +20 -0
- package/dist/element-directive.js +31 -0
- package/dist/element-directive.js.map +1 -0
- package/dist/element-types.d.ts +34 -0
- package/dist/element-types.js +2 -0
- package/dist/element-types.js.map +1 -0
- package/dist/focus.d.ts +27 -0
- package/dist/focus.js +30 -0
- package/dist/focus.js.map +1 -0
- package/dist/forms.d.ts +59 -0
- package/dist/forms.js +138 -0
- package/dist/forms.js.map +1 -0
- package/dist/hydration.d.ts +36 -0
- package/dist/hydration.js +72 -0
- package/dist/hydration.js.map +1 -0
- package/dist/index.d.ts +42 -0
- package/dist/index.js +35 -0
- package/dist/index.js.map +1 -0
- package/dist/init.d.ts +7 -0
- package/dist/init.js +10 -0
- package/dist/init.js.map +1 -0
- package/dist/intent.d.ts +25 -0
- package/dist/intent.js +157 -0
- package/dist/intent.js.map +1 -0
- package/dist/internal/interpreter.d.ts +8 -0
- package/dist/internal/interpreter.js +128 -0
- package/dist/internal/interpreter.js.map +1 -0
- package/dist/internal/runtime.d.ts +7 -0
- package/dist/internal/runtime.js +8 -0
- package/dist/internal/runtime.js.map +1 -0
- package/dist/invalid.d.ts +21 -0
- package/dist/invalid.js +70 -0
- package/dist/invalid.js.map +1 -0
- package/dist/invokers.d.ts +15 -0
- package/dist/invokers.js +64 -0
- package/dist/invokers.js.map +1 -0
- package/dist/islands.d.ts +11 -0
- package/dist/islands.js +63 -0
- package/dist/islands.js.map +1 -0
- package/dist/json-safety.d.ts +8 -0
- package/dist/json-safety.js +68 -0
- package/dist/json-safety.js.map +1 -0
- package/dist/light-dom.d.ts +61 -0
- package/dist/light-dom.js +109 -0
- package/dist/light-dom.js.map +1 -0
- package/dist/live-boolean.d.ts +22 -0
- package/dist/live-boolean.js +34 -0
- package/dist/live-boolean.js.map +1 -0
- package/dist/props.d.ts +26 -0
- package/dist/props.js +44 -0
- package/dist/props.js.map +1 -0
- package/dist/random.d.ts +13 -0
- package/dist/random.js +19 -0
- package/dist/random.js.map +1 -0
- package/dist/states.d.ts +7 -0
- package/dist/states.js +23 -0
- package/dist/states.js.map +1 -0
- package/dist/store-binding.d.ts +14 -0
- package/dist/store-binding.js +63 -0
- package/dist/store-binding.js.map +1 -0
- package/dist/store-scope.d.ts +40 -0
- package/dist/store-scope.js +146 -0
- package/dist/store-scope.js.map +1 -0
- package/dist/store.d.ts +114 -0
- package/dist/store.js +129 -0
- package/dist/store.js.map +1 -0
- package/dist/stores-provider.d.ts +6 -0
- package/dist/stores-provider.js +57 -0
- package/dist/stores-provider.js.map +1 -0
- package/dist/styles.d.ts +12 -0
- package/dist/styles.js +11 -0
- package/dist/styles.js.map +1 -0
- package/dist/textarea.d.ts +26 -0
- package/dist/textarea.js +85 -0
- package/dist/textarea.js.map +1 -0
- package/dist/transitions.d.ts +9 -0
- package/dist/transitions.js +26 -0
- package/dist/transitions.js.map +1 -0
- package/dist/types.d.ts +186 -0
- package/dist/types.js +2 -0
- package/dist/types.js.map +1 -0
- package/dist/vite.d.ts +25 -0
- package/dist/vite.js +37 -0
- package/dist/vite.js.map +1 -0
- package/package.json +41 -12
|
@@ -0,0 +1,57 @@
|
|
|
1
|
+
// `<gyral-stores>` as a real element for server rendering (gyral-czi.20, ADR 0013 addendum).
|
|
2
|
+
// On the client a provider is a plain element (scopeFor walks the DOM). On the server it must
|
|
3
|
+
// be a registered element: components find it through Lit's SSR event path, and its instances'
|
|
4
|
+
// states are written to `data-gyral-stores` for the client to restore.
|
|
5
|
+
import { css, html, isServer, LitElement } from 'lit';
|
|
6
|
+
import { warnJsonHazard } from './json-safety.js';
|
|
7
|
+
import { providerScope, STORE_SEED_ATTRIBUTE, STORES_ELEMENT, STORES_REQUEST, } from './store-scope.js';
|
|
8
|
+
const onServer = isServer;
|
|
9
|
+
/** Server-only element: renders `<slot>` in Declarative Shadow DOM, so children show as-is. */
|
|
10
|
+
class GyralStores extends LitElement {
|
|
11
|
+
static { this.styles = css `
|
|
12
|
+
:host {
|
|
13
|
+
display: contents;
|
|
14
|
+
}
|
|
15
|
+
`; }
|
|
16
|
+
#instances;
|
|
17
|
+
/** This subtree's store instances; stores not listed start from their seed or `init`. */
|
|
18
|
+
get instances() {
|
|
19
|
+
return this.#instances;
|
|
20
|
+
}
|
|
21
|
+
set instances(value) {
|
|
22
|
+
this.#instances = value;
|
|
23
|
+
// Written before the attributes render; the client restores it (providerScope()).
|
|
24
|
+
if (value !== undefined && value.length > 0) {
|
|
25
|
+
const seed = Object.fromEntries(value.map((i) => [i.store.name, i.state]));
|
|
26
|
+
for (const [name, state] of Object.entries(seed)) {
|
|
27
|
+
warnJsonHazard(`store "${name}" in <${STORES_ELEMENT}>`, state, 'state');
|
|
28
|
+
}
|
|
29
|
+
this.setAttribute(STORE_SEED_ATTRIBUTE, JSON.stringify(seed));
|
|
30
|
+
}
|
|
31
|
+
}
|
|
32
|
+
constructor() {
|
|
33
|
+
super();
|
|
34
|
+
// Lit's SSR routes a slotted child's events slot → getRootNode() → host, and the root is
|
|
35
|
+
// only this element's shadow root if one exists; the renderer never calls connectedCallback
|
|
36
|
+
// (which would create it), so attach it here.
|
|
37
|
+
this.attachShadow({ mode: 'open' });
|
|
38
|
+
this.addEventListener(STORES_REQUEST, (event) => {
|
|
39
|
+
event.stopPropagation();
|
|
40
|
+
event.detail.registry = providerScope(this);
|
|
41
|
+
});
|
|
42
|
+
}
|
|
43
|
+
render() {
|
|
44
|
+
return html `<slot></slot>`;
|
|
45
|
+
}
|
|
46
|
+
}
|
|
47
|
+
/**
|
|
48
|
+
* Registers `<gyral-stores>` for server renders; `@gyral/ssr` calls it. A no-op in the browser,
|
|
49
|
+
* where a plain `<gyral-stores>` element already scopes stores and the server's shadow root
|
|
50
|
+
* (a `<slot>`) needs no JavaScript. Idempotent.
|
|
51
|
+
*/
|
|
52
|
+
export function defineStoresProvider() {
|
|
53
|
+
if (onServer && customElements.get(STORES_ELEMENT) === undefined) {
|
|
54
|
+
customElements.define(STORES_ELEMENT, GyralStores);
|
|
55
|
+
}
|
|
56
|
+
}
|
|
57
|
+
//# sourceMappingURL=stores-provider.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"stores-provider.js","sourceRoot":"","sources":["../src/stores-provider.ts"],"names":[],"mappings":"AAAA,6FAA6F;AAC7F,8FAA8F;AAC9F,+FAA+F;AAC/F,uEAAuE;AACvE,OAAO,EAAE,GAAG,EAAE,IAAI,EAAE,QAAQ,EAAE,UAAU,EAAE,MAAM,KAAK,CAAC;AACtD,OAAO,EAAE,cAAc,EAAE,MAAM,kBAAkB,CAAC;AAElD,OAAO,EACL,aAAa,EACb,oBAAoB,EACpB,cAAc,EACd,cAAc,GAEf,MAAM,kBAAkB,CAAC;AAE1B,MAAM,QAAQ,GAAY,QAAQ,CAAC;AAEnC,+FAA+F;AAC/F,MAAM,WAAY,SAAQ,UAAU;aAClB,WAAM,GAAG,GAAG,CAAA;;;;GAI3B,CAAC;IAEF,UAAU,CAA0C;IAEpD,yFAAyF;IACzF,IAAI,SAAS;QACX,OAAO,IAAI,CAAC,UAAU,CAAC;IACzB,CAAC;IAED,IAAI,SAAS,CAAC,KAA8C;QAC1D,IAAI,CAAC,UAAU,GAAG,KAAK,CAAC;QACxB,kFAAkF;QAClF,IAAI,KAAK,KAAK,SAAS,IAAI,KAAK,CAAC,MAAM,GAAG,CAAC,EAAE,CAAC;YAC5C,MAAM,IAAI,GAAG,MAAM,CAAC,WAAW,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,CAAC,KAAK,CAAC,IAAI,EAAE,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC;YAC3E,KAAK,MAAM,CAAC,IAAI,EAAE,KAAK,CAAC,IAAI,MAAM,CAAC,OAAO,CAAC,IAAI,CAAC,EAAE,CAAC;gBACjD,cAAc,CAAC,UAAU,IAAI,SAAS,cAAc,GAAG,EAAE,KAAK,EAAE,OAAO,CAAC,CAAC;YAC3E,CAAC;YACD,IAAI,CAAC,YAAY,CAAC,oBAAoB,EAAE,IAAI,CAAC,SAAS,CAAC,IAAI,CAAC,CAAC,CAAC;QAChE,CAAC;IACH,CAAC;IAED;QACE,KAAK,EAAE,CAAC;QACR,yFAAyF;QACzF,4FAA4F;QAC5F,8CAA8C;QAC9C,IAAI,CAAC,YAAY,CAAC,EAAE,IAAI,EAAE,MAAM,EAAE,CAAC,CAAC;QACpC,IAAI,CAAC,gBAAgB,CAAC,cAAc,EAAE,CAAC,KAAK,EAAE,EAAE;YAC9C,KAAK,CAAC,eAAe,EAAE,CAAC;YACvB,KAAoC,CAAC,MAAM,CAAC,QAAQ,GAAG,aAAa,CAAC,IAAI,CAAC,CAAC;QAC9E,CAAC,CAAC,CAAC;IACL,CAAC;IAEkB,MAAM;QACvB,OAAO,IAAI,CAAA,eAAe,CAAC;IAC7B,CAAC;;AAGH;;;;GAIG;AACH,MAAM,UAAU,oBAAoB;IAClC,IAAI,QAAQ,IAAI,cAAc,CAAC,GAAG,CAAC,cAAc,CAAC,KAAK,SAAS,EAAE,CAAC;QACjE,cAAc,CAAC,MAAM,CAAC,cAAc,EAAE,WAAW,CAAC,CAAC;IACrD,CAAC;AACH,CAAC","sourcesContent":["// `<gyral-stores>` as a real element for server rendering (gyral-czi.20, ADR 0013 addendum).\n// On the client a provider is a plain element (scopeFor walks the DOM). On the server it must\n// be a registered element: components find it through Lit's SSR event path, and its instances'\n// states are written to `data-gyral-stores` for the client to restore.\nimport { css, html, isServer, LitElement } from 'lit';\nimport { warnJsonHazard } from './json-safety.js';\nimport type { AnyStoreInstance } from './store.js';\nimport {\n providerScope,\n STORE_SEED_ATTRIBUTE,\n STORES_ELEMENT,\n STORES_REQUEST,\n type StoresRequest,\n} from './store-scope.js';\n\nconst onServer: boolean = isServer;\n\n/** Server-only element: renders `<slot>` in Declarative Shadow DOM, so children show as-is. */\nclass GyralStores extends LitElement {\n static override styles = css`\n :host {\n display: contents;\n }\n `;\n\n #instances: readonly AnyStoreInstance[] | undefined;\n\n /** This subtree's store instances; stores not listed start from their seed or `init`. */\n get instances(): readonly AnyStoreInstance[] | undefined {\n return this.#instances;\n }\n\n set instances(value: readonly AnyStoreInstance[] | undefined) {\n this.#instances = value;\n // Written before the attributes render; the client restores it (providerScope()).\n if (value !== undefined && value.length > 0) {\n const seed = Object.fromEntries(value.map((i) => [i.store.name, i.state]));\n for (const [name, state] of Object.entries(seed)) {\n warnJsonHazard(`store \"${name}\" in <${STORES_ELEMENT}>`, state, 'state');\n }\n this.setAttribute(STORE_SEED_ATTRIBUTE, JSON.stringify(seed));\n }\n }\n\n constructor() {\n super();\n // Lit's SSR routes a slotted child's events slot → getRootNode() → host, and the root is\n // only this element's shadow root if one exists; the renderer never calls connectedCallback\n // (which would create it), so attach it here.\n this.attachShadow({ mode: 'open' });\n this.addEventListener(STORES_REQUEST, (event) => {\n event.stopPropagation();\n (event as CustomEvent<StoresRequest>).detail.registry = providerScope(this);\n });\n }\n\n protected override render(): unknown {\n return html`<slot></slot>`;\n }\n}\n\n/**\n * Registers `<gyral-stores>` for server renders; `@gyral/ssr` calls it. A no-op in the browser,\n * where a plain `<gyral-stores>` element already scopes stores and the server's shadow root\n * (a `<slot>`) needs no JavaScript. Idempotent.\n */\nexport function defineStoresProvider(): void {\n if (onServer && customElements.get(STORES_ELEMENT) === undefined) {\n customElements.define(STORES_ELEMENT, GyralStores);\n }\n}\n"]}
|
package/dist/styles.d.ts
ADDED
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
import { type CSSResultGroup, type CSSResultOrNative } from 'lit';
|
|
2
|
+
/**
|
|
3
|
+
* What `spec.styles` accepts:
|
|
4
|
+
* - `css` tagged templates (Lit's `CSSResult`);
|
|
5
|
+
* - plain strings, e.g. a stylesheet module shared with the document (`import base from
|
|
6
|
+
* './base.css?raw'`). Strings are trusted CSS from your own code, never user input;
|
|
7
|
+
* - `CSSStyleSheet` instances (constructable stylesheets, shared across components);
|
|
8
|
+
* - arrays of any of these, nested freely.
|
|
9
|
+
*/
|
|
10
|
+
export type Styles = CSSResultOrNative | string | readonly Styles[];
|
|
11
|
+
/** Normalizes `Styles` into what Lit's `static styles` expects. */
|
|
12
|
+
export declare function toCssResultGroup(styles: Styles): CSSResultGroup;
|
package/dist/styles.js
ADDED
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
// Component styles (gyral-czi.24): `css` templates, plain strings or constructed sheets.
|
|
2
|
+
import { unsafeCSS } from 'lit';
|
|
3
|
+
/** Normalizes `Styles` into what Lit's `static styles` expects. */
|
|
4
|
+
export function toCssResultGroup(styles) {
|
|
5
|
+
if (typeof styles === 'string')
|
|
6
|
+
return unsafeCSS(styles);
|
|
7
|
+
if (Array.isArray(styles))
|
|
8
|
+
return styles.map(toCssResultGroup);
|
|
9
|
+
return styles;
|
|
10
|
+
}
|
|
11
|
+
//# sourceMappingURL=styles.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"styles.js","sourceRoot":"","sources":["../src/styles.ts"],"names":[],"mappings":"AAAA,yFAAyF;AACzF,OAAO,EAAE,SAAS,EAA+C,MAAM,KAAK,CAAC;AAY7E,mEAAmE;AACnE,MAAM,UAAU,gBAAgB,CAAC,MAAc;IAC7C,IAAI,OAAO,MAAM,KAAK,QAAQ;QAAE,OAAO,SAAS,CAAC,MAAM,CAAC,CAAC;IACzD,IAAI,KAAK,CAAC,OAAO,CAAC,MAAM,CAAC;QAAE,OAAQ,MAA4B,CAAC,GAAG,CAAC,gBAAgB,CAAC,CAAC;IACtF,OAAO,MAA2B,CAAC;AACrC,CAAC","sourcesContent":["// Component styles (gyral-czi.24): `css` templates, plain strings or constructed sheets.\nimport { unsafeCSS, type CSSResultGroup, type CSSResultOrNative } from 'lit';\n\n/**\n * What `spec.styles` accepts:\n * - `css` tagged templates (Lit's `CSSResult`);\n * - plain strings, e.g. a stylesheet module shared with the document (`import base from\n * './base.css?raw'`). Strings are trusted CSS from your own code, never user input;\n * - `CSSStyleSheet` instances (constructable stylesheets, shared across components);\n * - arrays of any of these, nested freely.\n */\nexport type Styles = CSSResultOrNative | string | readonly Styles[];\n\n/** Normalizes `Styles` into what Lit's `static styles` expects. */\nexport function toCssResultGroup(styles: Styles): CSSResultGroup {\n if (typeof styles === 'string') return unsafeCSS(styles);\n if (Array.isArray(styles)) return (styles as readonly Styles[]).map(toCssResultGroup);\n return styles as CSSResultOrNative;\n}\n"]}
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
import { Directive, type ChildPart, type PartInfo } from 'lit/directive.js';
|
|
2
|
+
export type TextareaAttribute = string | number | boolean | null | undefined;
|
|
3
|
+
export interface TextareaOptions {
|
|
4
|
+
/** The model's value. Applied to the live element only when the model changes. */
|
|
5
|
+
readonly value: string;
|
|
6
|
+
/** Attributes such as name, id, rows, required, maxlength, data-intent, aria-invalid. */
|
|
7
|
+
readonly attrs?: Readonly<Record<string, TextareaAttribute>>;
|
|
8
|
+
}
|
|
9
|
+
/** The markup the server writes, and the client's first render: escaped, no bindings inside. */
|
|
10
|
+
export declare function textareaMarkup({ value, attrs }: TextareaOptions): string;
|
|
11
|
+
declare class TextareaDirective extends Directive {
|
|
12
|
+
#private;
|
|
13
|
+
constructor(info: PartInfo);
|
|
14
|
+
render(options: TextareaOptions): unknown;
|
|
15
|
+
update(part: ChildPart, [options]: [TextareaOptions]): unknown;
|
|
16
|
+
}
|
|
17
|
+
/**
|
|
18
|
+
* A `<textarea>` whose content comes from the model, safe for SSR and hydration:
|
|
19
|
+
*
|
|
20
|
+
* ${textarea({ value: s.message, attrs: { name: 'message', rows: 5, required: true,
|
|
21
|
+
* 'data-intent': i.Message } })}
|
|
22
|
+
*
|
|
23
|
+
* Text typed before or after hydration is kept until the model's value changes.
|
|
24
|
+
*/
|
|
25
|
+
export declare const textarea: (options: TextareaOptions) => import("lit/directive.js").DirectiveResult<typeof TextareaDirective>;
|
|
26
|
+
export {};
|
package/dist/textarea.js
ADDED
|
@@ -0,0 +1,85 @@
|
|
|
1
|
+
// <textarea> support (gyral-czi.34). Lit can't bind inside <textarea>: its content is raw
|
|
2
|
+
// text, so `html\`<textarea>${v}</textarea>\`` throws during SSR ("Unexpected final
|
|
3
|
+
// partIndex") and never updates in the browser. `textarea()` renders the element as a static,
|
|
4
|
+
// escaped template (correct no-JS markup and a hydration match), then keeps it in sync by
|
|
5
|
+
// setting properties and attributes on the same element.
|
|
6
|
+
import { noChange } from 'lit';
|
|
7
|
+
import { Directive, directive, PartType } from 'lit/directive.js';
|
|
8
|
+
import { html as staticHtml, unsafeStatic } from 'lit/static-html.js';
|
|
9
|
+
const escapeText = (s) => s.replace(/&/g, '&').replace(/</g, '<').replace(/>/g, '>');
|
|
10
|
+
const escapeAttr = (s) => escapeText(s).replace(/"/g, '"');
|
|
11
|
+
const ATTR_NAME = /^[a-zA-Z_:][-a-zA-Z0-9_:.]*$/;
|
|
12
|
+
function attrMarkup(attrs) {
|
|
13
|
+
return Object.entries(attrs ?? {})
|
|
14
|
+
.map(([name, value]) => {
|
|
15
|
+
if (!ATTR_NAME.test(name))
|
|
16
|
+
throw new Error(`textarea(): invalid attribute name "${name}"`);
|
|
17
|
+
if (value === false || value === null || value === undefined)
|
|
18
|
+
return '';
|
|
19
|
+
return value === true ? ` ${name}` : ` ${name}="${escapeAttr(String(value))}"`;
|
|
20
|
+
})
|
|
21
|
+
.join('');
|
|
22
|
+
}
|
|
23
|
+
/** The markup the server writes, and the client's first render: escaped, no bindings inside. */
|
|
24
|
+
export function textareaMarkup({ value, attrs }) {
|
|
25
|
+
return `<textarea${attrMarkup(attrs)}>${escapeText(value)}</textarea>`;
|
|
26
|
+
}
|
|
27
|
+
function findTextarea(part) {
|
|
28
|
+
for (let node = part.startNode?.nextSibling; node && node !== part.endNode; node = node.nextSibling) {
|
|
29
|
+
if (node instanceof HTMLTextAreaElement)
|
|
30
|
+
return node;
|
|
31
|
+
}
|
|
32
|
+
return undefined;
|
|
33
|
+
}
|
|
34
|
+
function syncAttributes(el, attrs) {
|
|
35
|
+
for (const [name, value] of Object.entries(attrs ?? {})) {
|
|
36
|
+
if (value === false || value === null || value === undefined)
|
|
37
|
+
el.removeAttribute(name);
|
|
38
|
+
else
|
|
39
|
+
el.setAttribute(name, value === true ? '' : String(value));
|
|
40
|
+
}
|
|
41
|
+
}
|
|
42
|
+
class TextareaDirective extends Directive {
|
|
43
|
+
/** The model value last applied, so typing isn't overwritten by an unchanged model. */
|
|
44
|
+
#applied;
|
|
45
|
+
constructor(info) {
|
|
46
|
+
super(info);
|
|
47
|
+
if (info.type !== PartType.CHILD) {
|
|
48
|
+
throw new Error('textarea() must be used in a child position: html`${textarea({…})}`');
|
|
49
|
+
}
|
|
50
|
+
}
|
|
51
|
+
render(options) {
|
|
52
|
+
return staticHtml `${unsafeStatic(textareaMarkup(options))}`;
|
|
53
|
+
}
|
|
54
|
+
update(part, [options]) {
|
|
55
|
+
const el = findTextarea(part);
|
|
56
|
+
if (el === undefined) {
|
|
57
|
+
// First render (client) or hydration (server markup already in place): same template.
|
|
58
|
+
this.#applied = options.value;
|
|
59
|
+
return this.render(options);
|
|
60
|
+
}
|
|
61
|
+
syncAttributes(el, options.attrs);
|
|
62
|
+
if (this.#applied === undefined) {
|
|
63
|
+
// Hydration: the server's element is already here. Keep whatever the user typed before
|
|
64
|
+
// the script loaded; only later model changes write the value.
|
|
65
|
+
this.#applied = options.value;
|
|
66
|
+
return noChange;
|
|
67
|
+
}
|
|
68
|
+
if (options.value !== this.#applied) {
|
|
69
|
+
this.#applied = options.value;
|
|
70
|
+
if (el.value !== options.value)
|
|
71
|
+
el.value = options.value;
|
|
72
|
+
}
|
|
73
|
+
return noChange;
|
|
74
|
+
}
|
|
75
|
+
}
|
|
76
|
+
/**
|
|
77
|
+
* A `<textarea>` whose content comes from the model, safe for SSR and hydration:
|
|
78
|
+
*
|
|
79
|
+
* ${textarea({ value: s.message, attrs: { name: 'message', rows: 5, required: true,
|
|
80
|
+
* 'data-intent': i.Message } })}
|
|
81
|
+
*
|
|
82
|
+
* Text typed before or after hydration is kept until the model's value changes.
|
|
83
|
+
*/
|
|
84
|
+
export const textarea = directive(TextareaDirective);
|
|
85
|
+
//# sourceMappingURL=textarea.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"textarea.js","sourceRoot":"","sources":["../src/textarea.ts"],"names":[],"mappings":"AAAA,0FAA0F;AAC1F,oFAAoF;AACpF,8FAA8F;AAC9F,0FAA0F;AAC1F,yDAAyD;AACzD,OAAO,EAAE,QAAQ,EAAE,MAAM,KAAK,CAAC;AAC/B,OAAO,EAAE,SAAS,EAAE,SAAS,EAAE,QAAQ,EAAiC,MAAM,kBAAkB,CAAC;AACjG,OAAO,EAAE,IAAI,IAAI,UAAU,EAAE,YAAY,EAAE,MAAM,oBAAoB,CAAC;AAWtE,MAAM,UAAU,GAAG,CAAC,CAAS,EAAU,EAAE,CACvC,CAAC,CAAC,OAAO,CAAC,IAAI,EAAE,OAAO,CAAC,CAAC,OAAO,CAAC,IAAI,EAAE,MAAM,CAAC,CAAC,OAAO,CAAC,IAAI,EAAE,MAAM,CAAC,CAAC;AACvE,MAAM,UAAU,GAAG,CAAC,CAAS,EAAU,EAAE,CAAC,UAAU,CAAC,CAAC,CAAC,CAAC,OAAO,CAAC,IAAI,EAAE,QAAQ,CAAC,CAAC;AAChF,MAAM,SAAS,GAAG,8BAA8B,CAAC;AAEjD,SAAS,UAAU,CAAC,KAA+B;IACjD,OAAO,MAAM,CAAC,OAAO,CAAC,KAAK,IAAI,EAAE,CAAC;SAC/B,GAAG,CAAC,CAAC,CAAC,IAAI,EAAE,KAAK,CAAC,EAAE,EAAE;QACrB,IAAI,CAAC,SAAS,CAAC,IAAI,CAAC,IAAI,CAAC;YAAE,MAAM,IAAI,KAAK,CAAC,uCAAuC,IAAI,GAAG,CAAC,CAAC;QAC3F,IAAI,KAAK,KAAK,KAAK,IAAI,KAAK,KAAK,IAAI,IAAI,KAAK,KAAK,SAAS;YAAE,OAAO,EAAE,CAAC;QACxE,OAAO,KAAK,KAAK,IAAI,CAAC,CAAC,CAAC,IAAI,IAAI,EAAE,CAAC,CAAC,CAAC,IAAI,IAAI,KAAK,UAAU,CAAC,MAAM,CAAC,KAAK,CAAC,CAAC,GAAG,CAAC;IACjF,CAAC,CAAC;SACD,IAAI,CAAC,EAAE,CAAC,CAAC;AACd,CAAC;AAED,gGAAgG;AAChG,MAAM,UAAU,cAAc,CAAC,EAAE,KAAK,EAAE,KAAK,EAAmB;IAC9D,OAAO,YAAY,UAAU,CAAC,KAAK,CAAC,IAAI,UAAU,CAAC,KAAK,CAAC,aAAa,CAAC;AACzE,CAAC;AAED,SAAS,YAAY,CAAC,IAAe;IACnC,KACE,IAAI,IAAI,GAAG,IAAI,CAAC,SAAS,EAAE,WAAW,EACtC,IAAI,IAAI,IAAI,KAAK,IAAI,CAAC,OAAO,EAC7B,IAAI,GAAG,IAAI,CAAC,WAAW,EACvB,CAAC;QACD,IAAI,IAAI,YAAY,mBAAmB;YAAE,OAAO,IAAI,CAAC;IACvD,CAAC;IACD,OAAO,SAAS,CAAC;AACnB,CAAC;AAED,SAAS,cAAc,CAAC,EAAuB,EAAE,KAA+B;IAC9E,KAAK,MAAM,CAAC,IAAI,EAAE,KAAK,CAAC,IAAI,MAAM,CAAC,OAAO,CAAC,KAAK,IAAI,EAAE,CAAC,EAAE,CAAC;QACxD,IAAI,KAAK,KAAK,KAAK,IAAI,KAAK,KAAK,IAAI,IAAI,KAAK,KAAK,SAAS;YAAE,EAAE,CAAC,eAAe,CAAC,IAAI,CAAC,CAAC;;YAClF,EAAE,CAAC,YAAY,CAAC,IAAI,EAAE,KAAK,KAAK,IAAI,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,MAAM,CAAC,KAAK,CAAC,CAAC,CAAC;IAClE,CAAC;AACH,CAAC;AAED,MAAM,iBAAkB,SAAQ,SAAS;IACvC,uFAAuF;IACvF,QAAQ,CAAqB;IAE7B,YAAY,IAAc;QACxB,KAAK,CAAC,IAAI,CAAC,CAAC;QACZ,IAAI,IAAI,CAAC,IAAI,KAAK,QAAQ,CAAC,KAAK,EAAE,CAAC;YACjC,MAAM,IAAI,KAAK,CAAC,qEAAqE,CAAC,CAAC;QACzF,CAAC;IACH,CAAC;IAEQ,MAAM,CAAC,OAAwB;QACtC,OAAO,UAAU,CAAA,GAAG,YAAY,CAAC,cAAc,CAAC,OAAO,CAAC,CAAC,EAAE,CAAC;IAC9D,CAAC;IAEQ,MAAM,CAAC,IAAe,EAAE,CAAC,OAAO,CAAoB;QAC3D,MAAM,EAAE,GAAG,YAAY,CAAC,IAAI,CAAC,CAAC;QAC9B,IAAI,EAAE,KAAK,SAAS,EAAE,CAAC;YACrB,sFAAsF;YACtF,IAAI,CAAC,QAAQ,GAAG,OAAO,CAAC,KAAK,CAAC;YAC9B,OAAO,IAAI,CAAC,MAAM,CAAC,OAAO,CAAC,CAAC;QAC9B,CAAC;QACD,cAAc,CAAC,EAAE,EAAE,OAAO,CAAC,KAAK,CAAC,CAAC;QAClC,IAAI,IAAI,CAAC,QAAQ,KAAK,SAAS,EAAE,CAAC;YAChC,uFAAuF;YACvF,+DAA+D;YAC/D,IAAI,CAAC,QAAQ,GAAG,OAAO,CAAC,KAAK,CAAC;YAC9B,OAAO,QAAQ,CAAC;QAClB,CAAC;QACD,IAAI,OAAO,CAAC,KAAK,KAAK,IAAI,CAAC,QAAQ,EAAE,CAAC;YACpC,IAAI,CAAC,QAAQ,GAAG,OAAO,CAAC,KAAK,CAAC;YAC9B,IAAI,EAAE,CAAC,KAAK,KAAK,OAAO,CAAC,KAAK;gBAAE,EAAE,CAAC,KAAK,GAAG,OAAO,CAAC,KAAK,CAAC;QAC3D,CAAC;QACD,OAAO,QAAQ,CAAC;IAClB,CAAC;CACF;AAED;;;;;;;GAOG;AACH,MAAM,CAAC,MAAM,QAAQ,GAAG,SAAS,CAAC,iBAAiB,CAAC,CAAC","sourcesContent":["// <textarea> support (gyral-czi.34). Lit can't bind inside <textarea>: its content is raw\n// text, so `html\\`<textarea>${v}</textarea>\\`` throws during SSR (\"Unexpected final\n// partIndex\") and never updates in the browser. `textarea()` renders the element as a static,\n// escaped template (correct no-JS markup and a hydration match), then keeps it in sync by\n// setting properties and attributes on the same element.\nimport { noChange } from 'lit';\nimport { Directive, directive, PartType, type ChildPart, type PartInfo } from 'lit/directive.js';\nimport { html as staticHtml, unsafeStatic } from 'lit/static-html.js';\n\nexport type TextareaAttribute = string | number | boolean | null | undefined;\n\nexport interface TextareaOptions {\n /** The model's value. Applied to the live element only when the model changes. */\n readonly value: string;\n /** Attributes such as name, id, rows, required, maxlength, data-intent, aria-invalid. */\n readonly attrs?: Readonly<Record<string, TextareaAttribute>>;\n}\n\nconst escapeText = (s: string): string =>\n s.replace(/&/g, '&').replace(/</g, '<').replace(/>/g, '>');\nconst escapeAttr = (s: string): string => escapeText(s).replace(/\"/g, '"');\nconst ATTR_NAME = /^[a-zA-Z_:][-a-zA-Z0-9_:.]*$/;\n\nfunction attrMarkup(attrs: TextareaOptions['attrs']): string {\n return Object.entries(attrs ?? {})\n .map(([name, value]) => {\n if (!ATTR_NAME.test(name)) throw new Error(`textarea(): invalid attribute name \"${name}\"`);\n if (value === false || value === null || value === undefined) return '';\n return value === true ? ` ${name}` : ` ${name}=\"${escapeAttr(String(value))}\"`;\n })\n .join('');\n}\n\n/** The markup the server writes, and the client's first render: escaped, no bindings inside. */\nexport function textareaMarkup({ value, attrs }: TextareaOptions): string {\n return `<textarea${attrMarkup(attrs)}>${escapeText(value)}</textarea>`;\n}\n\nfunction findTextarea(part: ChildPart): HTMLTextAreaElement | undefined {\n for (\n let node = part.startNode?.nextSibling;\n node && node !== part.endNode;\n node = node.nextSibling\n ) {\n if (node instanceof HTMLTextAreaElement) return node;\n }\n return undefined;\n}\n\nfunction syncAttributes(el: HTMLTextAreaElement, attrs: TextareaOptions['attrs']): void {\n for (const [name, value] of Object.entries(attrs ?? {})) {\n if (value === false || value === null || value === undefined) el.removeAttribute(name);\n else el.setAttribute(name, value === true ? '' : String(value));\n }\n}\n\nclass TextareaDirective extends Directive {\n /** The model value last applied, so typing isn't overwritten by an unchanged model. */\n #applied: string | undefined;\n\n constructor(info: PartInfo) {\n super(info);\n if (info.type !== PartType.CHILD) {\n throw new Error('textarea() must be used in a child position: html`${textarea({…})}`');\n }\n }\n\n override render(options: TextareaOptions): unknown {\n return staticHtml`${unsafeStatic(textareaMarkup(options))}`;\n }\n\n override update(part: ChildPart, [options]: [TextareaOptions]): unknown {\n const el = findTextarea(part);\n if (el === undefined) {\n // First render (client) or hydration (server markup already in place): same template.\n this.#applied = options.value;\n return this.render(options);\n }\n syncAttributes(el, options.attrs);\n if (this.#applied === undefined) {\n // Hydration: the server's element is already here. Keep whatever the user typed before\n // the script loaded; only later model changes write the value.\n this.#applied = options.value;\n return noChange;\n }\n if (options.value !== this.#applied) {\n this.#applied = options.value;\n if (el.value !== options.value) el.value = options.value;\n }\n return noChange;\n }\n}\n\n/**\n * A `<textarea>` whose content comes from the model, safe for SSR and hydration:\n *\n * ${textarea({ value: s.message, attrs: { name: 'message', rows: 5, required: true,\n * 'data-intent': i.Message } })}\n *\n * Text typed before or after hydration is kept until the model's value changes.\n */\nexport const textarea = directive(TextareaDirective);\n"]}
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
/** True when a view transition may run now (API present, motion not reduced). */
|
|
2
|
+
export declare function canTransition(): boolean;
|
|
3
|
+
/**
|
|
4
|
+
* Runs `update` inside `document.startViewTransition` when allowed, otherwise directly.
|
|
5
|
+
* `update` must resolve once the DOM reflects the new state. The returned promise settles when
|
|
6
|
+
* `update` has run. A transition skipped by a newer one still runs its update (per spec); its
|
|
7
|
+
* rejected `ready` is expected and swallowed.
|
|
8
|
+
*/
|
|
9
|
+
export declare function withViewTransition(update: () => Promise<void>): Promise<void>;
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
// View Transitions for define() components (ADR 0001 addendum). An ADR 0003 enhancement:
|
|
2
|
+
// without the API, or with reduced motion requested, updates render normally.
|
|
3
|
+
const supportsViewTransitions = (doc) => 'startViewTransition' in doc;
|
|
4
|
+
const ignore = () => undefined;
|
|
5
|
+
/** True when a view transition may run now (API present, motion not reduced). */
|
|
6
|
+
export function canTransition() {
|
|
7
|
+
if (typeof document === 'undefined' || !supportsViewTransitions(document))
|
|
8
|
+
return false;
|
|
9
|
+
return !window.matchMedia('(prefers-reduced-motion: reduce)').matches;
|
|
10
|
+
}
|
|
11
|
+
/**
|
|
12
|
+
* Runs `update` inside `document.startViewTransition` when allowed, otherwise directly.
|
|
13
|
+
* `update` must resolve once the DOM reflects the new state. The returned promise settles when
|
|
14
|
+
* `update` has run. A transition skipped by a newer one still runs its update (per spec); its
|
|
15
|
+
* rejected `ready` is expected and swallowed.
|
|
16
|
+
*/
|
|
17
|
+
export function withViewTransition(update) {
|
|
18
|
+
if (!canTransition() || !supportsViewTransitions(document))
|
|
19
|
+
return update();
|
|
20
|
+
return new Promise((resolve, reject) => {
|
|
21
|
+
const transition = document.startViewTransition(() => update().then(resolve, reject));
|
|
22
|
+
transition.ready.catch(ignore);
|
|
23
|
+
transition.finished.catch(ignore);
|
|
24
|
+
});
|
|
25
|
+
}
|
|
26
|
+
//# sourceMappingURL=transitions.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"transitions.js","sourceRoot":"","sources":["../src/transitions.ts"],"names":[],"mappings":"AAAA,yFAAyF;AACzF,8EAA8E;AAW9E,MAAM,uBAAuB,GAAG,CAAC,GAAa,EAA4C,EAAE,CAC1F,qBAAqB,IAAI,GAAG,CAAC;AAE/B,MAAM,MAAM,GAAG,GAAS,EAAE,CAAC,SAAS,CAAC;AAErC,iFAAiF;AACjF,MAAM,UAAU,aAAa;IAC3B,IAAI,OAAO,QAAQ,KAAK,WAAW,IAAI,CAAC,uBAAuB,CAAC,QAAQ,CAAC;QAAE,OAAO,KAAK,CAAC;IACxF,OAAO,CAAC,MAAM,CAAC,UAAU,CAAC,kCAAkC,CAAC,CAAC,OAAO,CAAC;AACxE,CAAC;AAED;;;;;GAKG;AACH,MAAM,UAAU,kBAAkB,CAAC,MAA2B;IAC5D,IAAI,CAAC,aAAa,EAAE,IAAI,CAAC,uBAAuB,CAAC,QAAQ,CAAC;QAAE,OAAO,MAAM,EAAE,CAAC;IAC5E,OAAO,IAAI,OAAO,CAAC,CAAC,OAAO,EAAE,MAAM,EAAE,EAAE;QACrC,MAAM,UAAU,GAAG,QAAQ,CAAC,mBAAmB,CAAC,GAAG,EAAE,CAAC,MAAM,EAAE,CAAC,IAAI,CAAC,OAAO,EAAE,MAAM,CAAC,CAAC,CAAC;QACtF,UAAU,CAAC,KAAK,CAAC,KAAK,CAAC,MAAM,CAAC,CAAC;QAC/B,UAAU,CAAC,QAAQ,CAAC,KAAK,CAAC,MAAM,CAAC,CAAC;IACpC,CAAC,CAAC,CAAC;AACL,CAAC","sourcesContent":["// View Transitions for define() components (ADR 0001 addendum). An ADR 0003 enhancement:\n// without the API, or with reduced motion requested, updates render normally.\n\ninterface ViewTransitionLike {\n readonly ready: Promise<unknown>;\n readonly finished: Promise<unknown>;\n}\n\ninterface ViewTransitionDocument {\n startViewTransition(update: () => Promise<void>): ViewTransitionLike;\n}\n\nconst supportsViewTransitions = (doc: Document): doc is Document & ViewTransitionDocument =>\n 'startViewTransition' in doc;\n\nconst ignore = (): void => undefined;\n\n/** True when a view transition may run now (API present, motion not reduced). */\nexport function canTransition(): boolean {\n if (typeof document === 'undefined' || !supportsViewTransitions(document)) return false;\n return !window.matchMedia('(prefers-reduced-motion: reduce)').matches;\n}\n\n/**\n * Runs `update` inside `document.startViewTransition` when allowed, otherwise directly.\n * `update` must resolve once the DOM reflects the new state. The returned promise settles when\n * `update` has run. A transition skipped by a newer one still runs its update (per spec); its\n * rejected `ready` is expected and swallowed.\n */\nexport function withViewTransition(update: () => Promise<void>): Promise<void> {\n if (!canTransition() || !supportsViewTransitions(document)) return update();\n return new Promise((resolve, reject) => {\n const transition = document.startViewTransition(() => update().then(resolve, reject));\n transition.ready.catch(ignore);\n transition.finished.catch(ignore);\n });\n}\n"]}
|
package/dist/types.d.ts
ADDED
|
@@ -0,0 +1,186 @@
|
|
|
1
|
+
import type { PropertyDeclaration } from 'lit';
|
|
2
|
+
import type { Styles } from './styles.js';
|
|
3
|
+
import type { CommandInfo } from './invokers.js';
|
|
4
|
+
import type { HydrateStrategy } from './islands.js';
|
|
5
|
+
import type { DriverOverrides, Next } from './command.js';
|
|
6
|
+
import type { AnyStore, StoreChanged, StoreRef } from './store.js';
|
|
7
|
+
/** Every message is a tagged object; the tag is also the intent name used in markup. */
|
|
8
|
+
export interface Tagged {
|
|
9
|
+
readonly _tag: string;
|
|
10
|
+
}
|
|
11
|
+
/** What the intent layer sees when a `data-intent` element fires its trigger event. */
|
|
12
|
+
export interface IntentInput {
|
|
13
|
+
/** The `data-intent` value (a message tag). */
|
|
14
|
+
readonly name: string;
|
|
15
|
+
readonly event: Event;
|
|
16
|
+
/** The element carrying `data-intent`. */
|
|
17
|
+
readonly target: Element;
|
|
18
|
+
/** `value` of the input, select, textarea or button that carries the intent. */
|
|
19
|
+
readonly value: string | undefined;
|
|
20
|
+
/** `checked` for checkbox and radio inputs. */
|
|
21
|
+
readonly checked: boolean | undefined;
|
|
22
|
+
/** Submitted data (including the submitter button) when the intent is on a `<form>`. */
|
|
23
|
+
readonly formData: FormData | undefined;
|
|
24
|
+
/** The output a child component emitted, when the intent is on a child element. */
|
|
25
|
+
readonly detail: unknown;
|
|
26
|
+
/** `KeyboardEvent.key` for `keydown`/`keyup` intents. */
|
|
27
|
+
readonly key: string | undefined;
|
|
28
|
+
/** For `toggle` intents (popover, `<details>`): the state it changed to. */
|
|
29
|
+
readonly newState: 'open' | 'closed' | undefined;
|
|
30
|
+
/** For `command` intents: the invoker's command (e.g. `--clear`) and source (gyral-czi.6). */
|
|
31
|
+
readonly command: CommandInfo | undefined;
|
|
32
|
+
}
|
|
33
|
+
/** Reads a declared store's current state, typed by the store (ADR 0013). */
|
|
34
|
+
export type StoreReader = <S>(store: StoreRef<S>) => S;
|
|
35
|
+
/** Read-only context handed to every reducer and to the view (ADR 0007, 0013). */
|
|
36
|
+
export interface Ctx<P> {
|
|
37
|
+
/** Props from above. */
|
|
38
|
+
readonly props: P;
|
|
39
|
+
/** Stores from the side: `read(cart).lines`. The store must be in `spec.stores`. */
|
|
40
|
+
readonly read: StoreReader;
|
|
41
|
+
}
|
|
42
|
+
/** Framework message: declared props changed after the first render (ADR 0007). */
|
|
43
|
+
export interface PropsChanged<P> {
|
|
44
|
+
readonly _tag: 'PropsChanged';
|
|
45
|
+
readonly props: P;
|
|
46
|
+
readonly prev: P;
|
|
47
|
+
}
|
|
48
|
+
/**
|
|
49
|
+
* Framework message: the component is live in the browser (ADR 0012 addendum). Sent once,
|
|
50
|
+
* after the first client render has completed, to every client-side instance. Use it for
|
|
51
|
+
* progressive enhancement: render the no-JS form on the server and in the first client render
|
|
52
|
+
* (so hydration matches), then switch to the enhanced UI in the `Hydrated` reducer.
|
|
53
|
+
*/
|
|
54
|
+
export interface Hydrated {
|
|
55
|
+
readonly _tag: 'Hydrated';
|
|
56
|
+
/** `true` when the instance resumed from server-rendered markup (a hydration seed). */
|
|
57
|
+
readonly serverRendered: boolean;
|
|
58
|
+
}
|
|
59
|
+
/** One validation problem. `path` is dot-joined and matches the field's `name`. */
|
|
60
|
+
export interface FieldIssue {
|
|
61
|
+
readonly path: string;
|
|
62
|
+
readonly message: string;
|
|
63
|
+
}
|
|
64
|
+
/** Submitted text values of a form (Files are dropped: they can't be re-filled). */
|
|
65
|
+
export type FormFields = Readonly<Record<string, string | readonly string[]>>;
|
|
66
|
+
/** Framework message: an intent's input failed schema validation (ADR 0008). */
|
|
67
|
+
export interface IntentRejected {
|
|
68
|
+
readonly _tag: 'IntentRejected';
|
|
69
|
+
/** The `data-intent` name whose input was rejected. */
|
|
70
|
+
readonly intent: string;
|
|
71
|
+
readonly issues: readonly FieldIssue[];
|
|
72
|
+
/**
|
|
73
|
+
* For `form()` rejections: what the user submitted, so the view can re-fill the form. On
|
|
74
|
+
* the no-JS path (ADR 0008 server half) the server re-renders the page from this.
|
|
75
|
+
*/
|
|
76
|
+
readonly values?: FormFields | undefined;
|
|
77
|
+
}
|
|
78
|
+
type ParseResult<M> = M | IntentRejected | undefined;
|
|
79
|
+
/**
|
|
80
|
+
* Parses a platform event into one message variant, `IntentRejected`, or `undefined` to
|
|
81
|
+
* ignore it. May be async because schema validation may be.
|
|
82
|
+
*/
|
|
83
|
+
export type IntentParser<M> = (input: IntentInput) => ParseResult<M> | Promise<ParseResult<M>>;
|
|
84
|
+
type Variant<M extends Tagged, K extends M['_tag']> = Extract<M, {
|
|
85
|
+
readonly _tag: K;
|
|
86
|
+
}>;
|
|
87
|
+
/** Intent parsers keyed by the message tag they produce. Messages from drivers need none. */
|
|
88
|
+
export type Intents<M extends Tagged> = {
|
|
89
|
+
readonly [K in M['_tag']]?: IntentParser<Variant<M, K>>;
|
|
90
|
+
};
|
|
91
|
+
type Reducer<S, M, Msg, P> = (state: S, msg: Msg, ctx: Ctx<P>) => Next<S, M>;
|
|
92
|
+
/**
|
|
93
|
+
* One pure reducer per message tag (exhaustive by construction), plus optional reducers
|
|
94
|
+
* for framework messages. Reducers may return commands.
|
|
95
|
+
*/
|
|
96
|
+
export type Update<S, M extends Tagged, P = object> = {
|
|
97
|
+
readonly [K in M['_tag']]: Reducer<S, M, Variant<M, K>, P>;
|
|
98
|
+
} & {
|
|
99
|
+
readonly PropsChanged?: Reducer<S, M, PropsChanged<P>, P>;
|
|
100
|
+
readonly IntentRejected?: Reducer<S, M, IntentRejected, P>;
|
|
101
|
+
readonly StoreChanged?: Reducer<S, M, StoreChanged, P>;
|
|
102
|
+
readonly Hydrated?: Reducer<S, M, Hydrated, P>;
|
|
103
|
+
};
|
|
104
|
+
/** Typed intent names handed to the view, so `data-intent=${i.Increment}` is checked. */
|
|
105
|
+
export type IntentNames<M extends Tagged> = {
|
|
106
|
+
readonly [K in M['_tag']]: K;
|
|
107
|
+
};
|
|
108
|
+
/**
|
|
109
|
+
* One prop's declaration: Lit's `PropertyDeclaration` plus Gyral's honesty rule (ADR 0007
|
|
110
|
+
* addendum). A prop is `undefined` until a parent, an attribute or a hydration seed sets it,
|
|
111
|
+
* so a prop whose type excludes `undefined` must say how that is guaranteed:
|
|
112
|
+
* - `required: true`: a missing value is a bug, reported once per instance at first render;
|
|
113
|
+
* - `default: value`: used whenever the element's value is `undefined`.
|
|
114
|
+
* A prop whose type includes `undefined` needs neither.
|
|
115
|
+
*/
|
|
116
|
+
export type PropDeclaration<T> = PropertyDeclaration & (undefined extends T ? {
|
|
117
|
+
readonly required?: false;
|
|
118
|
+
readonly default?: T;
|
|
119
|
+
} : {
|
|
120
|
+
readonly required: true;
|
|
121
|
+
readonly default?: undefined;
|
|
122
|
+
} | {
|
|
123
|
+
readonly required?: false;
|
|
124
|
+
readonly default: T;
|
|
125
|
+
});
|
|
126
|
+
export type PropDeclarations<P> = {
|
|
127
|
+
readonly [K in keyof P]-?: PropDeclaration<P[K]>;
|
|
128
|
+
};
|
|
129
|
+
/** State of a component that keeps none (a pure view of its props). Its `init` is optional. */
|
|
130
|
+
export type Stateless = Readonly<Record<string, never>>;
|
|
131
|
+
/** Initial model state (and optional commands), computed from props on first render. */
|
|
132
|
+
type Init<S, M, P> = (props: P) => Next<S, M>;
|
|
133
|
+
type InitField<S, M extends Tagged, P> = Stateless extends S ? {
|
|
134
|
+
readonly init?: Init<S, M, P>;
|
|
135
|
+
} : {
|
|
136
|
+
readonly init: Init<S, M, P>;
|
|
137
|
+
};
|
|
138
|
+
export type ComponentSpec<S, M extends Tagged, P> = SpecBody<S, M, P> & InitField<S, M, P>;
|
|
139
|
+
interface SpecBody<S, M extends Tagged, P> {
|
|
140
|
+
/** Lit reactive property declarations: the component's inputs. */
|
|
141
|
+
readonly props?: PropDeclarations<P>;
|
|
142
|
+
/** INTENT: platform events to messages. */
|
|
143
|
+
readonly intent: Intents<M>;
|
|
144
|
+
/** MODEL: pure state transitions. */
|
|
145
|
+
readonly update: Update<S, M, P>;
|
|
146
|
+
/** VIEW: pure function of state and props. Name intents in markup; never attach closures. */
|
|
147
|
+
readonly view: (state: S, intents: IntentNames<M>, ctx: Ctx<P>) => unknown;
|
|
148
|
+
/**
|
|
149
|
+
* Shadow-root styles: `css` templates, plain CSS strings, `CSSStyleSheet`s, or arrays of
|
|
150
|
+
* them. Ignored (with a warning) when `shadow: false`.
|
|
151
|
+
*/
|
|
152
|
+
readonly styles?: Styles;
|
|
153
|
+
/**
|
|
154
|
+
* `false` renders the view as the element's own light-DOM children (ADR 0014): document CSS
|
|
155
|
+
* applies, and the server writes plain children instead of a `<template shadowrootmode>`.
|
|
156
|
+
* For page-level components (listings, articles). No `<slot>`s and no `styles`. Default `true`.
|
|
157
|
+
*/
|
|
158
|
+
readonly shadow?: boolean;
|
|
159
|
+
/**
|
|
160
|
+
* When a server-rendered instance hydrates (gyral-4k7.4): `load` (default), `idle`,
|
|
161
|
+
* `visible` (scrolled into view) or `interaction` (first pointer/focus). Client-only
|
|
162
|
+
* renders are unaffected.
|
|
163
|
+
*/
|
|
164
|
+
readonly hydrate?: HydrateStrategy;
|
|
165
|
+
/** Extra event types that may trigger intents via `data-intent-on` (e.g. `pointerdown`). */
|
|
166
|
+
readonly events?: readonly string[];
|
|
167
|
+
/** Driver substitutions by name, for every instance (ADR 0006). */
|
|
168
|
+
readonly drivers?: DriverOverrides;
|
|
169
|
+
/**
|
|
170
|
+
* Stores this component reads with `ctx.read(store)` and writes with `send(store, msg)`.
|
|
171
|
+
* Their changes re-render it (and reach the optional `StoreChanged` reducer). ADR 0013.
|
|
172
|
+
*/
|
|
173
|
+
readonly stores?: readonly AnyStore[];
|
|
174
|
+
/**
|
|
175
|
+
* Return `true` to render this state change inside a View Transition (route changes, list
|
|
176
|
+
* reorders). Skipped without browser support or when reduced motion is requested.
|
|
177
|
+
*/
|
|
178
|
+
readonly viewTransition?: (prev: S, next: S, msg: Tagged) => boolean;
|
|
179
|
+
/**
|
|
180
|
+
* Boolean facts about the state, exposed to CSS as custom states:
|
|
181
|
+
* `states: (s) => ({ loading: s._tag === 'Loading' })` enables `:host(:state(loading))` and
|
|
182
|
+
* `gy-x:state(loading)`. Applied after each render; feature-detected; not on the server.
|
|
183
|
+
*/
|
|
184
|
+
readonly states?: (state: S) => Readonly<Record<string, boolean>>;
|
|
185
|
+
}
|
|
186
|
+
export {};
|
package/dist/types.js
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"types.js","sourceRoot":"","sources":["../src/types.ts"],"names":[],"mappings":"","sourcesContent":["import type { PropertyDeclaration } from 'lit';\nimport type { Styles } from './styles.js';\nimport type { CommandInfo } from './invokers.js';\nimport type { HydrateStrategy } from './islands.js';\nimport type { DriverOverrides, Next } from './command.js';\nimport type { AnyStore, StoreChanged, StoreRef } from './store.js';\n\n/** Every message is a tagged object; the tag is also the intent name used in markup. */\nexport interface Tagged {\n readonly _tag: string;\n}\n\n/** What the intent layer sees when a `data-intent` element fires its trigger event. */\nexport interface IntentInput {\n /** The `data-intent` value (a message tag). */\n readonly name: string;\n readonly event: Event;\n /** The element carrying `data-intent`. */\n readonly target: Element;\n /** `value` of the input, select, textarea or button that carries the intent. */\n readonly value: string | undefined;\n /** `checked` for checkbox and radio inputs. */\n readonly checked: boolean | undefined;\n /** Submitted data (including the submitter button) when the intent is on a `<form>`. */\n readonly formData: FormData | undefined;\n /** The output a child component emitted, when the intent is on a child element. */\n readonly detail: unknown;\n /** `KeyboardEvent.key` for `keydown`/`keyup` intents. */\n readonly key: string | undefined;\n /** For `toggle` intents (popover, `<details>`): the state it changed to. */\n readonly newState: 'open' | 'closed' | undefined;\n /** For `command` intents: the invoker's command (e.g. `--clear`) and source (gyral-czi.6). */\n readonly command: CommandInfo | undefined;\n}\n\n/** Reads a declared store's current state, typed by the store (ADR 0013). */\nexport type StoreReader = <S>(store: StoreRef<S>) => S;\n\n/** Read-only context handed to every reducer and to the view (ADR 0007, 0013). */\nexport interface Ctx<P> {\n /** Props from above. */\n readonly props: P;\n /** Stores from the side: `read(cart).lines`. The store must be in `spec.stores`. */\n readonly read: StoreReader;\n}\n\n/** Framework message: declared props changed after the first render (ADR 0007). */\nexport interface PropsChanged<P> {\n readonly _tag: 'PropsChanged';\n readonly props: P;\n readonly prev: P;\n}\n\n/**\n * Framework message: the component is live in the browser (ADR 0012 addendum). Sent once,\n * after the first client render has completed, to every client-side instance. Use it for\n * progressive enhancement: render the no-JS form on the server and in the first client render\n * (so hydration matches), then switch to the enhanced UI in the `Hydrated` reducer.\n */\nexport interface Hydrated {\n readonly _tag: 'Hydrated';\n /** `true` when the instance resumed from server-rendered markup (a hydration seed). */\n readonly serverRendered: boolean;\n}\n\n/** One validation problem. `path` is dot-joined and matches the field's `name`. */\nexport interface FieldIssue {\n readonly path: string;\n readonly message: string;\n}\n\n/** Submitted text values of a form (Files are dropped: they can't be re-filled). */\nexport type FormFields = Readonly<Record<string, string | readonly string[]>>;\n\n/** Framework message: an intent's input failed schema validation (ADR 0008). */\nexport interface IntentRejected {\n readonly _tag: 'IntentRejected';\n /** The `data-intent` name whose input was rejected. */\n readonly intent: string;\n readonly issues: readonly FieldIssue[];\n /**\n * For `form()` rejections: what the user submitted, so the view can re-fill the form. On\n * the no-JS path (ADR 0008 server half) the server re-renders the page from this.\n */\n // `| undefined` so schemas with plain optional fields (valibot `optional`) can produce it.\n readonly values?: FormFields | undefined;\n}\n\ntype ParseResult<M> = M | IntentRejected | undefined;\n\n/**\n * Parses a platform event into one message variant, `IntentRejected`, or `undefined` to\n * ignore it. May be async because schema validation may be.\n */\nexport type IntentParser<M> = (input: IntentInput) => ParseResult<M> | Promise<ParseResult<M>>;\n\ntype Variant<M extends Tagged, K extends M['_tag']> = Extract<M, { readonly _tag: K }>;\n\n/** Intent parsers keyed by the message tag they produce. Messages from drivers need none. */\nexport type Intents<M extends Tagged> = {\n readonly [K in M['_tag']]?: IntentParser<Variant<M, K>>;\n};\n\ntype Reducer<S, M, Msg, P> = (state: S, msg: Msg, ctx: Ctx<P>) => Next<S, M>;\n\n/**\n * One pure reducer per message tag (exhaustive by construction), plus optional reducers\n * for framework messages. Reducers may return commands.\n */\nexport type Update<S, M extends Tagged, P = object> = {\n readonly [K in M['_tag']]: Reducer<S, M, Variant<M, K>, P>;\n} & {\n readonly PropsChanged?: Reducer<S, M, PropsChanged<P>, P>;\n readonly IntentRejected?: Reducer<S, M, IntentRejected, P>;\n readonly StoreChanged?: Reducer<S, M, StoreChanged, P>;\n readonly Hydrated?: Reducer<S, M, Hydrated, P>;\n};\n\n/** Typed intent names handed to the view, so `data-intent=${i.Increment}` is checked. */\nexport type IntentNames<M extends Tagged> = { readonly [K in M['_tag']]: K };\n\n/**\n * One prop's declaration: Lit's `PropertyDeclaration` plus Gyral's honesty rule (ADR 0007\n * addendum). A prop is `undefined` until a parent, an attribute or a hydration seed sets it,\n * so a prop whose type excludes `undefined` must say how that is guaranteed:\n * - `required: true`: a missing value is a bug, reported once per instance at first render;\n * - `default: value`: used whenever the element's value is `undefined`.\n * A prop whose type includes `undefined` needs neither.\n */\nexport type PropDeclaration<T> = PropertyDeclaration &\n (undefined extends T\n ? { readonly required?: false; readonly default?: T }\n : | { readonly required: true; readonly default?: undefined }\n | { readonly required?: false; readonly default: T });\n\nexport type PropDeclarations<P> = { readonly [K in keyof P]-?: PropDeclaration<P[K]> };\n\n/** State of a component that keeps none (a pure view of its props). Its `init` is optional. */\nexport type Stateless = Readonly<Record<string, never>>;\n\n/** Initial model state (and optional commands), computed from props on first render. */\ntype Init<S, M, P> = (props: P) => Next<S, M>;\n\n// `init` may be omitted only when an empty object is a valid state (Stateless, all-optional).\ntype InitField<S, M extends Tagged, P> = Stateless extends S\n ? { readonly init?: Init<S, M, P> }\n : { readonly init: Init<S, M, P> };\n\nexport type ComponentSpec<S, M extends Tagged, P> = SpecBody<S, M, P> & InitField<S, M, P>;\n\ninterface SpecBody<S, M extends Tagged, P> {\n /** Lit reactive property declarations: the component's inputs. */\n readonly props?: PropDeclarations<P>;\n /** INTENT: platform events to messages. */\n readonly intent: Intents<M>;\n /** MODEL: pure state transitions. */\n readonly update: Update<S, M, P>;\n /** VIEW: pure function of state and props. Name intents in markup; never attach closures. */\n readonly view: (state: S, intents: IntentNames<M>, ctx: Ctx<P>) => unknown;\n /**\n * Shadow-root styles: `css` templates, plain CSS strings, `CSSStyleSheet`s, or arrays of\n * them. Ignored (with a warning) when `shadow: false`.\n */\n readonly styles?: Styles;\n /**\n * `false` renders the view as the element's own light-DOM children (ADR 0014): document CSS\n * applies, and the server writes plain children instead of a `<template shadowrootmode>`.\n * For page-level components (listings, articles). No `<slot>`s and no `styles`. Default `true`.\n */\n readonly shadow?: boolean;\n /**\n * When a server-rendered instance hydrates (gyral-4k7.4): `load` (default), `idle`,\n * `visible` (scrolled into view) or `interaction` (first pointer/focus). Client-only\n * renders are unaffected.\n */\n readonly hydrate?: HydrateStrategy;\n /** Extra event types that may trigger intents via `data-intent-on` (e.g. `pointerdown`). */\n readonly events?: readonly string[];\n /** Driver substitutions by name, for every instance (ADR 0006). */\n readonly drivers?: DriverOverrides;\n /**\n * Stores this component reads with `ctx.read(store)` and writes with `send(store, msg)`.\n * Their changes re-render it (and reach the optional `StoreChanged` reducer). ADR 0013.\n */\n readonly stores?: readonly AnyStore[];\n /**\n * Return `true` to render this state change inside a View Transition (route changes, list\n * reorders). Skipped without browser support or when reduced motion is requested.\n */\n readonly viewTransition?: (prev: S, next: S, msg: Tagged) => boolean;\n /**\n * Boolean facts about the state, exposed to CSS as custom states:\n * `states: (s) => ({ loading: s._tag === 'Loading' })` enables `:host(:state(loading))` and\n * `gy-x:state(loading)`. Applied after each render; feature-detected; not on the server.\n */\n readonly states?: (state: S) => Readonly<Record<string, boolean>>;\n}\n"]}
|
package/dist/vite.d.ts
ADDED
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
/** Every Lit package: resolve exactly one copy, even when Gyral is linked from elsewhere. */
|
|
2
|
+
export declare const LIT_PACKAGES: readonly string[];
|
|
3
|
+
/**
|
|
4
|
+
* Lit modules that Gyral imports or re-exports. Pre-bundling them up front stops Vite from
|
|
5
|
+
* discovering them mid-run, which reloads the page and fails the first browser test run.
|
|
6
|
+
*/
|
|
7
|
+
export declare const LIT_PREBUNDLE: readonly string[];
|
|
8
|
+
export interface GyralViteOptions {
|
|
9
|
+
/** More modules to pre-bundle (e.g. 'lit/directives/unsafe-html.js'). */
|
|
10
|
+
readonly optimize?: readonly string[];
|
|
11
|
+
}
|
|
12
|
+
export interface GyralViteConfig {
|
|
13
|
+
readonly resolve: {
|
|
14
|
+
readonly dedupe: string[];
|
|
15
|
+
};
|
|
16
|
+
readonly optimizeDeps: {
|
|
17
|
+
readonly include: string[];
|
|
18
|
+
};
|
|
19
|
+
}
|
|
20
|
+
/**
|
|
21
|
+
* Spread into a Vite config, or into each Vitest project:
|
|
22
|
+
*
|
|
23
|
+
* export default defineConfig({ ...gyralVitePreset(), build: { … } });
|
|
24
|
+
*/
|
|
25
|
+
export declare function gyralVitePreset(options?: GyralViteOptions): GyralViteConfig;
|
package/dist/vite.js
ADDED
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
// Vite / Vitest settings every Gyral app needs (gyral-a7r, docs/references/consumer-setup.md).
|
|
2
|
+
// Plain data, no imports: safe to load from vite.config.ts and vitest.config.ts.
|
|
3
|
+
/** Every Lit package: resolve exactly one copy, even when Gyral is linked from elsewhere. */
|
|
4
|
+
export const LIT_PACKAGES = [
|
|
5
|
+
'lit',
|
|
6
|
+
'lit-html',
|
|
7
|
+
'lit-element',
|
|
8
|
+
'@lit/reactive-element',
|
|
9
|
+
'@lit-labs/ssr',
|
|
10
|
+
'@lit-labs/ssr-client',
|
|
11
|
+
];
|
|
12
|
+
/**
|
|
13
|
+
* Lit modules that Gyral imports or re-exports. Pre-bundling them up front stops Vite from
|
|
14
|
+
* discovering them mid-run, which reloads the page and fails the first browser test run.
|
|
15
|
+
*/
|
|
16
|
+
export const LIT_PREBUNDLE = [
|
|
17
|
+
'lit',
|
|
18
|
+
'lit/directive.js',
|
|
19
|
+
'lit/static-html.js',
|
|
20
|
+
'lit/directives/class-map.js',
|
|
21
|
+
'lit/directives/keyed.js',
|
|
22
|
+
'lit/directives/live.js',
|
|
23
|
+
'lit/directives/repeat.js',
|
|
24
|
+
'lit/directives/style-map.js',
|
|
25
|
+
];
|
|
26
|
+
/**
|
|
27
|
+
* Spread into a Vite config, or into each Vitest project:
|
|
28
|
+
*
|
|
29
|
+
* export default defineConfig({ ...gyralVitePreset(), build: { … } });
|
|
30
|
+
*/
|
|
31
|
+
export function gyralVitePreset(options = {}) {
|
|
32
|
+
return {
|
|
33
|
+
resolve: { dedupe: [...LIT_PACKAGES] },
|
|
34
|
+
optimizeDeps: { include: [...new Set([...LIT_PREBUNDLE, ...(options.optimize ?? [])])] },
|
|
35
|
+
};
|
|
36
|
+
}
|
|
37
|
+
//# sourceMappingURL=vite.js.map
|
package/dist/vite.js.map
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"vite.js","sourceRoot":"","sources":["../src/vite.ts"],"names":[],"mappings":"AAAA,+FAA+F;AAC/F,iFAAiF;AAEjF,6FAA6F;AAC7F,MAAM,CAAC,MAAM,YAAY,GAAsB;IAC7C,KAAK;IACL,UAAU;IACV,aAAa;IACb,uBAAuB;IACvB,eAAe;IACf,sBAAsB;CACvB,CAAC;AAEF;;;GAGG;AACH,MAAM,CAAC,MAAM,aAAa,GAAsB;IAC9C,KAAK;IACL,kBAAkB;IAClB,oBAAoB;IACpB,6BAA6B;IAC7B,yBAAyB;IACzB,wBAAwB;IACxB,0BAA0B;IAC1B,6BAA6B;CAC9B,CAAC;AAYF;;;;GAIG;AACH,MAAM,UAAU,eAAe,CAAC,UAA4B,EAAE;IAC5D,OAAO;QACL,OAAO,EAAE,EAAE,MAAM,EAAE,CAAC,GAAG,YAAY,CAAC,EAAE;QACtC,YAAY,EAAE,EAAE,OAAO,EAAE,CAAC,GAAG,IAAI,GAAG,CAAC,CAAC,GAAG,aAAa,EAAE,GAAG,CAAC,OAAO,CAAC,QAAQ,IAAI,EAAE,CAAC,CAAC,CAAC,CAAC,EAAE;KACzF,CAAC;AACJ,CAAC","sourcesContent":["// Vite / Vitest settings every Gyral app needs (gyral-a7r, docs/references/consumer-setup.md).\n// Plain data, no imports: safe to load from vite.config.ts and vitest.config.ts.\n\n/** Every Lit package: resolve exactly one copy, even when Gyral is linked from elsewhere. */\nexport const LIT_PACKAGES: readonly string[] = [\n 'lit',\n 'lit-html',\n 'lit-element',\n '@lit/reactive-element',\n '@lit-labs/ssr',\n '@lit-labs/ssr-client',\n];\n\n/**\n * Lit modules that Gyral imports or re-exports. Pre-bundling them up front stops Vite from\n * discovering them mid-run, which reloads the page and fails the first browser test run.\n */\nexport const LIT_PREBUNDLE: readonly string[] = [\n 'lit',\n 'lit/directive.js',\n 'lit/static-html.js',\n 'lit/directives/class-map.js',\n 'lit/directives/keyed.js',\n 'lit/directives/live.js',\n 'lit/directives/repeat.js',\n 'lit/directives/style-map.js',\n];\n\nexport interface GyralViteOptions {\n /** More modules to pre-bundle (e.g. 'lit/directives/unsafe-html.js'). */\n readonly optimize?: readonly string[];\n}\n\nexport interface GyralViteConfig {\n readonly resolve: { readonly dedupe: string[] };\n readonly optimizeDeps: { readonly include: string[] };\n}\n\n/**\n * Spread into a Vite config, or into each Vitest project:\n *\n * export default defineConfig({ ...gyralVitePreset(), build: { … } });\n */\nexport function gyralVitePreset(options: GyralViteOptions = {}): GyralViteConfig {\n return {\n resolve: { dedupe: [...LIT_PACKAGES] },\n optimizeDeps: { include: [...new Set([...LIT_PREBUNDLE, ...(options.optimize ?? [])])] },\n };\n}\n"]}
|
package/package.json
CHANGED
|
@@ -1,16 +1,10 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@gyral/core",
|
|
3
|
-
"version": "0.
|
|
4
|
-
"description": "
|
|
5
|
-
"keywords": [
|
|
6
|
-
"gyral",
|
|
7
|
-
"web-components",
|
|
8
|
-
"lit",
|
|
9
|
-
"mvi"
|
|
10
|
-
],
|
|
3
|
+
"version": "0.1.0",
|
|
4
|
+
"description": "Gyral core: Model-View-Intent web components on Lit and the web platform. Inspired by Cycle.js.",
|
|
11
5
|
"license": "MIT",
|
|
12
6
|
"author": "The Zoop Troop, Inc.",
|
|
13
|
-
"homepage": "https://gyral
|
|
7
|
+
"homepage": "https://github.com/gyraljs/gyral/tree/main/packages/core#readme",
|
|
14
8
|
"repository": {
|
|
15
9
|
"type": "git",
|
|
16
10
|
"url": "git+https://github.com/gyraljs/gyral.git",
|
|
@@ -19,7 +13,42 @@
|
|
|
19
13
|
"bugs": {
|
|
20
14
|
"url": "https://github.com/gyraljs/gyral/issues"
|
|
21
15
|
},
|
|
22
|
-
"
|
|
23
|
-
|
|
16
|
+
"type": "module",
|
|
17
|
+
"sideEffects": false,
|
|
18
|
+
"exports": {
|
|
19
|
+
".": {
|
|
20
|
+
"types": "./dist/index.d.ts",
|
|
21
|
+
"default": "./dist/index.js"
|
|
22
|
+
},
|
|
23
|
+
"./vite": {
|
|
24
|
+
"types": "./dist/vite.d.ts",
|
|
25
|
+
"default": "./dist/vite.js"
|
|
26
|
+
}
|
|
27
|
+
},
|
|
28
|
+
"imports": {
|
|
29
|
+
"#devtools": {
|
|
30
|
+
"development": "./dist/devtools.js",
|
|
31
|
+
"default": "./dist/devtools-off.js"
|
|
32
|
+
}
|
|
33
|
+
},
|
|
34
|
+
"files": [
|
|
35
|
+
"dist",
|
|
36
|
+
"README.md",
|
|
37
|
+
"LICENSE",
|
|
38
|
+
"NOTICE",
|
|
39
|
+
"CHANGELOG.md"
|
|
40
|
+
],
|
|
41
|
+
"dependencies": {
|
|
42
|
+
"@standard-schema/spec": "1.1.0",
|
|
43
|
+
"effect": "3.22.2"
|
|
44
|
+
},
|
|
45
|
+
"peerDependencies": {
|
|
46
|
+
"lit": "^3.3.0"
|
|
47
|
+
},
|
|
48
|
+
"devDependencies": {
|
|
49
|
+
"lit": "3.3.3"
|
|
50
|
+
},
|
|
51
|
+
"scripts": {
|
|
52
|
+
"build": "node ../../scripts/build-package.mjs"
|
|
24
53
|
}
|
|
25
|
-
}
|
|
54
|
+
}
|