@xemahq/ui-kernel 0.10.0 → 0.11.1
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/dist/lib/biome-host/agent-validation.d.ts.map +1 -1
- package/dist/lib/biome-host/agent-validation.js +26 -13
- package/dist/lib/biome-host/agent-validation.js.map +1 -1
- package/dist/lib/biome-host/biome-registry.d.ts.map +1 -1
- package/dist/lib/biome-host/biome-registry.js +27 -10
- package/dist/lib/biome-host/biome-registry.js.map +1 -1
- package/dist/lib/biome-host/biome-scope-hooks.d.ts.map +1 -1
- package/dist/lib/biome-host/biome-scope-hooks.js +2 -1
- package/dist/lib/biome-host/biome-scope-hooks.js.map +1 -1
- package/dist/lib/biome-host/biome-scoped-query.d.ts.map +1 -1
- package/dist/lib/biome-host/biome-scoped-query.js +5 -3
- package/dist/lib/biome-host/biome-scoped-query.js.map +1 -1
- package/dist/lib/biome-host/frontend-biome.d.ts +1 -1
- package/dist/lib/biome-host/frontend-biome.d.ts.map +1 -1
- package/dist/lib/biome-host/host-bridge.d.ts +1 -1
- package/dist/lib/biome-host/host-bridge.d.ts.map +1 -1
- package/dist/lib/biome-host/host-bridge.js.map +1 -1
- package/dist/lib/biome-host/i18n-hooks.d.ts.map +1 -1
- package/dist/lib/biome-host/i18n-hooks.js.map +1 -1
- package/dist/lib/biome-host/realtime-hooks.d.ts.map +1 -1
- package/dist/lib/biome-host/realtime-hooks.js.map +1 -1
- package/dist/lib/biome-host/session-contributions.d.ts +1 -1
- package/dist/lib/biome-host/session-contributions.d.ts.map +1 -1
- package/dist/lib/biome-host/use-mutation-with-error-toast.d.ts.map +1 -1
- package/dist/lib/biome-host/use-mutation-with-error-toast.js +3 -2
- package/dist/lib/biome-host/use-mutation-with-error-toast.js.map +1 -1
- package/dist/lib/biome-host/use-page-state.d.ts.map +1 -1
- package/dist/lib/biome-host/use-page-state.js +19 -10
- package/dist/lib/biome-host/use-page-state.js.map +1 -1
- package/dist/lib/capabilities/capability-provider.d.ts +1 -1
- package/dist/lib/capabilities/capability-provider.d.ts.map +1 -1
- package/dist/lib/capabilities/capability-provider.js +2 -2
- package/dist/lib/capabilities/capability-provider.js.map +1 -1
- package/dist/lib/capabilities/use-capability.d.ts +1 -1
- package/dist/lib/capabilities/use-capability.d.ts.map +1 -1
- package/dist/lib/capabilities/use-capability.js +2 -1
- package/dist/lib/capabilities/use-capability.js.map +1 -1
- package/dist/lib/contribution-registry/contribution-registry.d.ts.map +1 -1
- package/dist/lib/contribution-registry/contribution-registry.js +2 -1
- package/dist/lib/contribution-registry/contribution-registry.js.map +1 -1
- package/dist/lib/system-bus/deeplink.d.ts.map +1 -1
- package/dist/lib/system-bus/deeplink.js +4 -2
- package/dist/lib/system-bus/deeplink.js.map +1 -1
- package/dist/lib/system-bus/host-ports.d.ts +2 -2
- package/dist/lib/system-bus/host-ports.d.ts.map +1 -1
- package/dist/lib/system-bus/intent-registry.d.ts.map +1 -1
- package/dist/lib/system-bus/intent-registry.js +6 -3
- package/dist/lib/system-bus/intent-registry.js.map +1 -1
- package/dist/lib/system-bus/intents.d.ts +1 -1
- package/dist/lib/system-bus/intents.d.ts.map +1 -1
- package/dist/lib/system-bus/palette.d.ts +1 -1
- package/dist/lib/system-bus/palette.d.ts.map +1 -1
- package/dist/lib/system-bus/system-bus-builder.d.ts.map +1 -1
- package/dist/lib/system-bus/system-bus-builder.js +1 -1
- package/dist/lib/system-bus/system-bus-builder.js.map +1 -1
- package/dist/lib/system-bus/windows.d.ts +1 -1
- package/dist/lib/system-bus/windows.d.ts.map +1 -1
- package/dist/offline/outbox.d.ts +1 -0
- package/dist/offline/outbox.d.ts.map +1 -1
- package/dist/offline/outbox.js +4 -1
- package/dist/offline/outbox.js.map +1 -1
- package/dist/offline/react-hooks.d.ts +1 -1
- package/dist/offline/react-hooks.d.ts.map +1 -1
- package/dist/offline/react-hooks.js.map +1 -1
- package/dist/org-db/components/DbResultTable.d.ts.map +1 -1
- package/dist/org-db/components/DbResultTable.js +15 -6
- package/dist/org-db/components/DbResultTable.js.map +1 -1
- package/dist/registry/lib/agent-validation-host.d.ts.map +1 -1
- package/dist/registry/lib/agent-validation-host.js +1 -1
- package/dist/registry/lib/agent-validation-host.js.map +1 -1
- package/dist/registry/lib/biome-slot.d.ts.map +1 -1
- package/dist/registry/lib/biome-slot.js +5 -3
- package/dist/registry/lib/biome-slot.js.map +1 -1
- package/dist/registry/lib/primitives/SessionEventCard.d.ts.map +1 -1
- package/dist/registry/lib/primitives/SessionEventCard.js +14 -2
- package/dist/registry/lib/primitives/SessionEventCard.js.map +1 -1
- package/dist/registry/lib/primitives/SessionEventTimeline.d.ts.map +1 -1
- package/dist/registry/lib/primitives/SessionEventTimeline.js +6 -3
- package/dist/registry/lib/primitives/SessionEventTimeline.js.map +1 -1
- package/dist/registry/lib/primitives/SessionTabbedDrawer.d.ts.map +1 -1
- package/dist/registry/lib/primitives/SessionTabbedDrawer.js +10 -5
- package/dist/registry/lib/primitives/SessionTabbedDrawer.js.map +1 -1
- package/dist/registry/lib/session-context-provider.d.ts +1 -1
- package/dist/registry/lib/session-context-provider.d.ts.map +1 -1
- package/dist/registry/lib/session-context-provider.js.map +1 -1
- package/dist/registry/lib/session-selectors.d.ts.map +1 -1
- package/dist/registry/lib/session-selectors.js +35 -20
- package/dist/registry/lib/session-selectors.js.map +1 -1
- package/dist/session/comments/CommentRail.d.ts.map +1 -1
- package/dist/session/comments/CommentRail.js.map +1 -1
- package/dist/session/shell/SessionWorkspaceShell.d.ts.map +1 -1
- package/dist/session/shell/SessionWorkspaceShell.js.map +1 -1
- package/dist/session-kit/approvals/ApprovalCard.d.ts.map +1 -1
- package/dist/session-kit/approvals/ApprovalCard.js +6 -2
- package/dist/session-kit/approvals/ApprovalCard.js.map +1 -1
- package/dist/session-kit/approvals/ApprovalsCenter.d.ts.map +1 -1
- package/dist/session-kit/approvals/ApprovalsCenter.js +6 -3
- package/dist/session-kit/approvals/ApprovalsCenter.js.map +1 -1
- package/dist/session-kit/combobox/Combobox.d.ts.map +1 -1
- package/dist/session-kit/combobox/Combobox.js +20 -6
- package/dist/session-kit/combobox/Combobox.js.map +1 -1
- package/dist/session-kit/display/MD.d.ts.map +1 -1
- package/dist/session-kit/display/MD.js +7 -4
- package/dist/session-kit/display/MD.js.map +1 -1
- package/dist/ui/branding/app-branding-provider.d.ts.map +1 -1
- package/dist/ui/branding/app-branding-provider.js.map +1 -1
- package/dist/ui/branding/sanitize.d.ts.map +1 -1
- package/dist/ui/branding/sanitize.js +12 -6
- package/dist/ui/branding/sanitize.js.map +1 -1
- package/dist/ui/capture/document-preview.d.ts +1 -1
- package/dist/ui/capture/document-preview.d.ts.map +1 -1
- package/dist/ui/capture/document-preview.js +8 -6
- package/dist/ui/capture/document-preview.js.map +1 -1
- package/dist/ui/capture/field-spec-to-zod.d.ts.map +1 -1
- package/dist/ui/capture/field-spec-to-zod.js +45 -16
- package/dist/ui/capture/field-spec-to-zod.js.map +1 -1
- package/dist/ui/capture/field-spec-validate.d.ts.map +1 -1
- package/dist/ui/capture/field-spec-validate.js +79 -38
- package/dist/ui/capture/field-spec-validate.js.map +1 -1
- package/dist/ui/capture/field-spec.d.ts.map +1 -1
- package/dist/ui/capture/field-spec.js +17 -6
- package/dist/ui/capture/field-spec.js.map +1 -1
- package/dist/ui/capture/schema-field-input.d.ts.map +1 -1
- package/dist/ui/capture/schema-field-input.js +23 -18
- package/dist/ui/capture/schema-field-input.js.map +1 -1
- package/dist/ui/capture/schema-form.d.ts +1 -1
- package/dist/ui/capture/schema-form.d.ts.map +1 -1
- package/dist/ui/capture/schema-form.js +7 -6
- package/dist/ui/capture/schema-form.js.map +1 -1
- package/dist/ui/capture/use-prefill.d.ts.map +1 -1
- package/dist/ui/capture/use-prefill.js +32 -14
- package/dist/ui/capture/use-prefill.js.map +1 -1
- package/dist/ui/capture/use-schema-validation.d.ts +1 -1
- package/dist/ui/capture/use-schema-validation.d.ts.map +1 -1
- package/dist/ui/capture/use-schema-validation.js +13 -8
- package/dist/ui/capture/use-schema-validation.js.map +1 -1
- package/dist/ui/capture/use-wizard.d.ts.map +1 -1
- package/dist/ui/capture/use-wizard.js +23 -8
- package/dist/ui/capture/use-wizard.js.map +1 -1
- package/dist/ui/capture/value-format.d.ts.map +1 -1
- package/dist/ui/capture/value-format.js +6 -3
- package/dist/ui/capture/value-format.js.map +1 -1
- package/dist/ui/capture/wizard.d.ts.map +1 -1
- package/dist/ui/capture/wizard.js +3 -3
- package/dist/ui/capture/wizard.js.map +1 -1
- package/dist/ui/charts/bar-chart.d.ts +1 -1
- package/dist/ui/charts/bar-chart.d.ts.map +1 -1
- package/dist/ui/charts/bar-chart.js +1 -1
- package/dist/ui/charts/bar-chart.js.map +1 -1
- package/dist/ui/charts/chart-frame.d.ts +2 -2
- package/dist/ui/charts/chart-frame.d.ts.map +1 -1
- package/dist/ui/charts/chart-frame.js +4 -3
- package/dist/ui/charts/chart-frame.js.map +1 -1
- package/dist/ui/charts/chart-utils.d.ts.map +1 -1
- package/dist/ui/charts/chart-utils.js +32 -14
- package/dist/ui/charts/chart-utils.js.map +1 -1
- package/dist/ui/charts/donut-chart.d.ts +1 -1
- package/dist/ui/charts/donut-chart.d.ts.map +1 -1
- package/dist/ui/charts/donut-chart.js +7 -3
- package/dist/ui/charts/donut-chart.js.map +1 -1
- package/dist/ui/charts/line-chart.d.ts +1 -1
- package/dist/ui/charts/line-chart.d.ts.map +1 -1
- package/dist/ui/charts/line-chart.js +7 -4
- package/dist/ui/charts/line-chart.js.map +1 -1
- package/dist/ui/charts/sparkline.d.ts +1 -1
- package/dist/ui/charts/sparkline.d.ts.map +1 -1
- package/dist/ui/charts/sparkline.js +10 -6
- package/dist/ui/charts/sparkline.js.map +1 -1
- package/dist/ui/chrome/AsyncBoundary.d.ts +2 -2
- package/dist/ui/chrome/AsyncBoundary.d.ts.map +1 -1
- package/dist/ui/chrome/AsyncBoundary.js +3 -3
- package/dist/ui/chrome/AsyncBoundary.js.map +1 -1
- package/dist/ui/chrome/EmptyState.d.ts +19 -8
- package/dist/ui/chrome/EmptyState.d.ts.map +1 -1
- package/dist/ui/chrome/EmptyState.js +6 -4
- package/dist/ui/chrome/EmptyState.js.map +1 -1
- package/dist/ui/chrome/RecordCardList.d.ts +19 -0
- package/dist/ui/chrome/RecordCardList.d.ts.map +1 -0
- package/dist/ui/chrome/RecordCardList.js +12 -0
- package/dist/ui/chrome/RecordCardList.js.map +1 -0
- package/dist/ui/chrome/page-shell.d.ts +1 -1
- package/dist/ui/chrome/page-shell.d.ts.map +1 -1
- package/dist/ui/chrome/page-shell.js +16 -5
- package/dist/ui/chrome/page-shell.js.map +1 -1
- package/dist/ui/chrome/status-badge.d.ts.map +1 -1
- package/dist/ui/chrome/status-badge.js +1 -1
- package/dist/ui/chrome/status-badge.js.map +1 -1
- package/dist/ui/design-tokens.d.ts +4 -6
- package/dist/ui/design-tokens.d.ts.map +1 -1
- package/dist/ui/design-tokens.js +17 -11
- package/dist/ui/design-tokens.js.map +1 -1
- package/dist/ui/index.d.ts +1 -0
- package/dist/ui/index.d.ts.map +1 -1
- package/dist/ui/index.js +1 -0
- package/dist/ui/index.js.map +1 -1
- package/dist/ui/primitives/async-combobox.d.ts.map +1 -1
- package/dist/ui/primitives/async-combobox.js +4 -2
- package/dist/ui/primitives/async-combobox.js.map +1 -1
- package/dist/ui/primitives/badge.d.ts +2 -2
- package/dist/ui/primitives/badge.d.ts.map +1 -1
- package/dist/ui/primitives/badge.js +3 -3
- package/dist/ui/primitives/badge.js.map +1 -1
- package/dist/ui/primitives/button.d.ts +2 -2
- package/dist/ui/primitives/button.d.ts.map +1 -1
- package/dist/ui/primitives/button.js +5 -5
- package/dist/ui/primitives/button.js.map +1 -1
- package/dist/ui/primitives/overflow-tabs.d.ts.map +1 -1
- package/dist/ui/primitives/overflow-tabs.js +19 -12
- package/dist/ui/primitives/overflow-tabs.js.map +1 -1
- package/dist/ui/primitives/preview-device-frame.js +8 -4
- package/dist/ui/primitives/preview-device-frame.js.map +1 -1
- package/dist/ui/primitives/tag-multi-select.d.ts.map +1 -1
- package/dist/ui/primitives/tag-multi-select.js +10 -5
- package/dist/ui/primitives/tag-multi-select.js.map +1 -1
- package/dist/ui/primitives/url-preview-chrome.d.ts.map +1 -1
- package/dist/ui/primitives/url-preview-chrome.js.map +1 -1
- package/dist/vista/GenericCatalogueSurface.d.ts.map +1 -1
- package/dist/vista/GenericCatalogueSurface.js +5 -3
- package/dist/vista/GenericCatalogueSurface.js.map +1 -1
- package/dist/vista/VistaPanel.d.ts.map +1 -1
- package/dist/vista/VistaPanel.js +8 -4
- package/dist/vista/VistaPanel.js.map +1 -1
- package/dist/vista/html/CustomUiFrame.d.ts.map +1 -1
- package/dist/vista/html/CustomUiFrame.js +2 -1
- package/dist/vista/html/CustomUiFrame.js.map +1 -1
- package/dist/vista/html/custom-ui-frame-bridge.d.ts.map +1 -1
- package/dist/vista/html/custom-ui-frame-bridge.js +6 -3
- package/dist/vista/html/custom-ui-frame-bridge.js.map +1 -1
- package/dist/vista/html/custom-ui-intents.d.ts.map +1 -1
- package/dist/vista/html/custom-ui-intents.js +13 -15
- package/dist/vista/html/custom-ui-intents.js.map +1 -1
- package/dist/vista/surface-catalogue.d.ts.map +1 -1
- package/dist/vista/surface-catalogue.js +6 -3
- package/dist/vista/surface-catalogue.js.map +1 -1
- package/dist/vista/surfaces/FormSurface.d.ts.map +1 -1
- package/dist/vista/surfaces/FormSurface.js +20 -7
- package/dist/vista/surfaces/FormSurface.js.map +1 -1
- package/dist/vista/surfaces/TableSurface.d.ts.map +1 -1
- package/dist/vista/surfaces/TableSurface.js +2 -1
- package/dist/vista/surfaces/TableSurface.js.map +1 -1
- package/dist/vista/surfaces/blob-surfaces.d.ts.map +1 -1
- package/dist/vista/surfaces/blob-surfaces.js +7 -2
- package/dist/vista/surfaces/blob-surfaces.js.map +1 -1
- package/dist/vista/surfaces/elicitation-transport.d.ts.map +1 -1
- package/dist/vista/surfaces/elicitation-transport.js +14 -7
- package/dist/vista/surfaces/elicitation-transport.js.map +1 -1
- package/dist/vista/surfaces/file-surface-utils.d.ts.map +1 -1
- package/dist/vista/surfaces/file-surface-utils.js +8 -4
- package/dist/vista/surfaces/file-surface-utils.js.map +1 -1
- package/dist/vista/surfaces/register-surfaces.js +2 -1
- package/dist/vista/surfaces/register-surfaces.js.map +1 -1
- package/dist/vista/surfaces/text-surfaces.d.ts +1 -1
- package/dist/vista/surfaces/text-surfaces.d.ts.map +1 -1
- package/dist/vista/surfaces/text-surfaces.js +13 -7
- package/dist/vista/surfaces/text-surfaces.js.map +1 -1
- package/dist/vista/use-vista-tabs.d.ts.map +1 -1
- package/dist/vista/use-vista-tabs.js +8 -4
- package/dist/vista/use-vista-tabs.js.map +1 -1
- package/dist/vista/vista-code-renderer.d.ts.map +1 -1
- package/dist/vista/vista-code-renderer.js.map +1 -1
- package/dist/vista/vista-file-source.d.ts.map +1 -1
- package/dist/vista/vista-file-source.js +9 -5
- package/dist/vista/vista-file-source.js.map +1 -1
- package/dist/vista/vista-form-host.d.ts.map +1 -1
- package/dist/vista/vista-form-host.js +1 -1
- package/dist/vista/vista-form-host.js.map +1 -1
- package/dist/vista/vista-model.d.ts.map +1 -1
- package/dist/vista/vista-model.js +5 -3
- package/dist/vista/vista-model.js.map +1 -1
- package/dist/vista/vista-open-context.d.ts.map +1 -1
- package/dist/vista/vista-open-context.js +1 -1
- package/dist/vista/vista-open-context.js.map +1 -1
- package/dist/vista/vista-payloads.d.ts.map +1 -1
- package/dist/vista/vista-payloads.js +127 -63
- package/dist/vista/vista-payloads.js.map +1 -1
- package/dist/vista/vista-tabs-manifest.d.ts.map +1 -1
- package/dist/vista/vista-tabs-manifest.js +18 -9
- package/dist/vista/vista-tabs-manifest.js.map +1 -1
- package/dist/vista/vista-tools.d.ts.map +1 -1
- package/dist/vista/vista-tools.js +12 -6
- package/dist/vista/vista-tools.js.map +1 -1
- package/package.json +7 -4
- package/src/lib/biome-host/agent-validation.ts +37 -13
- package/src/lib/biome-host/biome-registry.ts +48 -13
- package/src/lib/biome-host/biome-scope-hooks.ts +3 -1
- package/src/lib/biome-host/biome-scoped-query.ts +7 -6
- package/src/lib/biome-host/frontend-biome.ts +1 -1
- package/src/lib/biome-host/host-bridge.ts +5 -4
- package/src/lib/biome-host/i18n-hooks.ts +1 -0
- package/src/lib/biome-host/realtime-hooks.ts +1 -0
- package/src/lib/biome-host/session-contributions.ts +1 -1
- package/src/lib/biome-host/use-mutation-with-error-toast.ts +4 -2
- package/src/lib/biome-host/use-page-state.ts +27 -10
- package/src/lib/capabilities/capability-provider.tsx +12 -5
- package/src/lib/capabilities/use-capability.ts +8 -4
- package/src/lib/contribution-registry/contribution-registry.ts +3 -1
- package/src/lib/system-bus/deeplink.ts +14 -4
- package/src/lib/system-bus/host-ports.ts +3 -7
- package/src/lib/system-bus/intent-registry.ts +12 -8
- package/src/lib/system-bus/intents.ts +6 -2
- package/src/lib/system-bus/palette.ts +2 -1
- package/src/lib/system-bus/system-bus-builder.ts +4 -2
- package/src/lib/system-bus/windows.ts +1 -1
- package/src/offline/outbox.test.ts +12 -3
- package/src/offline/outbox.ts +5 -1
- package/src/offline/react-hooks.ts +5 -2
- package/src/org-db/components/DbResultTable.tsx +48 -15
- package/src/registry/lib/agent-validation-host.ts +1 -2
- package/src/registry/lib/biome-slot.tsx +7 -4
- package/src/registry/lib/primitives/SessionEventCard.tsx +29 -5
- package/src/registry/lib/primitives/SessionEventTimeline.tsx +9 -3
- package/src/registry/lib/primitives/SessionTabbedDrawer.tsx +15 -5
- package/src/registry/lib/session-context-provider.tsx +1 -1
- package/src/registry/lib/session-selectors.ts +66 -27
- package/src/session/comments/CommentRail.tsx +2 -2
- package/src/session/shell/SessionWorkspaceShell.tsx +2 -2
- package/src/session-kit/approvals/ApprovalCard.tsx +7 -2
- package/src/session-kit/approvals/ApprovalsCenter.tsx +13 -4
- package/src/session-kit/combobox/Combobox.tsx +42 -11
- package/src/session-kit/display/MD.tsx +14 -5
- package/src/ui/branding/app-branding-provider.tsx +2 -3
- package/src/ui/branding/sanitize.ts +18 -6
- package/src/ui/capture/document-preview.tsx +84 -19
- package/src/ui/capture/field-spec-to-zod.ts +62 -14
- package/src/ui/capture/field-spec-validate.ts +132 -43
- package/src/ui/capture/field-spec.test.ts +2 -2
- package/src/ui/capture/field-spec.ts +41 -10
- package/src/ui/capture/schema-field-input.tsx +218 -38
- package/src/ui/capture/schema-form.tsx +54 -13
- package/src/ui/capture/use-prefill.ts +50 -17
- package/src/ui/capture/use-schema-validation.ts +45 -13
- package/src/ui/capture/use-wizard.ts +57 -11
- package/src/ui/capture/value-format.ts +14 -4
- package/src/ui/capture/wizard.tsx +9 -5
- package/src/ui/charts/bar-chart.tsx +8 -4
- package/src/ui/charts/chart-frame.tsx +18 -5
- package/src/ui/charts/chart-utils.ts +47 -15
- package/src/ui/charts/donut-chart.tsx +24 -6
- package/src/ui/charts/line-chart.tsx +34 -12
- package/src/ui/charts/sparkline.tsx +17 -9
- package/src/ui/chrome/AsyncBoundary.tsx +14 -6
- package/src/ui/chrome/EmptyState.tsx +116 -43
- package/src/ui/chrome/RecordCardList.tsx +98 -0
- package/src/ui/chrome/page-shell.spec.tsx +117 -0
- package/src/ui/chrome/page-shell.tsx +81 -25
- package/src/ui/chrome/status-badge.tsx +8 -4
- package/src/ui/design-tokens.ts +39 -13
- package/src/ui/index.ts +5 -0
- package/src/ui/primitives/async-combobox.tsx +7 -3
- package/src/ui/primitives/badge.tsx +14 -5
- package/src/ui/primitives/button.tsx +13 -6
- package/src/ui/primitives/overflow-tabs.tsx +46 -16
- package/src/ui/primitives/preview-device-frame.tsx +12 -4
- package/src/ui/primitives/tag-multi-select.tsx +30 -9
- package/src/ui/primitives/url-preview-chrome.tsx +1 -0
- package/src/vista/GenericCatalogueSurface.tsx +7 -5
- package/src/vista/VistaPanel.tsx +12 -4
- package/src/vista/html/CustomUiFrame.spec.tsx +3 -1
- package/src/vista/html/CustomUiFrame.tsx +3 -1
- package/src/vista/html/custom-ui-frame-bridge.ts +9 -3
- package/src/vista/html/custom-ui-intents.spec.ts +3 -1
- package/src/vista/html/custom-ui-intents.ts +19 -15
- package/src/vista/surface-catalogue.ts +9 -3
- package/src/vista/surfaces/FormSurface.tsx +27 -10
- package/src/vista/surfaces/TableSurface.tsx +4 -3
- package/src/vista/surfaces/blob-surfaces.tsx +13 -3
- package/src/vista/surfaces/elicitation-transport.ts +21 -7
- package/src/vista/surfaces/file-surface-utils.ts +11 -4
- package/src/vista/surfaces/register-surfaces.tsx +3 -1
- package/src/vista/surfaces/text-surfaces.tsx +21 -8
- package/src/vista/use-vista-tabs.ts +12 -4
- package/src/vista/vista-code-renderer.tsx +6 -5
- package/src/vista/vista-file-source.tsx +15 -14
- package/src/vista/vista-form-host.tsx +3 -8
- package/src/vista/vista-model.ts +10 -3
- package/src/vista/vista-open-context.tsx +3 -8
- package/src/vista/vista-payloads.ts +186 -63
- package/src/vista/vista-tabs-manifest.ts +28 -13
- package/src/vista/vista-tools.ts +18 -6
|
@@ -33,28 +33,33 @@ import {
|
|
|
33
33
|
} from '../../index';
|
|
34
34
|
|
|
35
35
|
function sortByWeight<
|
|
36
|
-
T extends {
|
|
36
|
+
T extends {
|
|
37
|
+
readonly id: string;
|
|
38
|
+
readonly weight?: number;
|
|
39
|
+
readonly order?: number;
|
|
40
|
+
},
|
|
37
41
|
>(items: readonly T[]): readonly T[] {
|
|
38
42
|
return [...items].sort((a, b) => {
|
|
39
43
|
const aw = a.weight ?? a.order ?? 100;
|
|
40
44
|
const bw = b.weight ?? b.order ?? 100;
|
|
41
|
-
if (aw !== bw)
|
|
45
|
+
if (aw !== bw) {
|
|
46
|
+
return aw - bw;
|
|
47
|
+
}
|
|
42
48
|
return a.id.localeCompare(b.id);
|
|
43
49
|
});
|
|
44
50
|
}
|
|
45
51
|
|
|
46
|
-
type PredicateOf<T> = T extends {
|
|
52
|
+
type PredicateOf<T> = T extends {
|
|
53
|
+
readonly appliesTo?: (...args: infer A) => boolean;
|
|
54
|
+
}
|
|
47
55
|
? (...args: A) => boolean
|
|
48
56
|
: never;
|
|
49
57
|
|
|
50
|
-
function applies<
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
): boolean {
|
|
58
|
+
function applies<
|
|
59
|
+
T extends { readonly appliesTo?: (...args: never[]) => boolean },
|
|
60
|
+
>(item: T, args: Parameters<PredicateOf<T>>): boolean {
|
|
54
61
|
const predicate = item.appliesTo as PredicateOf<T> | undefined;
|
|
55
|
-
return predicate ===
|
|
56
|
-
? true
|
|
57
|
-
: predicate(...args);
|
|
62
|
+
return predicate === undefined ? true : predicate(...args);
|
|
58
63
|
}
|
|
59
64
|
|
|
60
65
|
// ── Slash commands ────────────────────────────────────────────────────
|
|
@@ -67,7 +72,9 @@ export function useSessionSlashCommands(
|
|
|
67
72
|
const out: SlashCommandContribution[] = [];
|
|
68
73
|
for (const biome of biomeRegistry.list()) {
|
|
69
74
|
for (const cmd of biome.session?.slashCommands ?? []) {
|
|
70
|
-
if (!applies(cmd, [session]))
|
|
75
|
+
if (!applies(cmd, [session])) {
|
|
76
|
+
continue;
|
|
77
|
+
}
|
|
71
78
|
out.push(cmd);
|
|
72
79
|
}
|
|
73
80
|
}
|
|
@@ -86,7 +93,9 @@ export function useSessionDrawerTabs(
|
|
|
86
93
|
const out: SecondaryDrawerTabContribution[] = [];
|
|
87
94
|
for (const biome of biomeRegistry.list()) {
|
|
88
95
|
for (const tab of biome.session?.secondaryDrawerTabs ?? []) {
|
|
89
|
-
if (!applies(tab, [session]))
|
|
96
|
+
if (!applies(tab, [session])) {
|
|
97
|
+
continue;
|
|
98
|
+
}
|
|
90
99
|
out.push(tab);
|
|
91
100
|
}
|
|
92
101
|
}
|
|
@@ -116,12 +125,18 @@ export function useActivityRenderer(
|
|
|
116
125
|
const candidates: ActivityRendererContribution[] = [];
|
|
117
126
|
for (const biome of biomeRegistry.list()) {
|
|
118
127
|
for (const r of biome.session?.activityRenderers ?? []) {
|
|
119
|
-
if (r.entryKind !== event.kind)
|
|
120
|
-
|
|
128
|
+
if (r.entryKind !== event.kind) {
|
|
129
|
+
continue;
|
|
130
|
+
}
|
|
131
|
+
if (!applies(r, [{ session, event }])) {
|
|
132
|
+
continue;
|
|
133
|
+
}
|
|
121
134
|
candidates.push(r);
|
|
122
135
|
}
|
|
123
136
|
}
|
|
124
|
-
if (candidates.length === 0)
|
|
137
|
+
if (candidates.length === 0) {
|
|
138
|
+
return null;
|
|
139
|
+
}
|
|
125
140
|
return sortByWeight(candidates)[0] ?? null;
|
|
126
141
|
// eslint-disable-next-line react-hooks/exhaustive-deps
|
|
127
142
|
}, [revision, session, event]);
|
|
@@ -132,24 +147,38 @@ export function useActivityRenderer(
|
|
|
132
147
|
type ToolMatch = 'exact' | 'glob' | 'none';
|
|
133
148
|
|
|
134
149
|
function matchToolName(toolName: string, eventName: string): ToolMatch {
|
|
135
|
-
if (toolName === eventName)
|
|
136
|
-
|
|
150
|
+
if (toolName === eventName) {
|
|
151
|
+
return 'exact';
|
|
152
|
+
}
|
|
153
|
+
if (toolName.endsWith('.*') && eventName.startsWith(toolName.slice(0, -1))) {
|
|
154
|
+
return 'glob';
|
|
155
|
+
}
|
|
137
156
|
return 'none';
|
|
138
157
|
}
|
|
139
158
|
|
|
140
159
|
function collectToolCallCandidates(
|
|
141
160
|
session: SessionContext,
|
|
142
161
|
event: SessionToolCallEvent,
|
|
143
|
-
): {
|
|
162
|
+
): {
|
|
163
|
+
exact: ToolCallRendererContribution[];
|
|
164
|
+
glob: ToolCallRendererContribution[];
|
|
165
|
+
} {
|
|
144
166
|
const exact: ToolCallRendererContribution[] = [];
|
|
145
167
|
const glob: ToolCallRendererContribution[] = [];
|
|
146
168
|
for (const biome of biomeRegistry.list()) {
|
|
147
169
|
for (const r of biome.session?.toolCallRenderers ?? []) {
|
|
148
170
|
const match = matchToolName(r.toolName, event.name);
|
|
149
|
-
if (match === 'none')
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
171
|
+
if (match === 'none') {
|
|
172
|
+
continue;
|
|
173
|
+
}
|
|
174
|
+
if (!applies(r, [{ session, event }])) {
|
|
175
|
+
continue;
|
|
176
|
+
}
|
|
177
|
+
if (match === 'exact') {
|
|
178
|
+
exact.push(r);
|
|
179
|
+
} else {
|
|
180
|
+
glob.push(r);
|
|
181
|
+
}
|
|
153
182
|
}
|
|
154
183
|
}
|
|
155
184
|
return { exact, glob };
|
|
@@ -168,8 +197,12 @@ export function useToolCallRenderer(
|
|
|
168
197
|
const revision = useBiomeRegistryRevision();
|
|
169
198
|
return useMemo(() => {
|
|
170
199
|
const { exact, glob } = collectToolCallCandidates(session, event);
|
|
171
|
-
if (exact.length > 0)
|
|
172
|
-
|
|
200
|
+
if (exact.length > 0) {
|
|
201
|
+
return sortByWeight(exact)[0] ?? null;
|
|
202
|
+
}
|
|
203
|
+
if (glob.length > 0) {
|
|
204
|
+
return sortByWeight(glob)[0] ?? null;
|
|
205
|
+
}
|
|
173
206
|
return null;
|
|
174
207
|
// eslint-disable-next-line react-hooks/exhaustive-deps
|
|
175
208
|
}, [revision, session, event]);
|
|
@@ -185,7 +218,9 @@ export function useSessionMutationBars(
|
|
|
185
218
|
const out: MutationBarContribution[] = [];
|
|
186
219
|
for (const biome of biomeRegistry.list()) {
|
|
187
220
|
for (const bar of biome.session?.mutationBars ?? []) {
|
|
188
|
-
if (!applies(bar, [session]))
|
|
221
|
+
if (!applies(bar, [session])) {
|
|
222
|
+
continue;
|
|
223
|
+
}
|
|
189
224
|
out.push(bar);
|
|
190
225
|
}
|
|
191
226
|
}
|
|
@@ -204,7 +239,9 @@ export function useSessionHeaderChips(
|
|
|
204
239
|
const out: HeaderChipContribution[] = [];
|
|
205
240
|
for (const biome of biomeRegistry.list()) {
|
|
206
241
|
for (const chip of biome.session?.headerChips ?? []) {
|
|
207
|
-
if (!applies(chip, [session]))
|
|
242
|
+
if (!applies(chip, [session])) {
|
|
243
|
+
continue;
|
|
244
|
+
}
|
|
208
245
|
out.push(chip);
|
|
209
246
|
}
|
|
210
247
|
}
|
|
@@ -223,7 +260,9 @@ export function useSessionAttachmentClasses(
|
|
|
223
260
|
const out: AttachmentClassContribution[] = [];
|
|
224
261
|
for (const biome of biomeRegistry.list()) {
|
|
225
262
|
for (const cls of biome.session?.attachmentClasses ?? []) {
|
|
226
|
-
if (!applies(cls, [session]))
|
|
263
|
+
if (!applies(cls, [session])) {
|
|
264
|
+
continue;
|
|
265
|
+
}
|
|
227
266
|
out.push(cls);
|
|
228
267
|
}
|
|
229
268
|
}
|
|
@@ -1,7 +1,7 @@
|
|
|
1
|
-
import type { ReactNode } from 'react';
|
|
2
|
-
|
|
3
1
|
import { cn } from '../lib/cn';
|
|
4
2
|
|
|
3
|
+
import type { ReactNode } from 'react';
|
|
4
|
+
|
|
5
5
|
/**
|
|
6
6
|
* Generic, data-layer-agnostic comment shape. Host surfaces map their
|
|
7
7
|
* own DTOs (KB `DocumentCommentResponseDto`, workflow `InquiryReply`,
|
|
@@ -1,7 +1,7 @@
|
|
|
1
|
-
import type { CSSProperties, ReactNode, MouseEvent, RefObject } from 'react';
|
|
2
|
-
|
|
3
1
|
import { cn } from '../lib/cn';
|
|
4
2
|
|
|
3
|
+
import type { CSSProperties, ReactNode, MouseEvent, RefObject } from 'react';
|
|
4
|
+
|
|
5
5
|
interface SessionWorkspaceShellProps {
|
|
6
6
|
/**
|
|
7
7
|
* Container ref from `useHorizontalSplit`. The shell forwards mouse
|
|
@@ -68,7 +68,9 @@ export function ApprovalCard({
|
|
|
68
68
|
const approveLabel = resolveApproveLabel(request, quorum, explicit);
|
|
69
69
|
|
|
70
70
|
function resolve(d: ApprovalDecision): void {
|
|
71
|
-
if (decision === undefined)
|
|
71
|
+
if (decision === undefined) {
|
|
72
|
+
setLocalDecision(d);
|
|
73
|
+
}
|
|
72
74
|
onResolve(d, request);
|
|
73
75
|
}
|
|
74
76
|
|
|
@@ -209,7 +211,10 @@ export function ApprovalCard({
|
|
|
209
211
|
|
|
210
212
|
{/* SCOPED biome body */}
|
|
211
213
|
<div
|
|
212
|
-
style={{
|
|
214
|
+
style={{
|
|
215
|
+
padding: '10px 14px',
|
|
216
|
+
background: 'hsl(var(--paper) / 0.5)',
|
|
217
|
+
}}
|
|
213
218
|
>
|
|
214
219
|
<div
|
|
215
220
|
style={{
|
|
@@ -52,8 +52,11 @@ export function ApprovalsCenter({
|
|
|
52
52
|
const toggle = useCallback((id: string) => {
|
|
53
53
|
setSelected((prev) => {
|
|
54
54
|
const next = new Set(prev);
|
|
55
|
-
if (next.has(id))
|
|
56
|
-
|
|
55
|
+
if (next.has(id)) {
|
|
56
|
+
next.delete(id);
|
|
57
|
+
} else {
|
|
58
|
+
next.add(id);
|
|
59
|
+
}
|
|
57
60
|
return next;
|
|
58
61
|
});
|
|
59
62
|
}, []);
|
|
@@ -71,7 +74,9 @@ export function ApprovalsCenter({
|
|
|
71
74
|
const approveSelected = useCallback(() => {
|
|
72
75
|
for (const id of selected) {
|
|
73
76
|
const it = items.find((x) => x.id === id);
|
|
74
|
-
if (it)
|
|
77
|
+
if (it) {
|
|
78
|
+
onResolve(ApprovalDecision.Approved, it);
|
|
79
|
+
}
|
|
75
80
|
}
|
|
76
81
|
setSelected(new Set());
|
|
77
82
|
}, [selected, items, onResolve]);
|
|
@@ -302,7 +307,11 @@ function ApprovalRow({
|
|
|
302
307
|
}}
|
|
303
308
|
>
|
|
304
309
|
{onOpen && (
|
|
305
|
-
<ApprovalButton
|
|
310
|
+
<ApprovalButton
|
|
311
|
+
variant="ghost"
|
|
312
|
+
size="xs"
|
|
313
|
+
onClick={() => onOpen(item)}
|
|
314
|
+
>
|
|
306
315
|
Open session
|
|
307
316
|
</ApprovalButton>
|
|
308
317
|
)}
|
|
@@ -108,7 +108,9 @@ const POP_STYLE: CSSProperties = {
|
|
|
108
108
|
overflow: 'hidden',
|
|
109
109
|
};
|
|
110
110
|
|
|
111
|
-
export function Combobox<V extends string>(
|
|
111
|
+
export function Combobox<V extends string>(
|
|
112
|
+
props: ComboboxProps<V>,
|
|
113
|
+
): ReactElement {
|
|
112
114
|
const {
|
|
113
115
|
items,
|
|
114
116
|
trigger,
|
|
@@ -134,12 +136,16 @@ export function Combobox<V extends string>(props: ComboboxProps<V>): ReactElemen
|
|
|
134
136
|
// Move focus to the search field when the dropdown opens (replaces the
|
|
135
137
|
// a11y-discouraged `autoFocus` attribute).
|
|
136
138
|
useEffect(() => {
|
|
137
|
-
if (open && showSearch)
|
|
139
|
+
if (open && showSearch) {
|
|
140
|
+
searchRef.current?.focus();
|
|
141
|
+
}
|
|
138
142
|
}, [open, showSearch]);
|
|
139
143
|
|
|
140
144
|
const filtered = query
|
|
141
145
|
? items.filter((it) =>
|
|
142
|
-
`${it.label} ${it.hint ?? ''}
|
|
146
|
+
`${it.label} ${it.hint ?? ''}`
|
|
147
|
+
.toLowerCase()
|
|
148
|
+
.includes(query.toLowerCase()),
|
|
143
149
|
)
|
|
144
150
|
: items;
|
|
145
151
|
|
|
@@ -181,7 +187,9 @@ export function Combobox<V extends string>(props: ComboboxProps<V>): ReactElemen
|
|
|
181
187
|
}}
|
|
182
188
|
>
|
|
183
189
|
{icons?.search && (
|
|
184
|
-
<span
|
|
190
|
+
<span
|
|
191
|
+
style={{ display: 'inline-flex', color: 'hsl(var(--ink-3))' }}
|
|
192
|
+
>
|
|
185
193
|
{icons.search}
|
|
186
194
|
</span>
|
|
187
195
|
)}
|
|
@@ -200,7 +208,10 @@ export function Combobox<V extends string>(props: ComboboxProps<V>): ReactElemen
|
|
|
200
208
|
}}
|
|
201
209
|
/>
|
|
202
210
|
{items.length > 0 && (
|
|
203
|
-
<span
|
|
211
|
+
<span
|
|
212
|
+
className="mono"
|
|
213
|
+
style={{ fontSize: 10, color: 'hsl(var(--ink-4))' }}
|
|
214
|
+
>
|
|
204
215
|
{filtered.length}/{items.length}
|
|
205
216
|
</span>
|
|
206
217
|
)}
|
|
@@ -223,12 +234,15 @@ export function Combobox<V extends string>(props: ComboboxProps<V>): ReactElemen
|
|
|
223
234
|
padding: '7px 9px',
|
|
224
235
|
borderRadius: 7,
|
|
225
236
|
textAlign: 'left',
|
|
226
|
-
background: singleSelected
|
|
237
|
+
background: singleSelected
|
|
238
|
+
? 'hsl(var(--accent) / 0.6)'
|
|
239
|
+
: 'transparent',
|
|
227
240
|
transition: 'background 140ms ease',
|
|
228
241
|
}}
|
|
229
242
|
onMouseEnter={(e) => {
|
|
230
243
|
if (!singleSelected) {
|
|
231
|
-
e.currentTarget.style.background =
|
|
244
|
+
e.currentTarget.style.background =
|
|
245
|
+
'hsl(var(--paper-sunk))';
|
|
232
246
|
}
|
|
233
247
|
}}
|
|
234
248
|
onMouseLeave={(e) => {
|
|
@@ -238,7 +252,13 @@ export function Combobox<V extends string>(props: ComboboxProps<V>): ReactElemen
|
|
|
238
252
|
}}
|
|
239
253
|
>
|
|
240
254
|
{it.icon && (
|
|
241
|
-
<span
|
|
255
|
+
<span
|
|
256
|
+
style={{
|
|
257
|
+
display: 'inline-flex',
|
|
258
|
+
color: 'hsl(var(--ink-3))',
|
|
259
|
+
flexShrink: 0,
|
|
260
|
+
}}
|
|
261
|
+
>
|
|
242
262
|
{it.icon}
|
|
243
263
|
</span>
|
|
244
264
|
)}
|
|
@@ -272,7 +292,10 @@ export function Combobox<V extends string>(props: ComboboxProps<V>): ReactElemen
|
|
|
272
292
|
)}
|
|
273
293
|
</span>
|
|
274
294
|
{it.kind && (
|
|
275
|
-
<span
|
|
295
|
+
<span
|
|
296
|
+
className="cap"
|
|
297
|
+
style={{ fontSize: 8.5, flexShrink: 0 }}
|
|
298
|
+
>
|
|
276
299
|
{it.kind}
|
|
277
300
|
</span>
|
|
278
301
|
)}
|
|
@@ -294,7 +317,13 @@ export function Combobox<V extends string>(props: ComboboxProps<V>): ReactElemen
|
|
|
294
317
|
</span>
|
|
295
318
|
) : (
|
|
296
319
|
on && (
|
|
297
|
-
<span
|
|
320
|
+
<span
|
|
321
|
+
style={{
|
|
322
|
+
display: 'inline-flex',
|
|
323
|
+
color: 'hsl(var(--primary))',
|
|
324
|
+
flexShrink: 0,
|
|
325
|
+
}}
|
|
326
|
+
>
|
|
298
327
|
{icons?.check}
|
|
299
328
|
</span>
|
|
300
329
|
)
|
|
@@ -316,7 +345,9 @@ export function Combobox<V extends string>(props: ComboboxProps<V>): ReactElemen
|
|
|
316
345
|
)}
|
|
317
346
|
</div>
|
|
318
347
|
{footer && (
|
|
319
|
-
<div
|
|
348
|
+
<div
|
|
349
|
+
style={{ borderTop: '1px solid hsl(var(--rule))', padding: 6 }}
|
|
350
|
+
>
|
|
320
351
|
{footer}
|
|
321
352
|
</div>
|
|
322
353
|
)}
|
|
@@ -33,10 +33,15 @@ function renderInline(text: string): ReactNode[] {
|
|
|
33
33
|
// Split on bold or inline-code tokens, keeping the delimiters.
|
|
34
34
|
const parts = text.split(/(\*\*[^*]+\*\*|`[^`]+`)/g);
|
|
35
35
|
parts.forEach((part, index) => {
|
|
36
|
-
if (!part)
|
|
36
|
+
if (!part) {
|
|
37
|
+
return;
|
|
38
|
+
}
|
|
37
39
|
if (part.startsWith('**') && part.endsWith('**')) {
|
|
38
40
|
nodes.push(
|
|
39
|
-
<strong
|
|
41
|
+
<strong
|
|
42
|
+
key={index}
|
|
43
|
+
style={{ fontWeight: 600, color: 'hsl(var(--ink))' }}
|
|
44
|
+
>
|
|
40
45
|
{part.slice(2, -2)}
|
|
41
46
|
</strong>,
|
|
42
47
|
);
|
|
@@ -53,8 +58,12 @@ function renderInline(text: string): ReactNode[] {
|
|
|
53
58
|
// Plain text — preserve hard line breaks.
|
|
54
59
|
const lines = part.split('\n');
|
|
55
60
|
lines.forEach((line, lineIndex) => {
|
|
56
|
-
if (lineIndex > 0)
|
|
57
|
-
|
|
61
|
+
if (lineIndex > 0) {
|
|
62
|
+
nodes.push(<br key={`${index}-br-${lineIndex}`} />);
|
|
63
|
+
}
|
|
64
|
+
if (line) {
|
|
65
|
+
nodes.push(<Fragment key={`${index}-t-${lineIndex}`}>{line}</Fragment>);
|
|
66
|
+
}
|
|
58
67
|
});
|
|
59
68
|
});
|
|
60
69
|
return nodes;
|
|
@@ -65,7 +74,7 @@ export interface MDProps {
|
|
|
65
74
|
}
|
|
66
75
|
|
|
67
76
|
export function MD({ children }: MDProps): ReactElement {
|
|
68
|
-
const text =
|
|
77
|
+
const text = children;
|
|
69
78
|
const blocks = text.split(/\n\n+/);
|
|
70
79
|
return (
|
|
71
80
|
<div style={{ display: 'flex', flexDirection: 'column', gap: 9 }}>
|
|
@@ -20,20 +20,19 @@
|
|
|
20
20
|
// ═══════════════════════════════════════════════════════════════════════════
|
|
21
21
|
import * as React from 'react';
|
|
22
22
|
|
|
23
|
-
import type { BrandingConfig } from '@xemahq/kernel-contracts/app-platform';
|
|
24
|
-
|
|
25
23
|
import { cn } from '../cn';
|
|
26
24
|
import {
|
|
27
25
|
AppBrandingContext,
|
|
28
26
|
type AppBrandingContextValue,
|
|
29
27
|
} from './app-branding-context';
|
|
30
|
-
|
|
31
28
|
import {
|
|
32
29
|
sanitizeCssCustomPropertyName,
|
|
33
30
|
sanitizeCssValue,
|
|
34
31
|
sanitizeLogoUrl,
|
|
35
32
|
} from './sanitize';
|
|
36
33
|
|
|
34
|
+
import type { BrandingConfig } from '@xemahq/kernel-contracts/app-platform';
|
|
35
|
+
|
|
37
36
|
/** CSS custom property carrying the app's resolved primary brand color. */
|
|
38
37
|
export const APP_PRIMARY_COLOR_VAR = '--app-primary-color';
|
|
39
38
|
|
|
@@ -30,7 +30,9 @@ const CSS_CUSTOM_PROPERTY_NAME = /^[a-zA-Z_][a-zA-Z0-9_-]*$/;
|
|
|
30
30
|
function hasControlChar(value: string): boolean {
|
|
31
31
|
for (let i = 0; i < value.length; i += 1) {
|
|
32
32
|
const code = value.charCodeAt(i);
|
|
33
|
-
if (code < 0x20 || code === 0x7f)
|
|
33
|
+
if (code < 0x20 || code === 0x7f) {
|
|
34
|
+
return true;
|
|
35
|
+
}
|
|
34
36
|
}
|
|
35
37
|
return false;
|
|
36
38
|
}
|
|
@@ -41,9 +43,15 @@ function hasControlChar(value: string): boolean {
|
|
|
41
43
|
*/
|
|
42
44
|
export function sanitizeCssValue(raw: string): string | null {
|
|
43
45
|
const value = raw.trim();
|
|
44
|
-
if (value.length === 0)
|
|
45
|
-
|
|
46
|
-
|
|
46
|
+
if (value.length === 0) {
|
|
47
|
+
return null;
|
|
48
|
+
}
|
|
49
|
+
if (CSS_VALUE_UNSAFE.test(value)) {
|
|
50
|
+
return null;
|
|
51
|
+
}
|
|
52
|
+
if (hasControlChar(value)) {
|
|
53
|
+
return null;
|
|
54
|
+
}
|
|
47
55
|
return value;
|
|
48
56
|
}
|
|
49
57
|
|
|
@@ -53,7 +61,9 @@ export function sanitizeCssValue(raw: string): string | null {
|
|
|
53
61
|
*/
|
|
54
62
|
export function sanitizeCssCustomPropertyName(rawKey: string): string | null {
|
|
55
63
|
const name = rawKey.trim();
|
|
56
|
-
if (!CSS_CUSTOM_PROPERTY_NAME.test(name))
|
|
64
|
+
if (!CSS_CUSTOM_PROPERTY_NAME.test(name)) {
|
|
65
|
+
return null;
|
|
66
|
+
}
|
|
57
67
|
return `--${name}`;
|
|
58
68
|
}
|
|
59
69
|
|
|
@@ -63,7 +73,9 @@ export function sanitizeCssCustomPropertyName(rawKey: string): string | null {
|
|
|
63
73
|
* is refused (returns `undefined`) so it never reaches `src`.
|
|
64
74
|
*/
|
|
65
75
|
export function sanitizeLogoUrl(raw: string | undefined): string | undefined {
|
|
66
|
-
if (raw === undefined)
|
|
76
|
+
if (raw === undefined) {
|
|
77
|
+
return undefined;
|
|
78
|
+
}
|
|
67
79
|
let parsed: URL;
|
|
68
80
|
try {
|
|
69
81
|
parsed = new URL(raw);
|
|
@@ -9,8 +9,14 @@
|
|
|
9
9
|
import { type ReactNode } from 'react';
|
|
10
10
|
|
|
11
11
|
import { cn } from '../cn';
|
|
12
|
-
|
|
13
|
-
|
|
12
|
+
import {
|
|
13
|
+
CaptureFieldType,
|
|
14
|
+
type CaptureFieldSpec,
|
|
15
|
+
type CaptureSchema,
|
|
16
|
+
type CaptureSection,
|
|
17
|
+
type CaptureValues,
|
|
18
|
+
toSections,
|
|
19
|
+
} from './field-spec';
|
|
14
20
|
import { formatScalar } from './value-format';
|
|
15
21
|
|
|
16
22
|
export interface DocumentPreviewProps {
|
|
@@ -28,18 +34,44 @@ export interface DocumentPreviewProps {
|
|
|
28
34
|
* @example
|
|
29
35
|
* <DocumentPreview title="Review" sections={sections} values={values} />
|
|
30
36
|
*/
|
|
31
|
-
export function DocumentPreview({
|
|
37
|
+
export function DocumentPreview({
|
|
38
|
+
fields,
|
|
39
|
+
sections,
|
|
40
|
+
schema,
|
|
41
|
+
values,
|
|
42
|
+
title,
|
|
43
|
+
emptyText = '—',
|
|
44
|
+
className,
|
|
45
|
+
}: DocumentPreviewProps) {
|
|
32
46
|
const resolved = toSections(sections ?? (fields ? fields : schema) ?? []);
|
|
33
47
|
return (
|
|
34
|
-
<article
|
|
35
|
-
|
|
48
|
+
<article
|
|
49
|
+
className={cn(
|
|
50
|
+
'rounded-xl border border-border bg-card p-5 text-card-foreground shadow-sm sm:p-6',
|
|
51
|
+
className,
|
|
52
|
+
)}
|
|
53
|
+
>
|
|
54
|
+
{title ? (
|
|
55
|
+
<h2 className="mb-4 text-title font-semibold tracking-tight text-ink">
|
|
56
|
+
{title}
|
|
57
|
+
</h2>
|
|
58
|
+
) : null}
|
|
36
59
|
<div className="space-y-6">
|
|
37
60
|
{resolved.map((section) => (
|
|
38
61
|
<section key={section.key}>
|
|
39
|
-
{section.title ?
|
|
62
|
+
{section.title ? (
|
|
63
|
+
<h3 className="mb-2 border-b border-rule pb-1 text-caption font-semibold uppercase tracking-wider text-ink-3">
|
|
64
|
+
{section.title}
|
|
65
|
+
</h3>
|
|
66
|
+
) : null}
|
|
40
67
|
<dl className="grid grid-cols-1 gap-x-6 gap-y-3 sm:grid-cols-[minmax(8rem,12rem)_1fr]">
|
|
41
68
|
{section.fields.map((field) => (
|
|
42
|
-
<FieldRow
|
|
69
|
+
<FieldRow
|
|
70
|
+
key={field.key}
|
|
71
|
+
field={field}
|
|
72
|
+
value={values[field.key]}
|
|
73
|
+
emptyText={emptyText}
|
|
74
|
+
/>
|
|
43
75
|
))}
|
|
44
76
|
</dl>
|
|
45
77
|
</section>
|
|
@@ -49,25 +81,49 @@ export function DocumentPreview({ fields, sections, schema, values, title, empty
|
|
|
49
81
|
);
|
|
50
82
|
}
|
|
51
83
|
|
|
52
|
-
function FieldRow({
|
|
84
|
+
function FieldRow({
|
|
85
|
+
field,
|
|
86
|
+
value,
|
|
87
|
+
emptyText,
|
|
88
|
+
}: {
|
|
89
|
+
field: CaptureFieldSpec;
|
|
90
|
+
value: unknown;
|
|
91
|
+
emptyText: string;
|
|
92
|
+
}) {
|
|
53
93
|
return (
|
|
54
94
|
<>
|
|
55
|
-
<dt className="text-body-1 font-medium text-ink-3 sm:text-right">
|
|
56
|
-
|
|
95
|
+
<dt className="text-body-1 font-medium text-ink-3 sm:text-right">
|
|
96
|
+
{field.label}
|
|
97
|
+
</dt>
|
|
98
|
+
<dd className="min-w-0 text-body-1 text-ink">
|
|
99
|
+
{renderValue(field, value, emptyText)}
|
|
100
|
+
</dd>
|
|
57
101
|
</>
|
|
58
102
|
);
|
|
59
103
|
}
|
|
60
104
|
|
|
61
|
-
function renderValue(
|
|
105
|
+
function renderValue(
|
|
106
|
+
field: CaptureFieldSpec,
|
|
107
|
+
value: unknown,
|
|
108
|
+
emptyText: string,
|
|
109
|
+
): ReactNode {
|
|
62
110
|
if (field.type === CaptureFieldType.Object) {
|
|
63
|
-
const record = (
|
|
64
|
-
|
|
111
|
+
const record = (
|
|
112
|
+
value && typeof value === 'object' && !Array.isArray(value) ? value : null
|
|
113
|
+
) as CaptureValues | null;
|
|
114
|
+
if (!record) {
|
|
115
|
+
return <span className="text-ink-3">{emptyText}</span>;
|
|
116
|
+
}
|
|
65
117
|
return (
|
|
66
118
|
<dl className="space-y-1 rounded-md border border-rule bg-paper-elev/40 p-2">
|
|
67
119
|
{(field.fields ?? []).map((child) => (
|
|
68
120
|
<div key={child.key} className="flex flex-wrap gap-2">
|
|
69
|
-
<dt className="text-caption font-medium text-ink-3">
|
|
70
|
-
|
|
121
|
+
<dt className="text-caption font-medium text-ink-3">
|
|
122
|
+
{child.label}:
|
|
123
|
+
</dt>
|
|
124
|
+
<dd className="text-caption text-ink">
|
|
125
|
+
{renderValue(child, record[child.key], emptyText)}
|
|
126
|
+
</dd>
|
|
71
127
|
</div>
|
|
72
128
|
))}
|
|
73
129
|
</dl>
|
|
@@ -75,19 +131,28 @@ function renderValue(field: CaptureFieldSpec, value: unknown, emptyText: string)
|
|
|
75
131
|
}
|
|
76
132
|
if (field.type === CaptureFieldType.List) {
|
|
77
133
|
const items = (Array.isArray(value) ? value : []) as CaptureValues[];
|
|
78
|
-
if (items.length === 0)
|
|
134
|
+
if (items.length === 0) {
|
|
135
|
+
return <span className="text-ink-3">{emptyText}</span>;
|
|
136
|
+
}
|
|
79
137
|
return (
|
|
80
138
|
<ol className="space-y-2">
|
|
81
139
|
{items.map((item, index) => (
|
|
82
|
-
<li
|
|
140
|
+
<li
|
|
141
|
+
key={index}
|
|
142
|
+
className="rounded-md border border-rule bg-paper-elev/40 p-2"
|
|
143
|
+
>
|
|
83
144
|
<p className="mb-1 text-caption font-medium text-ink-3">
|
|
84
145
|
{field.label} #{index + 1}
|
|
85
146
|
</p>
|
|
86
147
|
<dl className="space-y-1">
|
|
87
148
|
{(field.fields ?? []).map((child) => (
|
|
88
149
|
<div key={child.key} className="flex flex-wrap gap-2">
|
|
89
|
-
<dt className="text-caption font-medium text-ink-3">
|
|
90
|
-
|
|
150
|
+
<dt className="text-caption font-medium text-ink-3">
|
|
151
|
+
{child.label}:
|
|
152
|
+
</dt>
|
|
153
|
+
<dd className="text-caption text-ink">
|
|
154
|
+
{renderValue(child, item[child.key], emptyText)}
|
|
155
|
+
</dd>
|
|
91
156
|
</div>
|
|
92
157
|
))}
|
|
93
158
|
</dl>
|