@cosmicdrift/kumiko-renderer 0.373.0 → 0.377.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +2 -2
- package/dist/app/action-form-support.d.ts +58 -0
- package/dist/app/action-form-support.js +96 -0
- package/dist/app/client-actions.d.ts +46 -0
- package/dist/app/client-actions.js +60 -0
- package/dist/app/column-renderers.js +1 -1
- package/dist/app/config-edit-shim.js +1 -1
- package/dist/app/content-preview.js +1 -6
- package/dist/app/custom-screens.js +1 -1
- package/dist/app/dashboard-body.d.ts +1 -1
- package/dist/app/entity-list-expanded-row.d.ts +1 -1
- package/dist/app/entity-list-expanded-row.js +4 -0
- package/dist/app/form-schema.d.ts +1 -1
- package/dist/app/form-schema.js +2 -2
- package/dist/app/header-actions-bar.d.ts +19 -0
- package/dist/app/header-actions-bar.js +30 -0
- package/dist/app/kumiko-screen.d.ts +1 -1
- package/dist/app/kumiko-screen.js +134 -66
- package/dist/app/list-empty-content.d.ts +2 -2
- package/dist/app/list-empty-content.js +3 -2
- package/dist/app/list-facets.d.ts +1 -1
- package/dist/app/nav.js +2 -2
- package/dist/app/query-state-banners.d.ts +1 -1
- package/dist/app/reference-link.d.ts +1 -1
- package/dist/app/row-actions.d.ts +10 -2
- package/dist/app/row-actions.js +85 -6
- package/dist/app/secret-mint-body.d.ts +1 -1
- package/dist/app/secrets-edit-body.d.ts +1 -1
- package/dist/app/use-record-actions.d.ts +12 -0
- package/dist/app/use-record-actions.js +30 -0
- package/dist/app/write-failed-error.d.ts +1 -1
- package/dist/components/availability-options-select.d.ts +1 -1
- package/dist/components/embedded-list-field.d.ts +1 -1
- package/dist/components/embedded-list-field.js +1 -1
- package/dist/components/file-list-field.d.ts +1 -1
- package/dist/components/grid-cell-for-field.d.ts +4 -2
- package/dist/components/grid-cell-for-field.js +2 -2
- package/dist/components/multi-select-checkboxes.d.ts +1 -1
- package/dist/components/multi-select-checkboxes.js +1 -1
- package/dist/components/query-options-select.d.ts +1 -1
- package/dist/components/related-list-section.d.ts +1 -1
- package/dist/components/related-list-section.js +16 -3
- package/dist/components/render-edit-logic.d.ts +1 -1
- package/dist/components/render-edit-types.d.ts +2 -2
- package/dist/components/render-edit.d.ts +1 -1
- package/dist/components/render-edit.js +5 -3
- package/dist/components/render-field.d.ts +5 -2
- package/dist/components/render-field.js +103 -9
- package/dist/components/render-list.d.ts +1 -1
- package/dist/components/render-list.js +20 -4
- package/dist/components/write-form-section.d.ts +1 -1
- package/dist/components/write-form-section.js +1 -1
- package/dist/context/dispatcher-context.d.ts +1 -1
- package/dist/format-when.js +1 -1
- package/dist/headless/apex/css.d.ts +3 -0
- package/dist/headless/apex/css.js +298 -0
- package/dist/headless/apex/index.d.ts +236 -0
- package/dist/headless/apex/index.js +377 -0
- package/dist/headless/apex/lightbox.d.ts +4 -0
- package/dist/headless/apex/lightbox.js +81 -0
- package/dist/headless/contracts/asset.d.ts +15 -0
- package/dist/headless/contracts/asset.js +17 -0
- package/dist/headless/contracts/index.d.ts +3 -0
- package/dist/headless/contracts/index.js +1 -0
- package/dist/headless/contracts/locale.d.ts +7 -0
- package/dist/headless/contracts/locale.js +11 -0
- package/dist/headless/contracts/primitives.d.ts +93 -0
- package/dist/headless/contracts/primitives.js +21 -0
- package/dist/headless/dispatcher/index.d.ts +2 -0
- package/dist/headless/dispatcher/index.js +1 -0
- package/dist/headless/dispatcher/types.d.ts +86 -0
- package/dist/headless/dispatcher/types.js +34 -0
- package/dist/headless/form/form-controller.d.ts +2 -0
- package/dist/headless/form/form-controller.js +409 -0
- package/dist/headless/form/index.d.ts +3 -0
- package/dist/headless/form/index.js +2 -0
- package/dist/headless/form/types.d.ts +76 -0
- package/dist/headless/form/types.js +1 -0
- package/dist/headless/form/zod-bridge.d.ts +10 -0
- package/dist/headless/form/zod-bridge.js +103 -0
- package/dist/headless/format/document-values.d.ts +12 -0
- package/dist/headless/format/document-values.js +70 -0
- package/dist/headless/format/escape.d.ts +5 -0
- package/dist/headless/format/escape.js +75 -0
- package/dist/headless/format/html-template.d.ts +9 -0
- package/dist/headless/format/html-template.js +39 -0
- package/dist/headless/format/index.d.ts +12 -0
- package/dist/headless/format/index.js +237 -0
- package/dist/headless/format/money.d.ts +3 -0
- package/dist/headless/format/money.js +39 -0
- package/dist/headless/index.d.ts +14 -0
- package/dist/headless/index.js +9 -0
- package/dist/headless/locale-routing/index.d.ts +41 -0
- package/dist/headless/locale-routing/index.js +145 -0
- package/dist/headless/nav/index.d.ts +2 -0
- package/dist/headless/nav/index.js +1 -0
- package/dist/headless/nav/resolve.d.ts +2 -0
- package/dist/headless/nav/resolve.js +71 -0
- package/dist/headless/nav/types.d.ts +26 -0
- package/dist/headless/nav/types.js +1 -0
- package/dist/headless/store/create-store.d.ts +2 -0
- package/dist/headless/store/create-store.js +43 -0
- package/dist/headless/store/equality.d.ts +1 -0
- package/dist/headless/store/equality.js +34 -0
- package/dist/headless/store/index.d.ts +3 -0
- package/dist/headless/store/index.js +2 -0
- package/dist/headless/store/types.d.ts +7 -0
- package/dist/headless/store/types.js +10 -0
- package/dist/headless/view-model/edit.d.ts +18 -0
- package/dist/headless/view-model/edit.js +501 -0
- package/dist/headless/view-model/embedded-list.d.ts +27 -0
- package/dist/headless/view-model/embedded-list.js +63 -0
- package/dist/headless/view-model/index.d.ts +7 -0
- package/dist/headless/view-model/index.js +3 -0
- package/dist/headless/view-model/list-file-display.d.ts +3 -0
- package/dist/headless/view-model/list-file-display.js +27 -0
- package/dist/headless/view-model/list.d.ts +16 -0
- package/dist/headless/view-model/list.js +229 -0
- package/dist/headless/view-model/types.d.ts +382 -0
- package/dist/headless/view-model/types.js +1 -0
- package/dist/hooks/use-ai-text.d.ts +1 -1
- package/dist/hooks/use-form.d.ts +1 -1
- package/dist/hooks/use-form.js +1 -1
- package/dist/hooks/use-mutation.d.ts +1 -1
- package/dist/hooks/use-query.d.ts +1 -1
- package/dist/hooks/use-store.d.ts +1 -1
- package/dist/hooks/use-store.js +7 -7
- package/dist/hooks/use-stream-handler.d.ts +1 -1
- package/dist/i18n-defaults.js +7 -0
- package/dist/i18n.d.ts +1 -1
- package/dist/i18n.js +1 -1
- package/dist/index.d.ts +5 -1
- package/dist/index.js +7 -4
- package/dist/live/csrf.d.ts +2 -0
- package/dist/live/csrf.js +60 -0
- package/dist/live/dispatcher-live.d.ts +7 -0
- package/dist/live/dispatcher-live.js +286 -0
- package/dist/live/envelopes.d.ts +101 -0
- package/dist/live/envelopes.js +35 -0
- package/dist/live/error-mapping.d.ts +16 -0
- package/dist/live/error-mapping.js +82 -0
- package/dist/live/index.d.ts +7 -0
- package/dist/live/index.js +5 -0
- package/dist/live/locale.d.ts +2 -0
- package/dist/live/locale.js +25 -0
- package/dist/live/sse-stream.d.ts +14 -0
- package/dist/live/sse-stream.js +128 -0
- package/dist/primitives.d.ts +53 -36
- package/dist/primitives.js +1 -1
- package/dist/session/session-ended.d.ts +1 -1
- package/dist/tokens.d.ts +3 -4
- package/dist/tokens.js +4 -5
- package/dist/web/app/app-schema-boot.d.ts +19 -0
- package/dist/web/app/app-schema-boot.js +124 -0
- package/dist/web/app/browser-locale.d.ts +22 -0
- package/dist/web/app/browser-locale.js +78 -0
- package/dist/web/app/client-plugin.d.ts +106 -0
- package/dist/web/app/client-plugin.js +12 -0
- package/dist/web/app/create-app.d.ts +104 -0
- package/dist/web/app/create-app.js +498 -0
- package/dist/web/app/create-public-surface.d.ts +36 -0
- package/dist/web/app/create-public-surface.js +40 -0
- package/dist/web/app/dashboard-body.d.ts +3 -0
- package/dist/web/app/dashboard-body.js +865 -0
- package/dist/web/app/dashboard-refresh.d.ts +6 -0
- package/dist/web/app/dashboard-refresh.js +15 -0
- package/dist/web/app/document-lang-sync.d.ts +4 -0
- package/dist/web/app/document-lang-sync.js +27 -0
- package/dist/web/app/draft-storage.d.ts +11 -0
- package/dist/web/app/draft-storage.js +53 -0
- package/dist/web/app/nav-providers-context.d.ts +13 -0
- package/dist/web/app/nav-providers-context.js +18 -0
- package/dist/web/app/nav.d.ts +40 -0
- package/dist/web/app/nav.js +231 -0
- package/dist/web/app/plain-content-editor.d.ts +3 -0
- package/dist/web/app/plain-content-editor.js +30 -0
- package/dist/web/app/relative-time.d.ts +10 -0
- package/dist/web/app/relative-time.js +56 -0
- package/dist/web/app/resolvers-context.d.ts +12 -0
- package/dist/web/app/resolvers-context.js +10 -0
- package/dist/web/app/rich-content-editor.d.ts +3 -0
- package/dist/web/app/rich-content-editor.js +15 -0
- package/dist/web/app/root-error-fallback.d.ts +2 -0
- package/dist/web/app/root-error-fallback.js +21 -0
- package/dist/web/app/screen-error-fallback.d.ts +6 -0
- package/dist/web/app/screen-error-fallback.js +17 -0
- package/dist/web/app/tiptap-editor.d.ts +3 -0
- package/dist/web/app/tiptap-editor.js +120 -0
- package/dist/web/app/toast-action-notifier.d.ts +5 -0
- package/dist/web/app/toast-action-notifier.js +17 -0
- package/dist/web/components/config-cascade.d.ts +13 -0
- package/dist/web/components/config-cascade.js +155 -0
- package/dist/web/components/config-source-badge.d.ts +6 -0
- package/dist/web/components/config-source-badge.js +55 -0
- package/dist/web/default-color-scheme.d.ts +2 -0
- package/dist/web/default-color-scheme.js +3 -0
- package/dist/web/icons.d.ts +94 -0
- package/dist/web/icons.js +100 -0
- package/dist/web/index.d.ts +78 -0
- package/dist/web/index.js +53 -0
- package/dist/web/layout/app-layout.d.ts +21 -0
- package/dist/web/layout/app-layout.js +8 -0
- package/dist/web/layout/avatar.d.ts +12 -0
- package/dist/web/layout/avatar.js +63 -0
- package/dist/web/layout/default-app-shell.d.ts +41 -0
- package/dist/web/layout/default-app-shell.js +16 -0
- package/dist/web/layout/editor-panel.d.ts +10 -0
- package/dist/web/layout/editor-panel.js +29 -0
- package/dist/web/layout/fill-classes.d.ts +9 -0
- package/dist/web/layout/fill-classes.js +15 -0
- package/dist/web/layout/filter-app-schema-navs.d.ts +7 -0
- package/dist/web/layout/filter-app-schema-navs.js +68 -0
- package/dist/web/layout/header-action-group.d.ts +6 -0
- package/dist/web/layout/header-action-group.js +8 -0
- package/dist/web/layout/header-overflow-menu.d.ts +4 -0
- package/dist/web/layout/header-overflow-menu.js +8 -0
- package/dist/web/layout/language-menu-items.d.ts +8 -0
- package/dist/web/layout/language-menu-items.js +16 -0
- package/dist/web/layout/language-switcher.d.ts +25 -0
- package/dist/web/layout/language-switcher.js +46 -0
- package/dist/web/layout/nav-tree.d.ts +19 -0
- package/dist/web/layout/nav-tree.js +536 -0
- package/dist/web/layout/page-header-slot.d.ts +25 -0
- package/dist/web/layout/page-header-slot.js +50 -0
- package/dist/web/layout/profile-menu.d.ts +13 -0
- package/dist/web/layout/profile-menu.js +6 -0
- package/dist/web/layout/shell-breadcrumb.d.ts +11 -0
- package/dist/web/layout/shell-breadcrumb.js +34 -0
- package/dist/web/layout/shell-header.d.ts +12 -0
- package/dist/web/layout/shell-header.js +159 -0
- package/dist/web/layout/sidebar-brand.d.ts +15 -0
- package/dist/web/layout/sidebar-brand.js +9 -0
- package/dist/web/layout/sidebar-panel.d.ts +41 -0
- package/dist/web/layout/sidebar-panel.js +107 -0
- package/dist/web/layout/sidebar-user.d.ts +8 -0
- package/dist/web/layout/sidebar-user.js +17 -0
- package/dist/web/layout/sidebar.d.ts +17 -0
- package/dist/web/layout/sidebar.js +11 -0
- package/dist/web/layout/target-resolver-stub.d.ts +13 -0
- package/dist/web/layout/target-resolver-stub.js +61 -0
- package/dist/web/layout/target-url.d.ts +12 -0
- package/dist/web/layout/target-url.js +77 -0
- package/dist/web/layout/theme-label.d.ts +15 -0
- package/dist/web/layout/theme-label.js +35 -0
- package/dist/web/layout/theme-menu-item.d.ts +12 -0
- package/dist/web/layout/theme-menu-item.js +16 -0
- package/dist/web/layout/theme-toggle.d.ts +17 -0
- package/dist/web/layout/theme-toggle.js +22 -0
- package/dist/web/layout/topbar.d.ts +8 -0
- package/dist/web/layout/topbar.js +4 -0
- package/dist/web/layout/workspace-shell.d.ts +63 -0
- package/dist/web/layout/workspace-shell.js +220 -0
- package/dist/web/layout/workspace-switcher.d.ts +15 -0
- package/dist/web/layout/workspace-switcher.js +36 -0
- package/dist/web/lib/accept-attr.d.ts +1 -0
- package/dist/web/lib/accept-attr.js +6 -0
- package/dist/web/lib/clamp.d.ts +1 -0
- package/dist/web/lib/clamp.js +3 -0
- package/dist/web/lib/cn.d.ts +6 -0
- package/dist/web/lib/cn.js +9 -0
- package/dist/web/lib/download.d.ts +2 -0
- package/dist/web/lib/download.js +24 -0
- package/dist/web/lib/file-ref-download.d.ts +15 -0
- package/dist/web/lib/file-ref-download.js +62 -0
- package/dist/web/lib/file-upload-form-data.d.ts +7 -0
- package/dist/web/lib/file-upload-form-data.js +11 -0
- package/dist/web/lib/resize-image.d.ts +1 -0
- package/dist/web/lib/resize-image.js +66 -0
- package/dist/web/lib/upload-file-ref.d.ts +9 -0
- package/dist/web/lib/upload-file-ref.js +29 -0
- package/dist/web/primitives/action-menu.d.ts +34 -0
- package/dist/web/primitives/action-menu.js +30 -0
- package/dist/web/primitives/calendar-popover.d.ts +13 -0
- package/dist/web/primitives/calendar-popover.js +76 -0
- package/dist/web/primitives/combobox.d.ts +56 -0
- package/dist/web/primitives/combobox.js +127 -0
- package/dist/web/primitives/date-field.d.ts +18 -0
- package/dist/web/primitives/date-field.js +74 -0
- package/dist/web/primitives/date-input.d.ts +1 -0
- package/dist/web/primitives/date-input.js +5 -0
- package/dist/web/primitives/date-parse.d.ts +11 -0
- package/dist/web/primitives/date-parse.js +159 -0
- package/dist/web/primitives/dialog.d.ts +3 -0
- package/dist/web/primitives/dialog.js +42 -0
- package/dist/web/primitives/drawer.d.ts +3 -0
- package/dist/web/primitives/drawer.js +17 -0
- package/dist/web/primitives/dropdown-menu.d.ts +15 -0
- package/dist/web/primitives/dropdown-menu.js +56 -0
- package/dist/web/primitives/embedded-list-input.d.ts +9 -0
- package/dist/web/primitives/embedded-list-input.js +382 -0
- package/dist/web/primitives/file-thumbnail.d.ts +25 -0
- package/dist/web/primitives/file-thumbnail.js +90 -0
- package/dist/web/primitives/file-upload.d.ts +21 -0
- package/dist/web/primitives/file-upload.js +56 -0
- package/dist/web/primitives/index.d.ts +34 -0
- package/dist/web/primitives/index.js +2021 -0
- package/dist/web/primitives/json-view.d.ts +7 -0
- package/dist/web/primitives/json-view.js +84 -0
- package/dist/web/primitives/layout.d.ts +27 -0
- package/dist/web/primitives/layout.js +30 -0
- package/dist/web/primitives/lightbox.d.ts +3 -0
- package/dist/web/primitives/lightbox.js +36 -0
- package/dist/web/primitives/locale-number.d.ts +2 -0
- package/dist/web/primitives/locale-number.js +54 -0
- package/dist/web/primitives/located-timestamp-input.d.ts +22 -0
- package/dist/web/primitives/located-timestamp-input.js +22 -0
- package/dist/web/primitives/metric.d.ts +5 -0
- package/dist/web/primitives/metric.js +18 -0
- package/dist/web/primitives/modal-shell.d.ts +17 -0
- package/dist/web/primitives/modal-shell.js +9 -0
- package/dist/web/primitives/modal.d.ts +3 -0
- package/dist/web/primitives/modal.js +13 -0
- package/dist/web/primitives/money-input.d.ts +18 -0
- package/dist/web/primitives/money-input.js +122 -0
- package/dist/web/primitives/narrow-pinned-footer.d.ts +12 -0
- package/dist/web/primitives/narrow-pinned-footer.js +153 -0
- package/dist/web/primitives/number-input.d.ts +18 -0
- package/dist/web/primitives/number-input.js +53 -0
- package/dist/web/primitives/option-groups.d.ts +11 -0
- package/dist/web/primitives/option-groups.js +27 -0
- package/dist/web/primitives/page-header.d.ts +3 -0
- package/dist/web/primitives/page-header.js +52 -0
- package/dist/web/primitives/promo-panel.d.ts +3 -0
- package/dist/web/primitives/promo-panel.js +11 -0
- package/dist/web/primitives/segmented-select.d.ts +21 -0
- package/dist/web/primitives/segmented-select.js +62 -0
- package/dist/web/primitives/share-actions.d.ts +4 -0
- package/dist/web/primitives/share-actions.js +56 -0
- package/dist/web/primitives/status-badge.d.ts +3 -0
- package/dist/web/primitives/status-badge.js +5 -0
- package/dist/web/primitives/sticky-action-bar.d.ts +5 -0
- package/dist/web/primitives/sticky-action-bar.js +15 -0
- package/dist/web/primitives/tabs.d.ts +3 -0
- package/dist/web/primitives/tabs.js +107 -0
- package/dist/web/primitives/timestamp-input.d.ts +27 -0
- package/dist/web/primitives/timestamp-input.js +87 -0
- package/dist/web/primitives/toast.d.ts +19 -0
- package/dist/web/primitives/toast.js +63 -0
- package/dist/web/primitives/tz-input.d.ts +11 -0
- package/dist/web/primitives/tz-input.js +8 -0
- package/dist/web/primitives/tz-options.d.ts +4 -0
- package/dist/web/primitives/tz-options.js +17 -0
- package/dist/web/primitives/use-keyboard-inset.d.ts +1 -0
- package/dist/web/primitives/use-keyboard-inset.js +28 -0
- package/dist/web/primitives/use-narrow-viewport.d.ts +4 -0
- package/dist/web/primitives/use-narrow-viewport.js +46 -0
- package/dist/web/react-css-custom-properties.d.ts +6 -0
- package/dist/web/react-css-custom-properties.js +1 -0
- package/dist/web/sse/live-events.d.ts +15 -0
- package/dist/web/sse/live-events.js +148 -0
- package/dist/web/theme-plugin.d.ts +41 -0
- package/dist/web/theme-plugin.js +123 -0
- package/dist/web/tokens.d.ts +24 -0
- package/dist/web/tokens.js +203 -0
- package/dist/web/ui/avatar.d.ts +11 -0
- package/dist/web/ui/avatar.js +25 -0
- package/dist/web/ui/badge.d.ts +9 -0
- package/dist/web/ui/badge.js +26 -0
- package/dist/web/ui/breadcrumb.d.ts +11 -0
- package/dist/web/ui/breadcrumb.js +29 -0
- package/dist/web/ui/button.d.ts +10 -0
- package/dist/web/ui/button.js +37 -0
- package/dist/web/ui/checkbox.d.ts +4 -0
- package/dist/web/ui/checkbox.js +11 -0
- package/dist/web/ui/input.d.ts +3 -0
- package/dist/web/ui/input.js +8 -0
- package/dist/web/ui/label.d.ts +4 -0
- package/dist/web/ui/label.js +10 -0
- package/dist/web/ui/resizable.d.ts +7 -0
- package/dist/web/ui/resizable.js +16 -0
- package/dist/web/ui/separator.d.ts +4 -0
- package/dist/web/ui/separator.js +10 -0
- package/dist/web/ui/sheet.d.ts +14 -0
- package/dist/web/ui/sheet.js +42 -0
- package/dist/web/ui/sidebar.d.ts +73 -0
- package/dist/web/ui/sidebar.js +211 -0
- package/dist/web/ui/skeleton.d.ts +2 -0
- package/dist/web/ui/skeleton.js +7 -0
- package/dist/web/ui/switch.d.ts +6 -0
- package/dist/web/ui/switch.js +10 -0
- package/dist/web/ui/table.d.ts +10 -0
- package/dist/web/ui/table.js +30 -0
- package/dist/web/ui/tabs.d.ts +11 -0
- package/dist/web/ui/tabs.js +31 -0
- package/dist/web/ui/textarea.d.ts +3 -0
- package/dist/web/ui/textarea.js +8 -0
- package/dist/web/ui/tooltip.d.ts +7 -0
- package/dist/web/ui/tooltip.js +19 -0
- package/dist/web/ui/use-mobile.d.ts +1 -0
- package/dist/web/ui/use-mobile.js +16 -0
- package/dist/web/version/update-checker.d.ts +9 -0
- package/dist/web/version/update-checker.js +88 -0
- package/dist/web/widgets/ai-text-field.d.ts +36 -0
- package/dist/web/widgets/ai-text-field.js +137 -0
- package/dist/web/widgets/chart-window.d.ts +58 -0
- package/dist/web/widgets/chart-window.js +190 -0
- package/dist/web/widgets/charts.d.ts +208 -0
- package/dist/web/widgets/charts.js +685 -0
- package/dist/web/widgets/collapsible-section.d.ts +10 -0
- package/dist/web/widgets/collapsible-section.js +17 -0
- package/dist/web/widgets/dashboard-list.d.ts +21 -0
- package/dist/web/widgets/dashboard-list.js +45 -0
- package/dist/web/widgets/detail-list.d.ts +15 -0
- package/dist/web/widgets/detail-list.js +8 -0
- package/dist/web/widgets/drawer.d.ts +65 -0
- package/dist/web/widgets/drawer.js +142 -0
- package/dist/web/widgets/feed-list.d.ts +13 -0
- package/dist/web/widgets/feed-list.js +9 -0
- package/dist/web/widgets/floating-panel.d.ts +30 -0
- package/dist/web/widgets/floating-panel.js +242 -0
- package/dist/web/widgets/form-fields.d.ts +93 -0
- package/dist/web/widgets/form-fields.js +50 -0
- package/dist/web/widgets/index.d.ts +27 -0
- package/dist/web/widgets/index.js +30 -0
- package/dist/web/widgets/infinity-list.d.ts +46 -0
- package/dist/web/widgets/infinity-list.js +211 -0
- package/dist/web/widgets/mode-switch.d.ts +21 -0
- package/dist/web/widgets/mode-switch.js +25 -0
- package/dist/web/widgets/photo-slots.d.ts +29 -0
- package/dist/web/widgets/photo-slots.js +52 -0
- package/dist/web/widgets/plan-card.d.ts +36 -0
- package/dist/web/widgets/plan-card.js +13 -0
- package/dist/web/widgets/progress-bar.d.ts +19 -0
- package/dist/web/widgets/progress-bar.js +24 -0
- package/dist/web/widgets/progress-list.d.ts +19 -0
- package/dist/web/widgets/progress-list.js +11 -0
- package/dist/web/widgets/public-shell.d.ts +22 -0
- package/dist/web/widgets/public-shell.js +15 -0
- package/dist/web/widgets/query-table.d.ts +29 -0
- package/dist/web/widgets/query-table.js +30 -0
- package/dist/web/widgets/result-panel.d.ts +69 -0
- package/dist/web/widgets/result-panel.js +30 -0
- package/dist/web/widgets/section-card.d.ts +12 -0
- package/dist/web/widgets/section-card.js +9 -0
- package/dist/web/widgets/sheet-parts.d.ts +9 -0
- package/dist/web/widgets/sheet-parts.js +11 -0
- package/dist/web/widgets/side-by-side-table.d.ts +31 -0
- package/dist/web/widgets/side-by-side-table.js +11 -0
- package/dist/web/widgets/stat.d.ts +54 -0
- package/dist/web/widgets/stat.js +65 -0
- package/dist/web/widgets/states.d.ts +23 -0
- package/dist/web/widgets/states.js +20 -0
- package/dist/web/widgets/status-badge.d.ts +15 -0
- package/dist/web/widgets/status-badge.js +24 -0
- package/dist/web/widgets/step-bar.d.ts +35 -0
- package/dist/web/widgets/step-bar.js +60 -0
- package/dist/web/widgets/upload-zone.d.ts +24 -0
- package/dist/web/widgets/upload-zone.js +108 -0
- package/dist/web/widgets/use-draft.d.ts +20 -0
- package/dist/web/widgets/use-draft.js +21 -0
- package/dist/web/widgets/use-pointer-drag.d.ts +21 -0
- package/dist/web/widgets/use-pointer-drag.js +53 -0
- package/package.json +105 -7
- package/src/changes.json +77 -0
- package/src/web/fonts/OFL.txt +93 -0
- package/src/web/fonts/ibm-plex-mono-latin-400.woff2 +0 -0
- package/src/web/fonts/ibm-plex-mono-latin-500.woff2 +0 -0
- package/src/web/fonts/ibm-plex-mono-latin-ext-400.woff2 +0 -0
- package/src/web/fonts/ibm-plex-mono-latin-ext-500.woff2 +0 -0
- package/src/web/fonts/ibm-plex-sans-latin-400.woff2 +0 -0
- package/src/web/fonts/ibm-plex-sans-latin-500.woff2 +0 -0
- package/src/web/fonts/ibm-plex-sans-latin-600.woff2 +0 -0
- package/src/web/fonts/ibm-plex-sans-latin-ext-400.woff2 +0 -0
- package/src/web/fonts/ibm-plex-sans-latin-ext-500.woff2 +0 -0
- package/src/web/fonts/ibm-plex-sans-latin-ext-600.woff2 +0 -0
- package/src/web/styles.css +401 -0
|
@@ -0,0 +1,70 @@
|
|
|
1
|
+
import { Temporal } from "@cosmicdrift/kumiko-types/temporal";
|
|
2
|
+
import { formatMoney, resolveSafeMoneyLocale } from "./money.js";
|
|
3
|
+
// Used when the tenant has no currency setting.
|
|
4
|
+
export const DOCUMENT_FALLBACK_CURRENCY = "EUR";
|
|
5
|
+
const DATE_ONLY = /^\d{4}-\d{2}-\d{2}$/;
|
|
6
|
+
const DATE_TIME_WITH_OFFSET = /^\d{4}-\d{2}-\d{2}T.*[+-]\d{2}(:?\d{2})?$/;
|
|
7
|
+
function isPlainRecord(value) {
|
|
8
|
+
return typeof value === "object" && value !== null && !Array.isArray(value);
|
|
9
|
+
}
|
|
10
|
+
// A bare number is minor units in the tenant currency; a `{ amount, currency }`
|
|
11
|
+
// record brings its own currency.
|
|
12
|
+
export function formatDocumentMoney(value, tenantCurrency, locale) {
|
|
13
|
+
if (typeof value === "number" && Number.isFinite(value)) {
|
|
14
|
+
return formatMoney(value, tenantCurrency, locale);
|
|
15
|
+
}
|
|
16
|
+
if (isPlainRecord(value)) {
|
|
17
|
+
const { amount, currency } = value;
|
|
18
|
+
if (typeof amount === "number" && Number.isFinite(amount) && typeof currency === "string") {
|
|
19
|
+
return formatMoney(amount, currency, locale);
|
|
20
|
+
}
|
|
21
|
+
}
|
|
22
|
+
return value === undefined || value === null ? "" : String(value);
|
|
23
|
+
}
|
|
24
|
+
function formatOffsetDateTime(value, locale, withTime) {
|
|
25
|
+
const wallClock = Temporal.PlainDateTime.from(value);
|
|
26
|
+
return withTime
|
|
27
|
+
? wallClock.toLocaleString(locale, { dateStyle: "long", timeStyle: "short" })
|
|
28
|
+
: wallClock.toPlainDate().toLocaleString(locale, { dateStyle: "long" });
|
|
29
|
+
}
|
|
30
|
+
function instantFormatOptions(options) {
|
|
31
|
+
if (options.time !== true)
|
|
32
|
+
return { dateStyle: "long", timeZone: "UTC" };
|
|
33
|
+
return { dateStyle: "long", timeStyle: "short", timeZone: options.timeZone ?? "UTC" };
|
|
34
|
+
}
|
|
35
|
+
// The long date a rendered mail or PDF prints for a `date` placeholder; the editor's
|
|
36
|
+
// sample values use it too, so both show the same text.
|
|
37
|
+
export function formatDocumentDate(value, locale, options = {}) {
|
|
38
|
+
if (typeof value !== "string" && typeof value !== "number") {
|
|
39
|
+
return value === undefined || value === null ? "" : String(value);
|
|
40
|
+
}
|
|
41
|
+
const safeLocale = resolveSafeMoneyLocale(locale);
|
|
42
|
+
try {
|
|
43
|
+
// A date-only string has no zone; going through an instant would show the
|
|
44
|
+
// previous day west of UTC.
|
|
45
|
+
if (typeof value === "string" && DATE_ONLY.test(value)) {
|
|
46
|
+
return Temporal.PlainDate.from(value).toLocaleString(safeLocale, { dateStyle: "long" });
|
|
47
|
+
}
|
|
48
|
+
// An explicit offset names the sender's zone: the calendar date is the wall-clock
|
|
49
|
+
// date of the string, not the date at UTC.
|
|
50
|
+
if (typeof value === "string" && DATE_TIME_WITH_OFFSET.test(value)) {
|
|
51
|
+
return formatOffsetDateTime(value, safeLocale, options.time === true);
|
|
52
|
+
}
|
|
53
|
+
const instant = typeof value === "number"
|
|
54
|
+
? Temporal.Instant.fromEpochMilliseconds(value)
|
|
55
|
+
: Temporal.Instant.from(value);
|
|
56
|
+
return instant.toLocaleString(safeLocale, instantFormatOptions(options));
|
|
57
|
+
}
|
|
58
|
+
catch {
|
|
59
|
+
return String(value);
|
|
60
|
+
}
|
|
61
|
+
}
|
|
62
|
+
export function formatDocumentPercent(value, locale) {
|
|
63
|
+
if (typeof value === "number" && Number.isFinite(value)) {
|
|
64
|
+
return new Intl.NumberFormat(resolveSafeMoneyLocale(locale), {
|
|
65
|
+
style: "percent",
|
|
66
|
+
maximumFractionDigits: 2,
|
|
67
|
+
}).format(value / 100);
|
|
68
|
+
}
|
|
69
|
+
return value === undefined || value === null ? "" : String(value);
|
|
70
|
+
}
|
|
@@ -0,0 +1,5 @@
|
|
|
1
|
+
export declare function escapeHtml(s: string): string;
|
|
2
|
+
export declare function escapeHtmlAttr(s: string): string;
|
|
3
|
+
export declare function escapeXml(s: string): string;
|
|
4
|
+
export declare function stripControlChars(value: string): string;
|
|
5
|
+
export declare function isSafeHref(href: string): boolean;
|
|
@@ -0,0 +1,75 @@
|
|
|
1
|
+
export function escapeHtml(s) {
|
|
2
|
+
return s
|
|
3
|
+
.replace(/&/g, "&")
|
|
4
|
+
.replace(/</g, "<")
|
|
5
|
+
.replace(/>/g, ">")
|
|
6
|
+
.replace(/"/g, """);
|
|
7
|
+
}
|
|
8
|
+
// Superset of escapeHtml for attribute contexts: additionally escapes ' so
|
|
9
|
+
// single-quoted attributes cannot be broken out of.
|
|
10
|
+
export function escapeHtmlAttr(s) {
|
|
11
|
+
return escapeHtml(s).replace(/'/g, "'");
|
|
12
|
+
}
|
|
13
|
+
// Shared API for app repos (publicstatus badge-SVG renders XML by hand) —
|
|
14
|
+
// no in-repo consumer yet, deliberately exported for cross-repo dedup.
|
|
15
|
+
export function escapeXml(s) {
|
|
16
|
+
return s
|
|
17
|
+
.replace(/&/g, "&")
|
|
18
|
+
.replace(/</g, "<")
|
|
19
|
+
.replace(/>/g, ">")
|
|
20
|
+
.replace(/"/g, """)
|
|
21
|
+
.replace(/'/g, "'");
|
|
22
|
+
}
|
|
23
|
+
// Strips ASCII control chars + space (codepoints 0x00-0x20 and 0x7f) — the
|
|
24
|
+
// same characters browsers strip before scheme detection. `.trim()` alone
|
|
25
|
+
// only removes leading/trailing whitespace, so a scheme like
|
|
26
|
+
// "java\tscript:" (tab embedded mid-scheme) survives to isSafeHref's regex
|
|
27
|
+
// check below, breaks its character class before the ":", falls through to
|
|
28
|
+
// `return true`, and the browser then normalizes it back to "javascript:"
|
|
29
|
+
// and executes it. Written as a char-code filter rather than a regex range
|
|
30
|
+
// to avoid embedding literal control characters in source.
|
|
31
|
+
export function stripControlChars(value) {
|
|
32
|
+
let result = "";
|
|
33
|
+
for (const ch of value) {
|
|
34
|
+
const code = ch.codePointAt(0) ?? 0;
|
|
35
|
+
if (code > 0x20 && code !== 0x7f)
|
|
36
|
+
result += ch;
|
|
37
|
+
}
|
|
38
|
+
return result;
|
|
39
|
+
}
|
|
40
|
+
// http(s)/mailto or scheme-less (relative/anchor) allowed; javascript:,
|
|
41
|
+
// data:, vbscript:, etc. rejected. Shared between renderer/web's Link
|
|
42
|
+
// primitive and page-render's server-side markdown renderer (both take
|
|
43
|
+
// untrusted tenant-authored hrefs) — no sanitizer dependency needed for a
|
|
44
|
+
// four-line regex check.
|
|
45
|
+
// Browsers decode HTML character references (:, :, :, 	,
|
|
46
|
+
// 	, ...) while parsing the href attribute, before the URL parser ever
|
|
47
|
+
// sees the value — so "javascript:alert(1)" and "java	script:"
|
|
48
|
+
// both normalize to an executable javascript: URL at click time even though
|
|
49
|
+
// neither contains a literal ":" for the regex below to catch. Decode
|
|
50
|
+
// (not delete) so the scheme check sees what the browser will execute —
|
|
51
|
+
// deleting ":" would leave no colon at all, which reads as a safe
|
|
52
|
+
// scheme-less href, exactly backwards.
|
|
53
|
+
const NAMED_HTML_ENTITY_CHARS = {
|
|
54
|
+
colon: ":",
|
|
55
|
+
tab: "\t",
|
|
56
|
+
newline: "\n",
|
|
57
|
+
semi: ";",
|
|
58
|
+
amp: "&",
|
|
59
|
+
};
|
|
60
|
+
function decodeHtmlEntities(value) {
|
|
61
|
+
return value.replace(/&(#x[0-9a-f]+|#[0-9]+|[a-z][a-z0-9]*);/gi, (match, entity) => {
|
|
62
|
+
if (entity[0] === "#") {
|
|
63
|
+
const isHex = entity[1]?.toLowerCase() === "x";
|
|
64
|
+
const code = Number.parseInt(isHex ? entity.slice(2) : entity.slice(1), isHex ? 16 : 10);
|
|
65
|
+
return Number.isFinite(code) ? String.fromCodePoint(code) : match;
|
|
66
|
+
}
|
|
67
|
+
return NAMED_HTML_ENTITY_CHARS[entity.toLowerCase()] ?? match;
|
|
68
|
+
});
|
|
69
|
+
}
|
|
70
|
+
export function isSafeHref(href) {
|
|
71
|
+
const trimmed = stripControlChars(decodeHtmlEntities(href)).toLowerCase();
|
|
72
|
+
if (!/^[a-z][a-z0-9+.-]*:/.test(trimmed))
|
|
73
|
+
return true;
|
|
74
|
+
return /^(?:https?|mailto):/.test(trimmed);
|
|
75
|
+
}
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
export declare class RawHtml {
|
|
2
|
+
readonly html: string;
|
|
3
|
+
constructor(html: string);
|
|
4
|
+
toString(): string;
|
|
5
|
+
}
|
|
6
|
+
/** Marks already escaped or trusted markup for html`...`. */
|
|
7
|
+
export declare function raw(html: string): RawHtml;
|
|
8
|
+
export type HtmlValue = string | number | boolean | null | undefined | RawHtml | ReadonlyArray<HtmlValue>;
|
|
9
|
+
export declare function html(strings: TemplateStringsArray, ...values: ReadonlyArray<HtmlValue>): RawHtml;
|
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
// html`...` — tagged template that HTML-escapes every interpolation automatically.
|
|
2
|
+
// Makes escaping structural instead of a per-call-site convention: forgetting
|
|
3
|
+
// it is impossible, deliberately raw HTML needs an explicit raw(). The
|
|
4
|
+
// HTML-escape guard (kumiko-guards) accepts html`...` as safe.
|
|
5
|
+
import { escapeHtml } from "./escape.js";
|
|
6
|
+
export class RawHtml {
|
|
7
|
+
html;
|
|
8
|
+
constructor(html) {
|
|
9
|
+
this.html = html;
|
|
10
|
+
}
|
|
11
|
+
toString() {
|
|
12
|
+
return this.html;
|
|
13
|
+
}
|
|
14
|
+
}
|
|
15
|
+
/** Marks already escaped or trusted markup for html`...`. */
|
|
16
|
+
export function raw(html) {
|
|
17
|
+
return new RawHtml(html);
|
|
18
|
+
}
|
|
19
|
+
function renderValue(value) {
|
|
20
|
+
if (value === null || value === undefined)
|
|
21
|
+
return "";
|
|
22
|
+
if (value instanceof RawHtml)
|
|
23
|
+
return value.html;
|
|
24
|
+
if (Array.isArray(value))
|
|
25
|
+
return value.map(renderValue).join("");
|
|
26
|
+
if (typeof value === "string")
|
|
27
|
+
return escapeHtml(value);
|
|
28
|
+
return String(value);
|
|
29
|
+
}
|
|
30
|
+
// Returns RawHtml so fragments can be nested without double escaping:
|
|
31
|
+
// `html`<div>${item}</div>`` inside an outer html`...` passes through
|
|
32
|
+
// unchanged. toString() yields the finished markup.
|
|
33
|
+
export function html(strings, ...values) {
|
|
34
|
+
let out = strings[0] ?? "";
|
|
35
|
+
values.forEach((value, i) => {
|
|
36
|
+
out += renderValue(value) + (strings[i + 1] ?? "");
|
|
37
|
+
});
|
|
38
|
+
return new RawHtml(out);
|
|
39
|
+
}
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
import { Temporal } from "@cosmicdrift/kumiko-types/temporal";
|
|
2
|
+
export declare const EMPTY_VALUE_PLACEHOLDER = "\u2014";
|
|
3
|
+
export declare function toInstant(raw: string): Temporal.Instant;
|
|
4
|
+
/** Exported for UnitKey parity tests against @cosmicdrift/kumiko-types/screen. */
|
|
5
|
+
export declare const UNIT_FORMAT_KEYS: readonly string[];
|
|
6
|
+
export { DOCUMENT_FALLBACK_CURRENCY, type DocumentDateOptions, formatDocumentDate, formatDocumentMoney, formatDocumentPercent, } from "./document-values.ts";
|
|
7
|
+
export { escapeHtml, escapeHtmlAttr, escapeXml, isSafeHref, stripControlChars } from "./escape.ts";
|
|
8
|
+
export { type HtmlValue, html, RawHtml, raw } from "./html-template.ts";
|
|
9
|
+
export { currencyDecimals, formatMoney, resolveSafeMoneyLocale } from "./money.ts";
|
|
10
|
+
export declare function applyFormatSpec(spec: {
|
|
11
|
+
format: string;
|
|
12
|
+
} & Record<string, unknown>, value: unknown, translate?: (key: string) => string): string;
|
|
@@ -0,0 +1,237 @@
|
|
|
1
|
+
// Pure format utilities — no web or platform dependencies.
|
|
2
|
+
// Shared between renderer/web, renderer-native, and server-side tests.
|
|
3
|
+
import { Temporal } from "@cosmicdrift/kumiko-types/temporal";
|
|
4
|
+
import { isOneOf } from "@cosmicdrift/kumiko-types/type-guards";
|
|
5
|
+
export const EMPTY_VALUE_PLACEHOLDER = "—";
|
|
6
|
+
function toPlainDate(raw) {
|
|
7
|
+
try {
|
|
8
|
+
return Temporal.PlainDate.from(raw);
|
|
9
|
+
}
|
|
10
|
+
catch {
|
|
11
|
+
// "date"-typed field stored as a full instant (day-boundary timestamp) —
|
|
12
|
+
// take the calendar date in the local zone rather than fail.
|
|
13
|
+
return toInstant(raw).toZonedDateTimeISO(Temporal.Now.timeZoneId()).toPlainDate();
|
|
14
|
+
}
|
|
15
|
+
}
|
|
16
|
+
// Temporal.Instant.from is stricter than the `new Date(raw)` this replaced:
|
|
17
|
+
// it requires a UTC designator/offset (Z/+hh:mm). Timestamps without one
|
|
18
|
+
// (e.g. "2026-07-18T12:00:00", still valid input to `new Date`) throw here
|
|
19
|
+
// instead of parsing — fall back to reading them as a local wall-clock time,
|
|
20
|
+
// same posture as toPlainDate's own fallback above.
|
|
21
|
+
export function toInstant(raw) {
|
|
22
|
+
try {
|
|
23
|
+
return Temporal.Instant.from(raw);
|
|
24
|
+
}
|
|
25
|
+
catch {
|
|
26
|
+
return Temporal.PlainDateTime.from(raw).toZonedDateTime(Temporal.Now.timeZoneId()).toInstant();
|
|
27
|
+
}
|
|
28
|
+
}
|
|
29
|
+
function formatDateCell(value, type, opts) {
|
|
30
|
+
try {
|
|
31
|
+
const raw = typeof value === "string" ? value : String(value);
|
|
32
|
+
const locale = opts?.locale;
|
|
33
|
+
if (opts?.dateStyle || opts?.timeStyle) {
|
|
34
|
+
if (type === "date") {
|
|
35
|
+
// ponytail: timeStyle is ignored here on purpose — a PlainDate has no
|
|
36
|
+
// time component to format, so a timeStyle-only "date" field falls
|
|
37
|
+
// back to PlainDate's default dateStyle instead of rendering a time.
|
|
38
|
+
return toPlainDate(raw).toLocaleString(locale, {
|
|
39
|
+
dateStyle: opts.dateStyle,
|
|
40
|
+
});
|
|
41
|
+
}
|
|
42
|
+
return toInstant(raw).toLocaleString(locale, {
|
|
43
|
+
dateStyle: opts.dateStyle,
|
|
44
|
+
timeStyle: opts.timeStyle,
|
|
45
|
+
timeZone: opts.timeZone,
|
|
46
|
+
});
|
|
47
|
+
}
|
|
48
|
+
if (type === "date") {
|
|
49
|
+
return toPlainDate(raw).toLocaleString(locale, {
|
|
50
|
+
year: "numeric",
|
|
51
|
+
month: "2-digit",
|
|
52
|
+
day: "2-digit",
|
|
53
|
+
});
|
|
54
|
+
}
|
|
55
|
+
return toInstant(raw).toLocaleString(locale, {
|
|
56
|
+
year: "numeric",
|
|
57
|
+
month: "short",
|
|
58
|
+
day: "numeric",
|
|
59
|
+
hour: "2-digit",
|
|
60
|
+
minute: "2-digit",
|
|
61
|
+
timeZone: opts?.timeZone,
|
|
62
|
+
});
|
|
63
|
+
}
|
|
64
|
+
catch {
|
|
65
|
+
return String(value);
|
|
66
|
+
}
|
|
67
|
+
}
|
|
68
|
+
// No `locale` fallback to a browser API here (headless has none) — passing
|
|
69
|
+
// `undefined` to Intl.NumberFormat resolves the runtime's default locale,
|
|
70
|
+
// the same value a browser's navigator.language-based guess would produce.
|
|
71
|
+
function formatNumberCell(value, locale, grouping = true) {
|
|
72
|
+
if (typeof value !== "number" || !Number.isFinite(value))
|
|
73
|
+
return String(value);
|
|
74
|
+
try {
|
|
75
|
+
return new Intl.NumberFormat(locale, { useGrouping: grouping }).format(value);
|
|
76
|
+
}
|
|
77
|
+
catch {
|
|
78
|
+
// Malformed BCP-47 locale tag — mirrors formatDateCell's fallback above.
|
|
79
|
+
return String(value);
|
|
80
|
+
}
|
|
81
|
+
}
|
|
82
|
+
// Two-tier unit table for `{ format: "unit" }`. Keys mirror
|
|
83
|
+
// @cosmicdrift/kumiko-types' UnitKey (kept as a local literal union instead
|
|
84
|
+
// of an import — headless has no build-time dependency on kumiko-types
|
|
85
|
+
// today, and applyFormatSpec's spec param is already an untyped
|
|
86
|
+
// Record<string, unknown>, cast per-case like every other format below).
|
|
87
|
+
const UNIT_INTL_IDS = {
|
|
88
|
+
km: "kilometer",
|
|
89
|
+
m: "meter",
|
|
90
|
+
kg: "kilogram",
|
|
91
|
+
percent: "percent",
|
|
92
|
+
mi: "mile",
|
|
93
|
+
};
|
|
94
|
+
// "m2" (square meter) has no ECMA-402 sanctioned unit — Intl.NumberFormat
|
|
95
|
+
// throws RangeError for "square-meter". Locale-format the number and append
|
|
96
|
+
// the literal suffix instead of going through `style: "unit"`.
|
|
97
|
+
const UNIT_SUFFIXES = { m2: "m²" };
|
|
98
|
+
function isIntlUnit(unit) {
|
|
99
|
+
return Object.hasOwn(UNIT_INTL_IDS, unit);
|
|
100
|
+
}
|
|
101
|
+
function isSuffixUnit(unit) {
|
|
102
|
+
return Object.hasOwn(UNIT_SUFFIXES, unit);
|
|
103
|
+
}
|
|
104
|
+
function formatUnitCell(value, unit, locale, unitDisplay) {
|
|
105
|
+
const n = typeof value === "number" ? value : Number(value);
|
|
106
|
+
if (unit === undefined || !Number.isFinite(n))
|
|
107
|
+
return String(value);
|
|
108
|
+
if (isIntlUnit(unit)) {
|
|
109
|
+
try {
|
|
110
|
+
return new Intl.NumberFormat(locale, {
|
|
111
|
+
style: "unit",
|
|
112
|
+
unit: UNIT_INTL_IDS[unit],
|
|
113
|
+
unitDisplay,
|
|
114
|
+
}).format(n);
|
|
115
|
+
}
|
|
116
|
+
catch {
|
|
117
|
+
// Malformed BCP-47 locale tag — mirrors formatNumberCell's fallback below.
|
|
118
|
+
return formatNumberCell(n, locale);
|
|
119
|
+
}
|
|
120
|
+
}
|
|
121
|
+
if (isSuffixUnit(unit)) {
|
|
122
|
+
return `${formatNumberCell(n, locale)} ${UNIT_SUFFIXES[unit]}`;
|
|
123
|
+
}
|
|
124
|
+
return String(value);
|
|
125
|
+
}
|
|
126
|
+
/** Exported for UnitKey parity tests against @cosmicdrift/kumiko-types/screen. */
|
|
127
|
+
export const UNIT_FORMAT_KEYS = [
|
|
128
|
+
...Object.keys(UNIT_INTL_IDS),
|
|
129
|
+
...Object.keys(UNIT_SUFFIXES),
|
|
130
|
+
];
|
|
131
|
+
export { DOCUMENT_FALLBACK_CURRENCY, formatDocumentDate, formatDocumentMoney, formatDocumentPercent, } from "./document-values.js";
|
|
132
|
+
export { escapeHtml, escapeHtmlAttr, escapeXml, isSafeHref, stripControlChars } from "./escape.js";
|
|
133
|
+
export { html, RawHtml, raw } from "./html-template.js";
|
|
134
|
+
export { currencyDecimals, formatMoney, resolveSafeMoneyLocale } from "./money.js";
|
|
135
|
+
// JSON.stringify throws on BigInt and circular values; a cell must degrade to text instead of crashing the screen.
|
|
136
|
+
function stringifyJsonOrString(value, indent) {
|
|
137
|
+
try {
|
|
138
|
+
return JSON.stringify(value, null, indent) ?? String(value);
|
|
139
|
+
}
|
|
140
|
+
catch {
|
|
141
|
+
try {
|
|
142
|
+
return String(value);
|
|
143
|
+
}
|
|
144
|
+
catch {
|
|
145
|
+
return "[unserializable value]";
|
|
146
|
+
}
|
|
147
|
+
}
|
|
148
|
+
}
|
|
149
|
+
const INTL_DATE_STYLES = ["full", "long", "medium", "short"];
|
|
150
|
+
const INTL_UNIT_DISPLAYS = ["short", "long", "narrow"];
|
|
151
|
+
function stringSpec(spec, key) {
|
|
152
|
+
const v = spec[key];
|
|
153
|
+
return typeof v === "string" ? v : undefined;
|
|
154
|
+
}
|
|
155
|
+
function booleanSpec(spec, key) {
|
|
156
|
+
const v = spec[key];
|
|
157
|
+
return typeof v === "boolean" ? v : undefined;
|
|
158
|
+
}
|
|
159
|
+
function dateStyleSpec(spec, key) {
|
|
160
|
+
const v = spec[key];
|
|
161
|
+
return isOneOf(INTL_DATE_STYLES, v) ? v : undefined;
|
|
162
|
+
}
|
|
163
|
+
function unitDisplaySpec(spec) {
|
|
164
|
+
const v = spec["unitDisplay"];
|
|
165
|
+
return isOneOf(INTL_UNIT_DISPLAYS, v) ? v : "short";
|
|
166
|
+
}
|
|
167
|
+
export function applyFormatSpec(spec, value, translate) {
|
|
168
|
+
const isEmpty = value === null || value === undefined || value === "";
|
|
169
|
+
// priority renders its emptyLabel for empty values — every other format
|
|
170
|
+
// collapses empty to "".
|
|
171
|
+
if (isEmpty && spec.format !== "priority")
|
|
172
|
+
return "";
|
|
173
|
+
switch (spec.format) {
|
|
174
|
+
case "timestamp":
|
|
175
|
+
case "date":
|
|
176
|
+
return formatDateCell(value, spec.format, {
|
|
177
|
+
locale: stringSpec(spec, "locale"),
|
|
178
|
+
dateStyle: dateStyleSpec(spec, "dateStyle"),
|
|
179
|
+
timeStyle: spec.format === "timestamp" ? dateStyleSpec(spec, "timeStyle") : undefined,
|
|
180
|
+
timeZone: spec.format === "timestamp" ? stringSpec(spec, "timeZone") : undefined,
|
|
181
|
+
});
|
|
182
|
+
case "boolean": {
|
|
183
|
+
if (value === true) {
|
|
184
|
+
const trueLabel = stringSpec(spec, "trueLabel");
|
|
185
|
+
return trueLabel === undefined ? "✓" : (translate?.(trueLabel) ?? trueLabel);
|
|
186
|
+
}
|
|
187
|
+
if (value === false) {
|
|
188
|
+
const falseLabel = stringSpec(spec, "falseLabel");
|
|
189
|
+
return falseLabel === undefined ? "" : (translate?.(falseLabel) ?? falseLabel);
|
|
190
|
+
}
|
|
191
|
+
return "";
|
|
192
|
+
}
|
|
193
|
+
case "currency": {
|
|
194
|
+
const sym = stringSpec(spec, "symbol") ?? "";
|
|
195
|
+
return sym.length > 0 ? `${value} ${sym}` : String(value);
|
|
196
|
+
}
|
|
197
|
+
case "number":
|
|
198
|
+
case "decimal":
|
|
199
|
+
case "bigInt":
|
|
200
|
+
return formatNumberCell(value, stringSpec(spec, "locale"), booleanSpec(spec, "grouping") ?? true);
|
|
201
|
+
case "unit":
|
|
202
|
+
return formatUnitCell(value, stringSpec(spec, "unit"), stringSpec(spec, "locale"), unitDisplaySpec(spec));
|
|
203
|
+
case "priority": {
|
|
204
|
+
const emptyLabel = stringSpec(spec, "emptyLabel") ?? EMPTY_VALUE_PLACEHOLDER;
|
|
205
|
+
const prefix = stringSpec(spec, "prefix") ?? "";
|
|
206
|
+
if (isEmpty || value === 0)
|
|
207
|
+
return emptyLabel;
|
|
208
|
+
return `${prefix}${value}`;
|
|
209
|
+
}
|
|
210
|
+
case "enumOption": {
|
|
211
|
+
const keyPrefix = stringSpec(spec, "keyPrefix");
|
|
212
|
+
const labelFor = (item) => {
|
|
213
|
+
const raw = typeof item === "string" ? item : String(item);
|
|
214
|
+
if (keyPrefix === undefined || translate === undefined)
|
|
215
|
+
return raw;
|
|
216
|
+
const key = `${keyPrefix}${raw}`;
|
|
217
|
+
const translated = translate(key);
|
|
218
|
+
return translated === key ? raw : translated;
|
|
219
|
+
};
|
|
220
|
+
// multiSelect-style columns hold an array of option values
|
|
221
|
+
return Array.isArray(value) ? value.map(labelFor).join(", ") : labelFor(value);
|
|
222
|
+
}
|
|
223
|
+
// Thumbnails and file links are drawn by the web list cell; this is the
|
|
224
|
+
// text fallback for every other surface.
|
|
225
|
+
case "image":
|
|
226
|
+
case "file":
|
|
227
|
+
return Array.isArray(value) ? value.join(", ") : String(value);
|
|
228
|
+
case "json":
|
|
229
|
+
return stringifyJsonOrString(value, typeof spec["indent"] === "number" ? spec["indent"] : 2);
|
|
230
|
+
default:
|
|
231
|
+
if (typeof process !== "undefined" && process.env.NODE_ENV !== "production") {
|
|
232
|
+
// biome-ignore lint/suspicious/noConsole: dev-only warning
|
|
233
|
+
console.warn(`[kumiko] applyFormatSpec: unknown format key "${spec.format}" — registered via FieldFormatRegistry module augmentation?`);
|
|
234
|
+
}
|
|
235
|
+
return typeof value === "string" ? value : String(value);
|
|
236
|
+
}
|
|
237
|
+
}
|
|
@@ -0,0 +1,3 @@
|
|
|
1
|
+
export declare function currencyDecimals(code: string): number;
|
|
2
|
+
export declare function resolveSafeMoneyLocale(locale: string | undefined): string;
|
|
3
|
+
export declare function formatMoney(amountMinor: number, currency: string, locale?: string, fractionDigits?: number): string;
|
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
// Currency decimal places — covers the world's zero- and three-decimal
|
|
2
|
+
// outliers, defaults to 2 for everything else. Shared between renderer/web's
|
|
3
|
+
// MoneyInput (minor-unit display factor) and RenderField's minor/major-unit
|
|
4
|
+
// conversion (kumiko-framework#1923) — a single source keeps both sides
|
|
5
|
+
// scaling the same currency the same way.
|
|
6
|
+
export function currencyDecimals(code) {
|
|
7
|
+
if (code === "JPY" || code === "KRW" || code === "VND" || code === "ISK")
|
|
8
|
+
return 0;
|
|
9
|
+
if (code === "BHD" || code === "JOD" || code === "KWD" || code === "OMR" || code === "TND")
|
|
10
|
+
return 3;
|
|
11
|
+
return 2;
|
|
12
|
+
}
|
|
13
|
+
const FALLBACK_MONEY_LOCALE = "en-US";
|
|
14
|
+
// An invalid tag makes Intl constructors throw a RangeError; canonicalizing up
|
|
15
|
+
// front keeps server renders and client cells safe. No navigator lookup, so it
|
|
16
|
+
// behaves the same on the server.
|
|
17
|
+
export function resolveSafeMoneyLocale(locale) {
|
|
18
|
+
try {
|
|
19
|
+
return Intl.getCanonicalLocales(locale ?? FALLBACK_MONEY_LOCALE)[0] ?? FALLBACK_MONEY_LOCALE;
|
|
20
|
+
}
|
|
21
|
+
catch {
|
|
22
|
+
return FALLBACK_MONEY_LOCALE;
|
|
23
|
+
}
|
|
24
|
+
}
|
|
25
|
+
// currency is validated against the 3-letter-alpha shape Intl.NumberFormat
|
|
26
|
+
// requires: a non-conforming value (e.g. from a JSONB custom field) would throw
|
|
27
|
+
// a RangeError and take down the whole render instead of just this value.
|
|
28
|
+
export function formatMoney(amountMinor, currency, locale, fractionDigits) {
|
|
29
|
+
if (!/^[A-Za-z]{3}$/.test(currency))
|
|
30
|
+
return String(amountMinor);
|
|
31
|
+
const decimals = currencyDecimals(currency);
|
|
32
|
+
const displayDigits = fractionDigits ?? decimals;
|
|
33
|
+
return new Intl.NumberFormat(resolveSafeMoneyLocale(locale), {
|
|
34
|
+
style: "currency",
|
|
35
|
+
currency,
|
|
36
|
+
minimumFractionDigits: displayDigits,
|
|
37
|
+
maximumFractionDigits: displayDigits,
|
|
38
|
+
}).format(amountMinor / 10 ** decimals);
|
|
39
|
+
}
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
export type { ParsedRefTarget } from "@cosmicdrift/kumiko-framework/ui-types";
|
|
2
|
+
export { parseRefTarget } from "@cosmicdrift/kumiko-framework/ui-types";
|
|
3
|
+
export type { AssetResolution, AssetResolveContext, AssetResolver, BadgeProps, ButtonProps, CardProps, DatePickerProps, IconProps, LocaleResolver, ModalProps, NumberInputProps, PrimitiveCommonProps, PrimitivesContract, SelectOption, SelectProps, TextInputProps, ToastIntent, ToastProps, ToggleProps, } from "./contracts/index.ts";
|
|
4
|
+
export type { BatchResult, Command, Dispatcher, DispatcherError, DispatcherStatus, FieldIssue, PendingFile, PendingWrite, QueryOpts, QueryResult, StreamOpts, WriteOpts, WriteResult, } from "./dispatcher/index.ts";
|
|
5
|
+
export { StreamFrame, type StreamFrameEvent } from "./dispatcher/index.ts";
|
|
6
|
+
export type { FieldConditionPredicate, FieldConditions, FieldConditionValue, FieldState, FormController, FormControllerOptions, FormSnapshot, FormValues, SubmitConfig, SubmitPayloadMode, SubmitResult, } from "./form/index.ts";
|
|
7
|
+
export { createFormController, groupIssuesByPath, I18N_KEY_PARAM, relevantFieldIssues, zodErrorToFieldIssues, } from "./form/index.ts";
|
|
8
|
+
export { applyFormatSpec, currencyDecimals, DOCUMENT_FALLBACK_CURRENCY, EMPTY_VALUE_PLACEHOLDER, escapeHtml, escapeHtmlAttr, escapeXml, formatDocumentDate, formatDocumentMoney, formatDocumentPercent, formatMoney, type HtmlValue, html, isSafeHref, RawHtml, raw, resolveSafeMoneyLocale, stripControlChars, toInstant, } from "./format/index.ts";
|
|
9
|
+
export type { NavDefinition, NavNode, NavRegistrySlice, NavTree, ResolveNavigationOptions, } from "./nav/index.ts";
|
|
10
|
+
export { resolveNavigation } from "./nav/index.ts";
|
|
11
|
+
export type { Store, WritableStore } from "./store/index.ts";
|
|
12
|
+
export { createStore, shallowEqual } from "./store/index.ts";
|
|
13
|
+
export type { CellLink, CellLinkItem, ComputeEditViewModelInput, ComputeListViewModelInput, DerivedCellRoundingTarget, EditExtensionSectionViewModel, EditFieldSpec, EditFieldsSectionViewModel, EditFieldViewModel, EditFormMode, EditRelatedListSectionViewModel, EditSectionSpec, EditSectionViewModel, EditViewModel, EditWriteFormSectionViewModel, EmbeddedDerivedOp, EmbeddedListCellViewModel, EmbeddedListIssueGroups, FieldConditionCtx, FieldRenderer, ListColumnFileDisplay, ListColumnSpec, ListColumnViewModel, ListRowViewModel, ListViewModel, RuntimeCellLink, RuntimeCellLinkItems, RuntimeRenderer, ScreenSlots, Translate, } from "./view-model/index.ts";
|
|
14
|
+
export { buildOptionLabels, computeDerivedCellValue, computeEditViewModel, computeListViewModel, computeRelatedListSectionViewModel, embeddedCellLabelKey, embeddedCellOptionLabelKey, fieldLabelKey, fieldOptionLabelKey, fieldOptionLabelKeyPrefix, groupEmbeddedListIssues, roundDerivedCellValue, sumEmbeddedListColumn, } from "./view-model/index.ts";
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
// Re-Export aus framework/ui-types damit Renderer-Code denselben
|
|
2
|
+
// Parser nutzt wie der Server-Boot-Validator (Cross-Feature-Refs).
|
|
3
|
+
export { parseRefTarget } from "@cosmicdrift/kumiko-framework/ui-types";
|
|
4
|
+
export { StreamFrame } from "./dispatcher/index.js";
|
|
5
|
+
export { createFormController, groupIssuesByPath, I18N_KEY_PARAM, relevantFieldIssues, zodErrorToFieldIssues, } from "./form/index.js";
|
|
6
|
+
export { applyFormatSpec, currencyDecimals, DOCUMENT_FALLBACK_CURRENCY, EMPTY_VALUE_PLACEHOLDER, escapeHtml, escapeHtmlAttr, escapeXml, formatDocumentDate, formatDocumentMoney, formatDocumentPercent, formatMoney, html, isSafeHref, RawHtml, raw, resolveSafeMoneyLocale, stripControlChars, toInstant, } from "./format/index.js";
|
|
7
|
+
export { resolveNavigation } from "./nav/index.js";
|
|
8
|
+
export { createStore, shallowEqual } from "./store/index.js";
|
|
9
|
+
export { buildOptionLabels, computeDerivedCellValue, computeEditViewModel, computeListViewModel, computeRelatedListSectionViewModel, embeddedCellLabelKey, embeddedCellOptionLabelKey, fieldLabelKey, fieldOptionLabelKey, fieldOptionLabelKeyPrefix, groupEmbeddedListIssues, roundDerivedCellValue, sumEmbeddedListColumn, } from "./view-model/index.js";
|
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
import type { LocaleResolver } from "../contracts/index.ts";
|
|
2
|
+
export type LocaleRouterConfig<TPage extends string> = {
|
|
3
|
+
/** Canonical default, usually "de". No URL prefix. */
|
|
4
|
+
readonly defaultLocale: string;
|
|
5
|
+
/** Locales that get a URL prefix, e.g. ["en"] → /en/... */
|
|
6
|
+
readonly prefixedLocales: readonly string[];
|
|
7
|
+
/** Prefix segment per locale, default: locale code ("en" → "/en"). */
|
|
8
|
+
readonly prefixFor?: (locale: string) => string;
|
|
9
|
+
/** Logical page → path per locale. Every page must define defaultLocale path. */
|
|
10
|
+
readonly routes: Record<TPage, Record<string, string>>;
|
|
11
|
+
/** Legacy slug-only paths for detectLang/resolvePage, e.g. { en: ["/features"] }. */
|
|
12
|
+
readonly localeHints?: Readonly<Record<string, readonly string[]>>;
|
|
13
|
+
/** Fallback page when altLocalePath cannot resolve pathname. Default: "home". */
|
|
14
|
+
readonly homePage?: TPage;
|
|
15
|
+
};
|
|
16
|
+
export type LocaleRouter<TPage extends string> = {
|
|
17
|
+
detectLang(pathname: string): string;
|
|
18
|
+
publicPath(page: TPage, locale: string): string;
|
|
19
|
+
resolvePage(pathname: string): TPage | undefined;
|
|
20
|
+
altLocalePath(pathname: string, targetLocale?: string): string;
|
|
21
|
+
sectionAnchor(page: TPage, locale: string, fragment: string): string;
|
|
22
|
+
};
|
|
23
|
+
export declare function createLocaleRouter<TPage extends string>(config: LocaleRouterConfig<TPage>): LocaleRouter<TPage>;
|
|
24
|
+
export type WrapUrlLocaleResolverOptions = {
|
|
25
|
+
resolvePage: (pathname: string) => string | undefined;
|
|
26
|
+
detectLang: (pathname: string) => string;
|
|
27
|
+
pathname?: () => string | undefined;
|
|
28
|
+
/** Optional pathname-change subscription. Browser default listens to `popstate` only,
|
|
29
|
+
* which does not fire on `history.pushState`/`replaceState`: apps with a client-side
|
|
30
|
+
* router must supply this themselves. */
|
|
31
|
+
subscribePathname?: (listener: () => void) => () => void;
|
|
32
|
+
/** When set, translate against the URL-resolved locale instead of base.translate
|
|
33
|
+
* (needed for fixed-T / cloneInstance resolvers that are not locale-live). */
|
|
34
|
+
translateFor?: (locale: string, key: string, params?: Readonly<Record<string, unknown>>) => string;
|
|
35
|
+
};
|
|
36
|
+
/**
|
|
37
|
+
* Prefer URL-derived locale when `resolvePage` matches the current path;
|
|
38
|
+
* otherwise defer to `base.locale()`. Passes through setLocale and the rest of LocaleResolver.
|
|
39
|
+
* Without `translateFor`, `base.translate` must already be locale-live.
|
|
40
|
+
*/
|
|
41
|
+
export declare function wrapUrlLocaleResolver(base: LocaleResolver, options: WrapUrlLocaleResolverOptions): LocaleResolver;
|