@softov/scena 0.1.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/LICENSE +21 -0
- package/README.md +42 -0
- package/dist/controls/command.d.ts +18 -0
- package/dist/controls/command.js +150 -0
- package/dist/controls/events.d.ts +3 -0
- package/dist/controls/events.js +43 -0
- package/dist/controls/index.d.ts +10 -0
- package/dist/controls/index.js +10 -0
- package/dist/controls/keybinding.d.ts +9 -0
- package/dist/controls/keybinding.js +94 -0
- package/dist/controls/layout.d.ts +16 -0
- package/dist/controls/layout.js +201 -0
- package/dist/controls/manifest.d.ts +21 -0
- package/dist/controls/manifest.js +219 -0
- package/dist/controls/session.d.ts +16 -0
- package/dist/controls/session.js +95 -0
- package/dist/controls/shell.d.ts +8 -0
- package/dist/controls/shell.js +48 -0
- package/dist/controls/storage/layout-local.d.ts +6 -0
- package/dist/controls/storage/layout-local.js +47 -0
- package/dist/controls/storage/session-local.d.ts +5 -0
- package/dist/controls/storage/session-local.js +38 -0
- package/dist/controls/when.d.ts +7 -0
- package/dist/controls/when.js +226 -0
- package/dist/converters/a2ui-v0.10.d.ts +23 -0
- package/dist/converters/a2ui-v0.10.js +136 -0
- package/dist/converters/index.d.ts +1 -0
- package/dist/converters/index.js +1 -0
- package/dist/core/backends/modus-backend.d.ts +13 -0
- package/dist/core/backends/modus-backend.js +115 -0
- package/dist/core/backends/storage-backend.d.ts +7 -0
- package/dist/core/backends/storage-backend.js +73 -0
- package/dist/core/backends/yjs-backend.d.ts +3 -0
- package/dist/core/backends/yjs-backend.js +44 -0
- package/dist/core/binding-resolver.d.ts +7 -0
- package/dist/core/binding-resolver.js +106 -0
- package/dist/core/component-graph.d.ts +6 -0
- package/dist/core/component-graph.js +77 -0
- package/dist/core/component-registry.d.ts +7 -0
- package/dist/core/component-registry.js +87 -0
- package/dist/core/computed-dsl.d.ts +2 -0
- package/dist/core/computed-dsl.js +267 -0
- package/dist/core/converter-registry.d.ts +2 -0
- package/dist/core/converter-registry.js +37 -0
- package/dist/core/disposable.d.ts +3 -0
- package/dist/core/disposable.js +19 -0
- package/dist/core/dynamic-resolver.d.ts +12 -0
- package/dist/core/dynamic-resolver.js +134 -0
- package/dist/core/index.d.ts +44 -0
- package/dist/core/index.js +48 -0
- package/dist/core/label.d.ts +2 -0
- package/dist/core/label.js +14 -0
- package/dist/core/mount-menu.d.ts +2 -0
- package/dist/core/mount-menu.js +23 -0
- package/dist/core/mount-surface.d.ts +15 -0
- package/dist/core/mount-surface.js +214 -0
- package/dist/core/path-resolver.d.ts +14 -0
- package/dist/core/path-resolver.js +169 -0
- package/dist/core/permissions.d.ts +2 -0
- package/dist/core/permissions.js +50 -0
- package/dist/core/reactive-store.d.ts +17 -0
- package/dist/core/reactive-store.js +496 -0
- package/dist/core/scena.d.ts +2 -0
- package/dist/core/scena.js +115 -0
- package/dist/core/surface-presentation.d.ts +6 -0
- package/dist/core/surface-presentation.js +12 -0
- package/dist/i18n/i18n-backend.d.ts +2 -0
- package/dist/i18n/i18n-backend.js +35 -0
- package/dist/i18n/registry.d.ts +32 -0
- package/dist/i18n/registry.js +200 -0
- package/dist/porta/Limen.css +50 -0
- package/dist/porta/Limen.d.ts +16 -0
- package/dist/porta/Limen.js +14 -0
- package/dist/porta/PortaContext.d.ts +10 -0
- package/dist/porta/PortaContext.js +20 -0
- package/dist/porta/PortaLock.css +14 -0
- package/dist/porta/PortaLock.d.ts +10 -0
- package/dist/porta/PortaLock.js +13 -0
- package/dist/porta/SigillumGate.d.ts +8 -0
- package/dist/porta/SigillumGate.js +7 -0
- package/dist/porta/commands.d.ts +3 -0
- package/dist/porta/commands.js +125 -0
- package/dist/porta/index.d.ts +18 -0
- package/dist/porta/index.js +22 -0
- package/dist/porta/login-form.block.d.ts +2 -0
- package/dist/porta/login-form.block.js +7 -0
- package/dist/porta/match.d.ts +2 -0
- package/dist/porta/match.js +20 -0
- package/dist/porta/provider.d.ts +59 -0
- package/dist/porta/provider.js +1 -0
- package/dist/porta/providers/examples/google-oauth.d.ts +6 -0
- package/dist/porta/providers/examples/google-oauth.js +21 -0
- package/dist/porta/providers/examples/index.d.ts +6 -0
- package/dist/porta/providers/examples/index.js +3 -0
- package/dist/porta/providers/examples/magic-link.d.ts +8 -0
- package/dist/porta/providers/examples/magic-link.js +31 -0
- package/dist/porta/providers/examples/sms-otp.d.ts +9 -0
- package/dist/porta/providers/examples/sms-otp.js +31 -0
- package/dist/porta/providers/password.d.ts +12 -0
- package/dist/porta/providers/password.js +46 -0
- package/dist/porta/register-blocks.d.ts +3 -0
- package/dist/porta/register-blocks.js +31 -0
- package/dist/porta/register.d.ts +15 -0
- package/dist/porta/register.js +31 -0
- package/dist/porta/sigillum.d.ts +19 -0
- package/dist/porta/sigillum.js +41 -0
- package/dist/react/DefaultShell.d.ts +1 -0
- package/dist/react/DefaultShell.js +37 -0
- package/dist/react/Scena.d.ts +9 -0
- package/dist/react/Scena.js +20 -0
- package/dist/react/ScenaProvider.d.ts +8 -0
- package/dist/react/ScenaProvider.js +13 -0
- package/dist/react/ShellSplitter.d.ts +13 -0
- package/dist/react/ShellSplitter.js +88 -0
- package/dist/react/SurfaceArea.d.ts +13 -0
- package/dist/react/SurfaceArea.js +75 -0
- package/dist/react/Translate.d.ts +8 -0
- package/dist/react/Translate.js +10 -0
- package/dist/react/ViewMount.d.ts +12 -0
- package/dist/react/ViewMount.js +268 -0
- package/dist/react/core.d.ts +6 -0
- package/dist/react/core.js +10 -0
- package/dist/react/hooks/useCommand.d.ts +1 -0
- package/dist/react/hooks/useCommand.js +6 -0
- package/dist/react/hooks/useI18n.d.ts +9 -0
- package/dist/react/hooks/useI18n.js +16 -0
- package/dist/react/hooks/useLabel.d.ts +2 -0
- package/dist/react/hooks/useLabel.js +19 -0
- package/dist/react/hooks/useLayout.d.ts +2 -0
- package/dist/react/hooks/useLayout.js +10 -0
- package/dist/react/hooks/useMounts.d.ts +2 -0
- package/dist/react/hooks/useMounts.js +17 -0
- package/dist/react/hooks/useStore.d.ts +3 -0
- package/dist/react/hooks/useStore.js +40 -0
- package/dist/react/hooks/useStoreLabel.d.ts +3 -0
- package/dist/react/hooks/useStoreLabel.js +25 -0
- package/dist/react/hooks/useSurfacePresentation.d.ts +4 -0
- package/dist/react/hooks/useSurfacePresentation.js +16 -0
- package/dist/react/index.d.ts +20 -0
- package/dist/react/index.js +20 -0
- package/dist/react/mount-context.d.ts +8 -0
- package/dist/react/mount-context.js +20 -0
- package/dist/react/useSurfaceResize.d.ts +39 -0
- package/dist/react/useSurfaceResize.js +135 -0
- package/dist/runtime/args-schema.d.ts +11 -0
- package/dist/runtime/args-schema.js +45 -0
- package/dist/runtime/builtins.d.ts +3 -0
- package/dist/runtime/builtins.js +193 -0
- package/dist/runtime/client-handlers.d.ts +3 -0
- package/dist/runtime/client-handlers.js +19 -0
- package/dist/runtime/in-memory-socket.d.ts +7 -0
- package/dist/runtime/in-memory-socket.js +53 -0
- package/dist/runtime/index.d.ts +10 -0
- package/dist/runtime/index.js +7 -0
- package/dist/runtime/layout-commands.d.ts +5 -0
- package/dist/runtime/layout-commands.js +548 -0
- package/dist/runtime/opener-commands.d.ts +17 -0
- package/dist/runtime/opener-commands.js +96 -0
- package/dist/runtime/surface-bridge.d.ts +15 -0
- package/dist/runtime/surface-bridge.js +116 -0
- package/dist/styles/bar.css +155 -0
- package/dist/styles/base.css +285 -0
- package/dist/styles/geometry.css +32 -0
- package/dist/styles/index.d.ts +29 -0
- package/dist/styles/index.js +109 -0
- package/dist/styles/scrollbar.css +45 -0
- package/dist/styles/surface.css +179 -0
- package/dist/styles/theme.css +3 -0
- package/dist/styles/themes/dark.css +30 -0
- package/dist/styles/themes/light.css +1 -0
- package/dist/styles/themes/tokens.css +222 -0
- package/dist/types/binding-resolver.d.ts +30 -0
- package/dist/types/binding-resolver.js +1 -0
- package/dist/types/colors.d.ts +7 -0
- package/dist/types/colors.js +59 -0
- package/dist/types/command.d.ts +62 -0
- package/dist/types/command.js +1 -0
- package/dist/types/component-graph.d.ts +72 -0
- package/dist/types/component-graph.js +40 -0
- package/dist/types/component-registry.d.ts +70 -0
- package/dist/types/component-registry.js +1 -0
- package/dist/types/converter-registry.d.ts +17 -0
- package/dist/types/converter-registry.js +1 -0
- package/dist/types/disposable.d.ts +3 -0
- package/dist/types/disposable.js +1 -0
- package/dist/types/events.d.ts +75 -0
- package/dist/types/events.js +1 -0
- package/dist/types/host.d.ts +50 -0
- package/dist/types/host.js +1 -0
- package/dist/types/index.d.ts +23 -0
- package/dist/types/index.js +23 -0
- package/dist/types/keybinding.d.ts +36 -0
- package/dist/types/keybinding.js +1 -0
- package/dist/types/label.d.ts +9 -0
- package/dist/types/label.js +1 -0
- package/dist/types/layout.d.ts +117 -0
- package/dist/types/layout.js +1 -0
- package/dist/types/manifest.d.ts +152 -0
- package/dist/types/manifest.js +1 -0
- package/dist/types/mount-menu.d.ts +8 -0
- package/dist/types/mount-menu.js +1 -0
- package/dist/types/mount-surface.d.ts +87 -0
- package/dist/types/mount-surface.js +1 -0
- package/dist/types/permissions.d.ts +18 -0
- package/dist/types/permissions.js +1 -0
- package/dist/types/query.d.ts +34 -0
- package/dist/types/query.js +7 -0
- package/dist/types/reactive-store.d.ts +39 -0
- package/dist/types/reactive-store.js +1 -0
- package/dist/types/scena.d.ts +53 -0
- package/dist/types/scena.js +1 -0
- package/dist/types/scope-backend.d.ts +16 -0
- package/dist/types/scope-backend.js +1 -0
- package/dist/types/session.d.ts +39 -0
- package/dist/types/session.js +1 -0
- package/dist/types/shell.d.ts +21 -0
- package/dist/types/shell.js +1 -0
- package/dist/types/when.d.ts +10 -0
- package/dist/types/when.js +1 -0
- package/dist/ui/_utils.d.ts +8 -0
- package/dist/ui/_utils.js +53 -0
- package/dist/ui/campus/CampusMappa.d.ts +18 -0
- package/dist/ui/campus/CampusMappa.js +106 -0
- package/dist/ui/campus/CampusNodus.d.ts +25 -0
- package/dist/ui/campus/CampusNodus.js +211 -0
- package/dist/ui/campus/CampusStratum.d.ts +13 -0
- package/dist/ui/campus/CampusStratum.js +20 -0
- package/dist/ui/campus/CampusVelum.d.ts +7 -0
- package/dist/ui/campus/CampusVelum.js +12 -0
- package/dist/ui/campus/CampusView.d.ts +27 -0
- package/dist/ui/campus/CampusView.js +420 -0
- package/dist/ui/campus/context.d.ts +13 -0
- package/dist/ui/campus/context.js +12 -0
- package/dist/ui/campus/index.d.ts +14 -0
- package/dist/ui/campus/index.js +11 -0
- package/dist/ui/campus/stratum-context.d.ts +2 -0
- package/dist/ui/campus/stratum-context.js +10 -0
- package/dist/ui/campus/types.d.ts +47 -0
- package/dist/ui/campus/types.js +4 -0
- package/dist/ui/chart/BarChart.css +53 -0
- package/dist/ui/chart/BarChart.d.ts +24 -0
- package/dist/ui/chart/BarChart.js +32 -0
- package/dist/ui/chart/Donut.css +15 -0
- package/dist/ui/chart/Donut.d.ts +15 -0
- package/dist/ui/chart/Donut.js +18 -0
- package/dist/ui/chart/LineChart.css +8 -0
- package/dist/ui/chart/LineChart.d.ts +24 -0
- package/dist/ui/chart/LineChart.js +29 -0
- package/dist/ui/chart/catalog.d.ts +2 -0
- package/dist/ui/chart/catalog.js +7 -0
- package/dist/ui/chart/index.d.ts +6 -0
- package/dist/ui/chart/index.js +4 -0
- package/dist/ui/control/Button.css +7 -0
- package/dist/ui/control/Button.d.ts +17 -0
- package/dist/ui/control/Button.js +17 -0
- package/dist/ui/control/CheckBox.css +16 -0
- package/dist/ui/control/CheckBox.d.ts +15 -0
- package/dist/ui/control/CheckBox.js +23 -0
- package/dist/ui/control/Checks.css +6 -0
- package/dist/ui/control/Checks.d.ts +9 -0
- package/dist/ui/control/Checks.js +10 -0
- package/dist/ui/control/ChoicePicker.css +16 -0
- package/dist/ui/control/ChoicePicker.d.ts +25 -0
- package/dist/ui/control/ChoicePicker.js +38 -0
- package/dist/ui/control/DateTimeInput.css +1 -0
- package/dist/ui/control/DateTimeInput.d.ts +22 -0
- package/dist/ui/control/DateTimeInput.js +41 -0
- package/dist/ui/control/LocaleToggle.css +38 -0
- package/dist/ui/control/LocaleToggle.d.ts +11 -0
- package/dist/ui/control/LocaleToggle.js +23 -0
- package/dist/ui/control/ReloadButton.d.ts +6 -0
- package/dist/ui/control/ReloadButton.js +9 -0
- package/dist/ui/control/Slider.css +2 -0
- package/dist/ui/control/Slider.d.ts +21 -0
- package/dist/ui/control/Slider.js +37 -0
- package/dist/ui/control/TextField.css +0 -0
- package/dist/ui/control/TextField.d.ts +25 -0
- package/dist/ui/control/TextField.js +36 -0
- package/dist/ui/control/_field-parts.css +102 -0
- package/dist/ui/control/_field-parts.d.ts +15 -0
- package/dist/ui/control/_field-parts.js +17 -0
- package/dist/ui/control/catalog.d.ts +2 -0
- package/dist/ui/control/catalog.js +10 -0
- package/dist/ui/control/index.d.ts +13 -0
- package/dist/ui/control/index.js +11 -0
- package/dist/ui/data/DataTable.d.ts +19 -0
- package/dist/ui/data/DataTable.js +20 -0
- package/dist/ui/data/Filter.d.ts +13 -0
- package/dist/ui/data/Filter.js +56 -0
- package/dist/ui/data/List.css +16 -0
- package/dist/ui/data/List.d.ts +15 -0
- package/dist/ui/data/List.js +18 -0
- package/dist/ui/data/Listable.css +245 -0
- package/dist/ui/data/Listable.d.ts +60 -0
- package/dist/ui/data/Listable.js +209 -0
- package/dist/ui/data/Pagination.d.ts +5 -0
- package/dist/ui/data/Pagination.js +43 -0
- package/dist/ui/data/Tree.css +118 -0
- package/dist/ui/data/Tree.d.ts +45 -0
- package/dist/ui/data/Tree.js +170 -0
- package/dist/ui/data/catalog.d.ts +2 -0
- package/dist/ui/data/catalog.js +7 -0
- package/dist/ui/data/index.d.ts +11 -0
- package/dist/ui/data/index.js +7 -0
- package/dist/ui/display/AddPlaceholder.d.ts +6 -0
- package/dist/ui/display/AddPlaceholder.js +24 -0
- package/dist/ui/display/Alert.css +42 -0
- package/dist/ui/display/Alert.d.ts +14 -0
- package/dist/ui/display/Alert.js +13 -0
- package/dist/ui/display/Avatar.css +19 -0
- package/dist/ui/display/Avatar.d.ts +16 -0
- package/dist/ui/display/Avatar.js +52 -0
- package/dist/ui/display/Badge.css +26 -0
- package/dist/ui/display/Badge.d.ts +16 -0
- package/dist/ui/display/Badge.js +9 -0
- package/dist/ui/display/Card.css +15 -0
- package/dist/ui/display/Card.d.ts +11 -0
- package/dist/ui/display/Card.js +8 -0
- package/dist/ui/display/DetailContainer.d.ts +6 -0
- package/dist/ui/display/DetailContainer.js +7 -0
- package/dist/ui/display/DetailHeader.css +53 -0
- package/dist/ui/display/DetailHeader.d.ts +22 -0
- package/dist/ui/display/DetailHeader.js +8 -0
- package/dist/ui/display/DetailList.css +26 -0
- package/dist/ui/display/DetailList.d.ts +13 -0
- package/dist/ui/display/DetailList.js +5 -0
- package/dist/ui/display/DetailNotFound.d.ts +17 -0
- package/dist/ui/display/DetailNotFound.js +39 -0
- package/dist/ui/display/Divider.css +6 -0
- package/dist/ui/display/Divider.d.ts +8 -0
- package/dist/ui/display/Divider.js +16 -0
- package/dist/ui/display/Divisor.css +30 -0
- package/dist/ui/display/Divisor.d.ts +11 -0
- package/dist/ui/display/Divisor.js +43 -0
- package/dist/ui/display/Icon.css +10 -0
- package/dist/ui/display/Icon.d.ts +14 -0
- package/dist/ui/display/Icon.js +144 -0
- package/dist/ui/display/Image.css +1 -0
- package/dist/ui/display/Image.d.ts +16 -0
- package/dist/ui/display/Image.js +19 -0
- package/dist/ui/display/Markdown.css +38 -0
- package/dist/ui/display/Markdown.d.ts +8 -0
- package/dist/ui/display/Markdown.js +140 -0
- package/dist/ui/display/Progress.css +39 -0
- package/dist/ui/display/Progress.d.ts +15 -0
- package/dist/ui/display/Progress.js +17 -0
- package/dist/ui/display/SectionTitle.d.ts +6 -0
- package/dist/ui/display/SectionTitle.js +6 -0
- package/dist/ui/display/Skeleton.css +20 -0
- package/dist/ui/display/Skeleton.d.ts +11 -0
- package/dist/ui/display/Skeleton.js +11 -0
- package/dist/ui/display/Spinner.css +20 -0
- package/dist/ui/display/Spinner.d.ts +12 -0
- package/dist/ui/display/Spinner.js +12 -0
- package/dist/ui/display/Svg.d.ts +13 -0
- package/dist/ui/display/Svg.js +17 -0
- package/dist/ui/display/Text.css +20 -0
- package/dist/ui/display/Text.d.ts +13 -0
- package/dist/ui/display/Text.js +15 -0
- package/dist/ui/display/catalog.d.ts +2 -0
- package/dist/ui/display/catalog.js +12 -0
- package/dist/ui/display/index.d.ts +22 -0
- package/dist/ui/display/index.js +14 -0
- package/dist/ui/embed/HtmlEmbed.d.ts +12 -0
- package/dist/ui/embed/HtmlEmbed.js +16 -0
- package/dist/ui/embed/index.d.ts +2 -0
- package/dist/ui/embed/index.js +1 -0
- package/dist/ui/forms/DangerZone.d.ts +8 -0
- package/dist/ui/forms/DangerZone.js +31 -0
- package/dist/ui/forms/Field.css +15 -0
- package/dist/ui/forms/Field.d.ts +28 -0
- package/dist/ui/forms/Field.js +25 -0
- package/dist/ui/forms/FieldGroup.css +15 -0
- package/dist/ui/forms/FieldGroup.d.ts +7 -0
- package/dist/ui/forms/FieldGroup.js +7 -0
- package/dist/ui/forms/Form.css +14 -0
- package/dist/ui/forms/Form.d.ts +18 -0
- package/dist/ui/forms/Form.js +17 -0
- package/dist/ui/forms/FormActions.css +11 -0
- package/dist/ui/forms/FormActions.d.ts +18 -0
- package/dist/ui/forms/FormActions.js +10 -0
- package/dist/ui/forms/FormSection.css +19 -0
- package/dist/ui/forms/FormSection.d.ts +7 -0
- package/dist/ui/forms/FormSection.js +7 -0
- package/dist/ui/forms/LoginForm.css +105 -0
- package/dist/ui/forms/LoginForm.d.ts +12 -0
- package/dist/ui/forms/LoginForm.js +137 -0
- package/dist/ui/forms/SchemaForm.css +81 -0
- package/dist/ui/forms/SchemaForm.d.ts +26 -0
- package/dist/ui/forms/SchemaForm.js +186 -0
- package/dist/ui/forms/SettingsContainer.d.ts +8 -0
- package/dist/ui/forms/SettingsContainer.js +8 -0
- package/dist/ui/forms/catalog.d.ts +2 -0
- package/dist/ui/forms/catalog.js +11 -0
- package/dist/ui/forms/index.d.ts +19 -0
- package/dist/ui/forms/index.js +12 -0
- package/dist/ui/forms/schema-walk.d.ts +50 -0
- package/dist/ui/forms/schema-walk.js +116 -0
- package/dist/ui/index.d.ts +58 -0
- package/dist/ui/index.js +63 -0
- package/dist/ui/layout/BarLayout.d.ts +2 -0
- package/dist/ui/layout/BarLayout.js +18 -0
- package/dist/ui/layout/Column.css +6 -0
- package/dist/ui/layout/Column.d.ts +12 -0
- package/dist/ui/layout/Column.js +13 -0
- package/dist/ui/layout/FloatingLayout.d.ts +2 -0
- package/dist/ui/layout/FloatingLayout.js +12 -0
- package/dist/ui/layout/Grid.css +5 -0
- package/dist/ui/layout/Grid.d.ts +13 -0
- package/dist/ui/layout/Grid.js +19 -0
- package/dist/ui/layout/InlineLayout.d.ts +2 -0
- package/dist/ui/layout/InlineLayout.js +13 -0
- package/dist/ui/layout/MountTitle.d.ts +12 -0
- package/dist/ui/layout/MountTitle.js +42 -0
- package/dist/ui/layout/RailLayout.d.ts +2 -0
- package/dist/ui/layout/RailLayout.js +38 -0
- package/dist/ui/layout/Row.css +16 -0
- package/dist/ui/layout/Row.d.ts +13 -0
- package/dist/ui/layout/Row.js +21 -0
- package/dist/ui/layout/SectionHeader.d.ts +10 -0
- package/dist/ui/layout/SectionHeader.js +65 -0
- package/dist/ui/layout/SingleLayout.d.ts +2 -0
- package/dist/ui/layout/SingleLayout.js +25 -0
- package/dist/ui/layout/SpatialCard.d.ts +9 -0
- package/dist/ui/layout/SpatialCard.js +30 -0
- package/dist/ui/layout/SpatialLayout.d.ts +2 -0
- package/dist/ui/layout/SpatialLayout.js +446 -0
- package/dist/ui/layout/SplitLayout.d.ts +2 -0
- package/dist/ui/layout/SplitLayout.js +159 -0
- package/dist/ui/layout/Splitter.d.ts +12 -0
- package/dist/ui/layout/Splitter.js +64 -0
- package/dist/ui/layout/StackHeader.d.ts +9 -0
- package/dist/ui/layout/StackHeader.js +87 -0
- package/dist/ui/layout/StackLayout.d.ts +2 -0
- package/dist/ui/layout/StackLayout.js +137 -0
- package/dist/ui/layout/TabLayout.d.ts +2 -0
- package/dist/ui/layout/TabLayout.js +145 -0
- package/dist/ui/layout/TabPanelLayout.d.ts +20 -0
- package/dist/ui/layout/TabPanelLayout.js +615 -0
- package/dist/ui/layout/catalog.d.ts +2 -0
- package/dist/ui/layout/catalog.js +10 -0
- package/dist/ui/layout/index.d.ts +17 -0
- package/dist/ui/layout/index.js +17 -0
- package/dist/ui/layout/register.d.ts +3 -0
- package/dist/ui/layout/register.js +25 -0
- package/dist/ui/media/Audio.css +1 -0
- package/dist/ui/media/Audio.d.ts +12 -0
- package/dist/ui/media/Audio.js +8 -0
- package/dist/ui/media/Video.css +1 -0
- package/dist/ui/media/Video.d.ts +16 -0
- package/dist/ui/media/Video.js +9 -0
- package/dist/ui/media/catalog.d.ts +2 -0
- package/dist/ui/media/catalog.js +5 -0
- package/dist/ui/media/index.d.ts +2 -0
- package/dist/ui/media/index.js +3 -0
- package/dist/ui/menu/ActionList.css +262 -0
- package/dist/ui/menu/ActionList.d.ts +19 -0
- package/dist/ui/menu/ActionList.js +369 -0
- package/dist/ui/menu/ContainerMenu.d.ts +13 -0
- package/dist/ui/menu/ContainerMenu.js +57 -0
- package/dist/ui/menu/ContextMenu.d.ts +27 -0
- package/dist/ui/menu/ContextMenu.js +93 -0
- package/dist/ui/menu/index.d.ts +10 -0
- package/dist/ui/menu/index.js +7 -0
- package/dist/ui/menu/token.d.ts +22 -0
- package/dist/ui/menu/token.js +145 -0
- package/dist/ui/menu/useChatPicker.d.ts +24 -0
- package/dist/ui/menu/useChatPicker.js +210 -0
- package/dist/ui/navigation/Breadcrumb.css +30 -0
- package/dist/ui/navigation/Breadcrumb.d.ts +14 -0
- package/dist/ui/navigation/Breadcrumb.js +12 -0
- package/dist/ui/navigation/Link.css +13 -0
- package/dist/ui/navigation/Link.d.ts +18 -0
- package/dist/ui/navigation/Link.js +43 -0
- package/dist/ui/navigation/Tabs.css +39 -0
- package/dist/ui/navigation/Tabs.d.ts +18 -0
- package/dist/ui/navigation/Tabs.js +55 -0
- package/dist/ui/navigation/Toolbar.css +25 -0
- package/dist/ui/navigation/Toolbar.d.ts +12 -0
- package/dist/ui/navigation/Toolbar.js +21 -0
- package/dist/ui/navigation/catalog.d.ts +2 -0
- package/dist/ui/navigation/catalog.js +5 -0
- package/dist/ui/navigation/index.d.ts +8 -0
- package/dist/ui/navigation/index.js +5 -0
- package/dist/ui/overlay/Modal.css +35 -0
- package/dist/ui/overlay/Modal.d.ts +12 -0
- package/dist/ui/overlay/Modal.js +57 -0
- package/dist/ui/overlay/Popup.d.ts +12 -0
- package/dist/ui/overlay/Popup.js +74 -0
- package/dist/ui/overlay/catalog.d.ts +2 -0
- package/dist/ui/overlay/catalog.js +4 -0
- package/dist/ui/overlay/index.d.ts +1 -0
- package/dist/ui/overlay/index.js +2 -0
- package/dist/ui/register.d.ts +6 -0
- package/dist/ui/register.js +26 -0
- package/package.json +115 -0
|
@@ -0,0 +1,496 @@
|
|
|
1
|
+
import { disposableFrom } from './disposable.js';
|
|
2
|
+
import { parsePath, joinSegments, hasWildcard } from './path-resolver.js';
|
|
3
|
+
import { compileSelect } from './computed-dsl.js';
|
|
4
|
+
function makeNode() {
|
|
5
|
+
return { hasValue: false, value: undefined };
|
|
6
|
+
}
|
|
7
|
+
function isWildcardPath(path) {
|
|
8
|
+
return path.includes('*');
|
|
9
|
+
}
|
|
10
|
+
function segmentsOf(path) {
|
|
11
|
+
// Store paths are always absolute ($/scope/...) — relative resolution happens
|
|
12
|
+
// in the React hooks / resolver before reaching the store. parsePath handles
|
|
13
|
+
// RFC6901 unescape + `..` rejection.
|
|
14
|
+
return parsePath(path).segments;
|
|
15
|
+
}
|
|
16
|
+
function nodeEmpty(node) {
|
|
17
|
+
return (!node.hasValue &&
|
|
18
|
+
!(node.subscribers && node.subscribers.size) &&
|
|
19
|
+
!(node.wildSubs && node.wildSubs.length) &&
|
|
20
|
+
!(node.children && node.children.size));
|
|
21
|
+
}
|
|
22
|
+
function matchPattern(pattern, segs) {
|
|
23
|
+
if (pattern.length !== segs.length)
|
|
24
|
+
return false;
|
|
25
|
+
for (let i = 0; i < pattern.length; i++) {
|
|
26
|
+
if (pattern[i] !== '*' && pattern[i] !== segs[i])
|
|
27
|
+
return false;
|
|
28
|
+
}
|
|
29
|
+
return true;
|
|
30
|
+
}
|
|
31
|
+
export function createReactiveStore(deps) {
|
|
32
|
+
const { events } = deps;
|
|
33
|
+
const root = makeNode();
|
|
34
|
+
const dataProviders = new Map();
|
|
35
|
+
const loadedNamespaces = new Set();
|
|
36
|
+
// scope -> value backend (in-memory tree is the default; absent = use tree)
|
|
37
|
+
const backends = new Map();
|
|
38
|
+
const backendFactories = new Map();
|
|
39
|
+
for (const f of deps.backendFactories ?? [])
|
|
40
|
+
backendFactories.set(f.scope, f);
|
|
41
|
+
const backendDisposers = [];
|
|
42
|
+
// computed target (canonical path) -> its `from` paths, for cycle detection.
|
|
43
|
+
const computedDeps = new Map();
|
|
44
|
+
const pending = new Map();
|
|
45
|
+
// Paths whose change came from a backend push (Yjs/socket): the backend
|
|
46
|
+
// already holds the new value before emit() fires, so `previous` can't be
|
|
47
|
+
// captured and the Object.is dedupe would wrongly swallow it. Force-notify.
|
|
48
|
+
const forced = new Set();
|
|
49
|
+
let flushScheduled = false;
|
|
50
|
+
// ── tree walking ────────────────────────────────────────────────────────
|
|
51
|
+
function walk(segs, create) {
|
|
52
|
+
let node = root;
|
|
53
|
+
for (const seg of segs) {
|
|
54
|
+
let next = node.children?.get(seg);
|
|
55
|
+
if (!next) {
|
|
56
|
+
if (!create)
|
|
57
|
+
return undefined;
|
|
58
|
+
if (!node.children)
|
|
59
|
+
node.children = new Map();
|
|
60
|
+
next = makeNode();
|
|
61
|
+
node.children.set(seg, next);
|
|
62
|
+
}
|
|
63
|
+
node = next;
|
|
64
|
+
}
|
|
65
|
+
return node;
|
|
66
|
+
}
|
|
67
|
+
// Collect [root, n1, …] for an existing path (stops at first missing node).
|
|
68
|
+
function walkStack(segs) {
|
|
69
|
+
const stack = [root];
|
|
70
|
+
let node = root;
|
|
71
|
+
for (const seg of segs) {
|
|
72
|
+
const next = node.children?.get(seg);
|
|
73
|
+
if (!next)
|
|
74
|
+
break;
|
|
75
|
+
stack.push(next);
|
|
76
|
+
node = next;
|
|
77
|
+
}
|
|
78
|
+
return stack;
|
|
79
|
+
}
|
|
80
|
+
function prune(segs) {
|
|
81
|
+
const stack = walkStack(segs);
|
|
82
|
+
// stack[i] is the node after consuming segs[0..i-1]; stack[0] = root.
|
|
83
|
+
for (let i = stack.length - 1; i >= 1; i--) {
|
|
84
|
+
const node = stack[i];
|
|
85
|
+
if (!nodeEmpty(node))
|
|
86
|
+
break;
|
|
87
|
+
const parent = stack[i - 1];
|
|
88
|
+
parent.children?.delete(segs[i - 1]);
|
|
89
|
+
if (parent.children && parent.children.size === 0)
|
|
90
|
+
parent.children = undefined;
|
|
91
|
+
}
|
|
92
|
+
}
|
|
93
|
+
// ── value storage (backend-routed; default = in-memory tree node) ─────────
|
|
94
|
+
function ensureBackend(scope) {
|
|
95
|
+
let backend = backends.get(scope);
|
|
96
|
+
if (backend)
|
|
97
|
+
return backend;
|
|
98
|
+
const factory = backendFactories.get(scope);
|
|
99
|
+
if (!factory)
|
|
100
|
+
return undefined;
|
|
101
|
+
backend = factory.create();
|
|
102
|
+
backends.set(scope, backend);
|
|
103
|
+
if (backend.attach) {
|
|
104
|
+
backendDisposers.push(backend.attach((path, value) => emitExternal(path, value)));
|
|
105
|
+
}
|
|
106
|
+
return backend;
|
|
107
|
+
}
|
|
108
|
+
function readValue(segs) {
|
|
109
|
+
const backend = segs.length ? ensureBackend(segs[0]) : undefined;
|
|
110
|
+
if (backend)
|
|
111
|
+
return backend.get(segs.slice(1));
|
|
112
|
+
const node = walk(segs, false);
|
|
113
|
+
return node && node.hasValue
|
|
114
|
+
? { hasValue: true, value: node.value }
|
|
115
|
+
: { hasValue: false, value: undefined };
|
|
116
|
+
}
|
|
117
|
+
function writeValue(segs, value) {
|
|
118
|
+
const backend = segs.length ? ensureBackend(segs[0]) : undefined;
|
|
119
|
+
if (backend) {
|
|
120
|
+
backend.set(segs.slice(1), value);
|
|
121
|
+
return;
|
|
122
|
+
}
|
|
123
|
+
const node = walk(segs, true);
|
|
124
|
+
node.hasValue = true;
|
|
125
|
+
node.value = value;
|
|
126
|
+
}
|
|
127
|
+
function removeValue(segs) {
|
|
128
|
+
const backend = segs.length ? ensureBackend(segs[0]) : undefined;
|
|
129
|
+
if (backend) {
|
|
130
|
+
const had = backend.get(segs.slice(1)).hasValue;
|
|
131
|
+
backend.delete(segs.slice(1));
|
|
132
|
+
return had;
|
|
133
|
+
}
|
|
134
|
+
const node = walk(segs, false);
|
|
135
|
+
if (!node || !node.hasValue)
|
|
136
|
+
return false;
|
|
137
|
+
node.hasValue = false;
|
|
138
|
+
node.value = undefined;
|
|
139
|
+
return true;
|
|
140
|
+
}
|
|
141
|
+
// ── batching / notification ───────────────────────────────────────────────
|
|
142
|
+
function queueChange(canonical) {
|
|
143
|
+
if (!pending.has(canonical)) {
|
|
144
|
+
pending.set(canonical, { previous: readValue(segmentsOf(canonical)).value });
|
|
145
|
+
}
|
|
146
|
+
if (!flushScheduled) {
|
|
147
|
+
flushScheduled = true;
|
|
148
|
+
queueMicrotask(flush);
|
|
149
|
+
}
|
|
150
|
+
}
|
|
151
|
+
function safeExact(fn, value, path) {
|
|
152
|
+
try {
|
|
153
|
+
fn(value);
|
|
154
|
+
}
|
|
155
|
+
catch (err) {
|
|
156
|
+
console.error(`[scena.store] subscriber for "${path}" threw:`, err);
|
|
157
|
+
}
|
|
158
|
+
}
|
|
159
|
+
function safeWild(fn, value, path) {
|
|
160
|
+
try {
|
|
161
|
+
fn(value, path);
|
|
162
|
+
}
|
|
163
|
+
catch (err) {
|
|
164
|
+
console.error(`[scena.store] wildcard subscriber threw:`, err);
|
|
165
|
+
}
|
|
166
|
+
}
|
|
167
|
+
function notify(canonical, value) {
|
|
168
|
+
const segs = segmentsOf(canonical);
|
|
169
|
+
// Walk root → exact node. At each visited node check wildcard subs whose
|
|
170
|
+
// anchor is that node; at the terminal node fire exact subscribers.
|
|
171
|
+
let node = root;
|
|
172
|
+
fireWild(node, segs, 0, value, canonical);
|
|
173
|
+
for (let d = 0; d < segs.length; d++) {
|
|
174
|
+
node = node.children?.get(segs[d]);
|
|
175
|
+
if (!node)
|
|
176
|
+
break;
|
|
177
|
+
fireWild(node, segs, d + 1, value, canonical);
|
|
178
|
+
if (d === segs.length - 1 && node.subscribers) {
|
|
179
|
+
for (const fn of [...node.subscribers])
|
|
180
|
+
safeExact(fn, value, canonical);
|
|
181
|
+
}
|
|
182
|
+
}
|
|
183
|
+
}
|
|
184
|
+
function fireWild(node, segs, depth, value, path) {
|
|
185
|
+
if (!node.wildSubs)
|
|
186
|
+
return;
|
|
187
|
+
const rem = segs.slice(depth);
|
|
188
|
+
for (const ws of [...node.wildSubs]) {
|
|
189
|
+
if (matchPattern(ws.pattern, rem))
|
|
190
|
+
safeWild(ws.fn, value, path);
|
|
191
|
+
}
|
|
192
|
+
}
|
|
193
|
+
function flush() {
|
|
194
|
+
flushScheduled = false;
|
|
195
|
+
if (pending.size === 0)
|
|
196
|
+
return;
|
|
197
|
+
const batch = [...pending.entries()];
|
|
198
|
+
pending.clear();
|
|
199
|
+
for (const [canonical, { previous }] of batch) {
|
|
200
|
+
const { hasValue, value } = readValue(segmentsOf(canonical));
|
|
201
|
+
const force = forced.delete(canonical);
|
|
202
|
+
if (!force && Object.is(value, previous) && hasValue)
|
|
203
|
+
continue;
|
|
204
|
+
events.emit('scena:store:changed', { path: canonical, value, previous });
|
|
205
|
+
notify(canonical, value);
|
|
206
|
+
}
|
|
207
|
+
}
|
|
208
|
+
// External (backend-pushed) change: write already happened in the backend.
|
|
209
|
+
function emitExternal(path, _value) {
|
|
210
|
+
const canonical = joinSegments(segmentsOf(path));
|
|
211
|
+
forced.add(canonical);
|
|
212
|
+
queueChange(canonical);
|
|
213
|
+
}
|
|
214
|
+
function ensureNamespaceLoaded(scope) {
|
|
215
|
+
if (loadedNamespaces.has(scope))
|
|
216
|
+
return;
|
|
217
|
+
const def = dataProviders.get(scope);
|
|
218
|
+
if (!def)
|
|
219
|
+
return;
|
|
220
|
+
if (def.load === 'lazy' || def.load === undefined) {
|
|
221
|
+
loadedNamespaces.add(scope);
|
|
222
|
+
void def.provider.load(store, deps.socket);
|
|
223
|
+
}
|
|
224
|
+
}
|
|
225
|
+
// ── subtree helpers ───────────────────────────────────────────────────────
|
|
226
|
+
function walkSubtree(node, segs, visit) {
|
|
227
|
+
visit(node, segs);
|
|
228
|
+
if (node.children) {
|
|
229
|
+
for (const [seg, child] of node.children)
|
|
230
|
+
walkSubtree(child, [...segs, seg], visit);
|
|
231
|
+
}
|
|
232
|
+
}
|
|
233
|
+
// Writing a CONTAINER value invalidates sub-path subscribers — a binding to
|
|
234
|
+
// `$/a/b/name` reads via readPath, descending into the object stored at
|
|
235
|
+
// `$/a/b`, so replacing that object changes its resolved value even though no
|
|
236
|
+
// `name` node was written. notify() only walks root→exact, never down, so
|
|
237
|
+
// queue every SUBSCRIBED descendant of the written node here. Gated on the old
|
|
238
|
+
// OR new value being a container — a primitive write (e.g. `$/a = 1`) can't
|
|
239
|
+
// change any descendant's descended value, so it stays exact-path-only.
|
|
240
|
+
// Bounded: only materialized nodes (subscribed/written) exist, and only when
|
|
241
|
+
// the node has children — leaf/primitive writes stay O(1). Descendants flush
|
|
242
|
+
// with a node-only value (often undefined); subscribers re-read via readPath
|
|
243
|
+
// (which useStore does), so the fired value arg is just a wake-up signal.
|
|
244
|
+
function isContainer(v) {
|
|
245
|
+
return typeof v === 'object' && v !== null;
|
|
246
|
+
}
|
|
247
|
+
function queueDescendants(segs, prev, next) {
|
|
248
|
+
if (!isContainer(prev) && !isContainer(next))
|
|
249
|
+
return;
|
|
250
|
+
const node = walk(segs, false);
|
|
251
|
+
if (!node?.children)
|
|
252
|
+
return;
|
|
253
|
+
walkSubtree(node, segs, (n, s) => {
|
|
254
|
+
if (n === node)
|
|
255
|
+
return; // the exact path is queued by the caller
|
|
256
|
+
if ((n.subscribers && n.subscribers.size) || (n.wildSubs && n.wildSubs.length)) {
|
|
257
|
+
queueChange(joinSegments(s));
|
|
258
|
+
}
|
|
259
|
+
});
|
|
260
|
+
}
|
|
261
|
+
// ── public API ──────────────────────────────────────────────────────────
|
|
262
|
+
const store = {
|
|
263
|
+
_internalKeys() {
|
|
264
|
+
const keys = [];
|
|
265
|
+
walkSubtree(root, [], (node, segs) => {
|
|
266
|
+
if (node.hasValue && segs.length)
|
|
267
|
+
keys.push(joinSegments(segs));
|
|
268
|
+
});
|
|
269
|
+
return keys;
|
|
270
|
+
},
|
|
271
|
+
get(path) {
|
|
272
|
+
const segs = segmentsOf(path);
|
|
273
|
+
if (segs.length)
|
|
274
|
+
ensureNamespaceLoaded(segs[0]);
|
|
275
|
+
return readValue(segs).value;
|
|
276
|
+
},
|
|
277
|
+
set(path, value) {
|
|
278
|
+
const segs = segmentsOf(path);
|
|
279
|
+
const canonical = joinSegments(segs);
|
|
280
|
+
queueChange(canonical);
|
|
281
|
+
const prev = readValue(segs).value;
|
|
282
|
+
writeValue(segs, value);
|
|
283
|
+
queueDescendants(segs, prev, value);
|
|
284
|
+
},
|
|
285
|
+
patch(path, partial) {
|
|
286
|
+
const segs = segmentsOf(path);
|
|
287
|
+
const canonical = joinSegments(segs);
|
|
288
|
+
queueChange(canonical);
|
|
289
|
+
const current = readValue(segs).value;
|
|
290
|
+
const next = { ...current, ...partial };
|
|
291
|
+
writeValue(segs, next);
|
|
292
|
+
queueDescendants(segs, current, next);
|
|
293
|
+
},
|
|
294
|
+
patchMany(entries) {
|
|
295
|
+
for (const [path, value] of Object.entries(entries)) {
|
|
296
|
+
const segs = segmentsOf(path);
|
|
297
|
+
queueChange(joinSegments(segs));
|
|
298
|
+
const prev = readValue(segs).value;
|
|
299
|
+
writeValue(segs, value);
|
|
300
|
+
queueDescendants(segs, prev, value);
|
|
301
|
+
}
|
|
302
|
+
},
|
|
303
|
+
delete(path) {
|
|
304
|
+
const segs = segmentsOf(path);
|
|
305
|
+
const canonical = joinSegments(segs);
|
|
306
|
+
// capture previous before mutating
|
|
307
|
+
queueChange(canonical);
|
|
308
|
+
const removed = removeValue(segs);
|
|
309
|
+
if (removed)
|
|
310
|
+
prune(segs);
|
|
311
|
+
},
|
|
312
|
+
clearNamespace(scope) {
|
|
313
|
+
loadedNamespaces.delete(scope);
|
|
314
|
+
const node = root.children?.get(scope);
|
|
315
|
+
const backend = backends.get(scope);
|
|
316
|
+
if (!node && !backend)
|
|
317
|
+
return;
|
|
318
|
+
// Queue changes (capturing previous) for every value-bearing or
|
|
319
|
+
// subscribed descendant BEFORE clearing, so subscribers fire with the
|
|
320
|
+
// post-clear value (undefined). O(subtree), not O(total store).
|
|
321
|
+
if (node) {
|
|
322
|
+
walkSubtree(node, [scope], (n, segs) => {
|
|
323
|
+
const present = backend ? backend.get(segs.slice(1)).hasValue : n.hasValue;
|
|
324
|
+
if (present || (n.subscribers && n.subscribers.size)) {
|
|
325
|
+
queueChange(joinSegments(segs));
|
|
326
|
+
}
|
|
327
|
+
});
|
|
328
|
+
}
|
|
329
|
+
if (backend) {
|
|
330
|
+
backend.clear();
|
|
331
|
+
}
|
|
332
|
+
else if (node) {
|
|
333
|
+
walkSubtree(node, [scope], (n) => {
|
|
334
|
+
n.hasValue = false;
|
|
335
|
+
n.value = undefined;
|
|
336
|
+
});
|
|
337
|
+
}
|
|
338
|
+
},
|
|
339
|
+
subscribe(path, fn) {
|
|
340
|
+
const segs = segmentsOf(path);
|
|
341
|
+
if (segs.length) {
|
|
342
|
+
ensureNamespaceLoaded(segs[0]);
|
|
343
|
+
// Activate the scope's backend so external-push backends (Yjs/socket)
|
|
344
|
+
// attach their observer before the first change arrives.
|
|
345
|
+
ensureBackend(segs[0]);
|
|
346
|
+
}
|
|
347
|
+
if (isWildcardPath(path)) {
|
|
348
|
+
const star = segs.indexOf('*');
|
|
349
|
+
const prefix = segs.slice(0, star);
|
|
350
|
+
const pattern = segs.slice(star); // includes the '*' and the rest
|
|
351
|
+
const anchor = walk(prefix, true);
|
|
352
|
+
if (!anchor.wildSubs)
|
|
353
|
+
anchor.wildSubs = [];
|
|
354
|
+
const entry = { pattern, fn: fn };
|
|
355
|
+
anchor.wildSubs.push(entry);
|
|
356
|
+
return disposableFrom(() => {
|
|
357
|
+
const arr = anchor.wildSubs;
|
|
358
|
+
if (!arr)
|
|
359
|
+
return;
|
|
360
|
+
const i = arr.indexOf(entry);
|
|
361
|
+
if (i >= 0)
|
|
362
|
+
arr.splice(i, 1);
|
|
363
|
+
if (arr.length === 0)
|
|
364
|
+
anchor.wildSubs = undefined;
|
|
365
|
+
prune(prefix);
|
|
366
|
+
});
|
|
367
|
+
}
|
|
368
|
+
const node = walk(segs, true);
|
|
369
|
+
if (!node.subscribers)
|
|
370
|
+
node.subscribers = new Set();
|
|
371
|
+
node.subscribers.add(fn);
|
|
372
|
+
return disposableFrom(() => {
|
|
373
|
+
node.subscribers?.delete(fn);
|
|
374
|
+
if (node.subscribers && node.subscribers.size === 0)
|
|
375
|
+
node.subscribers = undefined;
|
|
376
|
+
prune(segs);
|
|
377
|
+
});
|
|
378
|
+
},
|
|
379
|
+
subscriberCount(scope) {
|
|
380
|
+
const node = root.children?.get(scope);
|
|
381
|
+
if (!node)
|
|
382
|
+
return 0;
|
|
383
|
+
let count = 0;
|
|
384
|
+
walkSubtree(node, [scope], (n) => {
|
|
385
|
+
if (n.subscribers)
|
|
386
|
+
count += n.subscribers.size;
|
|
387
|
+
if (n.wildSubs)
|
|
388
|
+
count += n.wildSubs.length;
|
|
389
|
+
});
|
|
390
|
+
return count;
|
|
391
|
+
},
|
|
392
|
+
computed(path, def) {
|
|
393
|
+
const target = joinSegments(segmentsOf(path));
|
|
394
|
+
const froms = def.from.slice();
|
|
395
|
+
detectCycle(target, froms);
|
|
396
|
+
computedDeps.set(target, froms);
|
|
397
|
+
const selectFn = typeof def.select === 'function' ? def.select : compileSelect(def.select);
|
|
398
|
+
const recompute = () => {
|
|
399
|
+
const inputs = {};
|
|
400
|
+
for (const f of froms)
|
|
401
|
+
inputs[f] = gatherInput(f);
|
|
402
|
+
store.set(path, selectFn(inputs));
|
|
403
|
+
};
|
|
404
|
+
const disposables = froms.map((p) => store.subscribe(p, recompute));
|
|
405
|
+
recompute();
|
|
406
|
+
return disposableFrom(() => {
|
|
407
|
+
disposables.forEach((d) => d.dispose());
|
|
408
|
+
computedDeps.delete(target);
|
|
409
|
+
});
|
|
410
|
+
},
|
|
411
|
+
registerDataProvider(def) {
|
|
412
|
+
dataProviders.set(def.namespace, def);
|
|
413
|
+
if (def.load === 'eager') {
|
|
414
|
+
loadedNamespaces.add(def.namespace);
|
|
415
|
+
void def.provider.load(store, deps.socket);
|
|
416
|
+
}
|
|
417
|
+
return disposableFrom(() => {
|
|
418
|
+
if (loadedNamespaces.has(def.namespace)) {
|
|
419
|
+
void def.provider.unload?.(store, deps.socket);
|
|
420
|
+
loadedNamespaces.delete(def.namespace);
|
|
421
|
+
}
|
|
422
|
+
dataProviders.delete(def.namespace);
|
|
423
|
+
});
|
|
424
|
+
},
|
|
425
|
+
listDataProviders() {
|
|
426
|
+
return [...dataProviders.values()];
|
|
427
|
+
},
|
|
428
|
+
};
|
|
429
|
+
// ── computed helpers ──────────────────────────────────────────────────────
|
|
430
|
+
function gatherInput(from) {
|
|
431
|
+
if (hasWildcard(from)) {
|
|
432
|
+
// Expand a wildcard `from` to the array of matched stored values
|
|
433
|
+
// (in-memory scopes only). Used by collection selects (countWhere, …).
|
|
434
|
+
const segs = segmentsOf(from);
|
|
435
|
+
const star = segs.indexOf('*');
|
|
436
|
+
const prefix = segs.slice(0, star);
|
|
437
|
+
const pattern = segs.slice(star);
|
|
438
|
+
const anchor = walk(prefix, false);
|
|
439
|
+
if (!anchor)
|
|
440
|
+
return [];
|
|
441
|
+
const out = [];
|
|
442
|
+
walkSubtree(anchor, prefix, (n, s) => {
|
|
443
|
+
if (!n.hasValue)
|
|
444
|
+
return;
|
|
445
|
+
if (matchPattern(pattern, s.slice(prefix.length)))
|
|
446
|
+
out.push(n.value);
|
|
447
|
+
});
|
|
448
|
+
return out;
|
|
449
|
+
}
|
|
450
|
+
return store.get(from);
|
|
451
|
+
}
|
|
452
|
+
function detectCycle(target, froms) {
|
|
453
|
+
const seen = new Set();
|
|
454
|
+
const stack = froms.map((f) => joinSegments(segmentsOf(f)));
|
|
455
|
+
while (stack.length) {
|
|
456
|
+
const cur = stack.pop();
|
|
457
|
+
if (cur === target) {
|
|
458
|
+
throw new Error(`computed: registering "${target}" would create a dependency cycle.`);
|
|
459
|
+
}
|
|
460
|
+
if (seen.has(cur))
|
|
461
|
+
continue;
|
|
462
|
+
seen.add(cur);
|
|
463
|
+
const deps2 = computedDeps.get(cur);
|
|
464
|
+
if (deps2)
|
|
465
|
+
stack.push(...deps2.map((f) => joinSegments(segmentsOf(f))));
|
|
466
|
+
}
|
|
467
|
+
}
|
|
468
|
+
return store;
|
|
469
|
+
}
|
|
470
|
+
// ── mount-local helpers (canonical layout: `$/local/<mountKey>/<rest>`) ──────
|
|
471
|
+
export function localPath(mountKey, suffix) {
|
|
472
|
+
const tail = suffix.startsWith('/') ? suffix.slice(1) : suffix;
|
|
473
|
+
return `$/local/${mountKey}/${tail}`;
|
|
474
|
+
}
|
|
475
|
+
const LOCAL_PREFIX = '$/local/';
|
|
476
|
+
export function rewriteLocal(path, mountKey) {
|
|
477
|
+
if (!mountKey)
|
|
478
|
+
return path;
|
|
479
|
+
if (!path.startsWith(LOCAL_PREFIX))
|
|
480
|
+
return path;
|
|
481
|
+
const tail = path.slice(LOCAL_PREFIX.length);
|
|
482
|
+
if (tail.startsWith(`${mountKey}/`) || tail === mountKey)
|
|
483
|
+
return path;
|
|
484
|
+
return `$/local/${mountKey}/${tail}`;
|
|
485
|
+
}
|
|
486
|
+
export function clearMountLocal(store, mountKey) {
|
|
487
|
+
const internal = store;
|
|
488
|
+
const keys = internal._internalKeys?.() ?? [];
|
|
489
|
+
const prefix = `$/local/${mountKey}/`;
|
|
490
|
+
const exact = `$/local/${mountKey}`;
|
|
491
|
+
for (const key of keys) {
|
|
492
|
+
if (key === exact || key.startsWith(prefix)) {
|
|
493
|
+
store.delete(key);
|
|
494
|
+
}
|
|
495
|
+
}
|
|
496
|
+
}
|
|
@@ -0,0 +1,115 @@
|
|
|
1
|
+
import { createEventBus } from '../controls/events.js';
|
|
2
|
+
import { createWhenEngine } from '../controls/when.js';
|
|
3
|
+
import { createCommandRegistry } from '../controls/command.js';
|
|
4
|
+
import { createKeybindingRegistry } from '../controls/keybinding.js';
|
|
5
|
+
import { createLayoutAPI, createLayoutRegistry } from '../controls/layout.js';
|
|
6
|
+
import { createSessionAPI } from '../controls/session.js';
|
|
7
|
+
import { createShellRegistry } from '../controls/shell.js';
|
|
8
|
+
import { createManifestAPI } from '../controls/manifest.js';
|
|
9
|
+
import { createPermissionEngine } from './permissions.js';
|
|
10
|
+
import { createReactiveStore } from './reactive-store.js';
|
|
11
|
+
import { createBindingResolver } from './binding-resolver.js';
|
|
12
|
+
import { createComponentRegistry } from './component-registry.js';
|
|
13
|
+
import { createConverterRegistry } from './converter-registry.js';
|
|
14
|
+
import { createMountSurfaceRegistry } from './mount-surface.js';
|
|
15
|
+
import { createMountMenuRegistry } from './mount-menu.js';
|
|
16
|
+
import { registerBuiltinFunctions } from '../runtime/builtins.js';
|
|
17
|
+
export const createScena = (opts = {}) => {
|
|
18
|
+
const events = opts.events ?? createEventBus();
|
|
19
|
+
const permissions = createPermissionEngine();
|
|
20
|
+
const store = createReactiveStore({
|
|
21
|
+
events,
|
|
22
|
+
socket: opts.socket,
|
|
23
|
+
backendFactories: opts.backendFactories,
|
|
24
|
+
});
|
|
25
|
+
const bindings = createBindingResolver({ store });
|
|
26
|
+
const when = createWhenEngine({ store });
|
|
27
|
+
const components = createComponentRegistry({ events });
|
|
28
|
+
const converters = createConverterRegistry();
|
|
29
|
+
const surfaces = createMountSurfaceRegistry({ events, when, bindings, store, components });
|
|
30
|
+
const mountMenus = createMountMenuRegistry();
|
|
31
|
+
const layouts = createLayoutRegistry({ events });
|
|
32
|
+
const shells = createShellRegistry({ events, initialId: opts.initialShellId });
|
|
33
|
+
const layout = createLayoutAPI({
|
|
34
|
+
events,
|
|
35
|
+
store,
|
|
36
|
+
initial: opts.initialLayout,
|
|
37
|
+
storage: opts.layoutStorage,
|
|
38
|
+
});
|
|
39
|
+
const scenaRef = { current: null };
|
|
40
|
+
const keybindings = createKeybindingRegistry({ events, when });
|
|
41
|
+
const commands = createCommandRegistry({
|
|
42
|
+
events,
|
|
43
|
+
store,
|
|
44
|
+
surfaces,
|
|
45
|
+
when,
|
|
46
|
+
socket: opts.socket,
|
|
47
|
+
keybindings,
|
|
48
|
+
getScena: () => {
|
|
49
|
+
if (!scenaRef.current) {
|
|
50
|
+
throw new Error('Scena instance accessed before createScena() returned');
|
|
51
|
+
}
|
|
52
|
+
return scenaRef.current;
|
|
53
|
+
},
|
|
54
|
+
});
|
|
55
|
+
const session = createSessionAPI({
|
|
56
|
+
events,
|
|
57
|
+
store,
|
|
58
|
+
surfaces,
|
|
59
|
+
components,
|
|
60
|
+
storage: opts.sessionStorage,
|
|
61
|
+
});
|
|
62
|
+
const manifest = createManifestAPI({
|
|
63
|
+
events,
|
|
64
|
+
store,
|
|
65
|
+
components,
|
|
66
|
+
commands,
|
|
67
|
+
keybindings,
|
|
68
|
+
surfaces,
|
|
69
|
+
converters,
|
|
70
|
+
permissions,
|
|
71
|
+
});
|
|
72
|
+
if (opts.initialActive) {
|
|
73
|
+
for (const [path, value] of Object.entries(opts.initialActive)) {
|
|
74
|
+
store.set(path, value);
|
|
75
|
+
}
|
|
76
|
+
}
|
|
77
|
+
events.on('scena:mount:focused', (payload) => {
|
|
78
|
+
const ev = payload;
|
|
79
|
+
layout.setSurface(ev.surface, { activeContainerKey: ev.key });
|
|
80
|
+
});
|
|
81
|
+
const scena = {
|
|
82
|
+
components,
|
|
83
|
+
store,
|
|
84
|
+
bindings,
|
|
85
|
+
surfaces,
|
|
86
|
+
mountMenus,
|
|
87
|
+
layouts,
|
|
88
|
+
converters,
|
|
89
|
+
permissions,
|
|
90
|
+
commands,
|
|
91
|
+
keybindings,
|
|
92
|
+
shells,
|
|
93
|
+
layout,
|
|
94
|
+
session,
|
|
95
|
+
manifest,
|
|
96
|
+
events,
|
|
97
|
+
when,
|
|
98
|
+
open: surfaces.open.bind(surfaces),
|
|
99
|
+
openResource: surfaces.openResource.bind(surfaces),
|
|
100
|
+
execute: commands.execute.bind(commands),
|
|
101
|
+
setSessionStorage(s) {
|
|
102
|
+
session.setStorage(s);
|
|
103
|
+
},
|
|
104
|
+
setLayoutStorage(s) {
|
|
105
|
+
layout.setStorage(s);
|
|
106
|
+
},
|
|
107
|
+
dispose() {
|
|
108
|
+
// Per-source disposable tracking lives at the registration site.
|
|
109
|
+
},
|
|
110
|
+
};
|
|
111
|
+
scenaRef.current = scena;
|
|
112
|
+
// The a2ui v0.10 basic-catalog functions are always available.
|
|
113
|
+
registerBuiltinFunctions(scena);
|
|
114
|
+
return scena;
|
|
115
|
+
};
|
|
@@ -0,0 +1,6 @@
|
|
|
1
|
+
import type { SurfaceName } from '../types/mount-surface.js';
|
|
2
|
+
import type { SurfacePresentation } from '../types/layout.js';
|
|
3
|
+
import type { ModusClass } from './backends/modus-backend.js';
|
|
4
|
+
export type PresentationPolicy = Partial<Record<SurfaceName, Partial<Record<ModusClass, SurfacePresentation>>>>;
|
|
5
|
+
export declare function resolveSurfacePresentation(surface: SurfaceName, modus: ModusClass, policy?: PresentationPolicy): SurfacePresentation;
|
|
6
|
+
export declare function isOverlaid(presentation: SurfacePresentation): boolean;
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
export function resolveSurfacePresentation(surface, modus, policy = {}) {
|
|
2
|
+
return policy[surface]?.[modus] ?? 'docked';
|
|
3
|
+
}
|
|
4
|
+
// True when a presentation takes the surface out of the flex flow. Shells use
|
|
5
|
+
// this to decide whether to render a splitter at all — a floating surface has
|
|
6
|
+
// nothing left to resize against — and whether a scrim is needed.
|
|
7
|
+
//
|
|
8
|
+
// `bar` is excluded on purpose: it is pinned to an edge but still occupies it,
|
|
9
|
+
// so a shell keeps reserving space for it and draws no scrim.
|
|
10
|
+
export function isOverlaid(presentation) {
|
|
11
|
+
return presentation === 'floating' || presentation === 'sheet';
|
|
12
|
+
}
|
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
import { resolveMessage, subscribeI18n } from './registry.js';
|
|
2
|
+
// A ScopeBackend that makes `$/t/<key>` resolve to the active locale's message
|
|
3
|
+
// from the i18n registry — your `$translate -> $i18n/<locale>` alias, realized
|
|
4
|
+
// through the backend seam. Read-only (translations are registered via
|
|
5
|
+
// registerMessages, not store writes). No dictionary is copied into the store
|
|
6
|
+
// tree; values resolve on read.
|
|
7
|
+
//
|
|
8
|
+
// On any registry change (locale switch OR new messages), the backend re-emits
|
|
9
|
+
// the keys that have actually been READ (bound somewhere) so their store
|
|
10
|
+
// subscribers refresh — bounded to live keys, not the whole dictionary.
|
|
11
|
+
export function createI18nBackend(scope = 't') {
|
|
12
|
+
const accessed = new Set();
|
|
13
|
+
const keyOf = (segs) => segs.join('/');
|
|
14
|
+
return {
|
|
15
|
+
get(segs) {
|
|
16
|
+
const key = keyOf(segs);
|
|
17
|
+
accessed.add(key);
|
|
18
|
+
const v = resolveMessage(key);
|
|
19
|
+
return v === undefined ? { hasValue: false, value: undefined } : { hasValue: true, value: v };
|
|
20
|
+
},
|
|
21
|
+
set() {
|
|
22
|
+
/* translations are read-only via the store; use registerMessages */
|
|
23
|
+
},
|
|
24
|
+
delete() { },
|
|
25
|
+
clear() { },
|
|
26
|
+
attach(emit) {
|
|
27
|
+
const unsub = subscribeI18n(() => {
|
|
28
|
+
for (const key of accessed) {
|
|
29
|
+
emit(`$/${scope}/${key}`, resolveMessage(key));
|
|
30
|
+
}
|
|
31
|
+
});
|
|
32
|
+
return { dispose: unsub };
|
|
33
|
+
},
|
|
34
|
+
};
|
|
35
|
+
}
|