@cosmicdrift/kumiko-renderer 0.374.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 +9 -2
- package/dist/app/action-form-support.js +24 -2
- package/dist/app/client-actions.d.ts +2 -2
- 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/form-schema.d.ts +1 -1
- package/dist/app/form-schema.js +2 -2
- package/dist/app/kumiko-screen.d.ts +1 -1
- package/dist/app/kumiko-screen.js +7 -6
- package/dist/app/list-empty-content.d.ts +1 -1
- 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 +1 -1
- 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 +1 -1
- 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 +1 -1
- 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/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 +4 -2
- package/dist/components/render-field.d.ts +1 -1
- package/dist/components/render-field.js +4 -1
- 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.d.ts +1 -1
- package/dist/i18n.js +1 -1
- package/dist/index.js +4 -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 +35 -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 +53 -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,7 @@
|
|
|
1
|
+
export { CSRF_HEADER_NAME, readCsrfToken } from "./csrf.ts";
|
|
2
|
+
export type { LiveDispatcherOptions } from "./dispatcher-live.ts";
|
|
3
|
+
export { createLiveDispatcher } from "./dispatcher-live.ts";
|
|
4
|
+
export { buildAbortError, buildNetworkError, mapServerError } from "./error-mapping.ts";
|
|
5
|
+
export { LOCALE_HEADER_NAME, readActiveLocale } from "./locale.ts";
|
|
6
|
+
export type { SseFrame } from "./sse-stream.ts";
|
|
7
|
+
export { iterateSseChunks, parseSseBlock, parseSseFrames } from "./sse-stream.ts";
|
|
@@ -0,0 +1,5 @@
|
|
|
1
|
+
export { CSRF_HEADER_NAME, readCsrfToken } from "./csrf.js";
|
|
2
|
+
export { createLiveDispatcher } from "./dispatcher-live.js";
|
|
3
|
+
export { buildAbortError, buildNetworkError, mapServerError } from "./error-mapping.js";
|
|
4
|
+
export { LOCALE_HEADER_NAME, readActiveLocale } from "./locale.js";
|
|
5
|
+
export { iterateSseChunks, parseSseBlock, parseSseFrames } from "./sse-stream.js";
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
// Active-locale header transport for the live dispatcher.
|
|
2
|
+
//
|
|
3
|
+
// @cosmicdrift/kumiko-renderer/web's DocumentLangSync (mounted by
|
|
4
|
+
// createKumikoApp/createPublicSurface) sets dataset.kumikoLocale from the
|
|
5
|
+
// LocaleResolver. This module reads that marker back so every outgoing
|
|
6
|
+
// request carries the language the user is ACTUALLY using — not a static
|
|
7
|
+
// <html lang> — with zero app-side wiring.
|
|
8
|
+
import { propertyOf } from "@cosmicdrift/kumiko-types/type-guards";
|
|
9
|
+
// Kept in sync with LOCALE_HEADER_NAME in api-constants.ts by hand rather
|
|
10
|
+
// than imported from @cosmicdrift/kumiko-framework — this package must
|
|
11
|
+
// remain server-dep-free (runs in browsers and React Native).
|
|
12
|
+
export const LOCALE_HEADER_NAME = "X-Locale";
|
|
13
|
+
// Loose BCP-47 tag check — reject newlines/junk that would break fetch headers.
|
|
14
|
+
const LOCALE_TAG = /^[A-Za-z]{2,3}(-[A-Za-z0-9]{2,8})*$/;
|
|
15
|
+
// Reads dataset.kumikoLocale. Returns undefined for non-browser environments
|
|
16
|
+
// (SSR, Web Worker, React Native), before DocumentLangSync has run, or when
|
|
17
|
+
// the value is not a safe language tag — callers skip the header and the
|
|
18
|
+
// server falls back to Accept-Language, then its boot default.
|
|
19
|
+
export function readActiveLocale() {
|
|
20
|
+
const dataset = propertyOf(propertyOf(propertyOf(globalThis, "document"), "documentElement"), "dataset");
|
|
21
|
+
const lang = propertyOf(dataset, "kumikoLocale");
|
|
22
|
+
if (typeof lang !== "string" || lang.length === 0)
|
|
23
|
+
return undefined;
|
|
24
|
+
return LOCALE_TAG.test(lang) ? lang : undefined;
|
|
25
|
+
}
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
export type SseFrame = {
|
|
2
|
+
readonly event: string;
|
|
3
|
+
readonly data: string;
|
|
4
|
+
};
|
|
5
|
+
export declare function parseSseBlock(block: string): SseFrame | null;
|
|
6
|
+
/** Split a complete SSE body (tests / non-streaming buffers) into frames. */
|
|
7
|
+
export declare function parseSseFrames(text: string): SseFrame[];
|
|
8
|
+
/**
|
|
9
|
+
* Incremental SSE reader over a fetch body. Yields `chunk` payloads as
|
|
10
|
+
* parsed JSON; swallows `ping`; returns on `done`; throws DispatcherError
|
|
11
|
+
* on `error` frames. Caller is responsible for aborting the underlying
|
|
12
|
+
* fetch via AbortSignal.
|
|
13
|
+
*/
|
|
14
|
+
export declare function iterateSseChunks<TChunk>(body: ReadableStream<Uint8Array>): AsyncGenerator<TChunk, void, undefined>;
|
|
@@ -0,0 +1,128 @@
|
|
|
1
|
+
import { StreamFrame } from "../headless/index.js";
|
|
2
|
+
import { serverErrorSchema } from "./envelopes.js";
|
|
3
|
+
import { mapServerError } from "./error-mapping.js";
|
|
4
|
+
export function parseSseBlock(block) {
|
|
5
|
+
const trimmed = block.trim();
|
|
6
|
+
if (trimmed.length === 0)
|
|
7
|
+
return null;
|
|
8
|
+
const event = /^event: (.*)$/m.exec(trimmed)?.[1] ?? "";
|
|
9
|
+
const data = /^data: (.*)$/m.exec(trimmed)?.[1] ?? "";
|
|
10
|
+
return { event, data };
|
|
11
|
+
}
|
|
12
|
+
/** Split a complete SSE body (tests / non-streaming buffers) into frames. */
|
|
13
|
+
export function parseSseFrames(text) {
|
|
14
|
+
return text
|
|
15
|
+
.split("\n\n")
|
|
16
|
+
.map(parseSseBlock)
|
|
17
|
+
.filter((f) => f !== null);
|
|
18
|
+
}
|
|
19
|
+
/**
|
|
20
|
+
* Incremental SSE reader over a fetch body. Yields `chunk` payloads as
|
|
21
|
+
* parsed JSON; swallows `ping`; returns on `done`; throws DispatcherError
|
|
22
|
+
* on `error` frames. Caller is responsible for aborting the underlying
|
|
23
|
+
* fetch via AbortSignal.
|
|
24
|
+
*/
|
|
25
|
+
export async function* iterateSseChunks(body) {
|
|
26
|
+
const reader = body.getReader();
|
|
27
|
+
const decoder = new TextDecoder();
|
|
28
|
+
let buffer = "";
|
|
29
|
+
let sawDone = false;
|
|
30
|
+
try {
|
|
31
|
+
while (true) {
|
|
32
|
+
const { done, value } = await reader.read();
|
|
33
|
+
if (done)
|
|
34
|
+
break;
|
|
35
|
+
buffer += decoder.decode(value, { stream: true });
|
|
36
|
+
const parts = buffer.split("\n\n");
|
|
37
|
+
buffer = parts.pop() ?? "";
|
|
38
|
+
for (const part of parts) {
|
|
39
|
+
const frame = parseSseBlock(part);
|
|
40
|
+
if (frame === null)
|
|
41
|
+
continue;
|
|
42
|
+
if (frame.event === StreamFrame.ping)
|
|
43
|
+
continue;
|
|
44
|
+
// skip: terminal SSE done frame — end the generator cleanly
|
|
45
|
+
if (frame.event === StreamFrame.done) {
|
|
46
|
+
sawDone = true;
|
|
47
|
+
return;
|
|
48
|
+
}
|
|
49
|
+
if (frame.event === StreamFrame.error) {
|
|
50
|
+
throw frameDataToDispatcherError(frame.data);
|
|
51
|
+
}
|
|
52
|
+
if (frame.event === StreamFrame.chunk) {
|
|
53
|
+
yield parseChunkData(frame.data);
|
|
54
|
+
}
|
|
55
|
+
}
|
|
56
|
+
}
|
|
57
|
+
// Trailing buffer without final blank line (some runtimes).
|
|
58
|
+
const frame = parseSseBlock(buffer);
|
|
59
|
+
if (frame?.event === StreamFrame.chunk) {
|
|
60
|
+
yield parseChunkData(frame.data);
|
|
61
|
+
}
|
|
62
|
+
else if (frame?.event === StreamFrame.error) {
|
|
63
|
+
throw frameDataToDispatcherError(frame.data);
|
|
64
|
+
}
|
|
65
|
+
else if (frame?.event === StreamFrame.done) {
|
|
66
|
+
sawDone = true;
|
|
67
|
+
}
|
|
68
|
+
if (!sawDone) {
|
|
69
|
+
throw buildTruncatedStreamError();
|
|
70
|
+
}
|
|
71
|
+
}
|
|
72
|
+
finally {
|
|
73
|
+
// cancel() releases the reader's lock too (safe on an already-drained
|
|
74
|
+
// stream) and, unlike releaseLock() alone, tells the underlying HTTP
|
|
75
|
+
// response to close instead of leaving the connection open until the
|
|
76
|
+
// server finishes writing a body no one is reading anymore.
|
|
77
|
+
await reader.cancel().catch(() => { });
|
|
78
|
+
}
|
|
79
|
+
}
|
|
80
|
+
function parseChunkData(data) {
|
|
81
|
+
try {
|
|
82
|
+
return JSON.parse(data);
|
|
83
|
+
}
|
|
84
|
+
catch (e) {
|
|
85
|
+
const cause = e instanceof Error ? e.message : String(e);
|
|
86
|
+
throw {
|
|
87
|
+
code: "stream_error",
|
|
88
|
+
httpStatus: 200,
|
|
89
|
+
i18nKey: "errors.unknown",
|
|
90
|
+
message: `malformed chunk frame: ${cause}`,
|
|
91
|
+
};
|
|
92
|
+
}
|
|
93
|
+
}
|
|
94
|
+
function buildTruncatedStreamError() {
|
|
95
|
+
return {
|
|
96
|
+
code: "stream_error",
|
|
97
|
+
httpStatus: 200,
|
|
98
|
+
i18nKey: "errors.unknown",
|
|
99
|
+
message: "stream ended without a done frame",
|
|
100
|
+
};
|
|
101
|
+
}
|
|
102
|
+
function frameDataToDispatcherError(data) {
|
|
103
|
+
let parsed;
|
|
104
|
+
try {
|
|
105
|
+
parsed = JSON.parse(data);
|
|
106
|
+
}
|
|
107
|
+
catch {
|
|
108
|
+
return unparsableErrorFrame(data);
|
|
109
|
+
}
|
|
110
|
+
// Server serializeError shape — mapServerError expects the same fields
|
|
111
|
+
// as /api/query failures (httpStatus may be absent; reinject 200 for
|
|
112
|
+
// mid-stream gates that flush SSE headers first).
|
|
113
|
+
const envelope = serverErrorSchema.safeParse(parsed);
|
|
114
|
+
if (!envelope.success)
|
|
115
|
+
return unparsableErrorFrame(data);
|
|
116
|
+
return mapServerError({
|
|
117
|
+
...envelope.data,
|
|
118
|
+
httpStatus: envelope.data.httpStatus ?? 200,
|
|
119
|
+
});
|
|
120
|
+
}
|
|
121
|
+
function unparsableErrorFrame(data) {
|
|
122
|
+
return {
|
|
123
|
+
code: "stream_error",
|
|
124
|
+
httpStatus: 200,
|
|
125
|
+
i18nKey: "errors.unknown",
|
|
126
|
+
message: data.length > 0 ? data : "stream error frame",
|
|
127
|
+
};
|
|
128
|
+
}
|
package/dist/primitives.d.ts
CHANGED
|
@@ -1,11 +1,11 @@
|
|
|
1
1
|
import type { ConfigCascade, ConfigScope, ConfigValueSource } from "@cosmicdrift/kumiko-framework/engine";
|
|
2
2
|
import type { FieldIconKey, FormWidth, IconKey, NavIconKey, RowActionDisplay, SelectOptionTone } from "@cosmicdrift/kumiko-framework/ui-types";
|
|
3
|
-
import type { FieldIssue, ListColumnViewModel, ListRowViewModel, RuntimeRenderer } from "@cosmicdrift/kumiko-headless";
|
|
4
3
|
import { type ComponentType, type FormEvent, type KeyboardEvent, type ReactNode, type Ref } from "react";
|
|
4
|
+
import type { FieldIssue, ListColumnViewModel, ListRowViewModel, RuntimeRenderer } from "./headless/index.ts";
|
|
5
5
|
export type { RuntimeRenderer };
|
|
6
6
|
/** Escape hatch for `data-*` test hooks (e.g. an E2E selector) that don't
|
|
7
7
|
* warrant a dedicated typed prop. Web merges these onto the rendered
|
|
8
|
-
* element
|
|
8
|
+
* element. */
|
|
9
9
|
export type DataAttributes = Readonly<Record<`data-${string}`, string>>;
|
|
10
10
|
/** Structural marker a top-level `actions` node can carry so DefaultForm's
|
|
11
11
|
* sticky-footer split (fw#1918) treats it as the pinned primary action even
|
|
@@ -56,7 +56,7 @@ type ButtonBaseProps = {
|
|
|
56
56
|
/** Barrierefreies Label — Pflicht bei icon-only-Buttons (children ist nur
|
|
57
57
|
* ein Icon/Zeichen), sonst hat der Button keinen zugänglichen Namen. */
|
|
58
58
|
readonly ariaLabel?: string;
|
|
59
|
-
/** Tooltip —
|
|
59
|
+
/** Tooltip — rendered as the `title` attribute. */
|
|
60
60
|
readonly title?: string;
|
|
61
61
|
/** Toggle state for toggle buttons — web sets `aria-pressed`; leave unset for plain buttons. */
|
|
62
62
|
readonly pressed?: boolean;
|
|
@@ -67,12 +67,10 @@ type ButtonBaseProps = {
|
|
|
67
67
|
* des Containers, kein Button-Prop (Kit hält arbiträres Sizing draußen). */
|
|
68
68
|
readonly width?: "full" | "auto";
|
|
69
69
|
readonly testId?: string;
|
|
70
|
-
/** Layout extras
|
|
71
|
-
* (precedent: LinkProps.className). */
|
|
70
|
+
/** Layout extras, merged via cn(). */
|
|
72
71
|
readonly className?: string;
|
|
73
72
|
/** DOM ref on the button — escape hatch for cases that need more than
|
|
74
|
-
* a click (e.g. binding a drop-target handler).
|
|
75
|
-
* impls ignore it (no native equivalent). */
|
|
73
|
+
* a click (e.g. binding a drop-target handler). Forwarded to the element. */
|
|
76
74
|
readonly ref?: Ref<HTMLButtonElement>;
|
|
77
75
|
/** Icon before the label. */
|
|
78
76
|
readonly icon?: NavIconKey;
|
|
@@ -94,8 +92,7 @@ export type LinkProps = {
|
|
|
94
92
|
/** Plain left-click handler (SPA navigation); `href` stays set for
|
|
95
93
|
* modifier/middle clicks, which the browser handles itself. */
|
|
96
94
|
readonly onPress?: () => void;
|
|
97
|
-
/** Layout
|
|
98
|
-
* Native-Impls ignorieren es (Präzedenz: CardProps.className). */
|
|
95
|
+
/** Layout extras (self-center, text-xs), merged via cn(). */
|
|
99
96
|
readonly className?: string;
|
|
100
97
|
readonly children: ReactNode;
|
|
101
98
|
readonly testId?: string;
|
|
@@ -220,7 +217,7 @@ export type InputProps = {
|
|
|
220
217
|
/** Read-only Input (z.B. gewürfelter Free-Tier-Slug). Nicht `disabled`
|
|
221
218
|
* — bleibt fokussier-/kopierbar. */
|
|
222
219
|
readonly readOnly?: boolean;
|
|
223
|
-
/** Closed FieldIconKey vocabulary (FIELD_ICONS registry, renderer
|
|
220
|
+
/** Closed FieldIconKey vocabulary (FIELD_ICONS registry, renderer/web). */
|
|
224
221
|
readonly icon?: FieldIconKey;
|
|
225
222
|
/** Resolved inline text before/after the input (EditFieldSpec.prefix/suffix). */
|
|
226
223
|
readonly prefix?: string;
|
|
@@ -228,8 +225,7 @@ export type InputProps = {
|
|
|
228
225
|
readonly fill?: InputFillAction;
|
|
229
226
|
readonly dataAttributes?: DataAttributes;
|
|
230
227
|
/** Raw keydown access (e.g. Enter-to-submit at the field instead of
|
|
231
|
-
* the surrounding Form).
|
|
232
|
-
* (precedent: `ButtonProps.ref`). */
|
|
228
|
+
* the surrounding Form). Forwarded to the element. */
|
|
233
229
|
readonly onKeyDown?: (event: KeyboardEvent<HTMLInputElement>) => void;
|
|
234
230
|
} | {
|
|
235
231
|
readonly kind: "email";
|
|
@@ -245,6 +241,17 @@ export type InputProps = {
|
|
|
245
241
|
* Username-or-Email) reichen das durch. */
|
|
246
242
|
readonly autoComplete?: string;
|
|
247
243
|
readonly testId?: string;
|
|
244
|
+
} | {
|
|
245
|
+
/** Month picker; the value is `YYYY-MM` (empty string when unset). */
|
|
246
|
+
readonly kind: "month";
|
|
247
|
+
readonly id: string;
|
|
248
|
+
readonly name: string;
|
|
249
|
+
readonly value: string;
|
|
250
|
+
readonly onChange: (v: string) => void;
|
|
251
|
+
readonly disabled?: boolean;
|
|
252
|
+
readonly required?: boolean;
|
|
253
|
+
readonly hasError?: boolean;
|
|
254
|
+
readonly testId?: string;
|
|
248
255
|
} | {
|
|
249
256
|
readonly kind: "password";
|
|
250
257
|
readonly id: string;
|
|
@@ -276,7 +283,7 @@ export type InputProps = {
|
|
|
276
283
|
/** Hint text shown when the field is empty (analog to kind:"text"). */
|
|
277
284
|
readonly placeholder?: string;
|
|
278
285
|
readonly testId?: string;
|
|
279
|
-
/** Closed FieldIconKey vocabulary (FIELD_ICONS registry, renderer
|
|
286
|
+
/** Closed FieldIconKey vocabulary (FIELD_ICONS registry, renderer/web). */
|
|
280
287
|
readonly icon?: FieldIconKey;
|
|
281
288
|
/** `<input step>`. "any" disables the native stepMismatch constraint
|
|
282
289
|
* (needed for decimal fields — integer fields leave this unset).
|
|
@@ -345,7 +352,7 @@ export type InputProps = {
|
|
|
345
352
|
* attribute so a phone opens the camera instead of the file picker. */
|
|
346
353
|
readonly capture?: "environment" | "user";
|
|
347
354
|
/** Web-only folder picker: the picked files (with `webkitRelativePath`)
|
|
348
|
-
* go to `onFilesPicked` and nothing is uploaded.
|
|
355
|
+
* go to `onFilesPicked` and nothing is uploaded. */
|
|
349
356
|
readonly directory?: boolean;
|
|
350
357
|
readonly onFilesPicked?: (files: readonly PickedFile[]) => void;
|
|
351
358
|
/** Translated label of the pick button; absent → the upload/change default. */
|
|
@@ -541,8 +548,8 @@ export type InputProps = {
|
|
|
541
548
|
readonly dataAttributes?: DataAttributes;
|
|
542
549
|
/** Raw keydown access (e.g. plain-Enter-submits/Shift+Enter-newline at
|
|
543
550
|
* the field instead of the surrounding Form). Composes with
|
|
544
|
-
* `onSubmitShortcut` — both fire on the same keystroke when set.
|
|
545
|
-
*
|
|
551
|
+
* `onSubmitShortcut` — both fire on the same keystroke when set. Forwarded
|
|
552
|
+
* to the element. */
|
|
546
553
|
readonly onKeyDown?: (event: KeyboardEvent<HTMLTextAreaElement>) => void;
|
|
547
554
|
};
|
|
548
555
|
export type DataTableSortDir = "asc" | "desc";
|
|
@@ -783,7 +790,7 @@ export type DataTableProps = {
|
|
|
783
790
|
readonly renderExpandedRow?: (row: ListRowViewModel) => ReactNode;
|
|
784
791
|
};
|
|
785
792
|
/** Cell type for one column of an embedded-list field. Mirrors
|
|
786
|
-
* EmbeddedListCellViewModel["type"] from `@cosmicdrift/kumiko-headless`. */
|
|
793
|
+
* EmbeddedListCellViewModel["type"] from `@cosmicdrift/kumiko-renderer/headless`. */
|
|
787
794
|
export type EmbeddedListCellType = "text" | "number" | "boolean" | "date" | "money" | "decimal" | "select" | "reference" | "timestamp";
|
|
788
795
|
/** One column of an embedded-list table (one entry per key of the source
|
|
789
796
|
* EmbeddedFieldDef's `schema`). */
|
|
@@ -880,8 +887,7 @@ export type FormSectionNavItem = {
|
|
|
880
887
|
*
|
|
881
888
|
* `title`: slot in the card header. `actions`: optional slot for the
|
|
882
889
|
* primary form actions (Save, Cancel) — renders as a footer row at the
|
|
883
|
-
* end of the card (normal document flow).
|
|
884
|
-
* same slot as a bottom bar instead. */
|
|
890
|
+
* end of the card (normal document flow). */
|
|
885
891
|
export type FormProps = {
|
|
886
892
|
readonly onSubmit: (e?: FormEvent) => void;
|
|
887
893
|
readonly children: ReactNode;
|
|
@@ -895,24 +901,20 @@ export type FormProps = {
|
|
|
895
901
|
readonly secondaryActions?: ReactNode;
|
|
896
902
|
readonly testId?: string;
|
|
897
903
|
/** Max width of the form container. Default "full" — see FormWidth
|
|
898
|
-
* (`packages/types/src/screen.ts`, EditLayout.width).
|
|
899
|
-
* ignore this prop (no width constraint there). */
|
|
904
|
+
* (`packages/types/src/screen.ts`, EditLayout.width). */
|
|
900
905
|
readonly width?: FormWidth;
|
|
901
906
|
/** Pins `actions` to the viewport bottom on narrow screens (`<640px`)
|
|
902
907
|
* instead of normal document flow, so it stays reachable when a virtual
|
|
903
908
|
* keyboard shrinks the visible viewport (fw#1918). Desktop/tablet
|
|
904
|
-
* unaffected.
|
|
905
|
-
* convention there). */
|
|
909
|
+
* unaffected. */
|
|
906
910
|
readonly stickyActions?: boolean;
|
|
907
911
|
/** Extra content rendered above the card, inside the same page padding
|
|
908
912
|
* the card itself sits in — for a host that needs its own header region
|
|
909
913
|
* (title/metrics/tabs) to share the form's left padding and width
|
|
910
|
-
* instead of rendering as unpadded siblings before it.
|
|
911
|
-
* ignore this prop. */
|
|
914
|
+
* instead of rendering as unpadded siblings before it. */
|
|
912
915
|
readonly headerRegion?: ReactNode;
|
|
913
916
|
/** Compact content on the right of the form title, same row — status
|
|
914
|
-
* chips or allowance badges that belong to the screen, not to a field.
|
|
915
|
-
* Native impls may ignore this prop. */
|
|
917
|
+
* chips or allowance badges that belong to the screen, not to a field. */
|
|
916
918
|
readonly titleAction?: ReactNode;
|
|
917
919
|
/** Sizes the form to fill its container's height (instead of the page's
|
|
918
920
|
* natural content height) so a single scrolling child — a lone
|
|
@@ -921,8 +923,7 @@ export type FormProps = {
|
|
|
921
923
|
* section and for screens that fill the shell height (together with
|
|
922
924
|
* `stickyActions`: sections scroll, footer stays pinned without
|
|
923
925
|
* `position: fixed`); every other caller leaves it unset and keeps normal
|
|
924
|
-
* document-flow height.
|
|
925
|
-
* bounded viewport there). */
|
|
926
|
+
* document-flow height. */
|
|
926
927
|
readonly fillHeight?: boolean;
|
|
927
928
|
/** Drops the surrounding card (bg/border/rounded, title/subtitle block,
|
|
928
929
|
* footer border) so sections+footer render as siblings of `headerRegion`
|
|
@@ -930,14 +931,12 @@ export type FormProps = {
|
|
|
930
931
|
* projectionDetail's tab content is a sibling of the head card, not its
|
|
931
932
|
* child (bedienkonzept A1), so it must look like a standalone screen
|
|
932
933
|
* instead of a form embedded in another card. Default false: unchanged
|
|
933
|
-
* card chrome.
|
|
934
|
-
* to begin with). */
|
|
934
|
+
* card chrome. */
|
|
935
935
|
readonly chromeless?: boolean;
|
|
936
936
|
/** Set by RenderEdit for entityEdit/actionForm screens that fill the shell
|
|
937
937
|
* height: the form renders without a surrounding card, in a padded scroll
|
|
938
938
|
* surface with a fixed-width form column. Requires `fillHeight`; projection
|
|
939
|
-
* detail screens (which also fill the height) do not set it.
|
|
940
|
-
* may ignore this prop. */
|
|
939
|
+
* detail screens (which also fill the height) do not set it. */
|
|
941
940
|
readonly screenForm?: boolean;
|
|
942
941
|
/** Number of unsaved changes, shown in the pinned footer; 0 shows the quiet
|
|
943
942
|
* "No unsaved changes" status. Omitted (create mode) — no status at all. */
|
|
@@ -951,7 +950,7 @@ export type FormProps = {
|
|
|
951
950
|
* `screenForm`. The web impl shows it only with three or more entries. */
|
|
952
951
|
readonly sectionNav?: readonly FormSectionNavItem[];
|
|
953
952
|
/** Leading column next to the scroll surface of a `screenForm` (wizard step
|
|
954
|
-
* navigation).
|
|
953
|
+
* navigation). */
|
|
955
954
|
readonly sideRail?: ReactNode;
|
|
956
955
|
};
|
|
957
956
|
/** Titled Gruppe von Feldern. Web: `<fieldset>` + `<legend>`, Native:
|
|
@@ -1432,7 +1431,7 @@ export type CopyButtonProps = {
|
|
|
1432
1431
|
readonly label: string;
|
|
1433
1432
|
readonly copiedLabel: string;
|
|
1434
1433
|
readonly variant?: "primary" | "secondary";
|
|
1435
|
-
/** Layout extras
|
|
1434
|
+
/** Layout extras, merged via cn(). */
|
|
1436
1435
|
readonly className?: string;
|
|
1437
1436
|
readonly testId?: string;
|
|
1438
1437
|
};
|
|
@@ -1444,7 +1443,7 @@ export type ShareButtonProps = {
|
|
|
1444
1443
|
readonly text: string;
|
|
1445
1444
|
readonly label: string;
|
|
1446
1445
|
readonly variant?: "primary" | "secondary";
|
|
1447
|
-
/** Layout extras
|
|
1446
|
+
/** Layout extras, merged via cn(). */
|
|
1448
1447
|
readonly className?: string;
|
|
1449
1448
|
readonly testId?: string;
|
|
1450
1449
|
} & ({
|
package/dist/primitives.js
CHANGED
|
@@ -79,7 +79,7 @@ export function useOptionalPrimitives() {
|
|
|
79
79
|
export function usePrimitives() {
|
|
80
80
|
const registry = useContext(PrimitivesContext);
|
|
81
81
|
if (registry === undefined) {
|
|
82
|
-
throw new Error("usePrimitives: no <PrimitivesProvider> mounted. Wrap your app in one (createKumikoApp does this for you with defaultPrimitives from @cosmicdrift/kumiko-renderer
|
|
82
|
+
throw new Error("usePrimitives: no <PrimitivesProvider> mounted. Wrap your app in one (createKumikoApp does this for you with defaultPrimitives from @cosmicdrift/kumiko-renderer/web).");
|
|
83
83
|
}
|
|
84
84
|
return registry;
|
|
85
85
|
}
|
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
import type { Dispatcher, DispatcherError } from "@cosmicdrift/kumiko-headless";
|
|
2
1
|
import { type ReactNode } from "react";
|
|
2
|
+
import type { Dispatcher, DispatcherError } from "../headless/index.ts";
|
|
3
3
|
export declare const SESSION_ENDED_ERROR_CODES: readonly ["session_invalid", "invalid_token", "missing_token", "unauthenticated"];
|
|
4
4
|
export declare function isSessionEndedError(error: Pick<DispatcherError, "code" | "httpStatus">): boolean;
|
|
5
5
|
export type SessionEndedSignal = {
|
package/dist/tokens.d.ts
CHANGED
|
@@ -85,8 +85,7 @@ export declare function TokensProvider({ children, value }: TokensProviderProps)
|
|
|
85
85
|
export declare function useTokens(): Tokens;
|
|
86
86
|
/** Volle API inkl. Theme-Toggle. Für den Dark/Light-Switch-Button. */
|
|
87
87
|
export declare function useTokenController(): TokensApi;
|
|
88
|
-
/** Tokens
|
|
89
|
-
*
|
|
90
|
-
*
|
|
91
|
-
* -native) importieren das in ihre TokensApi-Impl. */
|
|
88
|
+
/** Tokens with var-string values. Constant: the "values" are references,
|
|
89
|
+
* the real colors change via CSS without mutating the object. Platform
|
|
90
|
+
* bindings (renderer/web) import it into their TokensApi impl. */
|
|
92
91
|
export declare const cssVarTokens: Tokens;
|
package/dist/tokens.js
CHANGED
|
@@ -30,14 +30,13 @@ export function useTokens() {
|
|
|
30
30
|
export function useTokenController() {
|
|
31
31
|
const api = useContext(TokensContext);
|
|
32
32
|
if (api === undefined) {
|
|
33
|
-
throw new Error("useTokens/useTokenController: no <TokensProvider> mounted. createKumikoApp verdrahtet den Provider automatisch mit @cosmicdrift/kumiko-renderer
|
|
33
|
+
throw new Error("useTokens/useTokenController: no <TokensProvider> mounted. createKumikoApp verdrahtet den Provider automatisch mit @cosmicdrift/kumiko-renderer/web defaults.");
|
|
34
34
|
}
|
|
35
35
|
return api;
|
|
36
36
|
}
|
|
37
|
-
/** Tokens
|
|
38
|
-
*
|
|
39
|
-
*
|
|
40
|
-
* -native) importieren das in ihre TokensApi-Impl. */
|
|
37
|
+
/** Tokens with var-string values. Constant: the "values" are references,
|
|
38
|
+
* the real colors change via CSS without mutating the object. Platform
|
|
39
|
+
* bindings (renderer/web) import it into their TokensApi impl. */
|
|
41
40
|
export const cssVarTokens = {
|
|
42
41
|
color: {
|
|
43
42
|
background: "var(--color-background)",
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
import { type ReactNode } from "react";
|
|
2
|
+
import type { AppSchema } from "../../index.ts";
|
|
3
|
+
export declare const APP_SCHEMA_API_PATH = "/api/schema";
|
|
4
|
+
export declare function isAppSchemaPayload(value: unknown): value is AppSchema;
|
|
5
|
+
export type AppSchemaFetchResult = {
|
|
6
|
+
readonly kind: "loaded";
|
|
7
|
+
readonly app: AppSchema;
|
|
8
|
+
} | {
|
|
9
|
+
readonly kind: "session-ended";
|
|
10
|
+
} | {
|
|
11
|
+
readonly kind: "unauthorized";
|
|
12
|
+
} | {
|
|
13
|
+
readonly kind: "failed";
|
|
14
|
+
};
|
|
15
|
+
export declare function fetchAppSchema(signal: AbortSignal, schemaUrl?: string): Promise<AppSchemaFetchResult>;
|
|
16
|
+
export declare function AppSchemaFetchBoot({ onLoaded, schemaUrl, }: {
|
|
17
|
+
readonly onLoaded: (app: AppSchema) => void;
|
|
18
|
+
readonly schemaUrl?: string;
|
|
19
|
+
}): ReactNode;
|
|
@@ -0,0 +1,124 @@
|
|
|
1
|
+
import { jsx as _jsx } from "react/jsx-runtime";
|
|
2
|
+
import { useEffect, useRef, useState } from "react";
|
|
3
|
+
import { toAppSchema, usePrimitives, useSessionEndedSignal, useTranslation } from "../../index.js";
|
|
4
|
+
// Mirrors framework's api-constants Routes.schema, same pattern as
|
|
5
|
+
// dispatcher-live's PATH_* constants — the one place that spells out the
|
|
6
|
+
// wire path both sides agree on.
|
|
7
|
+
export const APP_SCHEMA_API_PATH = "/api/schema";
|
|
8
|
+
function isFeatureSchemaPayload(value) {
|
|
9
|
+
if (typeof value !== "object" || value === null)
|
|
10
|
+
return false;
|
|
11
|
+
if (!("featureName" in value) || typeof value.featureName !== "string")
|
|
12
|
+
return false;
|
|
13
|
+
return "screens" in value && Array.isArray(value.screens);
|
|
14
|
+
}
|
|
15
|
+
export function isAppSchemaPayload(value) {
|
|
16
|
+
if (typeof value !== "object" || value === null)
|
|
17
|
+
return false;
|
|
18
|
+
if (!("features" in value) || !Array.isArray(value.features))
|
|
19
|
+
return false;
|
|
20
|
+
return value.features.every((feature) => isFeatureSchemaPayload(feature));
|
|
21
|
+
}
|
|
22
|
+
function isAbortError(err) {
|
|
23
|
+
return err instanceof DOMException && err.name === "AbortError";
|
|
24
|
+
}
|
|
25
|
+
// Mirrors createLiveDispatcher: a cross-origin API (absolute baseUrl) needs
|
|
26
|
+
// credentials "include" for the session cookie to travel; same-origin stays
|
|
27
|
+
// "same-origin" so a relative path never widens.
|
|
28
|
+
function schemaFetchCredentials(schemaUrl) {
|
|
29
|
+
try {
|
|
30
|
+
return new URL(schemaUrl, window.location.href).origin === window.location.origin
|
|
31
|
+
? "same-origin"
|
|
32
|
+
: "include";
|
|
33
|
+
}
|
|
34
|
+
catch {
|
|
35
|
+
return "same-origin";
|
|
36
|
+
}
|
|
37
|
+
}
|
|
38
|
+
// Rejects only on abort (caller-cancelled) — every other failure mode
|
|
39
|
+
// (network error, non-2xx, unparseable/invalid body) resolves to
|
|
40
|
+
// `{ kind: "failed" }` so callers get one uniform result shape to branch
|
|
41
|
+
// on instead of a mix of thrown errors and resolved results.
|
|
42
|
+
export async function fetchAppSchema(signal, schemaUrl = APP_SCHEMA_API_PATH) {
|
|
43
|
+
let res;
|
|
44
|
+
try {
|
|
45
|
+
res = await fetch(schemaUrl, {
|
|
46
|
+
credentials: schemaFetchCredentials(schemaUrl),
|
|
47
|
+
headers: { Accept: "application/json" },
|
|
48
|
+
signal,
|
|
49
|
+
});
|
|
50
|
+
}
|
|
51
|
+
catch (err) {
|
|
52
|
+
if (isAbortError(err))
|
|
53
|
+
throw err;
|
|
54
|
+
return { kind: "failed" };
|
|
55
|
+
}
|
|
56
|
+
if (res.status === 401)
|
|
57
|
+
return { kind: "session-ended" };
|
|
58
|
+
if (res.status === 403)
|
|
59
|
+
return { kind: "unauthorized" };
|
|
60
|
+
if (!res.ok)
|
|
61
|
+
return { kind: "failed" };
|
|
62
|
+
let payload;
|
|
63
|
+
try {
|
|
64
|
+
payload = await res.json();
|
|
65
|
+
}
|
|
66
|
+
catch {
|
|
67
|
+
return { kind: "failed" };
|
|
68
|
+
}
|
|
69
|
+
if (!isAppSchemaPayload(payload))
|
|
70
|
+
return { kind: "failed" };
|
|
71
|
+
return { kind: "loaded", app: toAppSchema(payload) };
|
|
72
|
+
}
|
|
73
|
+
// Boots the app once the caller (AppSchemaBoundary, itself inside the
|
|
74
|
+
// clientFeature gates) decides to mount it — a login gate renders its own
|
|
75
|
+
// placeholder instead of children, so this component (and its fetch) never
|
|
76
|
+
// mounts until the user is authenticated.
|
|
77
|
+
export function AppSchemaFetchBoot({ onLoaded, schemaUrl, }) {
|
|
78
|
+
const t = useTranslation();
|
|
79
|
+
const { Banner, Button } = usePrimitives();
|
|
80
|
+
const [status, setStatus] = useState("loading");
|
|
81
|
+
const sessionEndedSignal = useSessionEndedSignal();
|
|
82
|
+
const [attempt, setAttempt] = useState(0);
|
|
83
|
+
// Ref instead of an effect dependency: onLoaded is a fresh closure on
|
|
84
|
+
// every KumikoAppRoot render (it captures setApp) — depending on it
|
|
85
|
+
// directly would refetch on every unrelated re-render.
|
|
86
|
+
const onLoadedRef = useRef(onLoaded);
|
|
87
|
+
onLoadedRef.current = onLoaded;
|
|
88
|
+
// biome-ignore lint/correctness/useExhaustiveDependencies: attempt is the retry trigger, never read in the body — bumping it is how the Retry button re-fires this effect.
|
|
89
|
+
useEffect(() => {
|
|
90
|
+
const controller = new AbortController();
|
|
91
|
+
setStatus("loading");
|
|
92
|
+
fetchAppSchema(controller.signal, schemaUrl)
|
|
93
|
+
.then((result) => {
|
|
94
|
+
if (controller.signal.aborted)
|
|
95
|
+
return;
|
|
96
|
+
if (result.kind === "loaded") {
|
|
97
|
+
onLoadedRef.current(result.app);
|
|
98
|
+
return;
|
|
99
|
+
}
|
|
100
|
+
setStatus(result.kind);
|
|
101
|
+
})
|
|
102
|
+
.catch((err) => {
|
|
103
|
+
if (!isAbortError(err))
|
|
104
|
+
setStatus("failed");
|
|
105
|
+
});
|
|
106
|
+
return () => controller.abort();
|
|
107
|
+
}, [attempt, schemaUrl]);
|
|
108
|
+
useEffect(() => {
|
|
109
|
+
if (status === "session-ended")
|
|
110
|
+
sessionEndedSignal?.notify();
|
|
111
|
+
}, [status, sessionEndedSignal]);
|
|
112
|
+
if (status === "loading") {
|
|
113
|
+
return (_jsx("div", { role: "status", "aria-busy": "true", children: t("kumiko.app-boot.loading") }));
|
|
114
|
+
}
|
|
115
|
+
if (status === "unauthorized" || status === "session-ended") {
|
|
116
|
+
// No auto-retry/reload here on purpose — a signed-out user retrying
|
|
117
|
+
// the same request just gets the same 401 again; the login gate that
|
|
118
|
+
// wraps this component is the actual way out. For session-ended the
|
|
119
|
+
// notify above normally swaps this banner for the login screen; the
|
|
120
|
+
// banner stays as fallback when no session provider is mounted.
|
|
121
|
+
return (_jsx(Banner, { variant: "error", padded: true, children: t("kumiko.app-boot.unauthorized") }));
|
|
122
|
+
}
|
|
123
|
+
return (_jsx(Banner, { variant: "error", padded: true, actions: _jsx(Button, { variant: "secondary", onClick: () => setAttempt((n) => n + 1), children: t("kumiko.actions.reload") }), children: t("kumiko.app-boot.failed") }));
|
|
124
|
+
}
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
import { type LocaleResolver } from "../../headless/index.ts";
|
|
2
|
+
export type CreateBrowserLocaleResolverOptions = {
|
|
3
|
+
/** localStorage-Key unter dem die aktive Locale persistiert wird.
|
|
4
|
+
* Default: `"kumiko:locale"`. Apps die mehrere Kumiko-Instanzen auf
|
|
5
|
+
* derselben Origin mounten (selten), setzen verschiedene Keys. */
|
|
6
|
+
readonly storageKey?: string;
|
|
7
|
+
/** Fallback wenn weder localStorage noch navigator.language liefern.
|
|
8
|
+
* Default: `"en"`. */
|
|
9
|
+
readonly defaultLocale?: string;
|
|
10
|
+
/** Maps a stored or browser-reported tag onto one of the app's locales;
|
|
11
|
+
* `undefined` rejects it (a stored tag then falls through to
|
|
12
|
+
* navigator.language, the browser tag to `defaultLocale`). Only applied to
|
|
13
|
+
* the initial detection, not to `setLocale`. */
|
|
14
|
+
readonly normalizeLocale?: (tag: string) => string | undefined;
|
|
15
|
+
};
|
|
16
|
+
export declare const BROWSER_LOCALE_STORAGE_KEY = "kumiko:locale";
|
|
17
|
+
/** Default-Resolver wenn createKumikoApp ohne `locale`-Option gebootet
|
|
18
|
+
* wird. Stateful: setLocale() persistiert in localStorage und ruft
|
|
19
|
+
* subscribed listeners. Apps die eine vollwertige i18n-Schicht haben
|
|
20
|
+
* (i18next, FormatJS, eigener Store), reichen stattdessen ihre eigene
|
|
21
|
+
* Resolver-Impl via `createKumikoApp({ locale })`. */
|
|
22
|
+
export declare function createBrowserLocaleResolver(options?: CreateBrowserLocaleResolverOptions): LocaleResolver;
|