@gyral/core 0.2.0 → 0.3.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 +87 -0
- package/README.md +7 -5
- package/dist/children.d.ts +5 -2
- package/dist/children.js +8 -3
- package/dist/children.js.map +1 -1
- package/dist/command.js +6 -0
- package/dist/command.js.map +1 -1
- package/dist/compiler/ast.d.ts +21 -0
- package/dist/compiler/ast.js +145 -0
- package/dist/compiler/ast.js.map +1 -0
- package/dist/compiler/compile.d.ts +38 -0
- package/dist/compiler/compile.js +129 -0
- package/dist/compiler/compile.js.map +1 -0
- package/dist/compiler/hooks.d.ts +18 -0
- package/dist/compiler/hooks.js +186 -0
- package/dist/compiler/hooks.js.map +1 -0
- package/dist/compiler/parse5-check.d.ts +21 -0
- package/dist/compiler/parse5-check.js +55 -0
- package/dist/compiler/parse5-check.js.map +1 -0
- package/dist/compiler/scan.d.ts +31 -0
- package/dist/compiler/scan.js +152 -0
- package/dist/compiler/scan.js.map +1 -0
- package/dist/compiler/source.d.ts +34 -0
- package/dist/compiler/source.js +114 -0
- package/dist/compiler/source.js.map +1 -0
- package/dist/define.d.ts +2 -2
- package/dist/define.js +35 -327
- package/dist/define.js.map +1 -1
- package/dist/devtools-events.d.ts +5 -0
- package/dist/devtools-events.js.map +1 -1
- package/dist/devtools-off.d.ts +1 -0
- package/dist/devtools-off.js +1 -0
- package/dist/devtools-off.js.map +1 -1
- package/dist/devtools.d.ts +1 -0
- package/dist/devtools.js +3 -2
- package/dist/devtools.js.map +1 -1
- package/dist/drivers-scope.d.ts +1 -1
- package/dist/drivers-scope.js +1 -8
- package/dist/drivers-scope.js.map +1 -1
- package/dist/element-types.d.ts +5 -3
- package/dist/element-types.js.map +1 -1
- package/dist/element.d.ts +3 -0
- package/dist/element.js +269 -0
- package/dist/element.js.map +1 -0
- package/dist/eslint/imports.d.ts +24 -0
- package/dist/eslint/imports.js +78 -0
- package/dist/eslint/imports.js.map +1 -0
- package/dist/eslint/index.d.ts +15 -0
- package/dist/eslint/index.js +15 -0
- package/dist/eslint/index.js.map +1 -0
- package/dist/eslint/locate.d.ts +33 -0
- package/dist/eslint/locate.js +132 -0
- package/dist/eslint/locate.js.map +1 -0
- package/dist/eslint/row-purity-rule.d.ts +2 -0
- package/dist/eslint/row-purity-rule.js +103 -0
- package/dist/eslint/row-purity-rule.js.map +1 -0
- package/dist/eslint/template-rule.d.ts +5 -0
- package/dist/eslint/template-rule.js +66 -0
- package/dist/eslint/template-rule.js.map +1 -0
- package/dist/features.d.ts +39 -0
- package/dist/features.js +2 -0
- package/dist/features.js.map +1 -0
- package/dist/focus.d.ts +7 -12
- package/dist/focus.js +13 -10
- package/dist/focus.js.map +1 -1
- package/dist/hooks/invalid.d.ts +14 -0
- package/dist/hooks/invalid.js +72 -0
- package/dist/hooks/invalid.js.map +1 -0
- package/dist/hooks/labelled-by.d.ts +13 -0
- package/dist/hooks/labelled-by.js +51 -0
- package/dist/hooks/labelled-by.js.map +1 -0
- package/dist/host-model.d.ts +48 -0
- package/dist/host-model.js +155 -0
- package/dist/host-model.js.map +1 -0
- package/dist/hydration-client.d.ts +9 -0
- package/dist/hydration-client.js +35 -0
- package/dist/hydration-client.js.map +1 -0
- package/dist/hydration.d.ts +13 -19
- package/dist/hydration.js +45 -45
- package/dist/hydration.js.map +1 -1
- package/dist/index.d.ts +9 -17
- package/dist/index.js +9 -18
- package/dist/index.js.map +1 -1
- package/dist/intent.d.ts +31 -8
- package/dist/intent.js +82 -27
- package/dist/intent.js.map +1 -1
- package/dist/internal/interpreter.d.ts +7 -1
- package/dist/internal/interpreter.js +11 -4
- package/dist/internal/interpreter.js.map +1 -1
- package/dist/invokers-shim.d.ts +6 -0
- package/dist/invokers-shim.js +32 -0
- package/dist/invokers-shim.js.map +1 -0
- package/dist/invokers.d.ts +3 -5
- package/dist/invokers.js +11 -51
- package/dist/invokers.js.map +1 -1
- package/dist/islands.d.ts +0 -2
- package/dist/islands.js +4 -11
- package/dist/islands.js.map +1 -1
- package/dist/light-dom.d.ts +3 -52
- package/dist/light-dom.js +5 -100
- package/dist/light-dom.js.map +1 -1
- package/dist/prop.d.ts +66 -0
- package/dist/prop.js +22 -0
- package/dist/prop.js.map +1 -0
- package/dist/props.d.ts +52 -21
- package/dist/props.js +150 -34
- package/dist/props.js.map +1 -1
- package/dist/scheduler.d.ts +39 -0
- package/dist/scheduler.js +230 -0
- package/dist/scheduler.js.map +1 -0
- package/dist/server-component.d.ts +10 -0
- package/dist/server-component.js +102 -0
- package/dist/server-component.js.map +1 -0
- package/dist/server-specs.d.ts +6 -0
- package/dist/server-specs.js +13 -0
- package/dist/server-specs.js.map +1 -0
- package/dist/server.d.ts +28 -0
- package/dist/server.js +50 -0
- package/dist/server.js.map +1 -0
- package/dist/settled.d.ts +10 -0
- package/dist/settled.js +40 -0
- package/dist/settled.js.map +1 -0
- package/dist/states.d.ts +3 -3
- package/dist/states.js +4 -7
- package/dist/states.js.map +1 -1
- package/dist/store-binding.d.ts +6 -3
- package/dist/store-binding.js +5 -6
- package/dist/store-binding.js.map +1 -1
- package/dist/store-scope.d.ts +6 -7
- package/dist/store-scope.js +11 -26
- package/dist/store-scope.js.map +1 -1
- package/dist/store.d.ts +3 -0
- package/dist/store.js +9 -2
- package/dist/store.js.map +1 -1
- package/dist/stores-provider.d.ts +2 -6
- package/dist/stores-provider.js +21 -55
- package/dist/stores-provider.js.map +1 -1
- package/dist/transitions.d.ts +5 -6
- package/dist/transitions.js +11 -20
- package/dist/transitions.js.map +1 -1
- package/dist/types.d.ts +19 -23
- package/dist/types.js.map +1 -1
- package/dist/view/attributes.d.ts +6 -0
- package/dist/view/attributes.js +10 -0
- package/dist/view/attributes.js.map +1 -0
- package/dist/view/compiled.d.ts +1 -0
- package/dist/view/compiled.js +6 -0
- package/dist/view/compiled.js.map +1 -0
- package/dist/view/dev-off.d.ts +1 -0
- package/dist/view/dev-off.js +4 -0
- package/dist/view/dev-off.js.map +1 -0
- package/dist/view/dev.d.ts +1 -0
- package/dist/view/dev.js +5 -0
- package/dist/view/dev.js.map +1 -0
- package/dist/view/flags.d.ts +1 -0
- package/dist/view/flags.js +4 -0
- package/dist/view/flags.js.map +1 -0
- package/dist/view/index.d.ts +21 -0
- package/dist/view/index.js +21 -0
- package/dist/view/index.js.map +1 -0
- package/dist/view/normalize/check.d.ts +20 -0
- package/dist/view/normalize/check.js +78 -0
- package/dist/view/normalize/check.js.map +1 -0
- package/dist/view/normalize/emit.d.ts +13 -0
- package/dist/view/normalize/emit.js +136 -0
- package/dist/view/normalize/emit.js.map +1 -0
- package/dist/view/normalize/entities.d.ts +4 -0
- package/dist/view/normalize/entities.js +38 -0
- package/dist/view/normalize/entities.js.map +1 -0
- package/dist/view/normalize/errors.d.ts +9 -0
- package/dist/view/normalize/errors.js +19 -0
- package/dist/view/normalize/errors.js.map +1 -0
- package/dist/view/normalize/id.d.ts +7 -0
- package/dist/view/normalize/id.js +48 -0
- package/dist/view/normalize/id.js.map +1 -0
- package/dist/view/normalize/normalize.d.ts +15 -0
- package/dist/view/normalize/normalize.js +36 -0
- package/dist/view/normalize/normalize.js.map +1 -0
- package/dist/view/normalize/repairs.d.ts +24 -0
- package/dist/view/normalize/repairs.js +166 -0
- package/dist/view/normalize/repairs.js.map +1 -0
- package/dist/view/normalize/rules.d.ts +30 -0
- package/dist/view/normalize/rules.js +90 -0
- package/dist/view/normalize/rules.js.map +1 -0
- package/dist/view/normalize/shape.d.ts +5 -0
- package/dist/view/normalize/shape.js +38 -0
- package/dist/view/normalize/shape.js.map +1 -0
- package/dist/view/normalize/source.d.ts +13 -0
- package/dist/view/normalize/source.js +34 -0
- package/dist/view/normalize/source.js.map +1 -0
- package/dist/view/normalize/tag-states.d.ts +23 -0
- package/dist/view/normalize/tag-states.js +192 -0
- package/dist/view/normalize/tag-states.js.map +1 -0
- package/dist/view/normalize/tokenizer.d.ts +5 -0
- package/dist/view/normalize/tokenizer.js +233 -0
- package/dist/view/normalize/tokenizer.js.map +1 -0
- package/dist/view/normalize/tokens.d.ts +51 -0
- package/dist/view/normalize/tokens.js +24 -0
- package/dist/view/normalize/tokens.js.map +1 -0
- package/dist/view/normalize/tree.d.ts +59 -0
- package/dist/view/normalize/tree.js +190 -0
- package/dist/view/normalize/tree.js.map +1 -0
- package/dist/view/normalize/types.d.ts +126 -0
- package/dist/view/normalize/types.js +26 -0
- package/dist/view/normalize/types.js.map +1 -0
- package/dist/view/normalize/whitespace.d.ts +2 -0
- package/dist/{template-whitespace.js → view/normalize/whitespace.js} +24 -34
- package/dist/view/normalize/whitespace.js.map +1 -0
- package/dist/view/prepare-stub.d.ts +3 -0
- package/dist/view/prepare-stub.js +7 -0
- package/dist/view/prepare-stub.js.map +1 -0
- package/dist/view/prepare.d.ts +8 -0
- package/dist/view/prepare.js +57 -0
- package/dist/view/prepare.js.map +1 -0
- package/dist/view/registry.d.ts +63 -0
- package/dist/view/registry.js +19 -0
- package/dist/view/registry.js.map +1 -0
- package/dist/view/render/adopt-attr.d.ts +14 -0
- package/dist/view/render/adopt-attr.js +77 -0
- package/dist/view/render/adopt-attr.js.map +1 -0
- package/dist/view/render/adopt-plan.d.ts +10 -0
- package/dist/view/render/adopt-plan.js +26 -0
- package/dist/view/render/adopt-plan.js.map +1 -0
- package/dist/view/render/adopt.d.ts +3 -0
- package/dist/view/render/adopt.js +269 -0
- package/dist/view/render/adopt.js.map +1 -0
- package/dist/view/render/attr-parts.d.ts +61 -0
- package/dist/view/render/attr-parts.js +229 -0
- package/dist/view/render/attr-parts.js.map +1 -0
- package/dist/view/render/child-part.d.ts +51 -0
- package/dist/view/render/child-part.js +170 -0
- package/dist/view/render/child-part.js.map +1 -0
- package/dist/view/render/dev-check.d.ts +12 -0
- package/dist/view/render/dev-check.js +122 -0
- package/dist/view/render/dev-check.js.map +1 -0
- package/dist/view/render/hook-part.d.ts +3 -0
- package/dist/view/render/hook-part.js +20 -0
- package/dist/view/render/hook-part.js.map +1 -0
- package/dist/view/render/hooks.d.ts +40 -0
- package/dist/view/render/hooks.js +46 -0
- package/dist/view/render/hooks.js.map +1 -0
- package/dist/view/render/hydrate.d.ts +10 -0
- package/dist/view/render/hydrate.js +33 -0
- package/dist/view/render/hydrate.js.map +1 -0
- package/dist/view/render/instance.d.ts +33 -0
- package/dist/view/render/instance.js +107 -0
- package/dist/view/render/instance.js.map +1 -0
- package/dist/view/render/list.d.ts +20 -0
- package/dist/view/render/list.js +156 -0
- package/dist/view/render/list.js.map +1 -0
- package/dist/view/render/mismatch.d.ts +10 -0
- package/dist/view/render/mismatch.js +53 -0
- package/dist/view/render/mismatch.js.map +1 -0
- package/dist/view/render/nodes.d.ts +10 -0
- package/dist/view/render/nodes.js +37 -0
- package/dist/view/render/nodes.js.map +1 -0
- package/dist/view/render/place.d.ts +18 -0
- package/dist/view/render/place.js +69 -0
- package/dist/view/render/place.js.map +1 -0
- package/dist/view/render/plan.d.ts +26 -0
- package/dist/view/render/plan.js +124 -0
- package/dist/view/render/plan.js.map +1 -0
- package/dist/view/render/raw.d.ts +18 -0
- package/dist/view/render/raw.js +68 -0
- package/dist/view/render/raw.js.map +1 -0
- package/dist/view/render/render.d.ts +12 -0
- package/dist/view/render/render.js +60 -0
- package/dist/view/render/render.js.map +1 -0
- package/dist/view/render/reorder.d.ts +4 -0
- package/dist/view/render/reorder.js +101 -0
- package/dist/view/render/reorder.js.map +1 -0
- package/dist/view/render/rows.d.ts +23 -0
- package/dist/view/render/rows.js +95 -0
- package/dist/view/render/rows.js.map +1 -0
- package/dist/view/render/seen.d.ts +11 -0
- package/dist/view/render/seen.js +17 -0
- package/dist/view/render/seen.js.map +1 -0
- package/dist/view/render/values.d.ts +29 -0
- package/dist/view/render/values.js +13 -0
- package/dist/view/render/values.js.map +1 -0
- package/dist/view/render/warn.d.ts +14 -0
- package/dist/view/render/warn.js +69 -0
- package/dist/view/render/warn.js.map +1 -0
- package/dist/view/server/component.d.ts +9 -0
- package/dist/view/server/component.js +42 -0
- package/dist/view/server/component.js.map +1 -0
- package/dist/view/server/escape.d.ts +10 -0
- package/dist/view/server/escape.js +34 -0
- package/dist/view/server/escape.js.map +1 -0
- package/dist/view/server/index.d.ts +28 -0
- package/dist/view/server/index.js +72 -0
- package/dist/view/server/index.js.map +1 -0
- package/dist/view/server/sha256.d.ts +2 -0
- package/dist/view/server/sha256.js +75 -0
- package/dist/view/server/sha256.js.map +1 -0
- package/dist/view/server/tags.d.ts +57 -0
- package/dist/view/server/tags.js +121 -0
- package/dist/view/server/tags.js.map +1 -0
- package/dist/view/server/values.d.ts +16 -0
- package/dist/view/server/values.js +86 -0
- package/dist/view/server/values.js.map +1 -0
- package/dist/view/server/writer.d.ts +16 -0
- package/dist/view/server/writer.js +155 -0
- package/dist/view/server/writer.js.map +1 -0
- package/dist/view/styles.d.ts +25 -0
- package/dist/view/styles.js +58 -0
- package/dist/view/styles.js.map +1 -0
- package/dist/view/template-element.d.ts +3 -0
- package/dist/view/template-element.js +25 -0
- package/dist/view/template-element.js.map +1 -0
- package/dist/view/template.d.ts +21 -0
- package/dist/view/template.js +30 -0
- package/dist/view/template.js.map +1 -0
- package/dist/vite.d.ts +45 -6
- package/dist/vite.js +150 -25
- package/dist/vite.js.map +1 -1
- package/package.json +39 -4
- package/dist/accessible-name.d.ts +0 -19
- package/dist/accessible-name.js +0 -56
- package/dist/accessible-name.js.map +0 -1
- package/dist/element-directive.d.ts +0 -20
- package/dist/element-directive.js +0 -31
- package/dist/element-directive.js.map +0 -1
- package/dist/invalid.d.ts +0 -21
- package/dist/invalid.js +0 -70
- package/dist/invalid.js.map +0 -1
- package/dist/lit-html-check.d.ts +0 -6
- package/dist/lit-html-check.js +0 -48
- package/dist/lit-html-check.js.map +0 -1
- package/dist/live-boolean.d.ts +0 -22
- package/dist/live-boolean.js +0 -34
- package/dist/live-boolean.js.map +0 -1
- package/dist/styles.d.ts +0 -12
- package/dist/styles.js +0 -11
- package/dist/styles.js.map +0 -1
- package/dist/template-whitespace.d.ts +0 -7
- package/dist/template-whitespace.js.map +0 -1
- package/dist/templates.d.ts +0 -5
- package/dist/templates.js +0 -15
- package/dist/templates.js.map +0 -1
- package/dist/textarea.d.ts +0 -26
- package/dist/textarea.js +0 -85
- package/dist/textarea.js.map +0 -1
package/dist/hydration.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"hydration.js","sourceRoot":"","sources":["../src/hydration.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"hydration.js","sourceRoot":"","sources":["../src/hydration.ts"],"names":[],"mappings":"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","sourcesContent":["// Server-render seeds (docs/design-docs/0012-ssr.md, view/06-server.md \"Components\"). The\n// server writes each component's state, plus the props an attribute can't carry, into one\n// attribute; the client reads it on connect, before its first render, so both sides start from\n// the same state. The walk that then hydrates the server's DOM is hydration-client.ts, which\n// core loads lazily (view/07-hydration.md \"Loading\").\nimport { warnJsonHazard } from './json-safety.js';\nimport { hold } from './scheduler.js';\nimport { DEV } from './view/index.js';\n\n/** Host attribute holding the JSON seed. Removed once the client has read it. */\nexport const SEED_ATTRIBUTE = 'data-gyral-seed';\n\nexport interface Seed {\n /**\n * The server's state. Omitted when it equals what `init(props)` returns for the seeded\n * props (gyral-czi 4k7.10): the client recomputes it instead of reading a second copy of\n * data the props already carry.\n */\n readonly state?: unknown;\n readonly props: Readonly<Record<string, unknown>>;\n}\n\n/** JSON equality: seeds are JSON, so two values that serialize alike hydrate alike. */\nexport const sameJson = (a: unknown, b: unknown): boolean =>\n JSON.stringify(a) === JSON.stringify(b);\n\n/**\n * Server side: the seed for a component whose props `carried` travel in no attribute\n * (property holes) and whose state is `state`; `initial` is `init(props)`'s state.\n */\nexport function makeSeed(\n tag: string,\n state: unknown,\n initial: unknown,\n carried: Readonly<Record<string, unknown>>,\n): Seed {\n const seed: Seed = sameJson(state, initial) ? { props: carried } : { state, props: carried };\n if (DEV) warnJsonHazard(`<${tag}>`, seed, 'seed'); // view/06-server.md \"Seed\": development\n\n return seed;\n}\n\n/** Client side: reads and removes the seed, if this element was server-rendered by Gyral. */\nexport function takeSeed(host: Element): Seed | undefined {\n const raw = host.getAttribute(SEED_ATTRIBUTE);\n if (raw === null) return undefined;\n host.removeAttribute(SEED_ATTRIBUTE);\n try {\n const parsed = JSON.parse(raw) as Partial<Seed> | null;\n if (parsed === null || typeof parsed !== 'object') return undefined;\n const props = parsed.props ?? {};\n return 'state' in parsed ? { state: parsed.state, props } : { props };\n } catch (error) {\n console.error(`<${host.localName}> has an unreadable ${SEED_ATTRIBUTE}`, error);\n return undefined;\n }\n}\n\n/**\n * The walk and islands (hydration-client.ts) once loaded; `null` if loading failed (a stale\n * deployment: server-rendered hosts then render fresh); undefined until then.\n */\nexport let hydrationCode: typeof import('./hydration-client.js') | null | undefined;\n/** Hosts waiting for the code, in connection order; undefined when no load is pending. */\nlet waiting: (() => void)[] | undefined;\n\n/**\n * Loads the hydration code (once) and runs `next` when it has loaded or failed, in call\n * order. settled() waits meanwhile (view/07-hydration.md \"Loading\").\n */\nexport function whenHydrationLoads(next: () => void): void {\n if (waiting !== undefined) {\n waiting.push(next);\n return;\n }\n waiting = [next];\n const done = (code: typeof hydrationCode): void => {\n hydrationCode = code;\n const hosts = waiting ?? [];\n waiting = undefined;\n // Each in its own microtask, in order: one host throwing doesn't stop the others. They all\n // run before `hold` counts the load as done.\n for (const host of hosts) queueMicrotask(host);\n };\n hold(\n import('./hydration-client.js').then(done, (error: unknown) => {\n console.error('gyral: hydration code failed to load; rendering fresh', error);\n done(null);\n }),\n );\n}\n"]}
|
package/dist/index.d.ts
CHANGED
|
@@ -9,35 +9,27 @@ export { ISLAND_ATTRIBUTE } from './islands.js';
|
|
|
9
9
|
export type { HydrateStrategy } from './islands.js';
|
|
10
10
|
export type { ChildSource, OutputSource } from './children.js';
|
|
11
11
|
export { define } from './define.js';
|
|
12
|
+
export { intents } from './intent.js';
|
|
13
|
+
export { settled } from './settled.js';
|
|
12
14
|
export { changed, defineStore, send } from './store.js';
|
|
13
15
|
export type { AnyStore, AnyStoreInstance, Store, StoreChanged, StoreInstance, StoreOverrides, StoreRef, StoreSendInput, SeedCheck, StoreResolver, StoreSpec, StoreUpdate, } from './store.js';
|
|
14
16
|
export { STORE_SEND } from './store.js';
|
|
15
17
|
export { resetDocumentStores, scriptSafeJson, STORE_SEED_ATTRIBUTE, StoreRegistry, STORES_ELEMENT, withStoreScope, } from './store-scope.js';
|
|
16
|
-
export { defineStoresProvider } from './stores-provider.js';
|
|
17
18
|
export { DRIVERS_ELEMENT, provideDrivers } from './drivers-scope.js';
|
|
18
19
|
export { jsonHazard, warnJsonHazard } from './json-safety.js';
|
|
19
20
|
export { random, randomDriver, randomInt, toInt, type RandomInput } from './random.js';
|
|
20
21
|
export { defineForm, field, fieldErrors, form, formDataToObject, formFields, intentRejectedSchema, redirectedTo, validateForm, } from './forms.js';
|
|
21
22
|
export type { FormDefinition, FormRedirected, FormResult, FormValue } from './forms.js';
|
|
22
|
-
export { ElementDirective } from './element-directive.js';
|
|
23
23
|
export { runInit } from './init.js';
|
|
24
|
-
export { invalid } from './invalid.js';
|
|
25
|
-
export { findInScope, labelledBy } from './
|
|
26
|
-
export {
|
|
27
|
-
export {
|
|
24
|
+
export { invalid } from './hooks/invalid.js';
|
|
25
|
+
export { findInScope, labelledBy } from './hooks/labelled-by.js';
|
|
26
|
+
export { prop } from './prop.js';
|
|
27
|
+
export type { Prop, PropKind, PropsOf } from './prop.js';
|
|
28
28
|
export { DEVTOOLS_ENABLED as devtoolsEnabled, devLiveComponents as devtoolsLiveComponents, } from '#devtools';
|
|
29
29
|
export { DEVTOOLS_GLOBAL } from './devtools-events.js';
|
|
30
30
|
export type { CommandPhase, CommandTraceEvent, DevComponentRef, DevEvent, DevtoolsHook, } from './devtools-events.js';
|
|
31
|
-
export
|
|
32
|
-
export type { Styles } from './styles.js';
|
|
33
|
-
export { HIDDEN_MARKER, HYDRATE_KEY, isLightComponent, LIGHT_ATTRIBUTE } from './light-dom.js';
|
|
31
|
+
export { isLightComponent, LIGHT_ATTRIBUTE } from './light-dom.js';
|
|
34
32
|
export type { GyralElement, GyralElementClass } from './define.js';
|
|
35
33
|
export type { ComponentSpec, Ctx, FieldIssue, FormFields, IntentInput, IntentNames, IntentParser, IntentRejected, Intents, PropDeclarations, Hydrated, PropsChanged, Stateless, StoreReader, Tagged, Update, } from './types.js';
|
|
36
|
-
export { css, nothing,
|
|
37
|
-
export {
|
|
38
|
-
export { directive } from 'lit/directive.js';
|
|
39
|
-
export { classMap } from 'lit/directives/class-map.js';
|
|
40
|
-
export { keyed } from 'lit/directives/keyed.js';
|
|
41
|
-
export { live } from 'lit/directives/live.js';
|
|
42
|
-
export { repeat } from 'lit/directives/repeat.js';
|
|
43
|
-
export { styleMap } from 'lit/directives/style-map.js';
|
|
34
|
+
export { css, defineHook, each, html, HydrationMismatch, nothing, raw } from './view/index.js';
|
|
35
|
+
export type { ChildValue, CssValue, HookAttributes, HookResult, HookSpec, ListResult, RawResult, StyleSource, Styles, TemplateResult, } from './view/index.js';
|
package/dist/index.js
CHANGED
|
@@ -4,34 +4,25 @@ export { focus } from './focus.js';
|
|
|
4
4
|
export { invokersSupported } from './invokers.js';
|
|
5
5
|
export { ISLAND_ATTRIBUTE } from './islands.js';
|
|
6
6
|
export { define } from './define.js';
|
|
7
|
+
export { intents } from './intent.js';
|
|
8
|
+
export { settled } from './settled.js';
|
|
7
9
|
export { changed, defineStore, send } from './store.js';
|
|
8
10
|
export { STORE_SEND } from './store.js';
|
|
9
11
|
// Store scoping: used by @gyral/ssr (server scope + page seed) and @gyral/testing.
|
|
10
12
|
export { resetDocumentStores, scriptSafeJson, STORE_SEED_ATTRIBUTE, StoreRegistry, STORES_ELEMENT, withStoreScope, } from './store-scope.js';
|
|
11
|
-
export { defineStoresProvider } from './stores-provider.js';
|
|
12
13
|
export { DRIVERS_ELEMENT, provideDrivers } from './drivers-scope.js';
|
|
13
14
|
export { jsonHazard, warnJsonHazard } from './json-safety.js';
|
|
14
15
|
export { random, randomDriver, randomInt, toInt } from './random.js';
|
|
15
16
|
export { defineForm, field, fieldErrors, form, formDataToObject, formFields, intentRejectedSchema, redirectedTo, validateForm, } from './forms.js';
|
|
16
|
-
export { ElementDirective } from './element-directive.js';
|
|
17
17
|
export { runInit } from './init.js';
|
|
18
|
-
export { invalid } from './invalid.js';
|
|
19
|
-
export { findInScope, labelledBy } from './
|
|
20
|
-
export {
|
|
21
|
-
export { textarea, textareaMarkup } from './textarea.js';
|
|
18
|
+
export { invalid } from './hooks/invalid.js';
|
|
19
|
+
export { findInScope, labelledBy } from './hooks/labelled-by.js';
|
|
20
|
+
export { prop } from './prop.js';
|
|
22
21
|
// Devtools event stream (ADR 0017): emitted in development builds only.
|
|
23
22
|
export { DEVTOOLS_ENABLED as devtoolsEnabled, devLiveComponents as devtoolsLiveComponents, } from '#devtools';
|
|
24
23
|
export { DEVTOOLS_GLOBAL } from './devtools-events.js';
|
|
25
|
-
// Used by @gyral/ssr
|
|
26
|
-
export {
|
|
27
|
-
// The view layer
|
|
28
|
-
|
|
29
|
-
export { css, nothing, unsafeCSS } from 'lit';
|
|
30
|
-
export { html, svg } from './templates.js';
|
|
31
|
-
export { directive } from 'lit/directive.js';
|
|
32
|
-
export { classMap } from 'lit/directives/class-map.js';
|
|
33
|
-
export { keyed } from 'lit/directives/keyed.js';
|
|
34
|
-
export { live } from 'lit/directives/live.js';
|
|
35
|
-
export { repeat } from 'lit/directives/repeat.js';
|
|
36
|
-
export { styleMap } from 'lit/directives/style-map.js';
|
|
24
|
+
// Used by the server renderer and @gyral/ssr (ADR 0014, view/06-server.md).
|
|
25
|
+
export { isLightComponent, LIGHT_ATTRIBUTE } from './light-dom.js';
|
|
26
|
+
// The view layer (ADR 0018, docs/design-docs/view/): templates, lists, hooks and styles.
|
|
27
|
+
export { css, defineHook, each, html, HydrationMismatch, nothing, raw } from './view/index.js';
|
|
37
28
|
//# sourceMappingURL=index.js.map
|
package/dist/index.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,OAAO,EAAE,YAAY,EAAE,MAAM,cAAc,CAAC;AAYrD,OAAO,EAAE,KAAK,EAAE,IAAI,EAAE,MAAM,eAAe,CAAC;AAC5C,OAAO,EAAE,KAAK,EAAE,MAAM,YAAY,CAAC;AAEnC,OAAO,EAAE,iBAAiB,EAAE,MAAM,eAAe,CAAC;AAElD,OAAO,EAAE,gBAAgB,EAAE,MAAM,cAAc,CAAC;AAGhD,OAAO,EAAE,MAAM,EAAE,MAAM,aAAa,CAAC;AACrC,OAAO,EAAE,OAAO,EAAE,WAAW,EAAE,IAAI,EAAE,MAAM,YAAY,CAAC;AAexD,OAAO,EAAE,UAAU,EAAE,MAAM,YAAY,CAAC;AACxC,mFAAmF;AACnF,OAAO,EACL,mBAAmB,EACnB,cAAc,EACd,oBAAoB,EACpB,aAAa,EACb,cAAc,EACd,cAAc,GACf,MAAM,kBAAkB,CAAC;AAC1B,OAAO,EAAE,
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,OAAO,EAAE,YAAY,EAAE,MAAM,cAAc,CAAC;AAYrD,OAAO,EAAE,KAAK,EAAE,IAAI,EAAE,MAAM,eAAe,CAAC;AAC5C,OAAO,EAAE,KAAK,EAAE,MAAM,YAAY,CAAC;AAEnC,OAAO,EAAE,iBAAiB,EAAE,MAAM,eAAe,CAAC;AAElD,OAAO,EAAE,gBAAgB,EAAE,MAAM,cAAc,CAAC;AAGhD,OAAO,EAAE,MAAM,EAAE,MAAM,aAAa,CAAC;AACrC,OAAO,EAAE,OAAO,EAAE,MAAM,aAAa,CAAC;AACtC,OAAO,EAAE,OAAO,EAAE,MAAM,cAAc,CAAC;AACvC,OAAO,EAAE,OAAO,EAAE,WAAW,EAAE,IAAI,EAAE,MAAM,YAAY,CAAC;AAexD,OAAO,EAAE,UAAU,EAAE,MAAM,YAAY,CAAC;AACxC,mFAAmF;AACnF,OAAO,EACL,mBAAmB,EACnB,cAAc,EACd,oBAAoB,EACpB,aAAa,EACb,cAAc,EACd,cAAc,GACf,MAAM,kBAAkB,CAAC;AAC1B,OAAO,EAAE,eAAe,EAAE,cAAc,EAAE,MAAM,oBAAoB,CAAC;AACrE,OAAO,EAAE,UAAU,EAAE,cAAc,EAAE,MAAM,kBAAkB,CAAC;AAC9D,OAAO,EAAE,MAAM,EAAE,YAAY,EAAE,SAAS,EAAE,KAAK,EAAoB,MAAM,aAAa,CAAC;AACvF,OAAO,EACL,UAAU,EACV,KAAK,EACL,WAAW,EACX,IAAI,EACJ,gBAAgB,EAChB,UAAU,EACV,oBAAoB,EACpB,YAAY,EACZ,YAAY,GACb,MAAM,YAAY,CAAC;AAEpB,OAAO,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;AACpC,OAAO,EAAE,OAAO,EAAE,MAAM,oBAAoB,CAAC;AAC7C,OAAO,EAAE,WAAW,EAAE,UAAU,EAAE,MAAM,wBAAwB,CAAC;AACjE,OAAO,EAAE,IAAI,EAAE,MAAM,WAAW,CAAC;AAEjC,wEAAwE;AACxE,OAAO,EACL,gBAAgB,IAAI,eAAe,EACnC,iBAAiB,IAAI,sBAAsB,GAC5C,MAAM,WAAW,CAAC;AACnB,OAAO,EAAE,eAAe,EAAE,MAAM,sBAAsB,CAAC;AAQvD,4EAA4E;AAC5E,OAAO,EAAE,gBAAgB,EAAE,eAAe,EAAE,MAAM,gBAAgB,CAAC;AAqBnE,yFAAyF;AACzF,OAAO,EAAE,GAAG,EAAE,UAAU,EAAE,IAAI,EAAE,IAAI,EAAE,iBAAiB,EAAE,OAAO,EAAE,GAAG,EAAE,MAAM,iBAAiB,CAAC","sourcesContent":["export { command, defineDriver } from './command.js';\nexport type {\n AnyDriver,\n Command,\n CommandHandlers,\n Concurrency,\n Driver,\n DriverContext,\n DriverOverrides,\n Next,\n RetryPolicy,\n} from './command.js';\nexport { child, emit } from './children.js';\nexport { focus } from './focus.js';\nexport type { FocusOptions } from './focus.js';\nexport { invokersSupported } from './invokers.js';\nexport type { CommandInfo } from './invokers.js';\nexport { ISLAND_ATTRIBUTE } from './islands.js';\nexport type { HydrateStrategy } from './islands.js';\nexport type { ChildSource, OutputSource } from './children.js';\nexport { define } from './define.js';\nexport { intents } from './intent.js';\nexport { settled } from './settled.js';\nexport { changed, defineStore, send } from './store.js';\nexport type {\n AnyStore,\n AnyStoreInstance,\n Store,\n StoreChanged,\n StoreInstance,\n StoreOverrides,\n StoreRef,\n StoreSendInput,\n SeedCheck,\n StoreResolver,\n StoreSpec,\n StoreUpdate,\n} from './store.js';\nexport { STORE_SEND } from './store.js';\n// Store scoping: used by @gyral/ssr (server scope + page seed) and @gyral/testing.\nexport {\n resetDocumentStores,\n scriptSafeJson,\n STORE_SEED_ATTRIBUTE,\n StoreRegistry,\n STORES_ELEMENT,\n withStoreScope,\n} from './store-scope.js';\nexport { DRIVERS_ELEMENT, provideDrivers } from './drivers-scope.js';\nexport { jsonHazard, warnJsonHazard } from './json-safety.js';\nexport { random, randomDriver, randomInt, toInt, type RandomInput } from './random.js';\nexport {\n defineForm,\n field,\n fieldErrors,\n form,\n formDataToObject,\n formFields,\n intentRejectedSchema,\n redirectedTo,\n validateForm,\n} from './forms.js';\nexport type { FormDefinition, FormRedirected, FormResult, FormValue } from './forms.js';\nexport { runInit } from './init.js';\nexport { invalid } from './hooks/invalid.js';\nexport { findInScope, labelledBy } from './hooks/labelled-by.js';\nexport { prop } from './prop.js';\nexport type { Prop, PropKind, PropsOf } from './prop.js';\n// Devtools event stream (ADR 0017): emitted in development builds only.\nexport {\n DEVTOOLS_ENABLED as devtoolsEnabled,\n devLiveComponents as devtoolsLiveComponents,\n} from '#devtools';\nexport { DEVTOOLS_GLOBAL } from './devtools-events.js';\nexport type {\n CommandPhase,\n CommandTraceEvent,\n DevComponentRef,\n DevEvent,\n DevtoolsHook,\n} from './devtools-events.js';\n// Used by the server renderer and @gyral/ssr (ADR 0014, view/06-server.md).\nexport { isLightComponent, LIGHT_ATTRIBUTE } from './light-dom.js';\nexport type { GyralElement, GyralElementClass } from './define.js';\nexport type {\n ComponentSpec,\n Ctx,\n FieldIssue,\n FormFields,\n IntentInput,\n IntentNames,\n IntentParser,\n IntentRejected,\n Intents,\n PropDeclarations,\n Hydrated,\n PropsChanged,\n Stateless,\n StoreReader,\n Tagged,\n Update,\n} from './types.js';\n\n// The view layer (ADR 0018, docs/design-docs/view/): templates, lists, hooks and styles.\nexport { css, defineHook, each, html, HydrationMismatch, nothing, raw } from './view/index.js';\nexport type {\n ChildValue,\n CssValue,\n HookAttributes,\n HookResult,\n HookSpec,\n ListResult,\n RawResult,\n StyleSource,\n Styles,\n TemplateResult,\n} from './view/index.js';\n"]}
|
package/dist/intent.d.ts
CHANGED
|
@@ -1,16 +1,26 @@
|
|
|
1
|
-
import type { IntentInput, IntentParser, Tagged } from './types.js';
|
|
1
|
+
import type { IntentInput, IntentNames, IntentParser, Tagged } from './types.js';
|
|
2
|
+
import type { Markup } from './view/index.js';
|
|
2
3
|
/** Event a child component dispatches on its host to send an output up (ADR 0010). */
|
|
3
4
|
export declare const OUTPUT_EVENT = "gyral-output";
|
|
5
|
+
/** Default triggers (`defaultTrigger`): every component root listens for these. */
|
|
6
|
+
export declare const DEFAULT_EVENTS: readonly string[];
|
|
4
7
|
/**
|
|
5
|
-
*
|
|
6
|
-
* non-bubbling events such as `toggle` are seen too)
|
|
7
|
-
* `
|
|
8
|
-
*
|
|
8
|
+
* The events `data-intent-on` usually names. A component root listens (capture phase, so
|
|
9
|
+
* non-bubbling events such as `toggle` are seen too) for the defaults, for `spec.events`, and
|
|
10
|
+
* for the `data-intent-on` values in the templates it renders; a template that binds
|
|
11
|
+
* `data-intent-on` dynamically adds all of these (view/05-element.md "Intent events").
|
|
9
12
|
*/
|
|
10
|
-
export declare const INTENT_EVENTS: readonly [
|
|
13
|
+
export declare const INTENT_EVENTS: readonly string[];
|
|
14
|
+
/** The intent events a template's (or `raw()` markup's) `data-intent-on` attributes name. */
|
|
15
|
+
export declare function eventsOf(markup: Markup): readonly string[];
|
|
11
16
|
/** The event that fires an intent unless `data-intent-on` overrides it. */
|
|
12
17
|
export declare function defaultTrigger(el: Element): string;
|
|
13
18
|
export declare function markGyralHost(ctor: object): void;
|
|
19
|
+
/**
|
|
20
|
+
* The number of Gyral host ancestors of `el` in the composed tree (across shadow roots): the
|
|
21
|
+
* scheduler renders smaller depths first (view/04-scheduler.md "Marking").
|
|
22
|
+
*/
|
|
23
|
+
export declare function hostDepth(el: Element): number;
|
|
14
24
|
/**
|
|
15
25
|
* Finds the nearest `data-intent` element for this event that belongs to `root`. Elements
|
|
16
26
|
* inside nested components are ignored: that is component isolation.
|
|
@@ -19,7 +29,20 @@ export declare function findIntentElement(event: Event, root: Node): Element | u
|
|
|
19
29
|
/** Reads an event into an IntentInput. Form submissions are prevented and turned into FormData. */
|
|
20
30
|
export declare function readIntent(event: Event, root: Node): IntentInput | undefined;
|
|
21
31
|
export declare const intentNames: unknown;
|
|
22
|
-
/**
|
|
23
|
-
|
|
32
|
+
/**
|
|
33
|
+
* A component's intent names as a module-level constant, so pure list rows can name intents
|
|
34
|
+
* without passing them through `pick` (view/03-lists.md "Rows must be pure"). The same object
|
|
35
|
+
* the view gets as `i`:
|
|
36
|
+
*
|
|
37
|
+
* const i = intents<Msg>();
|
|
38
|
+
* const Row = (t: Todo) => html`<input value=${t.id} data-intent=${i.Toggle} />`;
|
|
39
|
+
*/
|
|
40
|
+
export declare function intents<M extends Tagged>(): IntentNames<M>;
|
|
41
|
+
/**
|
|
42
|
+
* Adds capture listeners for `types` to a component root, skipping those in `listening`. A
|
|
43
|
+
* root that listens for `command` in a browser without invoker commands loads the fallback
|
|
44
|
+
* (invokers-shim.ts, ADR 0003 tier 3); settled() waits for it.
|
|
45
|
+
*/
|
|
46
|
+
export declare function listenForIntents(root: Node, listening: Set<string>, types: readonly string[], handler: (event: Event) => void): void;
|
|
24
47
|
/** Parses one event with its matching parser and delivers the message (sync or async). */
|
|
25
48
|
export declare function handleIntent<M>(event: Event, root: Node, parsers: Readonly<Record<string, IntentParser<M> | undefined>>, tag: string, deliver: (msg: Tagged | undefined) => void): void;
|
package/dist/intent.js
CHANGED
|
@@ -1,25 +1,44 @@
|
|
|
1
|
-
import { commandOf,
|
|
1
|
+
import { commandOf, invokersSupported } from './invokers.js';
|
|
2
|
+
import { hold } from './scheduler.js';
|
|
2
3
|
/** Event a child component dispatches on its host to send an output up (ADR 0010). */
|
|
3
4
|
export const OUTPUT_EVENT = 'gyral-output';
|
|
4
|
-
/**
|
|
5
|
-
|
|
6
|
-
* non-bubbling events such as `toggle` are seen too). Only `click`, `submit`, `input`,
|
|
7
|
-
* `change` and outputs are default triggers; the rest fire via `data-intent-on="…"`.
|
|
8
|
-
* Components may add more with `spec.events`.
|
|
9
|
-
*/
|
|
10
|
-
export const INTENT_EVENTS = [
|
|
5
|
+
/** Default triggers (`defaultTrigger`): every component root listens for these. */
|
|
6
|
+
export const DEFAULT_EVENTS = [
|
|
11
7
|
'click',
|
|
12
8
|
'submit',
|
|
13
9
|
'input',
|
|
14
10
|
'change',
|
|
11
|
+
OUTPUT_EVENT,
|
|
12
|
+
];
|
|
13
|
+
/**
|
|
14
|
+
* The events `data-intent-on` usually names. A component root listens (capture phase, so
|
|
15
|
+
* non-bubbling events such as `toggle` are seen too) for the defaults, for `spec.events`, and
|
|
16
|
+
* for the `data-intent-on` values in the templates it renders; a template that binds
|
|
17
|
+
* `data-intent-on` dynamically adds all of these (view/05-element.md "Intent events").
|
|
18
|
+
*/
|
|
19
|
+
export const INTENT_EVENTS = [
|
|
20
|
+
...DEFAULT_EVENTS,
|
|
15
21
|
'keydown',
|
|
16
22
|
'keyup',
|
|
17
23
|
'focusin',
|
|
18
24
|
'focusout',
|
|
19
25
|
'toggle',
|
|
20
26
|
'command',
|
|
21
|
-
OUTPUT_EVENT,
|
|
22
27
|
];
|
|
28
|
+
/** A static `data-intent-on` value, quoted or not (event names have no spaces or quotes). */
|
|
29
|
+
const INTENT_ON = /\sdata-intent-on=["']?([^"'\s>]+)/gi;
|
|
30
|
+
const eventsByTemplate = new WeakMap();
|
|
31
|
+
/** The intent events a template's (or `raw()` markup's) `data-intent-on` attributes name. */
|
|
32
|
+
export function eventsOf(markup) {
|
|
33
|
+
let events = eventsByTemplate.get(markup);
|
|
34
|
+
if (events === undefined) {
|
|
35
|
+
events = markup.parts?.some((p) => p[2] === 'data-intent-on') // a bound attribute's name
|
|
36
|
+
? INTENT_EVENTS
|
|
37
|
+
: Array.from(markup.html.matchAll(INTENT_ON), (m) => m[1] ?? '');
|
|
38
|
+
eventsByTemplate.set(markup, events);
|
|
39
|
+
}
|
|
40
|
+
return events;
|
|
41
|
+
}
|
|
23
42
|
const isToggle = (el) => el instanceof HTMLInputElement && (el.type === 'checkbox' || el.type === 'radio');
|
|
24
43
|
// ToggleEvent (popover, <details>) is not Baseline widely available; read it structurally.
|
|
25
44
|
function toggleState(event) {
|
|
@@ -27,24 +46,25 @@ function toggleState(event) {
|
|
|
27
46
|
return undefined;
|
|
28
47
|
return event.newState === 'open' ? 'open' : 'closed';
|
|
29
48
|
}
|
|
30
|
-
const CLICK_INPUT_TYPES =
|
|
49
|
+
const CLICK_INPUT_TYPES = /^(button|submit|reset|image)$/;
|
|
31
50
|
/** The event that fires an intent unless `data-intent-on` overrides it. */
|
|
32
51
|
export function defaultTrigger(el) {
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
52
|
+
switch (el.localName) {
|
|
53
|
+
case 'form':
|
|
54
|
+
return 'submit';
|
|
55
|
+
case 'select':
|
|
56
|
+
return 'change';
|
|
57
|
+
case 'textarea':
|
|
58
|
+
return 'input';
|
|
59
|
+
case 'input': {
|
|
60
|
+
const type = el.type;
|
|
61
|
+
if (CLICK_INPUT_TYPES.test(type))
|
|
62
|
+
return 'click';
|
|
63
|
+
return type === 'checkbox' || type === 'radio' ? 'change' : 'input';
|
|
64
|
+
}
|
|
43
65
|
}
|
|
44
66
|
// Custom elements (autonomous: the name has a dash) talk to their parent via outputs.
|
|
45
|
-
|
|
46
|
-
return OUTPUT_EVENT;
|
|
47
|
-
return 'click';
|
|
67
|
+
return el.localName.includes('-') ? OUTPUT_EVENT : 'click';
|
|
48
68
|
}
|
|
49
69
|
function triggerOf(el) {
|
|
50
70
|
return el.getAttribute('data-intent-on') ?? defaultTrigger(el);
|
|
@@ -55,6 +75,19 @@ export function markGyralHost(ctor) {
|
|
|
55
75
|
hostClasses.add(ctor);
|
|
56
76
|
}
|
|
57
77
|
const isGyralHost = (node) => hostClasses.has(node.constructor);
|
|
78
|
+
/**
|
|
79
|
+
* The number of Gyral host ancestors of `el` in the composed tree (across shadow roots): the
|
|
80
|
+
* scheduler renders smaller depths first (view/04-scheduler.md "Marking").
|
|
81
|
+
*/
|
|
82
|
+
export function hostDepth(el) {
|
|
83
|
+
let depth = 0;
|
|
84
|
+
for (let node = el.parentNode; node !== null;) {
|
|
85
|
+
if (isGyralHost(node))
|
|
86
|
+
depth += 1;
|
|
87
|
+
node = node instanceof ShadowRoot ? node.host : node.parentNode;
|
|
88
|
+
}
|
|
89
|
+
return depth;
|
|
90
|
+
}
|
|
58
91
|
/**
|
|
59
92
|
* Does `node` belong to the component whose intent root is `root`? `root` is the component's
|
|
60
93
|
* shadow root, or the host itself for light-DOM components (ADR 0014). The node must be in the
|
|
@@ -127,12 +160,34 @@ export function readIntent(event, root) {
|
|
|
127
160
|
// Any property read returns its own name, so `intents.Increment === 'Increment'`.
|
|
128
161
|
// Types restrict reads to real message tags; a tag without a parser warns at event time.
|
|
129
162
|
export const intentNames = new Proxy({}, { get: (_target, key) => (typeof key === 'string' ? key : undefined) });
|
|
130
|
-
/**
|
|
131
|
-
|
|
132
|
-
|
|
163
|
+
/**
|
|
164
|
+
* A component's intent names as a module-level constant, so pure list rows can name intents
|
|
165
|
+
* without passing them through `pick` (view/03-lists.md "Rows must be pure"). The same object
|
|
166
|
+
* the view gets as `i`:
|
|
167
|
+
*
|
|
168
|
+
* const i = intents<Msg>();
|
|
169
|
+
* const Row = (t: Todo) => html`<input value=${t.id} data-intent=${i.Toggle} />`;
|
|
170
|
+
*/
|
|
171
|
+
export function intents() {
|
|
172
|
+
return intentNames;
|
|
173
|
+
}
|
|
174
|
+
/**
|
|
175
|
+
* Adds capture listeners for `types` to a component root, skipping those in `listening`. A
|
|
176
|
+
* root that listens for `command` in a browser without invoker commands loads the fallback
|
|
177
|
+
* (invokers-shim.ts, ADR 0003 tier 3); settled() waits for it.
|
|
178
|
+
*/
|
|
179
|
+
export function listenForIntents(root, listening, types, handler) {
|
|
180
|
+
for (const type of types) {
|
|
181
|
+
if (listening.has(type))
|
|
182
|
+
continue;
|
|
183
|
+
listening.add(type);
|
|
133
184
|
root.addEventListener(type, handler, { capture: true });
|
|
185
|
+
if (type === 'command' && !invokersSupported()) {
|
|
186
|
+
hold(import('./invokers-shim.js').then((shim) => {
|
|
187
|
+
shim.shimInvokers(root);
|
|
188
|
+
}, reportError));
|
|
189
|
+
}
|
|
134
190
|
}
|
|
135
|
-
shimInvokers(root); // `command` intents in browsers without invoker commands
|
|
136
191
|
}
|
|
137
192
|
/** Parses one event with its matching parser and delivers the message (sync or async). */
|
|
138
193
|
export function handleIntent(event, root, parsers, tag, deliver) {
|
package/dist/intent.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"intent.js","sourceRoot":"","sources":["../src/intent.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,SAAS,EAAE,YAAY,EAAE,MAAM,eAAe,CAAC;AAGxD,sFAAsF;AACtF,MAAM,CAAC,MAAM,YAAY,GAAG,cAAc,CAAC;AAE3C;;;;;GAKG;AACH,MAAM,CAAC,MAAM,aAAa,GAAG;IAC3B,OAAO;IACP,QAAQ;IACR,OAAO;IACP,QAAQ;IACR,SAAS;IACT,OAAO;IACP,SAAS;IACT,UAAU;IACV,QAAQ;IACR,SAAS;IACT,YAAY;CACJ,CAAC;AAEX,MAAM,QAAQ,GAAG,CAAC,EAAW,EAA0B,EAAE,CACvD,EAAE,YAAY,gBAAgB,IAAI,CAAC,EAAE,CAAC,IAAI,KAAK,UAAU,IAAI,EAAE,CAAC,IAAI,KAAK,OAAO,CAAC,CAAC;AAEpF,2FAA2F;AAC3F,SAAS,WAAW,CAAC,KAAY;IAC/B,IAAI,KAAK,CAAC,IAAI,KAAK,QAAQ,IAAI,CAAC,CAAC,UAAU,IAAI,KAAK,CAAC;QAAE,OAAO,SAAS,CAAC;IACxE,OAAO,KAAK,CAAC,QAAQ,KAAK,MAAM,CAAC,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,QAAQ,CAAC;AACvD,CAAC;AAED,MAAM,iBAAiB,GAAG,IAAI,GAAG,CAAC,CAAC,QAAQ,EAAE,QAAQ,EAAE,OAAO,EAAE,OAAO,CAAC,CAAC,CAAC;AAE1E,2EAA2E;AAC3E,MAAM,UAAU,cAAc,CAAC,EAAW;IACxC,IAAI,EAAE,YAAY,eAAe;QAAE,OAAO,QAAQ,CAAC;IACnD,IAAI,EAAE,YAAY,iBAAiB;QAAE,OAAO,QAAQ,CAAC;IACrD,IAAI,EAAE,YAAY,mBAAmB;QAAE,OAAO,OAAO,CAAC;IACtD,IAAI,EAAE,YAAY,gBAAgB,EAAE,CAAC;QACnC,IAAI,iBAAiB,CAAC,GAAG,CAAC,EAAE,CAAC,IAAI,CAAC;YAAE,OAAO,OAAO,CAAC;QACnD,OAAO,EAAE,CAAC,IAAI,KAAK,UAAU,IAAI,EAAE,CAAC,IAAI,KAAK,OAAO,CAAC,CAAC,CAAC,QAAQ,CAAC,CAAC,CAAC,OAAO,CAAC;IAC5E,CAAC;IACD,sFAAsF;IACtF,IAAI,EAAE,CAAC,SAAS,CAAC,QAAQ,CAAC,GAAG,CAAC;QAAE,OAAO,YAAY,CAAC;IACpD,OAAO,OAAO,CAAC;AACjB,CAAC;AAED,SAAS,SAAS,CAAC,EAAW;IAC5B,OAAO,EAAE,CAAC,YAAY,CAAC,gBAAgB,CAAC,IAAI,cAAc,CAAC,EAAE,CAAC,CAAC;AACjE,CAAC;AAED,0FAA0F;AAC1F,MAAM,WAAW,GAAG,IAAI,OAAO,EAAU,CAAC;AAE1C,MAAM,UAAU,aAAa,CAAC,IAAY;IACxC,WAAW,CAAC,GAAG,CAAC,IAAI,CAAC,CAAC;AACxB,CAAC;AAED,MAAM,WAAW,GAAG,CAAC,IAAU,EAAW,EAAE,CAAC,WAAW,CAAC,GAAG,CAAC,IAAI,CAAC,WAAW,CAAC,CAAC;AAE/E;;;;;;GAMG;AACH,SAAS,OAAO,CAAC,IAAa,EAAE,IAAU;IACxC,MAAM,IAAI,GAAG,IAAI,YAAY,UAAU,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,IAAI,CAAC,WAAW,EAAE,CAAC;IACpE,IAAI,IAAI,CAAC,WAAW,EAAE,KAAK,IAAI;QAAE,OAAO,KAAK,CAAC;IAC9C,KAAK,IAAI,CAAC,GAAG,IAAI,CAAC,UAAU,EAAE,CAAC,KAAK,IAAI,EAAE,CAAC,GAAG,CAAC,CAAC,UAAU,EAAE,CAAC;QAC3D,IAAI,CAAC,KAAK,IAAI;YAAE,OAAO,IAAI,CAAC;QAC5B,IAAI,WAAW,CAAC,CAAC,CAAC;YAAE,OAAO,KAAK,CAAC;IACnC,CAAC;IACD,OAAO,KAAK,CAAC;AACf,CAAC;AAED;;;GAGG;AACH,MAAM,UAAU,iBAAiB,CAAC,KAAY,EAAE,IAAU;IACxD,KAAK,MAAM,IAAI,IAAI,KAAK,CAAC,YAAY,EAAE,EAAE,CAAC;QACxC,IAAI,IAAI,KAAK,IAAI;YAAE,OAAO,SAAS,CAAC;QACpC,IACE,IAAI,YAAY,OAAO;YACvB,IAAI,CAAC,YAAY,CAAC,aAAa,CAAC;YAChC,SAAS,CAAC,IAAI,CAAC,KAAK,KAAK,CAAC,IAAI;YAC9B,OAAO,CAAC,IAAI,EAAE,IAAI,CAAC,EACnB,CAAC;YACD,OAAO,IAAI,CAAC;QACd,CAAC;IACH,CAAC;IACD,OAAO,SAAS,CAAC;AACnB,CAAC;AAED,SAAS,OAAO,CAAC,EAAW;IAC1B,IACE,EAAE,YAAY,gBAAgB;QAC9B,EAAE,YAAY,iBAAiB;QAC/B,EAAE,YAAY,mBAAmB;QACjC,EAAE,YAAY,iBAAiB,EAC/B,CAAC;QACD,OAAO,EAAE,CAAC,KAAK,CAAC;IAClB,CAAC;IACD,OAAO,SAAS,CAAC;AACnB,CAAC;AAED,mGAAmG;AACnG,MAAM,UAAU,UAAU,CAAC,KAAY,EAAE,IAAU;IACjD,MAAM,MAAM,GAAG,iBAAiB,CAAC,KAAK,EAAE,IAAI,CAAC,CAAC;IAC9C,MAAM,IAAI,GAAG,MAAM,EAAE,YAAY,CAAC,aAAa,CAAC,CAAC;IACjD,IAAI,MAAM,KAAK,SAAS,IAAI,IAAI,IAAI,IAAI;QAAE,OAAO,SAAS,CAAC;IAC3D,IAAI,QAA8B,CAAC;IACnC,IAAI,MAAM,YAAY,eAAe,IAAI,KAAK,YAAY,WAAW,EAAE,CAAC;QACtE,KAAK,CAAC,cAAc,EAAE,CAAC;QACvB,QAAQ,GAAG,IAAI,QAAQ,CAAC,MAAM,EAAE,KAAK,CAAC,SAAS,CAAC,CAAC;IACnD,CAAC;IACD,OAAO;QACL,IAAI;QACJ,KAAK;QACL,MAAM;QACN,KAAK,EAAE,OAAO,CAAC,MAAM,CAAC;QACtB,OAAO,EAAE,QAAQ,CAAC,MAAM,CAAC,CAAC,CAAC,CAAC,MAAM,CAAC,OAAO,CAAC,CAAC,CAAC,SAAS;QACtD,QAAQ;QACR,MAAM,EAAE,KAAK,YAAY,WAAW,CAAC,CAAC,CAAE,KAAK,CAAC,MAAkB,CAAC,CAAC,CAAC,SAAS;QAC5E,GAAG,EAAE,KAAK,YAAY,aAAa,CAAC,CAAC,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC,CAAC,SAAS;QAC3D,QAAQ,EAAE,WAAW,CAAC,KAAK,CAAC;QAC5B,OAAO,EAAE,SAAS,CAAC,KAAK,CAAC;KAC1B,CAAC;AACJ,CAAC;AAED,kFAAkF;AAClF,yFAAyF;AACzF,MAAM,CAAC,MAAM,WAAW,GAAY,IAAI,KAAK,CAC3C,EAAE,EACF,EAAE,GAAG,EAAE,CAAC,OAAO,EAAE,GAAG,EAAE,EAAE,CAAC,CAAC,OAAO,GAAG,KAAK,QAAQ,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,SAAS,CAAC,EAAE,CACvE,CAAC;AAEF,8FAA8F;AAC9F,MAAM,UAAU,gBAAgB,CAC9B,IAAU,EACV,KAAwB,EACxB,OAA+B;IAE/B,KAAK,MAAM,IAAI,IAAI,IAAI,GAAG,CAAC,CAAC,GAAG,aAAa,EAAE,GAAG,KAAK,CAAC,CAAC,EAAE,CAAC;QACzD,IAAI,CAAC,gBAAgB,CAAC,IAAI,EAAE,OAAO,EAAE,EAAE,OAAO,EAAE,IAAI,EAAE,CAAC,CAAC;IAC1D,CAAC;IACD,YAAY,CAAC,IAAI,CAAC,CAAC,CAAC,yDAAyD;AAC/E,CAAC;AAED,0FAA0F;AAC1F,MAAM,UAAU,YAAY,CAC1B,KAAY,EACZ,IAAU,EACV,OAA8D,EAC9D,GAAW,EACX,OAA0C;IAE1C,MAAM,KAAK,GAAG,UAAU,CAAC,KAAK,EAAE,IAAI,CAAC,CAAC;IACtC,IAAI,KAAK,KAAK,SAAS;QAAE,OAAO;IAChC,MAAM,MAAM,GAAG,OAAO,CAAC,KAAK,CAAC,IAAI,CAAC,CAAC;IACnC,IAAI,MAAM,KAAK,SAAS,EAAE,CAAC;QACzB,OAAO,CAAC,IAAI,CAAC,IAAI,GAAG,2CAA2C,KAAK,CAAC,IAAI,IAAI,CAAC,CAAC;QAC/E,OAAO;IACT,CAAC;IACD,MAAM,MAAM,GAAG,MAAM,CAAC,KAAK,CAAqD,CAAC;IACjF,IAAI,MAAM,YAAY,OAAO,EAAE,CAAC;QAC9B,MAAM,CAAC,IAAI,CAAC,OAAO,EAAE,CAAC,KAAc,EAAE,EAAE;YACtC,OAAO,CAAC,KAAK,CAAC,IAAI,GAAG,wBAAwB,KAAK,CAAC,IAAI,UAAU,EAAE,KAAK,CAAC,CAAC;QAC5E,CAAC,CAAC,CAAC;IACL,CAAC;SAAM,CAAC;QACN,OAAO,CAAC,MAAM,CAAC,CAAC;IAClB,CAAC;AACH,CAAC","sourcesContent":["import { commandOf, shimInvokers } from './invokers.js';\nimport type { IntentInput, IntentParser, Tagged } from './types.js';\n\n/** Event a child component dispatches on its host to send an output up (ADR 0010). */\nexport const OUTPUT_EVENT = 'gyral-output';\n\n/**\n * Events the intent layer listens for on each component's shadow root (capture phase, so\n * non-bubbling events such as `toggle` are seen too). Only `click`, `submit`, `input`,\n * `change` and outputs are default triggers; the rest fire via `data-intent-on=\"…\"`.\n * Components may add more with `spec.events`.\n */\nexport const INTENT_EVENTS = [\n 'click',\n 'submit',\n 'input',\n 'change',\n 'keydown',\n 'keyup',\n 'focusin',\n 'focusout',\n 'toggle',\n 'command',\n OUTPUT_EVENT,\n] as const;\n\nconst isToggle = (el: Element): el is HTMLInputElement =>\n el instanceof HTMLInputElement && (el.type === 'checkbox' || el.type === 'radio');\n\n// ToggleEvent (popover, <details>) is not Baseline widely available; read it structurally.\nfunction toggleState(event: Event): 'open' | 'closed' | undefined {\n if (event.type !== 'toggle' || !('newState' in event)) return undefined;\n return event.newState === 'open' ? 'open' : 'closed';\n}\n\nconst CLICK_INPUT_TYPES = new Set(['button', 'submit', 'reset', 'image']);\n\n/** The event that fires an intent unless `data-intent-on` overrides it. */\nexport function defaultTrigger(el: Element): string {\n if (el instanceof HTMLFormElement) return 'submit';\n if (el instanceof HTMLSelectElement) return 'change';\n if (el instanceof HTMLTextAreaElement) return 'input';\n if (el instanceof HTMLInputElement) {\n if (CLICK_INPUT_TYPES.has(el.type)) return 'click';\n return el.type === 'checkbox' || el.type === 'radio' ? 'change' : 'input';\n }\n // Custom elements (autonomous: the name has a dash) talk to their parent via outputs.\n if (el.localName.includes('-')) return OUTPUT_EVENT;\n return 'click';\n}\n\nfunction triggerOf(el: Element): string {\n return el.getAttribute('data-intent-on') ?? defaultTrigger(el);\n}\n\n/** Every class `define()` creates, so intent lookup can tell where a component begins. */\nconst hostClasses = new WeakSet<object>();\n\nexport function markGyralHost(ctor: object): void {\n hostClasses.add(ctor);\n}\n\nconst isGyralHost = (node: Node): boolean => hostClasses.has(node.constructor);\n\n/**\n * Does `node` belong to the component whose intent root is `root`? `root` is the component's\n * shadow root, or the host itself for light-DOM components (ADR 0014). The node must be in the\n * same tree (not inside a nested shadow root) with no other Gyral host between them: a nested\n * component, light-DOM or shadow, owns its own content. The nested host element itself (with\n * the parent's `data-intent` on it) still belongs to the parent.\n */\nfunction ownedBy(node: Element, root: Node): boolean {\n const tree = root instanceof ShadowRoot ? root : root.getRootNode();\n if (node.getRootNode() !== tree) return false;\n for (let p = node.parentNode; p !== null; p = p.parentNode) {\n if (p === root) return true;\n if (isGyralHost(p)) return false;\n }\n return false;\n}\n\n/**\n * Finds the nearest `data-intent` element for this event that belongs to `root`. Elements\n * inside nested components are ignored: that is component isolation.\n */\nexport function findIntentElement(event: Event, root: Node): Element | undefined {\n for (const node of event.composedPath()) {\n if (node === root) return undefined;\n if (\n node instanceof Element &&\n node.hasAttribute('data-intent') &&\n triggerOf(node) === event.type &&\n ownedBy(node, root)\n ) {\n return node;\n }\n }\n return undefined;\n}\n\nfunction valueOf(el: Element): string | undefined {\n if (\n el instanceof HTMLInputElement ||\n el instanceof HTMLSelectElement ||\n el instanceof HTMLTextAreaElement ||\n el instanceof HTMLButtonElement\n ) {\n return el.value;\n }\n return undefined;\n}\n\n/** Reads an event into an IntentInput. Form submissions are prevented and turned into FormData. */\nexport function readIntent(event: Event, root: Node): IntentInput | undefined {\n const target = findIntentElement(event, root);\n const name = target?.getAttribute('data-intent');\n if (target === undefined || name == null) return undefined;\n let formData: FormData | undefined;\n if (target instanceof HTMLFormElement && event instanceof SubmitEvent) {\n event.preventDefault();\n formData = new FormData(target, event.submitter);\n }\n return {\n name,\n event,\n target,\n value: valueOf(target),\n checked: isToggle(target) ? target.checked : undefined,\n formData,\n detail: event instanceof CustomEvent ? (event.detail as unknown) : undefined,\n key: event instanceof KeyboardEvent ? event.key : undefined,\n newState: toggleState(event),\n command: commandOf(event),\n };\n}\n\n// Any property read returns its own name, so `intents.Increment === 'Increment'`.\n// Types restrict reads to real message tags; a tag without a parser warns at event time.\nexport const intentNames: unknown = new Proxy(\n {},\n { get: (_target, key) => (typeof key === 'string' ? key : undefined) },\n);\n\n/** Listens for intent events on a component root (capture phase: `toggle` doesn't bubble). */\nexport function listenForIntents(\n root: Node,\n extra: readonly string[],\n handler: (event: Event) => void,\n): void {\n for (const type of new Set([...INTENT_EVENTS, ...extra])) {\n root.addEventListener(type, handler, { capture: true });\n }\n shimInvokers(root); // `command` intents in browsers without invoker commands\n}\n\n/** Parses one event with its matching parser and delivers the message (sync or async). */\nexport function handleIntent<M>(\n event: Event,\n root: Node,\n parsers: Readonly<Record<string, IntentParser<M> | undefined>>,\n tag: string,\n deliver: (msg: Tagged | undefined) => void,\n): void {\n const input = readIntent(event, root);\n if (input === undefined) return;\n const parser = parsers[input.name];\n if (parser === undefined) {\n console.warn(`<${tag}> has no intent parser for data-intent=\"${input.name}\".`);\n return;\n }\n const result = parser(input) as Tagged | undefined | Promise<Tagged | undefined>;\n if (result instanceof Promise) {\n result.then(deliver, (error: unknown) => {\n console.error(`<${tag}> intent parser for \"${input.name}\" failed`, error);\n });\n } else {\n deliver(result);\n }\n}\n"]}
|
|
1
|
+
{"version":3,"file":"intent.js","sourceRoot":"","sources":["../src/intent.ts"],"names":[],"mappings":"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","sourcesContent":["import { commandOf, invokersSupported } from './invokers.js';\nimport { hold } from './scheduler.js';\nimport type { IntentInput, IntentNames, IntentParser, Tagged } from './types.js';\nimport type { Markup } from './view/index.js';\n\n/** Event a child component dispatches on its host to send an output up (ADR 0010). */\nexport const OUTPUT_EVENT = 'gyral-output';\n\n/** Default triggers (`defaultTrigger`): every component root listens for these. */\nexport const DEFAULT_EVENTS: readonly string[] = [\n 'click',\n 'submit',\n 'input',\n 'change',\n OUTPUT_EVENT,\n];\n\n/**\n * The events `data-intent-on` usually names. A component root listens (capture phase, so\n * non-bubbling events such as `toggle` are seen too) for the defaults, for `spec.events`, and\n * for the `data-intent-on` values in the templates it renders; a template that binds\n * `data-intent-on` dynamically adds all of these (view/05-element.md \"Intent events\").\n */\nexport const INTENT_EVENTS: readonly string[] = [\n ...DEFAULT_EVENTS,\n 'keydown',\n 'keyup',\n 'focusin',\n 'focusout',\n 'toggle',\n 'command',\n];\n\n/** A static `data-intent-on` value, quoted or not (event names have no spaces or quotes). */\nconst INTENT_ON = /\\sdata-intent-on=[\"']?([^\"'\\s>]+)/gi;\nconst eventsByTemplate = new WeakMap<Markup, readonly string[]>();\n\n/** The intent events a template's (or `raw()` markup's) `data-intent-on` attributes name. */\nexport function eventsOf(markup: Markup): readonly string[] {\n let events = eventsByTemplate.get(markup);\n if (events === undefined) {\n events = markup.parts?.some((p) => p[2] === 'data-intent-on') // a bound attribute's name\n ? INTENT_EVENTS\n : Array.from(markup.html.matchAll(INTENT_ON), (m) => m[1] ?? '');\n eventsByTemplate.set(markup, events);\n }\n return events;\n}\n\nconst isToggle = (el: Element): el is HTMLInputElement =>\n el instanceof HTMLInputElement && (el.type === 'checkbox' || el.type === 'radio');\n\n// ToggleEvent (popover, <details>) is not Baseline widely available; read it structurally.\nfunction toggleState(event: Event): 'open' | 'closed' | undefined {\n if (event.type !== 'toggle' || !('newState' in event)) return undefined;\n return event.newState === 'open' ? 'open' : 'closed';\n}\n\nconst CLICK_INPUT_TYPES = /^(button|submit|reset|image)$/;\n\n/** The event that fires an intent unless `data-intent-on` overrides it. */\nexport function defaultTrigger(el: Element): string {\n switch (el.localName) {\n case 'form':\n return 'submit';\n case 'select':\n return 'change';\n case 'textarea':\n return 'input';\n case 'input': {\n const type = (el as HTMLInputElement).type;\n if (CLICK_INPUT_TYPES.test(type)) return 'click';\n return type === 'checkbox' || type === 'radio' ? 'change' : 'input';\n }\n }\n // Custom elements (autonomous: the name has a dash) talk to their parent via outputs.\n return el.localName.includes('-') ? OUTPUT_EVENT : 'click';\n}\n\nfunction triggerOf(el: Element): string {\n return el.getAttribute('data-intent-on') ?? defaultTrigger(el);\n}\n\n/** Every class `define()` creates, so intent lookup can tell where a component begins. */\nconst hostClasses = new WeakSet<object>();\n\nexport function markGyralHost(ctor: object): void {\n hostClasses.add(ctor);\n}\n\nconst isGyralHost = (node: Node): boolean => hostClasses.has(node.constructor);\n\n/**\n * The number of Gyral host ancestors of `el` in the composed tree (across shadow roots): the\n * scheduler renders smaller depths first (view/04-scheduler.md \"Marking\").\n */\nexport function hostDepth(el: Element): number {\n let depth = 0;\n for (let node: Node | null = el.parentNode; node !== null;) {\n if (isGyralHost(node)) depth += 1;\n node = node instanceof ShadowRoot ? node.host : node.parentNode;\n }\n return depth;\n}\n\n/**\n * Does `node` belong to the component whose intent root is `root`? `root` is the component's\n * shadow root, or the host itself for light-DOM components (ADR 0014). The node must be in the\n * same tree (not inside a nested shadow root) with no other Gyral host between them: a nested\n * component, light-DOM or shadow, owns its own content. The nested host element itself (with\n * the parent's `data-intent` on it) still belongs to the parent.\n */\nfunction ownedBy(node: Element, root: Node): boolean {\n const tree = root instanceof ShadowRoot ? root : root.getRootNode();\n if (node.getRootNode() !== tree) return false;\n for (let p = node.parentNode; p !== null; p = p.parentNode) {\n if (p === root) return true;\n if (isGyralHost(p)) return false;\n }\n return false;\n}\n\n/**\n * Finds the nearest `data-intent` element for this event that belongs to `root`. Elements\n * inside nested components are ignored: that is component isolation.\n */\nexport function findIntentElement(event: Event, root: Node): Element | undefined {\n for (const node of event.composedPath()) {\n if (node === root) return undefined;\n if (\n node instanceof Element &&\n node.hasAttribute('data-intent') &&\n triggerOf(node) === event.type &&\n ownedBy(node, root)\n ) {\n return node;\n }\n }\n return undefined;\n}\n\nfunction valueOf(el: Element): string | undefined {\n if (\n el instanceof HTMLInputElement ||\n el instanceof HTMLSelectElement ||\n el instanceof HTMLTextAreaElement ||\n el instanceof HTMLButtonElement\n ) {\n return el.value;\n }\n return undefined;\n}\n\n/** Reads an event into an IntentInput. Form submissions are prevented and turned into FormData. */\nexport function readIntent(event: Event, root: Node): IntentInput | undefined {\n const target = findIntentElement(event, root);\n const name = target?.getAttribute('data-intent');\n if (target === undefined || name == null) return undefined;\n let formData: FormData | undefined;\n if (target instanceof HTMLFormElement && event instanceof SubmitEvent) {\n event.preventDefault();\n formData = new FormData(target, event.submitter);\n }\n return {\n name,\n event,\n target,\n value: valueOf(target),\n checked: isToggle(target) ? target.checked : undefined,\n formData,\n detail: event instanceof CustomEvent ? (event.detail as unknown) : undefined,\n key: event instanceof KeyboardEvent ? event.key : undefined,\n newState: toggleState(event),\n command: commandOf(event),\n };\n}\n\n// Any property read returns its own name, so `intents.Increment === 'Increment'`.\n// Types restrict reads to real message tags; a tag without a parser warns at event time.\nexport const intentNames: unknown = new Proxy(\n {},\n { get: (_target, key) => (typeof key === 'string' ? key : undefined) },\n);\n\n/**\n * A component's intent names as a module-level constant, so pure list rows can name intents\n * without passing them through `pick` (view/03-lists.md \"Rows must be pure\"). The same object\n * the view gets as `i`:\n *\n * const i = intents<Msg>();\n * const Row = (t: Todo) => html`<input value=${t.id} data-intent=${i.Toggle} />`;\n */\nexport function intents<M extends Tagged>(): IntentNames<M> {\n return intentNames as IntentNames<M>;\n}\n\n/**\n * Adds capture listeners for `types` to a component root, skipping those in `listening`. A\n * root that listens for `command` in a browser without invoker commands loads the fallback\n * (invokers-shim.ts, ADR 0003 tier 3); settled() waits for it.\n */\nexport function listenForIntents(\n root: Node,\n listening: Set<string>,\n types: readonly string[],\n handler: (event: Event) => void,\n): void {\n for (const type of types) {\n if (listening.has(type)) continue;\n listening.add(type);\n root.addEventListener(type, handler, { capture: true });\n if (type === 'command' && !invokersSupported()) {\n hold(\n import('./invokers-shim.js').then((shim) => {\n shim.shimInvokers(root);\n }, reportError),\n );\n }\n }\n}\n\n/** Parses one event with its matching parser and delivers the message (sync or async). */\nexport function handleIntent<M>(\n event: Event,\n root: Node,\n parsers: Readonly<Record<string, IntentParser<M> | undefined>>,\n tag: string,\n deliver: (msg: Tagged | undefined) => void,\n): void {\n const input = readIntent(event, root);\n if (input === undefined) return;\n const parser = parsers[input.name];\n if (parser === undefined) {\n console.warn(`<${tag}> has no intent parser for data-intent=\"${input.name}\".`);\n return;\n }\n const result = parser(input) as Tagged | undefined | Promise<Tagged | undefined>;\n if (result instanceof Promise) {\n result.then(deliver, (error: unknown) => {\n console.error(`<${tag}> intent parser for \"${input.name}\" failed`, error);\n });\n } else {\n deliver(result);\n }\n}\n"]}
|
|
@@ -1,8 +1,14 @@
|
|
|
1
|
-
import type { AnyDriver, Command } from '../command.js';
|
|
1
|
+
import type { AnyDriver, Command, DriverOverrides } from '../command.js';
|
|
2
2
|
import type { CommandTrace } from '../devtools-events.js';
|
|
3
|
+
import type { FeatureHost } from '../features.js';
|
|
3
4
|
/** Runs commands for one connected element. Disposed on disconnect. */
|
|
4
5
|
export interface Interpreter<M> {
|
|
5
6
|
readonly run: (cmd: Command<M>) => void;
|
|
6
7
|
readonly dispose: () => void;
|
|
7
8
|
}
|
|
8
9
|
export declare function makeInterpreter<M>(resolve: (driver: AnyDriver) => AnyDriver, dispatch: (msg: M) => void, trace?: CommandTrace): Interpreter<M>;
|
|
10
|
+
/**
|
|
11
|
+
* A component's interpreter (registered by `command()`, features.ts). Drivers resolve by name:
|
|
12
|
+
* el.drivers → nearest provider → spec.drivers → the command's own (gyral-czi.35).
|
|
13
|
+
*/
|
|
14
|
+
export declare const hostInterpreter: <M>(el: FeatureHost, drivers: DriverOverrides | undefined, dispatch: (msg: M) => void, trace: CommandTrace | undefined) => Interpreter<M>;
|
|
@@ -1,12 +1,11 @@
|
|
|
1
1
|
import { DEVTOOLS_ENABLED } from '#devtools';
|
|
2
|
-
|
|
3
|
-
class Interrupted extends Error {
|
|
4
|
-
}
|
|
2
|
+
import { providedDriver } from '../drivers-scope.js';
|
|
5
3
|
/** Rejects when `signal` aborts. Marked handled so a losing race never reports it. */
|
|
6
4
|
const aborted = (signal) => {
|
|
7
5
|
const promise = new Promise((_resolve, reject) => {
|
|
6
|
+
// Callers check `signal.aborted`, never the reason.
|
|
8
7
|
const interrupt = () => {
|
|
9
|
-
reject(
|
|
8
|
+
reject(signal.reason);
|
|
10
9
|
};
|
|
11
10
|
if (signal.aborted)
|
|
12
11
|
interrupt();
|
|
@@ -163,4 +162,12 @@ export function makeInterpreter(resolve, dispatch, trace) {
|
|
|
163
162
|
};
|
|
164
163
|
return { run, dispose };
|
|
165
164
|
}
|
|
165
|
+
/**
|
|
166
|
+
* A component's interpreter (registered by `command()`, features.ts). Drivers resolve by name:
|
|
167
|
+
* el.drivers → nearest provider → spec.drivers → the command's own (gyral-czi.35).
|
|
168
|
+
*/
|
|
169
|
+
export const hostInterpreter = (el, drivers, dispatch, trace) => makeInterpreter((driver) => el.drivers[driver.name] ??
|
|
170
|
+
providedDriver(el, driver.name) ??
|
|
171
|
+
drivers?.[driver.name] ??
|
|
172
|
+
driver, dispatch, trace);
|
|
166
173
|
//# sourceMappingURL=interpreter.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"interpreter.js","sourceRoot":"","sources":["../../src/internal/interpreter.ts"],"names":[],"mappings":"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","sourcesContent":["import { DEVTOOLS_ENABLED } from '#devtools';\nimport type { AnyDriver, Command, Concurrency, RetryPolicy } from '../command.js';\nimport type { CommandPhase, CommandTrace } from '../devtools-events.js';\n\n// The command interpreter (ADR 0015: hand-written, no runtime dependencies). Each running command is a task with its own AbortController; lanes hold the\n// latest task per key. Interruption is `controller.abort()`, retry schedules are timers\n// that cancel on abort, and `queue` chains on the previous task's promise.\n\n/** Runs commands for one connected element. Disposed on disconnect. */\nexport interface Interpreter<M> {\n readonly run: (cmd: Command<M>) => void;\n readonly dispose: () => void;\n}\n\ninterface Task {\n readonly controller: AbortController;\n done: Promise<void>;\n running: boolean;\n}\n\n/** Reports one command's lifecycle to devtools (ADR 0017); undefined in production. */\ntype Report = ((phase: CommandPhase, result?: unknown) => void) | undefined;\n\n/** Internal rejection for an aborted task; callers check `signal.aborted`, never this. */\nclass Interrupted extends Error {}\n\n/** Rejects when `signal` aborts. Marked handled so a losing race never reports it. */\nconst aborted = (signal: AbortSignal): Promise<never> => {\n const promise = new Promise<never>((_resolve, reject) => {\n const interrupt = (): void => {\n reject(new Interrupted('gyral: command interrupted'));\n };\n if (signal.aborted) interrupt();\n else signal.addEventListener('abort', interrupt, { once: true });\n });\n promise.catch(() => undefined);\n return promise;\n};\n\n/** Waits `ms`, or rejects as soon as `signal` aborts. */\nconst sleep = (ms: number, signal: AbortSignal): Promise<void> =>\n Promise.race([\n new Promise<void>((resolve) => {\n const timer = setTimeout(resolve, ms);\n signal.addEventListener(\n 'abort',\n () => {\n clearTimeout(timer);\n },\n { once: true },\n );\n }),\n aborted(signal),\n ]);\n\n/** Delay before retry number `retry` (0-based): fixed, or doubling from `delayMs`. */\nconst delayFor = (policy: RetryPolicy, retry: number): number => {\n const base = policy.delayMs ?? 0;\n return policy.backoff === 'exponential' ? base * 2 ** retry : base;\n};\n\nasync function attemptWithRetry(\n driver: AnyDriver,\n cmd: Command<unknown>,\n signal: AbortSignal,\n emit: (output: unknown) => void,\n): Promise<unknown> {\n const policy = driver.retry;\n for (let retry = 0; ; retry += 1) {\n try {\n // The input type was erased by command(); it was built for this driver's name.\n const result = Promise.resolve(driver.run(cmd.input as never, { signal, emit }));\n return await Promise.race([result, aborted(signal)]);\n } catch (cause) {\n if (signal.aborted || policy === undefined || retry >= policy.times) throw cause;\n await sleep(delayFor(policy, retry), signal);\n }\n }\n}\n\n/** Maps a result to a message and dispatches it; a throwing mapper is logged, not fatal. */\nconst deliver = <M>(map: () => M | undefined, dispatch: (msg: M) => void): void => {\n try {\n const msg = map();\n if (msg !== undefined) dispatch(msg);\n } catch (defect) {\n console.error('gyral: command mapper threw', defect);\n }\n};\n\nasync function execute<M>(\n driver: AnyDriver,\n cmd: Command<M>,\n signal: AbortSignal,\n dispatch: (msg: M) => void,\n report: Report,\n): Promise<void> {\n let settled = false;\n const emit = (output: unknown): void => {\n if (!settled && !signal.aborted) deliver(() => cmd.onSuccess(output), dispatch);\n };\n if (DEVTOOLS_ENABLED && report !== undefined) {\n signal.addEventListener(\n 'abort',\n () => {\n if (!settled) report('interrupted');\n },\n { once: true },\n );\n }\n let output: unknown;\n try {\n output = await attemptWithRetry(driver, cmd, signal, emit);\n } catch (cause) {\n if (signal.aborted) return; // interrupted: reported by the abort listener\n settled = true;\n const error = driver.toError === undefined ? cause : driver.toError(cause);\n if (DEVTOOLS_ENABLED) report?.('failed', error);\n if (cmd.onFailure === undefined) {\n console.warn(`gyral: unhandled failure from driver \"${driver.name}\"`, error);\n return;\n }\n const onFailure = cmd.onFailure;\n deliver(() => onFailure(error), dispatch);\n return;\n }\n if (signal.aborted) return;\n settled = true;\n if (DEVTOOLS_ENABLED) report?.('settled', output);\n deliver(() => cmd.onSuccess(output), dispatch);\n}\n\nexport function makeInterpreter<M>(\n resolve: (driver: AnyDriver) => AnyDriver,\n dispatch: (msg: M) => void,\n trace?: CommandTrace,\n): Interpreter<M> {\n const reporter = (driver: string, lane: string, policy: Concurrency, input: unknown): Report =>\n trace === undefined\n ? undefined\n : (phase, result) => {\n trace({\n phase,\n driver,\n lane,\n policy,\n input,\n ...(result === undefined ? {} : { result }),\n });\n };\n const lanes = new Map<string, Task>();\n const all = new Set<Task>();\n let active = true;\n const guardedDispatch = (msg: M): void => {\n if (active) dispatch(msg);\n };\n\n const start = (\n lane: string,\n driver: AnyDriver,\n cmd: Command<M>,\n report: Report,\n after?: Task,\n ): void => {\n const controller = new AbortController();\n const task: Task = { controller, running: true, done: Promise.resolve() };\n const body = async (): Promise<void> => {\n if (after !== undefined) await after.done;\n if (!controller.signal.aborted) {\n await execute(driver, cmd, controller.signal, guardedDispatch, report);\n }\n };\n task.done = body().finally(() => {\n task.running = false;\n all.delete(task);\n if (lanes.get(lane) === task) lanes.delete(lane);\n });\n lanes.set(lane, task);\n all.add(task);\n };\n\n const run = (cmd: Command<M>): void => {\n if (!active) return;\n const driver = resolve(cmd.driver);\n const lane = cmd.key ?? driver.name;\n const policy = cmd.concurrency ?? driver.concurrency ?? 'merge';\n const previous = lanes.get(lane);\n const inFlight = previous?.running === true ? previous : undefined;\n const report = DEVTOOLS_ENABLED ? reporter(driver.name, lane, policy, cmd.input) : undefined;\n if (inFlight !== undefined && policy === 'exhaust') {\n if (DEVTOOLS_ENABLED) report?.('dropped');\n return;\n }\n if (DEVTOOLS_ENABLED) report?.('issued');\n if (inFlight !== undefined && policy === 'switch') inFlight.controller.abort();\n start(\n lane,\n driver,\n cmd,\n report,\n inFlight !== undefined && policy === 'queue' ? inFlight : undefined,\n );\n };\n\n const dispose = (): void => {\n active = false;\n for (const task of all) task.controller.abort();\n all.clear();\n lanes.clear();\n };\n\n return { run, dispose };\n}\n"]}
|
|
1
|
+
{"version":3,"file":"interpreter.js","sourceRoot":"","sources":["../../src/internal/interpreter.ts"],"names":[],"mappings":"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","sourcesContent":["import { DEVTOOLS_ENABLED } from '#devtools';\nimport type { AnyDriver, Command, Concurrency, DriverOverrides, RetryPolicy } from '../command.js';\nimport type { CommandPhase, CommandTrace } from '../devtools-events.js';\nimport { providedDriver } from '../drivers-scope.js';\nimport type { FeatureHost } from '../features.js';\n\n// The command interpreter (ADR 0015: hand-written, no runtime dependencies). Each running command is a task with its own AbortController; lanes hold the\n// latest task per key. Interruption is `controller.abort()`, retry schedules are timers\n// that cancel on abort, and `queue` chains on the previous task's promise.\n\n/** Runs commands for one connected element. Disposed on disconnect. */\nexport interface Interpreter<M> {\n readonly run: (cmd: Command<M>) => void;\n readonly dispose: () => void;\n}\n\ninterface Task {\n readonly controller: AbortController;\n done: Promise<void>;\n running: boolean;\n}\n\n/** Reports one command's lifecycle to devtools (ADR 0017); undefined in production. */\ntype Report = ((phase: CommandPhase, result?: unknown) => void) | undefined;\n\n/** Rejects when `signal` aborts. Marked handled so a losing race never reports it. */\nconst aborted = (signal: AbortSignal): Promise<never> => {\n const promise = new Promise<never>((_resolve, reject) => {\n // Callers check `signal.aborted`, never the reason.\n const interrupt = (): void => {\n reject(signal.reason as Error);\n };\n if (signal.aborted) interrupt();\n else signal.addEventListener('abort', interrupt, { once: true });\n });\n promise.catch(() => undefined);\n return promise;\n};\n\n/** Waits `ms`, or rejects as soon as `signal` aborts. */\nconst sleep = (ms: number, signal: AbortSignal): Promise<void> =>\n Promise.race([\n new Promise<void>((resolve) => {\n const timer = setTimeout(resolve, ms);\n signal.addEventListener(\n 'abort',\n () => {\n clearTimeout(timer);\n },\n { once: true },\n );\n }),\n aborted(signal),\n ]);\n\n/** Delay before retry number `retry` (0-based): fixed, or doubling from `delayMs`. */\nconst delayFor = (policy: RetryPolicy, retry: number): number => {\n const base = policy.delayMs ?? 0;\n return policy.backoff === 'exponential' ? base * 2 ** retry : base;\n};\n\nasync function attemptWithRetry(\n driver: AnyDriver,\n cmd: Command<unknown>,\n signal: AbortSignal,\n emit: (output: unknown) => void,\n): Promise<unknown> {\n const policy = driver.retry;\n for (let retry = 0; ; retry += 1) {\n try {\n // The input type was erased by command(); it was built for this driver's name.\n const result = Promise.resolve(driver.run(cmd.input as never, { signal, emit }));\n return await Promise.race([result, aborted(signal)]);\n } catch (cause) {\n if (signal.aborted || policy === undefined || retry >= policy.times) throw cause;\n await sleep(delayFor(policy, retry), signal);\n }\n }\n}\n\n/** Maps a result to a message and dispatches it; a throwing mapper is logged, not fatal. */\nconst deliver = <M>(map: () => M | undefined, dispatch: (msg: M) => void): void => {\n try {\n const msg = map();\n if (msg !== undefined) dispatch(msg);\n } catch (defect) {\n console.error('gyral: command mapper threw', defect);\n }\n};\n\nasync function execute<M>(\n driver: AnyDriver,\n cmd: Command<M>,\n signal: AbortSignal,\n dispatch: (msg: M) => void,\n report: Report,\n): Promise<void> {\n let settled = false;\n const emit = (output: unknown): void => {\n if (!settled && !signal.aborted) deliver(() => cmd.onSuccess(output), dispatch);\n };\n if (DEVTOOLS_ENABLED && report !== undefined) {\n signal.addEventListener(\n 'abort',\n () => {\n if (!settled) report('interrupted');\n },\n { once: true },\n );\n }\n let output: unknown;\n try {\n output = await attemptWithRetry(driver, cmd, signal, emit);\n } catch (cause) {\n if (signal.aborted) return; // interrupted: reported by the abort listener\n settled = true;\n const error = driver.toError === undefined ? cause : driver.toError(cause);\n if (DEVTOOLS_ENABLED) report?.('failed', error);\n if (cmd.onFailure === undefined) {\n console.warn(`gyral: unhandled failure from driver \"${driver.name}\"`, error);\n return;\n }\n const onFailure = cmd.onFailure;\n deliver(() => onFailure(error), dispatch);\n return;\n }\n if (signal.aborted) return;\n settled = true;\n if (DEVTOOLS_ENABLED) report?.('settled', output);\n deliver(() => cmd.onSuccess(output), dispatch);\n}\n\nexport function makeInterpreter<M>(\n resolve: (driver: AnyDriver) => AnyDriver,\n dispatch: (msg: M) => void,\n trace?: CommandTrace,\n): Interpreter<M> {\n const reporter = (driver: string, lane: string, policy: Concurrency, input: unknown): Report =>\n trace === undefined\n ? undefined\n : (phase, result) => {\n trace({\n phase,\n driver,\n lane,\n policy,\n input,\n ...(result === undefined ? {} : { result }),\n });\n };\n const lanes = new Map<string, Task>();\n const all = new Set<Task>();\n let active = true;\n const guardedDispatch = (msg: M): void => {\n if (active) dispatch(msg);\n };\n\n const start = (\n lane: string,\n driver: AnyDriver,\n cmd: Command<M>,\n report: Report,\n after?: Task,\n ): void => {\n const controller = new AbortController();\n const task: Task = { controller, running: true, done: Promise.resolve() };\n const body = async (): Promise<void> => {\n if (after !== undefined) await after.done;\n if (!controller.signal.aborted) {\n await execute(driver, cmd, controller.signal, guardedDispatch, report);\n }\n };\n task.done = body().finally(() => {\n task.running = false;\n all.delete(task);\n if (lanes.get(lane) === task) lanes.delete(lane);\n });\n lanes.set(lane, task);\n all.add(task);\n };\n\n const run = (cmd: Command<M>): void => {\n if (!active) return;\n const driver = resolve(cmd.driver);\n const lane = cmd.key ?? driver.name;\n const policy = cmd.concurrency ?? driver.concurrency ?? 'merge';\n const previous = lanes.get(lane);\n const inFlight = previous?.running === true ? previous : undefined;\n const report = DEVTOOLS_ENABLED ? reporter(driver.name, lane, policy, cmd.input) : undefined;\n if (inFlight !== undefined && policy === 'exhaust') {\n if (DEVTOOLS_ENABLED) report?.('dropped');\n return;\n }\n if (DEVTOOLS_ENABLED) report?.('issued');\n if (inFlight !== undefined && policy === 'switch') inFlight.controller.abort();\n start(\n lane,\n driver,\n cmd,\n report,\n inFlight !== undefined && policy === 'queue' ? inFlight : undefined,\n );\n };\n\n const dispose = (): void => {\n active = false;\n for (const task of all) task.controller.abort();\n all.clear();\n lanes.clear();\n };\n\n return { run, dispose };\n}\n\n/**\n * A component's interpreter (registered by `command()`, features.ts). Drivers resolve by name:\n * el.drivers → nearest provider → spec.drivers → the command's own (gyral-czi.35).\n */\nexport const hostInterpreter = <M>(\n el: FeatureHost,\n drivers: DriverOverrides | undefined,\n dispatch: (msg: M) => void,\n trace: CommandTrace | undefined,\n): Interpreter<M> =>\n makeInterpreter(\n (driver) =>\n el.drivers[driver.name] ??\n providedDriver(el, driver.name) ??\n drivers?.[driver.name] ??\n driver,\n dispatch,\n trace,\n );\n"]}
|
|
@@ -0,0 +1,6 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Fallback for browsers without invoker commands: a click on a `command="--…"` invoker inside
|
|
3
|
+
* `root` dispatches a `command` event on its `commandfor` target (same tree scope), with the
|
|
4
|
+
* `command` and `source` properties a native `CommandEvent` has.
|
|
5
|
+
*/
|
|
6
|
+
export declare function shimInvokers(root: Node): void;
|