@xemahq/ui-kernel 0.9.2 → 0.11.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/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/index.d.ts +0 -1
- package/dist/lib/biome-host/index.d.ts.map +1 -1
- package/dist/lib/biome-host/index.js +0 -1
- package/dist/lib/biome-host/index.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 +10 -5
- 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-builder.d.ts +10 -2
- package/dist/registry/lib/session-context-builder.d.ts.map +1 -1
- package/dist/registry/lib/session-context-builder.js +14 -7
- package/dist/registry/lib/session-context-builder.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.map +1 -1
- package/dist/ui/chrome/page-shell.js +9 -3
- 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 +3 -3
- 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/index.ts +0 -1
- package/src/lib/biome-host/realtime-hooks.ts +1 -0
- package/src/lib/biome-host/session-contributions.ts +22 -19
- 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-builder.ts +33 -17
- 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.tsx +32 -8
- 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
- package/dist/lib/biome-host/session-profiles.d.ts +0 -18
- package/dist/lib/biome-host/session-profiles.d.ts.map +0 -1
- package/dist/lib/biome-host/session-profiles.js +0 -38
- package/dist/lib/biome-host/session-profiles.js.map +0 -1
- package/src/lib/biome-host/session-profiles.ts +0 -105
|
@@ -17,15 +17,19 @@ import { Eye, EyeOff, Plus, Trash2 } from 'lucide-react';
|
|
|
17
17
|
import { useCallback, useRef, useState, type ReactNode } from 'react';
|
|
18
18
|
|
|
19
19
|
import { cn } from '../cn';
|
|
20
|
+
import {
|
|
21
|
+
applyCaptureTransform,
|
|
22
|
+
CaptureFieldType,
|
|
23
|
+
type CaptureFieldSpec,
|
|
24
|
+
type CaptureValues,
|
|
25
|
+
} from './field-spec';
|
|
26
|
+
import { asString } from './value-format';
|
|
20
27
|
import { Button } from '../primitives/button';
|
|
21
28
|
import { Checkbox } from '../primitives/checkbox';
|
|
22
29
|
import { Input } from '../primitives/input';
|
|
23
30
|
import { Label } from '../primitives/label';
|
|
24
31
|
import { Textarea } from '../primitives/textarea';
|
|
25
32
|
|
|
26
|
-
import { applyCaptureTransform, CaptureFieldType, type CaptureFieldSpec, type CaptureValues } from './field-spec';
|
|
27
|
-
import { asString } from './value-format';
|
|
28
|
-
|
|
29
33
|
const SELECT_CLASS =
|
|
30
34
|
'mt-1 flex h-10 w-full rounded-md border border-input bg-background px-3 py-2 text-body-1 text-foreground ring-offset-background focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-2 disabled:cursor-not-allowed disabled:opacity-50';
|
|
31
35
|
|
|
@@ -51,7 +55,9 @@ export interface SchemaFieldInputProps {
|
|
|
51
55
|
}
|
|
52
56
|
|
|
53
57
|
/** Native `type` for the single-line text-ish capture types. */
|
|
54
|
-
function nativeInputType(
|
|
58
|
+
function nativeInputType(
|
|
59
|
+
type: CaptureFieldSpec['type'],
|
|
60
|
+
): 'text' | 'email' | 'url' {
|
|
55
61
|
switch (type) {
|
|
56
62
|
case CaptureFieldType.Email:
|
|
57
63
|
return 'email';
|
|
@@ -69,17 +75,38 @@ export function SchemaFieldInput(props: SchemaFieldInputProps) {
|
|
|
69
75
|
// The ONE place a captured string is normalized. Composites (object/list)
|
|
70
76
|
// emit records/arrays and pass through untouched.
|
|
71
77
|
const emit = (next: unknown): void =>
|
|
72
|
-
onChange(
|
|
78
|
+
onChange(
|
|
79
|
+
typeof next === 'string'
|
|
80
|
+
? applyCaptureTransform(next, field.transform)
|
|
81
|
+
: next,
|
|
82
|
+
);
|
|
73
83
|
|
|
74
84
|
// DECLARED secrecy wins over the field type: a secret is always write-only
|
|
75
85
|
// and masked, whatever shape it has. Never inferred from `type`.
|
|
76
86
|
if (field.isSecret === true) {
|
|
77
|
-
return
|
|
87
|
+
return (
|
|
88
|
+
<SecretFieldInput
|
|
89
|
+
field={field}
|
|
90
|
+
value={value}
|
|
91
|
+
onChange={emit}
|
|
92
|
+
disabled={disabled}
|
|
93
|
+
inputId={inputId}
|
|
94
|
+
/>
|
|
95
|
+
);
|
|
78
96
|
}
|
|
79
97
|
|
|
80
98
|
switch (field.type) {
|
|
81
99
|
case CaptureFieldType.Text:
|
|
82
|
-
return
|
|
100
|
+
return (
|
|
101
|
+
<Textarea
|
|
102
|
+
id={inputId}
|
|
103
|
+
value={asString(value)}
|
|
104
|
+
onChange={(e) => emit(e.target.value)}
|
|
105
|
+
disabled={disabled}
|
|
106
|
+
rows={4}
|
|
107
|
+
placeholder={field.placeholder}
|
|
108
|
+
/>
|
|
109
|
+
);
|
|
83
110
|
case CaptureFieldType.Json:
|
|
84
111
|
return (
|
|
85
112
|
<Textarea
|
|
@@ -99,29 +126,76 @@ export function SchemaFieldInput(props: SchemaFieldInputProps) {
|
|
|
99
126
|
id={inputId}
|
|
100
127
|
type="number"
|
|
101
128
|
value={asString(value)}
|
|
102
|
-
onChange={(e) =>
|
|
129
|
+
onChange={(e) =>
|
|
130
|
+
emit(e.target.value === '' ? '' : Number(e.target.value))
|
|
131
|
+
}
|
|
103
132
|
disabled={disabled}
|
|
104
133
|
placeholder={field.placeholder}
|
|
105
134
|
/>
|
|
106
135
|
);
|
|
107
136
|
case CaptureFieldType.Decimal:
|
|
108
137
|
// NUMERIC carried verbatim as text — never Number()-coerced (precision).
|
|
109
|
-
return
|
|
138
|
+
return (
|
|
139
|
+
<Input
|
|
140
|
+
id={inputId}
|
|
141
|
+
type="text"
|
|
142
|
+
inputMode="decimal"
|
|
143
|
+
value={asString(value)}
|
|
144
|
+
onChange={(e) => emit(e.target.value)}
|
|
145
|
+
disabled={disabled}
|
|
146
|
+
placeholder={field.placeholder ?? '0.00'}
|
|
147
|
+
/>
|
|
148
|
+
);
|
|
110
149
|
case CaptureFieldType.User:
|
|
111
|
-
return
|
|
150
|
+
return (
|
|
151
|
+
<Input
|
|
152
|
+
id={inputId}
|
|
153
|
+
value={asString(value)}
|
|
154
|
+
onChange={(e) => emit(e.target.value)}
|
|
155
|
+
disabled={disabled}
|
|
156
|
+
placeholder={field.placeholder ?? 'subject id'}
|
|
157
|
+
/>
|
|
158
|
+
);
|
|
112
159
|
case CaptureFieldType.Boolean:
|
|
113
160
|
return (
|
|
114
161
|
<div className="mt-1">
|
|
115
|
-
<Checkbox
|
|
162
|
+
<Checkbox
|
|
163
|
+
id={inputId}
|
|
164
|
+
checked={value === true}
|
|
165
|
+
onCheckedChange={(checked) => emit(checked === true)}
|
|
166
|
+
disabled={disabled}
|
|
167
|
+
/>
|
|
116
168
|
</div>
|
|
117
169
|
);
|
|
118
170
|
case CaptureFieldType.Date:
|
|
119
|
-
return
|
|
171
|
+
return (
|
|
172
|
+
<Input
|
|
173
|
+
id={inputId}
|
|
174
|
+
type="date"
|
|
175
|
+
value={asString(value)}
|
|
176
|
+
onChange={(e) => emit(e.target.value)}
|
|
177
|
+
disabled={disabled}
|
|
178
|
+
/>
|
|
179
|
+
);
|
|
120
180
|
case CaptureFieldType.Datetime:
|
|
121
|
-
return
|
|
181
|
+
return (
|
|
182
|
+
<Input
|
|
183
|
+
id={inputId}
|
|
184
|
+
type="datetime-local"
|
|
185
|
+
value={asString(value)}
|
|
186
|
+
onChange={(e) => emit(e.target.value)}
|
|
187
|
+
disabled={disabled}
|
|
188
|
+
/>
|
|
189
|
+
);
|
|
122
190
|
case CaptureFieldType.Enum:
|
|
123
191
|
return (
|
|
124
|
-
<select
|
|
192
|
+
<select
|
|
193
|
+
id={inputId}
|
|
194
|
+
className={SELECT_CLASS}
|
|
195
|
+
value={asString(value)}
|
|
196
|
+
onChange={(e) => emit(e.target.value)}
|
|
197
|
+
disabled={disabled}
|
|
198
|
+
>
|
|
125
199
|
<option value="">— select —</option>
|
|
126
200
|
{(field.enumValues ?? []).map((v) => (
|
|
127
201
|
<option key={v} value={v}>
|
|
@@ -132,9 +206,17 @@ export function SchemaFieldInput(props: SchemaFieldInputProps) {
|
|
|
132
206
|
);
|
|
133
207
|
case CaptureFieldType.Reference:
|
|
134
208
|
return renderReference ? (
|
|
135
|
-
<>
|
|
209
|
+
<>
|
|
210
|
+
{renderReference({ field, value, onChange: emit, disabled, inputId })}
|
|
211
|
+
</>
|
|
136
212
|
) : (
|
|
137
|
-
<Input
|
|
213
|
+
<Input
|
|
214
|
+
id={inputId}
|
|
215
|
+
value={asString(value)}
|
|
216
|
+
onChange={(e) => emit(e.target.value)}
|
|
217
|
+
disabled={disabled}
|
|
218
|
+
placeholder={field.placeholder ?? 'reference id'}
|
|
219
|
+
/>
|
|
138
220
|
);
|
|
139
221
|
case CaptureFieldType.Object:
|
|
140
222
|
return <ObjectInput {...props} />;
|
|
@@ -147,7 +229,16 @@ export function SchemaFieldInput(props: SchemaFieldInputProps) {
|
|
|
147
229
|
return <AudioFieldInput {...props} />;
|
|
148
230
|
// string / email / url (and any unknown) — single-line input.
|
|
149
231
|
default:
|
|
150
|
-
return
|
|
232
|
+
return (
|
|
233
|
+
<Input
|
|
234
|
+
id={inputId}
|
|
235
|
+
type={nativeInputType(field.type)}
|
|
236
|
+
value={asString(value)}
|
|
237
|
+
onChange={(e) => emit(e.target.value)}
|
|
238
|
+
disabled={disabled}
|
|
239
|
+
placeholder={field.placeholder}
|
|
240
|
+
/>
|
|
241
|
+
);
|
|
151
242
|
}
|
|
152
243
|
}
|
|
153
244
|
|
|
@@ -174,7 +265,9 @@ function SecretFieldInput({
|
|
|
174
265
|
inputId: string;
|
|
175
266
|
}>) {
|
|
176
267
|
const [reveal, setReveal] = useState(false);
|
|
177
|
-
const multiline =
|
|
268
|
+
const multiline =
|
|
269
|
+
field.type === CaptureFieldType.Json ||
|
|
270
|
+
field.type === CaptureFieldType.Text;
|
|
178
271
|
|
|
179
272
|
if (multiline && reveal) {
|
|
180
273
|
return (
|
|
@@ -214,7 +307,10 @@ function SecretFieldInput({
|
|
|
214
307
|
);
|
|
215
308
|
}
|
|
216
309
|
|
|
217
|
-
function RevealToggle({
|
|
310
|
+
function RevealToggle({
|
|
311
|
+
reveal,
|
|
312
|
+
onToggle,
|
|
313
|
+
}: Readonly<{ reveal: boolean; onToggle: () => void }>) {
|
|
218
314
|
return (
|
|
219
315
|
<Button
|
|
220
316
|
type="button"
|
|
@@ -245,7 +341,13 @@ function readAsDataUrl(file: Blob, onDone: (dataUrl: string) => void): void {
|
|
|
245
341
|
* the camera directly. The value is a data-URL so it stays JSON-serializable and
|
|
246
342
|
* flows unchanged through the record model + offline outbox.
|
|
247
343
|
*/
|
|
248
|
-
function MediaFieldInput({
|
|
344
|
+
function MediaFieldInput({
|
|
345
|
+
field,
|
|
346
|
+
value,
|
|
347
|
+
onChange,
|
|
348
|
+
disabled,
|
|
349
|
+
path,
|
|
350
|
+
}: SchemaFieldInputProps) {
|
|
249
351
|
const inputId = `field-${path}`;
|
|
250
352
|
const current = asString(value);
|
|
251
353
|
const isImage = field.type === CaptureFieldType.Image;
|
|
@@ -269,11 +371,23 @@ function MediaFieldInput({ field, value, onChange, disabled, path }: SchemaField
|
|
|
269
371
|
{current ? (
|
|
270
372
|
<div className="flex items-center gap-2">
|
|
271
373
|
{isImage && current.startsWith('data:image') ? (
|
|
272
|
-
<img
|
|
374
|
+
<img
|
|
375
|
+
src={current}
|
|
376
|
+
alt={field.label}
|
|
377
|
+
className="max-h-32 rounded-md border border-input"
|
|
378
|
+
/>
|
|
273
379
|
) : (
|
|
274
|
-
<span className="truncate text-body-2 text-muted-foreground">
|
|
380
|
+
<span className="truncate text-body-2 text-muted-foreground">
|
|
381
|
+
Attached
|
|
382
|
+
</span>
|
|
275
383
|
)}
|
|
276
|
-
<Button
|
|
384
|
+
<Button
|
|
385
|
+
type="button"
|
|
386
|
+
variant="ghost"
|
|
387
|
+
size="sm"
|
|
388
|
+
onClick={() => onChange('')}
|
|
389
|
+
disabled={disabled}
|
|
390
|
+
>
|
|
277
391
|
Clear
|
|
278
392
|
</Button>
|
|
279
393
|
</div>
|
|
@@ -286,7 +400,12 @@ function MediaFieldInput({ field, value, onChange, disabled, path }: SchemaField
|
|
|
286
400
|
* `audio` capture — records a voice memo via MediaRecorder and stores it as a
|
|
287
401
|
* data-URL. Browser APIs are touched only inside the record handler (SSR-safe).
|
|
288
402
|
*/
|
|
289
|
-
function AudioFieldInput({
|
|
403
|
+
function AudioFieldInput({
|
|
404
|
+
value,
|
|
405
|
+
onChange,
|
|
406
|
+
disabled,
|
|
407
|
+
path,
|
|
408
|
+
}: SchemaFieldInputProps) {
|
|
290
409
|
const inputId = `field-${path}`;
|
|
291
410
|
const current = asString(value);
|
|
292
411
|
const [recording, setRecording] = useState(false);
|
|
@@ -310,7 +429,9 @@ function AudioFieldInput({ value, onChange, disabled, path }: SchemaFieldInputPr
|
|
|
310
429
|
track.stop();
|
|
311
430
|
}
|
|
312
431
|
readAsDataUrl(
|
|
313
|
-
new Blob(chunksRef.current, {
|
|
432
|
+
new Blob(chunksRef.current, {
|
|
433
|
+
type: recorder.mimeType || 'audio/webm',
|
|
434
|
+
}),
|
|
314
435
|
onChange,
|
|
315
436
|
);
|
|
316
437
|
};
|
|
@@ -332,16 +453,34 @@ function AudioFieldInput({ value, onChange, disabled, path }: SchemaFieldInputPr
|
|
|
332
453
|
<div className="mt-1 space-y-2">
|
|
333
454
|
<div className="flex items-center gap-2">
|
|
334
455
|
{recording ? (
|
|
335
|
-
<Button
|
|
456
|
+
<Button
|
|
457
|
+
type="button"
|
|
458
|
+
variant="secondary"
|
|
459
|
+
size="sm"
|
|
460
|
+
onClick={stop}
|
|
461
|
+
disabled={disabled}
|
|
462
|
+
>
|
|
336
463
|
Stop
|
|
337
464
|
</Button>
|
|
338
465
|
) : (
|
|
339
|
-
<Button
|
|
466
|
+
<Button
|
|
467
|
+
type="button"
|
|
468
|
+
variant="secondary"
|
|
469
|
+
size="sm"
|
|
470
|
+
onClick={() => void start()}
|
|
471
|
+
disabled={disabled}
|
|
472
|
+
>
|
|
340
473
|
{current ? 'Re-record' : 'Record'}
|
|
341
474
|
</Button>
|
|
342
475
|
)}
|
|
343
476
|
{current ? (
|
|
344
|
-
<Button
|
|
477
|
+
<Button
|
|
478
|
+
type="button"
|
|
479
|
+
variant="ghost"
|
|
480
|
+
size="sm"
|
|
481
|
+
onClick={() => onChange('')}
|
|
482
|
+
disabled={disabled}
|
|
483
|
+
>
|
|
345
484
|
Clear
|
|
346
485
|
</Button>
|
|
347
486
|
) : null}
|
|
@@ -368,15 +507,29 @@ function NestedField(props: SchemaFieldInputProps) {
|
|
|
368
507
|
{field.label}
|
|
369
508
|
{field.required ? <span className="text-destructive"> *</span> : null}
|
|
370
509
|
</Label>
|
|
371
|
-
{field.description ?
|
|
510
|
+
{field.description ? (
|
|
511
|
+
<p className="mb-1 text-caption text-ink-3">{field.description}</p>
|
|
512
|
+
) : null}
|
|
372
513
|
<SchemaFieldInput {...props} />
|
|
373
|
-
{error ?
|
|
514
|
+
{error ? (
|
|
515
|
+
<p className="mt-1 text-caption text-destructive">{error}</p>
|
|
516
|
+
) : null}
|
|
374
517
|
</div>
|
|
375
518
|
);
|
|
376
519
|
}
|
|
377
520
|
|
|
378
|
-
function ObjectInput({
|
|
379
|
-
|
|
521
|
+
function ObjectInput({
|
|
522
|
+
field,
|
|
523
|
+
value,
|
|
524
|
+
onChange,
|
|
525
|
+
disabled,
|
|
526
|
+
path,
|
|
527
|
+
errors,
|
|
528
|
+
renderReference,
|
|
529
|
+
}: SchemaFieldInputProps) {
|
|
530
|
+
const record = (
|
|
531
|
+
value && typeof value === 'object' && !Array.isArray(value) ? value : {}
|
|
532
|
+
) as CaptureValues;
|
|
380
533
|
const fields = field.fields ?? [];
|
|
381
534
|
return (
|
|
382
535
|
<div className="mt-1 space-y-3 rounded-lg border border-rule bg-paper-elev/40 p-3">
|
|
@@ -396,24 +549,44 @@ function ObjectInput({ field, value, onChange, disabled, path, errors, renderRef
|
|
|
396
549
|
);
|
|
397
550
|
}
|
|
398
551
|
|
|
399
|
-
function ListInput({
|
|
552
|
+
function ListInput({
|
|
553
|
+
field,
|
|
554
|
+
value,
|
|
555
|
+
onChange,
|
|
556
|
+
disabled,
|
|
557
|
+
path,
|
|
558
|
+
errors,
|
|
559
|
+
renderReference,
|
|
560
|
+
}: SchemaFieldInputProps) {
|
|
400
561
|
const items = (Array.isArray(value) ? value : []) as CaptureValues[];
|
|
401
562
|
const fields = field.fields ?? [];
|
|
402
563
|
const atMax = typeof field.max === 'number' && items.length >= field.max;
|
|
403
564
|
|
|
404
|
-
const setItem = (index: number, next: CaptureValues) =>
|
|
405
|
-
|
|
565
|
+
const setItem = (index: number, next: CaptureValues) =>
|
|
566
|
+
onChange(items.map((it, i) => (i === index ? next : it)));
|
|
567
|
+
const removeItem = (index: number) =>
|
|
568
|
+
onChange(items.filter((_, i) => i !== index));
|
|
406
569
|
const addItem = () => onChange([...items, {}]);
|
|
407
570
|
|
|
408
571
|
return (
|
|
409
572
|
<div className="mt-1 space-y-2">
|
|
410
573
|
{items.map((item, index) => (
|
|
411
|
-
<div
|
|
574
|
+
<div
|
|
575
|
+
key={index}
|
|
576
|
+
className="relative space-y-3 rounded-lg border border-rule bg-paper-elev/40 p-3"
|
|
577
|
+
>
|
|
412
578
|
<div className="flex items-center justify-between">
|
|
413
579
|
<span className="text-caption font-medium text-ink-3">
|
|
414
580
|
{field.label} #{index + 1}
|
|
415
581
|
</span>
|
|
416
|
-
<Button
|
|
582
|
+
<Button
|
|
583
|
+
type="button"
|
|
584
|
+
variant="ghost"
|
|
585
|
+
size="icon"
|
|
586
|
+
onClick={() => removeItem(index)}
|
|
587
|
+
disabled={disabled}
|
|
588
|
+
aria-label={`Remove ${field.label} ${index + 1}`}
|
|
589
|
+
>
|
|
417
590
|
<Trash2 className="h-4 w-4" />
|
|
418
591
|
</Button>
|
|
419
592
|
</div>
|
|
@@ -431,7 +604,14 @@ function ListInput({ field, value, onChange, disabled, path, errors, renderRefer
|
|
|
431
604
|
))}
|
|
432
605
|
</div>
|
|
433
606
|
))}
|
|
434
|
-
<Button
|
|
607
|
+
<Button
|
|
608
|
+
type="button"
|
|
609
|
+
variant="outline"
|
|
610
|
+
size="sm"
|
|
611
|
+
onClick={addItem}
|
|
612
|
+
disabled={disabled || atMax}
|
|
613
|
+
className={cn(items.length === 0 && 'w-full')}
|
|
614
|
+
>
|
|
435
615
|
<Plus className="mr-1.5 h-3.5 w-3.5" />
|
|
436
616
|
Add {field.label}
|
|
437
617
|
</Button>
|
|
@@ -15,12 +15,17 @@ import { Sparkles } from 'lucide-react';
|
|
|
15
15
|
import { type ReactNode } from 'react';
|
|
16
16
|
|
|
17
17
|
import { cn } from '../cn';
|
|
18
|
+
import {
|
|
19
|
+
type CaptureFieldSpec,
|
|
20
|
+
type CaptureSchema,
|
|
21
|
+
type CaptureSection,
|
|
22
|
+
type CaptureValues,
|
|
23
|
+
toSections,
|
|
24
|
+
} from './field-spec';
|
|
25
|
+
import { SchemaFieldInput, type RenderReference } from './schema-field-input';
|
|
18
26
|
import { Badge } from '../primitives/badge';
|
|
19
27
|
import { Label } from '../primitives/label';
|
|
20
28
|
|
|
21
|
-
import { type CaptureFieldSpec, type CaptureSchema, type CaptureSection, type CaptureValues, toSections } from './field-spec';
|
|
22
|
-
import { SchemaFieldInput, type RenderReference } from './schema-field-input';
|
|
23
|
-
|
|
24
29
|
export interface SchemaFormProps {
|
|
25
30
|
/** Flat schema. Mutually exclusive with `sections`. */
|
|
26
31
|
readonly fields?: readonly CaptureFieldSpec[];
|
|
@@ -44,7 +49,9 @@ export interface SchemaFormProps {
|
|
|
44
49
|
}
|
|
45
50
|
|
|
46
51
|
function toSet(keys: SchemaFormProps['suggestedKeys']): ReadonlySet<string> {
|
|
47
|
-
if (!keys)
|
|
52
|
+
if (!keys) {
|
|
53
|
+
return new Set();
|
|
54
|
+
}
|
|
48
55
|
return keys instanceof Set ? keys : new Set(keys as readonly string[]);
|
|
49
56
|
}
|
|
50
57
|
|
|
@@ -54,20 +61,43 @@ function toSet(keys: SchemaFormProps['suggestedKeys']): ReadonlySet<string> {
|
|
|
54
61
|
* const { errors } = useSchemaValidation(fields, values);
|
|
55
62
|
* <SchemaForm fields={fields} values={values} onChange={setValues} errors={errors} />
|
|
56
63
|
*/
|
|
57
|
-
export function SchemaForm({
|
|
58
|
-
|
|
64
|
+
export function SchemaForm({
|
|
65
|
+
fields,
|
|
66
|
+
sections,
|
|
67
|
+
schema,
|
|
68
|
+
values,
|
|
69
|
+
onChange,
|
|
70
|
+
errors,
|
|
71
|
+
suggestedKeys,
|
|
72
|
+
disabled,
|
|
73
|
+
renderReference,
|
|
74
|
+
className,
|
|
75
|
+
footer,
|
|
76
|
+
}: SchemaFormProps) {
|
|
77
|
+
const resolved: readonly CaptureSection[] = toSections(
|
|
78
|
+
sections ?? (fields ? fields : schema) ?? [],
|
|
79
|
+
);
|
|
59
80
|
const suggested = toSet(suggestedKeys);
|
|
60
81
|
|
|
61
|
-
const setField = (key: string, value: unknown) =>
|
|
82
|
+
const setField = (key: string, value: unknown) =>
|
|
83
|
+
onChange({ ...values, [key]: value });
|
|
62
84
|
|
|
63
85
|
return (
|
|
64
86
|
<div className={cn('space-y-6', className)}>
|
|
65
87
|
{resolved.map((section) => (
|
|
66
|
-
<fieldset
|
|
88
|
+
<fieldset
|
|
89
|
+
key={section.key}
|
|
90
|
+
className="space-y-3 border-0 p-0"
|
|
91
|
+
disabled={disabled}
|
|
92
|
+
>
|
|
67
93
|
{section.title ? (
|
|
68
94
|
<legend className="mb-1 text-subtitle font-semibold text-ink">
|
|
69
95
|
{section.title}
|
|
70
|
-
{section.description ?
|
|
96
|
+
{section.description ? (
|
|
97
|
+
<span className="mt-0.5 block text-caption font-normal text-ink-3">
|
|
98
|
+
{section.description}
|
|
99
|
+
</span>
|
|
100
|
+
) : null}
|
|
71
101
|
</legend>
|
|
72
102
|
) : null}
|
|
73
103
|
{section.fields.map((field) => {
|
|
@@ -78,15 +108,24 @@ export function SchemaForm({ fields, sections, schema, values, onChange, errors,
|
|
|
78
108
|
<div className="flex items-center gap-2">
|
|
79
109
|
<Label htmlFor={`field-${field.key}`}>
|
|
80
110
|
{field.label}
|
|
81
|
-
{field.required ?
|
|
111
|
+
{field.required ? (
|
|
112
|
+
<span className="text-destructive"> *</span>
|
|
113
|
+
) : null}
|
|
82
114
|
</Label>
|
|
83
115
|
{isSuggested ? (
|
|
84
|
-
<Badge
|
|
116
|
+
<Badge
|
|
117
|
+
variant="outline"
|
|
118
|
+
className="gap-1 border-primary/30 bg-primary/10 px-1.5 py-0 text-caption text-primary"
|
|
119
|
+
>
|
|
85
120
|
<Sparkles className="h-3 w-3" /> AI suggested
|
|
86
121
|
</Badge>
|
|
87
122
|
) : null}
|
|
88
123
|
</div>
|
|
89
|
-
{field.description ?
|
|
124
|
+
{field.description ? (
|
|
125
|
+
<p className="mb-1 text-caption text-ink-3">
|
|
126
|
+
{field.description}
|
|
127
|
+
</p>
|
|
128
|
+
) : null}
|
|
90
129
|
<SchemaFieldInput
|
|
91
130
|
field={field}
|
|
92
131
|
value={values[field.key]}
|
|
@@ -96,7 +135,9 @@ export function SchemaForm({ fields, sections, schema, values, onChange, errors,
|
|
|
96
135
|
errors={errors}
|
|
97
136
|
renderReference={renderReference}
|
|
98
137
|
/>
|
|
99
|
-
{error ?
|
|
138
|
+
{error ? (
|
|
139
|
+
<p className="mt-1 text-caption text-destructive">{error}</p>
|
|
140
|
+
) : null}
|
|
100
141
|
</div>
|
|
101
142
|
);
|
|
102
143
|
})}
|
|
@@ -57,8 +57,12 @@ export function usePrefill<T extends CaptureValues = CaptureValues>(
|
|
|
57
57
|
): UsePrefillResult<T> {
|
|
58
58
|
const { fetchDefaults, initialValues, enabled = true } = options;
|
|
59
59
|
|
|
60
|
-
const [values, setValuesState] = useState<T>(() => ({
|
|
61
|
-
|
|
60
|
+
const [values, setValuesState] = useState<T>(() => ({
|
|
61
|
+
...(initialValues ?? ({} as T)),
|
|
62
|
+
}));
|
|
63
|
+
const [suggested, setSuggested] = useState<ReadonlySet<string>>(
|
|
64
|
+
() => new Set(),
|
|
65
|
+
);
|
|
62
66
|
const [loading, setLoading] = useState(false);
|
|
63
67
|
const [error, setError] = useState<unknown>(null);
|
|
64
68
|
|
|
@@ -72,7 +76,9 @@ export function usePrefill<T extends CaptureValues = CaptureValues>(
|
|
|
72
76
|
touched.current.add(key);
|
|
73
77
|
setValuesState((prev) => ({ ...prev, [key]: value }));
|
|
74
78
|
setSuggested((prev) => {
|
|
75
|
-
if (!prev.has(key))
|
|
79
|
+
if (!prev.has(key)) {
|
|
80
|
+
return prev;
|
|
81
|
+
}
|
|
76
82
|
const next = new Set(prev);
|
|
77
83
|
next.delete(key);
|
|
78
84
|
return next;
|
|
@@ -82,9 +88,7 @@ export function usePrefill<T extends CaptureValues = CaptureValues>(
|
|
|
82
88
|
const setValues = useCallback((updater: Partial<T> | ((prev: T) => T)) => {
|
|
83
89
|
setValuesState((prev) => {
|
|
84
90
|
const next =
|
|
85
|
-
typeof updater === 'function'
|
|
86
|
-
? updater(prev)
|
|
87
|
-
: { ...prev, ...updater };
|
|
91
|
+
typeof updater === 'function' ? updater(prev) : { ...prev, ...updater };
|
|
88
92
|
const changed = new Set<string>();
|
|
89
93
|
for (const k of Object.keys(next)) {
|
|
90
94
|
if (next[k] !== prev[k]) {
|
|
@@ -94,9 +98,13 @@ export function usePrefill<T extends CaptureValues = CaptureValues>(
|
|
|
94
98
|
}
|
|
95
99
|
if (changed.size > 0) {
|
|
96
100
|
setSuggested((prevSug) => {
|
|
97
|
-
if (![...changed].some((k) => prevSug.has(k)))
|
|
101
|
+
if (![...changed].some((k) => prevSug.has(k))) {
|
|
102
|
+
return prevSug;
|
|
103
|
+
}
|
|
98
104
|
const n = new Set(prevSug);
|
|
99
|
-
for (const k of changed)
|
|
105
|
+
for (const k of changed) {
|
|
106
|
+
n.delete(k);
|
|
107
|
+
}
|
|
100
108
|
return n;
|
|
101
109
|
});
|
|
102
110
|
}
|
|
@@ -110,14 +118,17 @@ export function usePrefill<T extends CaptureValues = CaptureValues>(
|
|
|
110
118
|
setError(null);
|
|
111
119
|
void fetchDefaults()
|
|
112
120
|
.then((defaults) => {
|
|
113
|
-
if (id !== requestId.current)
|
|
121
|
+
if (id !== requestId.current) {
|
|
122
|
+
return;
|
|
123
|
+
} // superseded — drop
|
|
114
124
|
const applied: string[] = [];
|
|
115
125
|
setValuesState((prev) => {
|
|
116
126
|
const next = { ...prev };
|
|
117
127
|
for (const [key, value] of Object.entries(defaults)) {
|
|
118
128
|
// Only fill keys the user hasn't touched and that are still empty.
|
|
119
129
|
const current = prev[key];
|
|
120
|
-
const isEmpty =
|
|
130
|
+
const isEmpty =
|
|
131
|
+
current === undefined || current === null || current === '';
|
|
121
132
|
if (!touched.current.has(key) && isEmpty && value !== undefined) {
|
|
122
133
|
(next as CaptureValues)[key] = value;
|
|
123
134
|
applied.push(key);
|
|
@@ -126,28 +137,50 @@ export function usePrefill<T extends CaptureValues = CaptureValues>(
|
|
|
126
137
|
return next;
|
|
127
138
|
});
|
|
128
139
|
setSuggested((prev) => {
|
|
129
|
-
if (applied.length === 0)
|
|
140
|
+
if (applied.length === 0) {
|
|
141
|
+
return prev;
|
|
142
|
+
}
|
|
130
143
|
const n = new Set(prev);
|
|
131
|
-
for (const k of applied)
|
|
144
|
+
for (const k of applied) {
|
|
145
|
+
n.add(k);
|
|
146
|
+
}
|
|
132
147
|
return n;
|
|
133
148
|
});
|
|
134
149
|
})
|
|
135
150
|
.catch((e: unknown) => {
|
|
136
|
-
if (id !== requestId.current)
|
|
151
|
+
if (id !== requestId.current) {
|
|
152
|
+
return;
|
|
153
|
+
}
|
|
137
154
|
setError(e);
|
|
138
155
|
})
|
|
139
156
|
.finally(() => {
|
|
140
|
-
if (id === requestId.current)
|
|
157
|
+
if (id === requestId.current) {
|
|
158
|
+
setLoading(false);
|
|
159
|
+
}
|
|
141
160
|
});
|
|
142
161
|
}, [fetchDefaults]);
|
|
143
162
|
|
|
144
163
|
useEffect(() => {
|
|
145
|
-
if (enabled)
|
|
164
|
+
if (enabled) {
|
|
165
|
+
run();
|
|
166
|
+
}
|
|
146
167
|
// Run once on mount / when re-enabled; `reload()` is the explicit re-fetch.
|
|
147
168
|
// eslint-disable-next-line react-hooks/exhaustive-deps
|
|
148
169
|
}, [enabled]);
|
|
149
170
|
|
|
150
|
-
const isSuggested = useCallback(
|
|
171
|
+
const isSuggested = useCallback(
|
|
172
|
+
(key: string) => suggested.has(key),
|
|
173
|
+
[suggested],
|
|
174
|
+
);
|
|
151
175
|
|
|
152
|
-
return {
|
|
176
|
+
return {
|
|
177
|
+
values,
|
|
178
|
+
setValue,
|
|
179
|
+
setValues,
|
|
180
|
+
suggestedKeys: suggested,
|
|
181
|
+
isSuggested,
|
|
182
|
+
loading,
|
|
183
|
+
error,
|
|
184
|
+
reload: run,
|
|
185
|
+
};
|
|
153
186
|
}
|