@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,78 @@
|
|
|
1
|
+
export type { AppPrimitives, AppSchema, AppTokens, BannerProps, ButtonProps, CardProps, ColorTokens, CorePrimitives, CoreTokens, DataTableProps, DispatcherProviderProps, FeatureSchema, FieldProps, FontTokens, FormProps, GridCellProps, GridProps, HeadingProps, InputProps, KumikoScreenProps, LiveEvent, LiveEventSubscriber, LiveEventsProviderProps, LocaleProviderProps, NavApi, NavProviderProps, NavRoute, NavTarget, PrimitivesProviderProps, PrimitivesRegistry, RadiusTokens, RenderEditChangeState, RenderEditControls, RenderEditProps, RenderFieldProps, RenderListProps, SectionProps, ShadowTokens, SpacingTokens, TextProps, ThemeMode, ThemePreference, Tokens, TokensApi, TokensProviderProps, TranslationBundle, TranslationsByLocale, UseFormOptions, UseFormResult, UseQueryOptions, UseQueryResult, UserRolesProviderProps, WorkspaceSchema, } from "../index.ts";
|
|
2
|
+
export { createStaticLocaleResolver, cssVarTokens, DispatcherProvider, formatPath, KumikoScreen, LiveEventsProvider, LocaleProvider, NavProvider, PrimitivesProvider, parsePath, qualifyScreenId, RenderEdit, RenderField, RenderList, synthesizeActionFormEntity, synthesizeActionFormScreen, TokensProvider, UserRolesProvider, useDispatcher, useDispatcherStatus, useForm, useLiveEvents, useLocale, useNav, usePrimitives, useQuery, useStore, useStoreSelector, useTokenController, useTokens, useTranslation, useUserRoles, } from "../index.ts";
|
|
3
|
+
export { BROWSER_LOCALE_STORAGE_KEY, type CreateBrowserLocaleResolverOptions, createBrowserLocaleResolver, } from "./app/browser-locale.ts";
|
|
4
|
+
export type { ClientFeatureDefinition } from "./app/client-plugin.tsx";
|
|
5
|
+
export type { CreateKumikoAppOptions } from "./app/create-app.tsx";
|
|
6
|
+
export { createKumikoApp } from "./app/create-app.tsx";
|
|
7
|
+
export type { CreatePublicSurfaceOptions, PublicRoute } from "./app/create-public-surface.tsx";
|
|
8
|
+
export { createPublicSurface } from "./app/create-public-surface.tsx";
|
|
9
|
+
export type { CreateBrowserDraftStorageOptions } from "./app/draft-storage.ts";
|
|
10
|
+
export { createBrowserDraftStorage } from "./app/draft-storage.ts";
|
|
11
|
+
export type { KumikoLinkProps } from "./app/nav.tsx";
|
|
12
|
+
export { KumikoLink, useBrowserNavApi } from "./app/nav.tsx";
|
|
13
|
+
export { PlainContentEditor } from "./app/plain-content-editor.tsx";
|
|
14
|
+
export { useResolvers } from "./app/resolvers-context.tsx";
|
|
15
|
+
export { RichContentEditor } from "./app/rich-content-editor.tsx";
|
|
16
|
+
export type { NavIconKey } from "./icons.tsx";
|
|
17
|
+
export { Icon } from "./icons.tsx";
|
|
18
|
+
export type { AppLayoutProps } from "./layout/app-layout.tsx";
|
|
19
|
+
export { AppLayout } from "./layout/app-layout.tsx";
|
|
20
|
+
export type { AvatarProps, AvatarSize } from "./layout/avatar.tsx";
|
|
21
|
+
export { Avatar } from "./layout/avatar.tsx";
|
|
22
|
+
export type { DefaultAppShellProps } from "./layout/default-app-shell.tsx";
|
|
23
|
+
export { DefaultAppShell } from "./layout/default-app-shell.tsx";
|
|
24
|
+
export type { EditorPanelProps, ResolverComponent } from "./layout/editor-panel.tsx";
|
|
25
|
+
export { EditorPanel } from "./layout/editor-panel.tsx";
|
|
26
|
+
export type { NavReparentOverride } from "./layout/filter-app-schema-navs.ts";
|
|
27
|
+
export { filterAppSchemaNavsByAllowlist, reparentAppSchemaNavs, } from "./layout/filter-app-schema-navs.ts";
|
|
28
|
+
export type { HeaderActionGroupProps } from "./layout/header-action-group.tsx";
|
|
29
|
+
export { HeaderActionGroup } from "./layout/header-action-group.tsx";
|
|
30
|
+
export type { LanguageMenuItemsProps } from "./layout/language-menu-items.tsx";
|
|
31
|
+
export { LanguageMenuItems } from "./layout/language-menu-items.tsx";
|
|
32
|
+
export type { LanguageSwitcherProps, LocaleOption } from "./layout/language-switcher.tsx";
|
|
33
|
+
export { LanguageSwitcher } from "./layout/language-switcher.tsx";
|
|
34
|
+
export type { NavTreeProps } from "./layout/nav-tree.tsx";
|
|
35
|
+
export { buildNavRegistrySlice, buildNavRegistrySliceForApp, NavTree } from "./layout/nav-tree.tsx";
|
|
36
|
+
export type { ProfileMenuItem, ProfileMenuProps } from "./layout/profile-menu.tsx";
|
|
37
|
+
export { ProfileMenu } from "./layout/profile-menu.tsx";
|
|
38
|
+
export type { SidebarProps } from "./layout/sidebar.tsx";
|
|
39
|
+
export { Sidebar } from "./layout/sidebar.tsx";
|
|
40
|
+
export type { SidebarBrandProps } from "./layout/sidebar-brand.tsx";
|
|
41
|
+
export { SidebarBrand } from "./layout/sidebar-brand.tsx";
|
|
42
|
+
export { SidebarPanel } from "./layout/sidebar-panel.tsx";
|
|
43
|
+
export type { SidebarUserProps } from "./layout/sidebar-user.tsx";
|
|
44
|
+
export { SidebarUser } from "./layout/sidebar-user.tsx";
|
|
45
|
+
export { parseTargetFromSearchParams } from "./layout/target-url.ts";
|
|
46
|
+
export type { ThemeMenuItemProps } from "./layout/theme-menu-item.tsx";
|
|
47
|
+
export { ThemeMenuItem } from "./layout/theme-menu-item.tsx";
|
|
48
|
+
export type { ThemeToggleProps } from "./layout/theme-toggle.tsx";
|
|
49
|
+
export { ThemeToggle } from "./layout/theme-toggle.tsx";
|
|
50
|
+
export type { TopbarProps } from "./layout/topbar.tsx";
|
|
51
|
+
export { Topbar } from "./layout/topbar.tsx";
|
|
52
|
+
export type { WorkspaceShellProps, WorkspaceShellUser } from "./layout/workspace-shell.tsx";
|
|
53
|
+
export { filterByAccess, resolveDefaultId, WorkspaceShell } from "./layout/workspace-shell.tsx";
|
|
54
|
+
export type { WorkspaceSwitcherProps } from "./layout/workspace-switcher.tsx";
|
|
55
|
+
export { WorkspaceSwitcher } from "./layout/workspace-switcher.tsx";
|
|
56
|
+
export { cn } from "./lib/cn.ts";
|
|
57
|
+
export { postWithDownload } from "./lib/download.ts";
|
|
58
|
+
export { downloadFileRef, FileDownloadFailedError, fetchFileRefBlob, fileNameFromContentDisposition, saveBlobAsFile, } from "./lib/file-ref-download.ts";
|
|
59
|
+
export { buildFileUploadFormData } from "./lib/file-upload-form-data.ts";
|
|
60
|
+
export { type FileRefTarget, FileUploadFailedError, uploadFileRef } from "./lib/upload-file-ref.ts";
|
|
61
|
+
export type { ActionMenuProps, MenuItemDef } from "./primitives/action-menu.tsx";
|
|
62
|
+
export { ActionMenu } from "./primitives/action-menu.tsx";
|
|
63
|
+
export { DropdownMenu, DropdownMenuCheckboxItem, DropdownMenuContent, DropdownMenuItem, DropdownMenuLabel, DropdownMenuPortal, DropdownMenuSeparator, DropdownMenuTrigger, } from "./primitives/dropdown-menu.tsx";
|
|
64
|
+
export { BareFormProvider, DefaultCard as Card, defaultPrimitives, FormScreenShell, ScreenWidthProvider, } from "./primitives/index.tsx";
|
|
65
|
+
export { PageSection, Stack } from "./primitives/layout.tsx";
|
|
66
|
+
export { formatMoney } from "./primitives/money-input.tsx";
|
|
67
|
+
export type { ToastOptions, ToastProviderProps, ToastVariant } from "./primitives/toast.tsx";
|
|
68
|
+
export { ToastProvider, useToast } from "./primitives/toast.tsx";
|
|
69
|
+
export { useIsNarrowViewport, useIsViewportBelow } from "./primitives/use-narrow-viewport.ts";
|
|
70
|
+
export type { CreateEventSourceLiveEventsOptions } from "./sse/live-events.ts";
|
|
71
|
+
export { createEventSourceLiveEvents } from "./sse/live-events.ts";
|
|
72
|
+
export { applyTokensToCssVars, defaultTokens, lightTokens, useBrowserTokensApi, } from "./tokens.ts";
|
|
73
|
+
export { ResizableHandle, ResizablePanel, ResizablePanelGroup } from "./ui/resizable.tsx";
|
|
74
|
+
export { SidebarMenu, SidebarMenuButton, SidebarMenuItem, SidebarProvider } from "./ui/sidebar.tsx";
|
|
75
|
+
export type { KumikoBuild } from "./version/update-checker.tsx";
|
|
76
|
+
export { readLoadedBuild } from "./version/update-checker.tsx";
|
|
77
|
+
export type { AiTextAreaProps, AiTextFieldProps, BooleanFieldProps, ComparisonMetric, DateFieldProps, DrawerProps, FeedRow, FileFieldProps, FloatingPanelGeometry, FloatingPanelProps, InfinityListProps, InfinityListSelection, ModeSwitchVariant, NumberFieldProps, PhotoSlotSpec, PhotoSlotsProps, PlanCardActionSlot, PlanCardLinkSlot, PlanCardPrice, PlanCardProps, PlanGridProps, ProgressListRow, PublicShellProps, PublicShellVariant, QueryTableColumn, QueryTableProps, RangeFieldProps, ResultColumn, SelectFieldProps, SideBySideTableCell, SideBySideTableColumn, SideBySideTableRow, StatDelta, StatTone, StatusBadgeTone, StatusBarEntry, StatusTone, TextareaFieldProps, TextFieldProps, TimeseriesHeight, TimeseriesPoint, TimeseriesReferenceLine, TimeseriesXAxis, TimeseriesYAxis, UploadZoneProps, } from "./widgets/index.ts";
|
|
78
|
+
export { AiTextArea, AiTextField, BooleanField, CollapsibleSection, ComparisonTable, DateField, DetailList, Drawer, EmptyState, ErrorState, FeedList, FileField, FloatingPanel, InfinityList, LoadingState, MiniStat, ModeSwitch, MoneyField, NumberField, PercentField, PhotoSlots, PlanCard, PlanGrid, ProgressBar, ProgressList, PublicShell, QueryTable, RangeField, ResultPanel, ResultTable, SectionCard, SelectField, SideBySideTable, Sparkline, STATUS_TONE_TEXT, StatCard, StatusBadge, StatusBarChart, StepBar, smoothPath, TextareaField, TextField, TimeseriesChart, UploadZone, useDraft, } from "./widgets/index.ts";
|
|
@@ -0,0 +1,53 @@
|
|
|
1
|
+
// Public entry of @cosmicdrift/kumiko-renderer/web. Re-exports the shared API
|
|
2
|
+
// of the renderer root so samples import one entry, and adds the web-specific
|
|
3
|
+
// helpers: createKumikoApp (react-dom bootstrap), defaultPrimitives (HTML),
|
|
4
|
+
// useBrowserNavApi (window.history), createEventSourceLiveEvents, KumikoLink.
|
|
5
|
+
export { createStaticLocaleResolver, cssVarTokens, DispatcherProvider, formatPath, KumikoScreen, LiveEventsProvider, LocaleProvider, NavProvider, PrimitivesProvider, parsePath, qualifyScreenId, RenderEdit, RenderField, RenderList, synthesizeActionFormEntity, synthesizeActionFormScreen, TokensProvider, UserRolesProvider, useDispatcher, useDispatcherStatus, useForm, useLiveEvents, useLocale, useNav, usePrimitives, useQuery, useStore, useStoreSelector, useTokenController, useTokens, useTranslation, useUserRoles, } from "../index.js";
|
|
6
|
+
// --- Web-platform specifics ---
|
|
7
|
+
export { BROWSER_LOCALE_STORAGE_KEY, createBrowserLocaleResolver, } from "./app/browser-locale.js";
|
|
8
|
+
export { createKumikoApp } from "./app/create-app.js";
|
|
9
|
+
export { createPublicSurface } from "./app/create-public-surface.js";
|
|
10
|
+
export { createBrowserDraftStorage } from "./app/draft-storage.js";
|
|
11
|
+
export { KumikoLink, useBrowserNavApi } from "./app/nav.js";
|
|
12
|
+
export { PlainContentEditor } from "./app/plain-content-editor.js";
|
|
13
|
+
export { useResolvers } from "./app/resolvers-context.js";
|
|
14
|
+
export { RichContentEditor } from "./app/rich-content-editor.js";
|
|
15
|
+
export { Icon } from "./icons.js";
|
|
16
|
+
export { AppLayout } from "./layout/app-layout.js";
|
|
17
|
+
export { Avatar } from "./layout/avatar.js";
|
|
18
|
+
export { DefaultAppShell } from "./layout/default-app-shell.js";
|
|
19
|
+
export { EditorPanel } from "./layout/editor-panel.js";
|
|
20
|
+
export { filterAppSchemaNavsByAllowlist, reparentAppSchemaNavs, } from "./layout/filter-app-schema-navs.js";
|
|
21
|
+
export { HeaderActionGroup } from "./layout/header-action-group.js";
|
|
22
|
+
export { LanguageMenuItems } from "./layout/language-menu-items.js";
|
|
23
|
+
export { LanguageSwitcher } from "./layout/language-switcher.js";
|
|
24
|
+
export { buildNavRegistrySlice, buildNavRegistrySliceForApp, NavTree } from "./layout/nav-tree.js";
|
|
25
|
+
export { ProfileMenu } from "./layout/profile-menu.js";
|
|
26
|
+
export { Sidebar } from "./layout/sidebar.js";
|
|
27
|
+
export { SidebarBrand } from "./layout/sidebar-brand.js";
|
|
28
|
+
export { SidebarPanel } from "./layout/sidebar-panel.js";
|
|
29
|
+
export { SidebarUser } from "./layout/sidebar-user.js";
|
|
30
|
+
export { parseTargetFromSearchParams } from "./layout/target-url.js";
|
|
31
|
+
export { ThemeMenuItem } from "./layout/theme-menu-item.js";
|
|
32
|
+
export { ThemeToggle } from "./layout/theme-toggle.js";
|
|
33
|
+
export { Topbar } from "./layout/topbar.js";
|
|
34
|
+
export { filterByAccess, resolveDefaultId, WorkspaceShell } from "./layout/workspace-shell.js";
|
|
35
|
+
export { WorkspaceSwitcher } from "./layout/workspace-switcher.js";
|
|
36
|
+
export { cn } from "./lib/cn.js";
|
|
37
|
+
export { postWithDownload } from "./lib/download.js";
|
|
38
|
+
export { downloadFileRef, FileDownloadFailedError, fetchFileRefBlob, fileNameFromContentDisposition, saveBlobAsFile, } from "./lib/file-ref-download.js";
|
|
39
|
+
export { buildFileUploadFormData } from "./lib/file-upload-form-data.js";
|
|
40
|
+
export { FileUploadFailedError, uploadFileRef } from "./lib/upload-file-ref.js";
|
|
41
|
+
export { ActionMenu } from "./primitives/action-menu.js";
|
|
42
|
+
export { DropdownMenu, DropdownMenuCheckboxItem, DropdownMenuContent, DropdownMenuItem, DropdownMenuLabel, DropdownMenuPortal, DropdownMenuSeparator, DropdownMenuTrigger, } from "./primitives/dropdown-menu.js";
|
|
43
|
+
export { BareFormProvider, DefaultCard as Card, defaultPrimitives, FormScreenShell, ScreenWidthProvider, } from "./primitives/index.js";
|
|
44
|
+
export { PageSection, Stack } from "./primitives/layout.js";
|
|
45
|
+
export { formatMoney } from "./primitives/money-input.js";
|
|
46
|
+
export { ToastProvider, useToast } from "./primitives/toast.js";
|
|
47
|
+
export { useIsNarrowViewport, useIsViewportBelow } from "./primitives/use-narrow-viewport.js";
|
|
48
|
+
export { createEventSourceLiveEvents } from "./sse/live-events.js";
|
|
49
|
+
export { applyTokensToCssVars, defaultTokens, lightTokens, useBrowserTokensApi, } from "./tokens.js";
|
|
50
|
+
export { ResizableHandle, ResizablePanel, ResizablePanelGroup } from "./ui/resizable.js";
|
|
51
|
+
export { SidebarMenu, SidebarMenuButton, SidebarMenuItem, SidebarProvider } from "./ui/sidebar.js";
|
|
52
|
+
export { readLoadedBuild } from "./version/update-checker.js";
|
|
53
|
+
export { AiTextArea, AiTextField, BooleanField, CollapsibleSection, ComparisonTable, DateField, DetailList, Drawer, EmptyState, ErrorState, FeedList, FileField, FloatingPanel, InfinityList, LoadingState, MiniStat, ModeSwitch, MoneyField, NumberField, PercentField, PhotoSlots, PlanCard, PlanGrid, ProgressBar, ProgressList, PublicShell, QueryTable, RangeField, ResultPanel, ResultTable, SectionCard, SelectField, SideBySideTable, Sparkline, STATUS_TONE_TEXT, StatCard, StatusBadge, StatusBarChart, StepBar, smoothPath, TextareaField, TextField, TimeseriesChart, UploadZone, useDraft, } from "./widgets/index.js";
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
import type { ReactNode } from "react";
|
|
2
|
+
export type AppLayoutProps = {
|
|
3
|
+
/** Optional. Lebt nur über dem Main-Bereich, nicht über der Sidebar. */
|
|
4
|
+
readonly topbar?: ReactNode;
|
|
5
|
+
readonly sidebar?: ReactNode;
|
|
6
|
+
readonly children: ReactNode;
|
|
7
|
+
readonly testId?: string;
|
|
8
|
+
/** Viewport-fit Shell. Default `true` → Wurzel = `h-screen` (fixe
|
|
9
|
+
* Viewport-Höhe), Sidebar/Topbar bleiben stehen, der Main-Bereich
|
|
10
|
+
* scrollt INNEN (`min-h-0` + `overflow-auto`). `false` → klassischer
|
|
11
|
+
* `min-h-screen`-Flow, die ganze Seite scrollt — Escape-Hatch für
|
|
12
|
+
* eine öffentliche, lange Content-Seite die echten Body-Scroll
|
|
13
|
+
* braucht. Clippt nie — der Content scrollt in `main` statt im Body. */
|
|
14
|
+
readonly fill?: boolean;
|
|
15
|
+
/** Optionaler Klassen-Append an die Wurzel (eigener Hintergrund etc.).
|
|
16
|
+
* Erweitert die Defaults, ersetzt sie nicht (cn-merge). */
|
|
17
|
+
readonly className?: string;
|
|
18
|
+
/** Optionaler Klassen-Append an `<main>`. */
|
|
19
|
+
readonly mainClassName?: string;
|
|
20
|
+
};
|
|
21
|
+
export declare function AppLayout({ topbar, sidebar, children, testId, fill, className, mainClassName, }: AppLayoutProps): ReactNode;
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
2
|
+
import { cn } from "../lib/cn.js";
|
|
3
|
+
export function AppLayout({ topbar, sidebar, children, testId, fill = true, className, mainClassName, }) {
|
|
4
|
+
return (_jsxs("div", { "data-testid": testId, "data-kumiko-layout": "app", ...(fill === true && { "data-kumiko-fill": "true" }), className: cn(
|
|
5
|
+
// new-york inset-Frame: gedämpfter Rail-Background, die Sidebar sitzt
|
|
6
|
+
// transparent darauf, der Main-Bereich schwebt als eigenes Panel.
|
|
7
|
+
"flex flex-row bg-muted/40 text-foreground", fill === true ? "h-screen" : "min-h-screen", className), children: [sidebar, _jsxs("div", { className: cn("flex flex-1 min-w-0 flex-col overflow-hidden rounded-xl border bg-background shadow-sm m-2 md:ml-0", fill === true && "min-h-0"), children: [topbar, _jsx("main", { className: cn("flex-1 overflow-auto", fill === true && "min-h-0", mainClassName), children: children })] })] }));
|
|
8
|
+
}
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
import { type ReactNode } from "react";
|
|
2
|
+
export type AvatarSize = "sm" | "md" | "lg";
|
|
3
|
+
export type AvatarProps = {
|
|
4
|
+
/** Stable Identifier — Hash-Quelle für die Background-Farbe. Üblich
|
|
5
|
+
* user.id; bei rein labelbasierten Avataren auch der label-String. */
|
|
6
|
+
readonly id: string;
|
|
7
|
+
/** Voller Name oder Email — Initials werden daraus extrahiert. */
|
|
8
|
+
readonly label: string;
|
|
9
|
+
readonly size?: AvatarSize;
|
|
10
|
+
readonly testId?: string;
|
|
11
|
+
};
|
|
12
|
+
export declare function Avatar({ id, label, size, testId }: AvatarProps): ReactNode;
|
|
@@ -0,0 +1,63 @@
|
|
|
1
|
+
import { jsx as _jsx } from "react/jsx-runtime";
|
|
2
|
+
// Avatar-Pill mit Initials. Color-coded background basierend auf
|
|
3
|
+
// string-hash damit der gleiche User immer dieselbe Farbe bekommt
|
|
4
|
+
// (Linear-Pattern). 8 Hue-Targets für gute Distinktion ohne über-
|
|
5
|
+
// bunte Sidebar.
|
|
6
|
+
//
|
|
7
|
+
// Nutzung: `<Avatar id="user-123" label="Daniel Hennig" size="md" />`.
|
|
8
|
+
// `id` ist die Hash-Quelle für die Farbe; `label` wird für Initials
|
|
9
|
+
// + aria-label genutzt. Kein Image-Slot im MVP — kommt wenn Apps
|
|
10
|
+
// echte Avatar-URLs haben.
|
|
11
|
+
import { useMemo } from "react";
|
|
12
|
+
import { cn } from "../lib/cn.js";
|
|
13
|
+
// Tailwind-Klassen pro Hue. Die Background-Lightness ist dezent (550-
|
|
14
|
+
// 600 für saturation), die Foreground-Lightness ist hell (50-100) für
|
|
15
|
+
// Kontrast. Passt zu beiden Modes weil die Tokens via CSS-vars greifen
|
|
16
|
+
// — aber: feste hex-Farben hier sind stabiler als token-mapping
|
|
17
|
+
// (Avatar-Farbe sollte deterministic sein, nicht theme-abhängig).
|
|
18
|
+
const COLOR_CLASSES = [
|
|
19
|
+
"bg-rose-600 text-rose-50",
|
|
20
|
+
"bg-orange-600 text-orange-50",
|
|
21
|
+
"bg-amber-600 text-amber-50",
|
|
22
|
+
"bg-emerald-600 text-emerald-50",
|
|
23
|
+
"bg-teal-600 text-teal-50",
|
|
24
|
+
"bg-sky-600 text-sky-50",
|
|
25
|
+
"bg-indigo-600 text-indigo-50",
|
|
26
|
+
"bg-fuchsia-600 text-fuchsia-50",
|
|
27
|
+
];
|
|
28
|
+
const SIZE_CLASSES = {
|
|
29
|
+
sm: "size-5 text-[10px]",
|
|
30
|
+
md: "size-6 text-[11px]",
|
|
31
|
+
lg: "size-8 text-xs",
|
|
32
|
+
};
|
|
33
|
+
function hashCode(str) {
|
|
34
|
+
// djb2-Variante — schnell, deterministic, gut genug verteilt für
|
|
35
|
+
// 8 Buckets. Crypto-Hash wäre Overkill für color-bucketing.
|
|
36
|
+
let hash = 5381;
|
|
37
|
+
for (let i = 0; i < str.length; i++) {
|
|
38
|
+
hash = ((hash << 5) + hash + str.charCodeAt(i)) >>> 0;
|
|
39
|
+
}
|
|
40
|
+
return hash;
|
|
41
|
+
}
|
|
42
|
+
function pickColor(id) {
|
|
43
|
+
const idx = hashCode(id) % COLOR_CLASSES.length;
|
|
44
|
+
return COLOR_CLASSES[idx] ?? COLOR_CLASSES[0] ?? "bg-muted";
|
|
45
|
+
}
|
|
46
|
+
function extractInitials(label) {
|
|
47
|
+
// "Daniel Hennig" → "DH". "alice@example.com" → "AL". Single-word
|
|
48
|
+
// fällt auf erste 2 Buchstaben zurück ("Daniel" → "DA"). Alles
|
|
49
|
+
// upper-case.
|
|
50
|
+
const trimmed = label.trim();
|
|
51
|
+
if (trimmed.length === 0)
|
|
52
|
+
return "?";
|
|
53
|
+
const parts = trimmed.split(/\s+/);
|
|
54
|
+
if (parts.length >= 2) {
|
|
55
|
+
return `${(parts[0]?.[0] ?? "").toUpperCase()}${(parts[1]?.[0] ?? "").toUpperCase()}`;
|
|
56
|
+
}
|
|
57
|
+
return trimmed.slice(0, 2).toUpperCase();
|
|
58
|
+
}
|
|
59
|
+
export function Avatar({ id, label, size = "md", testId }) {
|
|
60
|
+
const colorClass = useMemo(() => pickColor(id), [id]);
|
|
61
|
+
const initials = useMemo(() => extractInitials(label), [label]);
|
|
62
|
+
return (_jsx("span", { "data-testid": testId, role: "img", "aria-label": label, className: cn("inline-flex items-center justify-center rounded font-semibold uppercase select-none", SIZE_CLASSES[size], colorClass), children: initials }));
|
|
63
|
+
}
|
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
import type { ReactNode } from "react";
|
|
2
|
+
import { type AppSchema, type FeatureSchema } from "../../index.ts";
|
|
3
|
+
export type DefaultAppShellUser = {
|
|
4
|
+
readonly id: string;
|
|
5
|
+
readonly roles: readonly string[];
|
|
6
|
+
};
|
|
7
|
+
export type DefaultAppShellProps = {
|
|
8
|
+
/** Header-Slot oben in der Sidebar — Workspace-Identity (Logo, Name,
|
|
9
|
+
* Plan-Tag). Caller liefert frei. */
|
|
10
|
+
readonly brand: ReactNode;
|
|
11
|
+
/** Schema (AppSchema oder legacy FeatureSchema) wird an NavTree
|
|
12
|
+
* durchgereicht; Sidebar-Einträge bauen sich automatisch aus
|
|
13
|
+
* schema.navs (per-Feature) auf. */
|
|
14
|
+
readonly schema: AppSchema | FeatureSchema;
|
|
15
|
+
/** Current user — drives nav role-gating. Ohne user-prop werden
|
|
16
|
+
* role-gated nav-einträge (`access: { roles: [...] }`) komplett
|
|
17
|
+
* ausgeblendet (resolveNavigation behandelt undefined-user als
|
|
18
|
+
* anonymous). */
|
|
19
|
+
readonly user?: DefaultAppShellUser;
|
|
20
|
+
/** Icon-Row zwischen Brand und NavTree — typisch Search-Trigger,
|
|
21
|
+
* ThemeToggle, TenantSwitcher. */
|
|
22
|
+
readonly sidebarActions?: ReactNode;
|
|
23
|
+
/** Runtime-Badges pro Nav-Item (bare nav-id → ReactNode), an NavTree
|
|
24
|
+
* durchgereicht. Für Tier-/Status-Badges, die die App pro User liefert
|
|
25
|
+
* (Wert + Farbe), statt sie ins statische Schema zu backen. */
|
|
26
|
+
readonly navBadges?: ReadonlyMap<string, ReactNode>;
|
|
27
|
+
/** Rechtsbündiger Slot in der Topbar (neben dem Breadcrumb) — für
|
|
28
|
+
* ThemeToggle, globale Actions o.ä. Spart die eigene sidebarActions-
|
|
29
|
+
* Zeile in der Sidebar. */
|
|
30
|
+
readonly headerActions?: ReactNode;
|
|
31
|
+
/** Footer-Slot unten in der Sidebar — Profile-Row, Help-Link,
|
|
32
|
+
* Plan-Banner. */
|
|
33
|
+
readonly sidebarFooter?: ReactNode;
|
|
34
|
+
/** Viewport-fit Shell. true → fixe Viewport-Höhe (`h-svh`), der Content
|
|
35
|
+
* scrollt INNEN statt der ganzen Seite. Default true — `fill={false}`
|
|
36
|
+
* schaltet zurück auf Seiten-Scroll. */
|
|
37
|
+
readonly fill?: boolean;
|
|
38
|
+
/** Screen-Content der im SidebarInset gerendert wird. */
|
|
39
|
+
readonly children: ReactNode;
|
|
40
|
+
};
|
|
41
|
+
export declare function DefaultAppShell({ brand, schema, user, sidebarActions, headerActions, navBadges, sidebarFooter, fill, children, }: DefaultAppShellProps): ReactNode;
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
2
|
+
import { UserRolesProvider, useTranslation, } from "../../index.js";
|
|
3
|
+
import { Sidebar, SidebarContent, SidebarFooter, SidebarGroup, SidebarHeader, SidebarInset, SidebarProvider, SidebarRail, } from "../ui/sidebar.js";
|
|
4
|
+
import { fillClasses } from "./fill-classes.js";
|
|
5
|
+
import { NavTree } from "./nav-tree.js";
|
|
6
|
+
import { PageHeaderSlotProvider } from "./page-header-slot.js";
|
|
7
|
+
import { ShellHeader } from "./shell-header.js";
|
|
8
|
+
import { SidebarPanelProvider, useSidebarPanelHost } from "./sidebar-panel.js";
|
|
9
|
+
export function DefaultAppShell({ brand, schema, user, sidebarActions, headerActions, navBadges, sidebarFooter, fill = true, children, }) {
|
|
10
|
+
const fillCls = fillClasses(fill);
|
|
11
|
+
const t = useTranslation();
|
|
12
|
+
// Second column only when a screen fills it (sidebar-09 pattern) — otherwise
|
|
13
|
+
// every other screen would carry an empty strip next to the navigation.
|
|
14
|
+
const panel = useSidebarPanelHost();
|
|
15
|
+
return (_jsx(SidebarProvider, { ...fillCls.provider, children: _jsxs(SidebarPanelProvider, { value: panel.value, children: [_jsxs(Sidebar, { collapsible: "icon", mobileTitle: t("kumiko.sidebar.title"), mobileDescription: t("kumiko.sidebar.description"), children: [_jsx(SidebarHeader, { "data-kumiko-layout": "sidebar-header", children: brand }), sidebarActions !== undefined && (_jsx(SidebarGroup, { "data-kumiko-layout": "sidebar-actions", className: "flex-row flex-wrap items-center gap-1 py-0", children: sidebarActions })), _jsx(SidebarContent, { "data-kumiko-layout": "sidebar-nav", children: _jsx(NavTree, { schema: schema, ...(user !== undefined && { user }), ...(navBadges !== undefined && { navBadges }) }) }), sidebarFooter !== undefined && (_jsx(SidebarFooter, { "data-kumiko-layout": "sidebar-footer", className: "border-t border-sidebar-border", children: sidebarFooter })), _jsx(SidebarRail, { "aria-label": t("kumiko.sidebar.toggle"), title: t("kumiko.sidebar.toggle") })] }), _jsx("div", { ref: panel.ref, "data-kumiko-layout": "sidebar-panel", className: panel.occupied ? "flex h-svh shrink-0 flex-col" : "hidden" }), _jsx(SidebarInset, { className: fillCls.inset, children: _jsxs(PageHeaderSlotProvider, { children: [_jsx(ShellHeader, { schema: schema, ...(user !== undefined && { user }), ...(headerActions !== undefined && { headerActions }) }), _jsx("main", { className: fillCls.main, children: _jsx(UserRolesProvider, { roles: user?.roles, children: children }) })] }) })] }) }));
|
|
16
|
+
}
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
import type { TargetRef } from "@cosmicdrift/kumiko-framework/engine";
|
|
2
|
+
import type { ComponentType, ReactNode } from "react";
|
|
3
|
+
export type ResolverComponent = ComponentType<{
|
|
4
|
+
readonly target: TargetRef;
|
|
5
|
+
readonly onClose: () => void;
|
|
6
|
+
}>;
|
|
7
|
+
export type EditorPanelProps = {
|
|
8
|
+
readonly resolvers: ReadonlyMap<string, ResolverComponent>;
|
|
9
|
+
};
|
|
10
|
+
export declare function EditorPanel({ resolvers }: EditorPanelProps): ReactNode;
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
2
|
+
import { X } from "lucide-react";
|
|
3
|
+
import { useCallback, useMemo } from "react";
|
|
4
|
+
import { useNav, usePrimitives, useTranslation } from "../../index.js";
|
|
5
|
+
import { clearTargetSearchParams, parseTargetFromSearchParams } from "./target-url.js";
|
|
6
|
+
function EditorPanelInner({ target, resolvers, onClose, }) {
|
|
7
|
+
const { JsonView } = usePrimitives();
|
|
8
|
+
const t = useTranslation();
|
|
9
|
+
const resolverKey = `${target.featureId}:${target.action}`;
|
|
10
|
+
const Resolver = resolvers.get(resolverKey);
|
|
11
|
+
if (Resolver !== undefined) {
|
|
12
|
+
return _jsx(Resolver, { target: target, onClose: onClose });
|
|
13
|
+
}
|
|
14
|
+
return (_jsxs("div", { className: "flex flex-col gap-4 p-4", children: [_jsxs("div", { className: "flex items-center justify-between", children: [_jsx("h2", { className: "text-lg font-semibold", children: "Editor" }), _jsx("button", { type: "button", "aria-label": t("kumiko.dialog.close"), className: "p-1 hover:bg-accent rounded", onClick: onClose, children: _jsx(X, { className: "size-4" }) })] }), _jsxs("div", { className: "text-sm text-muted-foreground space-y-2", children: [_jsxs("p", { children: ["Kein Editor f\u00FCr", " ", _jsxs("code", { children: [target.featureId, ":", target.action] }), " ", "registriert."] }), JsonView !== undefined ? (_jsx(JsonView, { value: target.args })) : (_jsx("pre", { className: "bg-muted p-2 rounded text-xs overflow-auto", children: JSON.stringify(target.args, null, 2) }))] })] }));
|
|
15
|
+
}
|
|
16
|
+
export function EditorPanel({ resolvers }) {
|
|
17
|
+
const nav = useNav();
|
|
18
|
+
// target derived from URL → F5/Back stellen state wieder her.
|
|
19
|
+
// useMemo stabilisiert reference solange searchParams shallow-gleich
|
|
20
|
+
// sind (nav-Impl liefert plain-record für genau diesen check).
|
|
21
|
+
const target = useMemo(() => parseTargetFromSearchParams(nav.searchParams), [nav.searchParams]);
|
|
22
|
+
const handleClose = useCallback(() => {
|
|
23
|
+
nav.setSearchParams(clearTargetSearchParams(nav.searchParams));
|
|
24
|
+
}, [nav]);
|
|
25
|
+
return (_jsx("div", { "data-kumiko-layout": "editor-main", className: "flex-1 overflow-y-auto", children: target === undefined ? (_jsx(EditorEmptyState, {})) : (_jsx(EditorPanelInner, { target: target, resolvers: resolvers, onClose: handleClose })) }));
|
|
26
|
+
}
|
|
27
|
+
function EditorEmptyState() {
|
|
28
|
+
return (_jsx("div", { className: "flex h-full items-center justify-center p-8 text-sm text-muted-foreground", children: _jsx("p", { children: "W\u00E4hle einen Knoten links zum Bearbeiten." }) }));
|
|
29
|
+
}
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
// Shared `fill`-prop wiring for the sidebar-based app shells
|
|
2
|
+
// (DefaultAppShell, WorkspaceShell) — both wrap the same vendored
|
|
3
|
+
// shadcn sidebar and need identical viewport-fit classes.
|
|
4
|
+
//
|
|
5
|
+
// min-w-0 on the inset is unconditional (not fill-gated): vendored
|
|
6
|
+
// SidebarInset is `flex-1` with no min-width override, so a flex row child
|
|
7
|
+
// never shrinks below its content's intrinsic width by default. Wide screen
|
|
8
|
+
// content (e.g. a table with many columns) then grows the inset — and with
|
|
9
|
+
// it the whole sidebar row and the page — past the viewport instead of
|
|
10
|
+
// scrolling inside the inset's own `main` (which already has overflow-auto).
|
|
11
|
+
export const fillClasses = (fill) => ({
|
|
12
|
+
provider: fill === true ? { className: "h-svh" } : {},
|
|
13
|
+
inset: fill === true ? "min-h-0 min-w-0" : "min-w-0",
|
|
14
|
+
main: fill === true ? "min-h-0 flex-1 overflow-auto" : "flex-1 overflow-auto",
|
|
15
|
+
});
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
import type { AppSchema } from "../../index.ts";
|
|
2
|
+
export type NavReparentOverride = {
|
|
3
|
+
readonly parent: string;
|
|
4
|
+
readonly order: number;
|
|
5
|
+
};
|
|
6
|
+
export declare function reparentAppSchemaNavs(schema: AppSchema, overrides: ReadonlyMap<string, NavReparentOverride>): AppSchema;
|
|
7
|
+
export declare function filterAppSchemaNavsByAllowlist(schema: AppSchema, allowedNavQns: ReadonlySet<string>, reparentOverrides?: ReadonlyMap<string, NavReparentOverride>): AppSchema;
|
|
@@ -0,0 +1,68 @@
|
|
|
1
|
+
import { qualifyNavId } from "./nav-tree.js";
|
|
2
|
+
// Rewrites parent/order of the navs named in `overrides` (keyed by the nav's
|
|
3
|
+
// qualified QN), leaving every other nav and schema field untouched. This is
|
|
4
|
+
// how an app moves a foreign, otherwise-unmodifiable nav (a bundled feature's
|
|
5
|
+
// own entry, a settings-hub-synthesized one) into a group of its own: the
|
|
6
|
+
// boot-validator only lets a feature re-parent navs it registered itself.
|
|
7
|
+
export function reparentAppSchemaNavs(schema, overrides) {
|
|
8
|
+
if (overrides.size === 0)
|
|
9
|
+
return schema;
|
|
10
|
+
return {
|
|
11
|
+
...schema,
|
|
12
|
+
features: schema.features.map((feature) => {
|
|
13
|
+
if (feature.navs === undefined)
|
|
14
|
+
return feature;
|
|
15
|
+
return {
|
|
16
|
+
...feature,
|
|
17
|
+
navs: feature.navs.map((nav) => {
|
|
18
|
+
const override = overrides.get(qualifyNavId(feature.featureName, nav.id));
|
|
19
|
+
return override === undefined
|
|
20
|
+
? nav
|
|
21
|
+
: { ...nav, parent: override.parent, order: override.order };
|
|
22
|
+
}),
|
|
23
|
+
};
|
|
24
|
+
}),
|
|
25
|
+
};
|
|
26
|
+
}
|
|
27
|
+
// Reduces every feature's `navs` to the app's sidebar allowlist, leaving
|
|
28
|
+
// screens/entities/handlers/translations and every other schema field
|
|
29
|
+
// untouched. Pure and defensive: a feature with no `navs` passes through
|
|
30
|
+
// unchanged, and a feature whose every nav gets stripped ends up with an
|
|
31
|
+
// empty `navs` array, never `undefined` turned into something broken.
|
|
32
|
+
//
|
|
33
|
+
// An allowed nav whose parent exists but is not on the allowlist (and which has
|
|
34
|
+
// no reparent override) loses its `parent` and surfaces at the top level, the same
|
|
35
|
+
// as with `allowedNavQns` in buildNavRegistrySliceForApp; without that,
|
|
36
|
+
// dropNavsWithNonexistentParent would drop it silently.
|
|
37
|
+
//
|
|
38
|
+
// `reparentOverrides` re-parents the surviving navs (see reparentAppSchemaNavs).
|
|
39
|
+
export function filterAppSchemaNavsByAllowlist(schema, allowedNavQns, reparentOverrides = new Map()) {
|
|
40
|
+
const existingNavQns = new Set(schema.features.flatMap((feature) => (feature.navs ?? []).map((nav) => qualifyNavId(feature.featureName, nav.id))));
|
|
41
|
+
const parentFilteredOut = (featureName, nav) => {
|
|
42
|
+
if (nav.parent === undefined)
|
|
43
|
+
return false;
|
|
44
|
+
const parentQn = qualifyNavId(featureName, nav.parent);
|
|
45
|
+
return existingNavQns.has(parentQn) && !allowedNavQns.has(parentQn);
|
|
46
|
+
};
|
|
47
|
+
const allowed = {
|
|
48
|
+
...schema,
|
|
49
|
+
features: schema.features.map((feature) => {
|
|
50
|
+
if (feature.navs === undefined)
|
|
51
|
+
return feature;
|
|
52
|
+
return {
|
|
53
|
+
...feature,
|
|
54
|
+
navs: feature.navs
|
|
55
|
+
.filter((nav) => allowedNavQns.has(qualifyNavId(feature.featureName, nav.id)))
|
|
56
|
+
.map((nav) => parentFilteredOut(feature.featureName, nav) &&
|
|
57
|
+
!reparentOverrides.has(qualifyNavId(feature.featureName, nav.id))
|
|
58
|
+
? withoutParent(nav)
|
|
59
|
+
: nav),
|
|
60
|
+
};
|
|
61
|
+
}),
|
|
62
|
+
};
|
|
63
|
+
return reparentAppSchemaNavs(allowed, reparentOverrides);
|
|
64
|
+
}
|
|
65
|
+
function withoutParent(nav) {
|
|
66
|
+
const { parent: _filteredOutParent, ...topLevelNav } = nav;
|
|
67
|
+
return topLevelNav;
|
|
68
|
+
}
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
import { jsx as _jsx } from "react/jsx-runtime";
|
|
2
|
+
import { useContext } from "react";
|
|
3
|
+
import { cn } from "../lib/cn.js";
|
|
4
|
+
import { HeaderOverflowMenuContext } from "./header-overflow-menu.js";
|
|
5
|
+
export function HeaderActionGroup({ children, className }) {
|
|
6
|
+
const inOverflowMenu = useContext(HeaderOverflowMenuContext);
|
|
7
|
+
return (_jsx("div", { className: cn(inOverflowMenu ? "flex flex-col items-stretch gap-1" : "flex items-center gap-2", className), children: children }));
|
|
8
|
+
}
|
|
@@ -0,0 +1,4 @@
|
|
|
1
|
+
/** True for nodes rendered inside the phone header overflow menu, so controls
|
|
2
|
+
* like ThemeToggle can draw a labelled menu row instead of an icon button. */
|
|
3
|
+
export declare const HeaderOverflowMenuContext: import("react").Context<boolean>;
|
|
4
|
+
export declare const headerOverflowMenuItemClass: string;
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
import { createContext } from "react";
|
|
2
|
+
/** True for nodes rendered inside the phone header overflow menu, so controls
|
|
3
|
+
* like ThemeToggle can draw a labelled menu row instead of an icon button. */
|
|
4
|
+
export const HeaderOverflowMenuContext = createContext(false);
|
|
5
|
+
// Mirrors the DropdownMenuItem look in primitives/dropdown-menu.tsx, with a 40px touch target.
|
|
6
|
+
export const headerOverflowMenuItemClass = "relative flex min-h-10 w-full cursor-default select-none items-center gap-2 rounded-sm px-2 py-1.5 text-left text-sm " +
|
|
7
|
+
"outline-none transition-colors hover:bg-accent focus:bg-accent focus:text-accent-foreground " +
|
|
8
|
+
"disabled:pointer-events-none disabled:opacity-50";
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
import { type ReactNode } from "react";
|
|
2
|
+
import type { LocaleOption } from "./language-switcher.tsx";
|
|
3
|
+
export type LanguageMenuItemsProps = {
|
|
4
|
+
readonly locales: readonly LocaleOption[];
|
|
5
|
+
readonly label?: string;
|
|
6
|
+
};
|
|
7
|
+
/** Locale choices as dropdown entries, for a user menu that carries the shell controls. */
|
|
8
|
+
export declare function LanguageMenuItems({ locales, label }: LanguageMenuItemsProps): ReactNode;
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
import { Fragment as _Fragment, jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
2
|
+
import { useMemo } from "react";
|
|
3
|
+
import { useLocale, useTranslation } from "../../index.js";
|
|
4
|
+
import { DropdownMenuCheckboxItem, DropdownMenuLabel, DropdownMenuSeparator, } from "../primitives/dropdown-menu.js";
|
|
5
|
+
/** Locale choices as dropdown entries, for a user menu that carries the shell controls. */
|
|
6
|
+
export function LanguageMenuItems({ locales, label }) {
|
|
7
|
+
const resolver = useLocale();
|
|
8
|
+
const t = useTranslation();
|
|
9
|
+
const activeLocale = resolver.locale();
|
|
10
|
+
const activeOption = useMemo(() => locales.find((o) => o.code === activeLocale) ??
|
|
11
|
+
locales.find((o) => o.code === activeLocale.split("-")[0]), [locales, activeLocale]);
|
|
12
|
+
const setLocale = resolver.setLocale;
|
|
13
|
+
if (setLocale === undefined)
|
|
14
|
+
return null;
|
|
15
|
+
return (_jsxs(_Fragment, { children: [_jsx(DropdownMenuLabel, { children: label ?? t("kumiko.nav.language") }), locales.map((option) => (_jsx(DropdownMenuCheckboxItem, { checked: option === activeOption, onSelect: () => setLocale(option.code), children: _jsx("span", { className: "truncate", children: option.label }) }, option.code))), _jsx(DropdownMenuSeparator, {})] }));
|
|
16
|
+
}
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
import { type ReactNode } from "react";
|
|
2
|
+
export type LocaleOption = {
|
|
3
|
+
/** BCP-47 code, e.g. "de", "en-US", "fr-CA". Passed through 1:1 to
|
|
4
|
+
* resolver.setLocale(). */
|
|
5
|
+
readonly code: string;
|
|
6
|
+
/** Human-readable label shown in the dropdown. */
|
|
7
|
+
readonly label: string;
|
|
8
|
+
};
|
|
9
|
+
export type LanguageSwitcherProps = {
|
|
10
|
+
/** Selectable locales. Order = display order in the menu. */
|
|
11
|
+
readonly locales: readonly LocaleOption[];
|
|
12
|
+
/** Icon slot left of the button label. Default: 🌐. */
|
|
13
|
+
readonly icon?: ReactNode;
|
|
14
|
+
/** aria-label + title of the trigger. Default: translated "kumiko.nav.language". */
|
|
15
|
+
readonly label?: string;
|
|
16
|
+
/** What the trigger shows next to the icon: the uppercase code (default), the active
|
|
17
|
+
* locale's label, or the icon only. aria-label/title are unaffected. */
|
|
18
|
+
readonly triggerContent?: "code" | "label" | "icon-only";
|
|
19
|
+
/** `default`: icon plus code/label button. `chip`: compact monospace chip with
|
|
20
|
+
* the uppercase code in a border; `icon` and `triggerContent` are ignored. */
|
|
21
|
+
readonly variant?: "default" | "chip";
|
|
22
|
+
readonly testId?: string;
|
|
23
|
+
};
|
|
24
|
+
export declare const LANDMARK_SELECTOR = "header, footer, nav, main, aside, section[aria-label], section[aria-labelledby], [role='banner'], [role='contentinfo'], [role='navigation'], [role='main'], [role='complementary'], [role='region']";
|
|
25
|
+
export declare function LanguageSwitcher({ locales, icon, label, triggerContent, variant, testId, }: LanguageSwitcherProps): ReactNode;
|
|
@@ -0,0 +1,46 @@
|
|
|
1
|
+
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
2
|
+
// LanguageSwitcher — dropdown that switches the app locale via
|
|
3
|
+
// LocaleResolver.setLocale. Built on Radix DropdownMenu, same stack
|
|
4
|
+
// as UserMenu/TenantSwitcher.
|
|
5
|
+
//
|
|
6
|
+
// Renders nothing if the resolver doesn't offer a setLocale method
|
|
7
|
+
// (static resolver) — the app dev then immediately sees they need to
|
|
8
|
+
// wire up a stateful resolver before the switcher becomes visible in
|
|
9
|
+
// the UI.
|
|
10
|
+
//
|
|
11
|
+
// Icon slot is optional: the framework doesn't pull in lucide-react
|
|
12
|
+
// itself; an app that doesn't want an icon import gets the globe
|
|
13
|
+
// unicode glyph (🌐) as default.
|
|
14
|
+
import { useMemo, useState } from "react";
|
|
15
|
+
import { useLocale, useTranslation } from "../../index.js";
|
|
16
|
+
import { cn } from "../lib/cn.js";
|
|
17
|
+
import { DropdownMenu, DropdownMenuCheckboxItem, DropdownMenuContent, DropdownMenuTrigger, } from "../primitives/dropdown-menu.js";
|
|
18
|
+
export const LANDMARK_SELECTOR = "header, footer, nav, main, aside, section[aria-label], section[aria-labelledby], [role='banner'], [role='contentinfo'], [role='navigation'], [role='main'], [role='complementary'], [role='region']";
|
|
19
|
+
export function LanguageSwitcher({ locales, icon = "🌐", label, triggerContent = "code", variant = "default", testId, }) {
|
|
20
|
+
const resolver = useLocale();
|
|
21
|
+
const t = useTranslation();
|
|
22
|
+
const resolvedLabel = label ?? t("kumiko.nav.language");
|
|
23
|
+
// Portal into the surrounding landmark: content under document.body would sit outside every
|
|
24
|
+
// landmark and fail axe's "region" rule.
|
|
25
|
+
const [trigger, setTrigger] = useState(null);
|
|
26
|
+
const landmark = trigger?.closest(LANDMARK_SELECTOR);
|
|
27
|
+
const activeLocale = resolver.locale();
|
|
28
|
+
// Matches either exact ("de-DE") or the language root ("de") against
|
|
29
|
+
// the available options. So the switcher shows "German" active when
|
|
30
|
+
// the browser reports "de-AT" but the option is just "de".
|
|
31
|
+
const activeOption = useMemo(() => {
|
|
32
|
+
const exact = locales.find((o) => o.code === activeLocale);
|
|
33
|
+
if (exact)
|
|
34
|
+
return exact;
|
|
35
|
+
const root = activeLocale.split("-")[0];
|
|
36
|
+
return locales.find((o) => o.code === root);
|
|
37
|
+
}, [locales, activeLocale]);
|
|
38
|
+
if (resolver.setLocale === undefined) {
|
|
39
|
+
// Stateless resolver → no switching possible. No noise in the topbar.
|
|
40
|
+
return null;
|
|
41
|
+
}
|
|
42
|
+
const setLocale = resolver.setLocale;
|
|
43
|
+
return (_jsxs(DropdownMenu, { modal: false, children: [_jsx(DropdownMenuTrigger, { asChild: true, children: _jsxs("button", { ref: setTrigger, type: "button", "aria-label": resolvedLabel, title: resolvedLabel, "data-testid": testId, className: cn("inline-flex items-center border bg-background", "hover:bg-accent hover:text-accent-foreground", "focus-visible:outline-none focus-visible:ring-1 focus-visible:ring-ring", variant === "chip"
|
|
44
|
+
? "h-7 rounded-md px-2 font-mono text-xs text-foreground"
|
|
45
|
+
: "h-8 gap-1.5 rounded-md px-2 text-sm"), children: [variant === "chip" && (activeOption?.code ?? activeLocale.slice(0, 2)).toUpperCase(), variant === "default" && _jsx("span", { "aria-hidden": "true", children: icon }), variant === "default" && triggerContent === "label" && (_jsx("span", { className: "text-xs text-muted-foreground", children: activeOption?.label ?? activeLocale.slice(0, 2) })), variant === "default" && triggerContent === "code" && (_jsx("span", { className: "uppercase text-xs text-muted-foreground", children: activeOption?.code ?? activeLocale.slice(0, 2) }))] }) }), _jsx(DropdownMenuContent, { align: "end", className: "min-w-[10rem]", "aria-label": resolvedLabel, portalContainer: landmark instanceof HTMLElement ? landmark : undefined, children: locales.map((opt) => (_jsx(DropdownMenuCheckboxItem, { checked: opt === activeOption, onSelect: () => setLocale(opt.code), children: _jsx("span", { className: "truncate", children: opt.label }) }, opt.code))) })] }));
|
|
46
|
+
}
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
import { type ReactNode } from "react";
|
|
2
|
+
import type { NavRegistrySlice } from "../../headless/index.ts";
|
|
3
|
+
import type { AppSchema, FeatureSchema } from "../../index.ts";
|
|
4
|
+
import { lastSegment } from "../../index.ts";
|
|
5
|
+
export type NavTreeProps = {
|
|
6
|
+
readonly schema: AppSchema | FeatureSchema;
|
|
7
|
+
readonly user?: {
|
|
8
|
+
readonly id: string;
|
|
9
|
+
readonly roles: readonly string[];
|
|
10
|
+
};
|
|
11
|
+
readonly testId?: string;
|
|
12
|
+
readonly allowedNavQns?: ReadonlySet<string>;
|
|
13
|
+
readonly navBadges?: ReadonlyMap<string, ReactNode>;
|
|
14
|
+
};
|
|
15
|
+
export declare function NavTree({ schema, user, testId, allowedNavQns, navBadges, }: NavTreeProps): ReactNode;
|
|
16
|
+
export declare function buildNavRegistrySlice(schema: FeatureSchema, allowedNavQns?: ReadonlySet<string>): NavRegistrySlice;
|
|
17
|
+
export declare function buildNavRegistrySliceForApp(app: AppSchema, allowedNavQns?: ReadonlySet<string>): NavRegistrySlice;
|
|
18
|
+
export declare function qualifyNavId(feature: string, id: string): string;
|
|
19
|
+
export { lastSegment };
|