sygnal 5.3.7 → 6.0.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +646 -0
- package/README.md +77 -47
- package/dist/astro/client.cjs.js +33 -8114
- package/dist/astro/client.cjs.js.map +1 -0
- package/dist/astro/client.mjs +33 -8114
- package/dist/astro/client.mjs.map +1 -0
- package/dist/astro/index.cjs.js +1039 -9
- package/dist/astro/index.cjs.js.map +1 -0
- package/dist/astro/index.mjs +1038 -9
- package/dist/astro/index.mjs.map +1 -0
- package/dist/astro/server.cjs.js +3400 -166
- package/dist/astro/server.cjs.js.map +1 -0
- package/dist/astro/server.mjs +3400 -166
- package/dist/astro/server.mjs.map +1 -0
- package/dist/devtools.cjs.js +1431 -0
- package/dist/devtools.cjs.js.map +1 -0
- package/dist/devtools.esm.js +1419 -0
- package/dist/devtools.esm.js.map +1 -0
- package/dist/diagnostics.cjs.js +4033 -0
- package/dist/diagnostics.cjs.js.map +1 -0
- package/dist/diagnostics.esm.js +4003 -0
- package/dist/diagnostics.esm.js.map +1 -0
- package/dist/element.cjs.js +230 -0
- package/dist/element.cjs.js.map +1 -0
- package/dist/element.esm.js +228 -0
- package/dist/element.esm.js.map +1 -0
- package/dist/guide/accessibility.md +257 -0
- package/dist/guide/adapters.md +221 -0
- package/dist/guide/behaviors.md +312 -0
- package/dist/guide/browser-sources.md +203 -0
- package/dist/guide/drag-and-drop.md +342 -0
- package/dist/guide/element-commands.md +306 -0
- package/dist/guide/error-boundaries.md +169 -0
- package/dist/guide/forms-reference.md +381 -0
- package/dist/guide/forms.md +250 -0
- package/dist/guide/http.md +299 -0
- package/dist/guide/inputs.md +173 -0
- package/dist/guide/persistence.md +245 -0
- package/dist/guide/recipes/carousel.md +155 -0
- package/dist/guide/recipes/charts.md +177 -0
- package/dist/guide/recipes/code-editor.md +135 -0
- package/dist/guide/recipes/data-grid.md +155 -0
- package/dist/guide/recipes/data-table.md +196 -0
- package/dist/guide/recipes/i18n.md +222 -0
- package/dist/guide/recipes/icons.md +115 -0
- package/dist/guide/recipes/overview.md +33 -0
- package/dist/guide/recipes/rich-text.md +154 -0
- package/dist/guide/resources.md +471 -0
- package/dist/guide/ssr.md +255 -0
- package/dist/guide/timers.md +178 -0
- package/dist/guide/ui/accordion.md +93 -0
- package/dist/guide/ui/combobox.md +144 -0
- package/dist/guide/ui/dialog.md +124 -0
- package/dist/guide/ui/disclosure.md +60 -0
- package/dist/guide/ui/menu.md +125 -0
- package/dist/guide/ui/overview.md +166 -0
- package/dist/guide/ui/popover.md +101 -0
- package/dist/guide/ui/select.md +114 -0
- package/dist/guide/ui/tabs.md +161 -0
- package/dist/guide/ui/toaster.md +152 -0
- package/dist/guide/ui/tooltip.md +103 -0
- package/dist/guide/undo.md +178 -0
- package/dist/guide/virtual-collections.md +183 -0
- package/dist/guide/web-components.md +179 -0
- package/dist/guide/widgets.md +217 -0
- package/dist/index.cjs.js +15283 -6279
- package/dist/index.cjs.js.map +1 -0
- package/dist/index.d.ts +3739 -370
- package/dist/index.esm.js +15230 -6274
- package/dist/index.esm.js.map +1 -0
- package/dist/jsx-dev-runtime.cjs.js +27 -329
- package/dist/jsx-dev-runtime.cjs.js.map +1 -0
- package/dist/jsx-dev-runtime.esm.js +20 -322
- package/dist/jsx-dev-runtime.esm.js.map +1 -0
- package/dist/jsx-runtime.cjs.js +27 -329
- package/dist/jsx-runtime.cjs.js.map +1 -0
- package/dist/jsx-runtime.esm.js +20 -322
- package/dist/jsx-runtime.esm.js.map +1 -0
- package/dist/jsx.cjs.js +11 -309
- package/dist/jsx.cjs.js.map +1 -0
- package/dist/jsx.esm.js +9 -310
- package/dist/jsx.esm.js.map +1 -0
- package/dist/react.cjs.js +117 -0
- package/dist/react.cjs.js.map +1 -0
- package/dist/react.esm.js +115 -0
- package/dist/react.esm.js.map +1 -0
- package/dist/shims/globalthis.cjs +20 -0
- package/dist/sygnal.min.js +2 -1
- package/dist/sygnal.min.js.map +1 -0
- package/dist/ui-combobox.cjs.js +169 -0
- package/dist/ui-combobox.cjs.js.map +1 -0
- package/dist/ui-combobox.esm.js +148 -0
- package/dist/ui-combobox.esm.js.map +1 -0
- package/dist/ui-menu.cjs.js +87 -0
- package/dist/ui-menu.cjs.js.map +1 -0
- package/dist/ui-menu.esm.js +66 -0
- package/dist/ui-menu.esm.js.map +1 -0
- package/dist/ui-select.cjs.js +104 -0
- package/dist/ui-select.cjs.js.map +1 -0
- package/dist/ui-select.esm.js +83 -0
- package/dist/ui-select.esm.js.map +1 -0
- package/dist/ui.cjs.js +738 -0
- package/dist/ui.cjs.js.map +1 -0
- package/dist/ui.esm.js +727 -0
- package/dist/ui.esm.js.map +1 -0
- package/dist/vike/ClientOnly.cjs.js +5 -14
- package/dist/vike/ClientOnly.cjs.js.map +1 -0
- package/dist/vike/ClientOnly.mjs +5 -14
- package/dist/vike/ClientOnly.mjs.map +1 -0
- package/dist/vike/{+config.js → config/+config.js} +10 -1
- package/dist/vike/config/+config.js.map +1 -0
- package/dist/vike/config/package.json +6 -0
- package/dist/vike/onRenderClient.cjs.js +166 -95
- package/dist/vike/onRenderClient.cjs.js.map +1 -0
- package/dist/vike/onRenderClient.mjs +166 -95
- package/dist/vike/onRenderClient.mjs.map +1 -0
- package/dist/vike/onRenderHtml.cjs.js +60 -24
- package/dist/vike/onRenderHtml.cjs.js.map +1 -0
- package/dist/vike/onRenderHtml.mjs +61 -25
- package/dist/vike/onRenderHtml.mjs.map +1 -0
- package/dist/vite/plugin.cjs.js +926 -65
- package/dist/vite/plugin.cjs.js.map +1 -0
- package/dist/vite/plugin.mjs +925 -65
- package/dist/vite/plugin.mjs.map +1 -0
- package/dist/zag.cjs.js +408 -0
- package/dist/zag.cjs.js.map +1 -0
- package/dist/zag.esm.js +405 -0
- package/dist/zag.esm.js.map +1 -0
- package/llms.txt +313 -0
- package/package.json +109 -16
- package/src/astro/client.ts +40 -18
- package/src/astro/index.d.ts +48 -1
- package/src/astro/index.ts +106 -9
- package/src/astro/server.ts +11 -3
- package/src/collection.ts +6 -90
- package/src/core/actions.ts +134 -0
- package/src/core/cell.ts +202 -0
- package/src/core/debug.ts +23 -0
- package/src/core/define.ts +242 -0
- package/src/core/hooks.ts +314 -0
- package/src/core/hosts/collection.ts +325 -0
- package/src/core/hosts/switchable.ts +146 -0
- package/src/core/instance.ts +592 -0
- package/src/core/markers/clientonly.ts +13 -0
- package/src/core/markers/lazy.ts +40 -0
- package/src/core/markers/portal.ts +96 -0
- package/src/core/markers/suspense.ts +41 -0
- package/src/core/markers/transition.ts +70 -0
- package/src/core/registry.ts +25 -0
- package/src/core/runtime.ts +573 -0
- package/src/core/statics.ts +104 -0
- package/src/core/teardown.ts +60 -0
- package/src/core/view.ts +37 -0
- package/src/cycle/dom/DocumentDOMSource.ts +13 -8
- package/src/cycle/dom/ElementFinder.ts +7 -9
- package/src/cycle/dom/EventDelegator.ts +174 -223
- package/src/cycle/dom/IsolateModule.ts +65 -35
- package/src/cycle/dom/MainDOMSource.ts +13 -2
- package/src/cycle/dom/PriorityQueue.ts +4 -2
- package/src/cycle/dom/SymbolTree.ts +18 -47
- package/src/cycle/dom/classNameModule.ts +76 -0
- package/src/cycle/dom/controlledInputModule.ts +50 -0
- package/src/cycle/dom/enrichEventStream.ts +29 -45
- package/src/cycle/dom/fragment.ts +7 -0
- package/src/cycle/dom/isolate.ts +30 -27
- package/src/cycle/dom/makeDOMDriver.ts +115 -57
- package/src/cycle/dom/mockDOMSource.ts +83 -9
- package/src/cycle/dom/modules.ts +21 -4
- package/src/cycle/dom/propsModule.ts +65 -0
- package/src/cycle/dom/selectModule.ts +22 -17
- package/src/cycle/dom/snabbdom.ts +1 -6
- package/src/cycle/dom/thunk.ts +3 -0
- package/src/cycle/dom/utils.ts +98 -0
- package/src/cycle/dom/viewTransition.ts +43 -0
- package/src/cycle/state/StateSource.ts +20 -4
- package/src/cycle/state/objIsEqual.ts +50 -0
- package/src/cycle/state/types.ts +0 -10
- package/src/defineComponent.ts +34 -0
- package/src/devtools.d.ts +151 -0
- package/src/devtools.ts +34 -0
- package/src/element.d.ts +59 -0
- package/src/element.ts +235 -0
- package/src/extra/backoff.ts +9 -0
- package/src/extra/behaviors.ts +169 -0
- package/src/extra/browserSignals.ts +23 -0
- package/src/extra/browserSources.ts +326 -0
- package/src/extra/command.ts +3 -3
- package/src/extra/controls.ts +47 -0
- package/src/extra/copyAsTest.ts +286 -0
- package/src/extra/devtools.ts +109 -31
- package/src/extra/devtoolsActions.ts +379 -0
- package/src/extra/devtoolsHook.ts +9 -0
- package/src/extra/devtoolsNext.ts +83 -0
- package/src/extra/diagnostics/checks/actionLog.ts +108 -0
- package/src/extra/diagnostics/checks/behaviors.ts +49 -0
- package/src/extra/diagnostics/checks/browserSources.ts +96 -0
- package/src/extra/diagnostics/checks/collections.ts +67 -0
- package/src/extra/diagnostics/checks/controls.ts +148 -0
- package/src/extra/diagnostics/checks/dataset.ts +57 -0
- package/src/extra/diagnostics/checks/dom.ts +250 -0
- package/src/extra/diagnostics/checks/elementCommands.ts +175 -0
- package/src/extra/diagnostics/checks/events.ts +83 -0
- package/src/extra/diagnostics/checks/fetch.ts +135 -0
- package/src/extra/diagnostics/checks/forms.ts +163 -0
- package/src/extra/diagnostics/checks/index.ts +202 -0
- package/src/extra/diagnostics/checks/inspect.ts +427 -0
- package/src/extra/diagnostics/checks/next.ts +417 -0
- package/src/extra/diagnostics/checks/persist.ts +54 -0
- package/src/extra/diagnostics/checks/props.ts +56 -0
- package/src/extra/diagnostics/checks/public.d.ts +302 -0
- package/src/extra/diagnostics/checks/replies.ts +128 -0
- package/src/extra/diagnostics/checks/router.ts +100 -0
- package/src/extra/diagnostics/checks/rxjsHints.ts +88 -0
- package/src/extra/diagnostics/checks/shared.ts +203 -0
- package/src/extra/diagnostics/checks/shorthand.ts +115 -0
- package/src/extra/diagnostics/checks/sortable.ts +129 -0
- package/src/extra/diagnostics/checks/state.ts +148 -0
- package/src/extra/diagnostics/checks/statics.ts +48 -0
- package/src/extra/diagnostics/checks/strict.ts +55 -0
- package/src/extra/diagnostics/checks/timers.ts +80 -0
- package/src/extra/diagnostics/checks/viewTransitions.ts +47 -0
- package/src/extra/diagnostics/checks/virtual.ts +73 -0
- package/src/extra/diagnostics/checks/widgets.ts +109 -0
- package/src/extra/diagnostics/checks/wiring.ts +121 -0
- package/src/extra/diagnostics/codes.ts +477 -0
- package/src/extra/diagnostics/index.ts +353 -0
- package/src/extra/diagnostics/legacy.ts +76 -0
- package/src/extra/driverFactories.ts +172 -60
- package/src/extra/elementCommands.ts +53 -0
- package/src/extra/eventDriver.ts +4 -0
- package/src/extra/fetchDriver.ts +519 -0
- package/src/extra/flatten.ts +75 -0
- package/src/extra/focusWithin.ts +27 -0
- package/src/extra/form.ts +268 -0
- package/src/extra/formHelpers.ts +139 -0
- package/src/extra/head.ts +106 -0
- package/src/extra/hmr.ts +2 -3
- package/src/extra/owned.ts +24 -0
- package/src/extra/pager.ts +50 -0
- package/src/extra/persist.ts +133 -0
- package/src/extra/pwa.ts +1 -1
- package/src/extra/queryCache.ts +107 -0
- package/src/extra/reducers.ts +13 -6
- package/src/extra/reduxDevtools.ts +92 -0
- package/src/extra/replies.ts +54 -0
- package/src/extra/router.ts +323 -0
- package/src/extra/run.ts +94 -210
- package/src/extra/selection.ts +76 -0
- package/src/extra/socketDriver.ts +265 -0
- package/src/extra/sortable.ts +377 -0
- package/src/extra/ssr.ts +427 -160
- package/src/extra/standardSchema.ts +27 -0
- package/src/extra/testing.ts +3158 -190
- package/src/extra/timers.ts +95 -0
- package/src/extra/undo.ts +261 -0
- package/src/extra/viewTransitions.ts +38 -0
- package/src/extra/virtual.ts +513 -0
- package/src/extra/widget.ts +201 -0
- package/src/extra/xstreamExtras.ts +269 -0
- package/src/index.d.ts +3012 -87
- package/src/index.ts +32 -10
- package/src/jsx-runtime.ts +15 -1
- package/src/jsx.ts +2 -1
- package/src/lazy.ts +50 -7
- package/src/portal.ts +3 -1
- package/src/pragma/index.ts +262 -134
- package/src/react-peers.d.ts +5 -0
- package/src/react.d.ts +43 -0
- package/src/react.ts +110 -0
- package/src/shared.ts +48 -0
- package/src/slot.ts +1 -1
- package/src/suspense.ts +3 -1
- package/src/switchable.ts +6 -119
- package/src/transition.ts +3 -1
- package/src/ui/accordion.ts +64 -0
- package/src/ui/dialog.ts +129 -0
- package/src/ui/disclosure.ts +35 -0
- package/src/ui/popover.ts +45 -0
- package/src/ui/shared.ts +94 -0
- package/src/ui/tabs.ts +82 -0
- package/src/ui/toaster.ts +198 -0
- package/src/ui/tooltip.ts +70 -0
- package/src/ui/zag/combobox.ts +115 -0
- package/src/ui/zag/menu.ts +40 -0
- package/src/ui/zag/select.ts +54 -0
- package/src/ui/zag/shared.ts +43 -0
- package/src/ui-combobox.d.ts +20 -0
- package/src/ui-combobox.ts +6 -0
- package/src/ui-menu.d.ts +30 -0
- package/src/ui-menu.ts +6 -0
- package/src/ui-select.d.ts +17 -0
- package/src/ui-select.ts +6 -0
- package/src/ui-zag-types.d.ts +42 -0
- package/src/ui.d.ts +208 -0
- package/src/ui.ts +15 -0
- package/src/vike/+config.ts +9 -1
- package/src/vike/ClientOnly.ts +1 -1
- package/src/vike/onRenderClient.ts +144 -96
- package/src/vike/onRenderHtml.ts +69 -26
- package/src/vike/types.ts +27 -4
- package/src/vite/globalthis-shim.ts +18 -0
- package/src/vite/globalthis.ts +56 -0
- package/src/vite/plugin.d.ts +114 -2
- package/src/vite/plugin.ts +920 -56
- package/src/zag.d.ts +64 -0
- package/src/zag.ts +238 -0
- package/dist/astro/astro/client.d.ts +0 -5
- package/dist/astro/astro/index.d.ts +0 -16
- package/dist/astro/astro/server.d.ts +0 -12
- package/dist/astro/client.d.ts +0 -5
- package/dist/astro/client.esm.js +0 -4665
- package/dist/astro/collection.d.ts +0 -12
- package/dist/astro/component.d.ts +0 -22
- package/dist/astro/cycle/dom/BodyDOMSource.d.ts +0 -10
- package/dist/astro/cycle/dom/DOMSource.d.ts +0 -11
- package/dist/astro/cycle/dom/DocumentDOMSource.d.ts +0 -12
- package/dist/astro/cycle/dom/ElementFinder.d.ts +0 -8
- package/dist/astro/cycle/dom/EventDelegator.d.ts +0 -34
- package/dist/astro/cycle/dom/IsolateModule.d.ts +0 -23
- package/dist/astro/cycle/dom/MainDOMSource.d.ts +0 -32
- package/dist/astro/cycle/dom/PriorityQueue.d.ts +0 -7
- package/dist/astro/cycle/dom/ScopeChecker.d.ts +0 -9
- package/dist/astro/cycle/dom/SymbolTree.d.ts +0 -9
- package/dist/astro/cycle/dom/VNodeWrapper.d.ts +0 -8
- package/dist/astro/cycle/dom/enrichEventStream.d.ts +0 -24
- package/dist/astro/cycle/dom/fromEvent.d.ts +0 -6
- package/dist/astro/cycle/dom/index.d.ts +0 -8
- package/dist/astro/cycle/dom/isolate.d.ts +0 -9
- package/dist/astro/cycle/dom/makeDOMDriver.d.ts +0 -11
- package/dist/astro/cycle/dom/mockDOMSource.d.ts +0 -17
- package/dist/astro/cycle/dom/modules.d.ts +0 -5
- package/dist/astro/cycle/dom/snabbdom.d.ts +0 -22
- package/dist/astro/cycle/dom/styleModule.d.ts +0 -13
- package/dist/astro/cycle/dom/thunk.d.ts +0 -11
- package/dist/astro/cycle/dom/utils.d.ts +0 -8
- package/dist/astro/cycle/isolate/index.d.ts +0 -42
- package/dist/astro/cycle/run/adapt.d.ts +0 -6
- package/dist/astro/cycle/run/index.d.ts +0 -36
- package/dist/astro/cycle/run/internals.d.ts +0 -8
- package/dist/astro/cycle/run/types.d.ts +0 -49
- package/dist/astro/cycle/state/Collection.d.ts +0 -29
- package/dist/astro/cycle/state/StateSource.d.ts +0 -20
- package/dist/astro/cycle/state/index.d.ts +0 -5
- package/dist/astro/cycle/state/pickCombine.d.ts +0 -3
- package/dist/astro/cycle/state/pickMerge.d.ts +0 -3
- package/dist/astro/cycle/state/types.d.ts +0 -18
- package/dist/astro/cycle/state/withState.d.ts +0 -17
- package/dist/astro/extra/classes.d.ts +0 -7
- package/dist/astro/extra/devtools.d.ts +0 -78
- package/dist/astro/extra/dragDriver.d.ts +0 -20
- package/dist/astro/extra/driverFactories.d.ts +0 -12
- package/dist/astro/extra/eventDriver.d.ts +0 -9
- package/dist/astro/extra/exactState.d.ts +0 -1
- package/dist/astro/extra/hmr.d.ts +0 -17
- package/dist/astro/extra/logDriver.d.ts +0 -2
- package/dist/astro/extra/processDrag.d.ts +0 -19
- package/dist/astro/extra/processForm.d.ts +0 -15
- package/dist/astro/extra/run.d.ts +0 -13
- package/dist/astro/extra/xstreamCompat.d.ts +0 -5
- package/dist/astro/index.d.ts +0 -19
- package/dist/astro/index.esm.js +0 -27
- package/dist/astro/jsx-dev-runtime.d.ts +0 -1
- package/dist/astro/jsx-runtime.d.ts +0 -4
- package/dist/astro/jsx.d.ts +0 -2
- package/dist/astro/pragma/fn.d.ts +0 -7
- package/dist/astro/pragma/index.d.ts +0 -7
- package/dist/astro/pragma/is.d.ts +0 -10
- package/dist/astro/server.d.ts +0 -12
- package/dist/astro/server.esm.js +0 -25
- package/dist/astro/switchable.d.ts +0 -7
- package/dist/collection.d.ts +0 -12
- package/dist/component.d.ts +0 -22
- package/dist/cycle/dom/BodyDOMSource.d.ts +0 -10
- package/dist/cycle/dom/DOMSource.d.ts +0 -11
- package/dist/cycle/dom/DocumentDOMSource.d.ts +0 -12
- package/dist/cycle/dom/ElementFinder.d.ts +0 -8
- package/dist/cycle/dom/EventDelegator.d.ts +0 -34
- package/dist/cycle/dom/IsolateModule.d.ts +0 -23
- package/dist/cycle/dom/MainDOMSource.d.ts +0 -32
- package/dist/cycle/dom/PriorityQueue.d.ts +0 -7
- package/dist/cycle/dom/ScopeChecker.d.ts +0 -9
- package/dist/cycle/dom/SymbolTree.d.ts +0 -9
- package/dist/cycle/dom/VNodeWrapper.d.ts +0 -8
- package/dist/cycle/dom/enrichEventStream.d.ts +0 -24
- package/dist/cycle/dom/fromEvent.d.ts +0 -6
- package/dist/cycle/dom/index.d.ts +0 -8
- package/dist/cycle/dom/isolate.d.ts +0 -9
- package/dist/cycle/dom/makeDOMDriver.d.ts +0 -11
- package/dist/cycle/dom/mockDOMSource.d.ts +0 -17
- package/dist/cycle/dom/modules.d.ts +0 -5
- package/dist/cycle/dom/snabbdom.d.ts +0 -22
- package/dist/cycle/dom/styleModule.d.ts +0 -13
- package/dist/cycle/dom/thunk.d.ts +0 -11
- package/dist/cycle/dom/utils.d.ts +0 -8
- package/dist/cycle/isolate/index.d.ts +0 -42
- package/dist/cycle/run/adapt.d.ts +0 -6
- package/dist/cycle/run/index.d.ts +0 -36
- package/dist/cycle/run/internals.d.ts +0 -8
- package/dist/cycle/run/types.d.ts +0 -49
- package/dist/cycle/state/Collection.d.ts +0 -29
- package/dist/cycle/state/StateSource.d.ts +0 -20
- package/dist/cycle/state/index.d.ts +0 -5
- package/dist/cycle/state/pickCombine.d.ts +0 -3
- package/dist/cycle/state/pickMerge.d.ts +0 -3
- package/dist/cycle/state/types.d.ts +0 -18
- package/dist/cycle/state/withState.d.ts +0 -17
- package/dist/extra/classes.d.ts +0 -7
- package/dist/extra/devtools.d.ts +0 -78
- package/dist/extra/dragDriver.d.ts +0 -20
- package/dist/extra/driverFactories.d.ts +0 -12
- package/dist/extra/eventDriver.d.ts +0 -9
- package/dist/extra/exactState.d.ts +0 -1
- package/dist/extra/hmr.d.ts +0 -17
- package/dist/extra/logDriver.d.ts +0 -2
- package/dist/extra/processDrag.d.ts +0 -19
- package/dist/extra/processForm.d.ts +0 -15
- package/dist/extra/run.d.ts +0 -13
- package/dist/extra/xstreamCompat.d.ts +0 -5
- package/dist/jsx-dev-runtime.d.ts +0 -1
- package/dist/jsx-dev-runtime.js +0 -224
- package/dist/jsx-runtime.d.ts +0 -4
- package/dist/jsx-runtime.js +0 -224
- package/dist/jsx.d.ts +0 -2
- package/dist/pragma/fn.d.ts +0 -7
- package/dist/pragma/index.d.ts +0 -7
- package/dist/pragma/is.d.ts +0 -10
- package/dist/switchable.d.ts +0 -7
- package/dist/vike/+config.cjs.js +0 -65
- package/src/component.ts +0 -2256
- package/src/cycle/isolate/index.ts +0 -196
- package/src/cycle/run/index.ts +0 -151
- package/src/cycle/run/internals.ts +0 -143
- package/src/cycle/state/Collection.ts +0 -174
- package/src/cycle/state/index.ts +0 -5
- package/src/cycle/state/pickCombine.ts +0 -167
- package/src/cycle/state/pickMerge.ts +0 -122
- package/src/cycle/state/withState.ts +0 -47
- package/src/pragma/fn.ts +0 -55
|
@@ -4,15 +4,24 @@ import {Scope} from './isolate';
|
|
|
4
4
|
import {isEqualNamespace} from './utils';
|
|
5
5
|
import SymbolTree from './SymbolTree';
|
|
6
6
|
|
|
7
|
+
// G-356 (D196): the element an event bubbles to and a scope walk goes up to: a moved element's
|
|
8
|
+
// home (`__sygnalHome`), else its parent. G-381: a home inside the element (a cycle) isn't
|
|
9
|
+
// followed, nor more than 98 homes per walk (`c` counts them: two elements naming each other)
|
|
10
|
+
export const upOf = (e: any, c: any): any => {
|
|
11
|
+
const h = e.__sygnalHome;
|
|
12
|
+
return h && !e.contains(h) && (c.$h = (c.$h | 0) + 1) < 99 ? h : e.parentNode;
|
|
13
|
+
};
|
|
14
|
+
|
|
7
15
|
export class IsolateModule {
|
|
8
|
-
|
|
9
|
-
private
|
|
16
|
+
// G-144: a scope can own several root elements (a fragment-rooted component)
|
|
17
|
+
private namespaceTree = new SymbolTree<Set<Element>, Scope>(x => x.scope);
|
|
18
|
+
private namespaceByElement: WeakMap<Element, Array<Scope>>;
|
|
10
19
|
private eventDelegator: EventDelegator | undefined;
|
|
11
20
|
|
|
12
|
-
private vnodesBeingRemoved: Array<
|
|
21
|
+
private vnodesBeingRemoved: Array<Element>;
|
|
13
22
|
|
|
14
23
|
constructor() {
|
|
15
|
-
this.namespaceByElement = new
|
|
24
|
+
this.namespaceByElement = new WeakMap<Element, Array<Scope>>();
|
|
16
25
|
this.vnodesBeingRemoved = [];
|
|
17
26
|
}
|
|
18
27
|
|
|
@@ -22,22 +31,23 @@ export class IsolateModule {
|
|
|
22
31
|
|
|
23
32
|
private insertElement(namespace: Array<Scope>, el: Element): void {
|
|
24
33
|
this.namespaceByElement.set(el, namespace);
|
|
25
|
-
this.namespaceTree.
|
|
34
|
+
this.namespaceTree.get(namespace, () => new Set())!.add(el);
|
|
26
35
|
}
|
|
27
36
|
|
|
37
|
+
// the element keeps its scope (a leaving element under a Transition still is the
|
|
38
|
+
// child's); only the scope's set of root elements forgets it
|
|
28
39
|
private removeElement(elm: Element): void {
|
|
29
|
-
this.namespaceByElement.
|
|
30
|
-
const
|
|
31
|
-
if (
|
|
32
|
-
|
|
40
|
+
const namespace = this.namespaceByElement.get(elm);
|
|
41
|
+
const els = namespace && this.namespaceTree.get(namespace);
|
|
42
|
+
if (els) {
|
|
43
|
+
els.delete(elm);
|
|
44
|
+
// P45-A: an unmounted scope leaves no node behind
|
|
45
|
+
if (!els.size) this.namespaceTree.delete(namespace!);
|
|
33
46
|
}
|
|
34
47
|
}
|
|
35
48
|
|
|
36
|
-
public
|
|
37
|
-
namespace
|
|
38
|
-
max?: number
|
|
39
|
-
): Element | undefined {
|
|
40
|
-
return this.namespaceTree.get(namespace, undefined, max);
|
|
49
|
+
public getElements(namespace: Array<Scope>): Array<Element> {
|
|
50
|
+
return [...(this.namespaceTree.get(namespace) || [])];
|
|
41
51
|
}
|
|
42
52
|
|
|
43
53
|
public getRootElement(elm: Element): Element | undefined {
|
|
@@ -45,13 +55,17 @@ export class IsolateModule {
|
|
|
45
55
|
return elm;
|
|
46
56
|
}
|
|
47
57
|
|
|
58
|
+
// G-356 (D196): an element a hook moved out of its component's DOM (a toaster region
|
|
59
|
+
// re-parented into an open modal <dialog>) names where it belongs as `__sygnalHome` (an
|
|
60
|
+
// element of its component), so it stays in its component's scope. With no scope root above
|
|
61
|
+
// elm (moved without one, or out of the app) the event has no scope here (before: threw
|
|
62
|
+
// 'No root element found'). G-381: upOf guards against a home cycle
|
|
48
63
|
let curr = elm;
|
|
64
|
+
const c = {};
|
|
49
65
|
while (!this.namespaceByElement.has(curr)) {
|
|
50
|
-
curr = curr
|
|
51
|
-
if (!curr) {
|
|
66
|
+
curr = upOf(curr, c);
|
|
67
|
+
if (!curr || curr.tagName === 'HTML') {
|
|
52
68
|
return undefined;
|
|
53
|
-
} else if (curr.tagName === 'HTML') {
|
|
54
|
-
throw new Error('No root element found, this should not happen at all');
|
|
55
69
|
}
|
|
56
70
|
}
|
|
57
71
|
return curr;
|
|
@@ -67,14 +81,35 @@ export class IsolateModule {
|
|
|
67
81
|
|
|
68
82
|
public createModule() {
|
|
69
83
|
const self = this;
|
|
84
|
+
// G-564: a vnode can be in the old tree and the new one (a component's cached vnode, a
|
|
85
|
+
// Collection item's copy, a hoisted vnode). When an ancestor is recreated (`alt ? <ol>{c}</ol>
|
|
86
|
+
// : <ul>{c}</ul>`, a new key), snabbdom creates it again and gives it the new element before it
|
|
87
|
+
// destroys the old subtree, so destroy hooks saw the new element (a widget inside wasn't
|
|
88
|
+
// unmounted, its scope lost the new element). A created element notes its children's elements
|
|
89
|
+
// (M: a child with one is mounted, or was), before they are created; a destroyed vnode gives
|
|
90
|
+
// its noted children their old elements back for their destroy hooks (and theirs, down the
|
|
91
|
+
// subtree), and they get the new ones again when the removal starts (S), before the insert
|
|
92
|
+
// hooks. (A vnode that moves to another parent still gives its own destroy hook the new one)
|
|
93
|
+
const M = new Map<any, any>(), S: any[] = [];
|
|
94
|
+
// G-573: a vnode in the new tree twice: its first note (its element before the patch) wins.
|
|
95
|
+
// A destroy hook that throws ends the patch before remove / post: the next patch first gives
|
|
96
|
+
// the vnodes their new elements back and forgets the notes (pre)
|
|
97
|
+
const back = (c: any) => M.has(c) && (S.push(c, c.elm), c.elm = M.get(c));
|
|
98
|
+
const ret = () => { for (let e; S.length; ) e = S.pop(), S.pop().elm = e; };
|
|
70
99
|
return {
|
|
100
|
+
pre() {
|
|
101
|
+
ret();
|
|
102
|
+
M.clear();
|
|
103
|
+
},
|
|
104
|
+
|
|
71
105
|
create(emptyVNode: VNode, vNode: VNode) {
|
|
72
|
-
const {elm, data = {}} = vNode;
|
|
106
|
+
const {elm, data = {}, children} = vNode;
|
|
73
107
|
const namespace: Array<Scope> = (data as any).isolate;
|
|
74
108
|
|
|
75
109
|
if (Array.isArray(namespace)) {
|
|
76
110
|
self.insertElement(namespace, elm as Element);
|
|
77
111
|
}
|
|
112
|
+
children?.forEach((c: any) => c?.elm && M.set(c, M.get(c) || c.elm));
|
|
78
113
|
},
|
|
79
114
|
|
|
80
115
|
update(oldVNode: VNode, vNode: VNode) {
|
|
@@ -93,32 +128,27 @@ export class IsolateModule {
|
|
|
93
128
|
}
|
|
94
129
|
},
|
|
95
130
|
|
|
131
|
+
// (the elements as they are now: post runs after the vnodes got their new ones back)
|
|
96
132
|
destroy(vNode: VNode) {
|
|
97
|
-
|
|
133
|
+
vNode.children?.forEach(back);
|
|
134
|
+
self.vnodesBeingRemoved.push(vNode.elm as Element);
|
|
98
135
|
},
|
|
99
136
|
|
|
100
137
|
remove(vNode: VNode, cb: Function) {
|
|
101
|
-
self.vnodesBeingRemoved.push(vNode);
|
|
138
|
+
self.vnodesBeingRemoved.push(vNode.elm as Element);
|
|
139
|
+
ret();
|
|
102
140
|
cb();
|
|
103
141
|
},
|
|
104
142
|
|
|
105
143
|
post() {
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
? (vnode.data as any).isolation
|
|
112
|
-
: undefined;
|
|
113
|
-
if (namespace !== undefined) {
|
|
114
|
-
self.removeElement(namespace);
|
|
115
|
-
}
|
|
116
|
-
(self.eventDelegator as EventDelegator).removeElement(
|
|
117
|
-
vnode.elm as Element,
|
|
118
|
-
namespace
|
|
119
|
-
);
|
|
144
|
+
// G-144: a removed root element is no longer one of its scope's roots (an element no
|
|
145
|
+
// scope has as a root isn't in any set: removing it does nothing)
|
|
146
|
+
for (const elm of self.vnodesBeingRemoved) {
|
|
147
|
+
self.removeElement(elm);
|
|
148
|
+
(self.eventDelegator as EventDelegator).removeElement(elm);
|
|
120
149
|
}
|
|
121
150
|
self.vnodesBeingRemoved = [];
|
|
151
|
+
M.clear();
|
|
122
152
|
},
|
|
123
153
|
};
|
|
124
154
|
}
|
|
@@ -8,9 +8,11 @@ import {BodyDOMSource} from './BodyDOMSource';
|
|
|
8
8
|
import {VNode} from './snabbdom';
|
|
9
9
|
import {enrichEventStream, EnrichedEventStream} from './enrichEventStream';
|
|
10
10
|
import {ElementFinder} from './ElementFinder';
|
|
11
|
-
import {makeIsolateSink, getScopeObj, Scope, IsolateSink} from './isolate';
|
|
11
|
+
import {makeIsolateSink, makeIsolateValue, getScopeObj, Scope, IsolateSink} from './isolate';
|
|
12
12
|
import {IsolateModule} from './IsolateModule';
|
|
13
13
|
import {EventDelegator} from './EventDelegator';
|
|
14
|
+
// [diagnostics hook] no-op when diagnostics are off
|
|
15
|
+
import {onSelector} from '../../extra/diagnostics/index';
|
|
14
16
|
|
|
15
17
|
export interface SpecialSelector {
|
|
16
18
|
body: BodyDOMSource;
|
|
@@ -36,6 +38,7 @@ export class MainDOMSource {
|
|
|
36
38
|
source._name
|
|
37
39
|
);
|
|
38
40
|
this.isolateSink = makeIsolateSink(this._namespace) as any;
|
|
41
|
+
this.isolateValue = makeIsolateValue(this._namespace);
|
|
39
42
|
}
|
|
40
43
|
|
|
41
44
|
private _elements(): Stream<Array<Element>> {
|
|
@@ -77,7 +80,9 @@ export class MainDOMSource {
|
|
|
77
80
|
selector: T
|
|
78
81
|
): SpecialSelector[T];
|
|
79
82
|
public select(selector: string): MainDOMSource;
|
|
80
|
-
public select(selector:
|
|
83
|
+
public select(selector: any): DOMSource {
|
|
84
|
+
// CT-1: a control (controls()) selects its elements by its marker, [data-control="<Key>"]
|
|
85
|
+
if (selector?.__sygnalControl) selector = '' + selector;
|
|
81
86
|
if (typeof selector !== 'string') {
|
|
82
87
|
throw new Error(
|
|
83
88
|
`DOM driver's select() expects the argument to be a ` +
|
|
@@ -91,6 +96,8 @@ export class MainDOMSource {
|
|
|
91
96
|
return new BodyDOMSource(this._name);
|
|
92
97
|
}
|
|
93
98
|
|
|
99
|
+
if (selector !== ':root') onSelector(this, selector.trim());
|
|
100
|
+
|
|
94
101
|
const namespace =
|
|
95
102
|
selector === ':root'
|
|
96
103
|
? []
|
|
@@ -111,6 +118,9 @@ export class MainDOMSource {
|
|
|
111
118
|
options?: EventsFnOptions,
|
|
112
119
|
bubbles?: boolean
|
|
113
120
|
): EnrichedEventStream<HTMLElementEventMap[K]>;
|
|
121
|
+
// PLAN-5 0-S6: any other name (a custom element's 'wa-hover', a widget's or element's
|
|
122
|
+
// CustomEvent): the overload above only typed the built-in names (types only)
|
|
123
|
+
public events(eventType: string, options?: EventsFnOptions, bubbles?: boolean): EnrichedEventStream<Event>;
|
|
114
124
|
public events(
|
|
115
125
|
eventType: string,
|
|
116
126
|
options: EventsFnOptions = {},
|
|
@@ -140,4 +150,5 @@ export class MainDOMSource {
|
|
|
140
150
|
|
|
141
151
|
public isolateSource: (source: MainDOMSource, scope: string) => MainDOMSource;
|
|
142
152
|
public isolateSink: IsolateSink<VNode>;
|
|
153
|
+
public isolateValue: (node: any, scope: string) => any;
|
|
143
154
|
}
|
|
@@ -20,13 +20,15 @@ export default class PriorityQueue<T> {
|
|
|
20
20
|
}
|
|
21
21
|
}
|
|
22
22
|
|
|
23
|
-
|
|
23
|
+
// returns how many are left
|
|
24
|
+
public delete(t: T): number {
|
|
24
25
|
for (let i = 0; i < this.arr.length; i++) {
|
|
25
26
|
if (this.arr[i] === t) {
|
|
26
27
|
this.arr.splice(i, 1);
|
|
27
28
|
this.prios.splice(i, 1);
|
|
28
|
-
|
|
29
|
+
break;
|
|
29
30
|
}
|
|
30
31
|
}
|
|
32
|
+
return this.arr.length;
|
|
31
33
|
}
|
|
32
34
|
}
|
|
@@ -1,56 +1,30 @@
|
|
|
1
|
-
|
|
1
|
+
// [payload, children, number of children]: the count makes delete's "is this node empty" O(1)
|
|
2
|
+
// (G-290: Object.keys(children) per removal made removing n siblings O(n²))
|
|
3
|
+
type Node<Payload> = [Payload | undefined, InternalTree<Payload>, number];
|
|
2
4
|
|
|
3
5
|
interface InternalTree<Payload> {
|
|
4
6
|
[name: string]: Node<Payload>;
|
|
5
7
|
}
|
|
6
8
|
|
|
7
9
|
export default class SymbolTree<Payload, T> {
|
|
8
|
-
private tree: Node<Payload> = [
|
|
10
|
+
private tree: Node<Payload> = [, {}, 0];
|
|
9
11
|
|
|
10
12
|
constructor(private mapper: (t: T) => string) {}
|
|
11
13
|
|
|
12
|
-
public set(path: Array<T>, element: Payload | undefined, max?: number): void {
|
|
13
|
-
let curr = this.tree;
|
|
14
|
-
const _max = max !== undefined ? max : path.length;
|
|
15
|
-
for (let i = 0; i < _max; i++) {
|
|
16
|
-
const n = this.mapper(path[i]);
|
|
17
|
-
let child: Node<Payload> = curr[1][n];
|
|
18
|
-
if (!child) {
|
|
19
|
-
child = [undefined, {}];
|
|
20
|
-
curr[1][n] = child;
|
|
21
|
-
}
|
|
22
|
-
curr = child;
|
|
23
|
-
}
|
|
24
|
-
curr[0] = element;
|
|
25
|
-
}
|
|
26
|
-
|
|
27
|
-
public getDefault(
|
|
28
|
-
path: Array<T>,
|
|
29
|
-
mkDefaultElement: () => Payload,
|
|
30
|
-
max?: number
|
|
31
|
-
): Payload {
|
|
32
|
-
return this.get(path, mkDefaultElement, max) as Payload;
|
|
33
|
-
}
|
|
34
|
-
|
|
35
14
|
public get(
|
|
36
15
|
path: Array<T>,
|
|
37
16
|
mkDefaultElement?: () => Payload,
|
|
38
|
-
max
|
|
17
|
+
max = path.length
|
|
39
18
|
): Payload | undefined {
|
|
40
19
|
let curr = this.tree;
|
|
41
|
-
|
|
42
|
-
for (let i = 0; i < _max; i++) {
|
|
20
|
+
for (let i = 0; i < max; i++) {
|
|
43
21
|
const n = this.mapper(path[i]);
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
curr[1][n] = child;
|
|
49
|
-
} else {
|
|
50
|
-
return undefined;
|
|
51
|
-
}
|
|
22
|
+
if (!curr[1][n]) {
|
|
23
|
+
if (!mkDefaultElement) return undefined;
|
|
24
|
+
curr[2]++; // G-290: count the children
|
|
25
|
+
curr[1][n] = [, {}, 0];
|
|
52
26
|
}
|
|
53
|
-
curr =
|
|
27
|
+
curr = curr[1][n];
|
|
54
28
|
}
|
|
55
29
|
if (mkDefaultElement && !curr[0]) {
|
|
56
30
|
curr[0] = mkDefaultElement();
|
|
@@ -58,15 +32,12 @@ export default class SymbolTree<Payload, T> {
|
|
|
58
32
|
return curr[0];
|
|
59
33
|
}
|
|
60
34
|
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
const
|
|
65
|
-
if (
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
curr = child;
|
|
69
|
-
}
|
|
70
|
-
delete curr[1][this.mapper(path[path.length - 1])];
|
|
35
|
+
// P45-A: drop the payload at path and prune the nodes left empty; true when node is empty
|
|
36
|
+
public delete(path: Array<T>, max = path.length, node = this.tree, i = 0): boolean {
|
|
37
|
+
if (i < max) {
|
|
38
|
+
const k = this.mapper(path[i]), child = node[1][k];
|
|
39
|
+
if (child && this.delete(path, max, child, i + 1)) delete node[1][k], node[2]--;
|
|
40
|
+
} else node[0] = undefined;
|
|
41
|
+
return !node[0] && !node[2];
|
|
71
42
|
}
|
|
72
43
|
}
|
|
@@ -0,0 +1,76 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Snabbdom module that unsets a removed `className` prop (B-012).
|
|
3
|
+
*
|
|
4
|
+
* Problem: `className` goes through snabbdom's propsModule, which writes new
|
|
5
|
+
* and changed props but never unsets a prop that disappears. So when snabbdom
|
|
6
|
+
* reuses an element (`<p className="placeholder">` -> `<p>`), the old class
|
|
7
|
+
* stays. A nullish `className` is worse: propsModule writes the string
|
|
8
|
+
* "null"/"false".
|
|
9
|
+
*
|
|
10
|
+
* Fix: runs after propsModule. When `className` is gone (or nullish/false),
|
|
11
|
+
* drop the classes it had set, keeping the classes from the selector
|
|
12
|
+
* (`p.foo`) and the truthy `class={{...}}` entries.
|
|
13
|
+
*/
|
|
14
|
+
|
|
15
|
+
import type {VNode} from 'snabbdom/build/vnode.js';
|
|
16
|
+
|
|
17
|
+
function classObject(vnode: VNode): Array<string> {
|
|
18
|
+
const out: Array<string> = [];
|
|
19
|
+
const klass: any = vnode.data?.class;
|
|
20
|
+
if (klass && typeof klass === 'object') {
|
|
21
|
+
for (const name in klass) if (klass[name]) out.push(name);
|
|
22
|
+
}
|
|
23
|
+
return out;
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
function baseClasses(vnode: VNode): Array<string> {
|
|
27
|
+
const sel = vnode.sel || '';
|
|
28
|
+
const hashIdx = sel.indexOf('#');
|
|
29
|
+
const dotIdx = sel.indexOf('.', hashIdx);
|
|
30
|
+
const fromSel = dotIdx > 0 ? sel.slice(dotIdx + 1).split('.') : [];
|
|
31
|
+
return fromSel.concat(classObject(vnode));
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
function addAll(elm: any, names: Array<string>): void {
|
|
35
|
+
for (const name of names) if (name) elm.classList.add(name);
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
const isSet = (cn: any) => cn != null && cn !== false;
|
|
39
|
+
const tokens = (cn: any) => (typeof cn === 'string' ? cn.split(/\s+/).filter(Boolean) : []);
|
|
40
|
+
|
|
41
|
+
function syncClassName(oldVnode: VNode, vnode: VNode): void {
|
|
42
|
+
const props: any = vnode.data?.props;
|
|
43
|
+
const oldProps: any = oldVnode.data?.props;
|
|
44
|
+
const hasKey = !!props && 'className' in props;
|
|
45
|
+
const oldCn = oldProps ? oldProps.className : undefined;
|
|
46
|
+
// P45-A: keyed on the prop (B-012), not the tag: nothing to do when neither vnode has one
|
|
47
|
+
if (!hasKey && !isSet(oldCn)) return;
|
|
48
|
+
const elm = vnode.elm as any;
|
|
49
|
+
if (!elm || !elm.classList) return;
|
|
50
|
+
const cn = hasKey ? props.className : undefined;
|
|
51
|
+
if (isSet(cn)) {
|
|
52
|
+
// propsModule replaced the whole attribute: put the selector classes and the
|
|
53
|
+
// class={{...}} entries back
|
|
54
|
+
if (!oldProps || oldProps.className !== cn) addAll(elm, baseClasses(vnode));
|
|
55
|
+
return;
|
|
56
|
+
}
|
|
57
|
+
if (hasKey) {
|
|
58
|
+
// propsModule wrote String(cn) over the whole attribute: rebuild it
|
|
59
|
+
if (!oldProps || oldProps.className !== cn) {
|
|
60
|
+
elm.className = baseClasses(vnode).join(' ');
|
|
61
|
+
if (elm.className === '') elm.removeAttribute('class');
|
|
62
|
+
}
|
|
63
|
+
return;
|
|
64
|
+
}
|
|
65
|
+
const keep = baseClasses(vnode);
|
|
66
|
+
for (const name of tokens(oldCn)) {
|
|
67
|
+
if (keep.indexOf(name) === -1) elm.classList.remove(name);
|
|
68
|
+
}
|
|
69
|
+
addAll(elm, keep);
|
|
70
|
+
if (elm.getAttribute('class') === '') elm.removeAttribute('class');
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
export const classNameModule = {
|
|
74
|
+
create: syncClassName,
|
|
75
|
+
update: syncClassName,
|
|
76
|
+
};
|
|
@@ -0,0 +1,50 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Snabbdom module that keeps controlled form fields in sync with the vnode (B-004).
|
|
3
|
+
*
|
|
4
|
+
* Problem: snabbdom's propsModule only writes `value`/`checked` when the prop
|
|
5
|
+
* differs from the previous vnode's prop. If the user types 'x' and an action
|
|
6
|
+
* resets the state to '' within one render window, the 'x' render is
|
|
7
|
+
* coalesced away: the vnodes go '' -> '' and the typed text stays in the DOM.
|
|
8
|
+
*
|
|
9
|
+
* Fix: after propsModule has run, compare `value`/`checked` props against the
|
|
10
|
+
* live element and write them when they differ. Only form fields (INPUT,
|
|
11
|
+
* TEXTAREA, SELECT; not input type=file) are controlled: `value` compares as a
|
|
12
|
+
* string, `checked` as a boolean (1H-7). A present-but-nullish `value` keeps an
|
|
13
|
+
* input/textarea at '' and a nullish `checked` at false (D49); an absent prop
|
|
14
|
+
* leaves the field to the user. D196: a form-associated custom element is a field
|
|
15
|
+
* too (its value is written as the prop). Other elements with a value prop
|
|
16
|
+
* (<progress>, <meter>, custom elements that aren't form-associated) are left alone.
|
|
17
|
+
*
|
|
18
|
+
* (PLAN-4.6 R6, G-347: G-146's input stamps are gone with the old core: the core renders a
|
|
19
|
+
* state in the flush it is written in, so no render shows an older state than the field.)
|
|
20
|
+
*/
|
|
21
|
+
|
|
22
|
+
import type {VNode} from 'snabbdom/build/vnode.js';
|
|
23
|
+
|
|
24
|
+
// P45-A: a form field by its vnode's tag (sel), checked before any other work: most vnodes aren't.
|
|
25
|
+
// D196: a form-associated custom element (a hyphenated tag whose class has `static
|
|
26
|
+
// formAssociated = true`, e.g. Web Awesome's wa-input / wa-rating) is a field too; only a
|
|
27
|
+
// hyphenated tag's element is read
|
|
28
|
+
export const isField = (vnode: VNode): any =>
|
|
29
|
+
/^(input|textarea|select)(?![\w-])/i.test(vnode.sel as string) || /^\w+-/.test(vnode.sel as string) && (vnode.elm as any).constructor.formAssociated;
|
|
30
|
+
|
|
31
|
+
function syncControlled(oldVnode: VNode, vnode: VNode): void {
|
|
32
|
+
if (!isField(vnode)) return;
|
|
33
|
+
const props = vnode.data?.props;
|
|
34
|
+
const elm = vnode.elm as any;
|
|
35
|
+
if (!props || !elm || elm.type == 'file') return;
|
|
36
|
+
const oldProps: any = oldVnode.data?.props || {};
|
|
37
|
+
const {value, checked} = props;
|
|
38
|
+
// Only the case propsModule skipped (prop unchanged); it handles real changes.
|
|
39
|
+
// A nullish <select> value is left alone: on create the browser shows the first option.
|
|
40
|
+
if ('value' in props && value === oldProps.value && (value != null || elm.tagName != 'SELECT')) {
|
|
41
|
+
const v = value == null ? '' : String(value);
|
|
42
|
+
// a custom element's value can be a number: compared as a string, written as the prop
|
|
43
|
+
if (String(elm.value) !== v) elm.value = elm.constructor.formAssociated ? value : v;
|
|
44
|
+
}
|
|
45
|
+
if ('checked' in props && checked === oldProps.checked && elm.checked !== !!checked) {
|
|
46
|
+
elm.checked = !!checked;
|
|
47
|
+
}
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
export const controlledInputModule = {update: syncControlled};
|
|
@@ -15,8 +15,16 @@ export interface EnrichedEventStream<T = Event> extends Stream<T> {
|
|
|
15
15
|
|
|
16
16
|
key(): EnrichedEventStream<string>;
|
|
17
17
|
key<R>(fn: (key: string) => R): EnrichedEventStream<R>;
|
|
18
|
+
|
|
19
|
+
/** e.detail: a CustomEvent's payload (a widget's emit(name, detail), a web component's event) */
|
|
20
|
+
detail<D = any>(): EnrichedEventStream<D>;
|
|
21
|
+
detail<R, D = any>(fn: (detail: D) => R): EnrichedEventStream<R>;
|
|
18
22
|
}
|
|
19
23
|
|
|
24
|
+
// one enricher: a method that maps each event through `get`, then `fn` when given
|
|
25
|
+
const pick = (s$: any, get: (e: any) => any) => (fn?: (v: any) => any): any =>
|
|
26
|
+
enrichEventStream(s$.map((e: any) => (e = get(e), fn ? fn(e) : e)))
|
|
27
|
+
|
|
20
28
|
/**
|
|
21
29
|
* Adds chainable convenience methods to a DOM event stream.
|
|
22
30
|
*
|
|
@@ -26,53 +34,29 @@ export interface EnrichedEventStream<T = Event> extends Stream<T> {
|
|
|
26
34
|
* DOM.click('.item').data('id', Number)
|
|
27
35
|
* DOM.change('.checkbox').checked()
|
|
28
36
|
* DOM.keydown('.field').key()
|
|
37
|
+
* DOM.select('.due').events('change').detail()
|
|
29
38
|
*/
|
|
30
39
|
export function enrichEventStream(stream$: any): any {
|
|
31
|
-
// .value(fn?) —
|
|
32
|
-
stream$.value =
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
const
|
|
44
|
-
return
|
|
45
|
-
})
|
|
46
|
-
return enrichEventStream(mapped);
|
|
47
|
-
}
|
|
48
|
-
|
|
49
|
-
// .data(name, fn?) — extract e.target.dataset[name]
|
|
50
|
-
stream$.data = function data(name: string, fn?: (val: any) => any): any {
|
|
51
|
-
const mapped = stream$.map((e: any) => {
|
|
52
|
-
const el = e?.target instanceof Element ? e.target.closest(`[data-${name}]`) || e.target : e?.target
|
|
53
|
-
const val = el?.dataset?.[name]
|
|
54
|
-
return fn ? fn(val) : val
|
|
55
|
-
});
|
|
56
|
-
return enrichEventStream(mapped);
|
|
40
|
+
// .value(fn?) — e.target.value; .checked(fn?) — e.target.checked as a boolean
|
|
41
|
+
stream$.value = pick(stream$, (e: any) => e?.target?.value)
|
|
42
|
+
stream$.checked = pick(stream$, (e: any) => !!e?.target?.checked)
|
|
43
|
+
// .data(name, fn?) — dataset[name] from e.target or its nearest ancestor that has it.
|
|
44
|
+
// dataset keys are camelCase but attributes are kebab-case (`taskId` is `data-task-id`), so the
|
|
45
|
+
// closest() selector converts (B-028). The name may be given either way: `.data('taskId')` and
|
|
46
|
+
// `.data('task-id')` read the same attribute (3E/R3).
|
|
47
|
+
stream$.data = (name: string, fn?: (v: any) => any): any => {
|
|
48
|
+
const key = String(name).replace(/-([a-z])/g, (_, c) => c.toUpperCase())
|
|
49
|
+
const attr = `[data-${key.replace(/[A-Z]/g, c => '-' + c.toLowerCase())}]`
|
|
50
|
+
return pick(stream$, (e: any) => {
|
|
51
|
+
const t = e?.target
|
|
52
|
+
const el = typeof t?.closest == 'function' ? t.closest(attr) || t : t
|
|
53
|
+
return el?.dataset?.[key]
|
|
54
|
+
})(fn)
|
|
57
55
|
}
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
stream$.
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
return fn ? fn(el) : el
|
|
64
|
-
});
|
|
65
|
-
return enrichEventStream(mapped);
|
|
66
|
-
}
|
|
67
|
-
|
|
68
|
-
// .key(fn?) — extract e.key (keyboard events)
|
|
69
|
-
stream$.key = function key(fn?: (val: any) => any): any {
|
|
70
|
-
const mapped = stream$.map((e: any) => {
|
|
71
|
-
const val = e?.key
|
|
72
|
-
return fn ? fn(val) : val
|
|
73
|
-
});
|
|
74
|
-
return enrichEventStream(mapped);
|
|
75
|
-
}
|
|
76
|
-
|
|
56
|
+
// .target(fn?) — e.target; .key(fn?) — e.key (keyboard events)
|
|
57
|
+
stream$.target = pick(stream$, (e: any) => e?.target)
|
|
58
|
+
stream$.key = pick(stream$, (e: any) => e?.key)
|
|
59
|
+
// .detail(fn?) — e.detail (CustomEvents: widgets' emit(), web components) (PLAN-5 W-3)
|
|
60
|
+
stream$.detail = pick(stream$, (e: any) => e?.detail)
|
|
77
61
|
return stream$
|
|
78
62
|
}
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
import {Fragment as _Fragment} from 'snabbdom/build/jsx.js';
|
|
2
|
+
|
|
3
|
+
// Tag Fragment so we can identify it even after minification mangles Function.name.
|
|
4
|
+
// Its own module so the JSX runtime entries (which keep snabbdom external, D188) take it
|
|
5
|
+
// without the rest of the snabbdom barrel
|
|
6
|
+
(_Fragment as any).__sygnalFragment = true;
|
|
7
|
+
export const Fragment = _Fragment;
|
package/src/cycle/dom/isolate.ts
CHANGED
|
@@ -15,37 +15,40 @@ export type IsolateSink<T extends VNode> = (
|
|
|
15
15
|
export function makeIsolateSink<T extends VNode>(
|
|
16
16
|
namespace: Array<Scope>
|
|
17
17
|
): IsolateSink<T> {
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
}
|
|
18
|
+
const value = makeIsolateValue(namespace);
|
|
19
|
+
return (sink, scope) => scope === ':root' ? sink : sink.map(node => value(node, scope) as T);
|
|
20
|
+
}
|
|
22
21
|
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
newNode.key !== undefined
|
|
42
|
-
? newNode.key
|
|
43
|
-
: JSON.stringify(newNode.data.isolate),
|
|
44
|
-
} as T;
|
|
45
|
-
});
|
|
22
|
+
/**
|
|
23
|
+
* PLAN-4.6: the value-level isolateSink (the core scopes each instance's vnode without a
|
|
24
|
+
* stream per instance): the same mapping, applied to one vnode
|
|
25
|
+
*/
|
|
26
|
+
export function makeIsolateValue(namespace: Array<Scope>): (node: any, scope: string) => any {
|
|
27
|
+
return (node, scope) => {
|
|
28
|
+
if (scope === ':root' || !node) {
|
|
29
|
+
return node;
|
|
30
|
+
}
|
|
31
|
+
const isolate = namespace.concat([getScopeObj(scope)]);
|
|
32
|
+
const newNode = scoped(node, isolate);
|
|
33
|
+
return {
|
|
34
|
+
...newNode,
|
|
35
|
+
key:
|
|
36
|
+
newNode.key !== undefined
|
|
37
|
+
? newNode.key
|
|
38
|
+
: JSON.stringify((newNode.data && newNode.data.isolate) || isolate),
|
|
39
|
+
};
|
|
46
40
|
};
|
|
47
41
|
}
|
|
48
42
|
|
|
43
|
+
// G-144: a fragment has no element of its own, so each of its top-level elements (through
|
|
44
|
+
// nested fragments) carries the scope; the fragment keeps the key
|
|
45
|
+
function scoped(node: any, isolate: Array<Scope>): any {
|
|
46
|
+
return !node || typeof node != 'object' ? node
|
|
47
|
+
: node.sel ? {...node, data: {...node.data, isolate: node.data && Array.isArray(node.data.isolate) ? node.data.isolate : isolate}}
|
|
48
|
+
: node.children ? {...node, children: node.children.map((c: any) => scoped(c, isolate))}
|
|
49
|
+
: node;
|
|
50
|
+
}
|
|
51
|
+
|
|
49
52
|
export function getScopeObj(scope: string): Scope {
|
|
50
53
|
return {
|
|
51
54
|
type: isClassOrId(scope) ? 'sibling' : 'total',
|