@cosmicdrift/kumiko-renderer 0.373.0 → 0.377.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/README.md +2 -2
- package/dist/app/action-form-support.d.ts +58 -0
- package/dist/app/action-form-support.js +96 -0
- package/dist/app/client-actions.d.ts +46 -0
- package/dist/app/client-actions.js +60 -0
- package/dist/app/column-renderers.js +1 -1
- package/dist/app/config-edit-shim.js +1 -1
- package/dist/app/content-preview.js +1 -6
- package/dist/app/custom-screens.js +1 -1
- package/dist/app/dashboard-body.d.ts +1 -1
- package/dist/app/entity-list-expanded-row.d.ts +1 -1
- package/dist/app/entity-list-expanded-row.js +4 -0
- package/dist/app/form-schema.d.ts +1 -1
- package/dist/app/form-schema.js +2 -2
- package/dist/app/header-actions-bar.d.ts +19 -0
- package/dist/app/header-actions-bar.js +30 -0
- package/dist/app/kumiko-screen.d.ts +1 -1
- package/dist/app/kumiko-screen.js +134 -66
- package/dist/app/list-empty-content.d.ts +2 -2
- package/dist/app/list-empty-content.js +3 -2
- package/dist/app/list-facets.d.ts +1 -1
- package/dist/app/nav.js +2 -2
- package/dist/app/query-state-banners.d.ts +1 -1
- package/dist/app/reference-link.d.ts +1 -1
- package/dist/app/row-actions.d.ts +10 -2
- package/dist/app/row-actions.js +85 -6
- package/dist/app/secret-mint-body.d.ts +1 -1
- package/dist/app/secrets-edit-body.d.ts +1 -1
- package/dist/app/use-record-actions.d.ts +12 -0
- package/dist/app/use-record-actions.js +30 -0
- package/dist/app/write-failed-error.d.ts +1 -1
- package/dist/components/availability-options-select.d.ts +1 -1
- package/dist/components/embedded-list-field.d.ts +1 -1
- package/dist/components/embedded-list-field.js +1 -1
- package/dist/components/file-list-field.d.ts +1 -1
- package/dist/components/grid-cell-for-field.d.ts +4 -2
- package/dist/components/grid-cell-for-field.js +2 -2
- package/dist/components/multi-select-checkboxes.d.ts +1 -1
- package/dist/components/multi-select-checkboxes.js +1 -1
- package/dist/components/query-options-select.d.ts +1 -1
- package/dist/components/related-list-section.d.ts +1 -1
- package/dist/components/related-list-section.js +16 -3
- package/dist/components/render-edit-logic.d.ts +1 -1
- package/dist/components/render-edit-types.d.ts +2 -2
- package/dist/components/render-edit.d.ts +1 -1
- package/dist/components/render-edit.js +5 -3
- package/dist/components/render-field.d.ts +5 -2
- package/dist/components/render-field.js +103 -9
- package/dist/components/render-list.d.ts +1 -1
- package/dist/components/render-list.js +20 -4
- package/dist/components/write-form-section.d.ts +1 -1
- package/dist/components/write-form-section.js +1 -1
- package/dist/context/dispatcher-context.d.ts +1 -1
- package/dist/format-when.js +1 -1
- package/dist/headless/apex/css.d.ts +3 -0
- package/dist/headless/apex/css.js +298 -0
- package/dist/headless/apex/index.d.ts +236 -0
- package/dist/headless/apex/index.js +377 -0
- package/dist/headless/apex/lightbox.d.ts +4 -0
- package/dist/headless/apex/lightbox.js +81 -0
- package/dist/headless/contracts/asset.d.ts +15 -0
- package/dist/headless/contracts/asset.js +17 -0
- package/dist/headless/contracts/index.d.ts +3 -0
- package/dist/headless/contracts/index.js +1 -0
- package/dist/headless/contracts/locale.d.ts +7 -0
- package/dist/headless/contracts/locale.js +11 -0
- package/dist/headless/contracts/primitives.d.ts +93 -0
- package/dist/headless/contracts/primitives.js +21 -0
- package/dist/headless/dispatcher/index.d.ts +2 -0
- package/dist/headless/dispatcher/index.js +1 -0
- package/dist/headless/dispatcher/types.d.ts +86 -0
- package/dist/headless/dispatcher/types.js +34 -0
- package/dist/headless/form/form-controller.d.ts +2 -0
- package/dist/headless/form/form-controller.js +409 -0
- package/dist/headless/form/index.d.ts +3 -0
- package/dist/headless/form/index.js +2 -0
- package/dist/headless/form/types.d.ts +76 -0
- package/dist/headless/form/types.js +1 -0
- package/dist/headless/form/zod-bridge.d.ts +10 -0
- package/dist/headless/form/zod-bridge.js +103 -0
- package/dist/headless/format/document-values.d.ts +12 -0
- package/dist/headless/format/document-values.js +70 -0
- package/dist/headless/format/escape.d.ts +5 -0
- package/dist/headless/format/escape.js +75 -0
- package/dist/headless/format/html-template.d.ts +9 -0
- package/dist/headless/format/html-template.js +39 -0
- package/dist/headless/format/index.d.ts +12 -0
- package/dist/headless/format/index.js +237 -0
- package/dist/headless/format/money.d.ts +3 -0
- package/dist/headless/format/money.js +39 -0
- package/dist/headless/index.d.ts +14 -0
- package/dist/headless/index.js +9 -0
- package/dist/headless/locale-routing/index.d.ts +41 -0
- package/dist/headless/locale-routing/index.js +145 -0
- package/dist/headless/nav/index.d.ts +2 -0
- package/dist/headless/nav/index.js +1 -0
- package/dist/headless/nav/resolve.d.ts +2 -0
- package/dist/headless/nav/resolve.js +71 -0
- package/dist/headless/nav/types.d.ts +26 -0
- package/dist/headless/nav/types.js +1 -0
- package/dist/headless/store/create-store.d.ts +2 -0
- package/dist/headless/store/create-store.js +43 -0
- package/dist/headless/store/equality.d.ts +1 -0
- package/dist/headless/store/equality.js +34 -0
- package/dist/headless/store/index.d.ts +3 -0
- package/dist/headless/store/index.js +2 -0
- package/dist/headless/store/types.d.ts +7 -0
- package/dist/headless/store/types.js +10 -0
- package/dist/headless/view-model/edit.d.ts +18 -0
- package/dist/headless/view-model/edit.js +501 -0
- package/dist/headless/view-model/embedded-list.d.ts +27 -0
- package/dist/headless/view-model/embedded-list.js +63 -0
- package/dist/headless/view-model/index.d.ts +7 -0
- package/dist/headless/view-model/index.js +3 -0
- package/dist/headless/view-model/list-file-display.d.ts +3 -0
- package/dist/headless/view-model/list-file-display.js +27 -0
- package/dist/headless/view-model/list.d.ts +16 -0
- package/dist/headless/view-model/list.js +229 -0
- package/dist/headless/view-model/types.d.ts +382 -0
- package/dist/headless/view-model/types.js +1 -0
- package/dist/hooks/use-ai-text.d.ts +1 -1
- package/dist/hooks/use-form.d.ts +1 -1
- package/dist/hooks/use-form.js +1 -1
- package/dist/hooks/use-mutation.d.ts +1 -1
- package/dist/hooks/use-query.d.ts +1 -1
- package/dist/hooks/use-store.d.ts +1 -1
- package/dist/hooks/use-store.js +7 -7
- package/dist/hooks/use-stream-handler.d.ts +1 -1
- package/dist/i18n-defaults.js +7 -0
- package/dist/i18n.d.ts +1 -1
- package/dist/i18n.js +1 -1
- package/dist/index.d.ts +5 -1
- package/dist/index.js +7 -4
- package/dist/live/csrf.d.ts +2 -0
- package/dist/live/csrf.js +60 -0
- package/dist/live/dispatcher-live.d.ts +7 -0
- package/dist/live/dispatcher-live.js +286 -0
- package/dist/live/envelopes.d.ts +101 -0
- package/dist/live/envelopes.js +35 -0
- package/dist/live/error-mapping.d.ts +16 -0
- package/dist/live/error-mapping.js +82 -0
- package/dist/live/index.d.ts +7 -0
- package/dist/live/index.js +5 -0
- package/dist/live/locale.d.ts +2 -0
- package/dist/live/locale.js +25 -0
- package/dist/live/sse-stream.d.ts +14 -0
- package/dist/live/sse-stream.js +128 -0
- package/dist/primitives.d.ts +53 -36
- package/dist/primitives.js +1 -1
- package/dist/session/session-ended.d.ts +1 -1
- package/dist/tokens.d.ts +3 -4
- package/dist/tokens.js +4 -5
- package/dist/web/app/app-schema-boot.d.ts +19 -0
- package/dist/web/app/app-schema-boot.js +124 -0
- package/dist/web/app/browser-locale.d.ts +22 -0
- package/dist/web/app/browser-locale.js +78 -0
- package/dist/web/app/client-plugin.d.ts +106 -0
- package/dist/web/app/client-plugin.js +12 -0
- package/dist/web/app/create-app.d.ts +104 -0
- package/dist/web/app/create-app.js +498 -0
- package/dist/web/app/create-public-surface.d.ts +36 -0
- package/dist/web/app/create-public-surface.js +40 -0
- package/dist/web/app/dashboard-body.d.ts +3 -0
- package/dist/web/app/dashboard-body.js +865 -0
- package/dist/web/app/dashboard-refresh.d.ts +6 -0
- package/dist/web/app/dashboard-refresh.js +15 -0
- package/dist/web/app/document-lang-sync.d.ts +4 -0
- package/dist/web/app/document-lang-sync.js +27 -0
- package/dist/web/app/draft-storage.d.ts +11 -0
- package/dist/web/app/draft-storage.js +53 -0
- package/dist/web/app/nav-providers-context.d.ts +13 -0
- package/dist/web/app/nav-providers-context.js +18 -0
- package/dist/web/app/nav.d.ts +40 -0
- package/dist/web/app/nav.js +231 -0
- package/dist/web/app/plain-content-editor.d.ts +3 -0
- package/dist/web/app/plain-content-editor.js +30 -0
- package/dist/web/app/relative-time.d.ts +10 -0
- package/dist/web/app/relative-time.js +56 -0
- package/dist/web/app/resolvers-context.d.ts +12 -0
- package/dist/web/app/resolvers-context.js +10 -0
- package/dist/web/app/rich-content-editor.d.ts +3 -0
- package/dist/web/app/rich-content-editor.js +15 -0
- package/dist/web/app/root-error-fallback.d.ts +2 -0
- package/dist/web/app/root-error-fallback.js +21 -0
- package/dist/web/app/screen-error-fallback.d.ts +6 -0
- package/dist/web/app/screen-error-fallback.js +17 -0
- package/dist/web/app/tiptap-editor.d.ts +3 -0
- package/dist/web/app/tiptap-editor.js +120 -0
- package/dist/web/app/toast-action-notifier.d.ts +5 -0
- package/dist/web/app/toast-action-notifier.js +17 -0
- package/dist/web/components/config-cascade.d.ts +13 -0
- package/dist/web/components/config-cascade.js +155 -0
- package/dist/web/components/config-source-badge.d.ts +6 -0
- package/dist/web/components/config-source-badge.js +55 -0
- package/dist/web/default-color-scheme.d.ts +2 -0
- package/dist/web/default-color-scheme.js +3 -0
- package/dist/web/icons.d.ts +94 -0
- package/dist/web/icons.js +100 -0
- package/dist/web/index.d.ts +78 -0
- package/dist/web/index.js +53 -0
- package/dist/web/layout/app-layout.d.ts +21 -0
- package/dist/web/layout/app-layout.js +8 -0
- package/dist/web/layout/avatar.d.ts +12 -0
- package/dist/web/layout/avatar.js +63 -0
- package/dist/web/layout/default-app-shell.d.ts +41 -0
- package/dist/web/layout/default-app-shell.js +16 -0
- package/dist/web/layout/editor-panel.d.ts +10 -0
- package/dist/web/layout/editor-panel.js +29 -0
- package/dist/web/layout/fill-classes.d.ts +9 -0
- package/dist/web/layout/fill-classes.js +15 -0
- package/dist/web/layout/filter-app-schema-navs.d.ts +7 -0
- package/dist/web/layout/filter-app-schema-navs.js +68 -0
- package/dist/web/layout/header-action-group.d.ts +6 -0
- package/dist/web/layout/header-action-group.js +8 -0
- package/dist/web/layout/header-overflow-menu.d.ts +4 -0
- package/dist/web/layout/header-overflow-menu.js +8 -0
- package/dist/web/layout/language-menu-items.d.ts +8 -0
- package/dist/web/layout/language-menu-items.js +16 -0
- package/dist/web/layout/language-switcher.d.ts +25 -0
- package/dist/web/layout/language-switcher.js +46 -0
- package/dist/web/layout/nav-tree.d.ts +19 -0
- package/dist/web/layout/nav-tree.js +536 -0
- package/dist/web/layout/page-header-slot.d.ts +25 -0
- package/dist/web/layout/page-header-slot.js +50 -0
- package/dist/web/layout/profile-menu.d.ts +13 -0
- package/dist/web/layout/profile-menu.js +6 -0
- package/dist/web/layout/shell-breadcrumb.d.ts +11 -0
- package/dist/web/layout/shell-breadcrumb.js +34 -0
- package/dist/web/layout/shell-header.d.ts +12 -0
- package/dist/web/layout/shell-header.js +159 -0
- package/dist/web/layout/sidebar-brand.d.ts +15 -0
- package/dist/web/layout/sidebar-brand.js +9 -0
- package/dist/web/layout/sidebar-panel.d.ts +41 -0
- package/dist/web/layout/sidebar-panel.js +107 -0
- package/dist/web/layout/sidebar-user.d.ts +8 -0
- package/dist/web/layout/sidebar-user.js +17 -0
- package/dist/web/layout/sidebar.d.ts +17 -0
- package/dist/web/layout/sidebar.js +11 -0
- package/dist/web/layout/target-resolver-stub.d.ts +13 -0
- package/dist/web/layout/target-resolver-stub.js +61 -0
- package/dist/web/layout/target-url.d.ts +12 -0
- package/dist/web/layout/target-url.js +77 -0
- package/dist/web/layout/theme-label.d.ts +15 -0
- package/dist/web/layout/theme-label.js +35 -0
- package/dist/web/layout/theme-menu-item.d.ts +12 -0
- package/dist/web/layout/theme-menu-item.js +16 -0
- package/dist/web/layout/theme-toggle.d.ts +17 -0
- package/dist/web/layout/theme-toggle.js +22 -0
- package/dist/web/layout/topbar.d.ts +8 -0
- package/dist/web/layout/topbar.js +4 -0
- package/dist/web/layout/workspace-shell.d.ts +63 -0
- package/dist/web/layout/workspace-shell.js +220 -0
- package/dist/web/layout/workspace-switcher.d.ts +15 -0
- package/dist/web/layout/workspace-switcher.js +36 -0
- package/dist/web/lib/accept-attr.d.ts +1 -0
- package/dist/web/lib/accept-attr.js +6 -0
- package/dist/web/lib/clamp.d.ts +1 -0
- package/dist/web/lib/clamp.js +3 -0
- package/dist/web/lib/cn.d.ts +6 -0
- package/dist/web/lib/cn.js +9 -0
- package/dist/web/lib/download.d.ts +2 -0
- package/dist/web/lib/download.js +24 -0
- package/dist/web/lib/file-ref-download.d.ts +15 -0
- package/dist/web/lib/file-ref-download.js +62 -0
- package/dist/web/lib/file-upload-form-data.d.ts +7 -0
- package/dist/web/lib/file-upload-form-data.js +11 -0
- package/dist/web/lib/resize-image.d.ts +1 -0
- package/dist/web/lib/resize-image.js +66 -0
- package/dist/web/lib/upload-file-ref.d.ts +9 -0
- package/dist/web/lib/upload-file-ref.js +29 -0
- package/dist/web/primitives/action-menu.d.ts +34 -0
- package/dist/web/primitives/action-menu.js +30 -0
- package/dist/web/primitives/calendar-popover.d.ts +13 -0
- package/dist/web/primitives/calendar-popover.js +76 -0
- package/dist/web/primitives/combobox.d.ts +56 -0
- package/dist/web/primitives/combobox.js +127 -0
- package/dist/web/primitives/date-field.d.ts +18 -0
- package/dist/web/primitives/date-field.js +74 -0
- package/dist/web/primitives/date-input.d.ts +1 -0
- package/dist/web/primitives/date-input.js +5 -0
- package/dist/web/primitives/date-parse.d.ts +11 -0
- package/dist/web/primitives/date-parse.js +159 -0
- package/dist/web/primitives/dialog.d.ts +3 -0
- package/dist/web/primitives/dialog.js +42 -0
- package/dist/web/primitives/drawer.d.ts +3 -0
- package/dist/web/primitives/drawer.js +17 -0
- package/dist/web/primitives/dropdown-menu.d.ts +15 -0
- package/dist/web/primitives/dropdown-menu.js +56 -0
- package/dist/web/primitives/embedded-list-input.d.ts +9 -0
- package/dist/web/primitives/embedded-list-input.js +382 -0
- package/dist/web/primitives/file-thumbnail.d.ts +25 -0
- package/dist/web/primitives/file-thumbnail.js +90 -0
- package/dist/web/primitives/file-upload.d.ts +21 -0
- package/dist/web/primitives/file-upload.js +56 -0
- package/dist/web/primitives/index.d.ts +34 -0
- package/dist/web/primitives/index.js +2021 -0
- package/dist/web/primitives/json-view.d.ts +7 -0
- package/dist/web/primitives/json-view.js +84 -0
- package/dist/web/primitives/layout.d.ts +27 -0
- package/dist/web/primitives/layout.js +30 -0
- package/dist/web/primitives/lightbox.d.ts +3 -0
- package/dist/web/primitives/lightbox.js +36 -0
- package/dist/web/primitives/locale-number.d.ts +2 -0
- package/dist/web/primitives/locale-number.js +54 -0
- package/dist/web/primitives/located-timestamp-input.d.ts +22 -0
- package/dist/web/primitives/located-timestamp-input.js +22 -0
- package/dist/web/primitives/metric.d.ts +5 -0
- package/dist/web/primitives/metric.js +18 -0
- package/dist/web/primitives/modal-shell.d.ts +17 -0
- package/dist/web/primitives/modal-shell.js +9 -0
- package/dist/web/primitives/modal.d.ts +3 -0
- package/dist/web/primitives/modal.js +13 -0
- package/dist/web/primitives/money-input.d.ts +18 -0
- package/dist/web/primitives/money-input.js +122 -0
- package/dist/web/primitives/narrow-pinned-footer.d.ts +12 -0
- package/dist/web/primitives/narrow-pinned-footer.js +153 -0
- package/dist/web/primitives/number-input.d.ts +18 -0
- package/dist/web/primitives/number-input.js +53 -0
- package/dist/web/primitives/option-groups.d.ts +11 -0
- package/dist/web/primitives/option-groups.js +27 -0
- package/dist/web/primitives/page-header.d.ts +3 -0
- package/dist/web/primitives/page-header.js +52 -0
- package/dist/web/primitives/promo-panel.d.ts +3 -0
- package/dist/web/primitives/promo-panel.js +11 -0
- package/dist/web/primitives/segmented-select.d.ts +21 -0
- package/dist/web/primitives/segmented-select.js +62 -0
- package/dist/web/primitives/share-actions.d.ts +4 -0
- package/dist/web/primitives/share-actions.js +56 -0
- package/dist/web/primitives/status-badge.d.ts +3 -0
- package/dist/web/primitives/status-badge.js +5 -0
- package/dist/web/primitives/sticky-action-bar.d.ts +5 -0
- package/dist/web/primitives/sticky-action-bar.js +15 -0
- package/dist/web/primitives/tabs.d.ts +3 -0
- package/dist/web/primitives/tabs.js +107 -0
- package/dist/web/primitives/timestamp-input.d.ts +27 -0
- package/dist/web/primitives/timestamp-input.js +87 -0
- package/dist/web/primitives/toast.d.ts +19 -0
- package/dist/web/primitives/toast.js +63 -0
- package/dist/web/primitives/tz-input.d.ts +11 -0
- package/dist/web/primitives/tz-input.js +8 -0
- package/dist/web/primitives/tz-options.d.ts +4 -0
- package/dist/web/primitives/tz-options.js +17 -0
- package/dist/web/primitives/use-keyboard-inset.d.ts +1 -0
- package/dist/web/primitives/use-keyboard-inset.js +28 -0
- package/dist/web/primitives/use-narrow-viewport.d.ts +4 -0
- package/dist/web/primitives/use-narrow-viewport.js +46 -0
- package/dist/web/react-css-custom-properties.d.ts +6 -0
- package/dist/web/react-css-custom-properties.js +1 -0
- package/dist/web/sse/live-events.d.ts +15 -0
- package/dist/web/sse/live-events.js +148 -0
- package/dist/web/theme-plugin.d.ts +41 -0
- package/dist/web/theme-plugin.js +123 -0
- package/dist/web/tokens.d.ts +24 -0
- package/dist/web/tokens.js +203 -0
- package/dist/web/ui/avatar.d.ts +11 -0
- package/dist/web/ui/avatar.js +25 -0
- package/dist/web/ui/badge.d.ts +9 -0
- package/dist/web/ui/badge.js +26 -0
- package/dist/web/ui/breadcrumb.d.ts +11 -0
- package/dist/web/ui/breadcrumb.js +29 -0
- package/dist/web/ui/button.d.ts +10 -0
- package/dist/web/ui/button.js +37 -0
- package/dist/web/ui/checkbox.d.ts +4 -0
- package/dist/web/ui/checkbox.js +11 -0
- package/dist/web/ui/input.d.ts +3 -0
- package/dist/web/ui/input.js +8 -0
- package/dist/web/ui/label.d.ts +4 -0
- package/dist/web/ui/label.js +10 -0
- package/dist/web/ui/resizable.d.ts +7 -0
- package/dist/web/ui/resizable.js +16 -0
- package/dist/web/ui/separator.d.ts +4 -0
- package/dist/web/ui/separator.js +10 -0
- package/dist/web/ui/sheet.d.ts +14 -0
- package/dist/web/ui/sheet.js +42 -0
- package/dist/web/ui/sidebar.d.ts +73 -0
- package/dist/web/ui/sidebar.js +211 -0
- package/dist/web/ui/skeleton.d.ts +2 -0
- package/dist/web/ui/skeleton.js +7 -0
- package/dist/web/ui/switch.d.ts +6 -0
- package/dist/web/ui/switch.js +10 -0
- package/dist/web/ui/table.d.ts +10 -0
- package/dist/web/ui/table.js +30 -0
- package/dist/web/ui/tabs.d.ts +11 -0
- package/dist/web/ui/tabs.js +31 -0
- package/dist/web/ui/textarea.d.ts +3 -0
- package/dist/web/ui/textarea.js +8 -0
- package/dist/web/ui/tooltip.d.ts +7 -0
- package/dist/web/ui/tooltip.js +19 -0
- package/dist/web/ui/use-mobile.d.ts +1 -0
- package/dist/web/ui/use-mobile.js +16 -0
- package/dist/web/version/update-checker.d.ts +9 -0
- package/dist/web/version/update-checker.js +88 -0
- package/dist/web/widgets/ai-text-field.d.ts +36 -0
- package/dist/web/widgets/ai-text-field.js +137 -0
- package/dist/web/widgets/chart-window.d.ts +58 -0
- package/dist/web/widgets/chart-window.js +190 -0
- package/dist/web/widgets/charts.d.ts +208 -0
- package/dist/web/widgets/charts.js +685 -0
- package/dist/web/widgets/collapsible-section.d.ts +10 -0
- package/dist/web/widgets/collapsible-section.js +17 -0
- package/dist/web/widgets/dashboard-list.d.ts +21 -0
- package/dist/web/widgets/dashboard-list.js +45 -0
- package/dist/web/widgets/detail-list.d.ts +15 -0
- package/dist/web/widgets/detail-list.js +8 -0
- package/dist/web/widgets/drawer.d.ts +65 -0
- package/dist/web/widgets/drawer.js +142 -0
- package/dist/web/widgets/feed-list.d.ts +13 -0
- package/dist/web/widgets/feed-list.js +9 -0
- package/dist/web/widgets/floating-panel.d.ts +30 -0
- package/dist/web/widgets/floating-panel.js +242 -0
- package/dist/web/widgets/form-fields.d.ts +93 -0
- package/dist/web/widgets/form-fields.js +50 -0
- package/dist/web/widgets/index.d.ts +27 -0
- package/dist/web/widgets/index.js +30 -0
- package/dist/web/widgets/infinity-list.d.ts +46 -0
- package/dist/web/widgets/infinity-list.js +211 -0
- package/dist/web/widgets/mode-switch.d.ts +21 -0
- package/dist/web/widgets/mode-switch.js +25 -0
- package/dist/web/widgets/photo-slots.d.ts +29 -0
- package/dist/web/widgets/photo-slots.js +52 -0
- package/dist/web/widgets/plan-card.d.ts +36 -0
- package/dist/web/widgets/plan-card.js +13 -0
- package/dist/web/widgets/progress-bar.d.ts +19 -0
- package/dist/web/widgets/progress-bar.js +24 -0
- package/dist/web/widgets/progress-list.d.ts +19 -0
- package/dist/web/widgets/progress-list.js +11 -0
- package/dist/web/widgets/public-shell.d.ts +22 -0
- package/dist/web/widgets/public-shell.js +15 -0
- package/dist/web/widgets/query-table.d.ts +29 -0
- package/dist/web/widgets/query-table.js +30 -0
- package/dist/web/widgets/result-panel.d.ts +69 -0
- package/dist/web/widgets/result-panel.js +30 -0
- package/dist/web/widgets/section-card.d.ts +12 -0
- package/dist/web/widgets/section-card.js +9 -0
- package/dist/web/widgets/sheet-parts.d.ts +9 -0
- package/dist/web/widgets/sheet-parts.js +11 -0
- package/dist/web/widgets/side-by-side-table.d.ts +31 -0
- package/dist/web/widgets/side-by-side-table.js +11 -0
- package/dist/web/widgets/stat.d.ts +54 -0
- package/dist/web/widgets/stat.js +65 -0
- package/dist/web/widgets/states.d.ts +23 -0
- package/dist/web/widgets/states.js +20 -0
- package/dist/web/widgets/status-badge.d.ts +15 -0
- package/dist/web/widgets/status-badge.js +24 -0
- package/dist/web/widgets/step-bar.d.ts +35 -0
- package/dist/web/widgets/step-bar.js +60 -0
- package/dist/web/widgets/upload-zone.d.ts +24 -0
- package/dist/web/widgets/upload-zone.js +108 -0
- package/dist/web/widgets/use-draft.d.ts +20 -0
- package/dist/web/widgets/use-draft.js +21 -0
- package/dist/web/widgets/use-pointer-drag.d.ts +21 -0
- package/dist/web/widgets/use-pointer-drag.js +53 -0
- package/package.json +105 -7
- package/src/changes.json +77 -0
- package/src/web/fonts/OFL.txt +93 -0
- package/src/web/fonts/ibm-plex-mono-latin-400.woff2 +0 -0
- package/src/web/fonts/ibm-plex-mono-latin-500.woff2 +0 -0
- package/src/web/fonts/ibm-plex-mono-latin-ext-400.woff2 +0 -0
- package/src/web/fonts/ibm-plex-mono-latin-ext-500.woff2 +0 -0
- package/src/web/fonts/ibm-plex-sans-latin-400.woff2 +0 -0
- package/src/web/fonts/ibm-plex-sans-latin-500.woff2 +0 -0
- package/src/web/fonts/ibm-plex-sans-latin-600.woff2 +0 -0
- package/src/web/fonts/ibm-plex-sans-latin-ext-400.woff2 +0 -0
- package/src/web/fonts/ibm-plex-sans-latin-ext-500.woff2 +0 -0
- package/src/web/fonts/ibm-plex-sans-latin-ext-600.woff2 +0 -0
- package/src/web/styles.css +401 -0
|
@@ -0,0 +1,498 @@
|
|
|
1
|
+
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
2
|
+
import { isOpenToAllGranted } from "@cosmicdrift/kumiko-framework/ui-types";
|
|
3
|
+
import { createContext, useContext, useEffect, useMemo, useRef, useState, } from "react";
|
|
4
|
+
import { createRoot } from "react-dom/client";
|
|
5
|
+
import { AppFeaturesProvider, ClientActionsProvider, ColumnRenderersProvider, ContentEditorsProvider, CustomScreensProvider, createSessionEndedSignal, DashboardBodyProvider, DispatcherProvider, DraftStorageProvider, ErrorBoundary, ExtensionSectionsProvider, hasDetailScreen, KumikoScreen, kumikoDefaultTranslations, LiveEventsProvider, LocaleProvider, mergeTranslations, NavProvider, navigateWithReturnTo, PrimitivesProvider, qualifyScreenId, ScreenMissingState, SessionEndedSignalProvider, TokensProvider, toAppSchema, translationsByLocaleFromKeys, useNav, usePrimitives, useTranslation, withSessionEndedDetection, } from "../../index.js";
|
|
6
|
+
import { createLiveDispatcher } from "../../live/index.js";
|
|
7
|
+
import { lastSegment } from "../layout/nav-tree.js";
|
|
8
|
+
import { defaultPrimitives, ScreenWidthProvider } from "../primitives/index.js";
|
|
9
|
+
import { ToastProvider } from "../primitives/toast.js";
|
|
10
|
+
import { createEventSourceLiveEvents } from "../sse/live-events.js";
|
|
11
|
+
import { useBrowserTokensApi } from "../tokens.js";
|
|
12
|
+
import { UpdateChecker } from "../version/update-checker.js";
|
|
13
|
+
import { AppSchemaFetchBoot } from "./app-schema-boot.js";
|
|
14
|
+
import { createBrowserLocaleResolver } from "./browser-locale.js";
|
|
15
|
+
import { stackWrappers } from "./client-plugin.js";
|
|
16
|
+
import { WebDashboardBody } from "./dashboard-body.js";
|
|
17
|
+
import { DocumentLangSync } from "./document-lang-sync.js";
|
|
18
|
+
import { createBrowserDraftStorage } from "./draft-storage.js";
|
|
19
|
+
import { useBrowserNavApi } from "./nav.js";
|
|
20
|
+
import { NavProvidersProvider } from "./nav-providers-context.js";
|
|
21
|
+
import { ResolversProvider } from "./resolvers-context.js";
|
|
22
|
+
import { RootErrorFallback } from "./root-error-fallback.js";
|
|
23
|
+
import { ScreenErrorFallback } from "./screen-error-fallback.js";
|
|
24
|
+
import { ToastActionNotifier } from "./toast-action-notifier.js";
|
|
25
|
+
const EMPTY_FEATURES = [];
|
|
26
|
+
const EMPTY_COLLECTIONS = [];
|
|
27
|
+
// Qualifiziert den Key eines navProviders auf seine Nav-QN. Lokale ids
|
|
28
|
+
// (z.B. "content") werden wie in r.nav mit dem Feature-Namen qualifiziert;
|
|
29
|
+
// bereits qualifizierte QNs (App registriert die Nav für ein bundled-feature
|
|
30
|
+
// und gibt die QN als navId rein, z.B. "publicstatus:nav:content") gehen
|
|
31
|
+
// unverändert durch. MUSS konsistent zu qualifyNavId bleiben, sonst findet
|
|
32
|
+
// der NavTree-Knoten (Schema-Seite) seinen Provider nicht.
|
|
33
|
+
export function qualifyNavProviderKey(feature, id) {
|
|
34
|
+
return id.includes(":nav:") ? id : `${feature}:nav:${id}`;
|
|
35
|
+
}
|
|
36
|
+
// Nav-Provider-Map: ein navProvider hängt dynamische Children an einen
|
|
37
|
+
// konkreten r.nav({provider:true})-Knoten (per QN). Lokale nav-ids werden wie
|
|
38
|
+
// in r.nav mit dem Feature-Namen qualifiziert; bereits qualifizierte QNs
|
|
39
|
+
// (cross-feature, z.B. App registriert Nav für ein bundled-feature) gehen
|
|
40
|
+
// unverändert durch.
|
|
41
|
+
//
|
|
42
|
+
// Schema-derived providers (r.contentCollection) run first and hold the weaker
|
|
43
|
+
// claim on a QN — an explicitly registered navProvider overrides them without
|
|
44
|
+
// comment. Only two EXPLICIT registrations on the same QN are the conflict
|
|
45
|
+
// that deserves the warning.
|
|
46
|
+
export function buildNavProviderMaps(clientFeatures, collections) {
|
|
47
|
+
const navProviders = new Map();
|
|
48
|
+
const navEntities = new Map();
|
|
49
|
+
const derivedQns = new Set();
|
|
50
|
+
for (const f of clientFeatures) {
|
|
51
|
+
if (f.navProvidersFromCollections === undefined)
|
|
52
|
+
continue;
|
|
53
|
+
const derived = f.navProvidersFromCollections(collections);
|
|
54
|
+
for (const [qn, provider] of Object.entries(derived.providers)) {
|
|
55
|
+
navProviders.set(qn, provider);
|
|
56
|
+
derivedQns.add(qn);
|
|
57
|
+
}
|
|
58
|
+
for (const [qn, entities] of Object.entries(derived.entities ?? {})) {
|
|
59
|
+
if (entities.length > 0)
|
|
60
|
+
navEntities.set(qn, entities);
|
|
61
|
+
}
|
|
62
|
+
}
|
|
63
|
+
for (const f of clientFeatures) {
|
|
64
|
+
for (const [navId, provider] of Object.entries(f.navProviders ?? {})) {
|
|
65
|
+
const qn = qualifyNavProviderKey(f.name, navId);
|
|
66
|
+
if (navProviders.has(qn) && !derivedQns.delete(qn)) {
|
|
67
|
+
// biome-ignore lint/suspicious/noConsole: dev warning for schema conflicts
|
|
68
|
+
console.warn(`[kumiko] navProvider for "${qn}" defined by multiple clientFeatures — last wins.`);
|
|
69
|
+
}
|
|
70
|
+
navProviders.set(qn, provider);
|
|
71
|
+
}
|
|
72
|
+
for (const [navId, entities] of Object.entries(f.navEntities ?? {})) {
|
|
73
|
+
if (entities.length > 0)
|
|
74
|
+
navEntities.set(qualifyNavProviderKey(f.name, navId), entities);
|
|
75
|
+
}
|
|
76
|
+
}
|
|
77
|
+
return { navProviders, navEntities };
|
|
78
|
+
}
|
|
79
|
+
const BoundaryErrorHandlerContext = createContext(undefined);
|
|
80
|
+
// Reads a schema an app baked into the page itself (e.g. an e2e fixture) —
|
|
81
|
+
// nothing in this repo sets this global anymore now that HTML never carries
|
|
82
|
+
// an injected schema. Guarded for SSR/node even though this only runs in
|
|
83
|
+
// the browser today; harmless under jsdom either way.
|
|
84
|
+
function readInjectedSchema() {
|
|
85
|
+
if (typeof window === "undefined")
|
|
86
|
+
return undefined;
|
|
87
|
+
const w = window;
|
|
88
|
+
return w.__KUMIKO_SCHEMA__;
|
|
89
|
+
}
|
|
90
|
+
// Nav reachability is required, otherwise a dormant `type: "custom"`
|
|
91
|
+
// screen a feature only registers for manual app-side placement (e.g.
|
|
92
|
+
// auth-mfa's enable screen) can win by declaration order alone, landing
|
|
93
|
+
// every app without an explicit `screenQn` on a screen nobody wired a
|
|
94
|
+
// component for (#1258).
|
|
95
|
+
function firstNavReachableScreenQn(features, acceptsScreen) {
|
|
96
|
+
// NavDefinition.screen carries two shapes in practice: most bundled
|
|
97
|
+
// features author it pre-qualified ("tenant:screen:members"), but the
|
|
98
|
+
// config settings-hub generator emits the bare short id. Index both
|
|
99
|
+
// forms so nav-reachability doesn't depend on which convention a given
|
|
100
|
+
// feature happens to use.
|
|
101
|
+
const navScreenQns = new Set();
|
|
102
|
+
for (const f of features) {
|
|
103
|
+
for (const n of f.navs ?? []) {
|
|
104
|
+
if (n.screen === undefined)
|
|
105
|
+
continue;
|
|
106
|
+
navScreenQns.add(n.screen);
|
|
107
|
+
navScreenQns.add(qualifyScreenId(f.featureName, n.screen));
|
|
108
|
+
}
|
|
109
|
+
}
|
|
110
|
+
for (const feature of features) {
|
|
111
|
+
const screen = feature.screens.find((s) => acceptsScreen(s) && navScreenQns.has(qualifyScreenId(feature.featureName, s.id)));
|
|
112
|
+
if (screen !== undefined)
|
|
113
|
+
return qualifyScreenId(feature.featureName, screen.id);
|
|
114
|
+
}
|
|
115
|
+
return undefined;
|
|
116
|
+
}
|
|
117
|
+
// Only screens whose `access` excludes nobody: on an unprojected schema the
|
|
118
|
+
// landing is picked without knowing the user's roles, so a role-restricted
|
|
119
|
+
// screen would land every non-admin on access-denied (#1176).
|
|
120
|
+
export function firstOpenScreenQn(features) {
|
|
121
|
+
return firstNavReachableScreenQn(features, (s) => s.access === undefined || isOpenToAllGranted(s.access));
|
|
122
|
+
}
|
|
123
|
+
// Landing fallback for a schema that arrived already role-projected by the
|
|
124
|
+
// server (fetch mode, GET /api/schema strips screens the caller's roles
|
|
125
|
+
// can't see) — a pure SystemAdmin whose only screens are role-restricted
|
|
126
|
+
// must still get a landing instead of the "no-open-screen" banner.
|
|
127
|
+
// Regular users keep today's
|
|
128
|
+
// firstOpenScreenQn landing; only when that yields nothing do we fall back
|
|
129
|
+
// to any nav-reachable screen, since the projection already removed
|
|
130
|
+
// everything the caller's roles may not see.
|
|
131
|
+
export function firstLandingScreenQnForProjectedSchema(features) {
|
|
132
|
+
return firstOpenScreenQn(features) ?? firstNavReachableScreenQn(features, () => true);
|
|
133
|
+
}
|
|
134
|
+
// The server's role projection may strip an explicitly configured screenQn
|
|
135
|
+
// for this caller's roles; the root route then falls back to the first
|
|
136
|
+
// reachable landing instead of "Screen not found". An unprojected schema
|
|
137
|
+
// keeps the explicit screen as configured.
|
|
138
|
+
export function resolveRootScreenQn(features, explicitScreenQn, schemaIsRoleProjected) {
|
|
139
|
+
if (explicitScreenQn === undefined) {
|
|
140
|
+
return schemaIsRoleProjected
|
|
141
|
+
? firstLandingScreenQnForProjectedSchema(features)
|
|
142
|
+
: firstOpenScreenQn(features);
|
|
143
|
+
}
|
|
144
|
+
if (!schemaIsRoleProjected)
|
|
145
|
+
return explicitScreenQn;
|
|
146
|
+
if (findOwnerFeature(features, explicitScreenQn) !== undefined)
|
|
147
|
+
return explicitScreenQn;
|
|
148
|
+
return firstLandingScreenQnForProjectedSchema(features);
|
|
149
|
+
}
|
|
150
|
+
// Last-wins merge for a clientFeature-contributed map (contentEditors,
|
|
151
|
+
// columnRenderers, extensionSectionComponents, ...): later features in
|
|
152
|
+
// `clientFeatures` override earlier ones on key collision, logging once
|
|
153
|
+
// per collision so an accidental override isn't silent.
|
|
154
|
+
function mergeByKey(clientFeatures, pick, label) {
|
|
155
|
+
const merged = {};
|
|
156
|
+
for (const f of clientFeatures) {
|
|
157
|
+
const entries = pick(f);
|
|
158
|
+
if (entries === undefined)
|
|
159
|
+
continue;
|
|
160
|
+
for (const [key, value] of Object.entries(entries)) {
|
|
161
|
+
if (merged[key] !== undefined) {
|
|
162
|
+
// biome-ignore lint/suspicious/noConsole: dev warning for schema conflicts
|
|
163
|
+
console.warn(`[kumiko] ${label} "${key}" defined by multiple clientFeatures — last definition (from "${f.name}") wins.`);
|
|
164
|
+
}
|
|
165
|
+
merged[key] = value;
|
|
166
|
+
}
|
|
167
|
+
}
|
|
168
|
+
return merged;
|
|
169
|
+
}
|
|
170
|
+
// Merges the content-editor map — same last-wins semantics as
|
|
171
|
+
// columnRenderers. No entry for a contentFormat → useContentEditor falls
|
|
172
|
+
// back to the textarea on its own, no warning needed.
|
|
173
|
+
export function mergeContentEditors(clientFeatures) {
|
|
174
|
+
return mergeByKey(clientFeatures, (f) => f.contentEditors, "contentEditor");
|
|
175
|
+
}
|
|
176
|
+
// Fail loud at boot instead of per-URL: a mounted server feature can
|
|
177
|
+
// declare a `type: "custom"` screen that's reachable directly by URL
|
|
178
|
+
// even without nav placement — without this check, a missing client
|
|
179
|
+
// plugin only surfaces as an error placeholder to whoever happens to
|
|
180
|
+
// open that URL (kumiko-framework#2025). Screens flagged `dormant`
|
|
181
|
+
// (e.g. user-data-rights privacy-center, auth-mfa's enable screen) are
|
|
182
|
+
// registered without a self-owned r.nav on purpose — an app opts in by
|
|
183
|
+
// navving them explicitly, so a consumer that hasn't done that yet isn't
|
|
184
|
+
// missing anything (kumiko-framework#2034). Still dev-only: several
|
|
185
|
+
// bundled screens that ARE self-navved (e.g. compliance-profiles'
|
|
186
|
+
// profile-picker) have real unmounted-client-plugin bugs in existing
|
|
187
|
+
// consumer apps today (kumiko-framework#2025) — running this in
|
|
188
|
+
// production before those are fixed (tracked via infra#503) would just
|
|
189
|
+
// spam every affected app's console.
|
|
190
|
+
function warnMissingCustomScreens(app, customScreens) {
|
|
191
|
+
if (typeof process === "undefined" || process.env.NODE_ENV === "production")
|
|
192
|
+
return;
|
|
193
|
+
const missingCustomScreens = app.features.flatMap((f) => f.screens
|
|
194
|
+
.filter((s) => s.type === "custom" && s.dormant !== true && customScreens[s.id] === undefined)
|
|
195
|
+
.map((s) => `${f.featureName}:${s.id}`));
|
|
196
|
+
if (missingCustomScreens.length > 0) {
|
|
197
|
+
// biome-ignore lint/suspicious/noConsole: dev-only diagnostic for missing client plugins
|
|
198
|
+
console.error(`[kumiko] ${missingCustomScreens.length} custom screen(s) have no registered component in clientFeatures.components — they render an error placeholder instead of the intended UI: ${missingCustomScreens.join(", ")}. Add the feature's web client plugin to clientFeatures.`);
|
|
199
|
+
}
|
|
200
|
+
}
|
|
201
|
+
// Everything schema-INdependent (dispatcher, providers, gates, merged
|
|
202
|
+
// component maps, ...) is built once in createKumikoApp and passed in as
|
|
203
|
+
// props; only the schema-dependent slice (fallbackBundles, nav-provider
|
|
204
|
+
// derivation, the actual screen tree) lives in this component's own state
|
|
205
|
+
// so a schema arriving later (the fetch path) doesn't need a second copy
|
|
206
|
+
// of the provider tree.
|
|
207
|
+
function KumikoAppRoot(props) {
|
|
208
|
+
const [app, setApp] = useState(props.initialApp);
|
|
209
|
+
// Precedence in fallbackBundles (array order = priority, highest first):
|
|
210
|
+
// 1. clientFeatures.translations — app overrides always win, even
|
|
211
|
+
// against the framework's own labels.
|
|
212
|
+
// 2. schemaTranslations — server-authored r.translations, projected
|
|
213
|
+
// verbatim by buildAppSchema (#1059). Without this bundle, nav/
|
|
214
|
+
// screen labels only resolve if an app ALSO duplicates them in its
|
|
215
|
+
// own web/i18n.ts — most bundled features never did, labels then
|
|
216
|
+
// render as raw i18n keys.
|
|
217
|
+
// 3. kumikoDefaultTranslations — framework defaults, the very last
|
|
218
|
+
// fallback.
|
|
219
|
+
// biome-ignore lint/correctness/useExhaustiveDependencies: props.clientFeatures is stable for the app instance's lifetime (built once in createKumikoApp)
|
|
220
|
+
const { fallbackBundles, navProviders, navEntities } = useMemo(() => {
|
|
221
|
+
const schemaTranslations = (app?.features ?? EMPTY_FEATURES).reduce((acc, f) => f.translations ? mergeTranslations(acc, translationsByLocaleFromKeys(f.translations)) : acc, {});
|
|
222
|
+
const bundles = [
|
|
223
|
+
...props.clientFeatures.flatMap((f) => f.translations !== undefined ? [f.translations] : []),
|
|
224
|
+
schemaTranslations,
|
|
225
|
+
kumikoDefaultTranslations,
|
|
226
|
+
];
|
|
227
|
+
const { navProviders: providersByQn, navEntities: entitiesByQn } = buildNavProviderMaps(props.clientFeatures, app?.features.flatMap((f) => f.contentCollections ?? []) ?? EMPTY_COLLECTIONS);
|
|
228
|
+
return { fallbackBundles: bundles, navProviders: providersByQn, navEntities: entitiesByQn };
|
|
229
|
+
}, [app]);
|
|
230
|
+
// Sync path (initialApp given at construction) never resets — that
|
|
231
|
+
// schema was handed in explicitly and stays valid for the app's
|
|
232
|
+
// lifetime. Fetch path resets to undefined on unmount so a future
|
|
233
|
+
// role-aware schema projection never lets a re-login reuse a
|
|
234
|
+
// previous user's cached app.
|
|
235
|
+
const isFetchMode = props.initialApp === undefined;
|
|
236
|
+
const screenNode = (_jsx(AppSchemaBoundary, { app: app, screenQn: props.screenQn, ...(props.schemaUrl !== undefined && { schemaUrl: props.schemaUrl }), navAdapter: props.navAdapter, onAppLoaded: (loaded) => {
|
|
237
|
+
warnMissingCustomScreens(loaded, props.customScreens);
|
|
238
|
+
setApp(loaded);
|
|
239
|
+
}, schemaIsRoleProjected: isFetchMode, ...(isFetchMode && { onUnmountResetSchema: () => setApp(undefined) }), ...(props.translate !== undefined && { translate: props.translate }), ...(props.onRowClick !== undefined && { onRowClick: props.onRowClick }), ...(props.shell !== undefined && { shell: props.shell }) }));
|
|
240
|
+
return (_jsx(TokensBoot, { children: _jsxs(LocaleProvider, { resolver: props.localeResolver, fallbackBundles: fallbackBundles, children: [_jsx(DocumentLangSync, { resolver: props.localeResolver }), _jsx(PrimitivesProvider, { value: props.primitives, children: _jsx(ScreenWidthProvider, { width: props.screenWidth, children: _jsx(AppFeaturesProvider, { features: app?.features ?? EMPTY_FEATURES, children: _jsx(DispatcherProvider, { dispatcher: props.dispatcher, children: _jsx(DraftStorageProvider, { value: props.draftStorage, children: _jsx(LiveEventsProvider, { value: props.liveEvents, children: _jsx(DashboardBodyProvider, { value: WebDashboardBody, children: _jsx(CustomScreensProvider, { value: props.customScreens, children: _jsx(ColumnRenderersProvider, { value: props.columnRenderers, children: _jsx(ContentEditorsProvider, { value: props.contentEditors, children: _jsx(ExtensionSectionsProvider, { value: props.extensionSectionComponents, children: _jsx(ClientActionsProvider, { value: props.clientActions, children: _jsx(NavProvidersProvider, { value: navProviders, entities: navEntities, children: _jsx(ResolversProvider, { resolvers: props.resolvers, children: _jsx(ToastProvider, { children: _jsxs(ToastActionNotifier, { children: [_jsx(UpdateChecker, {}), _jsx(SessionEndedSignalProvider, { signal: props.sessionEndedSignal, children: stackWrappers(props.providers, stackWrappers(props.gates, screenNode)) })] }) }) }) }) }) }) }) }) }) }) }) }) }) }) }) })] }) }));
|
|
241
|
+
}
|
|
242
|
+
// Sits INSIDE the clientFeature gates (e.g. an auth gate) — a gate that
|
|
243
|
+
// renders a login placeholder instead of children keeps this component
|
|
244
|
+
// (and its schema fetch) from ever mounting until the user is signed in.
|
|
245
|
+
function AppSchemaBoundary({ app, screenQn, schemaUrl, navAdapter, onAppLoaded, schemaIsRoleProjected, onUnmountResetSchema, translate, onRowClick, shell, }) {
|
|
246
|
+
// Called unconditionally regardless of which branch below actually
|
|
247
|
+
// renders — this component's identity persists across the "no app yet"
|
|
248
|
+
// → "app loaded" transition, so its hooks must run in the same order on
|
|
249
|
+
// every render (Rules of Hooks).
|
|
250
|
+
const t = useTranslation();
|
|
251
|
+
const { Banner } = usePrimitives();
|
|
252
|
+
// Ref, not an effect dependency: onUnmountResetSchema closes over
|
|
253
|
+
// KumikoAppRoot's setApp and would otherwise force this effect to
|
|
254
|
+
// re-run (and re-fire its cleanup) on every render.
|
|
255
|
+
const onUnmountResetSchemaRef = useRef(onUnmountResetSchema);
|
|
256
|
+
onUnmountResetSchemaRef.current = onUnmountResetSchema;
|
|
257
|
+
// A real unmount (the gate withdrawing children, e.g. on logout) resets
|
|
258
|
+
// the schema so the next mount re-fetches instead of reusing this
|
|
259
|
+
// session's — fetch-mode only, see isFetchMode in KumikoAppRoot.
|
|
260
|
+
useEffect(() => {
|
|
261
|
+
return () => onUnmountResetSchemaRef.current?.();
|
|
262
|
+
}, []);
|
|
263
|
+
if (app === undefined) {
|
|
264
|
+
return (_jsx(AppSchemaFetchBoot, { onLoaded: onAppLoaded, ...(schemaUrl !== undefined && { schemaUrl }) }));
|
|
265
|
+
}
|
|
266
|
+
const fallbackQn = resolveRootScreenQn(app.features, screenQn, schemaIsRoleProjected);
|
|
267
|
+
if (fallbackQn === undefined) {
|
|
268
|
+
return (_jsx(Banner, { variant: "error", padded: true, children: t("kumiko.app-boot.no-open-screen") }));
|
|
269
|
+
}
|
|
270
|
+
return (_jsx(BrowserNavBoot, { app: app, fallbackQn: fallbackQn, useNavApi: navAdapter, hasWorkspaces: (app.workspaces?.length ?? 0) > 0, ...(translate !== undefined && { translate }), ...(onRowClick !== undefined && { onRowClick }), ...(shell !== undefined && { shell }) }));
|
|
271
|
+
}
|
|
272
|
+
export function createKumikoApp(options = {}) {
|
|
273
|
+
const rootId = options.rootId ?? "root";
|
|
274
|
+
const container = document.getElementById(rootId);
|
|
275
|
+
if (!container) {
|
|
276
|
+
throw new Error(`createKumikoApp: DOM element #${rootId} not found. Make sure your HTML has a matching <div id="${rootId}"></div> before the bundle loads.`);
|
|
277
|
+
}
|
|
278
|
+
// toAppSchema normalizes the FeatureSchema/AppSchema union — from here on
|
|
279
|
+
// every layout only ever sees AppSchema. No schema resolved yet (neither
|
|
280
|
+
// options.schema nor window.__KUMIKO_SCHEMA__) is no longer an error here:
|
|
281
|
+
// KumikoAppRoot/AppSchemaBoundary fetch it from GET /api/schema instead.
|
|
282
|
+
const rawSchema = options.schema ?? readInjectedSchema();
|
|
283
|
+
let initialApp;
|
|
284
|
+
if (rawSchema !== undefined) {
|
|
285
|
+
initialApp = toAppSchema(rawSchema);
|
|
286
|
+
const fallbackQn = options.screenQn ?? firstOpenScreenQn(initialApp.features);
|
|
287
|
+
if (!fallbackQn) {
|
|
288
|
+
throw new Error("createKumikoApp: schema contains no screens accessible without a role restriction. Add at least one entry to `schema.screens` without `access.roles`, or pass `screenQn` explicitly.");
|
|
289
|
+
}
|
|
290
|
+
}
|
|
291
|
+
const sessionEndedSignal = createSessionEndedSignal();
|
|
292
|
+
const dispatcher = withSessionEndedDetection(options.dispatcher ?? createLiveDispatcher(), sessionEndedSignal);
|
|
293
|
+
const draftStorage = options.draftStorage ?? createBrowserDraftStorage();
|
|
294
|
+
const primitives = { ...defaultPrimitives, ...(options.primitives ?? {}) };
|
|
295
|
+
const liveEvents = createEventSourceLiveEvents({
|
|
296
|
+
onSessionEnded: () => sessionEndedSignal.notify(),
|
|
297
|
+
});
|
|
298
|
+
// Feature plugins: providers stack outermost (every gate + screen sees
|
|
299
|
+
// every provider), gates stack between the renderer providers and the
|
|
300
|
+
// shell/screen. Array order: first element = outermost wrapper.
|
|
301
|
+
const clientFeatures = options.clientFeatures ?? [];
|
|
302
|
+
const providers = clientFeatures.flatMap((f) => f.providers ?? []);
|
|
303
|
+
const gates = clientFeatures.flatMap((f) => f.gates ?? []);
|
|
304
|
+
// Custom-screen component map merge: later features override earlier ones
|
|
305
|
+
// on screenId collision (last-wins). Lets an app override a bundled
|
|
306
|
+
// feature's screen with a local component.
|
|
307
|
+
const customScreens = {};
|
|
308
|
+
for (const f of clientFeatures) {
|
|
309
|
+
if (f.components !== undefined)
|
|
310
|
+
Object.assign(customScreens, f.components);
|
|
311
|
+
}
|
|
312
|
+
if (initialApp !== undefined)
|
|
313
|
+
warnMissingCustomScreens(initialApp, customScreens);
|
|
314
|
+
// Column-renderer map, same last-wins semantics as customScreens —
|
|
315
|
+
// duplicate keys across features are rarely intentional, so a
|
|
316
|
+
// collision logs once instead of silently overriding a library's
|
|
317
|
+
// renderer.
|
|
318
|
+
const columnRenderers = mergeByKey(clientFeatures, (f) => f.columnRenderers, "columnRenderer");
|
|
319
|
+
// Extension-section components — same last-wins + warn semantics as
|
|
320
|
+
// columnRenderers. Mounted on ExtensionSectionsProvider; RenderEdit
|
|
321
|
+
// resolves the component from the section's `__component` marker.
|
|
322
|
+
const extensionSectionComponents = mergeByKey(clientFeatures, (f) => f.extensionSectionComponents, "extensionSectionComponent");
|
|
323
|
+
const clientActions = mergeByKey(clientFeatures, (f) => f.clientActions, "clientAction");
|
|
324
|
+
const contentEditors = mergeContentEditors(clientFeatures);
|
|
325
|
+
// Aggregate editor resolvers — keyed by "featureId:action". Same
|
|
326
|
+
// last-wins semantics as columnRenderers. Warns on collision.
|
|
327
|
+
const resolvers = new Map();
|
|
328
|
+
for (const f of clientFeatures) {
|
|
329
|
+
if (f.resolvers === undefined)
|
|
330
|
+
continue;
|
|
331
|
+
for (const [key, component] of Object.entries(f.resolvers)) {
|
|
332
|
+
if (resolvers.has(key)) {
|
|
333
|
+
// biome-ignore lint/suspicious/noConsole: client-bundle has no logger; collision is a dev-time warning that must surface in the browser DevTools.
|
|
334
|
+
console.warn(`[kumiko] resolver "${key}" defined by multiple clientFeatures — last definition (from "${f.name}") wins.`);
|
|
335
|
+
}
|
|
336
|
+
resolvers.set(key, component);
|
|
337
|
+
}
|
|
338
|
+
}
|
|
339
|
+
const localeResolver = options.locale ?? createBrowserLocaleResolver();
|
|
340
|
+
const navAdapter = options.navAdapter ?? useBrowserNavApi;
|
|
341
|
+
const root = createRoot(container);
|
|
342
|
+
root.render(_jsx(ErrorBoundary, { scope: "root", ...(options.onError !== undefined && { onError: options.onError }), fallback: () => _jsx(RootErrorFallback, {}), children: _jsx(BoundaryErrorHandlerContext.Provider, { value: options.onError, children: _jsx(KumikoAppRoot, { initialApp: initialApp, screenQn: options.screenQn, ...(options.schemaUrl !== undefined && { schemaUrl: options.schemaUrl }), clientFeatures: clientFeatures, providers: providers, gates: gates, customScreens: customScreens, columnRenderers: columnRenderers, extensionSectionComponents: extensionSectionComponents, clientActions: clientActions, contentEditors: contentEditors, resolvers: resolvers, dispatcher: dispatcher, sessionEndedSignal: sessionEndedSignal, draftStorage: draftStorage, primitives: primitives, liveEvents: liveEvents, localeResolver: localeResolver, navAdapter: navAdapter, screenWidth: options.screenWidth, ...(options.translate !== undefined && { translate: options.translate }), ...(options.onRowClick !== undefined && { onRowClick: options.onRowClick }), ...(options.shell !== undefined && { shell: options.shell }) }) }) }));
|
|
343
|
+
return { root };
|
|
344
|
+
}
|
|
345
|
+
// TokensBoot uses the browser-backed TokensApi hook (class-based
|
|
346
|
+
// dark-toggle) and passes the value through to the shared
|
|
347
|
+
// TokensProvider. No own state — the class on <html> is the
|
|
348
|
+
// SSoT, useSyncExternalStore in the hook syncs that into React.
|
|
349
|
+
function TokensBoot({ children }) {
|
|
350
|
+
const api = useBrowserTokensApi();
|
|
351
|
+
return _jsx(TokensProvider, { value: api, children: children });
|
|
352
|
+
}
|
|
353
|
+
function BrowserNavBoot({ app, fallbackQn, useNavApi, hasWorkspaces, translate, onRowClick, shell, }) {
|
|
354
|
+
const navApi = useNavApi({ hasWorkspaces, features: app.features });
|
|
355
|
+
const Shell = shell;
|
|
356
|
+
const screen = (_jsx(RoutedScreen, { app: app, fallbackQn: fallbackQn, ...(translate !== undefined && { translate }), ...(onRowClick !== undefined && { onRowClick }) }));
|
|
357
|
+
return (_jsx(NavProvider, { value: navApi, children: Shell !== undefined ? _jsx(Shell, { schema: app, children: screen }) : screen }));
|
|
358
|
+
}
|
|
359
|
+
// Finds the feature that owns a fully qualified ScreenQn.
|
|
360
|
+
// Returns undefined if the screen isn't declared in any feature schema —
|
|
361
|
+
// KumikoScreen then renders the "Screen not found" banner.
|
|
362
|
+
function findOwnerFeature(features, qn) {
|
|
363
|
+
for (const feature of features) {
|
|
364
|
+
for (const s of feature.screens) {
|
|
365
|
+
if (qualifyScreenId(feature.featureName, s.id) === qn)
|
|
366
|
+
return feature;
|
|
367
|
+
}
|
|
368
|
+
}
|
|
369
|
+
return undefined;
|
|
370
|
+
}
|
|
371
|
+
// Single source for "which entityEdit screen does a row click land on", shared
|
|
372
|
+
// by the click handler and hasRowClickTarget so a row never looks clickable
|
|
373
|
+
// without a target (or the reverse).
|
|
374
|
+
function findEditScreenForEntity(features, entityName) {
|
|
375
|
+
for (const feature of features) {
|
|
376
|
+
const editScreen = feature.screens.find((s) => s.type === "entityEdit" && s.entity === entityName);
|
|
377
|
+
if (editScreen)
|
|
378
|
+
return editScreen;
|
|
379
|
+
}
|
|
380
|
+
return undefined;
|
|
381
|
+
}
|
|
382
|
+
// fw#2640: a list screen with no reachable click target (no `detailFor`
|
|
383
|
+
// screen for its entity, no app-wide onRowClick, no entityEdit screen)
|
|
384
|
+
// must render without the row-click affordance instead of a silent no-op —
|
|
385
|
+
// mirrors the precedence effectiveOnRowClick itself resolves at click time.
|
|
386
|
+
// Only entityList/projectionList screens ever render RenderList; every other
|
|
387
|
+
// screen type never wires onRowClick at all, so it can never have a target.
|
|
388
|
+
function hasRowClickTarget(app, screen, onRowClick) {
|
|
389
|
+
if (screen === undefined)
|
|
390
|
+
return false;
|
|
391
|
+
if (screen.type !== "entityList" && screen.type !== "projectionList")
|
|
392
|
+
return false;
|
|
393
|
+
if (onRowClick !== undefined)
|
|
394
|
+
return true;
|
|
395
|
+
if (screen.type !== "entityList")
|
|
396
|
+
return false;
|
|
397
|
+
if (hasDetailScreen(app.features, screen.entity))
|
|
398
|
+
return true;
|
|
399
|
+
return findEditScreenForEntity(app.features, screen.entity) !== undefined;
|
|
400
|
+
}
|
|
401
|
+
function RoutedScreen({ app, fallbackQn, translate, onRowClick, }) {
|
|
402
|
+
const nav = useNav();
|
|
403
|
+
const onBoundaryError = useContext(BoundaryErrorHandlerContext);
|
|
404
|
+
// ScreenId from the route is NOT qualified — nav.route.screenId
|
|
405
|
+
// comes from the URL path and is the short form ("order-list"). We
|
|
406
|
+
// need to pin it to the right feature. Strategy: iterate through all
|
|
407
|
+
// features until the matching screen decl turns up. No match →
|
|
408
|
+
// fallback feature (the one from fallbackQn).
|
|
409
|
+
const { feature, qn, entityId, activeScreen } = useMemo(() => {
|
|
410
|
+
if (nav.route === undefined) {
|
|
411
|
+
const ownerFeature = findOwnerFeature(app.features, fallbackQn);
|
|
412
|
+
return {
|
|
413
|
+
feature: ownerFeature,
|
|
414
|
+
qn: fallbackQn,
|
|
415
|
+
entityId: undefined,
|
|
416
|
+
activeScreen: ownerFeature?.screens.find((s) => qualifyScreenId(ownerFeature.featureName, s.id) === fallbackQn),
|
|
417
|
+
};
|
|
418
|
+
}
|
|
419
|
+
const shortId = nav.route.screenId;
|
|
420
|
+
// Suche das Feature dessen Screens den short id enthalten.
|
|
421
|
+
let matchedFeature;
|
|
422
|
+
for (const f of app.features) {
|
|
423
|
+
if (f.screens.some((s) => s.id === shortId)) {
|
|
424
|
+
matchedFeature = f;
|
|
425
|
+
break;
|
|
426
|
+
}
|
|
427
|
+
}
|
|
428
|
+
const ownerFeature = matchedFeature ?? findOwnerFeature(app.features, fallbackQn);
|
|
429
|
+
const qualifiedQn = ownerFeature ? qualifyScreenId(ownerFeature.featureName, shortId) : shortId;
|
|
430
|
+
return {
|
|
431
|
+
feature: ownerFeature,
|
|
432
|
+
qn: qualifiedQn,
|
|
433
|
+
entityId: nav.route.entityId,
|
|
434
|
+
activeScreen: ownerFeature?.screens.find((s) => qualifyScreenId(ownerFeature.featureName, s.id) === qualifiedQn),
|
|
435
|
+
};
|
|
436
|
+
}, [nav.route, app, fallbackQn]);
|
|
437
|
+
const effectiveOnRowClick = useMemo(() => {
|
|
438
|
+
if (!hasRowClickTarget(app, activeScreen, onRowClick))
|
|
439
|
+
return undefined;
|
|
440
|
+
return (row, entityName) => {
|
|
441
|
+
// No ReturnHostProvider out here — derive the host from this memo's own qn/entityId.
|
|
442
|
+
const host = {
|
|
443
|
+
screenId: lastSegment(qn),
|
|
444
|
+
...(entityId !== undefined && { entityId }),
|
|
445
|
+
};
|
|
446
|
+
// Precedence (fw#2164): detailFor screen, then onRowClick, then the
|
|
447
|
+
// entityEdit-search fallback below. An explicit rowActions
|
|
448
|
+
// rowClick:true already wins over all of this — kumiko-screen.tsx
|
|
449
|
+
// handles it before onRowClick is ever called.
|
|
450
|
+
if (hasDetailScreen(app.features, entityName)) {
|
|
451
|
+
navigateWithReturnTo(nav, { entity: entityName, id: row.id }, host);
|
|
452
|
+
return;
|
|
453
|
+
}
|
|
454
|
+
if (onRowClick !== undefined) {
|
|
455
|
+
onRowClick(row, entityName);
|
|
456
|
+
return;
|
|
457
|
+
}
|
|
458
|
+
// No declared detail screen and no app-wide onRowClick — search for
|
|
459
|
+
// the edit screen for the entity across all features — in a
|
|
460
|
+
// single-feature setup that's the same feature as the active one, in
|
|
461
|
+
// multi-feature the edit could theoretically live in a different
|
|
462
|
+
// feature (one that shares the entity).
|
|
463
|
+
const editScreen = findEditScreenForEntity(app.features, entityName);
|
|
464
|
+
if (editScreen) {
|
|
465
|
+
// editScreen.id is already short form; lastSegment is a no-op
|
|
466
|
+
// safety net here, kept for symmetry with the other call sites.
|
|
467
|
+
navigateWithReturnTo(nav, { screenId: lastSegment(editScreen.id), entityId: row.id }, host);
|
|
468
|
+
}
|
|
469
|
+
};
|
|
470
|
+
}, [app, activeScreen, onRowClick, nav, qn, entityId]);
|
|
471
|
+
// Copy-link action (Issue #912) for entityEdit update screens. Builds
|
|
472
|
+
// the absolute permalink URL from the current route + copies it —
|
|
473
|
+
// `navigator`/`window` are allowed here (renderer/web, not a
|
|
474
|
+
// platform-neutral package). No button without entityId (create-mode).
|
|
475
|
+
// Silent-catch on clipboard error (non-secure context) mirrors the
|
|
476
|
+
// existing pattern in pat-tokens-screen.tsx.
|
|
477
|
+
const effectiveOnCopyLink = useMemo(() => {
|
|
478
|
+
const route = nav.route;
|
|
479
|
+
if (route?.entityId === undefined)
|
|
480
|
+
return undefined;
|
|
481
|
+
return async () => {
|
|
482
|
+
const url = `${window.location.origin}${nav.hrefFor(route)}`;
|
|
483
|
+
try {
|
|
484
|
+
await navigator.clipboard.writeText(url);
|
|
485
|
+
}
|
|
486
|
+
catch {
|
|
487
|
+
// clipboard blocked (non-secure context) — no fallback UI needed here
|
|
488
|
+
}
|
|
489
|
+
};
|
|
490
|
+
}, [nav]);
|
|
491
|
+
if (feature === undefined || activeScreen === undefined) {
|
|
492
|
+
const landingExists = findOwnerFeature(app.features, fallbackQn) !== undefined;
|
|
493
|
+
return (_jsx(ScreenMissingState, { ...(landingExists && { homeScreenId: lastSegment(fallbackQn) }), screenQn: qn }));
|
|
494
|
+
}
|
|
495
|
+
// KumikoScreen takes a single-feature schema: the feature owning the active screen.
|
|
496
|
+
const schemaForScreen = feature;
|
|
497
|
+
return (_jsx(ErrorBoundary, { scope: "screen", ...(onBoundaryError !== undefined && { onError: onBoundaryError }), fallback: ({ error, reset }) => (_jsx(ScreenErrorFallback, { screen: qn, error: error, onReset: reset })), children: _jsx(KumikoScreen, { schema: schemaForScreen, qn: qn, ...(translate !== undefined && { translate }), ...(entityId !== undefined && { entityId }), onRowClick: effectiveOnRowClick, ...(effectiveOnCopyLink !== undefined && { onCopyLink: effectiveOnCopyLink }) }) }, `${qn}/${entityId ?? ""}`));
|
|
498
|
+
}
|
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
import type { ReactNode } from "react";
|
|
2
|
+
import { type Root } from "react-dom/client";
|
|
3
|
+
import type { Dispatcher, LocaleResolver } from "../../headless/index.ts";
|
|
4
|
+
import { type Formality, type PrimitivesRegistry } from "../../index.ts";
|
|
5
|
+
import { type ClientFeatureDefinition } from "./client-plugin.tsx";
|
|
6
|
+
export type PublicRoute = {
|
|
7
|
+
/** Exact window.location.pathname match (matched once on mount; every
|
|
8
|
+
* apex page is a full-page reload, no SPA router). */
|
|
9
|
+
readonly path: string;
|
|
10
|
+
readonly component: ReactNode;
|
|
11
|
+
};
|
|
12
|
+
export type CreatePublicSurfaceOptions = {
|
|
13
|
+
readonly routes: readonly PublicRoute[];
|
|
14
|
+
/** Rendered when no route.path matches the current path. */
|
|
15
|
+
readonly fallback?: ReactNode;
|
|
16
|
+
readonly rootId?: string;
|
|
17
|
+
readonly locale?: LocaleResolver;
|
|
18
|
+
readonly primitives?: Partial<PrimitivesRegistry>;
|
|
19
|
+
/** Dispatcher for handler calls (e.g. an anonymous deletion request).
|
|
20
|
+
* Auth screens don't need it (fetch via auth-client), but it's there for
|
|
21
|
+
* dispatching public flows. Default: createLiveDispatcher(). */
|
|
22
|
+
readonly dispatcher?: Dispatcher;
|
|
23
|
+
/** Feature client extensions — ONLY `providers` + `translations` are
|
|
24
|
+
* stacked. `gates` are deliberately ignored: an AuthGate would lock the
|
|
25
|
+
* public surface behind login. */
|
|
26
|
+
readonly clientFeatures?: readonly ClientFeatureDefinition[];
|
|
27
|
+
/** Page chrome around the matched content (apex/marketing layout). */
|
|
28
|
+
readonly shell?: (props: {
|
|
29
|
+
readonly children: ReactNode;
|
|
30
|
+
}) => ReactNode;
|
|
31
|
+
/** Wording for every page of this surface. Default: `"informal"`. */
|
|
32
|
+
readonly formality?: Formality;
|
|
33
|
+
};
|
|
34
|
+
export declare function createPublicSurface(options: CreatePublicSurfaceOptions): {
|
|
35
|
+
readonly root: Root;
|
|
36
|
+
};
|
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
2
|
+
import { createRoot } from "react-dom/client";
|
|
3
|
+
import { DispatcherProvider, FormalityProvider, kumikoDefaultTranslations, LocaleProvider, PrimitivesProvider, } from "../../index.js";
|
|
4
|
+
import { createLiveDispatcher } from "../../live/index.js";
|
|
5
|
+
import { defaultPrimitives } from "../primitives/index.js";
|
|
6
|
+
import { ToastProvider } from "../primitives/toast.js";
|
|
7
|
+
import { createBrowserLocaleResolver } from "./browser-locale.js";
|
|
8
|
+
import { stackWrappers } from "./client-plugin.js";
|
|
9
|
+
import { DocumentLangSync } from "./document-lang-sync.js";
|
|
10
|
+
function matchRoute(options, pathname) {
|
|
11
|
+
for (const route of options.routes) {
|
|
12
|
+
if (route.path === pathname)
|
|
13
|
+
return route.component;
|
|
14
|
+
}
|
|
15
|
+
return options.fallback ?? null;
|
|
16
|
+
}
|
|
17
|
+
export function createPublicSurface(options) {
|
|
18
|
+
const rootId = options.rootId ?? "root";
|
|
19
|
+
const container = document.getElementById(rootId);
|
|
20
|
+
if (!container) {
|
|
21
|
+
throw new Error(`createPublicSurface: DOM element #${rootId} not found. Make sure your HTML has a matching <div id="${rootId}"></div> before the bundle loads.`);
|
|
22
|
+
}
|
|
23
|
+
const dispatcher = options.dispatcher ?? createLiveDispatcher();
|
|
24
|
+
const primitives = { ...defaultPrimitives, ...(options.primitives ?? {}) };
|
|
25
|
+
const localeResolver = options.locale ?? createBrowserLocaleResolver();
|
|
26
|
+
const clientFeatures = options.clientFeatures ?? [];
|
|
27
|
+
const providers = clientFeatures.flatMap((f) => f.providers ?? []);
|
|
28
|
+
const fallbackBundles = [
|
|
29
|
+
...clientFeatures.flatMap((f) => (f.translations !== undefined ? [f.translations] : [])),
|
|
30
|
+
kumikoDefaultTranslations,
|
|
31
|
+
];
|
|
32
|
+
const pathname = typeof window !== "undefined" ? window.location.pathname : "";
|
|
33
|
+
const matched = matchRoute(options, pathname);
|
|
34
|
+
const Shell = options.shell;
|
|
35
|
+
const content = Shell !== undefined ? _jsx(Shell, { children: matched }) : matched;
|
|
36
|
+
const tree = (_jsx(LocaleProvider, { resolver: localeResolver, fallbackBundles: fallbackBundles, children: _jsxs(FormalityProvider, { formality: options.formality ?? "informal", children: [_jsx(DocumentLangSync, { resolver: localeResolver }), _jsx(PrimitivesProvider, { value: primitives, children: _jsx(DispatcherProvider, { dispatcher: dispatcher, children: _jsx(ToastProvider, { children: stackWrappers(providers, content) }) }) })] }) }));
|
|
37
|
+
const root = createRoot(container);
|
|
38
|
+
root.render(tree);
|
|
39
|
+
return { root };
|
|
40
|
+
}
|