@gyral/core 0.3.0 → 0.3.2
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 +57 -0
- package/NOTICE +19 -0
- package/README.md +36 -8
- package/dist/call.d.ts +32 -0
- package/dist/call.js +63 -0
- package/dist/call.js.map +1 -0
- package/dist/children.d.ts +25 -3
- package/dist/children.js +18 -1
- package/dist/children.js.map +1 -1
- package/dist/cli/gyral-types.d.ts +2 -0
- package/dist/cli/gyral-types.js +23 -0
- package/dist/cli/gyral-types.js.map +1 -0
- package/dist/command.d.ts +54 -12
- package/dist/command.js +25 -11
- package/dist/command.js.map +1 -1
- package/dist/compiler/ast.d.ts +2 -0
- package/dist/compiler/ast.js +5 -1
- package/dist/compiler/ast.js.map +1 -1
- package/dist/compiler/compile.d.ts +5 -2
- package/dist/compiler/compile.js +36 -17
- package/dist/compiler/compile.js.map +1 -1
- package/dist/compiler/component-entries.d.ts +7 -0
- package/dist/compiler/component-entries.js +42 -0
- package/dist/compiler/component-entries.js.map +1 -0
- package/dist/compiler/components.d.ts +4 -0
- package/dist/compiler/components.js +190 -0
- package/dist/compiler/components.js.map +1 -0
- package/dist/compiler/facts.d.ts +31 -0
- package/dist/compiler/facts.js +285 -0
- package/dist/compiler/facts.js.map +1 -0
- package/dist/compiler/features.d.ts +34 -0
- package/dist/compiler/features.js +158 -0
- package/dist/compiler/features.js.map +1 -0
- package/dist/compiler/hooks.d.ts +4 -0
- package/dist/compiler/hooks.js +144 -89
- package/dist/compiler/hooks.js.map +1 -1
- package/dist/compiler/loader-source.d.ts +14 -0
- package/dist/compiler/loader-source.js +86 -0
- package/dist/compiler/loader-source.js.map +1 -0
- package/dist/compiler/locate.d.ts +14 -0
- package/dist/compiler/locate.js +90 -0
- package/dist/compiler/locate.js.map +1 -0
- package/dist/compiler/parse5-check.d.ts +1 -1
- package/dist/compiler/parse5-check.js +8 -3
- package/dist/compiler/parse5-check.js.map +1 -1
- package/dist/compiler/prop-schemas.d.ts +4 -0
- package/dist/compiler/prop-schemas.js +108 -0
- package/dist/compiler/prop-schemas.js.map +1 -0
- package/dist/compiler/scan.d.ts +13 -3
- package/dist/compiler/scan.js +21 -13
- package/dist/compiler/scan.js.map +1 -1
- package/dist/compiler/scope.d.ts +8 -0
- package/dist/compiler/scope.js +116 -0
- package/dist/compiler/scope.js.map +1 -0
- package/dist/compiler/tag-map.d.ts +41 -0
- package/dist/compiler/tag-map.js +126 -0
- package/dist/compiler/tag-map.js.map +1 -0
- package/dist/components-ready.d.ts +7 -0
- package/dist/components-ready.js +19 -0
- package/dist/components-ready.js.map +1 -0
- package/dist/define.d.ts +12 -4
- package/dist/define.js +8 -12
- package/dist/define.js.map +1 -1
- package/dist/devtools-events.d.ts +8 -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 +3 -0
- package/dist/devtools.js +14 -0
- package/dist/devtools.js.map +1 -1
- package/dist/drivers-scope.js.map +1 -1
- package/dist/element-internals.d.ts +1 -0
- package/dist/element-internals.js +11 -0
- package/dist/element-internals.js.map +1 -0
- package/dist/element-types.d.ts +7 -4
- package/dist/element-types.js.map +1 -1
- package/dist/element.js +80 -27
- package/dist/element.js.map +1 -1
- package/dist/error-view.d.ts +10 -0
- package/dist/error-view.js +30 -0
- package/dist/error-view.js.map +1 -0
- package/dist/errors.d.ts +21 -0
- package/dist/errors.js +47 -0
- package/dist/errors.js.map +1 -0
- package/dist/errors.json +289 -0
- package/dist/eslint/imports.d.ts +2 -0
- package/dist/eslint/imports.js +2 -2
- package/dist/eslint/imports.js.map +1 -1
- package/dist/eslint/index.d.ts +2 -1
- package/dist/eslint/index.js +11 -3
- package/dist/eslint/index.js.map +1 -1
- package/dist/eslint/template-rule.d.ts +1 -0
- package/dist/eslint/template-rule.js +15 -5
- package/dist/eslint/template-rule.js.map +1 -1
- package/dist/eslint/unused-intent-rule.d.ts +2 -0
- package/dist/eslint/unused-intent-rule.js +186 -0
- package/dist/eslint/unused-intent-rule.js.map +1 -0
- package/dist/features.d.ts +2 -2
- package/dist/features.js.map +1 -1
- package/dist/focus.d.ts +6 -0
- package/dist/focus.js +32 -2
- package/dist/focus.js.map +1 -1
- package/dist/form-associated.d.ts +46 -0
- package/dist/form-associated.js +77 -0
- package/dist/form-associated.js.map +1 -0
- package/dist/forms.d.ts +42 -30
- package/dist/forms.js +85 -41
- package/dist/forms.js.map +1 -1
- package/dist/frame-lane.d.ts +11 -0
- package/dist/frame-lane.js +28 -0
- package/dist/frame-lane.js.map +1 -0
- package/dist/head.d.ts +61 -0
- package/dist/head.js +85 -0
- package/dist/head.js.map +1 -0
- package/dist/host-model.d.ts +34 -5
- package/dist/host-model.js +146 -23
- package/dist/host-model.js.map +1 -1
- package/dist/hydration-client.js +2 -2
- package/dist/hydration-client.js.map +1 -1
- package/dist/hydration-loader.d.ts +13 -0
- package/dist/hydration-loader.js +58 -0
- package/dist/hydration-loader.js.map +1 -0
- package/dist/hydration-off.d.ts +8 -0
- package/dist/hydration-off.js +25 -0
- package/dist/hydration-off.js.map +1 -0
- package/dist/hydration.d.ts +0 -12
- package/dist/hydration.js +3 -52
- package/dist/hydration.js.map +1 -1
- package/dist/index.d.ts +21 -24
- package/dist/index.js +10 -19
- package/dist/index.js.map +1 -1
- package/dist/indexeddb-types.d.ts +97 -0
- package/dist/indexeddb-types.js +2 -0
- package/dist/indexeddb-types.js.map +1 -0
- package/dist/indexeddb.d.ts +5 -0
- package/dist/indexeddb.js +118 -0
- package/dist/indexeddb.js.map +1 -0
- package/dist/intent.d.ts +42 -20
- package/dist/intent.js +145 -107
- package/dist/intent.js.map +1 -1
- package/dist/internal/indexeddb-open.d.ts +8 -0
- package/dist/internal/indexeddb-open.js +96 -0
- package/dist/internal/indexeddb-open.js.map +1 -0
- package/dist/internal/indexeddb-transaction.d.ts +4 -0
- package/dist/internal/indexeddb-transaction.js +134 -0
- package/dist/internal/indexeddb-transaction.js.map +1 -0
- package/dist/internal/interpreter.d.ts +12 -4
- package/dist/internal/interpreter.js +36 -48
- package/dist/internal/interpreter.js.map +1 -1
- package/dist/internal/token.d.ts +1 -0
- package/dist/internal/token.js +7 -0
- package/dist/internal/token.js.map +1 -0
- package/dist/internal.d.ts +20 -0
- package/dist/internal.js +22 -0
- package/dist/internal.js.map +1 -0
- package/dist/invoker-fallback-used.d.ts +4 -0
- package/dist/invoker-fallback-used.js +10 -0
- package/dist/invoker-fallback-used.js.map +1 -0
- package/dist/invoker-fallback.d.ts +4 -0
- package/dist/invoker-fallback.js +15 -0
- package/dist/invoker-fallback.js.map +1 -0
- package/dist/light-dom.d.ts +1 -1
- package/dist/light-dom.js.map +1 -1
- package/dist/prop.d.ts +30 -7
- package/dist/prop.js +19 -0
- package/dist/prop.js.map +1 -1
- package/dist/props.d.ts +8 -3
- package/dist/props.js +22 -15
- package/dist/props.js.map +1 -1
- package/dist/retry.d.ts +15 -0
- package/dist/retry.js +48 -0
- package/dist/retry.js.map +1 -0
- package/dist/scheduler.d.ts +7 -3
- package/dist/scheduler.js +38 -56
- package/dist/scheduler.js.map +1 -1
- package/dist/script-json.d.ts +2 -0
- package/dist/script-json.js +13 -0
- package/dist/script-json.js.map +1 -0
- package/dist/server-component.d.ts +1 -1
- package/dist/server-component.js +45 -14
- package/dist/server-component.js.map +1 -1
- package/dist/server.d.ts +9 -3
- package/dist/server.js +12 -3
- package/dist/server.js.map +1 -1
- package/dist/settled.d.ts +4 -3
- package/dist/settled.js +48 -26
- package/dist/settled.js.map +1 -1
- package/dist/spec-features-used.d.ts +21 -0
- package/dist/spec-features-used.js +50 -0
- package/dist/spec-features-used.js.map +1 -0
- package/dist/spec-features.d.ts +28 -0
- package/dist/spec-features.js +42 -0
- package/dist/spec-features.js.map +1 -0
- package/dist/states.d.ts +3 -5
- package/dist/states.js +22 -8
- package/dist/states.js.map +1 -1
- package/dist/storage.d.ts +69 -0
- package/dist/storage.js +158 -0
- package/dist/storage.js.map +1 -0
- package/dist/store-binding.js +2 -2
- package/dist/store-binding.js.map +1 -1
- package/dist/store-scope.d.ts +2 -4
- package/dist/store-scope.js +6 -16
- package/dist/store-scope.js.map +1 -1
- package/dist/store.d.ts +2 -6
- package/dist/store.js +36 -8
- package/dist/store.js.map +1 -1
- package/dist/subscription.d.ts +35 -0
- package/dist/subscription.js +74 -0
- package/dist/subscription.js.map +1 -0
- package/dist/subscriptions.d.ts +26 -0
- package/dist/subscriptions.js +98 -0
- package/dist/subscriptions.js.map +1 -0
- package/dist/transitions.d.ts +4 -5
- package/dist/transitions.js +10 -4
- package/dist/transitions.js.map +1 -1
- package/dist/types.d.ts +141 -32
- package/dist/types.js.map +1 -1
- package/dist/use-dialogs.d.ts +2 -0
- package/dist/use-dialogs.js +9 -0
- package/dist/use-dialogs.js.map +1 -0
- package/dist/use-disposal.d.ts +2 -0
- package/dist/use-disposal.js +9 -0
- package/dist/use-disposal.js.map +1 -0
- package/dist/use-error-view.d.ts +2 -0
- package/dist/use-error-view.js +9 -0
- package/dist/use-error-view.js.map +1 -0
- package/dist/use-errored.d.ts +2 -0
- package/dist/use-errored.js +9 -0
- package/dist/use-errored.js.map +1 -0
- package/dist/use-form-associated.d.ts +2 -0
- package/dist/use-form-associated.js +7 -0
- package/dist/use-form-associated.js.map +1 -0
- package/dist/use-frame-lane.d.ts +2 -0
- package/dist/use-frame-lane.js +10 -0
- package/dist/use-frame-lane.js.map +1 -0
- package/dist/use-invokers.d.ts +2 -0
- package/dist/use-invokers.js +10 -0
- package/dist/use-invokers.js.map +1 -0
- package/dist/use-states.d.ts +2 -0
- package/dist/use-states.js +10 -0
- package/dist/use-states.js.map +1 -0
- package/dist/use-subscriptions.d.ts +2 -0
- package/dist/use-subscriptions.js +10 -0
- package/dist/use-subscriptions.js.map +1 -0
- package/dist/use-transitions.d.ts +2 -0
- package/dist/use-transitions.js +10 -0
- package/dist/use-transitions.js.map +1 -0
- package/dist/view/attributes.d.ts +5 -0
- package/dist/view/attributes.js +5 -0
- package/dist/view/attributes.js.map +1 -1
- package/dist/view/compiled.d.ts +1 -1
- package/dist/view/compiled.js +1 -1
- package/dist/view/compiled.js.map +1 -1
- package/dist/view/index.d.ts +9 -4
- package/dist/view/index.js +9 -3
- package/dist/view/index.js.map +1 -1
- package/dist/view/loc.d.ts +9 -0
- package/dist/view/loc.js +50 -0
- package/dist/view/loc.js.map +1 -0
- package/dist/view/message.d.ts +17 -0
- package/dist/view/message.js +40 -0
- package/dist/view/message.js.map +1 -0
- package/dist/view/messages.d.ts +43 -0
- package/dist/view/messages.js +84 -0
- package/dist/view/messages.js.map +1 -0
- package/dist/view/normalize/check.d.ts +5 -2
- package/dist/view/normalize/check.js +6 -3
- package/dist/view/normalize/check.js.map +1 -1
- package/dist/view/normalize/emit.d.ts +2 -0
- package/dist/view/normalize/emit.js +40 -11
- package/dist/view/normalize/emit.js.map +1 -1
- package/dist/view/normalize/errors.js +1 -1
- package/dist/view/normalize/errors.js.map +1 -1
- package/dist/view/normalize/id.d.ts +5 -2
- package/dist/view/normalize/id.js +9 -2
- package/dist/view/normalize/id.js.map +1 -1
- package/dist/view/normalize/normalize.d.ts +7 -4
- package/dist/view/normalize/normalize.js +15 -9
- package/dist/view/normalize/normalize.js.map +1 -1
- package/dist/view/normalize/rules.d.ts +9 -0
- package/dist/view/normalize/rules.js +35 -5
- package/dist/view/normalize/rules.js.map +1 -1
- package/dist/view/normalize/svg.d.ts +14 -0
- package/dist/view/normalize/svg.js +40 -0
- package/dist/view/normalize/svg.js.map +1 -0
- package/dist/view/normalize/tokens.d.ts +5 -1
- package/dist/view/normalize/tokens.js.map +1 -1
- package/dist/view/normalize/tree.d.ts +8 -2
- package/dist/view/normalize/tree.js +58 -13
- package/dist/view/normalize/tree.js.map +1 -1
- package/dist/view/normalize/types.d.ts +24 -4
- package/dist/view/normalize/types.js +4 -1
- package/dist/view/normalize/types.js.map +1 -1
- package/dist/view/normalize/whitespace.js +4 -3
- package/dist/view/normalize/whitespace.js.map +1 -1
- package/dist/view/prepare-stub.js +2 -2
- package/dist/view/prepare-stub.js.map +1 -1
- package/dist/view/prepare.d.ts +5 -2
- package/dist/view/prepare.js +9 -3
- package/dist/view/prepare.js.map +1 -1
- package/dist/view/registry.d.ts +15 -0
- package/dist/view/registry.js +10 -2
- package/dist/view/registry.js.map +1 -1
- package/dist/view/render/adopt-attr.js +7 -1
- package/dist/view/render/adopt-attr.js.map +1 -1
- package/dist/view/render/adopt.js +21 -4
- package/dist/view/render/adopt.js.map +1 -1
- package/dist/view/render/attr-parts.d.ts +12 -1
- package/dist/view/render/attr-parts.js +38 -5
- package/dist/view/render/attr-parts.js.map +1 -1
- package/dist/view/render/child-part.js +5 -2
- package/dist/view/render/child-part.js.map +1 -1
- package/dist/view/render/dispose.d.ts +3 -0
- package/dist/view/render/dispose.js +76 -0
- package/dist/view/render/dispose.js.map +1 -0
- package/dist/view/render/hook-part.d.ts +3 -1
- package/dist/view/render/hook-part.js +21 -5
- package/dist/view/render/hook-part.js.map +1 -1
- package/dist/view/render/hook-run.d.ts +2 -0
- package/dist/view/render/hook-run.js +72 -0
- package/dist/view/render/hook-run.js.map +1 -0
- package/dist/view/render/hooks.d.ts +74 -6
- package/dist/view/render/hooks.js +79 -17
- package/dist/view/render/hooks.js.map +1 -1
- package/dist/view/render/hydrate.js +2 -2
- package/dist/view/render/hydrate.js.map +1 -1
- package/dist/view/render/keyed.d.ts +6 -0
- package/dist/view/render/keyed.js +15 -0
- package/dist/view/render/keyed.js.map +1 -0
- package/dist/view/render/list.d.ts +1 -1
- package/dist/view/render/list.js.map +1 -1
- package/dist/view/render/mismatch.js +5 -3
- package/dist/view/render/mismatch.js.map +1 -1
- package/dist/view/render/modal.d.ts +3 -0
- package/dist/view/render/modal.js +39 -0
- package/dist/view/render/modal.js.map +1 -0
- package/dist/view/render/raw.d.ts +4 -1
- package/dist/view/render/raw.js +6 -2
- package/dist/view/render/raw.js.map +1 -1
- package/dist/view/render/render.d.ts +4 -1
- package/dist/view/render/render.js +17 -12
- package/dist/view/render/render.js.map +1 -1
- package/dist/view/render/toggles.d.ts +6 -0
- package/dist/view/render/toggles.js +6 -0
- package/dist/view/render/toggles.js.map +1 -0
- package/dist/view/render/values.d.ts +1 -1
- package/dist/view/render/values.js.map +1 -1
- package/dist/view/render/warn.d.ts +14 -0
- package/dist/view/render/warn.js +45 -0
- package/dist/view/render/warn.js.map +1 -1
- package/dist/view/server/component.d.ts +6 -3
- package/dist/view/server/component.js +29 -7
- package/dist/view/server/component.js.map +1 -1
- package/dist/view/server/index.d.ts +20 -0
- package/dist/view/server/index.js +12 -4
- package/dist/view/server/index.js.map +1 -1
- package/dist/view/server/tags.d.ts +13 -2
- package/dist/view/server/tags.js +13 -2
- package/dist/view/server/tags.js.map +1 -1
- package/dist/view/server/values.d.ts +2 -0
- package/dist/view/server/values.js +8 -0
- package/dist/view/server/values.js.map +1 -1
- package/dist/view/server/writer.d.ts +9 -4
- package/dist/view/server/writer.js +33 -18
- package/dist/view/server/writer.js.map +1 -1
- package/dist/view/template-element.d.ts +7 -0
- package/dist/view/template-element.js +25 -5
- package/dist/view/template-element.js.map +1 -1
- package/dist/view/template.d.ts +9 -2
- package/dist/view/template.js +61 -8
- package/dist/view/template.js.map +1 -1
- package/dist/view/trusted-html.d.ts +6 -0
- package/dist/view/trusted-html.js +34 -0
- package/dist/view/trusted-html.js.map +1 -0
- package/dist/vite.d.ts +38 -31
- package/dist/vite.js +206 -31
- package/dist/vite.js.map +1 -1
- package/package.json +34 -3
- package/dist/hooks/labelled-by.d.ts +0 -13
- package/dist/hooks/labelled-by.js +0 -51
- package/dist/hooks/labelled-by.js.map +0 -1
- package/dist/random.d.ts +0 -13
- package/dist/random.js +0 -19
- package/dist/random.js.map +0 -1
|
@@ -1,12 +1,16 @@
|
|
|
1
1
|
// `defineHook` (view/02-bindings.md "Element hooks"): its results carry `commitHook`, so the
|
|
2
2
|
// code that compares arguments and queues client calls is bundled only by apps with hooks.
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
3
|
+
// A spec with `dispose` commits through dispose.ts's tracking, registered separately (hooks.ts
|
|
4
|
+
// `disposableCommit`) so apps whose hooks have no teardown don't bundle it (gyral-c5d.2).
|
|
5
|
+
import { DEV } from '#view-dev';
|
|
6
|
+
import { runner } from './hook-run.js';
|
|
7
|
+
import { disposableCommit, hookResult, hookSpec, queueHook, sameArgs, useHookRunner, } from './hooks.js';
|
|
8
|
+
/** Queues the client call when the hook or its arguments changed, or always (`update`). */
|
|
9
|
+
export function commitHook(part, result) {
|
|
6
10
|
const spec = hookSpec(result);
|
|
7
11
|
const args = result.args;
|
|
8
12
|
const same = spec === part.spec;
|
|
9
|
-
if (same && sameArgs(args, part.args))
|
|
13
|
+
if (same && spec.update !== 'always' && sameArgs(args, part.args))
|
|
10
14
|
return;
|
|
11
15
|
part.prev = same ? part.args : undefined;
|
|
12
16
|
part.spec = spec;
|
|
@@ -15,6 +19,18 @@ function commitHook(part, result) {
|
|
|
15
19
|
}
|
|
16
20
|
/** Defines an element hook: a small behaviour attached to the element it sits on. */
|
|
17
21
|
export function defineHook(spec) {
|
|
18
|
-
|
|
22
|
+
useHookRunner(runner);
|
|
23
|
+
return (...args) => hookResult(spec, args, spec.dispose === undefined ? commitHook : commitDisposable);
|
|
24
|
+
}
|
|
25
|
+
let warned = false;
|
|
26
|
+
/** A hook with `dispose`: tracked when disposal is registered, else committed plainly. */
|
|
27
|
+
function commitDisposable(part, result) {
|
|
28
|
+
if (DEV && disposableCommit === undefined && !warned) {
|
|
29
|
+
warned = true;
|
|
30
|
+
console.warn('gyral: a hook declares dispose, but the build found no module naming it, so hook ' +
|
|
31
|
+
'disposal was left out and dispose never runs. Write the dispose key in your source ' +
|
|
32
|
+
'(view/05-element.md "Features register themselves").');
|
|
33
|
+
}
|
|
34
|
+
(disposableCommit ?? commitHook)(part, result);
|
|
19
35
|
}
|
|
20
36
|
//# sourceMappingURL=hook-part.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"hook-part.js","sourceRoot":"","sources":["../../../src/view/render/hook-part.ts"],"names":[],"mappings":"AAAA,6FAA6F;AAC7F,2FAA2F;AAC3F,OAAO,EACL,UAAU,EACV,QAAQ,EACR,SAAS,EACT,QAAQ,
|
|
1
|
+
{"version":3,"file":"hook-part.js","sourceRoot":"","sources":["../../../src/view/render/hook-part.ts"],"names":[],"mappings":"AAAA,6FAA6F;AAC7F,2FAA2F;AAC3F,+FAA+F;AAC/F,0FAA0F;AAC1F,OAAO,EAAE,GAAG,EAAE,MAAM,WAAW,CAAC;AAChC,OAAO,EAAE,MAAM,EAAE,MAAM,eAAe,CAAC;AACvC,OAAO,EACL,gBAAgB,EAChB,UAAU,EACV,QAAQ,EACR,SAAS,EACT,QAAQ,EACR,aAAa,GAId,MAAM,YAAY,CAAC;AAEpB,2FAA2F;AAC3F,MAAM,UAAU,UAAU,CAAC,IAAc,EAAE,MAAkB;IAC3D,MAAM,IAAI,GAAG,QAAQ,CAAC,MAAM,CAAiC,CAAC;IAC9D,MAAM,IAAI,GAAG,MAAM,CAAC,IAAI,CAAC;IACzB,MAAM,IAAI,GAAG,IAAI,KAAK,IAAI,CAAC,IAAI,CAAC;IAChC,IAAI,IAAI,IAAI,IAAI,CAAC,MAAM,KAAK,QAAQ,IAAI,QAAQ,CAAC,IAAI,EAAE,IAAI,CAAC,IAAI,CAAC;QAAE,OAAO;IAC1E,IAAI,CAAC,IAAI,GAAG,IAAI,CAAC,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC,CAAC,SAAS,CAAC;IACzC,IAAI,CAAC,IAAI,GAAG,IAAI,CAAC;IACjB,IAAI,CAAC,IAAI,GAAG,IAAI,CAAC;IACjB,SAAS,CAAC,IAAI,CAAC,CAAC;AAClB,CAAC;AAED,qFAAqF;AACrF,MAAM,UAAU,UAAU,CACxB,IAAiB;IAEjB,aAAa,CAAC,MAAM,CAAC,CAAC;IACtB,OAAO,CAAC,GAAG,IAAI,EAAE,EAAE,CACjB,UAAU,CAAC,IAAI,EAAE,IAAI,EAAE,IAAI,CAAC,OAAO,KAAK,SAAS,CAAC,CAAC,CAAC,UAAU,CAAC,CAAC,CAAC,gBAAgB,CAAC,CAAC;AACvF,CAAC;AAED,IAAI,MAAM,GAAG,KAAK,CAAC;AAEnB,0FAA0F;AAC1F,SAAS,gBAAgB,CAAC,IAAc,EAAE,MAAkB;IAC1D,IAAI,GAAG,IAAI,gBAAgB,KAAK,SAAS,IAAI,CAAC,MAAM,EAAE,CAAC;QACrD,MAAM,GAAG,IAAI,CAAC;QACd,OAAO,CAAC,IAAI,CACV,mFAAmF;YACjF,qFAAqF;YACrF,sDAAsD,CACzD,CAAC;IACJ,CAAC;IACD,CAAC,gBAAgB,IAAI,UAAU,CAAC,CAAC,IAAI,EAAE,MAAM,CAAC,CAAC;AACjD,CAAC","sourcesContent":["// `defineHook` (view/02-bindings.md \"Element hooks\"): its results carry `commitHook`, so the\n// code that compares arguments and queues client calls is bundled only by apps with hooks.\n// A spec with `dispose` commits through dispose.ts's tracking, registered separately (hooks.ts\n// `disposableCommit`) so apps whose hooks have no teardown don't bundle it (gyral-c5d.2).\nimport { DEV } from '#view-dev';\nimport { runner } from './hook-run.js';\nimport {\n disposableCommit,\n hookResult,\n hookSpec,\n queueHook,\n sameArgs,\n useHookRunner,\n type HookPart,\n type HookResult,\n type HookSpec,\n} from './hooks.js';\n\n/** Queues the client call when the hook or its arguments changed, or always (`update`). */\nexport function commitHook(part: HookPart, result: HookResult): void {\n const spec = hookSpec(result) as HookSpec<readonly unknown[]>;\n const args = result.args;\n const same = spec === part.spec;\n if (same && spec.update !== 'always' && sameArgs(args, part.args)) return;\n part.prev = same ? part.args : undefined;\n part.spec = spec;\n part.args = args;\n queueHook(part);\n}\n\n/** Defines an element hook: a small behaviour attached to the element it sits on. */\nexport function defineHook<A extends readonly unknown[]>(\n spec: HookSpec<A>,\n): (...args: A) => HookResult<A> {\n useHookRunner(runner);\n return (...args) =>\n hookResult(spec, args, spec.dispose === undefined ? commitHook : commitDisposable);\n}\n\nlet warned = false;\n\n/** A hook with `dispose`: tracked when disposal is registered, else committed plainly. */\nfunction commitDisposable(part: HookPart, result: HookResult): void {\n if (DEV && disposableCommit === undefined && !warned) {\n warned = true;\n console.warn(\n 'gyral: a hook declares dispose, but the build found no module naming it, so hook ' +\n 'disposal was left out and dispose never runs. Write the dispose key in your source ' +\n '(view/05-element.md \"Features register themselves\").',\n );\n }\n (disposableCommit ?? commitHook)(part, result);\n}\n"]}
|
|
@@ -0,0 +1,72 @@
|
|
|
1
|
+
// Running element hooks' queued client calls (view/02-bindings.md "Commit order",
|
|
2
|
+
// gyral-1zd.27). Inside a scheduler flush the calls wait until every dirty host has rendered,
|
|
3
|
+
// then run children first: one root's calls in document order, roots in reverse render order
|
|
4
|
+
// (the scheduler renders parents before children), so a parent's hook sees the child components
|
|
5
|
+
// it renders. Outside a flush a `render` call runs its own calls when it returns. Installed by
|
|
6
|
+
// `defineHook`/`defineHook` (hook-part.ts), so apps without hooks bundle none of it.
|
|
7
|
+
import { disposalPass, hookFailure, queue, setCommitting, } from './hooks.js';
|
|
8
|
+
/** Inside a flush: the roots rendered since the last flush of hooks (the queue starts empty). */
|
|
9
|
+
let batch;
|
|
10
|
+
/**
|
|
11
|
+
* Runs the calls queued since `mark` for `roots`: disposal first (dispose.ts), then each
|
|
12
|
+
* root's `client` calls in document order, the last-rendered root first. The scheduler renders
|
|
13
|
+
* parents before children, so children's hooks run first. Each hook on its own: one that
|
|
14
|
+
* throws doesn't keep the others from running.
|
|
15
|
+
*/
|
|
16
|
+
function runQueued(mark, roots) {
|
|
17
|
+
try {
|
|
18
|
+
const dispose = disposalPass();
|
|
19
|
+
for (const root of roots) {
|
|
20
|
+
setCommitting(root);
|
|
21
|
+
dispose?.(root); // disposable hooks whose element left `root` dispose first
|
|
22
|
+
}
|
|
23
|
+
const failed = hookFailure();
|
|
24
|
+
// One root's calls are queued together: walk those runs from the end.
|
|
25
|
+
for (let end = queue.length; end > mark;) {
|
|
26
|
+
let start = end - 1;
|
|
27
|
+
while (start > mark && queue[start - 1]?.owner === queue[end - 1]?.owner)
|
|
28
|
+
start--;
|
|
29
|
+
for (let i = start; i < end; i++) {
|
|
30
|
+
const part = queue[i];
|
|
31
|
+
try {
|
|
32
|
+
part.spec.client(part.el, part.args, part.prev);
|
|
33
|
+
}
|
|
34
|
+
catch (error) {
|
|
35
|
+
failed(error, part.owner);
|
|
36
|
+
}
|
|
37
|
+
}
|
|
38
|
+
end = start;
|
|
39
|
+
}
|
|
40
|
+
}
|
|
41
|
+
finally {
|
|
42
|
+
queue.length = mark;
|
|
43
|
+
setCommitting(undefined);
|
|
44
|
+
}
|
|
45
|
+
}
|
|
46
|
+
function flush() {
|
|
47
|
+
if (batch === undefined || batch.length === 0)
|
|
48
|
+
return;
|
|
49
|
+
const roots = batch;
|
|
50
|
+
batch = [];
|
|
51
|
+
runQueued(0, roots);
|
|
52
|
+
}
|
|
53
|
+
export const runner = {
|
|
54
|
+
run(mark, root) {
|
|
55
|
+
if (batch !== undefined)
|
|
56
|
+
batch.push(root);
|
|
57
|
+
else
|
|
58
|
+
runQueued(mark, [root]);
|
|
59
|
+
},
|
|
60
|
+
start() {
|
|
61
|
+
batch = [];
|
|
62
|
+
},
|
|
63
|
+
flush,
|
|
64
|
+
end(ok) {
|
|
65
|
+
if (ok)
|
|
66
|
+
flush();
|
|
67
|
+
else
|
|
68
|
+
queue.length = 0;
|
|
69
|
+
batch = undefined;
|
|
70
|
+
},
|
|
71
|
+
};
|
|
72
|
+
//# sourceMappingURL=hook-run.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"hook-run.js","sourceRoot":"","sources":["../../../src/view/render/hook-run.ts"],"names":[],"mappings":"AAAA,kFAAkF;AAClF,8FAA8F;AAC9F,6FAA6F;AAC7F,gGAAgG;AAChG,+FAA+F;AAC/F,qFAAqF;AACrF,OAAO,EACL,YAAY,EACZ,WAAW,EACX,KAAK,EACL,aAAa,GAId,MAAM,YAAY,CAAC;AAEpB,iGAAiG;AACjG,IAAI,KAAyB,CAAC;AAE9B;;;;;GAKG;AACH,SAAS,SAAS,CAAC,IAAY,EAAE,KAAsB;IACrD,IAAI,CAAC;QACH,MAAM,OAAO,GAAG,YAAY,EAAE,CAAC;QAC/B,KAAK,MAAM,IAAI,IAAI,KAAK,EAAE,CAAC;YACzB,aAAa,CAAC,IAAI,CAAC,CAAC;YACpB,OAAO,EAAE,CAAC,IAAI,CAAC,CAAC,CAAC,2DAA2D;QAC9E,CAAC;QACD,MAAM,MAAM,GAAG,WAAW,EAAE,CAAC;QAC7B,sEAAsE;QACtE,KAAK,IAAI,GAAG,GAAG,KAAK,CAAC,MAAM,EAAE,GAAG,GAAG,IAAI,GAAG,CAAC;YACzC,IAAI,KAAK,GAAG,GAAG,GAAG,CAAC,CAAC;YACpB,OAAO,KAAK,GAAG,IAAI,IAAI,KAAK,CAAC,KAAK,GAAG,CAAC,CAAC,EAAE,KAAK,KAAK,KAAK,CAAC,GAAG,GAAG,CAAC,CAAC,EAAE,KAAK;gBAAE,KAAK,EAAE,CAAC;YAClF,KAAK,IAAI,CAAC,GAAG,KAAK,EAAE,CAAC,GAAG,GAAG,EAAE,CAAC,EAAE,EAAE,CAAC;gBACjC,MAAM,IAAI,GAAG,KAAK,CAAC,CAAC,CAAa,CAAC;gBAClC,IAAI,CAAC;oBACF,IAAI,CAAC,IAAqC,CAAC,MAAM,CAChD,IAAI,CAAC,EAAE,EACP,IAAI,CAAC,IAA0B,EAC/B,IAAI,CAAC,IAAI,CACV,CAAC;gBACJ,CAAC;gBAAC,OAAO,KAAK,EAAE,CAAC;oBACf,MAAM,CAAC,KAAK,EAAE,IAAI,CAAC,KAAa,CAAC,CAAC;gBACpC,CAAC;YACH,CAAC;YACD,GAAG,GAAG,KAAK,CAAC;QACd,CAAC;IACH,CAAC;YAAS,CAAC;QACT,KAAK,CAAC,MAAM,GAAG,IAAI,CAAC;QACpB,aAAa,CAAC,SAAS,CAAC,CAAC;IAC3B,CAAC;AACH,CAAC;AAED,SAAS,KAAK;IACZ,IAAI,KAAK,KAAK,SAAS,IAAI,KAAK,CAAC,MAAM,KAAK,CAAC;QAAE,OAAO;IACtD,MAAM,KAAK,GAAG,KAAK,CAAC;IACpB,KAAK,GAAG,EAAE,CAAC;IACX,SAAS,CAAC,CAAC,EAAE,KAAK,CAAC,CAAC;AACtB,CAAC;AAED,MAAM,CAAC,MAAM,MAAM,GAAe;IAChC,GAAG,CAAC,IAAI,EAAE,IAAI;QACZ,IAAI,KAAK,KAAK,SAAS;YAAE,KAAK,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;;YACrC,SAAS,CAAC,IAAI,EAAE,CAAC,IAAI,CAAC,CAAC,CAAC;IAC/B,CAAC;IACD,KAAK;QACH,KAAK,GAAG,EAAE,CAAC;IACb,CAAC;IACD,KAAK;IACL,GAAG,CAAC,EAAE;QACJ,IAAI,EAAE;YAAE,KAAK,EAAE,CAAC;;YACX,KAAK,CAAC,MAAM,GAAG,CAAC,CAAC;QACtB,KAAK,GAAG,SAAS,CAAC;IACpB,CAAC;CACF,CAAC","sourcesContent":["// Running element hooks' queued client calls (view/02-bindings.md \"Commit order\",\n// gyral-1zd.27). Inside a scheduler flush the calls wait until every dirty host has rendered,\n// then run children first: one root's calls in document order, roots in reverse render order\n// (the scheduler renders parents before children), so a parent's hook sees the child components\n// it renders. Outside a flush a `render` call runs its own calls when it returns. Installed by\n// `defineHook`/`defineHook` (hook-part.ts), so apps without hooks bundle none of it.\nimport {\n disposalPass,\n hookFailure,\n queue,\n setCommitting,\n type HookPart,\n type HookRunner,\n type HookSpec,\n} from './hooks.js';\n\n/** Inside a flush: the roots rendered since the last flush of hooks (the queue starts empty). */\nlet batch: Node[] | undefined;\n\n/**\n * Runs the calls queued since `mark` for `roots`: disposal first (dispose.ts), then each\n * root's `client` calls in document order, the last-rendered root first. The scheduler renders\n * parents before children, so children's hooks run first. Each hook on its own: one that\n * throws doesn't keep the others from running.\n */\nfunction runQueued(mark: number, roots: readonly Node[]): void {\n try {\n const dispose = disposalPass();\n for (const root of roots) {\n setCommitting(root);\n dispose?.(root); // disposable hooks whose element left `root` dispose first\n }\n const failed = hookFailure();\n // One root's calls are queued together: walk those runs from the end.\n for (let end = queue.length; end > mark;) {\n let start = end - 1;\n while (start > mark && queue[start - 1]?.owner === queue[end - 1]?.owner) start--;\n for (let i = start; i < end; i++) {\n const part = queue[i] as HookPart;\n try {\n (part.spec as HookSpec<readonly unknown[]>).client(\n part.el,\n part.args as readonly unknown[],\n part.prev,\n );\n } catch (error) {\n failed(error, part.owner as Node);\n }\n }\n end = start;\n }\n } finally {\n queue.length = mark;\n setCommitting(undefined);\n }\n}\n\nfunction flush(): void {\n if (batch === undefined || batch.length === 0) return;\n const roots = batch;\n batch = [];\n runQueued(0, roots);\n}\n\nexport const runner: HookRunner = {\n run(mark, root) {\n if (batch !== undefined) batch.push(root);\n else runQueued(mark, [root]);\n },\n start() {\n batch = [];\n },\n flush,\n end(ok) {\n if (ok) flush();\n else queue.length = 0;\n batch = undefined;\n },\n};\n"]}
|
|
@@ -4,10 +4,22 @@ export declare const COMMIT_HOOK: unique symbol;
|
|
|
4
4
|
/** Attributes a hook's server half adds to the start tag (`true`: present, no value). */
|
|
5
5
|
export type HookAttributes = Readonly<Record<string, string | true>>;
|
|
6
6
|
export interface HookSpec<A extends readonly unknown[]> {
|
|
7
|
-
/** Attributes for the server-rendered start tag
|
|
7
|
+
/** Attributes for the server-rendered start tag. */
|
|
8
8
|
server?(args: A): HookAttributes;
|
|
9
9
|
/** Runs after the commit when `args` changed; `prev` is undefined the first time. */
|
|
10
10
|
client(el: Element, args: A, prev: A | undefined): void;
|
|
11
|
+
/**
|
|
12
|
+
* When `client` runs again: `'args'` (the default) when an argument changed (`Object.is`),
|
|
13
|
+
* `'always'` on every render that commits the hook's position (a skipped `each` row doesn't).
|
|
14
|
+
*/
|
|
15
|
+
readonly update?: 'args' | 'always';
|
|
16
|
+
/**
|
|
17
|
+
* Teardown, with the last arguments `client` got: runs
|
|
18
|
+
* when Gyral removes the element, when the position stops holding this hook, or when the host
|
|
19
|
+
* disconnects (not on moves). After a host reconnects, `client` runs again with `prev`
|
|
20
|
+
* undefined.
|
|
21
|
+
*/
|
|
22
|
+
dispose?(el: Element, args: A): void;
|
|
11
23
|
}
|
|
12
24
|
/** What a hook returns in a template: `<input ${invalid(errors)}>`. */
|
|
13
25
|
export interface HookResult<A extends readonly unknown[] = readonly unknown[]> {
|
|
@@ -21,6 +33,13 @@ export interface HookPart {
|
|
|
21
33
|
spec: HookSpec<readonly unknown[]> | null;
|
|
22
34
|
args: readonly unknown[] | undefined;
|
|
23
35
|
prev: readonly unknown[] | undefined;
|
|
36
|
+
/** dispose.ts: the tracked disposable hook, its last arguments, and whether a disconnect
|
|
37
|
+
* disposed it (`client` runs again after the next render). */
|
|
38
|
+
kept?: HookSpec<readonly unknown[]> | undefined;
|
|
39
|
+
keptArgs?: readonly unknown[] | undefined;
|
|
40
|
+
off?: boolean | undefined;
|
|
41
|
+
/** The render root it was queued for (hook-run.ts: failures, order). */
|
|
42
|
+
owner?: Node | undefined;
|
|
24
43
|
}
|
|
25
44
|
export declare const isHook: (value: unknown) => value is HookResult;
|
|
26
45
|
/** The spec of a hook result, or undefined for anything else. */
|
|
@@ -29,12 +48,61 @@ export declare const hookSpec: (value: unknown) => HookSpec<readonly unknown[]>
|
|
|
29
48
|
export declare const hookResult: <A extends readonly unknown[]>(spec: HookSpec<A>, args: A, commit: HookResult[typeof COMMIT_HOOK]) => HookResult<A>;
|
|
30
49
|
/** Shallow comparison of two argument lists, `Object.is` per argument. */
|
|
31
50
|
export declare function sameArgs(a: readonly unknown[], b: readonly unknown[] | undefined): boolean;
|
|
32
|
-
/**
|
|
51
|
+
/**
|
|
52
|
+
* Hook disposal (dispose.ts), set when the first disposable hook commits: `disposal(root)`
|
|
53
|
+
* after a render of `root` commits (before its client calls), `disposal(root, true)` when the
|
|
54
|
+
* host owning `root` disconnects (true when hooks wait to run `client` again after the next
|
|
55
|
+
* render). A plain variable, not an object, to keep apps without it small.
|
|
56
|
+
*/
|
|
57
|
+
declare let disposal: ((root: Node, disconnect?: boolean) => boolean) | undefined;
|
|
58
|
+
/** Internal (dispose.ts): turns hook disposal on. */
|
|
59
|
+
export declare function useDisposal(run: (root: Node, disconnect?: boolean) => boolean): void;
|
|
60
|
+
/** How a hook with `dispose` commits (dispose.ts `commitTracked`), once registered. */
|
|
61
|
+
export declare let disposableCommit: ((part: HookPart, result: HookResult) => void) | undefined;
|
|
62
|
+
/** Internal (`#spec-features`, use-disposal.ts): registers hook disposal. */
|
|
63
|
+
export declare function useDisposableHooks(commit: (part: HookPart, result: HookResult) => void): void;
|
|
64
|
+
/** The host owning `root` disconnected (element.ts): disposes its disposable hooks. */
|
|
65
|
+
export declare const suspendHooks: (root: Node | undefined) => boolean | undefined;
|
|
66
|
+
/** Internal (hook-run.ts): queued client calls. */
|
|
67
|
+
export declare const queue: HookPart[];
|
|
68
|
+
/** Queues `part`'s client call for the end of the render, or of the flush. */
|
|
33
69
|
export declare function queueHook(part: HookPart): void;
|
|
34
|
-
/** The
|
|
35
|
-
export declare const
|
|
36
|
-
/**
|
|
37
|
-
export declare function
|
|
70
|
+
/** The root being committed (dispose.ts tracks disposable hooks per root). */
|
|
71
|
+
export declare const committing: () => Node | undefined;
|
|
72
|
+
/** Internal (hook-run.ts): sets the root being committed (disposal re-queues hooks for it). */
|
|
73
|
+
export declare function setCommitting(root: Node | undefined): void;
|
|
74
|
+
/** The queue position before a render of `root`, for `runHooks`/`dropHooks`. */
|
|
75
|
+
export declare function hookMark(root: Node): number;
|
|
76
|
+
/** Internal (core's element.ts): reports hook failures. */
|
|
77
|
+
export declare function onHookFailure(report: (error: unknown, root: Node) => void): void;
|
|
78
|
+
/** Internal (hook-run.ts): where failures go, and the disposal pass. */
|
|
79
|
+
export declare const hookFailure: () => ((error: unknown, root: Node) => void);
|
|
80
|
+
export declare const disposalPass: () => typeof disposal;
|
|
81
|
+
/**
|
|
82
|
+
* What runs queued client calls (hook-run.ts): ordering, batching across a flush, failures.
|
|
83
|
+
* Set by `defineHook`, so apps without hooks bundle none of it; without
|
|
84
|
+
* hooks nothing is ever queued.
|
|
85
|
+
*/
|
|
86
|
+
export interface HookRunner {
|
|
87
|
+
/** `root` committed: run its calls now, or note it for the end of the flush. */
|
|
88
|
+
run(mark: number, root: Node): void;
|
|
89
|
+
/** A flush starts. */
|
|
90
|
+
start(): void;
|
|
91
|
+
/** Runs the calls of every root rendered in the flush so far. */
|
|
92
|
+
flush(): void;
|
|
93
|
+
/** A flush ends: runs what's left (or drops it when the flush threw). */
|
|
94
|
+
end(ok: boolean): void;
|
|
95
|
+
}
|
|
96
|
+
/** Internal (hook-part.ts): installs the runner. */
|
|
97
|
+
export declare function useHookRunner(run: HookRunner): void;
|
|
98
|
+
/** `root` committed: its queued `client` calls run now, or with the flush's (hook-run.ts). */
|
|
99
|
+
export declare function runHooks(mark: number, root: Node): void;
|
|
100
|
+
/** A flush starts (render.ts `renderBatch`). */
|
|
101
|
+
export declare function startHooks(): void;
|
|
102
|
+
/** Runs the hooks of every root rendered in this flush so far (the scheduler, after each pass). */
|
|
103
|
+
export declare function flushHooks(): void;
|
|
104
|
+
/** A flush ends. */
|
|
105
|
+
export declare function endHooks(ok: boolean): void;
|
|
38
106
|
/** Forgets the calls queued since `mark` (the render threw). */
|
|
39
107
|
export declare function dropHooks(mark: number): void;
|
|
40
108
|
export {};
|
|
@@ -1,8 +1,18 @@
|
|
|
1
1
|
// Element hooks (view/02-bindings.md "Element hooks", "Commit order"): their types and the
|
|
2
2
|
// queue of client calls. A hook position (attr-parts.ts, kind HOOK) queues itself when its
|
|
3
3
|
// arguments change (shallow `Object.is` per argument, hook-part.ts, which also holds
|
|
4
|
-
// `defineHook`)
|
|
5
|
-
//
|
|
4
|
+
// `defineHook`), or on every commit with `update: 'always'`. Inside a scheduler flush
|
|
5
|
+
// (`renderBatch`) the queued `client` calls wait until every dirty host has rendered, then run
|
|
6
|
+
// children first, each root's calls in document order (hook-run.ts), so a parent's hook sees its
|
|
7
|
+
// child components rendered (view/02 "Commit order"). A `render` call outside a flush runs its
|
|
8
|
+
// own calls when it returns, in document order.
|
|
9
|
+
// A hook whose spec has `dispose` runs it when the element leaves its render root (Gyral removed
|
|
10
|
+
// it: its part cleared, its instance replaced, its row removed), when the position stops holding
|
|
11
|
+
// the hook, or when the host disconnects; not on moves. That machinery (dispose.ts) is reached
|
|
12
|
+
// through `disposableCommit`, filled by core's `#spec-features` (every build without the preset)
|
|
13
|
+
// or, with the preset, only when some module names `dispose` (compiler/features.ts): apps whose
|
|
14
|
+
// hooks have no teardown don't bundle it (gyral-c5d.2, gyral-1zd.24) and pay one empty check per
|
|
15
|
+
// render and per disconnect.
|
|
6
16
|
const HOOK = Symbol('gyral.hook');
|
|
7
17
|
/** Internal: a hook result's commit function (hook-part.ts), so apps without hooks skip it. */
|
|
8
18
|
export const COMMIT_HOOK = Symbol('gyral.hook.commit');
|
|
@@ -20,27 +30,79 @@ export function sameArgs(a, b) {
|
|
|
20
30
|
return false;
|
|
21
31
|
return true;
|
|
22
32
|
}
|
|
23
|
-
|
|
24
|
-
|
|
33
|
+
/**
|
|
34
|
+
* Hook disposal (dispose.ts), set when the first disposable hook commits: `disposal(root)`
|
|
35
|
+
* after a render of `root` commits (before its client calls), `disposal(root, true)` when the
|
|
36
|
+
* host owning `root` disconnects (true when hooks wait to run `client` again after the next
|
|
37
|
+
* render). A plain variable, not an object, to keep apps without it small.
|
|
38
|
+
*/
|
|
39
|
+
let disposal;
|
|
40
|
+
/** Internal (dispose.ts): turns hook disposal on. */
|
|
41
|
+
export function useDisposal(run) {
|
|
42
|
+
disposal = run;
|
|
43
|
+
}
|
|
44
|
+
/** How a hook with `dispose` commits (dispose.ts `commitTracked`), once registered. */
|
|
45
|
+
export let disposableCommit;
|
|
46
|
+
/** Internal (`#spec-features`, use-disposal.ts): registers hook disposal. */
|
|
47
|
+
export function useDisposableHooks(commit) {
|
|
48
|
+
disposableCommit = commit;
|
|
49
|
+
}
|
|
50
|
+
/** The host owning `root` disconnected (element.ts): disposes its disposable hooks. */
|
|
51
|
+
export const suspendHooks = (root) => disposal?.(root, true);
|
|
52
|
+
/** Internal (hook-run.ts): queued client calls. */
|
|
53
|
+
export const queue = [];
|
|
54
|
+
/** The root being committed, so `queueHook` knows the owner. */
|
|
55
|
+
let current;
|
|
56
|
+
/** Queues `part`'s client call for the end of the render, or of the flush. */
|
|
25
57
|
export function queueHook(part) {
|
|
58
|
+
part.owner = current;
|
|
26
59
|
queue.push(part);
|
|
27
60
|
}
|
|
28
|
-
/** The
|
|
29
|
-
export const
|
|
30
|
-
/**
|
|
31
|
-
export function
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
61
|
+
/** The root being committed (dispose.ts tracks disposable hooks per root). */
|
|
62
|
+
export const committing = () => current;
|
|
63
|
+
/** Internal (hook-run.ts): sets the root being committed (disposal re-queues hooks for it). */
|
|
64
|
+
export function setCommitting(root) {
|
|
65
|
+
current = root;
|
|
66
|
+
}
|
|
67
|
+
/** The queue position before a render of `root`, for `runHooks`/`dropHooks`. */
|
|
68
|
+
export function hookMark(root) {
|
|
69
|
+
current = root;
|
|
70
|
+
return queue.length;
|
|
71
|
+
}
|
|
72
|
+
/** Where a hook's failure goes (core reports it, ADR 0024); unset, `reportError`. */
|
|
73
|
+
let hookFailed;
|
|
74
|
+
/** Internal (core's element.ts): reports hook failures. */
|
|
75
|
+
export function onHookFailure(report) {
|
|
76
|
+
hookFailed = report;
|
|
77
|
+
}
|
|
78
|
+
/** Internal (hook-run.ts): where failures go, and the disposal pass. */
|
|
79
|
+
export const hookFailure = () => hookFailed ?? reportError;
|
|
80
|
+
export const disposalPass = () => disposal;
|
|
81
|
+
let runner;
|
|
82
|
+
/** Internal (hook-part.ts): installs the runner. */
|
|
83
|
+
export function useHookRunner(run) {
|
|
84
|
+
runner = run;
|
|
85
|
+
}
|
|
86
|
+
/** `root` committed: its queued `client` calls run now, or with the flush's (hook-run.ts). */
|
|
87
|
+
export function runHooks(mark, root) {
|
|
88
|
+
current = undefined;
|
|
89
|
+
runner?.run(mark, root);
|
|
90
|
+
}
|
|
91
|
+
/** A flush starts (render.ts `renderBatch`). */
|
|
92
|
+
export function startHooks() {
|
|
93
|
+
runner?.start();
|
|
94
|
+
}
|
|
95
|
+
/** Runs the hooks of every root rendered in this flush so far (the scheduler, after each pass). */
|
|
96
|
+
export function flushHooks() {
|
|
97
|
+
runner?.flush();
|
|
98
|
+
}
|
|
99
|
+
/** A flush ends. */
|
|
100
|
+
export function endHooks(ok) {
|
|
101
|
+
runner?.end(ok);
|
|
41
102
|
}
|
|
42
103
|
/** Forgets the calls queued since `mark` (the render threw). */
|
|
43
104
|
export function dropHooks(mark) {
|
|
44
105
|
queue.length = mark;
|
|
106
|
+
current = undefined;
|
|
45
107
|
}
|
|
46
108
|
//# sourceMappingURL=hooks.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"hooks.js","sourceRoot":"","sources":["../../../src/view/render/hooks.ts"],"names":[],"mappings":"AAAA,2FAA2F;AAC3F,2FAA2F;AAC3F,qFAAqF;AACrF,8FAA8F;AAC9F,mFAAmF;AAEnF,MAAM,IAAI,GAAkB,MAAM,CAAC,YAAY,CAAC,CAAC;AACjD,+FAA+F;AAC/F,MAAM,CAAC,MAAM,WAAW,GAAkB,MAAM,CAAC,mBAAmB,CAAC,CAAC;AA2BtE,MAAM,CAAC,MAAM,MAAM,GAAG,CAAC,KAAc,EAAuB,EAAE,CAC5D,OAAO,KAAK,KAAK,QAAQ,IAAI,KAAK,KAAK,IAAI,IAAI,IAAI,IAAI,KAAK,CAAC;AAE/D,iEAAiE;AACjE,MAAM,CAAC,MAAM,QAAQ,GAAG,CAAC,KAAc,EAA4C,EAAE,CACnF,MAAM,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,KAAK,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC,SAAS,CAAC;AAE1C,8CAA8C;AAC9C,MAAM,CAAC,MAAM,UAAU,GAAG,CACxB,IAAiB,EACjB,IAAO,EACP,MAAsC,EACvB,EAAE,CAAC,CAAC,EAAE,CAAC,IAAI,CAAC,EAAE,IAAI,EAAE,CAAC,WAAW,CAAC,EAAE,MAAM,EAAE,IAAI,EAAE,CAAC,CAAC;AAEpE,0EAA0E;AAC1E,MAAM,UAAU,QAAQ,CAAC,CAAqB,EAAE,CAAiC;IAC/E,IAAI,CAAC,KAAK,SAAS,IAAI,CAAC,CAAC,MAAM,KAAK,CAAC,CAAC,MAAM;QAAE,OAAO,KAAK,CAAC;IAC3D,KAAK,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,CAAC,CAAC,MAAM,EAAE,CAAC,EAAE;QAAE,IAAI,CAAC,MAAM,CAAC,EAAE,CAAC,CAAC,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,CAAC,CAAC;YAAE,OAAO,KAAK,CAAC;IAC5E,OAAO,IAAI,CAAC;AACd,CAAC;AAED,MAAM,KAAK,GAAe,EAAE,CAAC;AAE7B,8EAA8E;AAC9E,MAAM,UAAU,SAAS,CAAC,IAAc;IACtC,KAAK,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;AACnB,CAAC;AAED,sEAAsE;AACtE,MAAM,CAAC,MAAM,QAAQ,GAAG,GAAW,EAAE,CAAC,KAAK,CAAC,MAAM,CAAC;AAEnD,sEAAsE;AACtE,MAAM,UAAU,QAAQ,CAAC,IAAY;IACnC,IAAI,CAAC;QACH,KAAK,IAAI,CAAC,GAAG,IAAI,EAAE,CAAC,GAAG,KAAK,CAAC,MAAM,EAAE,CAAC,EAAE,EAAE,CAAC;YACzC,MAAM,IAAI,GAAG,KAAK,CAAC,CAAC,CAAa,CAAC;YACjC,IAAI,CAAC,IAAqC,CAAC,MAAM,CAChD,IAAI,CAAC,EAAE,EACP,IAAI,CAAC,IAA0B,EAC/B,IAAI,CAAC,IAAI,CACV,CAAC;QACJ,CAAC;IACH,CAAC;YAAS,CAAC;QACT,KAAK,CAAC,MAAM,GAAG,IAAI,CAAC;IACtB,CAAC;AACH,CAAC;AAED,gEAAgE;AAChE,MAAM,UAAU,SAAS,CAAC,IAAY;IACpC,KAAK,CAAC,MAAM,GAAG,IAAI,CAAC;AACtB,CAAC","sourcesContent":["// Element hooks (view/02-bindings.md \"Element hooks\", \"Commit order\"): their types and the\n// queue of client calls. A hook position (attr-parts.ts, kind HOOK) queues itself when its\n// arguments change (shallow `Object.is` per argument, hook-part.ts, which also holds\n// `defineHook`); `render` runs the queued `client` calls after the commit, in document order.\n// There is no cleanup: listeners a hook adds to its element are collected with it.\n\nconst HOOK: unique symbol = Symbol('gyral.hook');\n/** Internal: a hook result's commit function (hook-part.ts), so apps without hooks skip it. */\nexport const COMMIT_HOOK: unique symbol = Symbol('gyral.hook.commit');\n\n/** Attributes a hook's server half adds to the start tag (`true`: present, no value). */\nexport type HookAttributes = Readonly<Record<string, string | true>>;\n\nexport interface HookSpec<A extends readonly unknown[]> {\n /** Attributes for the server-rendered start tag (view/06-server.md). */\n server?(args: A): HookAttributes;\n /** Runs after the commit when `args` changed; `prev` is undefined the first time. */\n client(el: Element, args: A, prev: A | undefined): void;\n}\n\n/** What a hook returns in a template: `<input ${invalid(errors)}>`. */\nexport interface HookResult<A extends readonly unknown[] = readonly unknown[]> {\n readonly [HOOK]: HookSpec<A>;\n readonly [COMMIT_HOOK]: (part: HookPart, result: HookResult) => void;\n readonly args: A;\n}\n\n/** A hook position as committing sees it (an element part of kind HOOK). */\nexport interface HookPart {\n readonly el: Element;\n spec: HookSpec<readonly unknown[]> | null;\n args: readonly unknown[] | undefined;\n prev: readonly unknown[] | undefined;\n}\n\nexport const isHook = (value: unknown): value is HookResult =>\n typeof value === 'object' && value !== null && HOOK in value;\n\n/** The spec of a hook result, or undefined for anything else. */\nexport const hookSpec = (value: unknown): HookSpec<readonly unknown[]> | undefined =>\n isHook(value) ? value[HOOK] : undefined;\n\n/** Internal (hook-part.ts): a hook result. */\nexport const hookResult = <A extends readonly unknown[]>(\n spec: HookSpec<A>,\n args: A,\n commit: HookResult[typeof COMMIT_HOOK],\n): HookResult<A> => ({ [HOOK]: spec, [COMMIT_HOOK]: commit, args });\n\n/** Shallow comparison of two argument lists, `Object.is` per argument. */\nexport function sameArgs(a: readonly unknown[], b: readonly unknown[] | undefined): boolean {\n if (b === undefined || a.length !== b.length) return false;\n for (let i = 0; i < a.length; i++) if (!Object.is(a[i], b[i])) return false;\n return true;\n}\n\nconst queue: HookPart[] = [];\n\n/** Queues `part`'s client call for the end of the render (document order). */\nexport function queueHook(part: HookPart): void {\n queue.push(part);\n}\n\n/** The queue position before a render, for `runHooks`/`dropHooks`. */\nexport const hookMark = (): number => queue.length;\n\n/** Runs the `client` calls queued since `mark`, in document order. */\nexport function runHooks(mark: number): void {\n try {\n for (let i = mark; i < queue.length; i++) {\n const part = queue[i] as HookPart;\n (part.spec as HookSpec<readonly unknown[]>).client(\n part.el,\n part.args as readonly unknown[],\n part.prev,\n );\n }\n } finally {\n queue.length = mark;\n }\n}\n\n/** Forgets the calls queued since `mark` (the render threw). */\nexport function dropHooks(mark: number): void {\n queue.length = mark;\n}\n"]}
|
|
1
|
+
{"version":3,"file":"hooks.js","sourceRoot":"","sources":["../../../src/view/render/hooks.ts"],"names":[],"mappings":"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","sourcesContent":["// Element hooks (view/02-bindings.md \"Element hooks\", \"Commit order\"): their types and the\n// queue of client calls. A hook position (attr-parts.ts, kind HOOK) queues itself when its\n// arguments change (shallow `Object.is` per argument, hook-part.ts, which also holds\n// `defineHook`), or on every commit with `update: 'always'`. Inside a scheduler flush\n// (`renderBatch`) the queued `client` calls wait until every dirty host has rendered, then run\n// children first, each root's calls in document order (hook-run.ts), so a parent's hook sees its\n// child components rendered (view/02 \"Commit order\"). A `render` call outside a flush runs its\n// own calls when it returns, in document order.\n// A hook whose spec has `dispose` runs it when the element leaves its render root (Gyral removed\n// it: its part cleared, its instance replaced, its row removed), when the position stops holding\n// the hook, or when the host disconnects; not on moves. That machinery (dispose.ts) is reached\n// through `disposableCommit`, filled by core's `#spec-features` (every build without the preset)\n// or, with the preset, only when some module names `dispose` (compiler/features.ts): apps whose\n// hooks have no teardown don't bundle it (gyral-c5d.2, gyral-1zd.24) and pay one empty check per\n// render and per disconnect.\n\nconst HOOK: unique symbol = Symbol('gyral.hook');\n/** Internal: a hook result's commit function (hook-part.ts), so apps without hooks skip it. */\nexport const COMMIT_HOOK: unique symbol = Symbol('gyral.hook.commit');\n\n/** Attributes a hook's server half adds to the start tag (`true`: present, no value). */\nexport type HookAttributes = Readonly<Record<string, string | true>>;\n\nexport interface HookSpec<A extends readonly unknown[]> {\n /** Attributes for the server-rendered start tag. */\n server?(args: A): HookAttributes;\n /** Runs after the commit when `args` changed; `prev` is undefined the first time. */\n client(el: Element, args: A, prev: A | undefined): void;\n /**\n * When `client` runs again: `'args'` (the default) when an argument changed (`Object.is`),\n * `'always'` on every render that commits the hook's position (a skipped `each` row doesn't).\n */\n readonly update?: 'args' | 'always';\n /**\n * Teardown, with the last arguments `client` got: runs\n * when Gyral removes the element, when the position stops holding this hook, or when the host\n * disconnects (not on moves). After a host reconnects, `client` runs again with `prev`\n * undefined.\n */\n dispose?(el: Element, args: A): void;\n}\n\n/** What a hook returns in a template: `<input ${invalid(errors)}>`. */\nexport interface HookResult<A extends readonly unknown[] = readonly unknown[]> {\n readonly [HOOK]: HookSpec<A>;\n readonly [COMMIT_HOOK]: (part: HookPart, result: HookResult) => void;\n readonly args: A;\n}\n\n/** A hook position as committing sees it (an element part of kind HOOK). */\nexport interface HookPart {\n readonly el: Element;\n spec: HookSpec<readonly unknown[]> | null;\n args: readonly unknown[] | undefined;\n prev: readonly unknown[] | undefined;\n /** dispose.ts: the tracked disposable hook, its last arguments, and whether a disconnect\n * disposed it (`client` runs again after the next render). */\n kept?: HookSpec<readonly unknown[]> | undefined;\n keptArgs?: readonly unknown[] | undefined;\n off?: boolean | undefined;\n /** The render root it was queued for (hook-run.ts: failures, order). */\n owner?: Node | undefined;\n}\n\nexport const isHook = (value: unknown): value is HookResult =>\n typeof value === 'object' && value !== null && HOOK in value;\n\n/** The spec of a hook result, or undefined for anything else. */\nexport const hookSpec = (value: unknown): HookSpec<readonly unknown[]> | undefined =>\n isHook(value) ? value[HOOK] : undefined;\n\n/** Internal (hook-part.ts): a hook result. */\nexport const hookResult = <A extends readonly unknown[]>(\n spec: HookSpec<A>,\n args: A,\n commit: HookResult[typeof COMMIT_HOOK],\n): HookResult<A> => ({ [HOOK]: spec, [COMMIT_HOOK]: commit, args });\n\n/** Shallow comparison of two argument lists, `Object.is` per argument. */\nexport function sameArgs(a: readonly unknown[], b: readonly unknown[] | undefined): boolean {\n if (b === undefined || a.length !== b.length) return false;\n for (let i = 0; i < a.length; i++) if (!Object.is(a[i], b[i])) return false;\n return true;\n}\n\n/**\n * Hook disposal (dispose.ts), set when the first disposable hook commits: `disposal(root)`\n * after a render of `root` commits (before its client calls), `disposal(root, true)` when the\n * host owning `root` disconnects (true when hooks wait to run `client` again after the next\n * render). A plain variable, not an object, to keep apps without it small.\n */\nlet disposal: ((root: Node, disconnect?: boolean) => boolean) | undefined;\n\n/** Internal (dispose.ts): turns hook disposal on. */\nexport function useDisposal(run: (root: Node, disconnect?: boolean) => boolean): void {\n disposal = run;\n}\n\n/** How a hook with `dispose` commits (dispose.ts `commitTracked`), once registered. */\nexport let disposableCommit: ((part: HookPart, result: HookResult) => void) | undefined;\n\n/** Internal (`#spec-features`, use-disposal.ts): registers hook disposal. */\nexport function useDisposableHooks(commit: (part: HookPart, result: HookResult) => void): void {\n disposableCommit = commit;\n}\n\n/** The host owning `root` disconnected (element.ts): disposes its disposable hooks. */\nexport const suspendHooks = (root: Node | undefined): boolean | undefined =>\n disposal?.(root as Node, true);\n\n/** Internal (hook-run.ts): queued client calls. */\nexport const queue: HookPart[] = [];\n/** The root being committed, so `queueHook` knows the owner. */\nlet current: Node | undefined;\n\n/** Queues `part`'s client call for the end of the render, or of the flush. */\nexport function queueHook(part: HookPart): void {\n part.owner = current;\n queue.push(part);\n}\n\n/** The root being committed (dispose.ts tracks disposable hooks per root). */\nexport const committing = (): Node | undefined => current;\n\n/** Internal (hook-run.ts): sets the root being committed (disposal re-queues hooks for it). */\nexport function setCommitting(root: Node | undefined): void {\n current = root;\n}\n\n/** The queue position before a render of `root`, for `runHooks`/`dropHooks`. */\nexport function hookMark(root: Node): number {\n current = root;\n return queue.length;\n}\n\n/** Where a hook's failure goes (core reports it, ADR 0024); unset, `reportError`. */\nlet hookFailed: ((error: unknown, root: Node) => void) | undefined;\n\n/** Internal (core's element.ts): reports hook failures. */\nexport function onHookFailure(report: (error: unknown, root: Node) => void): void {\n hookFailed = report;\n}\n\n/** Internal (hook-run.ts): where failures go, and the disposal pass. */\nexport const hookFailure = (): ((error: unknown, root: Node) => void) => hookFailed ?? reportError;\nexport const disposalPass = (): typeof disposal => disposal;\n\n/**\n * What runs queued client calls (hook-run.ts): ordering, batching across a flush, failures.\n * Set by `defineHook`, so apps without hooks bundle none of it; without\n * hooks nothing is ever queued.\n */\nexport interface HookRunner {\n /** `root` committed: run its calls now, or note it for the end of the flush. */\n run(mark: number, root: Node): void;\n /** A flush starts. */\n start(): void;\n /** Runs the calls of every root rendered in the flush so far. */\n flush(): void;\n /** A flush ends: runs what's left (or drops it when the flush threw). */\n end(ok: boolean): void;\n}\n\nlet runner: HookRunner | undefined;\n\n/** Internal (hook-part.ts): installs the runner. */\nexport function useHookRunner(run: HookRunner): void {\n runner = run;\n}\n\n/** `root` committed: its queued `client` calls run now, or with the flush's (hook-run.ts). */\nexport function runHooks(mark: number, root: Node): void {\n current = undefined;\n runner?.run(mark, root);\n}\n\n/** A flush starts (render.ts `renderBatch`). */\nexport function startHooks(): void {\n runner?.start();\n}\n\n/** Runs the hooks of every root rendered in this flush so far (the scheduler, after each pass). */\nexport function flushHooks(): void {\n runner?.flush();\n}\n\n/** A flush ends. */\nexport function endHooks(ok: boolean): void {\n runner?.end(ok);\n}\n\n/** Forgets the calls queued since `mark` (the render threw). */\nexport function dropHooks(mark: number): void {\n queue.length = mark;\n current = undefined;\n}\n"]}
|
|
@@ -15,7 +15,7 @@ import { listenFor } from './seen.js';
|
|
|
15
15
|
*/
|
|
16
16
|
export function hydrate(value, root, host = 'the root', seen) {
|
|
17
17
|
const part = new ChildPart(root, null, null, 0, false, 0);
|
|
18
|
-
const mark = hookMark();
|
|
18
|
+
const mark = hookMark(root);
|
|
19
19
|
const outer = listenFor(seen);
|
|
20
20
|
try {
|
|
21
21
|
adopt(part, value, root, host);
|
|
@@ -28,6 +28,6 @@ export function hydrate(value, root, host = 'the root', seen) {
|
|
|
28
28
|
listenFor(outer);
|
|
29
29
|
}
|
|
30
30
|
setRootPart(root, part);
|
|
31
|
-
runHooks(mark);
|
|
31
|
+
runHooks(mark, root);
|
|
32
32
|
}
|
|
33
33
|
//# sourceMappingURL=hydrate.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"hydrate.js","sourceRoot":"","sources":["../../../src/view/render/hydrate.ts"],"names":[],"mappings":"AAAA,iGAAiG;AACjG,iGAAiG;AACjG,uEAAuE;AACvE,OAAO,EAAE,KAAK,EAAE,MAAM,YAAY,CAAC;AACnC,OAAO,EAAE,SAAS,EAAE,MAAM,iBAAiB,CAAC;AAC5C,OAAO,EAAE,SAAS,EAAE,QAAQ,EAAE,QAAQ,EAAE,MAAM,YAAY,CAAC;AAC3D,OAAO,EAAE,WAAW,EAAE,MAAM,aAAa,CAAC;AAC1C,OAAO,EAAE,SAAS,EAAmB,MAAM,WAAW,CAAC;AAGvD;;;;;;GAMG;AACH,MAAM,UAAU,OAAO,CACrB,KAAiB,EACjB,IAA0B,EAC1B,IAAI,GAAG,UAAU,EACjB,IAAiB;IAEjB,MAAM,IAAI,GAAG,IAAI,SAAS,CAAC,IAAI,EAAE,IAAI,EAAE,IAAI,EAAE,CAAC,EAAE,KAAK,EAAE,CAAC,CAAC,CAAC;IAC1D,MAAM,IAAI,GAAG,QAAQ,
|
|
1
|
+
{"version":3,"file":"hydrate.js","sourceRoot":"","sources":["../../../src/view/render/hydrate.ts"],"names":[],"mappings":"AAAA,iGAAiG;AACjG,iGAAiG;AACjG,uEAAuE;AACvE,OAAO,EAAE,KAAK,EAAE,MAAM,YAAY,CAAC;AACnC,OAAO,EAAE,SAAS,EAAE,MAAM,iBAAiB,CAAC;AAC5C,OAAO,EAAE,SAAS,EAAE,QAAQ,EAAE,QAAQ,EAAE,MAAM,YAAY,CAAC;AAC3D,OAAO,EAAE,WAAW,EAAE,MAAM,aAAa,CAAC;AAC1C,OAAO,EAAE,SAAS,EAAmB,MAAM,WAAW,CAAC;AAGvD;;;;;;GAMG;AACH,MAAM,UAAU,OAAO,CACrB,KAAiB,EACjB,IAA0B,EAC1B,IAAI,GAAG,UAAU,EACjB,IAAiB;IAEjB,MAAM,IAAI,GAAG,IAAI,SAAS,CAAC,IAAI,EAAE,IAAI,EAAE,IAAI,EAAE,CAAC,EAAE,KAAK,EAAE,CAAC,CAAC,CAAC;IAC1D,MAAM,IAAI,GAAG,QAAQ,CAAC,IAAI,CAAC,CAAC;IAC5B,MAAM,KAAK,GAAG,SAAS,CAAC,IAAI,CAAC,CAAC;IAC9B,IAAI,CAAC;QACH,KAAK,CAAC,IAAI,EAAE,KAAK,EAAE,IAAI,EAAE,IAAI,CAAC,CAAC;IACjC,CAAC;IAAC,OAAO,KAAK,EAAE,CAAC;QACf,SAAS,CAAC,IAAI,CAAC,CAAC;QAChB,MAAM,KAAK,CAAC;IACd,CAAC;YAAS,CAAC;QACT,SAAS,CAAC,KAAK,CAAC,CAAC;IACnB,CAAC;IACD,WAAW,CAAC,IAAI,EAAE,IAAI,CAAC,CAAC;IACxB,QAAQ,CAAC,IAAI,EAAE,IAAI,CAAC,CAAC;AACvB,CAAC","sourcesContent":["// `hydrate(value, root)` (view/07-hydration.md): the first client render of server-rendered DOM.\n// Kept apart from render.ts so the walk (adopt.ts) is bundled only where hydration is used: core\n// loads it lazily, with the first server-rendered host (07 \"Loading\").\nimport { adopt } from './adopt.js';\nimport { ChildPart } from './child-part.js';\nimport { dropHooks, hookMark, runHooks } from './hooks.js';\nimport { setRootPart } from './render.js';\nimport { listenFor, type SeenMarkup } from './seen.js';\nimport type { ChildValue } from './values.js';\n\n/**\n * Hydrates the server-rendered DOM in `root` with `value`, the first client render\n * (view/07-hydration.md): builds the parts over the existing nodes, runs element hooks' client\n * halves once, and leaves later `render` calls to update in place. Throws `HydrationMismatch`\n * when the DOM doesn't match; `host` names the component in its message; `seen` is as for\n * `render`.\n */\nexport function hydrate(\n value: ChildValue,\n root: Element | ShadowRoot,\n host = 'the root',\n seen?: SeenMarkup,\n): void {\n const part = new ChildPart(root, null, null, 0, false, 0);\n const mark = hookMark(root);\n const outer = listenFor(seen);\n try {\n adopt(part, value, root, host);\n } catch (error) {\n dropHooks(mark);\n throw error;\n } finally {\n listenFor(outer);\n }\n setRootPart(root, part);\n runHooks(mark, root);\n}\n"]}
|
|
@@ -0,0 +1,6 @@
|
|
|
1
|
+
import type { ChildValue, ListResult } from './values.js';
|
|
2
|
+
/**
|
|
3
|
+
* Renders `value`, and replaces it with a fresh copy whenever `key` changes: a form cleared
|
|
4
|
+
* after sending, a CSS animation restarted, a child component reset.
|
|
5
|
+
*/
|
|
6
|
+
export declare function keyed(key: string | number, value: ChildValue): ListResult;
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
// keyed(key, value): a child value that is recreated, DOM and nested component state included,
|
|
2
|
+
// whenever its key changes (view/03-lists.md "keyed"). It is a one-row each(), so it reuses the
|
|
3
|
+
// keyed list's reconciliation, server writer and hydration walk, and costs nothing in apps that
|
|
4
|
+
// don't call it.
|
|
5
|
+
import { each } from './list.js';
|
|
6
|
+
// One shared row function: each()'s development purity check is keyed by it.
|
|
7
|
+
const itself = (value) => value;
|
|
8
|
+
/**
|
|
9
|
+
* Renders `value`, and replaces it with a fresh copy whenever `key` changes: a form cleared
|
|
10
|
+
* after sending, a CSS animation restarted, a child component reset.
|
|
11
|
+
*/
|
|
12
|
+
export function keyed(key, value) {
|
|
13
|
+
return each([value], () => key, itself);
|
|
14
|
+
}
|
|
15
|
+
//# sourceMappingURL=keyed.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"keyed.js","sourceRoot":"","sources":["../../../src/view/render/keyed.ts"],"names":[],"mappings":"AAAA,+FAA+F;AAC/F,gGAAgG;AAChG,gGAAgG;AAChG,iBAAiB;AACjB,OAAO,EAAE,IAAI,EAAE,MAAM,WAAW,CAAC;AAGjC,6EAA6E;AAC7E,MAAM,MAAM,GAAG,CAAC,KAAiB,EAAc,EAAE,CAAC,KAAK,CAAC;AAExD;;;GAGG;AACH,MAAM,UAAU,KAAK,CAAC,GAAoB,EAAE,KAAiB;IAC3D,OAAO,IAAI,CAAC,CAAC,KAAK,CAAC,EAAE,GAAG,EAAE,CAAC,GAAG,EAAE,MAAM,CAAC,CAAC;AAC1C,CAAC","sourcesContent":["// keyed(key, value): a child value that is recreated, DOM and nested component state included,\n// whenever its key changes (view/03-lists.md \"keyed\"). It is a one-row each(), so it reuses the\n// keyed list's reconciliation, server writer and hydration walk, and costs nothing in apps that\n// don't call it.\nimport { each } from './list.js';\nimport type { ChildValue, ListResult } from './values.js';\n\n// One shared row function: each()'s development purity check is keyed by it.\nconst itself = (value: ChildValue): ChildValue => value;\n\n/**\n * Renders `value`, and replaces it with a fresh copy whenever `key` changes: a form cleared\n * after sending, a CSS animation restarted, a child component reset.\n */\nexport function keyed(key: string | number, value: ChildValue): ListResult {\n return each([value], () => key, itself);\n}\n"]}
|
|
@@ -10,7 +10,7 @@ export declare function clearList(part: ChildPart, list: List): void;
|
|
|
10
10
|
*/
|
|
11
11
|
export declare function createRows(part: ChildPart, list: List, l: ListResult, rows: ChildPart[], from: number, to: number, end: Node | null, keys?: readonly unknown[]): void;
|
|
12
12
|
/**
|
|
13
|
-
* A keyed list
|
|
13
|
+
* A keyed list. `key` must give each item a unique string or number; `row`
|
|
14
14
|
* must depend only on its arguments: a row re-renders only when its item object or its `pick`
|
|
15
15
|
* result changes.
|
|
16
16
|
*/
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"list.js","sourceRoot":"","sources":["../../../src/view/render/list.ts"],"names":[],"mappings":"AAAA,qFAAqF;AACrF,gGAAgG;AAChG,mFAAmF;AACnF,8FAA8F;AAC9F,sFAAsF;AACtF,8FAA8F;AAC9F,gGAAgG;AAChG,OAAO,EAAE,GAAG,EAAE,MAAM,WAAW,CAAC;AAChC,OAAO,EAAE,SAAS,EAAE,KAAK,EAAE,KAAK,EAAE,IAAI,EAAE,MAAM,iBAAiB,CAAC;AAChE,OAAO,EAAE,SAAS,EAAE,WAAW,EAAE,MAAM,gBAAgB,CAAC;AACxD,OAAO,EAAE,OAAO,EAAE,MAAM,cAAc,CAAC;AACvC,OAAO,EAAE,SAAS,EAAE,IAAI,EAAE,MAAM,EAAE,SAAS,EAAE,MAAM,WAAW,CAAC;AAC/D,OAAO,EAAE,IAAI,EAAoC,MAAM,aAAa,CAAC;AAErE,OAAO,EAAE,IAAI,EAAE,MAAM,WAAW,CAAC;AAEjC,SAAS,MAAM,CAAC,IAAe,EAAE,IAAY;IAC3C,IAAI,IAAI,CAAC,IAAI,KAAK,IAAI;QAAE,OAAO,IAAI,CAAC,OAAe,CAAC;IACpD,IAAI,IAAI,CAAC,IAAI,KAAK,KAAK;QAAE,IAAI,CAAC,KAAK,EAAE,CAAC;IACtC,MAAM,IAAI,GAAG,IAAI,IAAI,CAAC,IAAI,CAAC,CAAC;IAC5B,IAAI,CAAC,IAAI,GAAG,IAAI,CAAC;IACjB,IAAI,CAAC,OAAO,GAAG,IAAI,CAAC;IACpB,OAAO,IAAI,CAAC;AACd,CAAC;AAED,qEAAqE;AACrE,MAAM,UAAU,SAAS,CAAC,IAAe,EAAE,IAAU;IACnD,IAAI,IAAI,CAAC,IAAI,IAAI,IAAI,CAAC,UAAU,KAAK,IAAI;QAAG,IAAI,CAAC,UAAsB,CAAC,eAAe,EAAE,CAAC;;QACrF,KAAK,MAAM,GAAG,IAAI,IAAI,CAAC,IAAI;YAAE,GAAG,CAAC,KAAK,EAAE,CAAC;IAC9C,IAAI,CAAC,IAAI,GAAG,EAAE,CAAC;AACjB,CAAC;AAED;;;GAGG;AACH,MAAM,UAAU,UAAU,CACxB,IAAe,EACf,IAAU,EACV,CAAa,EACb,IAAiB,EACjB,IAAY,EACZ,EAAU,EACV,GAAgB,EAChB,IAAyB;IAEzB,MAAM,IAAI,GAAG,QAAQ,CAAC,sBAAsB,EAAE,CAAC;IAC/C,IAAI,CAAC,QAAQ,GAAG,IAAI,CAAC;IACrB,IAAI,CAAC;QACH,KAAK,IAAI,CAAC,GAAG,IAAI,EAAE,CAAC,IAAI,EAAE,EAAE,CAAC,EAAE,EAAE,CAAC;YAChC,MAAM,IAAI,GAAG,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC;YACxB,MAAM,GAAG,GAAG,IAAI,KAAK,SAAS,CAAC,CAAC,CAAC,CAAC,CAAC,GAAG,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,GAAG,IAAI,CAAC,CAAC;YAC9D,IAAI,CAAC,IAAI,CAAC,MAAM,CAAC,IAAI,EAAE,IAAI,EAAE,CAAC,EAAE,IAAI,EAAE,GAAG,EAAE,CAAC,CAAC,CAAC,CAAC;QACjD,CAAC;IACH,CAAC;YAAS,CAAC;QACT,IAAI,CAAC,QAAQ,GAAG,IAAI,CAAC;IACvB,CAAC;IACD,IAAI,CAAC,MAAM,EAAE,CAAC,YAAY,CAAC,IAAI,EAAE,GAAG,CAAC,CAAC;AACxC,CAAC;AAkBD,MAAM,UAAU,IAAI,CAClB,KAAmB,EACnB,GAAiC,EACjC,GAAuC,EACvC,IAAqB;IAErB,IAAI,GAAG,IAAI,OAAO,GAAG,KAAK,UAAU,EAAE,CAAC;QACrC,MAAM,IAAI,SAAS,CACjB,6DAA6D;YAC3D,mFAAmF,CACtF,CAAC;IACJ,CAAC;IACD,OAAO;QACL,CAAC,IAAI,CAAC,EAAE,UAAU;QAClB,KAAK;QACL,GAAG,EAAE,GAAiC;QACtC,GAAG,EAAE,GAAkD;QACvD,IAAI,EAAE,IAAgD;KACvD,CAAC;AACJ,CAAC;AAED,SAAS,UAAU,CAAC,IAAe,EAAE,CAAa;IAChD,MAAM,IAAI,GAAG,MAAM,CAAC,IAAI,EAAE,IAAI,CAAC,CAAC;IAChC,MAAM,CAAC,GAAG,CAAC,CAAC,KAAK,CAAC,MAAM,CAAC;IACzB,IAAI,GAAG;QAAE,SAAS,CAAC,CAAC,CAAC,KAAK,EAAE,CAAC,CAAC,GAAG,CAAC,CAAC;IACnC,IAAI,IAAI,CAAC,IAAI,CAAC,MAAM,KAAK,CAAC,EAAE,CAAC;QAC3B,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC;YACV,MAAM,IAAI,GAAgB,EAAE,CAAC;YAC7B,UAAU,CAAC,IAAI,EAAE,IAAI,EAAE,CAAC,EAAE,IAAI,EAAE,CAAC,EAAE,CAAC,GAAG,CAAC,EAAE,IAAI,CAAC,GAAG,EAAE,CAAC,CAAC;YACtD,IAAI,CAAC,IAAI,GAAG,IAAI,CAAC;QACnB,CAAC;IACH,CAAC;SAAM,IAAI,CAAC,KAAK,CAAC;QAAE,SAAS,CAAC,IAAI,EAAE,IAAI,CAAC,CAAC;;QACrC,SAAS,CAAC,IAAI,EAAE,IAAI,EAAE,CAAC,CAAC,CAAC;IAC9B,IAAI,GAAG;QAAE,WAAW,CAAC,IAAI,EAAE,CAAC,CAAC,CAAC;AAChC,CAAC;AAED,SAAS,SAAS,CAAC,IAAe,EAAE,IAAU,EAAE,CAAa;IAC3D,MAAM,EAAE,KAAK,EAAE,GAAG,EAAE,GAAG,CAAC,CAAC;IACzB,MAAM,GAAG,GAAG,IAAI,CAAC,IAAI,CAAC;IACtB,MAAM,CAAC,GAAG,KAAK,CAAC,MAAM,CAAC;IACvB,MAAM,EAAE,GAAG,GAAG,CAAC,MAAM,CAAC;IACtB,MAAM,CAAC,GAAG,CAAC,GAAG,EAAE,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,EAAE,CAAC;IAC1B,IAAI,CAAC,GAAG,CAAC,CAAC;IACV,OAAO,CAAC,GAAG,CAAC,EAAE,CAAC,EAAE,EAAE,CAAC;QAClB,MAAM,IAAI,GAAG,KAAK,CAAC,CAAC,CAAC,CAAC;QACtB,MAAM,GAAG,GAAG,GAAG,CAAC,CAAC,CAAc,CAAC;QAChC,IAAI,GAAG,CAAC,IAAI,CAAC,KAAK,GAAG,CAAC,GAAG;YAAE,MAAM;QACjC,SAAS,CAAC,GAAG,EAAE,IAAI,EAAE,CAAC,CAAC,CAAC;IAC1B,CAAC;IACD,IAAI,CAAC,KAAK,CAAC,IAAI,CAAC,KAAK,EAAE;QAAE,OAAO;IAChC,IAAI,EAAE,GAAG,EAAE,GAAG,CAAC,CAAC;IAChB,IAAI,EAAE,GAAG,CAAC,GAAG,CAAC,CAAC;IACf,OAAO,EAAE,IAAI,CAAC,IAAI,EAAE,IAAI,CAAC,IAAI,GAAG,CAAC,KAAK,CAAC,EAAE,CAAC,CAAC,KAAM,GAAG,CAAC,EAAE,CAAe,CAAC,GAAG,EAAE,CAAC;QAC3E,EAAE,EAAE,CAAC;QACL,EAAE,EAAE,CAAC;IACP,CAAC;IACD,MAAM,IAAI,GAAG,GAAG,CAAC,KAAK,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC;IAC7B,IAAI,CAAC,GAAG,EAAE;QAAE,UAAU,CAAC,IAAI,EAAE,IAAI,EAAE,CAAC,EAAE,IAAI,EAAE,CAAC,EAAE,EAAE,EAAE,SAAS,CAAC,GAAG,EAAE,EAAE,GAAG,CAAC,EAAE,IAAI,CAAC,CAAC,CAAC;SAC5E,IAAI,CAAC,GAAG,EAAE;QAAE,KAAK,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,IAAI,EAAE,EAAE,CAAC,EAAE;YAAG,GAAG,CAAC,CAAC,CAAe,CAAC,KAAK,EAAE,CAAC;;QACxE,OAAO,CAAC,IAAI,EAAE,IAAI,EAAE,CAAC,EAAE,IAAI,EAAE,CAAC,EAAE,EAAE,EAAE,EAAE,CAAC,CAAC;IAC7C,KAAK,IAAI,CAAC,GAAG,EAAE,GAAG,CAAC,EAAE,CAAC,GAAG,EAAE,EAAE,CAAC,EAAE;QAAE,IAAI,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC,CAAc,CAAC,CAAC;IACjE,IAAI,CAAC,IAAI,GAAG,IAAI,CAAC;IACjB,KAAK,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,CAAC,EAAE,CAAC,EAAE;QAAG,IAAI,CAAC,CAAC,CAAe,CAAC,KAAK,GAAG,CAAC,CAAC;IAC7D,KAAK,IAAI,CAAC,GAAG,EAAE,GAAG,CAAC,EAAE,CAAC,GAAG,CAAC,EAAE,CAAC,EAAE;QAAE,SAAS,CAAC,IAAI,CAAC,CAAC,CAAc,EAAE,KAAK,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC;AAChF,CAAC;AAED,sFAAsF;AACtF,MAAM,UAAU,WAAW,CAAC,IAAe,EAAE,MAA0B;IACrE,MAAM,IAAI,GAAG,MAAM,CAAC,IAAI,EAAE,KAAK,CAAC,CAAC;IACjC,MAAM,IAAI,GAAG,IAAI,CAAC,IAAI,CAAC;IACvB,MAAM,CAAC,GAAG,MAAM,CAAC,MAAM,CAAC;IACxB,IAAI,CAAC,KAAK,CAAC,EAAE,CAAC;QACZ,IAAI,IAAI,CAAC,MAAM,GAAG,CAAC;YAAE,SAAS,CAAC,IAAI,EAAE,IAAI,CAAC,CAAC;QAC3C,OAAO;IACT,CAAC;IACD,MAAM,MAAM,GAAG,CAAC,GAAG,IAAI,CAAC,MAAM,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC,MAAM,CAAC;IACjD,KAAK,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,MAAM,EAAE,CAAC,EAAE;QAAG,IAAI,CAAC,CAAC,CAAe,CAAC,MAAM,CAAC,MAAM,CAAC,CAAC,CAAC,CAAC,CAAC;IAC1E,IAAI,CAAC,GAAG,IAAI,CAAC,MAAM,EAAE,CAAC;QACpB,MAAM,GAAG,GAAG,IAAI,CAAC,GAAG,EAAE,CAAC;QACvB,MAAM,IAAI,GAAG,QAAQ,CAAC,sBAAsB,EAAE,CAAC;QAC/C,IAAI,CAAC,QAAQ,GAAG,IAAI,CAAC;QACrB,IAAI,CAAC;YACH,KAAK,IAAI,CAAC,GAAG,IAAI,CAAC,MAAM,EAAE,CAAC,GAAG,CAAC,EAAE,CAAC,EAAE,EAAE,CAAC;gBACrC,MAAM,GAAG,GAAG,IAAI,SAAS,CAAC,IAAI,EAAE,IAAI,EAAE,IAAI,EAAE,CAAC,EAAE,KAAK,EAAE,CAAC,CAAC,CAAC,CAAC;gBAC1D,IAAI,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC;gBACf,GAAG,CAAC,MAAM,CAAC,MAAM,CAAC,CAAC,CAAC,CAAC,CAAC;YACxB,CAAC;QACH,CAAC;gBAAS,CAAC;YACT,IAAI,CAAC,QAAQ,GAAG,IAAI,CAAC;QACvB,CAAC;QACD,IAAI,CAAC,MAAM,EAAE,CAAC,YAAY,CAAC,IAAI,EAAE,GAAG,CAAC,CAAC;IACxC,CAAC;;QAAM,OAAO,IAAI,CAAC,MAAM,GAAG,CAAC;YAAG,IAAI,CAAC,GAAG,EAAgB,CAAC,KAAK,EAAE,CAAC;AACnE,CAAC","sourcesContent":["// Lists in child holes: `each` (view/03-lists.md \"Reconciliation\", \"Fast paths\") and\n// positional arrays (view/02-bindings.md \"Child values\"). Rows are child parts tracked by their\n// node range, with no markers. Fast paths: create into empty (one fragment), clear\n// (replaceChildren when the list is its parent's only content), the common prefix and suffix,\n// insert-only (append, prepend, insert) and remove-only. What remains is reordered by\n// reorder.ts. Rows commit in document order. `each` is here: its result carries `commitList`,\n// so the keyed path (this, rows.ts, reorder.ts, place.ts) is bundled only by apps that call it.\nimport { DEV } from '#view-dev';\nimport { ChildPart, EMPTY, ITEMS, LIST } from './child-part.js';\nimport { checkKeys, recheckRows } from './dev-check.js';\nimport { reorder } from './reorder.js';\nimport { firstFrom, List, newRow, updateRow } from './rows.js';\nimport { EACH, type ChildValue, type ListResult } from './values.js';\n\nexport { List } from './rows.js';\n\nfunction listOf(part: ChildPart, kind: number): List {\n if (part.kind === kind) return part.content as List;\n if (part.kind !== EMPTY) part.clear();\n const list = new List(part);\n part.kind = kind;\n part.content = list;\n return list;\n}\n\n/** Removes every row; the list's part keeps its (now empty) list. */\nexport function clearList(part: ChildPart, list: List): void {\n if (part.sole && part.parentNode !== null) (part.parentNode as Element).replaceChildren();\n else for (const row of list.rows) row.clear();\n list.rows = [];\n}\n\n/**\n * Creates rows for `l.items[from…to]` (keys from `keys[i - from]` when given) into one\n * fragment, pushes them onto `rows` and inserts the fragment before `end`.\n */\nexport function createRows(\n part: ChildPart,\n list: List,\n l: ListResult,\n rows: ChildPart[],\n from: number,\n to: number,\n end: Node | null,\n keys?: readonly unknown[],\n): void {\n const frag = document.createDocumentFragment();\n list.building = frag;\n try {\n for (let i = from; i <= to; i++) {\n const item = l.items[i];\n const key = keys === undefined ? l.key(item) : keys[i - from];\n rows.push(newRow(list, null, l, item, key, i));\n }\n } finally {\n list.building = null;\n }\n part.parent().insertBefore(frag, end);\n}\n\n/**\n * A keyed list (view/03-lists.md). `key` must give each item a unique string or number; `row`\n * must depend only on its arguments: a row re-renders only when its item object or its `pick`\n * result changes.\n */\nexport function each<T>(\n items: readonly T[],\n key: (item: T) => string | number,\n row: (item: T) => ChildValue,\n): ListResult;\nexport function each<T, P>(\n items: readonly T[],\n key: (item: T) => string | number,\n row: (item: T, picked: P) => ChildValue,\n pick: (item: T) => P,\n): ListResult;\nexport function each<T, P>(\n items: readonly T[],\n key: (item: T) => string | number,\n row: (item: T, picked: P) => ChildValue,\n pick?: (item: T) => P,\n): ListResult {\n if (DEV && typeof key !== 'function') {\n throw new TypeError(\n 'gyral: each() needs a key function as its second argument: ' +\n 'each(items, (x) => x.id, Row) (docs/design-docs/view/03-lists.md \"Keys\", rule 9).',\n );\n }\n return {\n [EACH]: commitList,\n items,\n key: key as (item: unknown) => unknown,\n row: row as (item: unknown, picked: unknown) => unknown,\n pick: pick as ((item: unknown) => unknown) | undefined,\n };\n}\n\nfunction commitList(part: ChildPart, l: ListResult): void {\n const list = listOf(part, LIST);\n const n = l.items.length;\n if (DEV) checkKeys(l.items, l.key);\n if (list.rows.length === 0) {\n if (n > 0) {\n const rows: ChildPart[] = [];\n createRows(part, list, l, rows, 0, n - 1, part.end());\n list.rows = rows;\n }\n } else if (n === 0) clearList(part, list);\n else reconcile(part, list, l);\n if (DEV) recheckRows(list, l);\n}\n\nfunction reconcile(part: ChildPart, list: List, l: ListResult): void {\n const { items, key } = l;\n const old = list.rows;\n const n = items.length;\n const on = old.length;\n const m = n < on ? n : on;\n let s = 0;\n for (; s < m; s++) {\n const item = items[s];\n const row = old[s] as ChildPart;\n if (key(item) !== row.key) break;\n updateRow(row, item, l);\n }\n if (s === n && s === on) return;\n let oe = on - 1;\n let ne = n - 1;\n while (oe >= s && ne >= s && key(items[ne]) === (old[oe] as ChildPart).key) {\n oe--;\n ne--;\n }\n const rows = old.slice(0, s);\n if (s > oe) createRows(part, list, l, rows, s, ne, firstFrom(old, oe + 1, part));\n else if (s > ne) for (let j = s; j <= oe; j++) (old[j] as ChildPart).clear();\n else reorder(part, list, l, rows, s, oe, ne);\n for (let j = oe + 1; j < on; j++) rows.push(old[j] as ChildPart);\n list.rows = rows;\n for (let i = s; i < n; i++) (rows[i] as ChildPart).index = i;\n for (let i = ne + 1; i < n; i++) updateRow(rows[i] as ChildPart, items[i], l);\n}\n\n/** A positional array: items reused by index (view/02-bindings.md \"Child values\"). */\nexport function commitItems(part: ChildPart, values: readonly unknown[]): void {\n const list = listOf(part, ITEMS);\n const rows = list.rows;\n const n = values.length;\n if (n === 0) {\n if (rows.length > 0) clearList(part, list);\n return;\n }\n const common = n < rows.length ? n : rows.length;\n for (let i = 0; i < common; i++) (rows[i] as ChildPart).commit(values[i]);\n if (n > rows.length) {\n const end = part.end();\n const frag = document.createDocumentFragment();\n list.building = frag;\n try {\n for (let i = rows.length; i < n; i++) {\n const row = new ChildPart(null, null, list, i, false, -1);\n rows.push(row);\n row.commit(values[i]);\n }\n } finally {\n list.building = null;\n }\n part.parent().insertBefore(frag, end);\n } else while (rows.length > n) (rows.pop() as ChildPart).clear();\n}\n"]}
|
|
1
|
+
{"version":3,"file":"list.js","sourceRoot":"","sources":["../../../src/view/render/list.ts"],"names":[],"mappings":"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","sourcesContent":["// Lists in child holes: `each` (view/03-lists.md \"Reconciliation\", \"Fast paths\") and\n// positional arrays (view/02-bindings.md \"Child values\"). Rows are child parts tracked by their\n// node range, with no markers. Fast paths: create into empty (one fragment), clear\n// (replaceChildren when the list is its parent's only content), the common prefix and suffix,\n// insert-only (append, prepend, insert) and remove-only. What remains is reordered by\n// reorder.ts. Rows commit in document order. `each` is here: its result carries `commitList`,\n// so the keyed path (this, rows.ts, reorder.ts, place.ts) is bundled only by apps that call it.\nimport { DEV } from '#view-dev';\nimport { ChildPart, EMPTY, ITEMS, LIST } from './child-part.js';\nimport { checkKeys, recheckRows } from './dev-check.js';\nimport { reorder } from './reorder.js';\nimport { firstFrom, List, newRow, updateRow } from './rows.js';\nimport { EACH, type ChildValue, type ListResult } from './values.js';\n\nexport { List } from './rows.js';\n\nfunction listOf(part: ChildPart, kind: number): List {\n if (part.kind === kind) return part.content as List;\n if (part.kind !== EMPTY) part.clear();\n const list = new List(part);\n part.kind = kind;\n part.content = list;\n return list;\n}\n\n/** Removes every row; the list's part keeps its (now empty) list. */\nexport function clearList(part: ChildPart, list: List): void {\n if (part.sole && part.parentNode !== null) (part.parentNode as Element).replaceChildren();\n else for (const row of list.rows) row.clear();\n list.rows = [];\n}\n\n/**\n * Creates rows for `l.items[from…to]` (keys from `keys[i - from]` when given) into one\n * fragment, pushes them onto `rows` and inserts the fragment before `end`.\n */\nexport function createRows(\n part: ChildPart,\n list: List,\n l: ListResult,\n rows: ChildPart[],\n from: number,\n to: number,\n end: Node | null,\n keys?: readonly unknown[],\n): void {\n const frag = document.createDocumentFragment();\n list.building = frag;\n try {\n for (let i = from; i <= to; i++) {\n const item = l.items[i];\n const key = keys === undefined ? l.key(item) : keys[i - from];\n rows.push(newRow(list, null, l, item, key, i));\n }\n } finally {\n list.building = null;\n }\n part.parent().insertBefore(frag, end);\n}\n\n/**\n * A keyed list. `key` must give each item a unique string or number; `row`\n * must depend only on its arguments: a row re-renders only when its item object or its `pick`\n * result changes.\n */\nexport function each<T>(\n items: readonly T[],\n key: (item: T) => string | number,\n row: (item: T) => ChildValue,\n): ListResult;\nexport function each<T, P>(\n items: readonly T[],\n key: (item: T) => string | number,\n row: (item: T, picked: P) => ChildValue,\n pick: (item: T) => P,\n): ListResult;\nexport function each<T, P>(\n items: readonly T[],\n key: (item: T) => string | number,\n row: (item: T, picked: P) => ChildValue,\n pick?: (item: T) => P,\n): ListResult {\n if (DEV && typeof key !== 'function') {\n throw new TypeError(\n 'gyral: each() needs a key function as its second argument: ' +\n 'each(items, (x) => x.id, Row) (docs/design-docs/view/03-lists.md \"Keys\", rule 9).',\n );\n }\n return {\n [EACH]: commitList,\n items,\n key: key as (item: unknown) => unknown,\n row: row as (item: unknown, picked: unknown) => unknown,\n pick: pick as ((item: unknown) => unknown) | undefined,\n };\n}\n\nfunction commitList(part: ChildPart, l: ListResult): void {\n const list = listOf(part, LIST);\n const n = l.items.length;\n if (DEV) checkKeys(l.items, l.key);\n if (list.rows.length === 0) {\n if (n > 0) {\n const rows: ChildPart[] = [];\n createRows(part, list, l, rows, 0, n - 1, part.end());\n list.rows = rows;\n }\n } else if (n === 0) clearList(part, list);\n else reconcile(part, list, l);\n if (DEV) recheckRows(list, l);\n}\n\nfunction reconcile(part: ChildPart, list: List, l: ListResult): void {\n const { items, key } = l;\n const old = list.rows;\n const n = items.length;\n const on = old.length;\n const m = n < on ? n : on;\n let s = 0;\n for (; s < m; s++) {\n const item = items[s];\n const row = old[s] as ChildPart;\n if (key(item) !== row.key) break;\n updateRow(row, item, l);\n }\n if (s === n && s === on) return;\n let oe = on - 1;\n let ne = n - 1;\n while (oe >= s && ne >= s && key(items[ne]) === (old[oe] as ChildPart).key) {\n oe--;\n ne--;\n }\n const rows = old.slice(0, s);\n if (s > oe) createRows(part, list, l, rows, s, ne, firstFrom(old, oe + 1, part));\n else if (s > ne) for (let j = s; j <= oe; j++) (old[j] as ChildPart).clear();\n else reorder(part, list, l, rows, s, oe, ne);\n for (let j = oe + 1; j < on; j++) rows.push(old[j] as ChildPart);\n list.rows = rows;\n for (let i = s; i < n; i++) (rows[i] as ChildPart).index = i;\n for (let i = ne + 1; i < n; i++) updateRow(rows[i] as ChildPart, items[i], l);\n}\n\n/** A positional array: items reused by index (view/02-bindings.md \"Child values\"). */\nexport function commitItems(part: ChildPart, values: readonly unknown[]): void {\n const list = listOf(part, ITEMS);\n const rows = list.rows;\n const n = values.length;\n if (n === 0) {\n if (rows.length > 0) clearList(part, list);\n return;\n }\n const common = n < rows.length ? n : rows.length;\n for (let i = 0; i < common; i++) (rows[i] as ChildPart).commit(values[i]);\n if (n > rows.length) {\n const end = part.end();\n const frag = document.createDocumentFragment();\n list.building = frag;\n try {\n for (let i = rows.length; i < n; i++) {\n const row = new ChildPart(null, null, list, i, false, -1);\n rows.push(row);\n row.commit(values[i]);\n }\n } finally {\n list.building = null;\n }\n part.parent().insertBefore(frag, end);\n } else while (rows.length > n) (rows.pop() as ChildPart).clear();\n}\n"]}
|
|
@@ -3,6 +3,7 @@
|
|
|
3
3
|
// (development builds know it), the path from the root to the node, and what was expected
|
|
4
4
|
// and found. Development throws it; production recovers the one component (core's caller).
|
|
5
5
|
import { DEV } from '#view-dev';
|
|
6
|
+
import { docsLink } from '../message.js';
|
|
6
7
|
/** The server's DOM doesn't match the component's first client render. */
|
|
7
8
|
export class HydrationMismatch extends Error {
|
|
8
9
|
constructor(message) {
|
|
@@ -41,13 +42,14 @@ export function mismatch(expected, found, at, root, host, loc) {
|
|
|
41
42
|
: typeof found === 'string'
|
|
42
43
|
? found
|
|
43
44
|
: describe(found);
|
|
45
|
+
// G0062 (messages.ts), whose explanation only development carries.
|
|
44
46
|
throw new HydrationMismatch(`gyral: hydration mismatch in ${host}${loc === undefined ? '' : ` (template at ${loc})`} ` +
|
|
45
|
-
`at ${pathOf(where, root)}: expected ${expected}, found ${what}
|
|
47
|
+
`at ${pathOf(where, root)}: expected ${expected}, found ${what}. ` +
|
|
46
48
|
(DEV
|
|
47
|
-
? "
|
|
49
|
+
? "The server's HTML differs from the first client render: a view that isn't " +
|
|
48
50
|
'deterministic (Date.now(), locale), a third party that changed the DOM before ' +
|
|
49
51
|
'scripts ran, or a stale cached page (docs/design-docs/view/07-hydration.md ' +
|
|
50
52
|
'"Mismatches").'
|
|
51
|
-
:
|
|
53
|
+
: docsLink(62)));
|
|
52
54
|
}
|
|
53
55
|
//# sourceMappingURL=mismatch.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"mismatch.js","sourceRoot":"","sources":["../../../src/view/render/mismatch.ts"],"names":[],"mappings":"AAAA,6FAA6F;AAC7F,2FAA2F;AAC3F,0FAA0F;AAC1F,2FAA2F;AAC3F,OAAO,EAAE,GAAG,EAAE,MAAM,WAAW,CAAC;
|
|
1
|
+
{"version":3,"file":"mismatch.js","sourceRoot":"","sources":["../../../src/view/render/mismatch.ts"],"names":[],"mappings":"AAAA,6FAA6F;AAC7F,2FAA2F;AAC3F,0FAA0F;AAC1F,2FAA2F;AAC3F,OAAO,EAAE,GAAG,EAAE,MAAM,WAAW,CAAC;AAChC,OAAO,EAAE,QAAQ,EAAE,MAAM,eAAe,CAAC;AAEzC,0EAA0E;AAC1E,MAAM,OAAO,iBAAkB,SAAQ,KAAK;IAC1C,YAAY,OAAe;QACzB,KAAK,CAAC,OAAO,CAAC,CAAC;QACf,IAAI,CAAC,IAAI,GAAG,mBAAmB,CAAC;IAClC,CAAC;CACF;AAED,yCAAyC;AACzC,SAAS,QAAQ,CAAC,IAAU;IAC1B,IAAI,IAAI,CAAC,QAAQ,KAAK,CAAC;QAAE,OAAO,QAAQ,IAAI,CAAC,SAAS,CAAE,IAAa,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,EAAE,CAAC;IAC3F,IAAI,IAAI,CAAC,QAAQ,KAAK,CAAC;QAAE,OAAO,OAAQ,IAAgB,CAAC,IAAI,KAAK,CAAC;IACnE,OAAO,IAAI,CAAC,QAAQ,KAAK,CAAC,CAAC,CAAC,CAAC,IAAK,IAAgB,CAAC,SAAS,GAAG,CAAC,CAAC,CAAC,UAAU,CAAC;AAC/E,CAAC;AAED,0FAA0F;AAC1F,SAAS,MAAM,CAAC,IAAU,EAAE,IAAU;IACpC,MAAM,KAAK,GAAa,EAAE,CAAC;IAC3B,KAAK,IAAI,CAAC,GAAgB,IAAI,EAAE,CAAC,KAAK,IAAI,IAAI,CAAC,KAAK,IAAI,EAAE,CAAC,GAAG,CAAC,CAAC,UAAU,EAAE,CAAC;QAC3E,IAAI,KAAK,GAAG,CAAC,CAAC;QACd,KAAK,IAAI,CAAC,GAAG,CAAC,CAAC,eAAe,EAAE,CAAC,KAAK,IAAI,EAAE,CAAC,GAAG,CAAC,CAAC,eAAe;YAAE,KAAK,EAAE,CAAC;QAC3E,KAAK,CAAC,OAAO,CAAC,GAAG,CAAC,CAAC,QAAQ,KAAK,CAAC,CAAC,CAAC,CAAE,CAAa,CAAC,SAAS,CAAC,CAAC,CAAC,CAAC,CAAC,QAAQ,IAAI,MAAM,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC;IACjG,CAAC;IACD,OAAO,KAAK,CAAC,MAAM,KAAK,CAAC,CAAC,CAAC,CAAC,UAAU,CAAC,CAAC,CAAC,KAAK,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC;AAC7D,CAAC;AAED;;;;GAIG;AACH,MAAM,UAAU,QAAQ,CACtB,QAAgB,EAChB,KAA2B,EAC3B,EAAQ,EACR,IAAU,EACV,IAAY,EACZ,GAAuB;IAEvB,MAAM,KAAK,GAAG,OAAO,KAAK,KAAK,QAAQ,IAAI,KAAK,KAAK,IAAI,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,EAAE,CAAC;IACvE,MAAM,IAAI,GACR,KAAK,KAAK,IAAI;QACZ,CAAC,CAAC,cAAc,QAAQ,CAAC,EAAE,CAAC,EAAE;QAC9B,CAAC,CAAC,OAAO,KAAK,KAAK,QAAQ;YACzB,CAAC,CAAC,KAAK;YACP,CAAC,CAAC,QAAQ,CAAC,KAAK,CAAC,CAAC;IACxB,mEAAmE;IACnE,MAAM,IAAI,iBAAiB,CACzB,gCAAgC,IAAI,GAAG,GAAG,KAAK,SAAS,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,iBAAiB,GAAG,GAAG,GAAG;QACxF,MAAM,MAAM,CAAC,KAAK,EAAE,IAAI,CAAC,cAAc,QAAQ,WAAW,IAAI,IAAI;QAClE,CAAC,GAAG;YACF,CAAC,CAAC,4EAA4E;gBAC5E,gFAAgF;gBAChF,6EAA6E;gBAC7E,gBAAgB;YAClB,CAAC,CAAC,QAAQ,CAAC,EAAE,CAAC,CAAC,CACpB,CAAC;AACJ,CAAC","sourcesContent":["// Hydration mismatches (view/07-hydration.md \"Mismatches\"): the server DOM differs from what\n// the first client render needs. The message names the component, the template's call site\n// (development builds know it), the path from the root to the node, and what was expected\n// and found. Development throws it; production recovers the one component (core's caller).\nimport { DEV } from '#view-dev';\nimport { docsLink } from '../message.js';\n\n/** The server's DOM doesn't match the component's first client render. */\nexport class HydrationMismatch extends Error {\n constructor(message: string) {\n super(message);\n this.name = 'HydrationMismatch';\n }\n}\n\n/** A short description of a DOM node. */\nfunction describe(node: Node): string {\n if (node.nodeType === 3) return `text ${JSON.stringify((node as Text).data.slice(0, 40))}`;\n if (node.nodeType === 8) return `<!--${(node as Comment).data}-->`;\n return node.nodeType === 1 ? `<${(node as Element).localName}>` : 'the root';\n}\n\n/** `div[0] › ul[2] › li[1]`: local names and child indexes from `root` down to `node`. */\nfunction pathOf(node: Node, root: Node): string {\n const steps: string[] = [];\n for (let n: Node | null = node; n !== null && n !== root; n = n.parentNode) {\n let index = 0;\n for (let s = n.previousSibling; s !== null; s = s.previousSibling) index++;\n steps.unshift(`${n.nodeType === 1 ? (n as Element).localName : n.nodeName}[${String(index)}]`);\n }\n return steps.length === 0 ? 'the root' : steps.join(' › ');\n}\n\n/**\n * Throws a mismatch. `expected` describes what the walk needed; `found` is the DOM node there,\n * a description, or null when `at` (the parent) had no more children. `host` names the\n * component and `loc` the template's call site.\n */\nexport function mismatch(\n expected: string,\n found: Node | string | null,\n at: Node,\n root: Node,\n host: string,\n loc: string | undefined,\n): never {\n const where = typeof found === 'object' && found !== null ? found : at;\n const what =\n found === null\n ? `the end of ${describe(at)}`\n : typeof found === 'string'\n ? found\n : describe(found);\n // G0062 (messages.ts), whose explanation only development carries.\n throw new HydrationMismatch(\n `gyral: hydration mismatch in ${host}${loc === undefined ? '' : ` (template at ${loc})`} ` +\n `at ${pathOf(where, root)}: expected ${expected}, found ${what}. ` +\n (DEV\n ? \"The server's HTML differs from the first client render: a view that isn't \" +\n 'deterministic (Date.now(), locale), a third party that changed the DOM before ' +\n 'scripts ran, or a stale cached page (docs/design-docs/view/07-hydration.md ' +\n '\"Mismatches\").'\n : docsLink(62)),\n );\n}\n"]}
|