@microsoft/fast-element 2.10.3 → 3.0.0-rc.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/ARCHITECTURE_HTML_TAGGED_TEMPLATE_LITERAL.md +1 -1
- package/ARCHITECTURE_OVERVIEW.md +2 -2
- package/CHANGELOG.json +31 -1
- package/CHANGELOG.md +10 -2
- package/DECLARATIVE_DESIGN.md +806 -0
- package/DECLARATIVE_HTML.md +470 -0
- package/DECLARATIVE_MIGRATION.md +215 -0
- package/DECLARATIVE_RENDERING.md +530 -0
- package/DECLARATIVE_RENDERING_LIFECYCLE.md +288 -0
- package/DECLARATIVE_SCHEMA_OBSERVER_MAP.md +489 -0
- package/DESIGN.md +143 -34
- package/MIGRATION.md +387 -0
- package/README.md +208 -1
- package/SIZES.md +25 -0
- package/api-extractor.arrays.json +15 -0
- package/api-extractor.context.json +1 -0
- package/api-extractor.declarative.json +15 -0
- package/api-extractor.di.json +1 -0
- package/api-extractor.hydration.json +15 -0
- package/api-extractor.styles.json +15 -0
- package/dist/arrays/arrays.api.json +2621 -0
- package/dist/context/context.api.json +1 -1
- package/dist/declarative/declarative.api.json +7844 -0
- package/dist/di/di.api.json +2 -2
- package/dist/dts/array-observer.d.ts +2 -0
- package/dist/dts/arrays.d.ts +2 -0
- package/dist/dts/attr.d.ts +1 -0
- package/dist/dts/binding/signal.d.ts +6 -6
- package/dist/dts/binding/two-way.d.ts +1 -0
- package/dist/dts/binding.d.ts +7 -0
- package/dist/dts/components/attributes.d.ts +2 -5
- package/dist/dts/components/definition-schema-transforms.d.ts +9 -0
- package/dist/dts/components/element-controller.d.ts +80 -114
- package/dist/dts/components/element-hydration.d.ts +1 -1
- package/dist/dts/components/enable-hydration.d.ts +34 -0
- package/dist/dts/components/fast-definitions.d.ts +91 -42
- package/dist/dts/components/fast-element.d.ts +5 -8
- package/dist/dts/components/hydration-tracker.d.ts +40 -0
- package/dist/dts/components/hydration.d.ts +18 -53
- package/dist/dts/components/schema.d.ts +205 -0
- package/dist/dts/context.d.ts +6 -6
- package/dist/dts/css.d.ts +3 -0
- package/dist/dts/debug.d.ts +5 -1
- package/dist/dts/declarative/attribute-map.d.ts +58 -0
- package/dist/dts/declarative/debug.d.ts +5 -0
- package/dist/dts/declarative/index.d.ts +13 -0
- package/dist/dts/declarative/interfaces.d.ts +9 -0
- package/dist/dts/declarative/observer-map-utilities.d.ts +58 -0
- package/dist/dts/declarative/observer-map.d.ts +89 -0
- package/dist/dts/declarative/runtime.d.ts +5 -0
- package/dist/dts/declarative/syntax.d.ts +21 -0
- package/dist/dts/declarative/template-bridge.d.ts +33 -0
- package/dist/dts/declarative/template-parser.d.ts +98 -0
- package/dist/dts/declarative/template.d.ts +9 -0
- package/dist/dts/declarative/utilities.d.ts +312 -0
- package/dist/dts/di/di.d.ts +1 -1
- package/dist/dts/directives/children.d.ts +2 -0
- package/dist/dts/directives/node-observation.d.ts +2 -0
- package/dist/dts/directives/ref.d.ts +2 -0
- package/dist/dts/directives/repeat.d.ts +4 -0
- package/dist/dts/directives/slotted.d.ts +2 -0
- package/dist/dts/directives/when.d.ts +3 -0
- package/dist/dts/dom-policy.d.ts +1 -1
- package/dist/dts/html.d.ts +5 -0
- package/dist/dts/hydration/runtime.d.ts +7 -0
- package/dist/dts/hydration/target-builder.d.ts +15 -12
- package/dist/dts/hydration.d.ts +14 -0
- package/dist/dts/index.d.ts +38 -42
- package/dist/dts/index.debug.d.ts +0 -1
- package/dist/dts/index.rollup.debug.d.ts +0 -1
- package/dist/dts/interfaces.d.ts +1 -49
- package/dist/dts/observable.d.ts +3 -6
- package/dist/dts/observation/arrays.d.ts +1 -1
- package/dist/dts/observation/update-queue.d.ts +1 -1
- package/dist/dts/platform.d.ts +25 -4
- package/dist/dts/render.d.ts +7 -0
- package/dist/dts/schema.d.ts +1 -0
- package/dist/dts/state/exports.d.ts +1 -1
- package/dist/dts/state/state.d.ts +2 -2
- package/dist/dts/styles/css-directive.d.ts +5 -12
- package/dist/dts/styles/css.d.ts +5 -7
- package/dist/dts/styles/element-styles.d.ts +0 -10
- package/dist/dts/styles.d.ts +6 -0
- package/dist/dts/templating/children.d.ts +1 -1
- package/dist/dts/templating/html-binding-directive.d.ts +10 -0
- package/dist/dts/templating/html-directive.d.ts +17 -0
- package/dist/dts/templating/hydration-view.d.ts +109 -0
- package/dist/dts/templating/ref.d.ts +1 -1
- package/dist/dts/templating/render.d.ts +8 -2
- package/dist/dts/templating/repeat.d.ts +2 -2
- package/dist/dts/templating/slotted.d.ts +1 -1
- package/dist/dts/templating/template.d.ts +17 -9
- package/dist/dts/templating/view.d.ts +25 -102
- package/dist/dts/templating/when.d.ts +1 -1
- package/dist/dts/templating.d.ts +10 -0
- package/dist/dts/testing/exports.d.ts +2 -2
- package/dist/dts/tsdoc-metadata.json +1 -1
- package/dist/dts/updates.d.ts +1 -0
- package/dist/dts/volatile.d.ts +2 -0
- package/dist/esm/array-observer.js +1 -0
- package/dist/esm/arrays.js +1 -0
- package/dist/esm/attr.js +1 -0
- package/dist/esm/binding/normalize.js +1 -1
- package/dist/esm/binding/signal.js +4 -4
- package/dist/esm/binding/two-way.js +2 -1
- package/dist/esm/binding.js +4 -0
- package/dist/esm/components/attributes.js +8 -5
- package/dist/esm/components/definition-schema-transforms.js +23 -0
- package/dist/esm/components/element-controller.js +200 -269
- package/dist/esm/components/element-hydration.js +1 -1
- package/dist/esm/components/enable-hydration.js +100 -0
- package/dist/esm/components/fast-definitions.js +211 -49
- package/dist/esm/components/fast-element.js +18 -27
- package/dist/esm/components/hydration-tracker.js +93 -0
- package/dist/esm/components/hydration.js +62 -144
- package/dist/esm/components/schema.js +253 -0
- package/dist/esm/context.js +6 -6
- package/dist/esm/css.js +3 -0
- package/dist/esm/debug.js +26 -26
- package/dist/esm/declarative/attribute-map.js +121 -0
- package/dist/esm/declarative/debug.js +5 -0
- package/dist/esm/declarative/index.js +3 -0
- package/dist/esm/declarative/interfaces.js +10 -0
- package/dist/esm/declarative/observer-map-utilities.js +562 -0
- package/dist/esm/declarative/observer-map.js +216 -0
- package/dist/esm/declarative/runtime.js +14 -0
- package/dist/esm/declarative/syntax.js +36 -0
- package/dist/esm/declarative/template-bridge.js +170 -0
- package/dist/esm/declarative/template-parser.js +306 -0
- package/dist/esm/declarative/template.js +142 -0
- package/dist/esm/declarative/utilities.js +834 -0
- package/dist/esm/di/di.js +6 -8
- package/dist/esm/directives/children.js +1 -0
- package/dist/esm/directives/node-observation.js +1 -0
- package/dist/esm/directives/ref.js +1 -0
- package/dist/esm/directives/repeat.js +1 -0
- package/dist/esm/directives/slotted.js +1 -0
- package/dist/esm/directives/when.js +1 -0
- package/dist/esm/dom-policy.js +2 -2
- package/dist/esm/dom.js +1 -1
- package/dist/esm/html.js +2 -0
- package/dist/esm/hydration/runtime.js +33 -0
- package/dist/esm/hydration/target-builder.js +97 -90
- package/dist/esm/hydration.js +4 -0
- package/dist/esm/index.debug.js +2 -1
- package/dist/esm/index.js +34 -29
- package/dist/esm/index.rollup.debug.js +3 -2
- package/dist/esm/index.rollup.js +1 -1
- package/dist/esm/interfaces.js +1 -45
- package/dist/esm/observable.js +1 -4
- package/dist/esm/observation/arrays.js +1 -1
- package/dist/esm/observation/observable.js +5 -5
- package/dist/esm/observation/update-queue.js +47 -58
- package/dist/esm/platform.js +31 -30
- package/dist/esm/render.js +1 -0
- package/dist/esm/schema.js +1 -0
- package/dist/esm/state/exports.js +1 -1
- package/dist/esm/styles/css-directive.js +1 -2
- package/dist/esm/styles/css.js +15 -56
- package/dist/esm/styles/element-styles.js +69 -15
- package/dist/esm/styles.js +2 -0
- package/dist/esm/templating/html-binding-directive.js +24 -10
- package/dist/esm/templating/hydration-view.js +235 -0
- package/dist/esm/templating/render.js +13 -2
- package/dist/esm/templating/repeat.js +36 -34
- package/dist/esm/templating/template.js +7 -7
- package/dist/esm/templating/view.js +24 -233
- package/dist/esm/templating.js +7 -0
- package/dist/esm/testing/exports.js +2 -2
- package/dist/esm/updates.js +1 -0
- package/dist/esm/volatile.js +1 -0
- package/dist/fast-element.api.json +9017 -6996
- package/dist/fast-element.d.ts +3557 -796
- package/dist/fast-element.debug.js +5093 -4419
- package/dist/fast-element.debug.min.js +2 -2
- package/dist/fast-element.js +5398 -4655
- package/dist/fast-element.min.js +2 -2
- package/dist/fast-element.untrimmed.d.ts +881 -481
- package/dist/hydration/hydration.api.json +5237 -0
- package/dist/styles/styles.api.json +2672 -0
- package/docs/api-report.api.md +344 -167
- package/docs/arrays/api-report.api.md +114 -0
- package/docs/declarative/api-report.api.md +397 -0
- package/docs/hydration/api-report.api.md +285 -0
- package/docs/styles/api-report.api.md +135 -0
- package/package.json +149 -40
- package/playwright.declarative.config.ts +26 -0
- package/playwright.declarative.webui.config.ts +20 -0
- package/scripts/declarative/build-fixtures-with-webui.js +135 -0
- package/scripts/declarative/build-fixtures.js +49 -0
- package/scripts/declarative/build-fixtures.utilities.js +101 -0
- package/scripts/measure-sizes.js +219 -0
- package/scripts/run-api-extractor.js +39 -20
- package/test/declarative/fixtures/README.md +72 -0
- package/test/declarative/fixtures/WRITING_FIXTURES.md +330 -0
- package/test/declarative/fixtures/bindings/README.md +12 -0
- package/test/declarative/fixtures/bindings/attribute/entry.html +13 -0
- package/test/declarative/fixtures/bindings/attribute/fast-build.config.json +6 -0
- package/test/declarative/fixtures/bindings/attribute/index.html +25 -0
- package/test/declarative/fixtures/bindings/attribute/main.ts +41 -0
- package/test/declarative/fixtures/bindings/attribute/state.json +8 -0
- package/test/declarative/fixtures/bindings/attribute/templates.html +11 -0
- package/test/declarative/fixtures/bindings/content/entry.html +12 -0
- package/test/declarative/fixtures/bindings/content/fast-build.config.json +6 -0
- package/test/declarative/fixtures/bindings/content/index.html +19 -0
- package/test/declarative/fixtures/bindings/content/main.ts +27 -0
- package/test/declarative/fixtures/bindings/content/state.json +4 -0
- package/test/declarative/fixtures/bindings/content/templates.html +6 -0
- package/test/declarative/fixtures/bindings/dot-syntax/entry.html +11 -0
- package/test/declarative/fixtures/bindings/dot-syntax/fast-build.config.json +6 -0
- package/test/declarative/fixtures/bindings/dot-syntax/index.html +47 -0
- package/test/declarative/fixtures/bindings/dot-syntax/main.ts +59 -0
- package/test/declarative/fixtures/bindings/dot-syntax/state.json +16 -0
- package/test/declarative/fixtures/bindings/dot-syntax/templates.html +17 -0
- package/test/declarative/fixtures/bindings/event/entry.html +11 -0
- package/test/declarative/fixtures/bindings/event/fast-build.config.json +6 -0
- package/test/declarative/fixtures/bindings/event/index.html +43 -0
- package/test/declarative/fixtures/bindings/event/main.ts +43 -0
- package/test/declarative/fixtures/bindings/event/state.json +3 -0
- package/test/declarative/fixtures/bindings/event/templates.html +18 -0
- package/test/declarative/fixtures/bindings/host/entry.html +40 -0
- package/test/declarative/fixtures/bindings/host/fast-build.config.json +6 -0
- package/test/declarative/fixtures/bindings/host/index.html +96 -0
- package/test/declarative/fixtures/bindings/host/main.ts +222 -0
- package/test/declarative/fixtures/bindings/host/state.json +9 -0
- package/test/declarative/fixtures/bindings/host/templates.html +55 -0
- package/test/declarative/fixtures/directives/README.md +12 -0
- package/test/declarative/fixtures/directives/children/entry.html +11 -0
- package/test/declarative/fixtures/directives/children/fast-build.config.json +6 -0
- package/test/declarative/fixtures/directives/children/index.html +15 -0
- package/test/declarative/fixtures/directives/children/main.ts +22 -0
- package/test/declarative/fixtures/directives/children/state.json +3 -0
- package/test/declarative/fixtures/directives/children/templates.html +3 -0
- package/test/declarative/fixtures/directives/ref/entry.html +11 -0
- package/test/declarative/fixtures/directives/ref/fast-build.config.json +6 -0
- package/test/declarative/fixtures/directives/ref/index.html +15 -0
- package/test/declarative/fixtures/directives/ref/main.ts +17 -0
- package/test/declarative/fixtures/directives/ref/state.json +1 -0
- package/test/declarative/fixtures/directives/ref/templates.html +3 -0
- package/test/declarative/fixtures/directives/repeat/entry.html +21 -0
- package/test/declarative/fixtures/directives/repeat/fast-build.config.json +6 -0
- package/test/declarative/fixtures/directives/repeat/index.html +133 -0
- package/test/declarative/fixtures/directives/repeat/main.ts +110 -0
- package/test/declarative/fixtures/directives/repeat/sprites.svg +8 -0
- package/test/declarative/fixtures/directives/repeat/state.json +10 -0
- package/test/declarative/fixtures/directives/repeat/templates.html +75 -0
- package/test/declarative/fixtures/directives/slotted/entry.html +17 -0
- package/test/declarative/fixtures/directives/slotted/fast-build.config.json +6 -0
- package/test/declarative/fixtures/directives/slotted/index.html +27 -0
- package/test/declarative/fixtures/directives/slotted/main.ts +29 -0
- package/test/declarative/fixtures/directives/slotted/state.json +1 -0
- package/test/declarative/fixtures/directives/slotted/templates.html +7 -0
- package/test/declarative/fixtures/directives/when/entry.html +51 -0
- package/test/declarative/fixtures/directives/when/fast-build.config.json +6 -0
- package/test/declarative/fixtures/directives/when/index.html +136 -0
- package/test/declarative/fixtures/directives/when/main.ts +172 -0
- package/test/declarative/fixtures/directives/when/state.json +12 -0
- package/test/declarative/fixtures/directives/when/templates.html +75 -0
- package/test/declarative/fixtures/ecosystem/README.md +11 -0
- package/test/declarative/fixtures/ecosystem/declarative-no-hydration/entry.html +12 -0
- package/test/declarative/fixtures/ecosystem/declarative-no-hydration/fast-build.config.json +6 -0
- package/test/declarative/fixtures/ecosystem/declarative-no-hydration/index.html +20 -0
- package/test/declarative/fixtures/ecosystem/declarative-no-hydration/main.ts +68 -0
- package/test/declarative/fixtures/ecosystem/declarative-no-hydration/state.json +4 -0
- package/test/declarative/fixtures/ecosystem/declarative-no-hydration/templates.html +7 -0
- package/test/declarative/fixtures/ecosystem/errors/entry.html +12 -0
- package/test/declarative/fixtures/ecosystem/errors/fast-build.config.json +6 -0
- package/test/declarative/fixtures/ecosystem/errors/index.html +20 -0
- package/test/declarative/fixtures/ecosystem/errors/main.ts +17 -0
- package/test/declarative/fixtures/ecosystem/errors/state.json +1 -0
- package/test/declarative/fixtures/ecosystem/errors/templates.html +7 -0
- package/test/declarative/fixtures/ecosystem/lifecycle-callbacks/entry.html +17 -0
- package/test/declarative/fixtures/ecosystem/lifecycle-callbacks/fast-build.config.json +6 -0
- package/test/declarative/fixtures/ecosystem/lifecycle-callbacks/index.html +56 -0
- package/test/declarative/fixtures/ecosystem/lifecycle-callbacks/main.ts +134 -0
- package/test/declarative/fixtures/ecosystem/lifecycle-callbacks/state.json +12 -0
- package/test/declarative/fixtures/ecosystem/lifecycle-callbacks/templates.html +34 -0
- package/test/declarative/fixtures/ecosystem/performance-metrics/entry.html +25 -0
- package/test/declarative/fixtures/ecosystem/performance-metrics/fast-build.config.json +6 -0
- package/test/declarative/fixtures/ecosystem/performance-metrics/fast-card.css +10 -0
- package/test/declarative/fixtures/ecosystem/performance-metrics/index.html +181 -0
- package/test/declarative/fixtures/ecosystem/performance-metrics/main.ts +58 -0
- package/test/declarative/fixtures/ecosystem/performance-metrics/state.json +6 -0
- package/test/declarative/fixtures/ecosystem/performance-metrics/templates.html +15 -0
- package/test/declarative/fixtures/extensions/README.md +15 -0
- package/test/declarative/fixtures/extensions/attribute-map/entry.html +14 -0
- package/test/declarative/fixtures/extensions/attribute-map/fast-build.config.json +6 -0
- package/test/declarative/fixtures/extensions/attribute-map/index.html +31 -0
- package/test/declarative/fixtures/extensions/attribute-map/main.ts +40 -0
- package/test/declarative/fixtures/extensions/attribute-map/state.json +4 -0
- package/test/declarative/fixtures/extensions/attribute-map/templates.html +14 -0
- package/test/declarative/fixtures/extensions/attribute-map-naming-strategy/entry.html +12 -0
- package/test/declarative/fixtures/extensions/attribute-map-naming-strategy/fast-build.config.json +7 -0
- package/test/declarative/fixtures/extensions/attribute-map-naming-strategy/index.html +25 -0
- package/test/declarative/fixtures/extensions/attribute-map-naming-strategy/main.ts +31 -0
- package/test/declarative/fixtures/extensions/attribute-map-naming-strategy/state.json +5 -0
- package/test/declarative/fixtures/extensions/attribute-map-naming-strategy/templates.html +11 -0
- package/test/declarative/fixtures/extensions/attribute-map-naming-strategy-camel-case/entry.html +13 -0
- package/test/declarative/fixtures/extensions/attribute-map-naming-strategy-camel-case/fast-build.config.json +7 -0
- package/test/declarative/fixtures/extensions/attribute-map-naming-strategy-camel-case/index.html +23 -0
- package/test/declarative/fixtures/extensions/attribute-map-naming-strategy-camel-case/main.ts +37 -0
- package/test/declarative/fixtures/extensions/attribute-map-naming-strategy-camel-case/state.json +1 -0
- package/test/declarative/fixtures/extensions/attribute-map-naming-strategy-camel-case/templates.html +9 -0
- package/test/declarative/fixtures/extensions/observer-map/entry.html +15 -0
- package/test/declarative/fixtures/extensions/observer-map/fast-build.config.json +6 -0
- package/test/declarative/fixtures/extensions/observer-map/index.html +442 -0
- package/test/declarative/fixtures/extensions/observer-map/main.ts +482 -0
- package/test/declarative/fixtures/extensions/observer-map/state.json +158 -0
- package/test/declarative/fixtures/extensions/observer-map/templates.html +172 -0
- package/test/declarative/fixtures/extensions/observer-map-config-object/entry.html +16 -0
- package/test/declarative/fixtures/extensions/observer-map-config-object/fast-build.config.json +6 -0
- package/test/declarative/fixtures/extensions/observer-map-config-object/index.html +27 -0
- package/test/declarative/fixtures/extensions/observer-map-config-object/main.ts +53 -0
- package/test/declarative/fixtures/extensions/observer-map-config-object/state.json +9 -0
- package/test/declarative/fixtures/extensions/observer-map-config-object/templates.html +12 -0
- package/test/declarative/fixtures/extensions/observer-map-deep-merge/README.md +98 -0
- package/test/declarative/fixtures/extensions/observer-map-deep-merge/entry.html +156 -0
- package/test/declarative/fixtures/extensions/observer-map-deep-merge/fast-build.config.json +6 -0
- package/test/declarative/fixtures/extensions/observer-map-deep-merge/index.html +376 -0
- package/test/declarative/fixtures/extensions/observer-map-deep-merge/main.ts +366 -0
- package/test/declarative/fixtures/extensions/observer-map-deep-merge/state.json +69 -0
- package/test/declarative/fixtures/extensions/observer-map-deep-merge/templates.html +91 -0
- package/test/declarative/fixtures/extensions/observer-map-properties/entry.html +14 -0
- package/test/declarative/fixtures/extensions/observer-map-properties/fast-build.config.json +6 -0
- package/test/declarative/fixtures/extensions/observer-map-properties/index.html +110 -0
- package/test/declarative/fixtures/extensions/observer-map-properties/main.ts +175 -0
- package/test/declarative/fixtures/extensions/observer-map-properties/state.json +29 -0
- package/test/declarative/fixtures/extensions/observer-map-properties/templates.html +55 -0
- package/test/declarative/fixtures/scenarios/README.md +7 -0
- package/test/declarative/fixtures/scenarios/nested-elements/entry.html +16 -0
- package/test/declarative/fixtures/scenarios/nested-elements/fast-build.config.json +6 -0
- package/test/declarative/fixtures/scenarios/nested-elements/index.html +126 -0
- package/test/declarative/fixtures/scenarios/nested-elements/main.ts +214 -0
- package/test/declarative/fixtures/scenarios/nested-elements/state.json +10 -0
- package/test/declarative/fixtures/scenarios/nested-elements/templates.html +54 -0
- package/test/declarative/index.html +12 -0
- package/test/declarative/vite.config.ts +55 -0
- package/test/declarative-main.ts +6 -0
- package/test/extension-subpaths-main.ts +9 -0
- package/test/main.ts +38 -33
- package/test/pure-declarative-main.ts +1 -0
- package/dist/dts/components/install-hydration.d.ts +0 -1
- package/dist/dts/pending-task.d.ts +0 -32
- package/dist/dts/polyfills.d.ts +0 -0
- package/dist/dts/styles/css-binding-directive.d.ts +0 -60
- package/dist/dts/templating/install-hydratable-view-templates.d.ts +0 -1
- package/dist/esm/components/install-hydration.js +0 -3
- package/dist/esm/pending-task.js +0 -28
- package/dist/esm/polyfills.js +0 -60
- package/dist/esm/styles/css-binding-directive.js +0 -76
- package/dist/esm/templating/install-hydratable-view-templates.js +0 -23
|
@@ -0,0 +1,235 @@
|
|
|
1
|
+
var _a;
|
|
2
|
+
import { Hydratable } from "../components/hydration.js";
|
|
3
|
+
import { buildViewBindingTargets, createRangeForNodes, HydrationTargetElementError, targetFactory, } from "../hydration/target-builder.js";
|
|
4
|
+
import { SourceLifetime } from "../observation/observable.js";
|
|
5
|
+
import { makeSerializationNoop } from "../platform.js";
|
|
6
|
+
import { DefaultExecutionContext, removeNodeSequence, } from "./view.js";
|
|
7
|
+
/** @public */
|
|
8
|
+
export const HydrationStage = {
|
|
9
|
+
unhydrated: "unhydrated",
|
|
10
|
+
hydrating: "hydrating",
|
|
11
|
+
hydrated: "hydrated",
|
|
12
|
+
};
|
|
13
|
+
/** @public */
|
|
14
|
+
export class HydrationBindingError extends Error {
|
|
15
|
+
constructor(
|
|
16
|
+
/**
|
|
17
|
+
* The error message
|
|
18
|
+
*/
|
|
19
|
+
message,
|
|
20
|
+
/**
|
|
21
|
+
* The factory that was unable to be bound
|
|
22
|
+
*/
|
|
23
|
+
factory,
|
|
24
|
+
/**
|
|
25
|
+
* A DocumentFragment containing a clone of the
|
|
26
|
+
* view's Nodes.
|
|
27
|
+
*/
|
|
28
|
+
fragment,
|
|
29
|
+
/**
|
|
30
|
+
* String representation of the HTML in the template that
|
|
31
|
+
* threw the binding error.
|
|
32
|
+
*/
|
|
33
|
+
templateString) {
|
|
34
|
+
super(message);
|
|
35
|
+
this.factory = factory;
|
|
36
|
+
this.fragment = fragment;
|
|
37
|
+
this.templateString = templateString;
|
|
38
|
+
}
|
|
39
|
+
}
|
|
40
|
+
export class HydrationView extends DefaultExecutionContext {
|
|
41
|
+
get hydrationStage() {
|
|
42
|
+
return this._hydrationStage;
|
|
43
|
+
}
|
|
44
|
+
get targets() {
|
|
45
|
+
return this._targets;
|
|
46
|
+
}
|
|
47
|
+
get bindingViewBoundaries() {
|
|
48
|
+
return this._bindingViewBoundaries;
|
|
49
|
+
}
|
|
50
|
+
constructor(firstChild, lastChild, sourceTemplate, hostBindingTarget) {
|
|
51
|
+
super();
|
|
52
|
+
this.firstChild = firstChild;
|
|
53
|
+
this.lastChild = lastChild;
|
|
54
|
+
this.sourceTemplate = sourceTemplate;
|
|
55
|
+
this.hostBindingTarget = hostBindingTarget;
|
|
56
|
+
this[_a] = Hydratable;
|
|
57
|
+
this.context = this;
|
|
58
|
+
this.source = null;
|
|
59
|
+
this.isBound = false;
|
|
60
|
+
this.sourceLifetime = SourceLifetime.unknown;
|
|
61
|
+
this.unbindables = [];
|
|
62
|
+
this.fragment = null;
|
|
63
|
+
this.behaviors = null;
|
|
64
|
+
this._hydrationStage = HydrationStage.unhydrated;
|
|
65
|
+
this._bindingViewBoundaries = {};
|
|
66
|
+
this._targets = {};
|
|
67
|
+
this.factories = sourceTemplate.compile().factories;
|
|
68
|
+
}
|
|
69
|
+
/**
|
|
70
|
+
* no-op. Hydrated views are don't need to be moved from a documentFragment
|
|
71
|
+
* to the target node.
|
|
72
|
+
*/
|
|
73
|
+
insertBefore(node) {
|
|
74
|
+
// No-op in cases where this is called before the view is removed,
|
|
75
|
+
// because the nodes will already be in the document and just need hydrating.
|
|
76
|
+
if (this.fragment === null) {
|
|
77
|
+
return;
|
|
78
|
+
}
|
|
79
|
+
if (this.fragment.hasChildNodes()) {
|
|
80
|
+
node.parentNode.insertBefore(this.fragment, node);
|
|
81
|
+
}
|
|
82
|
+
else {
|
|
83
|
+
const end = this.lastChild;
|
|
84
|
+
if (node.previousSibling === end)
|
|
85
|
+
return;
|
|
86
|
+
const parentNode = node.parentNode;
|
|
87
|
+
let current = this.firstChild;
|
|
88
|
+
let next;
|
|
89
|
+
while (current !== end) {
|
|
90
|
+
next = current.nextSibling;
|
|
91
|
+
parentNode.insertBefore(current, node);
|
|
92
|
+
current = next;
|
|
93
|
+
}
|
|
94
|
+
parentNode.insertBefore(end, node);
|
|
95
|
+
}
|
|
96
|
+
}
|
|
97
|
+
/**
|
|
98
|
+
* Appends the view to a node. In cases where this is called before the
|
|
99
|
+
* view has been removed, the method will no-op.
|
|
100
|
+
* @param node - the node to append the view to.
|
|
101
|
+
*/
|
|
102
|
+
appendTo(node) {
|
|
103
|
+
if (this.fragment !== null) {
|
|
104
|
+
node.appendChild(this.fragment);
|
|
105
|
+
}
|
|
106
|
+
}
|
|
107
|
+
remove() {
|
|
108
|
+
const fragment = this.fragment || (this.fragment = document.createDocumentFragment());
|
|
109
|
+
const end = this.lastChild;
|
|
110
|
+
let current = this.firstChild;
|
|
111
|
+
let next;
|
|
112
|
+
while (current !== end) {
|
|
113
|
+
next = current.nextSibling;
|
|
114
|
+
if (!next) {
|
|
115
|
+
throw new Error(`Unmatched first/last child inside "${end.getRootNode().host.nodeName}".`);
|
|
116
|
+
}
|
|
117
|
+
fragment.appendChild(current);
|
|
118
|
+
current = next;
|
|
119
|
+
}
|
|
120
|
+
fragment.appendChild(end);
|
|
121
|
+
}
|
|
122
|
+
bind(source, context = this) {
|
|
123
|
+
var _b;
|
|
124
|
+
if (this.hydrationStage !== HydrationStage.hydrated) {
|
|
125
|
+
this._hydrationStage = HydrationStage.hydrating;
|
|
126
|
+
}
|
|
127
|
+
if (this.source === source) {
|
|
128
|
+
return;
|
|
129
|
+
}
|
|
130
|
+
let behaviors = this.behaviors;
|
|
131
|
+
if (behaviors === null) {
|
|
132
|
+
this.source = source;
|
|
133
|
+
this.context = context;
|
|
134
|
+
try {
|
|
135
|
+
const { targets, boundaries } = buildViewBindingTargets(this.firstChild, this.lastChild, this.factories);
|
|
136
|
+
this._targets = targets;
|
|
137
|
+
this._bindingViewBoundaries = boundaries;
|
|
138
|
+
}
|
|
139
|
+
catch (error) {
|
|
140
|
+
if (error instanceof HydrationTargetElementError) {
|
|
141
|
+
let templateString = this.sourceTemplate.html;
|
|
142
|
+
if (typeof templateString !== "string") {
|
|
143
|
+
templateString = templateString.innerHTML;
|
|
144
|
+
}
|
|
145
|
+
error.templateString = templateString;
|
|
146
|
+
}
|
|
147
|
+
throw error;
|
|
148
|
+
}
|
|
149
|
+
this.behaviors = behaviors = new Array(this.factories.length);
|
|
150
|
+
const factories = this.factories;
|
|
151
|
+
for (let i = 0, ii = factories.length; i < ii; ++i) {
|
|
152
|
+
const factory = factories[i];
|
|
153
|
+
if (factory.targetNodeId === "h" && this.hostBindingTarget) {
|
|
154
|
+
targetFactory(factory, this.hostBindingTarget, this._targets);
|
|
155
|
+
}
|
|
156
|
+
// If the binding has been targeted or it is a host binding and the view has a hostBindingTarget
|
|
157
|
+
if (factory.targetNodeId in this.targets) {
|
|
158
|
+
const behavior = factory.createBehavior();
|
|
159
|
+
behavior.bind(this);
|
|
160
|
+
behaviors[i] = behavior;
|
|
161
|
+
}
|
|
162
|
+
else {
|
|
163
|
+
let templateString = this.sourceTemplate.html;
|
|
164
|
+
if (typeof templateString !== "string") {
|
|
165
|
+
templateString = templateString.innerHTML;
|
|
166
|
+
}
|
|
167
|
+
const hostElement = ((_b = this.firstChild) === null || _b === void 0 ? void 0 : _b.getRootNode())
|
|
168
|
+
.host;
|
|
169
|
+
const hostName = (hostElement === null || hostElement === void 0 ? void 0 : hostElement.nodeName) || "unknown";
|
|
170
|
+
const factoryInfo = factory;
|
|
171
|
+
// Build detailed error message
|
|
172
|
+
const details = [
|
|
173
|
+
`HydrationView was unable to successfully target bindings inside "<${hostName.toLowerCase()}>".`,
|
|
174
|
+
`\nMismatch Details:`,
|
|
175
|
+
` - Expected target node ID: "${factory.targetNodeId}"`,
|
|
176
|
+
` - Available target IDs: [${Object.keys(this.targets).join(", ") || "none"}]`,
|
|
177
|
+
];
|
|
178
|
+
if (factory.targetTagName) {
|
|
179
|
+
details.push(` - Expected tag name: "${factory.targetTagName}"`);
|
|
180
|
+
}
|
|
181
|
+
if (factoryInfo.sourceAspect) {
|
|
182
|
+
details.push(` - Source aspect: "${factoryInfo.sourceAspect}"`);
|
|
183
|
+
}
|
|
184
|
+
if (factoryInfo.aspectType !== undefined) {
|
|
185
|
+
details.push(` - Aspect type: ${factoryInfo.aspectType}`);
|
|
186
|
+
}
|
|
187
|
+
details.push(`\nThis usually means:`, ` 1. The server-rendered HTML doesn't match the client template`, ` 2. The hydration markers are missing or corrupted`, ` 3. The DOM structure was modified before hydration`, `\nTemplate: ${templateString.slice(0, 200)}${templateString.length > 200 ? "..." : ""}`);
|
|
188
|
+
throw new HydrationBindingError(details.join("\n"), factory, createRangeForNodes(this.firstChild, this.lastChild).cloneContents(), templateString);
|
|
189
|
+
}
|
|
190
|
+
}
|
|
191
|
+
}
|
|
192
|
+
else {
|
|
193
|
+
if (this.source !== null) {
|
|
194
|
+
this.evaluateUnbindables();
|
|
195
|
+
}
|
|
196
|
+
this.isBound = false;
|
|
197
|
+
this.source = source;
|
|
198
|
+
this.context = context;
|
|
199
|
+
for (let i = 0, ii = behaviors.length; i < ii; ++i) {
|
|
200
|
+
behaviors[i].bind(this);
|
|
201
|
+
}
|
|
202
|
+
}
|
|
203
|
+
this.isBound = true;
|
|
204
|
+
this._hydrationStage = HydrationStage.hydrated;
|
|
205
|
+
}
|
|
206
|
+
unbind() {
|
|
207
|
+
if (!this.isBound || this.source === null) {
|
|
208
|
+
return;
|
|
209
|
+
}
|
|
210
|
+
this.evaluateUnbindables();
|
|
211
|
+
this.source = null;
|
|
212
|
+
this.context = this;
|
|
213
|
+
this.isBound = false;
|
|
214
|
+
}
|
|
215
|
+
/**
|
|
216
|
+
* Removes the view and unbinds its behaviors, disposing of DOM nodes afterward.
|
|
217
|
+
* Once a view has been disposed, it cannot be inserted or bound again.
|
|
218
|
+
*/
|
|
219
|
+
dispose() {
|
|
220
|
+
removeNodeSequence(this.firstChild, this.lastChild);
|
|
221
|
+
this.unbind();
|
|
222
|
+
}
|
|
223
|
+
onUnbind(behavior) {
|
|
224
|
+
this.unbindables.push(behavior);
|
|
225
|
+
}
|
|
226
|
+
evaluateUnbindables() {
|
|
227
|
+
const unbindables = this.unbindables;
|
|
228
|
+
for (let i = 0, ii = unbindables.length; i < ii; ++i) {
|
|
229
|
+
unbindables[i].unbind(this);
|
|
230
|
+
}
|
|
231
|
+
unbindables.length = 0;
|
|
232
|
+
}
|
|
233
|
+
}
|
|
234
|
+
_a = Hydratable;
|
|
235
|
+
makeSerializationNoop(HydrationView);
|
|
@@ -8,7 +8,7 @@ import { isFunction, isString } from "../interfaces.js";
|
|
|
8
8
|
import { HTMLDirective, } from "./html-directive.js";
|
|
9
9
|
import { Markup } from "./markup.js";
|
|
10
10
|
import { html, ViewTemplate, } from "./template.js";
|
|
11
|
-
import { HydrationStage } from "./view.js";
|
|
11
|
+
import { HydrationStage } from "./hydration-view.js";
|
|
12
12
|
/**
|
|
13
13
|
* A Behavior that enables advanced rendering.
|
|
14
14
|
* @public
|
|
@@ -62,8 +62,19 @@ export class RenderBehavior {
|
|
|
62
62
|
view.needsBindOnly = true;
|
|
63
63
|
}
|
|
64
64
|
}
|
|
65
|
-
/**
|
|
65
|
+
/**
|
|
66
|
+
* Handles changes from data or template binding observers.
|
|
67
|
+
* Guards against stale notifications that may arrive after the
|
|
68
|
+
* controller's view has been unbound (e.g., when a parent `when`
|
|
69
|
+
* directive tears down and later recreates a child element).
|
|
70
|
+
* @internal
|
|
71
|
+
*/
|
|
66
72
|
handleChange(source, observer) {
|
|
73
|
+
// https://github.com/microsoft/fast/issues/7444
|
|
74
|
+
// This guard will be reconsidered in the next major version.
|
|
75
|
+
if (!this.controller.isBound) {
|
|
76
|
+
return;
|
|
77
|
+
}
|
|
67
78
|
if (observer === this.dataBindingObserver) {
|
|
68
79
|
this.data = this.dataBindingObserver.bind(this.controller);
|
|
69
80
|
}
|
|
@@ -1,11 +1,12 @@
|
|
|
1
1
|
import { normalizeBinding } from "../binding/normalize.js";
|
|
2
|
-
import {
|
|
3
|
-
import { ArrayObserver
|
|
2
|
+
import { isHydratable } from "../components/hydration.js";
|
|
3
|
+
import { ArrayObserver } from "../observation/arrays.js";
|
|
4
4
|
import { Observable, } from "../observation/observable.js";
|
|
5
5
|
import { emptyArray } from "../platform.js";
|
|
6
6
|
import { HTMLDirective, } from "./html-directive.js";
|
|
7
7
|
import { Markup } from "./markup.js";
|
|
8
|
-
import {
|
|
8
|
+
import { HydrationStage, } from "./hydration-view.js";
|
|
9
|
+
import { HTMLView, } from "./view.js";
|
|
9
10
|
const defaultRepeatOptions = Object.freeze({
|
|
10
11
|
positioning: false,
|
|
11
12
|
recycle: true,
|
|
@@ -287,60 +288,61 @@ export class RepeatBehavior {
|
|
|
287
288
|
if (!this.items) {
|
|
288
289
|
return;
|
|
289
290
|
}
|
|
290
|
-
|
|
291
|
+
const itemCount = this.items.length;
|
|
292
|
+
this.views = new Array(itemCount);
|
|
293
|
+
// First pass: collect all repeat marker pairs by walking backward.
|
|
294
|
+
// Each entry is { start: Node, end: Node } for the item content range.
|
|
295
|
+
const itemRanges = [];
|
|
291
296
|
let current = this.location.previousSibling;
|
|
292
297
|
while (current !== null) {
|
|
293
|
-
if (!isCommentNode(current)) {
|
|
294
|
-
current = current.previousSibling;
|
|
295
|
-
continue;
|
|
296
|
-
}
|
|
297
|
-
const index = HydrationMarkup.parseRepeatEndMarker(current.data);
|
|
298
|
-
if (index === null) {
|
|
298
|
+
if (!isCommentNode(current) || current.data !== "fe:/r") {
|
|
299
299
|
current = current.previousSibling;
|
|
300
300
|
continue;
|
|
301
301
|
}
|
|
302
|
+
// Found repeat end marker
|
|
302
303
|
current.data = "";
|
|
303
|
-
// end of repeat is the previousSibling of end comment
|
|
304
304
|
const end = current.previousSibling;
|
|
305
305
|
if (!end) {
|
|
306
306
|
throw new Error(`Error when hydrating inside "${this.location.getRootNode().host.nodeName}": end should never be null.`);
|
|
307
307
|
}
|
|
308
|
-
//
|
|
308
|
+
// Find matching start marker via balanced counting
|
|
309
309
|
let start = end;
|
|
310
|
-
|
|
311
|
-
let unmatchedEndMarkers = 0;
|
|
310
|
+
let depth = 0;
|
|
312
311
|
while (start !== null) {
|
|
313
312
|
if (isCommentNode(start)) {
|
|
314
|
-
if (
|
|
315
|
-
|
|
313
|
+
if (start.data === "fe:/r") {
|
|
314
|
+
depth++;
|
|
316
315
|
}
|
|
317
|
-
else if (
|
|
318
|
-
if (
|
|
319
|
-
|
|
320
|
-
|
|
321
|
-
|
|
322
|
-
|
|
323
|
-
|
|
324
|
-
|
|
325
|
-
|
|
326
|
-
}
|
|
327
|
-
start.data = "";
|
|
328
|
-
current = start.previousSibling;
|
|
329
|
-
// start of repeat content is the nextSibling of start comment
|
|
330
|
-
start = start.nextSibling;
|
|
331
|
-
const view = template.hydrate(start, end);
|
|
332
|
-
this.views[index] = view;
|
|
333
|
-
this.bindView(view, this.items, index, this.controller);
|
|
316
|
+
else if (start.data === "fe:r") {
|
|
317
|
+
if (depth === 0) {
|
|
318
|
+
const startMarker = start;
|
|
319
|
+
startMarker.data = "";
|
|
320
|
+
current = startMarker.previousSibling;
|
|
321
|
+
const itemStart = startMarker.nextSibling;
|
|
322
|
+
// Empty item: start and end markers are adjacent.
|
|
323
|
+
const itemEnd = end === startMarker ? itemStart : end;
|
|
324
|
+
itemRanges.push({ start: itemStart, end: itemEnd });
|
|
334
325
|
break;
|
|
335
326
|
}
|
|
327
|
+
depth--;
|
|
336
328
|
}
|
|
337
329
|
}
|
|
338
330
|
start = start.previousSibling;
|
|
339
331
|
}
|
|
340
332
|
if (!start) {
|
|
341
|
-
throw new Error(`Error when hydrating inside "${this.location.getRootNode().host.nodeName}": start
|
|
333
|
+
throw new Error(`Error when hydrating inside "${this.location.getRootNode().host.nodeName}": repeat start marker not found.`);
|
|
342
334
|
}
|
|
343
335
|
}
|
|
336
|
+
// Ranges were collected backward (last item first).
|
|
337
|
+
// Reverse so index 0 = first SSR item.
|
|
338
|
+
itemRanges.reverse();
|
|
339
|
+
// Hydrate each SSR item at its correct index (0-based from start).
|
|
340
|
+
for (let i = 0; i < itemRanges.length && i < itemCount; i++) {
|
|
341
|
+
const { start, end } = itemRanges[i];
|
|
342
|
+
const view = template.hydrate(start, end);
|
|
343
|
+
this.views[i] = view;
|
|
344
|
+
this.bindView(view, this.items, i, this.controller);
|
|
345
|
+
}
|
|
344
346
|
}
|
|
345
347
|
}
|
|
346
348
|
/**
|
|
@@ -77,13 +77,6 @@ export class ViewTemplate {
|
|
|
77
77
|
}
|
|
78
78
|
return this.result;
|
|
79
79
|
}
|
|
80
|
-
/**
|
|
81
|
-
* Creates an HTMLView instance based on this template definition.
|
|
82
|
-
* @param hostBindingTarget - The element that host behaviors will be bound to.
|
|
83
|
-
*/
|
|
84
|
-
create(hostBindingTarget) {
|
|
85
|
-
return this.compile().createView(hostBindingTarget);
|
|
86
|
-
}
|
|
87
80
|
/**
|
|
88
81
|
* Returns a directive that can inline the template.
|
|
89
82
|
*/
|
|
@@ -121,6 +114,13 @@ export class ViewTemplate {
|
|
|
121
114
|
view.appendTo(host);
|
|
122
115
|
return view;
|
|
123
116
|
}
|
|
117
|
+
/**
|
|
118
|
+
* Creates an HTMLView instance based on this template definition.
|
|
119
|
+
* @param hostBindingTarget - The element that host behaviors will be bound to.
|
|
120
|
+
*/
|
|
121
|
+
create(hostBindingTarget) {
|
|
122
|
+
return this.compile().createView(hostBindingTarget);
|
|
123
|
+
}
|
|
124
124
|
/**
|
|
125
125
|
* Processes the tagged template literal's static strings and interpolated values and
|
|
126
126
|
* creates a ViewTemplate.
|
|
@@ -1,9 +1,6 @@
|
|
|
1
|
-
var _a;
|
|
2
|
-
import { Hydratable } from "../components/hydration.js";
|
|
3
|
-
import { buildViewBindingTargets, createRangeForNodes, HydrationTargetElementError, targetFactory, } from "../hydration/target-builder.js";
|
|
4
1
|
import { ExecutionContext, Observable, SourceLifetime, } from "../observation/observable.js";
|
|
5
2
|
import { makeSerializationNoop } from "../platform.js";
|
|
6
|
-
function removeNodeSequence(firstNode, lastNode) {
|
|
3
|
+
export function removeNodeSequence(firstNode, lastNode) {
|
|
7
4
|
const parent = firstNode.parentNode;
|
|
8
5
|
let current = firstNode;
|
|
9
6
|
let next;
|
|
@@ -17,7 +14,11 @@ function removeNodeSequence(firstNode, lastNode) {
|
|
|
17
14
|
}
|
|
18
15
|
parent.removeChild(lastNode);
|
|
19
16
|
}
|
|
20
|
-
|
|
17
|
+
/**
|
|
18
|
+
* The default execution context for template views.
|
|
19
|
+
* @public
|
|
20
|
+
*/
|
|
21
|
+
export class DefaultExecutionContext {
|
|
21
22
|
constructor() {
|
|
22
23
|
/**
|
|
23
24
|
* The index of the current item within a repeat context.
|
|
@@ -111,6 +112,24 @@ export class HTMLView extends DefaultExecutionContext {
|
|
|
111
112
|
* Indicates how the source's lifetime relates to the controller's lifetime.
|
|
112
113
|
*/
|
|
113
114
|
this.sourceLifetime = SourceLifetime.unknown;
|
|
115
|
+
/**
|
|
116
|
+
* When true, directives skip attribute/booleanAttribute DOM
|
|
117
|
+
* updates during bind(). Set only during the prerendered bind
|
|
118
|
+
* window and cleared immediately after.
|
|
119
|
+
* @internal
|
|
120
|
+
*/
|
|
121
|
+
this._skipAttrUpdates = false;
|
|
122
|
+
/**
|
|
123
|
+
* A promise that resolves with `true` after prerendered content
|
|
124
|
+
* has been hydrated, or `false` when the view is client-side
|
|
125
|
+
* rendered. Resolves once the first bind completes.
|
|
126
|
+
*/
|
|
127
|
+
this.isPrerendered = Promise.resolve(false);
|
|
128
|
+
/**
|
|
129
|
+
* Resolves `true` after prerendered content has been hydrated,
|
|
130
|
+
* `false` when client-side rendered or hydration not enabled.
|
|
131
|
+
*/
|
|
132
|
+
this.isHydrated = Promise.resolve(false);
|
|
114
133
|
/**
|
|
115
134
|
* The execution context the view is running within.
|
|
116
135
|
*/
|
|
@@ -258,231 +277,3 @@ export class HTMLView extends DefaultExecutionContext {
|
|
|
258
277
|
makeSerializationNoop(HTMLView);
|
|
259
278
|
Observable.defineProperty(HTMLView.prototype, "index");
|
|
260
279
|
Observable.defineProperty(HTMLView.prototype, "length");
|
|
261
|
-
export const HydrationStage = {
|
|
262
|
-
unhydrated: "unhydrated",
|
|
263
|
-
hydrating: "hydrating",
|
|
264
|
-
hydrated: "hydrated",
|
|
265
|
-
};
|
|
266
|
-
/** @public */
|
|
267
|
-
export class HydrationBindingError extends Error {
|
|
268
|
-
constructor(
|
|
269
|
-
/**
|
|
270
|
-
* The error message
|
|
271
|
-
*/
|
|
272
|
-
message,
|
|
273
|
-
/**
|
|
274
|
-
* The factory that was unable to be bound
|
|
275
|
-
*/
|
|
276
|
-
factory,
|
|
277
|
-
/**
|
|
278
|
-
* A DocumentFragment containing a clone of the
|
|
279
|
-
* view's Nodes.
|
|
280
|
-
*/
|
|
281
|
-
fragment,
|
|
282
|
-
/**
|
|
283
|
-
* String representation of the HTML in the template that
|
|
284
|
-
* threw the binding error.
|
|
285
|
-
*/
|
|
286
|
-
templateString) {
|
|
287
|
-
super(message);
|
|
288
|
-
this.factory = factory;
|
|
289
|
-
this.fragment = fragment;
|
|
290
|
-
this.templateString = templateString;
|
|
291
|
-
}
|
|
292
|
-
}
|
|
293
|
-
export class HydrationView extends DefaultExecutionContext {
|
|
294
|
-
get hydrationStage() {
|
|
295
|
-
return this._hydrationStage;
|
|
296
|
-
}
|
|
297
|
-
get targets() {
|
|
298
|
-
return this._targets;
|
|
299
|
-
}
|
|
300
|
-
get bindingViewBoundaries() {
|
|
301
|
-
return this._bindingViewBoundaries;
|
|
302
|
-
}
|
|
303
|
-
constructor(firstChild, lastChild, sourceTemplate, hostBindingTarget) {
|
|
304
|
-
super();
|
|
305
|
-
this.firstChild = firstChild;
|
|
306
|
-
this.lastChild = lastChild;
|
|
307
|
-
this.sourceTemplate = sourceTemplate;
|
|
308
|
-
this.hostBindingTarget = hostBindingTarget;
|
|
309
|
-
this[_a] = Hydratable;
|
|
310
|
-
this.context = this;
|
|
311
|
-
this.source = null;
|
|
312
|
-
this.isBound = false;
|
|
313
|
-
this.sourceLifetime = SourceLifetime.unknown;
|
|
314
|
-
this.unbindables = [];
|
|
315
|
-
this.fragment = null;
|
|
316
|
-
this.behaviors = null;
|
|
317
|
-
this._hydrationStage = HydrationStage.unhydrated;
|
|
318
|
-
this._bindingViewBoundaries = {};
|
|
319
|
-
this._targets = {};
|
|
320
|
-
this.factories = sourceTemplate.compile().factories;
|
|
321
|
-
}
|
|
322
|
-
/**
|
|
323
|
-
* no-op. Hydrated views are don't need to be moved from a documentFragment
|
|
324
|
-
* to the target node.
|
|
325
|
-
*/
|
|
326
|
-
insertBefore(node) {
|
|
327
|
-
// No-op in cases where this is called before the view is removed,
|
|
328
|
-
// because the nodes will already be in the document and just need hydrating.
|
|
329
|
-
if (this.fragment === null) {
|
|
330
|
-
return;
|
|
331
|
-
}
|
|
332
|
-
if (this.fragment.hasChildNodes()) {
|
|
333
|
-
node.parentNode.insertBefore(this.fragment, node);
|
|
334
|
-
}
|
|
335
|
-
else {
|
|
336
|
-
const end = this.lastChild;
|
|
337
|
-
if (node.previousSibling === end)
|
|
338
|
-
return;
|
|
339
|
-
const parentNode = node.parentNode;
|
|
340
|
-
let current = this.firstChild;
|
|
341
|
-
let next;
|
|
342
|
-
while (current !== end) {
|
|
343
|
-
next = current.nextSibling;
|
|
344
|
-
parentNode.insertBefore(current, node);
|
|
345
|
-
current = next;
|
|
346
|
-
}
|
|
347
|
-
parentNode.insertBefore(end, node);
|
|
348
|
-
}
|
|
349
|
-
}
|
|
350
|
-
/**
|
|
351
|
-
* Appends the view to a node. In cases where this is called before the
|
|
352
|
-
* view has been removed, the method will no-op.
|
|
353
|
-
* @param node - the node to append the view to.
|
|
354
|
-
*/
|
|
355
|
-
appendTo(node) {
|
|
356
|
-
if (this.fragment !== null) {
|
|
357
|
-
node.appendChild(this.fragment);
|
|
358
|
-
}
|
|
359
|
-
}
|
|
360
|
-
remove() {
|
|
361
|
-
const fragment = this.fragment || (this.fragment = document.createDocumentFragment());
|
|
362
|
-
const end = this.lastChild;
|
|
363
|
-
let current = this.firstChild;
|
|
364
|
-
let next;
|
|
365
|
-
while (current !== end) {
|
|
366
|
-
next = current.nextSibling;
|
|
367
|
-
if (!next) {
|
|
368
|
-
throw new Error(`Unmatched first/last child inside "${end.getRootNode().host.nodeName}".`);
|
|
369
|
-
}
|
|
370
|
-
fragment.appendChild(current);
|
|
371
|
-
current = next;
|
|
372
|
-
}
|
|
373
|
-
fragment.appendChild(end);
|
|
374
|
-
}
|
|
375
|
-
bind(source, context = this) {
|
|
376
|
-
var _b;
|
|
377
|
-
if (this.hydrationStage !== HydrationStage.hydrated) {
|
|
378
|
-
this._hydrationStage = HydrationStage.hydrating;
|
|
379
|
-
}
|
|
380
|
-
if (this.source === source) {
|
|
381
|
-
return;
|
|
382
|
-
}
|
|
383
|
-
let behaviors = this.behaviors;
|
|
384
|
-
if (behaviors === null) {
|
|
385
|
-
this.source = source;
|
|
386
|
-
this.context = context;
|
|
387
|
-
try {
|
|
388
|
-
const { targets, boundaries } = buildViewBindingTargets(this.firstChild, this.lastChild, this.factories);
|
|
389
|
-
this._targets = targets;
|
|
390
|
-
this._bindingViewBoundaries = boundaries;
|
|
391
|
-
}
|
|
392
|
-
catch (error) {
|
|
393
|
-
if (error instanceof HydrationTargetElementError) {
|
|
394
|
-
let templateString = this.sourceTemplate.html;
|
|
395
|
-
if (typeof templateString !== "string") {
|
|
396
|
-
templateString = templateString.innerHTML;
|
|
397
|
-
}
|
|
398
|
-
error.templateString = templateString;
|
|
399
|
-
}
|
|
400
|
-
throw error;
|
|
401
|
-
}
|
|
402
|
-
this.behaviors = behaviors = new Array(this.factories.length);
|
|
403
|
-
const factories = this.factories;
|
|
404
|
-
for (let i = 0, ii = factories.length; i < ii; ++i) {
|
|
405
|
-
const factory = factories[i];
|
|
406
|
-
if (factory.targetNodeId === "h" && this.hostBindingTarget) {
|
|
407
|
-
targetFactory(factory, this.hostBindingTarget, this._targets);
|
|
408
|
-
}
|
|
409
|
-
// If the binding has been targeted or it is a host binding and the view has a hostBindingTarget
|
|
410
|
-
if (factory.targetNodeId in this.targets) {
|
|
411
|
-
const behavior = factory.createBehavior();
|
|
412
|
-
behavior.bind(this);
|
|
413
|
-
behaviors[i] = behavior;
|
|
414
|
-
}
|
|
415
|
-
else {
|
|
416
|
-
let templateString = this.sourceTemplate.html;
|
|
417
|
-
if (typeof templateString !== "string") {
|
|
418
|
-
templateString = templateString.innerHTML;
|
|
419
|
-
}
|
|
420
|
-
const hostElement = ((_b = this.firstChild) === null || _b === void 0 ? void 0 : _b.getRootNode())
|
|
421
|
-
.host;
|
|
422
|
-
const hostName = (hostElement === null || hostElement === void 0 ? void 0 : hostElement.nodeName) || "unknown";
|
|
423
|
-
const factoryInfo = factory;
|
|
424
|
-
// Build detailed error message
|
|
425
|
-
const details = [
|
|
426
|
-
`HydrationView was unable to successfully target bindings inside "<${hostName.toLowerCase()}>".`,
|
|
427
|
-
`\nMismatch Details:`,
|
|
428
|
-
` - Expected target node ID: "${factory.targetNodeId}"`,
|
|
429
|
-
` - Available target IDs: [${Object.keys(this.targets).join(", ") || "none"}]`,
|
|
430
|
-
];
|
|
431
|
-
if (factory.targetTagName) {
|
|
432
|
-
details.push(` - Expected tag name: "${factory.targetTagName}"`);
|
|
433
|
-
}
|
|
434
|
-
if (factoryInfo.sourceAspect) {
|
|
435
|
-
details.push(` - Source aspect: "${factoryInfo.sourceAspect}"`);
|
|
436
|
-
}
|
|
437
|
-
if (factoryInfo.aspectType !== undefined) {
|
|
438
|
-
details.push(` - Aspect type: ${factoryInfo.aspectType}`);
|
|
439
|
-
}
|
|
440
|
-
details.push(`\nThis usually means:`, ` 1. The server-rendered HTML doesn't match the client template`, ` 2. The hydration markers are missing or corrupted`, ` 3. The DOM structure was modified before hydration`, `\nTemplate: ${templateString.slice(0, 200)}${templateString.length > 200 ? "..." : ""}`);
|
|
441
|
-
throw new HydrationBindingError(details.join("\n"), factory, createRangeForNodes(this.firstChild, this.lastChild).cloneContents(), templateString);
|
|
442
|
-
}
|
|
443
|
-
}
|
|
444
|
-
}
|
|
445
|
-
else {
|
|
446
|
-
if (this.source !== null) {
|
|
447
|
-
this.evaluateUnbindables();
|
|
448
|
-
}
|
|
449
|
-
this.isBound = false;
|
|
450
|
-
this.source = source;
|
|
451
|
-
this.context = context;
|
|
452
|
-
for (let i = 0, ii = behaviors.length; i < ii; ++i) {
|
|
453
|
-
behaviors[i].bind(this);
|
|
454
|
-
}
|
|
455
|
-
}
|
|
456
|
-
this.isBound = true;
|
|
457
|
-
this._hydrationStage = HydrationStage.hydrated;
|
|
458
|
-
}
|
|
459
|
-
unbind() {
|
|
460
|
-
if (!this.isBound || this.source === null) {
|
|
461
|
-
return;
|
|
462
|
-
}
|
|
463
|
-
this.evaluateUnbindables();
|
|
464
|
-
this.source = null;
|
|
465
|
-
this.context = this;
|
|
466
|
-
this.isBound = false;
|
|
467
|
-
}
|
|
468
|
-
/**
|
|
469
|
-
* Removes the view and unbinds its behaviors, disposing of DOM nodes afterward.
|
|
470
|
-
* Once a view has been disposed, it cannot be inserted or bound again.
|
|
471
|
-
*/
|
|
472
|
-
dispose() {
|
|
473
|
-
removeNodeSequence(this.firstChild, this.lastChild);
|
|
474
|
-
this.unbind();
|
|
475
|
-
}
|
|
476
|
-
onUnbind(behavior) {
|
|
477
|
-
this.unbindables.push(behavior);
|
|
478
|
-
}
|
|
479
|
-
evaluateUnbindables() {
|
|
480
|
-
const unbindables = this.unbindables;
|
|
481
|
-
for (let i = 0, ii = unbindables.length; i < ii; ++i) {
|
|
482
|
-
unbindables[i].unbind(this);
|
|
483
|
-
}
|
|
484
|
-
unbindables.length = 0;
|
|
485
|
-
}
|
|
486
|
-
}
|
|
487
|
-
_a = Hydratable;
|
|
488
|
-
makeSerializationNoop(HydrationView);
|