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
package/src/pragma/index.ts
CHANGED
|
@@ -1,76 +1,110 @@
|
|
|
1
1
|
|
|
2
2
|
import * as is from './is'
|
|
3
|
-
import * as fn from './fn'
|
|
4
3
|
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
4
|
+
// P45-B: a vnode this pragma made whose subtree has no component (or other marker the view
|
|
5
|
+
// walk handles), no form field and no vnode from elsewhere. the core's view walk skips it
|
|
6
|
+
// (and, at the root, the whole walk). The flag is on the prototype, not enumerable, so the
|
|
7
|
+
// vnode's own fields are snabbdom's six. Checked by name (`$p`), not by class (a second copy of
|
|
8
|
+
// the core, e.g. Astro's SSR bundle, makes its own).
|
|
9
|
+
function Plain(this: any, sel: any, data: any, children: any, text: any, key: any) {
|
|
10
|
+
this.sel = sel
|
|
11
|
+
this.data = data
|
|
12
|
+
this.children = children
|
|
13
|
+
this.text = text
|
|
14
|
+
this.elm = undefined
|
|
15
|
+
this.key = key
|
|
12
16
|
}
|
|
17
|
+
Object.defineProperty(Plain.prototype, '$p', { value: 1 })
|
|
13
18
|
|
|
14
|
-
const
|
|
15
|
-
|
|
16
|
-
|
|
19
|
+
const createTextElement = (text: any): any => is.text(text) ? new (Plain as any)(undefined, undefined, undefined, text, undefined) : undefined
|
|
20
|
+
// A tag whose tree isn't plain: a form field (a superset of isField: a re-run view with the same
|
|
21
|
+
// output keeps its last vnode (P46-P sameTree), which would skip the controlled-input module's
|
|
22
|
+
// re-sync of the DOM value) or a host the view walk knows by its string tag (<collection>,
|
|
23
|
+
// <switchable>). D196: a custom element (a hyphenated tag) may be a form-associated field
|
|
24
|
+
const FIELD = /^(input|textarea|select)|-/i
|
|
25
|
+
// P46-P: by tag: 1 a form field (FIELD: a prefix), 4 a host (<collection>, <switchable>), 2 an SVG
|
|
26
|
+
// tag. G-350: keyed by the tag part of the selector (before its first '#' or '.'), so dynamic
|
|
27
|
+
// selectors (`li#row-${id}`) don't grow it. A selector with an id or class keeps only bit 1, as
|
|
28
|
+
// P46-P's full-selector tests did (the host and SVG tags match the whole selector)
|
|
29
|
+
const tags: Record<string, number> = Object.create(null)
|
|
30
|
+
const bits = (tag: string): number => tags[tag] = +FIELD.test(tag) | (/^(collection|switchable)$/i.test(tag) ? 4 : 0) | (tag in svgTags ? 2 : 0) | (/-/.test(tag) ? 8 : 0)
|
|
31
|
+
const tagBits = (sel: string): number => {
|
|
32
|
+
const t = tags[sel]
|
|
33
|
+
if (t !== undefined) return t
|
|
34
|
+
let i = 0
|
|
35
|
+
for (let c; i < sel.length && (c = sel.charCodeAt(i)) != 35 && c != 46; i++);
|
|
36
|
+
if (i == sel.length) return bits(sel)
|
|
37
|
+
const tag = sel.slice(0, i)
|
|
38
|
+
return (tags[tag] ?? bits(tag)) & 9
|
|
39
|
+
}
|
|
17
40
|
|
|
41
|
+
// Mutates the vnode (and its SVG children, not below a foreignObject: that contains HTML):
|
|
42
|
+
// the props become attributes (className as class, attrs win), and the SVG namespace is set
|
|
43
|
+
const applySvg = (vnode: any): void => {
|
|
44
|
+
// Skip text vnodes (sel is undefined) and nullish values; a vnode this pragma made in the
|
|
45
|
+
// SVG namespace was done, with its subtree, when it was made
|
|
46
|
+
if (!vnode || vnode.sel === undefined || (vnode.$p && vnode.data.ns)) return
|
|
18
47
|
const data = vnode.data || {}
|
|
19
48
|
const props = data.props || {}
|
|
20
|
-
const
|
|
21
|
-
const
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
// foreignObject contains HTML, not SVG — do not recurse into its children
|
|
29
|
-
{ children: (!Array.isArray(vnode.children) || vnode.sel === 'foreignObject')
|
|
30
|
-
? vnode.children
|
|
31
|
-
: vnode.children.map((child: any) => applySvg(child))
|
|
32
|
-
}
|
|
33
|
-
)
|
|
49
|
+
const attrs: any = {}
|
|
50
|
+
for (const k in props) if (k != 'className' && props[k] !== undefined) attrs[k] = props[k]
|
|
51
|
+
if (props.className !== undefined) attrs.class = props.className
|
|
52
|
+
for (const k in data.attrs) if (data.attrs[k] !== undefined) attrs[k] = data.attrs[k]
|
|
53
|
+
const svgData = { ...data, ns: 'http://www.w3.org/2000/svg', attrs }
|
|
54
|
+
delete svgData.props
|
|
55
|
+
vnode.data = svgData
|
|
56
|
+
if (Array.isArray(vnode.children) && vnode.sel !== 'foreignObject') vnode.children.forEach(applySvg)
|
|
34
57
|
}
|
|
35
58
|
|
|
36
|
-
const
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
59
|
+
const svgTags: Record<string, number> = {
|
|
60
|
+
// Container / structural
|
|
61
|
+
svg: 1, g: 1, defs: 1, symbol: 1, use: 1,
|
|
62
|
+
// Shape
|
|
63
|
+
circle: 1, ellipse: 1, line: 1, path: 1, polygon: 1, polyline: 1, rect: 1,
|
|
64
|
+
// Text (no HTML collision: HTML has no <text>, <tspan>, or <textPath>)
|
|
65
|
+
text: 1, tspan: 1, textPath: 1,
|
|
66
|
+
// Gradient / paint
|
|
67
|
+
linearGradient: 1, radialGradient: 1, stop: 1, pattern: 1,
|
|
68
|
+
// Clipping / masking
|
|
69
|
+
clipPath: 1, mask: 1,
|
|
70
|
+
// Marker
|
|
71
|
+
marker: 1,
|
|
72
|
+
// Filter primitives
|
|
73
|
+
filter: 1, feBlend: 1, feColorMatrix: 1, feComponentTransfer: 1,
|
|
74
|
+
feComposite: 1, feConvolveMatrix: 1, feDiffuseLighting: 1,
|
|
75
|
+
feDisplacementMap: 1, feDropShadow: 1, feFlood: 1, feGaussianBlur: 1,
|
|
76
|
+
feImage: 1, feMerge: 1, feMergeNode: 1, feMorphology: 1, feOffset: 1,
|
|
77
|
+
fePointLight: 1, feSpecularLighting: 1, feSpotLight: 1, feTile: 1,
|
|
78
|
+
feTurbulence: 1, feFuncR: 1, feFuncG: 1, feFuncB: 1, feFuncA: 1,
|
|
79
|
+
// Descriptive (excluding 'title' — collides with HTML <title>)
|
|
80
|
+
desc: 1, metadata: 1,
|
|
81
|
+
// Other (excluding 'a', 'image', 'style', 'script' — collide with HTML)
|
|
82
|
+
foreignObject: 1, switch: 1,
|
|
83
|
+
// Animation
|
|
84
|
+
animate: 1, animateMotion: 1, animateTransform: 1, set: 1, mpath: 1,
|
|
44
85
|
}
|
|
45
86
|
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
}
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
for (
|
|
56
|
-
const
|
|
57
|
-
|
|
58
|
-
|
|
87
|
+
// Adds snabbdom hooks to data.hook (a copy); a hook already there runs first (also PLAN-5
|
|
88
|
+
// widget hosts: extra/widget.ts)
|
|
89
|
+
export const chainHooks = (data: any, hooks: Record<string, (...args: any[]) => void>): void => {
|
|
90
|
+
const existing = data.hook || {}
|
|
91
|
+
const hook = { ...existing }
|
|
92
|
+
// G-485 / G-521: a chained hook function is marked `s` (hydration adopts an element whose
|
|
93
|
+
// chained insert has a postpatch: a ref, autoFocus, a widget); `u`, an insert hook of the
|
|
94
|
+
// user's own under it (its element is made again so that insert runs, as an unchained one is)
|
|
95
|
+
if (existing.insert && !existing.insert.s) hook.u = 1
|
|
96
|
+
for (const name in hooks) {
|
|
97
|
+
const f: any = hook[name] = (...args: any[]) => {
|
|
98
|
+
if (existing[name]) existing[name](...args)
|
|
99
|
+
hooks[name](...args)
|
|
59
100
|
}
|
|
101
|
+
f.s = 1
|
|
60
102
|
}
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
}
|
|
64
|
-
if (modules.props !== undefined) {
|
|
65
|
-
return { props: inner }
|
|
66
|
-
}
|
|
67
|
-
return inner
|
|
68
|
-
})
|
|
103
|
+
data.hook = hook
|
|
104
|
+
}
|
|
69
105
|
|
|
70
|
-
const applyFocusProps = (data: any):
|
|
71
|
-
if (!data.props) return data
|
|
106
|
+
const applyFocusProps = (data: any): void => {
|
|
72
107
|
const { autoFocus, autoSelect, ...rest } = data.props
|
|
73
|
-
if (!autoFocus && !autoSelect) return data
|
|
74
108
|
|
|
75
109
|
data.props = rest
|
|
76
110
|
data._autoFocus = !!autoFocus
|
|
@@ -87,27 +121,17 @@ const applyFocusProps = (data: any): any => {
|
|
|
87
121
|
}
|
|
88
122
|
}
|
|
89
123
|
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
data.hook = {
|
|
93
|
-
...data.hook,
|
|
94
|
-
insert: (vnode: any) => {
|
|
95
|
-
if (existingInsert) existingInsert(vnode)
|
|
96
|
-
if (autoFocus || autoSelect) doFocus(vnode.elm)
|
|
97
|
-
},
|
|
124
|
+
chainHooks(data, {
|
|
125
|
+
insert: (vnode: any) => doFocus(vnode.elm),
|
|
98
126
|
postpatch: (oldVnode: any, vnode: any) => {
|
|
99
|
-
if (existingPostpatch) existingPostpatch(oldVnode, vnode)
|
|
100
127
|
const wasFocused = oldVnode.data?._autoFocus
|
|
101
128
|
const isFocused = vnode.data?._autoFocus
|
|
102
129
|
if (!wasFocused && isFocused) doFocus(vnode.elm)
|
|
103
130
|
},
|
|
104
|
-
}
|
|
105
|
-
return data
|
|
131
|
+
})
|
|
106
132
|
}
|
|
107
133
|
|
|
108
|
-
const applyRefProps = (data: any, ref: any):
|
|
109
|
-
if (!ref) return data
|
|
110
|
-
|
|
134
|
+
const applyRefProps = (data: any, ref: any): void => {
|
|
111
135
|
const setRef = (elm: any) => {
|
|
112
136
|
if (typeof ref === 'function') {
|
|
113
137
|
ref(elm)
|
|
@@ -116,41 +140,135 @@ const applyRefProps = (data: any, ref: any): any => {
|
|
|
116
140
|
}
|
|
117
141
|
}
|
|
118
142
|
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
143
|
+
chainHooks(data, {
|
|
144
|
+
insert: (vnode: any) => setRef(vnode.elm),
|
|
145
|
+
postpatch: (_oldVnode: any, vnode: any) => setRef(vnode.elm),
|
|
146
|
+
destroy: () => setRef(null),
|
|
147
|
+
})
|
|
148
|
+
}
|
|
149
|
+
|
|
150
|
+
// B-014: snabbdom's classModule wants a { name: boolean } map. A string ("a b") or an
|
|
151
|
+
// array (['a', cond && 'b']) would be iterated by index, adding the classes "0", "1", ...
|
|
152
|
+
// G-096: clsx-style: strings, nested arrays, objects (truthy keys); falsy entries skipped
|
|
153
|
+
const addClasses = (map: Record<string, boolean>, klass: any): any => {
|
|
154
|
+
if (klass && typeof klass === 'object') for (const k in klass) Array.isArray(klass) ? addClasses(map, klass[k as any]) : klass[k] && addClasses(map, k)
|
|
155
|
+
else if (klass) for (const name of String(klass).split(/\s+/)) if (name) map[name] = true
|
|
156
|
+
return map
|
|
157
|
+
}
|
|
158
|
+
|
|
159
|
+
const toClassMap = (klass: any): any =>
|
|
160
|
+
typeof klass !== 'string' && !Array.isArray(klass) ? klass : addClasses({}, klass)
|
|
161
|
+
|
|
162
|
+
const isObject = (v: any): boolean => is.object(v) && !Array.isArray(v)
|
|
163
|
+
|
|
164
|
+
// P45-B (D146): nested objects are passed by reference. An object with an undefined entry is
|
|
165
|
+
// copied without it (the DOM modules would write "undefined"; the old deep copy dropped it)
|
|
166
|
+
const clean = (obj: any): any => {
|
|
167
|
+
if (isObject(obj)) for (const k in obj) if (obj[k] === undefined) {
|
|
168
|
+
const out: any = {}
|
|
169
|
+
for (const j in obj) if (obj[j] !== undefined) out[j] = obj[j]
|
|
170
|
+
return out
|
|
136
171
|
}
|
|
137
|
-
return
|
|
172
|
+
return obj
|
|
138
173
|
}
|
|
139
174
|
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
175
|
+
// One pass over the JSX props into snabbdom's module buckets (audit rec 6):
|
|
176
|
+
// - `<module>-<name>` (on-click, attrs-href, data-task-id → dataset.taskId) and `<module>={...}`
|
|
177
|
+
// go to that module's bucket (`data` is snabbdom's `dataset`)
|
|
178
|
+
// - on an element tag, for, role, tabindex, aria-*, form and list (G-463: getter-only DOM
|
|
179
|
+
// properties, which the props module would throw on) and the popover / invoker / anchor attributes
|
|
180
|
+
// (ATTRS) go to attrs (G-370: a component placeholder keeps them as props); an aria-* true is
|
|
181
|
+
// written as "true" (D196: snabbdom writes true as "", which ARIA doesn't read as true), false
|
|
182
|
+
// as "false" for a state whose values include false (G-372: ARIA_FALSE), else (an IDREF, a
|
|
183
|
+
// string, a number) it removes the attribute, as null does; key is dropped; anything else is a
|
|
184
|
+
// prop
|
|
185
|
+
// - an undefined value is skipped (a `<module>-<name>` one still makes its bucket)
|
|
186
|
+
// A bucket is the object passed (`lent`) until a second source adds to it; then it is a copy.
|
|
187
|
+
// sanitizeData doesn't re-enter, so `lent` is per call (null until a bucket is lent).
|
|
188
|
+
let lent: any
|
|
189
|
+
const bucket = (out: any, b: string): any => {
|
|
190
|
+
const o = out[b]
|
|
191
|
+
if (is.object(o) && !lent?.[b]) return o
|
|
192
|
+
if (lent) lent[b] = 0
|
|
193
|
+
return out[b] = is.object(o) ? { ...o } : {}
|
|
194
|
+
}
|
|
195
|
+
const add = (out: any, b: string, v: any): void => {
|
|
196
|
+
if (isObject(out[b]) && isObject(v)) {
|
|
197
|
+
const o = bucket(out, b)
|
|
198
|
+
for (const k in v) if (v[k] !== undefined) o[k] = v[k]
|
|
199
|
+
} else {
|
|
200
|
+
out[b] = clean(v);
|
|
201
|
+
(lent ||= {})[b] = 1
|
|
202
|
+
}
|
|
203
|
+
}
|
|
204
|
+
// P46-P: where a key goes, by key (per modules map; 0: skipped): [bucket, name, kind]. kind 1: a
|
|
205
|
+
// `<module>-<name>` key (its bucket is made even for undefined); 2: a module's own object
|
|
206
|
+
// (3: `class`, made a map first); else the bucket's `name` (no bucket: the data's own key; 4:
|
|
207
|
+
// aria-*, a boolean stringified)
|
|
208
|
+
const ATTRS = /^(for|form|list|role|tabindex|popovertarget(action)?|command(for)?|closedby|interestfor|anchor|aria-.*)$/
|
|
209
|
+
// G-372: the WAI-ARIA 1.2 states and properties whose value set includes "false" (true/false,
|
|
210
|
+
// tristate, and the tokens aria-current / aria-invalid / aria-haspopup), by a prefix no other
|
|
211
|
+
// ARIA 1.2/1.3 attribute has: atomic, busy, checked, current, disabled, expanded, grabbed,
|
|
212
|
+
// haspopup, hidden, invalid, modal, multiline, multiselectable, pressed, readonly, required,
|
|
213
|
+
// selected (sel: not setsize)
|
|
214
|
+
const ARIA_FALSE = /^aria-(at|bu|ch|cu|di|ex|gr|ha|hi|in|mo|mu|pr|re[aq]|sel)/
|
|
215
|
+
// `c`: a component placeholder (G-370: ATTRS stay props)
|
|
216
|
+
const route = (key: string, modules: Record<string, any>, c?: any): any => {
|
|
217
|
+
if (key == 'ref' || key == 'key' || key == 'children') return 0
|
|
218
|
+
const dash = key.indexOf('-')
|
|
219
|
+
const prefix = dash > -1 && key.slice(0, dash)
|
|
220
|
+
// G-152: data-task-id → dataset key taskId (a hyphenated dataset key makes the DOM throw)
|
|
221
|
+
if (prefix && modules[prefix] !== undefined) return [modules[prefix] || prefix, prefix == 'data' ? key.slice(dash + 1).replace(/-([a-z])/g, (_, c) => c.toUpperCase()) : key.slice(dash + 1), 1]
|
|
222
|
+
// G-492: on a custom element (c 2), list is its own property (Lit, sygnal/element). G-519: form
|
|
223
|
+
// stays an attribute (a form-associated element's `form` is a getter; the attribute links it).
|
|
224
|
+
// G-542: there, only a string form (an object is the element's own property: r[3])
|
|
225
|
+
if (c != 1 && modules.attrs !== undefined && ATTRS.test(key) && !(c && key == 'list')) return ['attrs', key, prefix == 'aria' && 4, c && key == 'form']
|
|
226
|
+
if (modules[key] !== undefined) return [modules[key] || key, 0, key == 'class' && modules.class !== undefined ? 3 : 2]
|
|
227
|
+
return [modules.props !== undefined && 'props', key]
|
|
228
|
+
}
|
|
229
|
+
const own = Object.prototype.hasOwnProperty
|
|
230
|
+
const sanitizeData = (data: any, modules: Record<string, any>, routes: Map<string, any>, c?: any): any => {
|
|
231
|
+
const out: any = {}
|
|
232
|
+
lent = null
|
|
233
|
+
for (const key in data) {
|
|
234
|
+
// G-354: own properties only, as the rest-spread copy had (about 1 ns a call)
|
|
235
|
+
if (!own.call(data, key)) continue
|
|
236
|
+
const val = data[key]
|
|
237
|
+
let r = routes.get(key)
|
|
238
|
+
// G-350: capped (data-dependent keys, e.g. `data-${id}`, are routed but not kept)
|
|
239
|
+
if (r === undefined && (r = route(key, modules, c), routes.size < 1024)) routes.set(key, r)
|
|
240
|
+
if (!r) continue
|
|
241
|
+
const [b, name, kind] = r
|
|
242
|
+
if (kind == 1) {
|
|
243
|
+
const o = bucket(out, b)
|
|
244
|
+
if (val !== undefined) o[name] = val
|
|
245
|
+
} else if (val === undefined) continue
|
|
246
|
+
else if (kind & 2) add(out, b, kind == 3 ? toClassMap(val) : val)
|
|
247
|
+
else if (b) bucket(out, r[3] && typeof val != 'string' ? 'props' : b)[name] = kind ? val === !!val ? (val || ARIA_FALSE.test(key)) && '' + val : val ?? false : val
|
|
248
|
+
else out[key] = val
|
|
249
|
+
}
|
|
250
|
+
const props = out.props
|
|
251
|
+
if (props && (props.autoFocus || props.autoSelect)) applyFocusProps(out)
|
|
252
|
+
if (data.ref) applyRefProps(out, data.ref)
|
|
253
|
+
return out
|
|
144
254
|
}
|
|
145
255
|
|
|
146
256
|
const sanitizeText = (children: any[]): string | undefined => children.length > 1 || !is.text(children[0]) ? undefined : children[0].toString()
|
|
147
257
|
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
258
|
+
// Flattens the children into `out` (a non-vnode child becomes a text vnode, or undefined);
|
|
259
|
+
// 1 when every child is plain: none, text, or a plain vnode
|
|
260
|
+
const flatten = (children: any[], out: any[]): number => {
|
|
261
|
+
let plain = 1
|
|
262
|
+
for (let i = 0; i < children.length; i++) {
|
|
263
|
+
const child = children[i]
|
|
264
|
+
if (is.array(child)) plain &= flatten(child, out)
|
|
265
|
+
else if (is.vnode(child)) {
|
|
266
|
+
out.push(child)
|
|
267
|
+
if (!child.$p && (child.sel !== undefined || child.children)) plain = 0
|
|
268
|
+
} else out.push(createTextElement(child))
|
|
269
|
+
}
|
|
270
|
+
return plain
|
|
152
271
|
}
|
|
153
|
-
, [])
|
|
154
272
|
|
|
155
273
|
const defaultModules: Record<string, string> = {
|
|
156
274
|
attrs: '',
|
|
@@ -163,54 +281,64 @@ const defaultModules: Record<string, string> = {
|
|
|
163
281
|
}
|
|
164
282
|
|
|
165
283
|
export const createElementWithModules = (modules: Record<string, any>) => {
|
|
166
|
-
|
|
284
|
+
// G-370: a component placeholder's keys route without ATTRS, so in their own cache
|
|
285
|
+
const routes = new Map<string, any>(), croutes = new Map<string, any>(), xroutes = new Map<string, any>()
|
|
286
|
+
// the children as one array (`k`: a key that wins over data.key: the JSX runtime's own)
|
|
287
|
+
const ca = (sel: any, data: any, children: any[], k?: any): any => {
|
|
167
288
|
if (typeof sel === 'undefined') {
|
|
168
289
|
sel = 'UNDEFINED'
|
|
169
|
-
|
|
290
|
+
// Through the diagnostics bridge (G-044: collected like the other codes), or, with
|
|
291
|
+
// diagnostics not loaded, the same pre-formatted text.
|
|
292
|
+
const msg = 'A JSX tag is undefined, so <UNDEFINED> is rendered instead', fix = 'Import or define the component in this file'
|
|
293
|
+
const core = (globalThis as any).__SYGNAL_DIAGNOSTICS__
|
|
294
|
+
if (core && core.error) core.error('SYG420', 'JSX', msg, fix)
|
|
295
|
+
else console.error(`[Sygnal SYG420] JSX: ${msg}. ${fix}. https://sygnal.js.org/reference/errors#syg420`)
|
|
170
296
|
}
|
|
171
|
-
|
|
297
|
+
// CT-1: a control (src/extra/controls.ts) renders its element itself and stamps its marker.
|
|
298
|
+
// It gets this createElement (the JSX runtime entries use the core's, D188).
|
|
299
|
+
const isComponent = is.fun(sel)
|
|
300
|
+
if (isComponent && (sel as any).__sygnalControl) return (sel as any).__sygnalControl(data, children, ce)
|
|
301
|
+
// the core instantiates a component from the vnode's `data.c` (the component function, with
|
|
302
|
+
// its statics); `sel` is its name
|
|
303
|
+
let fn: any
|
|
304
|
+
if (isComponent) {
|
|
172
305
|
if ((sel as any).__sygnalFragment || sel.name === 'Fragment') {
|
|
173
306
|
return sel(data || {}, children)
|
|
174
307
|
}
|
|
175
308
|
data ||= {}
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
const text = sanitizeText(children)
|
|
182
|
-
const sanitized = data ? sanitizeData(data, modules) : {}
|
|
183
|
-
return considerSvg({
|
|
184
|
-
sel: name,
|
|
185
|
-
data: sanitized,
|
|
186
|
-
children: typeof text !== 'undefined' ? createTextElement(text) : sanitizeChildren(children),
|
|
187
|
-
text,
|
|
188
|
-
elm: undefined,
|
|
189
|
-
key: data ? data.key : undefined
|
|
190
|
-
})
|
|
191
|
-
}
|
|
192
|
-
const options = { name, view, model, intent, hmrActions, context, peers, components, initialState, isolatedState, calculated, storeCalculatedInState, DOMSourceName, stateSourceName, onError, debug }
|
|
193
|
-
data.sygnalOptions = options
|
|
194
|
-
sel = name
|
|
195
|
-
} else {
|
|
196
|
-
const factory = sel
|
|
197
|
-
sel = (sel as any).componentName || (sel as any).label || sel.name || 'sygnal-factory'
|
|
198
|
-
data.sygnalFactory = factory
|
|
199
|
-
}
|
|
309
|
+
// preventInstantiation (Portal/Suspense/...): a marker vnode, its function in `data.m` (G-470:
|
|
310
|
+
// how a check tells it from a plain element of that tag), not `data.c`; its children
|
|
311
|
+
// stay an array (they read vnode.children), as for every component below
|
|
312
|
+
fn = sel
|
|
313
|
+
sel = (sel as any).componentName || sel.name || 'FUNCTION_COMPONENT'
|
|
200
314
|
}
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
|
|
208
|
-
|
|
209
|
-
|
|
315
|
+
// B-011: a vnode is either text-only (`text`, no children) or has a children array,
|
|
316
|
+
// never both; snabbdom's diff mishandles a vnode with both. A component placeholder
|
|
317
|
+
// keeps an array so the component receives its text child via `children`.
|
|
318
|
+
const text = isComponent ? undefined : sanitizeText(children)
|
|
319
|
+
let kids: any
|
|
320
|
+
const t = tagBits(sel)
|
|
321
|
+
let plain = !isComponent && is.string(sel) && !(t & 5)
|
|
322
|
+
if (typeof text === 'undefined') plain = !!(flatten(children, kids = []) & +plain)
|
|
323
|
+
// G-492: a custom element (bit 8) routes list as a prop, in its own cache
|
|
324
|
+
const d = data ? sanitizeData(data, modules, isComponent ? croutes : t & 8 ? xroutes : routes, isComponent || t & 8 && 2) : {}
|
|
325
|
+
if (fn) d[fn.preventInstantiation ? 'm' : 'c'] = fn
|
|
326
|
+
const key = k !== undefined ? k : data ? data.key : undefined
|
|
327
|
+
const vnode = plain ? new (Plain as any)(sel, d, kids, text, key) : { sel, data: d, children: kids, text, elm: undefined, key }
|
|
328
|
+
if (t & 2) applySvg(vnode)
|
|
329
|
+
return vnode
|
|
210
330
|
}
|
|
331
|
+
const ce = (sel: any, data: any, ...children: any[]): any => ca(sel, data, children)
|
|
332
|
+
// P46-P: the JSX runtime's element path (its props object is the data as is: sanitizeData
|
|
333
|
+
// skips `children`)
|
|
334
|
+
;(ce as any).a = ca
|
|
335
|
+
;(ce as any).$r = routes
|
|
336
|
+
return ce
|
|
211
337
|
}
|
|
212
338
|
|
|
213
339
|
export const createElement = createElementWithModules(defaultModules)
|
|
340
|
+
/** G-350 (tests): the sizes of the tag cache and of a createElement's route cache */
|
|
341
|
+
export const __cacheSizes = (ce: any) => ({ tags: Object.keys(tags).length, routes: ce.$r.size })
|
|
214
342
|
|
|
215
343
|
export default {
|
|
216
344
|
createElement,
|
|
@@ -0,0 +1,5 @@
|
|
|
1
|
+
// Build-time declarations for the optional peer dependencies of the 'sygnal/react' entry, so the
|
|
2
|
+
// build doesn't need @types/react. The entry's public types are in react.d.ts.
|
|
3
|
+
declare module 'react' { export const createElement: (type: any, props?: any, ...children: any[]) => any }
|
|
4
|
+
declare module 'react-dom' { export const flushSync: <R>(fn: () => R) => R }
|
|
5
|
+
declare module 'react-dom/client' { export const createRoot: (el: Element) => { render(node: any): void; unmount(): void } }
|
package/src/react.d.ts
ADDED
|
@@ -0,0 +1,43 @@
|
|
|
1
|
+
// 'sygnal/react' (PLAN-5 W-2, D203): fromReact, a React component as a widget tag. Needs react
|
|
2
|
+
// and react-dom (or preact/compat through a bundler alias).
|
|
3
|
+
import type { Widget, WidgetDefinition } from 'sygnal'
|
|
4
|
+
|
|
5
|
+
/** The adapter instance (`t.widget(sel).instance` with `dom: 'real'`) */
|
|
6
|
+
export interface ReactInstance {
|
|
7
|
+
/** The React root on the host */
|
|
8
|
+
root: { render(node: any): void; unmount(): void }
|
|
9
|
+
/** The host element */
|
|
10
|
+
el: HTMLElement
|
|
11
|
+
/** The props of the last render */
|
|
12
|
+
props: Record<string, any>
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
export interface FromReactOptions<P = any> {
|
|
16
|
+
/**
|
|
17
|
+
* The callbacks that become DOM events on the host: `{ rate: 'onChange' }` (event name →
|
|
18
|
+
* callback prop), or `['onChange']` (dispatched under the callback's own name). The detail is
|
|
19
|
+
* the callback's argument (an array when it gets more than one).
|
|
20
|
+
*/
|
|
21
|
+
events?: Record<string, string> | readonly string[]
|
|
22
|
+
/** The component's props from the widget's (default: all but the host's className, class, id, style, attrs, tabIndex, hidden; D215) */
|
|
23
|
+
props?: (props: P) => Record<string, any>
|
|
24
|
+
/** Element commands, called with the instance */
|
|
25
|
+
commands?: Record<string, (instance: ReactInstance, options: Record<string, any>, el: HTMLElement) => unknown>
|
|
26
|
+
/** The host element (default 'div') */
|
|
27
|
+
tag?: string
|
|
28
|
+
/** A name for diagnostics (default: the component's displayName or name) */
|
|
29
|
+
name?: string
|
|
30
|
+
/** What server rendering puts in the host */
|
|
31
|
+
fallback?: WidgetDefinition['fallback']
|
|
32
|
+
/** More prop names for the host element (also a component-only one: aria-*, role, title) */
|
|
33
|
+
hostProps?: string[]
|
|
34
|
+
/** Prop names that stay off the host and go only to the component (aria-*, role and title always do) */
|
|
35
|
+
ownProps?: string[]
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
/**
|
|
39
|
+
* A React component as a widget tag (an escape hatch): `fromReact(StarRating, { events: { rate: 'onChange' } })`.
|
|
40
|
+
* Render it with a class (`<Stars className="rating" value={state.rating} />`) and read its events
|
|
41
|
+
* in the intent (`DOM.select('.rating').events('rate').detail()`).
|
|
42
|
+
*/
|
|
43
|
+
export function fromReact<P = any>(component: any, options?: FromReactOptions<P>): Widget<P, ReactInstance>
|
package/src/react.ts
ADDED
|
@@ -0,0 +1,110 @@
|
|
|
1
|
+
/*
|
|
2
|
+
* 'sygnal/react' (PLAN-5 W-2, D203): `fromReact(Component, { events })`, a React component as a
|
|
3
|
+
* widget tag (defineWidget). An escape hatch for the one component you can't replace: context
|
|
4
|
+
* and providers don't cross the boundary, a React portal renders outside the host, and the mock
|
|
5
|
+
* DOM can't run it (test with `dom: 'real'`).
|
|
6
|
+
*
|
|
7
|
+
* const Stars = fromReact(StarRating, { events: { rate: 'onChange' } })
|
|
8
|
+
* // view: <Stars className="rating" value={state.rating} max={5} />
|
|
9
|
+
* // intent: RATE: DOM.select('.rating').events('rate').detail()
|
|
10
|
+
*
|
|
11
|
+
* - Each host is a React root (react-dom/client createRoot). `mount` and `update` render the
|
|
12
|
+
* component with the newest props in flushSync, so the DOM is up to date when they return.
|
|
13
|
+
* - `events`: `{ eventName: 'onCallback' }`, or an array of callback names, each dispatched under
|
|
14
|
+
* its own name (`['onChange']` → 'onChange'; React's names never collide with native events).
|
|
15
|
+
* The detail is the callback's argument (an array when it gets more than one). The component
|
|
16
|
+
* gets a callback for each, and a callback passed as a prop runs first.
|
|
17
|
+
* - Props (D215): `className`, `class`, `id`, `style`, `attrs`, `tabIndex` and `hidden` go to the
|
|
18
|
+
* host only (one tab stop); `aria-*`, `role` and `title` to the component only (a labelled
|
|
19
|
+
* React control gets its own name; the host div is generic); `data-*` to both; the rest to the
|
|
20
|
+
* component (`name`, `placeholder`, `lang`, `dir` also to the host, as for any widget).
|
|
21
|
+
* `ownProps: ['tabIndex']` sends a host prop to the component instead; `hostProps: ['role']`
|
|
22
|
+
* puts a component-only one on the host too. `props` maps the component's props:
|
|
23
|
+
* `props: (p) => ({ ...p, size: 'small' })`.
|
|
24
|
+
* - Unmount: `root.unmount()` in a microtask (React refuses a synchronous unmount while it is
|
|
25
|
+
* rendering, which a callback → action → re-render chain can be in), and only once the host
|
|
26
|
+
* has left the document (G-412: inside a <Transition>, the content stays during the leave),
|
|
27
|
+
* seen in shadow roots too (G-437); a destroyed host still in the DOM after 10 s unmounts then.
|
|
28
|
+
* - SSR: the host with the `fallback` (no React on the server here).
|
|
29
|
+
* - preact/compat: alias `react` and `react-dom` to `preact/compat`, and `react-dom/client` to
|
|
30
|
+
* `preact/compat/client`, in the bundler; the adapter only uses createElement, createRoot and
|
|
31
|
+
* flushSync.
|
|
32
|
+
*
|
|
33
|
+
* Separate entry: './index' becomes the external 'sygnal'; react and react-dom stay external
|
|
34
|
+
* (optional peerDependencies, D209).
|
|
35
|
+
*/
|
|
36
|
+
import {createElement} from 'react'
|
|
37
|
+
import {flushSync} from 'react-dom'
|
|
38
|
+
import {createRoot} from 'react-dom/client'
|
|
39
|
+
import {defineWidget} from './index'
|
|
40
|
+
|
|
41
|
+
// D215: the host's own props (the component doesn't get them): tabIndex / hidden too, so a
|
|
42
|
+
// focusable host isn't doubled inside (two tab stops)
|
|
43
|
+
const HOST = /^(className|class|id|style|attrs|tab[iI]ndex|hidden)$/
|
|
44
|
+
// D215 (G-436): the component's own (kept off the host): a React control names itself
|
|
45
|
+
const OWN = /^(aria-|role$|title$)/
|
|
46
|
+
|
|
47
|
+
const fail = (m: string): never => {
|
|
48
|
+
throw new Error(`[Sygnal SYG667] ${m}. https://sygnal.js.org/reference/errors#syg667`)
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
// G-412: run f once the host has left the document. A host still in it is leaving with a delay
|
|
52
|
+
// (a <Transition> leave animation): its React content stays until the element is removed.
|
|
53
|
+
// G-437: the removal can happen inside a shadow root (sygnal/element `shadow: true`), which a
|
|
54
|
+
// document observer doesn't see: every root on the way up (shadow roots, then the document) is
|
|
55
|
+
// observed. A destroyed host that stays in the DOM (a leave whose transitionend never comes, a
|
|
56
|
+
// tree left in place) is unmounted after LATE ms anyway, so no React root or observer leaks.
|
|
57
|
+
const LATE = 10000
|
|
58
|
+
const gone = (el: any, f: () => void) => {
|
|
59
|
+
if (!el.isConnected) return f()
|
|
60
|
+
let t: any
|
|
61
|
+
const done = () => { o.disconnect(); clearTimeout(t); f() }
|
|
62
|
+
const o: MutationObserver = new MutationObserver(() => { if (!el.isConnected) done() })
|
|
63
|
+
for (let r = el.getRootNode(); r; r = r.host?.getRootNode()) o.observe(r, {childList: true, subtree: true})
|
|
64
|
+
t = setTimeout(done, LATE)
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
/**
|
|
68
|
+
* A React component as a widget tag: `fromReact(Comp, { events, props, tag, name, fallback,
|
|
69
|
+
* hostProps, commands })`. `commands` are called with the instance `{ root, el, props }`.
|
|
70
|
+
*/
|
|
71
|
+
export function fromReact(Comp: any, options: any = {}): any {
|
|
72
|
+
if (typeof Comp != 'function' && !(Comp && typeof Comp == 'object' && Comp.$$typeof)) {
|
|
73
|
+
fail('fromReact(Component): the first argument is not a React component')
|
|
74
|
+
}
|
|
75
|
+
const o = options, ev = o.events || {}
|
|
76
|
+
// event name → callback prop name
|
|
77
|
+
const events: Record<string, string> = Array.isArray(ev) ? Object.fromEntries(ev.map((c: string) => [c, c])) : ev
|
|
78
|
+
const draw = (i: any, p: any) => {
|
|
79
|
+
const q: any = {}
|
|
80
|
+
for (const k in p) if (!HOST.test(k) || o.ownProps?.includes(k)) q[k] = p[k]
|
|
81
|
+
const rp = o.props ? o.props(q) : q
|
|
82
|
+
for (const name in events) {
|
|
83
|
+
const cb = events[name], own = rp[cb]
|
|
84
|
+
rp[cb] = (...a: any[]) => {
|
|
85
|
+
own?.(...a)
|
|
86
|
+
i.d(name, a.length > 1 ? a : a[0])
|
|
87
|
+
}
|
|
88
|
+
}
|
|
89
|
+
i.props = rp
|
|
90
|
+
flushSync(() => i.root.render(createElement(Comp, rp)))
|
|
91
|
+
}
|
|
92
|
+
return defineWidget({
|
|
93
|
+
tag: o.tag,
|
|
94
|
+
name: o.name || Comp.displayName || Comp.name,
|
|
95
|
+
fallback: o.fallback,
|
|
96
|
+
hostProps: o.hostProps,
|
|
97
|
+
// D215: aria-* / role / title stay off the host unless hostProps names one (the list is the
|
|
98
|
+
// option's; its includes() also matches those patterns, which is all defineWidget asks of it)
|
|
99
|
+
ownProps: Object.assign([...(o.ownProps || [])], {includes: (k: string) => !!o.ownProps?.includes(k) || OWN.test(k) && !o.hostProps?.includes(k)}),
|
|
100
|
+
events: Object.keys(events),
|
|
101
|
+
commands: o.commands,
|
|
102
|
+
mount: (el: any, p: any, d: any) => {
|
|
103
|
+
const i = {root: createRoot(el), el, d, props: null}
|
|
104
|
+
draw(i, p)
|
|
105
|
+
return i
|
|
106
|
+
},
|
|
107
|
+
update: draw,
|
|
108
|
+
unmount: (i: any) => { queueMicrotask(() => gone(i.el, () => i.root.unmount())) },
|
|
109
|
+
})
|
|
110
|
+
}
|