@typed/template 0.14.0 → 1.0.0-beta.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +121 -2
- package/dist/EventHandler.d.ts +273 -0
- package/dist/EventHandler.d.ts.map +1 -0
- package/dist/EventHandler.js +261 -0
- package/dist/EventSource.d.ts +82 -0
- package/dist/EventSource.d.ts.map +1 -0
- package/dist/EventSource.js +127 -0
- package/dist/Html.d.ts +122 -0
- package/dist/Html.d.ts.map +1 -0
- package/dist/Html.js +250 -0
- package/dist/HtmlChunk.d.ts +118 -0
- package/dist/HtmlChunk.d.ts.map +1 -0
- package/dist/HtmlChunk.js +211 -0
- package/dist/HydrateContext.d.ts +28 -0
- package/dist/HydrateContext.d.ts.map +1 -0
- package/dist/HydrateContext.js +25 -0
- package/dist/Parser.d.ts +35 -0
- package/dist/Parser.d.ts.map +1 -0
- package/dist/Parser.js +437 -0
- package/dist/Render.d.ts +195 -0
- package/dist/Render.d.ts.map +1 -0
- package/dist/Render.js +609 -0
- package/dist/RenderEvent.d.ts +179 -0
- package/dist/RenderEvent.d.ts.map +1 -0
- package/dist/RenderEvent.js +102 -0
- package/dist/RenderQueue.d.ts +167 -0
- package/dist/RenderQueue.d.ts.map +1 -0
- package/dist/RenderQueue.js +298 -0
- package/dist/RenderTemplate.d.ts +90 -0
- package/dist/RenderTemplate.d.ts.map +1 -0
- package/dist/RenderTemplate.js +87 -0
- package/dist/Renderable.d.ts +88 -0
- package/dist/Renderable.d.ts.map +1 -0
- package/dist/Renderable.js +3 -0
- package/dist/{dts/Template.d.ts → Template.d.ts} +109 -74
- package/dist/Template.d.ts.map +1 -0
- package/dist/{esm/Template.js → Template.js} +96 -56
- package/dist/Wire.d.ts +169 -0
- package/dist/Wire.d.ts.map +1 -0
- package/dist/Wire.js +217 -0
- package/dist/errors.d.ts +145 -0
- package/dist/errors.d.ts.map +1 -0
- package/dist/errors.js +159 -0
- package/dist/index.d.ts +15 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +14 -0
- package/dist/internal/IndexRefCounter.d.ts +11 -0
- package/dist/internal/IndexRefCounter.d.ts.map +1 -0
- package/dist/internal/IndexRefCounter.js +42 -0
- package/dist/internal/ParentChildNodes.d.ts +6 -0
- package/dist/internal/ParentChildNodes.d.ts.map +1 -0
- package/dist/internal/ParentChildNodes.js +1 -0
- package/dist/internal/PathStack.d.ts +9 -0
- package/dist/internal/PathStack.d.ts.map +1 -0
- package/dist/internal/PathStack.js +18 -0
- package/dist/internal/buildTemplateFragement.d.ts +3 -0
- package/dist/internal/buildTemplateFragement.d.ts.map +1 -0
- package/dist/internal/buildTemplateFragement.js +61 -0
- package/dist/internal/diff.d.ts +2 -0
- package/dist/internal/diff.d.ts.map +1 -0
- package/dist/internal/diff.js +119 -0
- package/dist/internal/dom.d.ts +45 -0
- package/dist/internal/dom.d.ts.map +1 -0
- package/dist/internal/dom.js +304 -0
- package/dist/internal/encoding.d.ts +7 -0
- package/dist/internal/encoding.d.ts.map +1 -0
- package/dist/internal/encoding.js +134 -0
- package/dist/{dts/internal/v2/hydration-template.d.ts → internal/hydration.d.ts} +10 -7
- package/dist/internal/hydration.d.ts.map +1 -0
- package/dist/{esm/internal/v2/hydration-template.js → internal/hydration.js} +80 -26
- package/dist/internal/keyToPartType.d.ts +2 -0
- package/dist/internal/keyToPartType.d.ts.map +1 -0
- package/dist/internal/keyToPartType.js +110 -0
- package/dist/internal/meta.d.ts +17 -0
- package/dist/internal/meta.d.ts.map +1 -0
- package/dist/internal/meta.js +14 -0
- package/dist/internal/takeOneIfNotRenderEvent.d.ts +4 -0
- package/dist/internal/takeOneIfNotRenderEvent.d.ts.map +1 -0
- package/dist/internal/takeOneIfNotRenderEvent.js +10 -0
- package/dist/internal/templateHash.d.ts +2 -0
- package/dist/internal/templateHash.d.ts.map +1 -0
- package/dist/internal/templateHash.js +14 -0
- package/dist/many.d.ts +68 -0
- package/dist/many.d.ts.map +1 -0
- package/dist/many.js +107 -0
- package/package.json +29 -227
- package/src/EventHandler.ts +318 -86
- package/src/EventSource.ts +202 -0
- package/src/Html.test.ts +490 -0
- package/src/Html.ts +292 -333
- package/src/HtmlChunk.ts +290 -332
- package/src/HydrateContext.ts +40 -0
- package/src/Hydration.test.ts +408 -0
- package/src/Parser.test.ts +923 -0
- package/src/Parser.ts +598 -10
- package/src/Render.test.ts +337 -0
- package/src/Render.ts +878 -63
- package/src/RenderEvent.ts +169 -40
- package/src/RenderQueue.ts +291 -385
- package/src/RenderTemplate.ts +98 -31
- package/src/Renderable.ts +122 -24
- package/src/Template.ts +246 -145
- package/src/Wire.ts +309 -0
- package/src/errors.ts +173 -0
- package/src/index.ts +14 -66
- package/src/internal/IndexRefCounter.ts +53 -0
- package/src/internal/ParentChildNodes.ts +7 -0
- package/src/internal/PathStack.ts +23 -0
- package/src/internal/buildTemplateFragement.ts +82 -0
- package/src/internal/diff.ts +127 -0
- package/src/internal/dom.ts +357 -0
- package/src/internal/encoding.ts +147 -0
- package/src/internal/hydration.ts +406 -0
- package/src/internal/keyToPartType.ts +113 -0
- package/src/internal/meta.ts +25 -0
- package/src/internal/takeOneIfNotRenderEvent.ts +19 -0
- package/src/internal/templateHash.ts +18 -0
- package/src/many.ts +148 -0
- package/Directive/package.json +0 -6
- package/ElementRef/package.json +0 -6
- package/ElementSource/package.json +0 -6
- package/Entry/package.json +0 -6
- package/EventHandler/package.json +0 -6
- package/Html/package.json +0 -6
- package/HtmlChunk/package.json +0 -6
- package/Hydrate/package.json +0 -6
- package/LICENSE +0 -21
- package/Many/package.json +0 -6
- package/Meta/package.json +0 -6
- package/Parser/package.json +0 -6
- package/Part/package.json +0 -6
- package/Placeholder/package.json +0 -6
- package/Platform/package.json +0 -6
- package/Render/package.json +0 -6
- package/RenderContext/package.json +0 -6
- package/RenderEvent/package.json +0 -6
- package/RenderQueue/package.json +0 -6
- package/RenderTemplate/package.json +0 -6
- package/Renderable/package.json +0 -6
- package/Template/package.json +0 -6
- package/Test/package.json +0 -6
- package/Vitest/package.json +0 -6
- package/compiler-tools/package.json +0 -6
- package/dist/cjs/Directive.js +0 -76
- package/dist/cjs/Directive.js.map +0 -1
- package/dist/cjs/ElementRef.js +0 -92
- package/dist/cjs/ElementRef.js.map +0 -1
- package/dist/cjs/ElementSource.js +0 -246
- package/dist/cjs/ElementSource.js.map +0 -1
- package/dist/cjs/Entry.js +0 -6
- package/dist/cjs/Entry.js.map +0 -1
- package/dist/cjs/EventHandler.js +0 -76
- package/dist/cjs/EventHandler.js.map +0 -1
- package/dist/cjs/Html.js +0 -224
- package/dist/cjs/Html.js.map +0 -1
- package/dist/cjs/HtmlChunk.js +0 -306
- package/dist/cjs/HtmlChunk.js.map +0 -1
- package/dist/cjs/Hydrate.js +0 -43
- package/dist/cjs/Hydrate.js.map +0 -1
- package/dist/cjs/Many.js +0 -66
- package/dist/cjs/Many.js.map +0 -1
- package/dist/cjs/Meta.js +0 -50
- package/dist/cjs/Meta.js.map +0 -1
- package/dist/cjs/Parser.js +0 -19
- package/dist/cjs/Parser.js.map +0 -1
- package/dist/cjs/Part.js +0 -6
- package/dist/cjs/Part.js.map +0 -1
- package/dist/cjs/Placeholder.js +0 -34
- package/dist/cjs/Placeholder.js.map +0 -1
- package/dist/cjs/Platform.js +0 -65
- package/dist/cjs/Platform.js.map +0 -1
- package/dist/cjs/Render.js +0 -50
- package/dist/cjs/Render.js.map +0 -1
- package/dist/cjs/RenderContext.js +0 -67
- package/dist/cjs/RenderContext.js.map +0 -1
- package/dist/cjs/RenderEvent.js +0 -52
- package/dist/cjs/RenderEvent.js.map +0 -1
- package/dist/cjs/RenderQueue.js +0 -343
- package/dist/cjs/RenderQueue.js.map +0 -1
- package/dist/cjs/RenderTemplate.js +0 -26
- package/dist/cjs/RenderTemplate.js.map +0 -1
- package/dist/cjs/Renderable.js +0 -6
- package/dist/cjs/Renderable.js.map +0 -1
- package/dist/cjs/Template.js +0 -305
- package/dist/cjs/Template.js.map +0 -1
- package/dist/cjs/Test.js +0 -184
- package/dist/cjs/Test.js.map +0 -1
- package/dist/cjs/Vitest.js +0 -52
- package/dist/cjs/Vitest.js.map +0 -1
- package/dist/cjs/compiler-tools.js +0 -100
- package/dist/cjs/compiler-tools.js.map +0 -1
- package/dist/cjs/index.js +0 -138
- package/dist/cjs/index.js.map +0 -1
- package/dist/cjs/internal/EventSource.js +0 -129
- package/dist/cjs/internal/EventSource.js.map +0 -1
- package/dist/cjs/internal/HydrateContext.js +0 -13
- package/dist/cjs/internal/HydrateContext.js.map +0 -1
- package/dist/cjs/internal/browser.js +0 -110
- package/dist/cjs/internal/browser.js.map +0 -1
- package/dist/cjs/internal/character-entities.js +0 -2141
- package/dist/cjs/internal/character-entities.js.map +0 -1
- package/dist/cjs/internal/chunks.js +0 -68
- package/dist/cjs/internal/chunks.js.map +0 -1
- package/dist/cjs/internal/errors.js +0 -52
- package/dist/cjs/internal/errors.js.map +0 -1
- package/dist/cjs/internal/indexRefCounter.js +0 -52
- package/dist/cjs/internal/indexRefCounter.js.map +0 -1
- package/dist/cjs/internal/module-augmentation.js +0 -6
- package/dist/cjs/internal/module-augmentation.js.map +0 -1
- package/dist/cjs/internal/parser.js +0 -568
- package/dist/cjs/internal/parser.js.map +0 -1
- package/dist/cjs/internal/parser2.js +0 -382
- package/dist/cjs/internal/parser2.js.map +0 -1
- package/dist/cjs/internal/server-parts.js +0 -124
- package/dist/cjs/internal/server-parts.js.map +0 -1
- package/dist/cjs/internal/server.js +0 -48
- package/dist/cjs/internal/server.js.map +0 -1
- package/dist/cjs/internal/utils.js +0 -136
- package/dist/cjs/internal/utils.js.map +0 -1
- package/dist/cjs/internal/v2/SyncPart.js +0 -6
- package/dist/cjs/internal/v2/SyncPart.js.map +0 -1
- package/dist/cjs/internal/v2/helpers.js +0 -15
- package/dist/cjs/internal/v2/helpers.js.map +0 -1
- package/dist/cjs/internal/v2/hydration-template.js +0 -269
- package/dist/cjs/internal/v2/hydration-template.js.map +0 -1
- package/dist/cjs/internal/v2/parts.js +0 -169
- package/dist/cjs/internal/v2/parts.js.map +0 -1
- package/dist/cjs/internal/v2/render-entry.js +0 -110
- package/dist/cjs/internal/v2/render-entry.js.map +0 -1
- package/dist/cjs/internal/v2/render-sync-parts.js +0 -318
- package/dist/cjs/internal/v2/render-sync-parts.js.map +0 -1
- package/dist/cjs/internal/v2/render.js +0 -592
- package/dist/cjs/internal/v2/render.js.map +0 -1
- package/dist/cjs/internal/v2/sync-parts.js +0 -115
- package/dist/cjs/internal/v2/sync-parts.js.map +0 -1
- package/dist/dts/Directive.d.ts +0 -70
- package/dist/dts/Directive.d.ts.map +0 -1
- package/dist/dts/ElementRef.d.ts +0 -42
- package/dist/dts/ElementRef.d.ts.map +0 -1
- package/dist/dts/ElementSource.d.ts +0 -79
- package/dist/dts/ElementSource.d.ts.map +0 -1
- package/dist/dts/Entry.d.ts +0 -26
- package/dist/dts/Entry.d.ts.map +0 -1
- package/dist/dts/EventHandler.d.ts +0 -73
- package/dist/dts/EventHandler.d.ts.map +0 -1
- package/dist/dts/Html.d.ts +0 -35
- package/dist/dts/Html.d.ts.map +0 -1
- package/dist/dts/HtmlChunk.d.ts +0 -56
- package/dist/dts/HtmlChunk.d.ts.map +0 -1
- package/dist/dts/Hydrate.d.ts +0 -19
- package/dist/dts/Hydrate.d.ts.map +0 -1
- package/dist/dts/Many.d.ts +0 -32
- package/dist/dts/Many.d.ts.map +0 -1
- package/dist/dts/Meta.d.ts +0 -33
- package/dist/dts/Meta.d.ts.map +0 -1
- package/dist/dts/Parser.d.ts +0 -13
- package/dist/dts/Parser.d.ts.map +0 -1
- package/dist/dts/Part.d.ts +0 -121
- package/dist/dts/Part.d.ts.map +0 -1
- package/dist/dts/Placeholder.d.ts +0 -48
- package/dist/dts/Placeholder.d.ts.map +0 -1
- package/dist/dts/Platform.d.ts +0 -21
- package/dist/dts/Platform.d.ts.map +0 -1
- package/dist/dts/Render.d.ts +0 -31
- package/dist/dts/Render.d.ts.map +0 -1
- package/dist/dts/RenderContext.d.ts +0 -70
- package/dist/dts/RenderContext.d.ts.map +0 -1
- package/dist/dts/RenderEvent.d.ts +0 -42
- package/dist/dts/RenderEvent.d.ts.map +0 -1
- package/dist/dts/RenderQueue.d.ts +0 -103
- package/dist/dts/RenderQueue.d.ts.map +0 -1
- package/dist/dts/RenderTemplate.d.ts +0 -25
- package/dist/dts/RenderTemplate.d.ts.map +0 -1
- package/dist/dts/Renderable.d.ts +0 -28
- package/dist/dts/Renderable.d.ts.map +0 -1
- package/dist/dts/Template.d.ts.map +0 -1
- package/dist/dts/Test.d.ts +0 -85
- package/dist/dts/Test.d.ts.map +0 -1
- package/dist/dts/Vitest.d.ts +0 -43
- package/dist/dts/Vitest.d.ts.map +0 -1
- package/dist/dts/compiler-tools.d.ts +0 -143
- package/dist/dts/compiler-tools.d.ts.map +0 -1
- package/dist/dts/index.d.ts +0 -65
- package/dist/dts/index.d.ts.map +0 -1
- package/dist/dts/internal/EventSource.d.ts +0 -13
- package/dist/dts/internal/EventSource.d.ts.map +0 -1
- package/dist/dts/internal/HydrateContext.d.ts +0 -2
- package/dist/dts/internal/HydrateContext.d.ts.map +0 -1
- package/dist/dts/internal/browser.d.ts +0 -8
- package/dist/dts/internal/browser.d.ts.map +0 -1
- package/dist/dts/internal/character-entities.d.ts +0 -2133
- package/dist/dts/internal/character-entities.d.ts.map +0 -1
- package/dist/dts/internal/chunks.d.ts +0 -23
- package/dist/dts/internal/chunks.d.ts.map +0 -1
- package/dist/dts/internal/errors.d.ts +0 -22
- package/dist/dts/internal/errors.d.ts.map +0 -1
- package/dist/dts/internal/indexRefCounter.d.ts +0 -7
- package/dist/dts/internal/indexRefCounter.d.ts.map +0 -1
- package/dist/dts/internal/module-augmentation.d.ts +0 -32
- package/dist/dts/internal/module-augmentation.d.ts.map +0 -1
- package/dist/dts/internal/parser.d.ts +0 -33
- package/dist/dts/internal/parser.d.ts.map +0 -1
- package/dist/dts/internal/parser2.d.ts +0 -12
- package/dist/dts/internal/parser2.d.ts.map +0 -1
- package/dist/dts/internal/server-parts.d.ts +0 -223
- package/dist/dts/internal/server-parts.d.ts.map +0 -1
- package/dist/dts/internal/server.d.ts +0 -5
- package/dist/dts/internal/server.d.ts.map +0 -1
- package/dist/dts/internal/utils.d.ts +0 -19
- package/dist/dts/internal/utils.d.ts.map +0 -1
- package/dist/dts/internal/v2/SyncPart.d.ts +0 -87
- package/dist/dts/internal/v2/SyncPart.d.ts.map +0 -1
- package/dist/dts/internal/v2/helpers.d.ts +0 -3
- package/dist/dts/internal/v2/helpers.d.ts.map +0 -1
- package/dist/dts/internal/v2/hydration-template.d.ts.map +0 -1
- package/dist/dts/internal/v2/parts.d.ts +0 -245
- package/dist/dts/internal/v2/parts.d.ts.map +0 -1
- package/dist/dts/internal/v2/render-entry.d.ts +0 -6
- package/dist/dts/internal/v2/render-entry.d.ts.map +0 -1
- package/dist/dts/internal/v2/render-sync-parts.d.ts +0 -22
- package/dist/dts/internal/v2/render-sync-parts.d.ts.map +0 -1
- package/dist/dts/internal/v2/render.d.ts +0 -83
- package/dist/dts/internal/v2/render.d.ts.map +0 -1
- package/dist/dts/internal/v2/sync-parts.d.ts +0 -129
- package/dist/dts/internal/v2/sync-parts.d.ts.map +0 -1
- package/dist/esm/Directive.js +0 -64
- package/dist/esm/Directive.js.map +0 -1
- package/dist/esm/ElementRef.js +0 -76
- package/dist/esm/ElementRef.js.map +0 -1
- package/dist/esm/ElementSource.js +0 -246
- package/dist/esm/ElementSource.js.map +0 -1
- package/dist/esm/Entry.js +0 -2
- package/dist/esm/Entry.js.map +0 -1
- package/dist/esm/EventHandler.js +0 -68
- package/dist/esm/EventHandler.js.map +0 -1
- package/dist/esm/Html.js +0 -230
- package/dist/esm/Html.js.map +0 -1
- package/dist/esm/HtmlChunk.js +0 -330
- package/dist/esm/HtmlChunk.js.map +0 -1
- package/dist/esm/Hydrate.js +0 -31
- package/dist/esm/Hydrate.js.map +0 -1
- package/dist/esm/Many.js +0 -54
- package/dist/esm/Many.js.map +0 -1
- package/dist/esm/Meta.js +0 -40
- package/dist/esm/Meta.js.map +0 -1
- package/dist/esm/Parser.js +0 -13
- package/dist/esm/Parser.js.map +0 -1
- package/dist/esm/Part.js +0 -5
- package/dist/esm/Part.js.map +0 -1
- package/dist/esm/Placeholder.js +0 -26
- package/dist/esm/Placeholder.js.map +0 -1
- package/dist/esm/Platform.js +0 -42
- package/dist/esm/Platform.js.map +0 -1
- package/dist/esm/Render.js +0 -36
- package/dist/esm/Render.js.map +0 -1
- package/dist/esm/RenderContext.js +0 -54
- package/dist/esm/RenderContext.js.map +0 -1
- package/dist/esm/RenderEvent.js +0 -43
- package/dist/esm/RenderEvent.js.map +0 -1
- package/dist/esm/RenderQueue.js +0 -338
- package/dist/esm/RenderQueue.js.map +0 -1
- package/dist/esm/RenderTemplate.js +0 -16
- package/dist/esm/RenderTemplate.js.map +0 -1
- package/dist/esm/Renderable.js +0 -2
- package/dist/esm/Renderable.js.map +0 -1
- package/dist/esm/Template.js.map +0 -1
- package/dist/esm/Test.js +0 -167
- package/dist/esm/Test.js.map +0 -1
- package/dist/esm/Vitest.js +0 -44
- package/dist/esm/Vitest.js.map +0 -1
- package/dist/esm/compiler-tools.js +0 -91
- package/dist/esm/compiler-tools.js.map +0 -1
- package/dist/esm/index.js +0 -65
- package/dist/esm/index.js.map +0 -1
- package/dist/esm/internal/EventSource.js +0 -126
- package/dist/esm/internal/EventSource.js.map +0 -1
- package/dist/esm/internal/HydrateContext.js +0 -7
- package/dist/esm/internal/HydrateContext.js.map +0 -1
- package/dist/esm/internal/browser.js +0 -103
- package/dist/esm/internal/browser.js.map +0 -1
- package/dist/esm/internal/character-entities.js +0 -2134
- package/dist/esm/internal/character-entities.js.map +0 -1
- package/dist/esm/internal/chunks.js +0 -60
- package/dist/esm/internal/chunks.js.map +0 -1
- package/dist/esm/internal/errors.js +0 -46
- package/dist/esm/internal/errors.js.map +0 -1
- package/dist/esm/internal/indexRefCounter.js +0 -47
- package/dist/esm/internal/indexRefCounter.js.map +0 -1
- package/dist/esm/internal/module-augmentation.js +0 -2
- package/dist/esm/internal/module-augmentation.js.map +0 -1
- package/dist/esm/internal/parser.js +0 -596
- package/dist/esm/internal/parser.js.map +0 -1
- package/dist/esm/internal/parser2.js +0 -393
- package/dist/esm/internal/parser2.js.map +0 -1
- package/dist/esm/internal/server-parts.js +0 -109
- package/dist/esm/internal/server-parts.js.map +0 -1
- package/dist/esm/internal/server.js +0 -22
- package/dist/esm/internal/server.js.map +0 -1
- package/dist/esm/internal/utils.js +0 -119
- package/dist/esm/internal/utils.js.map +0 -1
- package/dist/esm/internal/v2/SyncPart.js +0 -5
- package/dist/esm/internal/v2/SyncPart.js.map +0 -1
- package/dist/esm/internal/v2/helpers.js +0 -12
- package/dist/esm/internal/v2/helpers.js.map +0 -1
- package/dist/esm/internal/v2/hydration-template.js.map +0 -1
- package/dist/esm/internal/v2/parts.js +0 -150
- package/dist/esm/internal/v2/parts.js.map +0 -1
- package/dist/esm/internal/v2/render-entry.js +0 -102
- package/dist/esm/internal/v2/render-entry.js.map +0 -1
- package/dist/esm/internal/v2/render-sync-parts.js +0 -265
- package/dist/esm/internal/v2/render-sync-parts.js.map +0 -1
- package/dist/esm/internal/v2/render.js +0 -521
- package/dist/esm/internal/v2/render.js.map +0 -1
- package/dist/esm/internal/v2/sync-parts.js +0 -102
- package/dist/esm/internal/v2/sync-parts.js.map +0 -1
- package/dist/esm/package.json +0 -4
- package/src/Directive.ts +0 -114
- package/src/ElementRef.ts +0 -148
- package/src/ElementSource.ts +0 -510
- package/src/Entry.ts +0 -28
- package/src/Hydrate.ts +0 -51
- package/src/Many.ts +0 -161
- package/src/Meta.ts +0 -45
- package/src/Part.ts +0 -154
- package/src/Placeholder.ts +0 -78
- package/src/Platform.ts +0 -70
- package/src/RenderContext.ts +0 -121
- package/src/Test.ts +0 -354
- package/src/Vitest.ts +0 -141
- package/src/compiler-tools.ts +0 -250
- package/src/internal/EventSource.ts +0 -188
- package/src/internal/HydrateContext.ts +0 -22
- package/src/internal/browser.ts +0 -138
- package/src/internal/character-entities.ts +0 -2136
- package/src/internal/chunks.ts +0 -89
- package/src/internal/errors.ts +0 -49
- package/src/internal/external.d.ts +0 -11
- package/src/internal/indexRefCounter.ts +0 -54
- package/src/internal/module-augmentation.ts +0 -44
- package/src/internal/parser.ts +0 -757
- package/src/internal/parser2.ts +0 -468
- package/src/internal/server-parts.ts +0 -161
- package/src/internal/server.ts +0 -37
- package/src/internal/utils.ts +0 -153
- package/src/internal/v2/SyncPart.ts +0 -112
- package/src/internal/v2/helpers.ts +0 -13
- package/src/internal/v2/hydration-template.ts +0 -308
- package/src/internal/v2/parts.ts +0 -254
- package/src/internal/v2/render-entry.ts +0 -131
- package/src/internal/v2/render-sync-parts.ts +0 -440
- package/src/internal/v2/render.ts +0 -813
- package/src/internal/v2/sync-parts.ts +0 -133
package/src/Render.ts
CHANGED
|
@@ -1,84 +1,899 @@
|
|
|
1
|
+
import * as Cause from "effect/Cause";
|
|
2
|
+
import * as Effect from "effect/Effect";
|
|
3
|
+
import { constVoid, dual, flow, identity } from "effect/Function";
|
|
4
|
+
import * as Layer from "effect/Layer";
|
|
5
|
+
import { getOrUndefined, isNone, isOption, type Some } from "effect/Option";
|
|
6
|
+
import { isFunction, isNullish, isObject } from "effect/Predicate";
|
|
7
|
+
import { map as mapRecord } from "effect/Record";
|
|
8
|
+
import * as Scope from "effect/Scope";
|
|
9
|
+
import * as ServiceMap from "effect/ServiceMap";
|
|
10
|
+
import { isStream } from "effect/Stream";
|
|
11
|
+
import { Fx, Sink } from "@typed/fx";
|
|
12
|
+
import { CouldNotFindCommentError, isHydrationError } from "./errors.js";
|
|
13
|
+
import * as EventHandler from "./EventHandler.js";
|
|
14
|
+
import { type EventSource, makeEventSource } from "./EventSource.js";
|
|
15
|
+
import { HydrateContext, makeHydrateContext } from "./HydrateContext.js";
|
|
16
|
+
import { buildTemplateFragment } from "./internal/buildTemplateFragement.js";
|
|
17
|
+
import {
|
|
18
|
+
findNodePartEndComment,
|
|
19
|
+
getClassList,
|
|
20
|
+
makeAttributeValueUpdater,
|
|
21
|
+
makeBooleanUpdater,
|
|
22
|
+
makeClassListUpdater,
|
|
23
|
+
makeDatasetUpdater,
|
|
24
|
+
makeNodeUpdater,
|
|
25
|
+
makeTextContentUpdater,
|
|
26
|
+
} from "./internal/dom.js";
|
|
27
|
+
import { renderToString } from "./internal/encoding.js";
|
|
28
|
+
import type { HydrationHole, HydrationNode, HydrationTemplate } from "./internal/hydration.js";
|
|
29
|
+
import {
|
|
30
|
+
findHydratePath,
|
|
31
|
+
findHydrationHole,
|
|
32
|
+
findHydrationTemplateByHash,
|
|
33
|
+
getChildNodes,
|
|
34
|
+
getRendered,
|
|
35
|
+
} from "./internal/hydration.js";
|
|
36
|
+
import { type IndexRefCounter, makeRefCounter } from "./internal/IndexRefCounter.js";
|
|
37
|
+
import { keyToPartType } from "./internal/keyToPartType.js";
|
|
38
|
+
import { findPath } from "./internal/ParentChildNodes.js";
|
|
39
|
+
import { parse } from "./Parser.js";
|
|
40
|
+
import type { Renderable } from "./Renderable.js";
|
|
41
|
+
import { DomRenderEvent, type RenderEvent } from "./RenderEvent.js";
|
|
42
|
+
import * as RQ from "./RenderQueue.js";
|
|
43
|
+
import { RenderTemplate } from "./RenderTemplate.js";
|
|
44
|
+
import * as Template from "./Template.js";
|
|
45
|
+
import { getAllSiblingsBetween, isText, persistent, type Rendered } from "./Wire.js";
|
|
46
|
+
|
|
47
|
+
// Can be utilized to override the document for rendering
|
|
1
48
|
/**
|
|
49
|
+
* A service that provides the `Document` interface for rendering.
|
|
50
|
+
*
|
|
51
|
+
* Defaults to the global `document` object. This can be overridden for testing
|
|
52
|
+
* or environments where the global document is not available or desired.
|
|
53
|
+
*
|
|
54
|
+
* @example
|
|
55
|
+
* ```ts
|
|
56
|
+
* import { CurrentRenderDocument } from "@typed/template/Render"
|
|
57
|
+
* import { Layer } from "effect"
|
|
58
|
+
*
|
|
59
|
+
* // Override document for testing
|
|
60
|
+
* const testDocument = new Document()
|
|
61
|
+
* const testLayer = Layer.succeed(CurrentRenderDocument, testDocument)
|
|
62
|
+
* ```
|
|
63
|
+
*
|
|
2
64
|
* @since 1.0.0
|
|
65
|
+
* @category services
|
|
3
66
|
*/
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
import type { DomServices, DomServicesElementParams } from "@typed/dom/DomServices"
|
|
8
|
-
import type { GlobalThis } from "@typed/dom/GlobalThis"
|
|
9
|
-
import { RootElement } from "@typed/dom/RootElement"
|
|
10
|
-
import type { CurrentEnvironment } from "@typed/environment"
|
|
11
|
-
import * as Fx from "@typed/fx/Fx"
|
|
12
|
-
import { type Rendered } from "@typed/wire"
|
|
13
|
-
import * as Effect from "effect/Effect"
|
|
14
|
-
import { pipe } from "effect/Function"
|
|
15
|
-
import * as Layer from "effect/Layer"
|
|
16
|
-
import type * as Scope from "effect/Scope"
|
|
17
|
-
import { attachRoot, renderTemplate } from "./internal/v2/render.js"
|
|
18
|
-
import * as RenderContext from "./RenderContext.js"
|
|
19
|
-
import { type RenderEvent } from "./RenderEvent.js"
|
|
20
|
-
import { RenderTemplate } from "./RenderTemplate.js"
|
|
67
|
+
export const CurrentRenderDocument = ServiceMap.Reference<Document>("RenderDocument", {
|
|
68
|
+
defaultValue: () => document,
|
|
69
|
+
});
|
|
21
70
|
|
|
22
71
|
/**
|
|
72
|
+
* A service that manages the queue of DOM updates.
|
|
73
|
+
*
|
|
74
|
+
* It ensures that DOM updates are batched and executed efficiently, often coordinating
|
|
75
|
+
* with browser painting cycles (e.g., via `requestAnimationFrame`).
|
|
76
|
+
*
|
|
77
|
+
* @example
|
|
78
|
+
* ```ts
|
|
79
|
+
* import { CurrentRenderQueue } from "@typed/template/Render"
|
|
80
|
+
* import { MixedRenderQueue } from "@typed/template/RenderQueue"
|
|
81
|
+
* import { Layer } from "effect"
|
|
82
|
+
*
|
|
83
|
+
* // Use a custom render queue
|
|
84
|
+
* const customQueue = new MixedRenderQueue()
|
|
85
|
+
* const queueLayer = Layer.succeed(CurrentRenderQueue, customQueue)
|
|
86
|
+
* ```
|
|
87
|
+
*
|
|
23
88
|
* @since 1.0.0
|
|
89
|
+
* @category services
|
|
24
90
|
*/
|
|
25
|
-
export
|
|
91
|
+
export const CurrentRenderQueue = ServiceMap.Reference<RQ.RenderQueue>("RenderQueue", {
|
|
92
|
+
defaultValue: () => new RQ.MixedRenderQueue(),
|
|
93
|
+
});
|
|
26
94
|
|
|
27
95
|
/**
|
|
96
|
+
* A service that provides the default priority for rendering tasks.
|
|
97
|
+
*
|
|
98
|
+
* The default value is `RenderPriority.Raf(10)`, which typically schedules updates
|
|
99
|
+
* to occur before the next repaint.
|
|
100
|
+
*
|
|
101
|
+
* @example
|
|
102
|
+
* ```ts
|
|
103
|
+
* import { CurrentRenderPriority } from "@typed/template/Render"
|
|
104
|
+
* import { RenderPriority } from "@typed/template/RenderQueue"
|
|
105
|
+
* import { Layer } from "effect"
|
|
106
|
+
*
|
|
107
|
+
* // Use synchronous priority for immediate updates
|
|
108
|
+
* const syncLayer = Layer.succeed(CurrentRenderPriority, RenderPriority.Sync)
|
|
109
|
+
* ```
|
|
110
|
+
*
|
|
28
111
|
* @since 1.0.0
|
|
112
|
+
* @category services
|
|
29
113
|
*/
|
|
30
|
-
export const
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
): Layer.Layer<
|
|
34
|
-
| RenderTemplate
|
|
35
|
-
| RenderContext.RenderContext
|
|
36
|
-
| CurrentEnvironment
|
|
37
|
-
| DomServices
|
|
38
|
-
> =>
|
|
39
|
-
Layer.provideMerge(
|
|
40
|
-
RenderTemplate.layer(
|
|
41
|
-
Effect.contextWith(
|
|
42
|
-
(context: Context.Context<Document | RenderContext.RenderContext>) => {
|
|
43
|
-
const [document, ctx] = pipe(
|
|
44
|
-
context,
|
|
45
|
-
Context.getMany(
|
|
46
|
-
Document,
|
|
47
|
-
RenderContext.RenderContext
|
|
48
|
-
)
|
|
49
|
-
)
|
|
50
|
-
|
|
51
|
-
return renderTemplate(document, ctx)
|
|
52
|
-
}
|
|
53
|
-
)
|
|
54
|
-
),
|
|
55
|
-
RenderContext.dom(window, options)
|
|
56
|
-
)
|
|
114
|
+
export const CurrentRenderPriority = ServiceMap.Reference<number>("CurrentRenderPriority", {
|
|
115
|
+
defaultValue: () => RQ.RenderPriority.Raf(10),
|
|
116
|
+
});
|
|
57
117
|
|
|
58
118
|
/**
|
|
119
|
+
* A Layer that provides the `RenderTemplate` service implemented for DOM rendering.
|
|
120
|
+
*
|
|
121
|
+
* This layer enables templates to be rendered as actual DOM nodes. It handles:
|
|
122
|
+
* - Parsing templates into DOM fragments.
|
|
123
|
+
* - Caching parsed templates.
|
|
124
|
+
* - Hydrating from existing DOM (if applicable).
|
|
125
|
+
* - Setting up event listeners.
|
|
126
|
+
* - Managing fine-grained updates to DOM nodes via `Fx` streams.
|
|
127
|
+
*
|
|
128
|
+
* @example
|
|
129
|
+
* ```ts
|
|
130
|
+
* import { Effect, Layer } from "effect"
|
|
131
|
+
* import { html } from "@typed/template"
|
|
132
|
+
* import { DomRenderTemplate, render } from "@typed/template/Render"
|
|
133
|
+
* import { Fx } from "@typed/fx"
|
|
134
|
+
*
|
|
135
|
+
* const program = Effect.gen(function* () {
|
|
136
|
+
* const template = html`<div>Hello, world!</div>`
|
|
137
|
+
*
|
|
138
|
+
* yield* render(template, document.body).pipe(
|
|
139
|
+
* Fx.drainLayer,
|
|
140
|
+
* Layer.provide(DomRenderTemplate),
|
|
141
|
+
* Layer.launch
|
|
142
|
+
* )
|
|
143
|
+
* })
|
|
144
|
+
* ```
|
|
145
|
+
*
|
|
59
146
|
* @since 1.0.0
|
|
147
|
+
* @category layers
|
|
60
148
|
*/
|
|
61
|
-
export
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
149
|
+
export const DomRenderTemplate = Object.assign(
|
|
150
|
+
Layer.effect(
|
|
151
|
+
RenderTemplate,
|
|
152
|
+
Effect.gen(function* () {
|
|
153
|
+
const document = yield* CurrentRenderDocument;
|
|
154
|
+
const templateCache = new WeakMap<TemplateStringsArray, Template.Template>();
|
|
155
|
+
const getTemplate = (templateStrings: TemplateStringsArray) => {
|
|
156
|
+
let template = templateCache.get(templateStrings);
|
|
157
|
+
if (template === undefined) {
|
|
158
|
+
template = parse(templateStrings);
|
|
159
|
+
templateCache.set(templateStrings, template);
|
|
160
|
+
}
|
|
161
|
+
return template;
|
|
162
|
+
};
|
|
163
|
+
const entries = new WeakMap<
|
|
164
|
+
TemplateStringsArray,
|
|
165
|
+
{
|
|
166
|
+
template: Template.Template;
|
|
167
|
+
fragment: DocumentFragment;
|
|
168
|
+
}
|
|
169
|
+
>();
|
|
170
|
+
const getEntry = (templateStrings: TemplateStringsArray) => {
|
|
171
|
+
let entry = entries.get(templateStrings);
|
|
172
|
+
if (entry === undefined) {
|
|
173
|
+
const template = getTemplate(templateStrings);
|
|
174
|
+
const fragment = buildTemplateFragment(document, template);
|
|
175
|
+
entry = { template, fragment };
|
|
176
|
+
entries.set(templateStrings, entry);
|
|
177
|
+
}
|
|
178
|
+
return entry;
|
|
179
|
+
};
|
|
70
180
|
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
181
|
+
return <const Values extends ArrayLike<Renderable.Any>>(
|
|
182
|
+
templateStrings: TemplateStringsArray,
|
|
183
|
+
values: Values,
|
|
184
|
+
): Fx.Fx<
|
|
185
|
+
RenderEvent,
|
|
186
|
+
Renderable.Error<Values[number]>,
|
|
187
|
+
Renderable.Services<Values[number]> | Scope.Scope
|
|
188
|
+
> =>
|
|
189
|
+
Fx.make<
|
|
190
|
+
RenderEvent,
|
|
191
|
+
Renderable.Error<Values[number]>,
|
|
192
|
+
Renderable.Services<Values[number]> | Scope.Scope
|
|
193
|
+
>(function render<RSink = never>(
|
|
194
|
+
sink: Sink.Sink<RenderEvent, Renderable.Error<Values[number]>, RSink>,
|
|
195
|
+
): Effect.Effect<
|
|
196
|
+
unknown,
|
|
197
|
+
never,
|
|
198
|
+
Renderable.Services<Values[number]> | Scope.Scope | RSink
|
|
199
|
+
> {
|
|
200
|
+
return Effect.gen(function* () {
|
|
201
|
+
const entry = getEntry(templateStrings);
|
|
202
|
+
const template = entry.template;
|
|
203
|
+
const fragment = document.importNode(entry.fragment, true);
|
|
204
|
+
const ctx = yield* makeTemplateContext<Values, RSink>(document, values, sink.onFailure);
|
|
205
|
+
|
|
206
|
+
return yield* Effect.gen(function* () {
|
|
207
|
+
const hydration = attemptHydration(ctx, template.hash);
|
|
208
|
+
|
|
209
|
+
let effects: Array<Effect.Effect<void, any, any>>;
|
|
210
|
+
let rendered: Rendered | undefined;
|
|
211
|
+
|
|
212
|
+
if (hydration) {
|
|
213
|
+
effects = setupHydrationParts(template.parts, {
|
|
214
|
+
...ctx,
|
|
215
|
+
...hydration,
|
|
216
|
+
makeHydrateContext: (where: HydrationNode): HydrateContext => ({
|
|
217
|
+
where,
|
|
218
|
+
hydrate: true,
|
|
219
|
+
}),
|
|
220
|
+
});
|
|
221
|
+
|
|
222
|
+
rendered = getRendered(hydration.where);
|
|
223
|
+
} else {
|
|
224
|
+
effects = setupRenderParts(template.parts, fragment, ctx);
|
|
225
|
+
}
|
|
226
|
+
|
|
227
|
+
if (effects.length > 0) {
|
|
228
|
+
yield* Effect.all(
|
|
229
|
+
effects.map(flow(Effect.catchCause(ctx.onCause), Effect.forkIn(ctx.scope))),
|
|
230
|
+
);
|
|
231
|
+
|
|
232
|
+
if (ctx.expected > 0 && ctx.refCounter.expect(ctx.expected)) {
|
|
233
|
+
yield* ctx.refCounter.wait;
|
|
234
|
+
}
|
|
235
|
+
}
|
|
236
|
+
|
|
237
|
+
if (rendered === undefined) {
|
|
238
|
+
// If we have more than one child, we need to wrap them in a PersistentDocumentFragment
|
|
239
|
+
// so they can be diffed within other templates more than once.
|
|
240
|
+
rendered = persistent(document, template.hash, fragment);
|
|
241
|
+
}
|
|
242
|
+
|
|
243
|
+
// Setup our event listeners for our rendered content.
|
|
244
|
+
yield* ctx.eventSource.setup(rendered, ctx.scope);
|
|
245
|
+
|
|
246
|
+
// If we're hydrating, we need to mark this part of the stack as hydrated
|
|
247
|
+
if (hydration !== undefined) {
|
|
248
|
+
hydration.hydrateCtx.hydrate = false;
|
|
249
|
+
}
|
|
250
|
+
|
|
251
|
+
// Emit just once
|
|
252
|
+
yield* sink.onSuccess(DomRenderEvent(rendered));
|
|
253
|
+
|
|
254
|
+
// Ensure our templates last forever in the DOM environment
|
|
255
|
+
// so event listeners are kept attached to the current Scope.
|
|
256
|
+
return yield* Effect.never.pipe(
|
|
257
|
+
// Close our scope whenever the current Fiber is interrupted
|
|
258
|
+
Effect.onExit((exit) => Scope.close(ctx.scope, exit)),
|
|
259
|
+
);
|
|
260
|
+
}).pipe(
|
|
261
|
+
Effect.catchDefect((defect) => {
|
|
262
|
+
// If we are hydrating and we have a hydration error, we need to re-render the template without hydration
|
|
263
|
+
if (ctx.hydrateContext && ctx.hydrateContext.hydrate && isHydrationError(defect)) {
|
|
264
|
+
ctx.hydrateContext.hydrate = false;
|
|
265
|
+
return render(sink);
|
|
266
|
+
}
|
|
267
|
+
return sink.onFailure(Cause.die(defect));
|
|
268
|
+
}),
|
|
269
|
+
);
|
|
270
|
+
});
|
|
271
|
+
});
|
|
272
|
+
}),
|
|
273
|
+
),
|
|
274
|
+
{
|
|
275
|
+
using: (document: Document) =>
|
|
276
|
+
DomRenderTemplate.pipe(Layer.provide(Layer.succeed(CurrentRenderDocument, document))),
|
|
277
|
+
} as const,
|
|
278
|
+
);
|
|
74
279
|
|
|
75
280
|
/**
|
|
281
|
+
* A helper type to determine the rendered output type.
|
|
282
|
+
*/
|
|
283
|
+
export type ToRendered<T extends RenderEvent | null> = Rendered | (T extends null ? null : never);
|
|
284
|
+
|
|
285
|
+
/**
|
|
286
|
+
* Mounts a reactive `Fx` stream of `RenderEvent`s to a specific DOM element.
|
|
287
|
+
*
|
|
288
|
+
* This function takes a stream of render events (usually from a template) and keeps
|
|
289
|
+
* the target DOM element updated. It handles:
|
|
290
|
+
* - Mounting the initial content.
|
|
291
|
+
* - Updating the content as new events are emitted.
|
|
292
|
+
* - Hydrating the content if hydration context is provided.
|
|
293
|
+
*
|
|
294
|
+
* @example
|
|
295
|
+
* ```ts
|
|
296
|
+
* import { Effect, Layer } from "effect"
|
|
297
|
+
* import { html } from "@typed/template"
|
|
298
|
+
* import { DomRenderTemplate, render } from "@typed/template/Render"
|
|
299
|
+
* import { Fx } from "@typed/fx"
|
|
300
|
+
* import * as RefSubject from "@typed/fx/RefSubject"
|
|
301
|
+
*
|
|
302
|
+
* const program = Effect.gen(function* () {
|
|
303
|
+
* const count = yield* RefSubject.make(0)
|
|
304
|
+
*
|
|
305
|
+
* const template = html`<div>
|
|
306
|
+
* <p>Count: ${count}</p>
|
|
307
|
+
* <button onclick=${RefSubject.increment(count)}>Increment</button>
|
|
308
|
+
* </div>`
|
|
309
|
+
*
|
|
310
|
+
* // Render to document.body
|
|
311
|
+
* yield* render(template, document.body).pipe(
|
|
312
|
+
* Fx.drainLayer,
|
|
313
|
+
* Layer.provide(DomRenderTemplate),
|
|
314
|
+
* Layer.launch
|
|
315
|
+
* )
|
|
316
|
+
* })
|
|
317
|
+
*
|
|
318
|
+
* // Can also use pipe syntax
|
|
319
|
+
* const program2 = Effect.gen(function* () {
|
|
320
|
+
* const template = html`<div>Hello</div>`
|
|
321
|
+
*
|
|
322
|
+
* yield* template.pipe(
|
|
323
|
+
* render(document.body),
|
|
324
|
+
* Fx.drainLayer,
|
|
325
|
+
* Layer.provide(DomRenderTemplate),
|
|
326
|
+
* Layer.launch
|
|
327
|
+
* )
|
|
328
|
+
* })
|
|
329
|
+
* ```
|
|
330
|
+
*
|
|
331
|
+
* @param fx - The `Fx` stream of content to render.
|
|
332
|
+
* @param where - The target DOM element to render into.
|
|
333
|
+
* @returns An `Fx` that emits the currently rendered DOM nodes.
|
|
76
334
|
* @since 1.0.0
|
|
335
|
+
* @category rendering
|
|
77
336
|
*/
|
|
78
|
-
export
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
337
|
+
export const render: {
|
|
338
|
+
(
|
|
339
|
+
where: HTMLElement,
|
|
340
|
+
): <A extends RenderEvent | null, E, R>(fx: Fx.Fx<A, E, R>) => Fx.Fx<ToRendered<A>, E, R>;
|
|
341
|
+
<A extends RenderEvent | null, E, R>(
|
|
342
|
+
fx: Fx.Fx<A, E, R>,
|
|
343
|
+
where: HTMLElement,
|
|
344
|
+
): Fx.Fx<ToRendered<A>, E, R>;
|
|
345
|
+
} = dual(2, function render<
|
|
346
|
+
T extends RenderEvent | null,
|
|
347
|
+
R,
|
|
348
|
+
E,
|
|
349
|
+
>(rendered: Fx.Fx<T, E, R>, rootElement: HTMLElement): Fx.Fx<ToRendered<T>, E, R> {
|
|
350
|
+
return Fx.provide(
|
|
351
|
+
Fx.mapEffect(rendered, (what) => attachRoot(rootElement, what)),
|
|
352
|
+
Layer.syncServices(() => makeHydrateContext(rootElement)),
|
|
353
|
+
);
|
|
354
|
+
});
|
|
355
|
+
|
|
356
|
+
const renderCache = new WeakMap<HTMLElement, Rendered>();
|
|
357
|
+
function attachRoot<A extends RenderEvent | null>(
|
|
358
|
+
where: HTMLElement,
|
|
359
|
+
what: A, // TODO: Should we support HTML RenderEvents here too?,
|
|
360
|
+
): Effect.Effect<ToRendered<A>> {
|
|
361
|
+
return Effect.sync(() => {
|
|
362
|
+
const rendered = what?.valueOf() as Rendered;
|
|
363
|
+
const previous = renderCache.get(where);
|
|
364
|
+
if (rendered !== previous) {
|
|
365
|
+
if (previous && !rendered) removeChildren(where, previous);
|
|
366
|
+
renderCache.set(where, rendered || null);
|
|
367
|
+
if (rendered) replaceChildren(where, rendered);
|
|
368
|
+
return rendered;
|
|
369
|
+
}
|
|
370
|
+
|
|
371
|
+
return previous;
|
|
372
|
+
});
|
|
373
|
+
}
|
|
374
|
+
|
|
375
|
+
function removeChildren(where: HTMLElement, previous: Rendered) {
|
|
376
|
+
for (const node of getNodesFromRendered(previous)) {
|
|
377
|
+
where.removeChild(node);
|
|
378
|
+
}
|
|
379
|
+
}
|
|
380
|
+
|
|
381
|
+
function replaceChildren(where: HTMLElement, wire: Rendered) {
|
|
382
|
+
where.replaceChildren(...getNodesFromRendered(wire));
|
|
383
|
+
}
|
|
384
|
+
|
|
385
|
+
function getNodesFromRendered(rendered: Rendered): Array<globalThis.Node> {
|
|
386
|
+
const value = rendered.valueOf() as globalThis.Node | Array<globalThis.Node>;
|
|
387
|
+
return Array.isArray(value) ? value : [value];
|
|
388
|
+
}
|
|
389
|
+
|
|
390
|
+
function setupRenderParts(
|
|
391
|
+
parts: Template.Template["parts"],
|
|
392
|
+
fragment: DocumentFragment,
|
|
393
|
+
ctx: TemplateContext,
|
|
394
|
+
): Array<Effect.Effect<unknown>> {
|
|
395
|
+
const effects: Array<Effect.Effect<unknown>> = [];
|
|
396
|
+
for (const [part, path] of parts) {
|
|
397
|
+
const effect = setupRenderPart(part, findPath(fragment, path), ctx);
|
|
398
|
+
if (effect !== undefined) {
|
|
399
|
+
effects.push(effect);
|
|
400
|
+
}
|
|
401
|
+
}
|
|
402
|
+
|
|
403
|
+
return effects;
|
|
404
|
+
}
|
|
405
|
+
|
|
406
|
+
const withCurrentRenderPriority = (
|
|
407
|
+
key: unknown,
|
|
408
|
+
index: number,
|
|
409
|
+
ctx: TemplateContext,
|
|
410
|
+
f: () => void,
|
|
411
|
+
) => {
|
|
412
|
+
return Effect.tap(Effect.service(CurrentRenderPriority), (priority) =>
|
|
413
|
+
Effect.sync(() => {
|
|
414
|
+
const dispose = addDisposable(
|
|
415
|
+
ctx,
|
|
416
|
+
ctx.renderQueue.add(
|
|
417
|
+
key,
|
|
418
|
+
() => {
|
|
419
|
+
f();
|
|
420
|
+
ctx.refCounter.release(index);
|
|
421
|
+
},
|
|
422
|
+
() => {
|
|
423
|
+
dispose();
|
|
424
|
+
},
|
|
425
|
+
priority,
|
|
426
|
+
),
|
|
427
|
+
);
|
|
428
|
+
}),
|
|
429
|
+
);
|
|
430
|
+
};
|
|
431
|
+
|
|
432
|
+
function setupRenderPart<E = never, R = never>(
|
|
433
|
+
part: Template.PartNode | Template.SparsePartNode,
|
|
434
|
+
node: Node,
|
|
435
|
+
ctx: TemplateContext<R>,
|
|
436
|
+
): Effect.Effect<unknown, E, R> | void {
|
|
437
|
+
switch (part._tag) {
|
|
438
|
+
case "node": {
|
|
439
|
+
return renderValue(
|
|
440
|
+
ctx,
|
|
441
|
+
part.index,
|
|
442
|
+
makeNodeUpdater(
|
|
443
|
+
ctx.document,
|
|
444
|
+
findNodePartEndComment(node as HTMLElement | SVGElement, part.index),
|
|
445
|
+
),
|
|
446
|
+
);
|
|
447
|
+
}
|
|
448
|
+
case "attr": {
|
|
449
|
+
const element = node as HTMLElement | SVGElement;
|
|
450
|
+
const setAttr = makeAttributeValueUpdater(
|
|
451
|
+
element,
|
|
452
|
+
element.getAttributeNode(part.name) ?? ctx.document.createAttribute(part.name),
|
|
453
|
+
);
|
|
454
|
+
return renderValue(ctx, part.index, (value) => setAttr(renderToString(value, "")));
|
|
455
|
+
}
|
|
456
|
+
case "boolean-part": {
|
|
457
|
+
const updater = makeBooleanUpdater(node as HTMLElement | SVGElement, part.name);
|
|
458
|
+
return renderValue(ctx, part.index, (value) => updater(!!value));
|
|
459
|
+
}
|
|
460
|
+
case "className-part": {
|
|
461
|
+
const updater = makeClassListUpdater(node as HTMLElement | SVGElement);
|
|
462
|
+
return renderValue(ctx, part.index, (value) => updater(getClassList(value)));
|
|
463
|
+
}
|
|
464
|
+
case "comment-part":
|
|
465
|
+
return renderValue(ctx, part.index, makeTextContentUpdater(node as Comment));
|
|
466
|
+
case "data":
|
|
467
|
+
return setupDataset<E, R>(node as HTMLElement | SVGElement, ctx, part.index);
|
|
468
|
+
case "event":
|
|
469
|
+
return setupEventHandler(node as Element, ctx, part.index, part.name);
|
|
470
|
+
case "property":
|
|
471
|
+
return renderValue(
|
|
472
|
+
ctx,
|
|
473
|
+
part.index,
|
|
474
|
+
setupPropertSetter(node as HTMLElement | SVGElement, part.name),
|
|
475
|
+
);
|
|
476
|
+
case "properties":
|
|
477
|
+
return setupProperties<E, R>(node as HTMLElement | SVGElement, ctx, part.index);
|
|
478
|
+
case "ref":
|
|
479
|
+
return setupRef<R>(node as HTMLElement | SVGElement, ctx, part.index);
|
|
480
|
+
case "sparse-attr": {
|
|
481
|
+
const element = node as HTMLElement | SVGElement;
|
|
482
|
+
const attr = element.getAttributeNode(part.name) ?? ctx.document.createAttribute(part.name);
|
|
483
|
+
return renderSparseTextContent(
|
|
484
|
+
element,
|
|
485
|
+
part.nodes,
|
|
486
|
+
++ctx.dynamicIndex,
|
|
487
|
+
ctx,
|
|
488
|
+
makeAttributeValueUpdater(element, attr),
|
|
489
|
+
);
|
|
490
|
+
}
|
|
491
|
+
case "sparse-class-name": {
|
|
492
|
+
const updater = makeClassListUpdater(node as HTMLElement | SVGElement);
|
|
493
|
+
return renderSparsePart(
|
|
494
|
+
part.nodes,
|
|
495
|
+
++ctx.dynamicIndex,
|
|
496
|
+
ctx,
|
|
497
|
+
(classNames) => updater(getClassList(classNames)),
|
|
498
|
+
(value) => value,
|
|
499
|
+
);
|
|
500
|
+
}
|
|
501
|
+
case "sparse-comment":
|
|
502
|
+
return renderSparseTextContent(node as Comment, part.nodes, ++ctx.dynamicIndex, ctx);
|
|
503
|
+
case "text-part":
|
|
504
|
+
return renderValue(ctx, part.index, makeTextContentUpdater(node as HTMLElement | SVGElement));
|
|
505
|
+
case "sparse-text":
|
|
506
|
+
return renderSparseTextContent(
|
|
507
|
+
node as HTMLElement | SVGElement,
|
|
508
|
+
part.nodes,
|
|
509
|
+
++ctx.dynamicIndex,
|
|
510
|
+
ctx,
|
|
511
|
+
);
|
|
512
|
+
}
|
|
513
|
+
}
|
|
514
|
+
|
|
515
|
+
type HydrateTemplateContext<R = never> = TemplateContext<R> & {
|
|
516
|
+
where: HydrationNode;
|
|
517
|
+
makeHydrateContext: (where: HydrationNode) => HydrateContext;
|
|
518
|
+
};
|
|
519
|
+
|
|
520
|
+
function setupHydrationParts<E, R>(
|
|
521
|
+
parts: Template.Template["parts"],
|
|
522
|
+
ctx: HydrateTemplateContext<R>,
|
|
523
|
+
): Array<Effect.Effect<unknown, E, R>> {
|
|
524
|
+
const effects: Array<Effect.Effect<unknown, E, R>> = [];
|
|
525
|
+
for (const [part, path] of parts) {
|
|
526
|
+
const effect = setupHydrationPart<E, R>(part, path, ctx);
|
|
527
|
+
if (effect !== undefined) {
|
|
528
|
+
effects.push(effect);
|
|
529
|
+
}
|
|
530
|
+
}
|
|
531
|
+
|
|
532
|
+
return effects;
|
|
533
|
+
}
|
|
534
|
+
|
|
535
|
+
function setupHydrationPart<E, R>(
|
|
536
|
+
part: Template.PartNode | Template.SparsePartNode,
|
|
537
|
+
path: ReadonlyArray<number>,
|
|
538
|
+
ctx: HydrateTemplateContext<R>,
|
|
539
|
+
): Effect.Effect<unknown, E, R> | void {
|
|
540
|
+
switch (part._tag) {
|
|
541
|
+
case "node": {
|
|
542
|
+
const hole = findHydrationHole(getChildNodes(ctx.where), part.index);
|
|
543
|
+
if (hole === null) throw new CouldNotFindCommentError(part.index);
|
|
544
|
+
return setupHydratedNodePart(part, hole, ctx);
|
|
545
|
+
}
|
|
546
|
+
default:
|
|
547
|
+
return setupRenderPart(part, findHydratePath(ctx.where, path), ctx);
|
|
548
|
+
}
|
|
549
|
+
}
|
|
550
|
+
|
|
551
|
+
function renderSparsePart<E, R, T = unknown>(
|
|
552
|
+
parts: Template.SparsePartNode["nodes"],
|
|
553
|
+
index: number,
|
|
554
|
+
ctx: TemplateContext<R>,
|
|
555
|
+
f: (value: ReadonlyArray<string | NoInfer<T>>) => void,
|
|
556
|
+
transformValue: (value: unknown) => T,
|
|
557
|
+
): Effect.Effect<unknown, E, R> {
|
|
558
|
+
ctx.expected++;
|
|
559
|
+
return Fx.tuple(
|
|
560
|
+
...parts.map((node) => {
|
|
561
|
+
if (node._tag === "text") return Fx.succeed(node.value);
|
|
562
|
+
return Fx.map(liftRenderableToFx<E, R>(ctx.values[node.index]), transformValue);
|
|
563
|
+
}),
|
|
564
|
+
).pipe(Fx.observe((values) => withCurrentRenderPriority(f, index, ctx, () => f(values))));
|
|
565
|
+
}
|
|
566
|
+
|
|
567
|
+
function renderSparseTextContent<E, R>(
|
|
568
|
+
node: Node,
|
|
569
|
+
nodes: Template.SparsePartNode["nodes"],
|
|
570
|
+
index: number,
|
|
571
|
+
ctx: TemplateContext<R>,
|
|
572
|
+
onTextContent: (value: string) => void = makeTextContentUpdater(node),
|
|
573
|
+
): Effect.Effect<unknown, E, R> {
|
|
574
|
+
return renderSparsePart(
|
|
575
|
+
nodes,
|
|
576
|
+
index,
|
|
577
|
+
ctx,
|
|
578
|
+
(texts) => onTextContent(texts.join("")),
|
|
579
|
+
(value) => renderToString(value, ""),
|
|
580
|
+
);
|
|
581
|
+
}
|
|
582
|
+
|
|
583
|
+
function renderValue<E, R, X>(
|
|
584
|
+
ctx: TemplateContext,
|
|
585
|
+
index: number,
|
|
586
|
+
f: (value: unknown) => X,
|
|
587
|
+
): void | X | Effect.Effect<unknown, E, R> {
|
|
588
|
+
return matchRenderable(ctx.values[index], {
|
|
589
|
+
Primitive: f,
|
|
590
|
+
Effect: (effect) => {
|
|
591
|
+
ctx.expected++;
|
|
592
|
+
return effect.pipe(
|
|
593
|
+
Effect.flatMap((value) => withCurrentRenderPriority(f, index, ctx, () => f(value))),
|
|
594
|
+
);
|
|
595
|
+
},
|
|
596
|
+
Fx: (fx) => {
|
|
597
|
+
ctx.expected++;
|
|
598
|
+
return fx.run(
|
|
599
|
+
Sink.make(ctx.onCause, (value) => withCurrentRenderPriority(f, index, ctx, () => f(value))),
|
|
600
|
+
);
|
|
601
|
+
},
|
|
602
|
+
});
|
|
603
|
+
}
|
|
604
|
+
|
|
605
|
+
function matchRenderable<X, A, B, C>(
|
|
606
|
+
renderable: Renderable.Any,
|
|
607
|
+
matches: {
|
|
608
|
+
Primitive: (value: X) => A;
|
|
609
|
+
Effect: (effect: Effect.Effect<X>) => B;
|
|
610
|
+
Fx: (fx: Fx.Fx<X>) => C;
|
|
611
|
+
},
|
|
612
|
+
): A | B | C | void {
|
|
613
|
+
if (isNullish(renderable)) return;
|
|
614
|
+
else if (Fx.isFx(renderable)) {
|
|
615
|
+
return matches.Fx(renderable as any);
|
|
616
|
+
} else if (isStream(renderable)) {
|
|
617
|
+
return matches.Fx(Fx.fromStream(renderable));
|
|
618
|
+
} else if (Effect.isEffect(renderable)) {
|
|
619
|
+
return matches.Effect(renderable as any);
|
|
620
|
+
} else if (Array.isArray(renderable)) {
|
|
621
|
+
return matches.Fx(liftRenderableToFx(renderable));
|
|
622
|
+
} else {
|
|
623
|
+
return matches.Primitive(renderable);
|
|
624
|
+
}
|
|
625
|
+
}
|
|
626
|
+
|
|
627
|
+
function setupRenderProperties<E = never, R = never>(
|
|
628
|
+
properties: Record<string, unknown>,
|
|
629
|
+
element: HTMLElement | SVGElement,
|
|
630
|
+
ctx: TemplateContext<R>,
|
|
631
|
+
): Effect.Effect<unknown, E, R> | void {
|
|
632
|
+
const effects: Array<Effect.Effect<unknown, E, R>> = [];
|
|
633
|
+
for (const [key, value] of Object.entries(properties)) {
|
|
634
|
+
const index = ctx.dynamicIndex++;
|
|
635
|
+
const part = makePropertiesPart(keyToPartType(key), index);
|
|
636
|
+
const effect = setupRenderPart(part, element, { ...ctx, values: makeArrayLike(index, value) });
|
|
637
|
+
if (effect !== undefined) {
|
|
638
|
+
effects.push(effect);
|
|
639
|
+
}
|
|
640
|
+
}
|
|
641
|
+
if (effects.length > 0) {
|
|
642
|
+
ctx.expected += effects.length;
|
|
643
|
+
return Effect.all(effects, { concurrency: "unbounded" });
|
|
644
|
+
}
|
|
645
|
+
}
|
|
646
|
+
|
|
647
|
+
type PartType = ReturnType<typeof keyToPartType>;
|
|
648
|
+
|
|
649
|
+
function makePropertiesPart([partType, partName]: PartType, index: number) {
|
|
650
|
+
switch (partType) {
|
|
651
|
+
case "attr":
|
|
652
|
+
return new Template.AttrPartNode(partName, index);
|
|
653
|
+
case "boolean":
|
|
654
|
+
return new Template.BooleanPartNode(partName, index);
|
|
655
|
+
case "class":
|
|
656
|
+
return new Template.ClassNamePartNode(index);
|
|
657
|
+
case "data":
|
|
658
|
+
return new Template.DataPartNode(index);
|
|
659
|
+
case "event":
|
|
660
|
+
return new Template.EventPartNode(partName, index);
|
|
661
|
+
case "property":
|
|
662
|
+
return new Template.PropertyPartNode(partName, index);
|
|
663
|
+
case "properties":
|
|
664
|
+
return new Template.PropertiesPartNode(index);
|
|
665
|
+
case "ref":
|
|
666
|
+
return new Template.RefPartNode(index);
|
|
667
|
+
default:
|
|
668
|
+
// oxlint-disable-next-line typescript/restrict-template-expressions
|
|
669
|
+
throw new Error(`Unknown part type: ${partType}`);
|
|
670
|
+
}
|
|
671
|
+
}
|
|
672
|
+
|
|
673
|
+
export type TemplateContext<R = never> = {
|
|
674
|
+
readonly document: Document;
|
|
675
|
+
readonly renderQueue: RQ.RenderQueue;
|
|
676
|
+
readonly disposables: Set<Disposable>;
|
|
677
|
+
readonly eventSource: EventSource;
|
|
678
|
+
readonly refCounter: IndexRefCounter;
|
|
679
|
+
readonly scope: Scope.Closeable;
|
|
680
|
+
readonly values: ArrayLike<Renderable<unknown, any, any>>;
|
|
681
|
+
readonly services: ServiceMap.ServiceMap<R | Scope.Scope>;
|
|
682
|
+
readonly onCause: (cause: Cause.Cause<any>) => Effect.Effect<unknown>;
|
|
683
|
+
|
|
684
|
+
/**
|
|
685
|
+
* @internal
|
|
686
|
+
*/
|
|
687
|
+
expected: number;
|
|
688
|
+
/**
|
|
689
|
+
* @internal
|
|
690
|
+
*/
|
|
691
|
+
dynamicIndex: number;
|
|
692
|
+
|
|
693
|
+
readonly hydrateContext: HydrateContext | undefined;
|
|
694
|
+
};
|
|
695
|
+
|
|
696
|
+
const makeTemplateContext = Effect.fn(function* <
|
|
697
|
+
Values extends ArrayLike<Renderable.Any>,
|
|
698
|
+
RSink = never,
|
|
699
|
+
>(
|
|
700
|
+
document: Document,
|
|
701
|
+
values: Values,
|
|
702
|
+
onCause: (
|
|
703
|
+
cause: Cause.Cause<Renderable.Error<Values[number]>>,
|
|
704
|
+
) => Effect.Effect<unknown, never, RSink>,
|
|
705
|
+
) {
|
|
706
|
+
const renderQueue: RQ.RenderQueue = yield* CurrentRenderQueue;
|
|
707
|
+
const services: ServiceMap.ServiceMap<Renderable.Services<Values[number]> | RSink | Scope.Scope> =
|
|
708
|
+
yield* Effect.services<Renderable.Services<Values[number]> | RSink | Scope.Scope>();
|
|
709
|
+
const refCounter: IndexRefCounter = yield* makeRefCounter;
|
|
710
|
+
const scope: Scope.Closeable = yield* Scope.fork(ServiceMap.get(services, Scope.Scope));
|
|
711
|
+
const eventSource: EventSource = makeEventSource();
|
|
712
|
+
const servicesWithScope = ServiceMap.add(services, Scope.Scope, scope);
|
|
713
|
+
const hydrateContext = ServiceMap.getOption(services, HydrateContext);
|
|
714
|
+
const ctx: TemplateContext<Renderable.Services<Values[number]> | RSink | Scope.Scope> = {
|
|
715
|
+
services: ServiceMap.add(services, Scope.Scope, scope),
|
|
716
|
+
document,
|
|
717
|
+
renderQueue,
|
|
718
|
+
disposables: new Set(),
|
|
719
|
+
eventSource,
|
|
720
|
+
refCounter,
|
|
721
|
+
scope,
|
|
722
|
+
values,
|
|
723
|
+
onCause: flow(onCause, Effect.provideServices(servicesWithScope)),
|
|
724
|
+
expected: 0,
|
|
725
|
+
dynamicIndex: values.length,
|
|
726
|
+
hydrateContext: getOrUndefined(hydrateContext),
|
|
727
|
+
};
|
|
728
|
+
|
|
729
|
+
yield* Scope.addFinalizer(
|
|
730
|
+
scope,
|
|
731
|
+
Effect.sync(() => ctx.disposables.forEach(dispose)),
|
|
732
|
+
);
|
|
733
|
+
|
|
734
|
+
return ctx;
|
|
735
|
+
});
|
|
736
|
+
|
|
737
|
+
function liftRenderableToFx<E = never, R = never>(
|
|
738
|
+
renderable: Renderable<unknown, E, R>,
|
|
739
|
+
): Fx.Fx<any, E, R> {
|
|
740
|
+
switch (typeof renderable) {
|
|
741
|
+
case "undefined":
|
|
742
|
+
case "function":
|
|
743
|
+
case "object": {
|
|
744
|
+
if (isNullish(renderable)) {
|
|
745
|
+
return Fx.null;
|
|
746
|
+
} else if (Array.isArray(renderable)) {
|
|
747
|
+
return Fx.tuple(...renderable.map(liftRenderableToFx<E, R>));
|
|
748
|
+
} else if (isOption(renderable)) {
|
|
749
|
+
return isNone(renderable) ? Fx.null : liftRenderableToFx((renderable as Some<any>).value);
|
|
750
|
+
} else if (Effect.isEffect(renderable)) {
|
|
751
|
+
return Fx.unwrap(Effect.map(renderable, liftRenderableToFx<E, R>));
|
|
752
|
+
} else if (Fx.isFx(renderable)) {
|
|
753
|
+
return renderable;
|
|
754
|
+
} else {
|
|
755
|
+
return Fx.struct(mapRecord(renderable, liftRenderableToFx));
|
|
756
|
+
}
|
|
757
|
+
}
|
|
758
|
+
default:
|
|
759
|
+
return Fx.succeed(renderable);
|
|
760
|
+
}
|
|
761
|
+
}
|
|
762
|
+
|
|
763
|
+
function addDisposable(ctx: TemplateContext, disposable: Disposable) {
|
|
764
|
+
ctx.disposables.add(disposable);
|
|
765
|
+
return () => ctx.disposables.delete(disposable);
|
|
766
|
+
}
|
|
767
|
+
|
|
768
|
+
function dispose(disposable: Disposable) {
|
|
769
|
+
disposable[Symbol.dispose]();
|
|
770
|
+
}
|
|
771
|
+
|
|
772
|
+
function makeArrayLike<A>(index: number, value: A): ArrayLike<A> {
|
|
773
|
+
return {
|
|
774
|
+
length: index + 1,
|
|
775
|
+
[index]: value,
|
|
776
|
+
};
|
|
777
|
+
}
|
|
778
|
+
|
|
779
|
+
export function attemptHydration(
|
|
780
|
+
ctx: TemplateContext,
|
|
781
|
+
hash: string,
|
|
782
|
+
): { readonly where: HydrationTemplate; readonly hydrateCtx: HydrateContext } | undefined {
|
|
783
|
+
if (ctx.hydrateContext && ctx.hydrateContext.hydrate) {
|
|
784
|
+
const where = findHydrationTemplateByHash(ctx.hydrateContext, hash);
|
|
785
|
+
if (where === null) {
|
|
786
|
+
ctx.hydrateContext.hydrate = false;
|
|
787
|
+
return;
|
|
788
|
+
} else {
|
|
789
|
+
return { where, hydrateCtx: ctx.hydrateContext };
|
|
790
|
+
}
|
|
791
|
+
}
|
|
792
|
+
}
|
|
793
|
+
|
|
794
|
+
function setupEventHandler(element: Element, ctx: TemplateContext, index: number, name: string) {
|
|
795
|
+
const value = ctx.values[index];
|
|
796
|
+
if (isNullish(value)) return;
|
|
797
|
+
ctx.eventSource.addEventListener(
|
|
798
|
+
element,
|
|
799
|
+
name,
|
|
800
|
+
EventHandler.fromEffectOrEventHandler(
|
|
801
|
+
value as
|
|
802
|
+
| Effect.Effect<unknown, never, never>
|
|
803
|
+
| EventHandler.EventHandler<Event, never, never>,
|
|
804
|
+
).pipe(EventHandler.provide(ctx.services), EventHandler.catchCause(ctx.onCause)),
|
|
805
|
+
);
|
|
806
|
+
}
|
|
807
|
+
|
|
808
|
+
function setupDataset<E, R>(
|
|
809
|
+
element: HTMLElement | SVGElement,
|
|
810
|
+
ctx: TemplateContext<R>,
|
|
811
|
+
index: number,
|
|
812
|
+
): Effect.Effect<unknown, E, R> | void {
|
|
813
|
+
const value = ctx.values[index];
|
|
814
|
+
if (isNullish(value)) return;
|
|
815
|
+
// Special case to convert sync object to data-* attributes
|
|
816
|
+
if (isObject(value)) {
|
|
817
|
+
const effects: Array<Effect.Effect<unknown, E, R>> = [];
|
|
818
|
+
for (const [k, v] of Object.entries(value)) {
|
|
819
|
+
const index = ctx.dynamicIndex++;
|
|
820
|
+
const part = makePropertiesPart(["attr", `data-${k}`], index);
|
|
821
|
+
const effect = setupRenderPart<E, R>(part, element, {
|
|
822
|
+
...ctx,
|
|
823
|
+
values: makeArrayLike(index, v),
|
|
824
|
+
});
|
|
825
|
+
if (effect !== undefined) {
|
|
826
|
+
effects.push(effect);
|
|
827
|
+
}
|
|
828
|
+
}
|
|
829
|
+
|
|
830
|
+
ctx.expected += effects.length;
|
|
831
|
+
|
|
832
|
+
return Effect.all(effects, { concurrency: "unbounded" });
|
|
833
|
+
}
|
|
834
|
+
return renderValue(ctx, index, makeDatasetUpdater(element));
|
|
835
|
+
}
|
|
836
|
+
|
|
837
|
+
function setupProperties<E, R>(
|
|
838
|
+
element: HTMLElement | SVGElement,
|
|
839
|
+
ctx: TemplateContext<R>,
|
|
840
|
+
index: number,
|
|
841
|
+
) {
|
|
842
|
+
const setupIfObject = (props: unknown) => {
|
|
843
|
+
if (isObject(props)) {
|
|
844
|
+
return setupRenderProperties<E, R>(props as Record<string, unknown>, element, ctx);
|
|
845
|
+
}
|
|
846
|
+
};
|
|
847
|
+
|
|
848
|
+
return matchRenderable(ctx.values[index], {
|
|
849
|
+
Primitive: setupIfObject,
|
|
850
|
+
Effect: Effect.tap(flow(setupIfObject, Effect.succeed)),
|
|
851
|
+
Fx: flow(
|
|
852
|
+
Fx.switchMapEffect((props) => setupIfObject(props) || Effect.void),
|
|
853
|
+
Fx.drain,
|
|
854
|
+
Effect.provideService(Scope.Scope, ctx.scope),
|
|
855
|
+
),
|
|
856
|
+
});
|
|
857
|
+
}
|
|
858
|
+
|
|
859
|
+
function setupRef<R>(element: HTMLElement | SVGElement, ctx: TemplateContext<R>, index: number) {
|
|
860
|
+
const renderable = ctx.values[index];
|
|
861
|
+
if (isNullish(renderable)) return;
|
|
862
|
+
if (isFunction(renderable)) {
|
|
863
|
+
return matchRenderable((renderable as Function)(element), {
|
|
864
|
+
Primitive: constVoid,
|
|
865
|
+
Effect: identity,
|
|
866
|
+
Fx: Fx.drain,
|
|
867
|
+
});
|
|
868
|
+
}
|
|
869
|
+
throw new Error("Invalid value provided to ref part");
|
|
870
|
+
}
|
|
871
|
+
|
|
872
|
+
function setupPropertSetter(element: Element, name: string) {
|
|
873
|
+
return (value: unknown) => {
|
|
874
|
+
(element as any)[name] = value;
|
|
875
|
+
};
|
|
876
|
+
}
|
|
877
|
+
|
|
878
|
+
function setupHydratedNodePart<E, R>(
|
|
879
|
+
part: Template.NodePart,
|
|
880
|
+
hole: HydrationHole,
|
|
881
|
+
ctx: HydrateTemplateContext<R>,
|
|
882
|
+
): Effect.Effect<unknown, E, R> | void {
|
|
883
|
+
const nestedCtx = ctx.makeHydrateContext(hole);
|
|
884
|
+
const previousNodes = getAllSiblingsBetween(hole.startComment, hole.endComment);
|
|
885
|
+
const text = previousNodes.length === 3 && isText(previousNodes[1]) ? previousNodes[1] : null;
|
|
886
|
+
|
|
887
|
+
const effect = renderValue<E, R, void>(
|
|
888
|
+
ctx,
|
|
889
|
+
part.index,
|
|
890
|
+
makeNodeUpdater(
|
|
891
|
+
ctx.document,
|
|
892
|
+
hole.endComment,
|
|
893
|
+
text,
|
|
894
|
+
text === null ? previousNodes : [hole.startComment, text, hole.endComment],
|
|
895
|
+
),
|
|
896
|
+
);
|
|
897
|
+
if (effect === undefined) return;
|
|
898
|
+
return Effect.provideService(effect, HydrateContext, nestedCtx);
|
|
84
899
|
}
|