@xemahq/ui-kernel 0.9.0 → 0.9.2
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/index.d.ts +1 -0
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +1 -0
- package/dist/index.js.map +1 -1
- package/dist/lib/biome-host/biome-builders.d.ts.map +1 -1
- package/dist/lib/biome-host/biome-builders.js +3 -1
- package/dist/lib/biome-host/biome-builders.js.map +1 -1
- package/dist/lib/biome-host/biome-registry.d.ts.map +1 -1
- package/dist/lib/biome-host/biome-registry.js +14 -9
- package/dist/lib/biome-host/biome-registry.js.map +1 -1
- package/dist/lib/biome-host/biome-scope-hooks.d.ts +11 -0
- package/dist/lib/biome-host/biome-scope-hooks.d.ts.map +1 -0
- package/dist/lib/biome-host/biome-scope-hooks.js +25 -0
- package/dist/lib/biome-host/biome-scope-hooks.js.map +1 -0
- package/dist/lib/biome-host/biome-scope.d.ts +1 -10
- package/dist/lib/biome-host/biome-scope.d.ts.map +1 -1
- package/dist/lib/biome-host/biome-scope.js +1 -24
- package/dist/lib/biome-host/biome-scope.js.map +1 -1
- package/dist/lib/biome-host/biome-scoped-query.d.ts +1 -1
- package/dist/lib/biome-host/biome-scoped-query.d.ts.map +1 -1
- package/dist/lib/biome-host/biome-scoped-query.js +1 -1
- package/dist/lib/biome-host/biome-scoped-query.js.map +1 -1
- package/dist/lib/biome-host/create-biome-orval-config.js +2 -2
- package/dist/lib/biome-host/create-biome-orval-config.js.map +1 -1
- package/dist/lib/biome-host/errors.js.map +1 -1
- package/dist/lib/biome-host/index.d.ts +1 -1
- package/dist/lib/biome-host/index.d.ts.map +1 -1
- package/dist/lib/biome-host/index.js +1 -1
- package/dist/lib/biome-host/index.js.map +1 -1
- package/dist/lib/biome-host/session-profiles.d.ts.map +1 -1
- package/dist/lib/biome-host/session-profiles.js +4 -1
- package/dist/lib/biome-host/session-profiles.js.map +1 -1
- package/dist/lib/capabilities/capability-context.d.ts +9 -0
- package/dist/lib/capabilities/capability-context.d.ts.map +1 -0
- package/dist/lib/capabilities/capability-context.js +13 -0
- package/dist/lib/capabilities/capability-context.js.map +1 -0
- package/dist/lib/capabilities/capability-provider.d.ts +2 -8
- package/dist/lib/capabilities/capability-provider.d.ts.map +1 -1
- package/dist/lib/capabilities/capability-provider.js +1 -12
- package/dist/lib/capabilities/capability-provider.js.map +1 -1
- package/dist/lib/capabilities/index.d.ts +1 -0
- package/dist/lib/capabilities/index.d.ts.map +1 -1
- package/dist/lib/capabilities/index.js +1 -0
- package/dist/lib/capabilities/index.js.map +1 -1
- package/dist/lib/capabilities/use-capability.d.ts.map +1 -1
- package/dist/lib/capabilities/use-capability.js +1 -1
- package/dist/lib/capabilities/use-capability.js.map +1 -1
- package/dist/lib/contribution-registry/contribution-registry.d.ts +24 -0
- package/dist/lib/contribution-registry/contribution-registry.d.ts.map +1 -0
- package/dist/lib/contribution-registry/contribution-registry.js +67 -0
- package/dist/lib/contribution-registry/contribution-registry.js.map +1 -0
- package/dist/lib/contribution-registry/index.d.ts +3 -0
- package/dist/lib/contribution-registry/index.d.ts.map +1 -0
- package/dist/lib/contribution-registry/index.js +3 -0
- package/dist/lib/contribution-registry/index.js.map +1 -0
- package/dist/lib/contribution-registry/renderable-registry.d.ts +33 -0
- package/dist/lib/contribution-registry/renderable-registry.d.ts.map +1 -0
- package/dist/lib/contribution-registry/renderable-registry.js +51 -0
- package/dist/lib/contribution-registry/renderable-registry.js.map +1 -0
- package/dist/lib/system-bus/deeplink.js.map +1 -1
- package/dist/lib/system-bus/host-ports.d.ts +2 -1
- 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.map +1 -1
- package/dist/offline/index.d.ts +2 -1
- package/dist/offline/index.d.ts.map +1 -1
- package/dist/offline/index.js +2 -1
- package/dist/offline/index.js.map +1 -1
- package/dist/offline/offline-status-badge.js +1 -1
- package/dist/offline/offline-status-badge.js.map +1 -1
- package/dist/offline/outbox.js.map +1 -1
- package/dist/offline/react-hooks.d.ts +7 -0
- package/dist/offline/react-hooks.d.ts.map +1 -0
- package/dist/offline/react-hooks.js +25 -0
- package/dist/offline/react-hooks.js.map +1 -0
- package/dist/offline/react.d.ts +0 -4
- package/dist/offline/react.d.ts.map +1 -1
- package/dist/offline/react.js +2 -24
- package/dist/offline/react.js.map +1 -1
- package/dist/offline/storage.d.ts.map +1 -1
- package/dist/offline/storage.js +8 -5
- package/dist/offline/storage.js.map +1 -1
- package/dist/registry/index.d.ts +1 -0
- package/dist/registry/index.d.ts.map +1 -1
- package/dist/registry/index.js +1 -0
- package/dist/registry/index.js.map +1 -1
- package/dist/registry/lib/primitives/SessionEventCard.d.ts.map +1 -1
- package/dist/registry/lib/primitives/SessionEventCard.js +1 -1
- package/dist/registry/lib/primitives/SessionEventCard.js.map +1 -1
- package/dist/registry/lib/session-context-provider.d.ts +1 -3
- package/dist/registry/lib/session-context-provider.d.ts.map +1 -1
- package/dist/registry/lib/session-context-provider.js +2 -15
- package/dist/registry/lib/session-context-provider.js.map +1 -1
- package/dist/registry/lib/session-context.d.ts +5 -0
- package/dist/registry/lib/session-context.d.ts.map +1 -0
- package/dist/registry/lib/session-context.js +15 -0
- package/dist/registry/lib/session-context.js.map +1 -0
- package/dist/registry/lib/session-selectors.d.ts.map +1 -1
- package/dist/registry/lib/session-selectors.js +3 -1
- package/dist/registry/lib/session-selectors.js.map +1 -1
- package/dist/ui/branding/app-branding-context.d.ts +9 -0
- package/dist/ui/branding/app-branding-context.d.ts.map +1 -0
- package/dist/ui/branding/app-branding-context.js +10 -0
- package/dist/ui/branding/app-branding-context.js.map +1 -0
- package/dist/ui/branding/app-branding-provider.d.ts +0 -6
- package/dist/ui/branding/app-branding-provider.d.ts.map +1 -1
- package/dist/ui/branding/app-branding-provider.js +1 -8
- package/dist/ui/branding/app-branding-provider.js.map +1 -1
- package/dist/ui/capture/field-spec-to-zod.d.ts +1 -0
- package/dist/ui/capture/field-spec-to-zod.d.ts.map +1 -1
- package/dist/ui/capture/field-spec-to-zod.js +19 -0
- package/dist/ui/capture/field-spec-to-zod.js.map +1 -1
- package/dist/ui/capture/field-spec-validate.d.ts +4 -0
- package/dist/ui/capture/field-spec-validate.d.ts.map +1 -0
- package/dist/ui/capture/field-spec-validate.js +129 -0
- package/dist/ui/capture/field-spec-validate.js.map +1 -0
- package/dist/ui/capture/field-spec.d.ts +13 -1
- package/dist/ui/capture/field-spec.d.ts.map +1 -1
- package/dist/ui/capture/field-spec.js +25 -0
- package/dist/ui/capture/field-spec.js.map +1 -1
- package/dist/ui/capture/index.d.ts +4 -2
- package/dist/ui/capture/index.d.ts.map +1 -1
- package/dist/ui/capture/index.js +4 -2
- package/dist/ui/capture/index.js.map +1 -1
- package/dist/ui/capture/schema-field-input.d.ts.map +1 -1
- package/dist/ui/capture/schema-field-input.js +40 -13
- package/dist/ui/capture/schema-field-input.js.map +1 -1
- package/dist/ui/capture/submit-values.d.ts +6 -0
- package/dist/ui/capture/submit-values.d.ts.map +1 -0
- package/dist/ui/capture/submit-values.js +28 -0
- package/dist/ui/capture/submit-values.js.map +1 -0
- package/dist/ui/capture/use-prefill.d.ts.map +1 -1
- package/dist/ui/capture/use-prefill.js +3 -1
- package/dist/ui/capture/use-prefill.js.map +1 -1
- package/dist/ui/capture/use-wizard.d.ts +1 -1
- package/dist/ui/capture/use-wizard.d.ts.map +1 -1
- package/dist/ui/capture/use-wizard.js +1 -1
- package/dist/ui/capture/use-wizard.js.map +1 -1
- package/dist/ui/capture/wizard.d.ts.map +1 -1
- package/dist/ui/capture/wizard.js.map +1 -1
- package/dist/ui/index.d.ts +6 -1
- package/dist/ui/index.d.ts.map +1 -1
- package/dist/ui/index.js +6 -1
- package/dist/ui/index.js.map +1 -1
- package/dist/ui/primitives/alert-dialog.js +1 -1
- package/dist/ui/primitives/alert-dialog.js.map +1 -1
- package/dist/ui/primitives/badge-variants.d.ts +4 -0
- package/dist/ui/primitives/badge-variants.d.ts.map +1 -0
- package/dist/ui/primitives/badge-variants.js +15 -0
- package/dist/ui/primitives/badge-variants.js.map +1 -0
- package/dist/ui/primitives/badge.d.ts +3 -5
- package/dist/ui/primitives/badge.d.ts.map +1 -1
- package/dist/ui/primitives/badge.js +2 -15
- package/dist/ui/primitives/badge.js.map +1 -1
- package/dist/ui/primitives/button-variants.d.ts +5 -0
- package/dist/ui/primitives/button-variants.d.ts.map +1 -0
- package/dist/ui/primitives/button-variants.js +24 -0
- package/dist/ui/primitives/button-variants.js.map +1 -0
- package/dist/ui/primitives/button.d.ts +3 -6
- package/dist/ui/primitives/button.d.ts.map +1 -1
- package/dist/ui/primitives/button.js +2 -24
- package/dist/ui/primitives/button.js.map +1 -1
- package/dist/ui/primitives/form-stepper.d.ts +1 -13
- package/dist/ui/primitives/form-stepper.d.ts.map +1 -1
- package/dist/ui/primitives/form-stepper.js +1 -6
- package/dist/ui/primitives/form-stepper.js.map +1 -1
- package/dist/ui/primitives/form-stepper.types.d.ts +14 -0
- package/dist/ui/primitives/form-stepper.types.d.ts.map +1 -0
- package/dist/ui/primitives/form-stepper.types.js +7 -0
- package/dist/ui/primitives/form-stepper.types.js.map +1 -0
- package/dist/ui/primitives/overflow-tabs.d.ts +5 -0
- package/dist/ui/primitives/overflow-tabs.d.ts.map +1 -1
- package/dist/ui/primitives/overflow-tabs.js +4 -4
- package/dist/ui/primitives/overflow-tabs.js.map +1 -1
- package/dist/ui/primitives/preview-device-frame.js +1 -1
- 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 +1 -1
- package/dist/ui/primitives/tag-multi-select.js.map +1 -1
- package/dist/ui/primitives/url-preview-chrome.d.ts +8 -0
- package/dist/ui/primitives/url-preview-chrome.d.ts.map +1 -0
- package/dist/ui/primitives/url-preview-chrome.js +40 -0
- package/dist/ui/primitives/url-preview-chrome.js.map +1 -0
- package/dist/vista/GenericCatalogueSurface.d.ts +10 -0
- package/dist/vista/GenericCatalogueSurface.d.ts.map +1 -0
- package/dist/vista/GenericCatalogueSurface.js +80 -0
- package/dist/vista/GenericCatalogueSurface.js.map +1 -0
- package/dist/vista/SurfaceFallbackCard.d.ts +9 -0
- package/dist/vista/SurfaceFallbackCard.d.ts.map +1 -0
- package/dist/vista/SurfaceFallbackCard.js +44 -0
- package/dist/vista/SurfaceFallbackCard.js.map +1 -0
- package/dist/vista/VistaPanel.d.ts +21 -0
- package/dist/vista/VistaPanel.d.ts.map +1 -0
- package/dist/vista/VistaPanel.js +31 -0
- package/dist/vista/VistaPanel.js.map +1 -0
- package/dist/vista/html/CustomUiFrame.d.ts +20 -0
- package/dist/vista/html/CustomUiFrame.d.ts.map +1 -0
- package/dist/vista/html/CustomUiFrame.js +69 -0
- package/dist/vista/html/CustomUiFrame.js.map +1 -0
- package/dist/vista/html/custom-ui-frame-bridge.d.ts +13 -0
- package/dist/vista/html/custom-ui-frame-bridge.d.ts.map +1 -0
- package/dist/vista/html/custom-ui-frame-bridge.js +30 -0
- package/dist/vista/html/custom-ui-frame-bridge.js.map +1 -0
- package/dist/vista/html/custom-ui-frame-contract.d.ts +29 -0
- package/dist/vista/html/custom-ui-frame-contract.d.ts.map +1 -0
- package/dist/vista/html/custom-ui-frame-contract.js +16 -0
- package/dist/vista/html/custom-ui-frame-contract.js.map +1 -0
- package/dist/vista/html/custom-ui-intents.d.ts +20 -0
- package/dist/vista/html/custom-ui-intents.d.ts.map +1 -0
- package/dist/vista/html/custom-ui-intents.js +57 -0
- package/dist/vista/html/custom-ui-intents.js.map +1 -0
- package/dist/vista/html/custom-ui-srcdoc.d.ts +17 -0
- package/dist/vista/html/custom-ui-srcdoc.d.ts.map +1 -0
- package/dist/vista/html/custom-ui-srcdoc.js +70 -0
- package/dist/vista/html/custom-ui-srcdoc.js.map +1 -0
- package/dist/vista/html/index.d.ts +6 -0
- package/dist/vista/html/index.d.ts.map +1 -0
- package/dist/vista/html/index.js +6 -0
- package/dist/vista/html/index.js.map +1 -0
- package/dist/vista/index.d.ts +22 -0
- package/dist/vista/index.d.ts.map +1 -0
- package/dist/vista/index.js +22 -0
- package/dist/vista/index.js.map +1 -0
- package/dist/vista/surface-catalogue.d.ts +5 -0
- package/dist/vista/surface-catalogue.d.ts.map +1 -0
- package/dist/vista/surface-catalogue.js +30 -0
- package/dist/vista/surface-catalogue.js.map +1 -0
- package/dist/vista/surface-icons.d.ts +7 -0
- package/dist/vista/surface-icons.d.ts.map +1 -0
- package/dist/vista/surface-icons.js +26 -0
- package/dist/vista/surface-icons.js.map +1 -0
- package/dist/vista/surface-registry.d.ts +7 -0
- package/dist/vista/surface-registry.d.ts.map +1 -0
- package/dist/vista/surface-registry.js +7 -0
- package/dist/vista/surface-registry.js.map +1 -0
- package/dist/vista/surfaces/ChartSurface.d.ts +4 -0
- package/dist/vista/surfaces/ChartSurface.d.ts.map +1 -0
- package/dist/vista/surfaces/ChartSurface.js +17 -0
- package/dist/vista/surfaces/ChartSurface.js.map +1 -0
- package/dist/vista/surfaces/FilesSurface.d.ts +4 -0
- package/dist/vista/surfaces/FilesSurface.d.ts.map +1 -0
- package/dist/vista/surfaces/FilesSurface.js +77 -0
- package/dist/vista/surfaces/FilesSurface.js.map +1 -0
- package/dist/vista/surfaces/FormSurface.d.ts +4 -0
- package/dist/vista/surfaces/FormSurface.d.ts.map +1 -0
- package/dist/vista/surfaces/FormSurface.js +124 -0
- package/dist/vista/surfaces/FormSurface.js.map +1 -0
- package/dist/vista/surfaces/HtmlSurface.d.ts +4 -0
- package/dist/vista/surfaces/HtmlSurface.d.ts.map +1 -0
- package/dist/vista/surfaces/HtmlSurface.js +11 -0
- package/dist/vista/surfaces/HtmlSurface.js.map +1 -0
- package/dist/vista/surfaces/TableSurface.d.ts +4 -0
- package/dist/vista/surfaces/TableSurface.d.ts.map +1 -0
- package/dist/vista/surfaces/TableSurface.js +42 -0
- package/dist/vista/surfaces/TableSurface.js.map +1 -0
- package/dist/vista/surfaces/UrlSurface.d.ts +4 -0
- package/dist/vista/surfaces/UrlSurface.d.ts.map +1 -0
- package/dist/vista/surfaces/UrlSurface.js +7 -0
- package/dist/vista/surfaces/UrlSurface.js.map +1 -0
- package/dist/vista/surfaces/blob-surfaces.d.ts +6 -0
- package/dist/vista/surfaces/blob-surfaces.d.ts.map +1 -0
- package/dist/vista/surfaces/blob-surfaces.js +38 -0
- package/dist/vista/surfaces/blob-surfaces.js.map +1 -0
- package/dist/vista/surfaces/elicitation-transport.d.ts +27 -0
- package/dist/vista/surfaces/elicitation-transport.d.ts.map +1 -0
- package/dist/vista/surfaces/elicitation-transport.js +193 -0
- package/dist/vista/surfaces/elicitation-transport.js.map +1 -0
- package/dist/vista/surfaces/file-surface-utils.d.ts +13 -0
- package/dist/vista/surfaces/file-surface-utils.d.ts.map +1 -0
- package/dist/vista/surfaces/file-surface-utils.js +46 -0
- package/dist/vista/surfaces/file-surface-utils.js.map +1 -0
- package/dist/vista/surfaces/index.d.ts +12 -0
- package/dist/vista/surfaces/index.d.ts.map +1 -0
- package/dist/vista/surfaces/index.js +12 -0
- package/dist/vista/surfaces/index.js.map +1 -0
- package/dist/vista/surfaces/register-surfaces.d.ts +2 -0
- package/dist/vista/surfaces/register-surfaces.d.ts.map +1 -0
- package/dist/vista/surfaces/register-surfaces.js +80 -0
- package/dist/vista/surfaces/register-surfaces.js.map +1 -0
- package/dist/vista/surfaces/text-surfaces.d.ts +8 -0
- package/dist/vista/surfaces/text-surfaces.d.ts.map +1 -0
- package/dist/vista/surfaces/text-surfaces.js +54 -0
- package/dist/vista/surfaces/text-surfaces.js.map +1 -0
- package/dist/vista/use-vista-tabs.d.ts +30 -0
- package/dist/vista/use-vista-tabs.d.ts.map +1 -0
- package/dist/vista/use-vista-tabs.js +77 -0
- package/dist/vista/use-vista-tabs.js.map +1 -0
- package/dist/vista/vista-code-renderer-context.d.ts +9 -0
- package/dist/vista/vista-code-renderer-context.d.ts.map +1 -0
- package/dist/vista/vista-code-renderer-context.js +6 -0
- package/dist/vista/vista-code-renderer-context.js.map +1 -0
- package/dist/vista/vista-code-renderer.d.ts +7 -0
- package/dist/vista/vista-code-renderer.d.ts.map +1 -0
- package/dist/vista/vista-code-renderer.js +6 -0
- package/dist/vista/vista-code-renderer.js.map +1 -0
- package/dist/vista/vista-file-context.d.ts +8 -0
- package/dist/vista/vista-file-context.d.ts.map +1 -0
- package/dist/vista/vista-file-context.js +6 -0
- package/dist/vista/vista-file-context.js.map +1 -0
- package/dist/vista/vista-file-source.d.ts +15 -0
- package/dist/vista/vista-file-source.d.ts.map +1 -0
- package/dist/vista/vista-file-source.js +66 -0
- package/dist/vista/vista-file-source.js.map +1 -0
- package/dist/vista/vista-form-context.d.ts +13 -0
- package/dist/vista/vista-form-context.d.ts.map +1 -0
- package/dist/vista/vista-form-context.js +6 -0
- package/dist/vista/vista-form-context.js.map +1 -0
- package/dist/vista/vista-form-host.d.ts +7 -0
- package/dist/vista/vista-form-host.d.ts.map +1 -0
- package/dist/vista/vista-form-host.js +6 -0
- package/dist/vista/vista-form-host.js.map +1 -0
- package/dist/vista/vista-model.d.ts +12 -0
- package/dist/vista/vista-model.d.ts.map +1 -0
- package/dist/vista/vista-model.js +72 -0
- package/dist/vista/vista-model.js.map +1 -0
- package/dist/vista/vista-open-context.d.ts +7 -0
- package/dist/vista/vista-open-context.d.ts.map +1 -0
- package/dist/vista/vista-open-context.js +6 -0
- package/dist/vista/vista-open-context.js.map +1 -0
- package/dist/vista/vista-open-state.d.ts +5 -0
- package/dist/vista/vista-open-state.d.ts.map +1 -0
- package/dist/vista/vista-open-state.js +6 -0
- package/dist/vista/vista-open-state.js.map +1 -0
- package/dist/vista/vista-payloads.d.ts +106 -0
- package/dist/vista/vista-payloads.d.ts.map +1 -0
- package/dist/vista/vista-payloads.js +302 -0
- package/dist/vista/vista-payloads.js.map +1 -0
- package/dist/vista/vista-tabs-manifest.d.ts +17 -0
- package/dist/vista/vista-tabs-manifest.d.ts.map +1 -0
- package/dist/vista/vista-tabs-manifest.js +60 -0
- package/dist/vista/vista-tabs-manifest.js.map +1 -0
- package/dist/vista/vista-tools.d.ts +41 -0
- package/dist/vista/vista-tools.d.ts.map +1 -0
- package/dist/vista/vista-tools.js +113 -0
- package/dist/vista/vista-tools.js.map +1 -0
- package/package.json +4 -4
- package/src/index.ts +5 -0
- package/src/lib/biome-host/biome-builders.ts +4 -1
- package/src/lib/biome-host/biome-registry.ts +31 -12
- package/src/lib/biome-host/biome-scope-hooks.ts +39 -0
- package/src/lib/biome-host/biome-scope.tsx +1 -68
- package/src/lib/biome-host/biome-scoped-query.ts +4 -1
- package/src/lib/biome-host/create-biome-orval-config.ts +2 -2
- package/src/lib/biome-host/errors.ts +1 -1
- package/src/lib/biome-host/index.ts +1 -1
- package/src/lib/biome-host/session-profiles.ts +7 -1
- package/src/lib/capabilities/capability-context.ts +25 -0
- package/src/lib/capabilities/capability-provider.tsx +5 -34
- package/src/lib/capabilities/index.ts +1 -0
- package/src/lib/capabilities/use-capability.ts +4 -1
- package/src/lib/contribution-registry/contribution-registry.spec.ts +141 -0
- package/src/lib/contribution-registry/contribution-registry.ts +202 -0
- package/src/lib/contribution-registry/index.ts +9 -0
- package/src/lib/contribution-registry/renderable-registry.ts +142 -0
- package/src/lib/system-bus/deeplink.ts +1 -1
- package/src/lib/system-bus/host-ports.ts +2 -1
- package/src/lib/system-bus/intent-registry.ts +1 -2
- package/src/offline/index.ts +4 -2
- package/src/offline/offline-status-badge.tsx +1 -1
- package/src/offline/outbox.test.ts +23 -16
- package/src/offline/outbox.ts +1 -1
- package/src/offline/react-hooks.ts +37 -0
- package/src/offline/react.tsx +1 -40
- package/src/offline/storage.ts +11 -6
- package/src/registry/index.ts +1 -0
- package/src/registry/lib/primitives/SessionEventCard.tsx +4 -2
- package/src/registry/lib/session-context-provider.tsx +8 -25
- package/src/registry/lib/session-context.ts +21 -0
- package/src/registry/lib/session-selectors.ts +3 -1
- package/src/ui/branding/app-branding-context.ts +20 -0
- package/src/ui/branding/app-branding-provider.tsx +5 -27
- package/src/ui/capture/field-spec-to-zod.ts +22 -0
- package/src/ui/capture/field-spec-validate.ts +147 -0
- package/src/ui/capture/field-spec.ts +62 -0
- package/src/ui/capture/index.ts +9 -1
- package/src/ui/capture/schema-field-input.tsx +141 -15
- package/src/ui/capture/submit-values.test.ts +70 -0
- package/src/ui/capture/submit-values.ts +63 -0
- package/src/ui/capture/use-prefill.ts +4 -1
- package/src/ui/capture/use-wizard.ts +2 -2
- package/src/ui/capture/wizard.tsx +2 -1
- package/src/ui/index.ts +11 -2
- package/src/ui/primitives/alert-dialog.tsx +1 -1
- package/src/ui/primitives/badge-variants.ts +21 -0
- package/src/ui/primitives/badge.tsx +3 -19
- package/src/ui/primitives/button-variants.ts +31 -0
- package/src/ui/primitives/button.tsx +3 -28
- package/src/ui/primitives/form-stepper.tsx +1 -16
- package/src/ui/primitives/form-stepper.types.ts +15 -0
- package/src/ui/primitives/overflow-tabs.tsx +24 -4
- package/src/ui/primitives/preview-device-frame.tsx +1 -1
- package/src/ui/primitives/tag-multi-select.tsx +3 -4
- package/src/ui/primitives/url-preview-chrome.tsx +102 -0
- package/src/vista/GenericCatalogueSurface.tsx +177 -0
- package/src/vista/SurfaceFallbackCard.tsx +109 -0
- package/src/vista/VistaPanel.tsx +155 -0
- package/src/vista/form-payload.spec.ts +139 -0
- package/src/vista/html/CustomUiFrame.spec.tsx +125 -0
- package/src/vista/html/CustomUiFrame.tsx +204 -0
- package/src/vista/html/custom-ui-frame-bridge.spec.ts +191 -0
- package/src/vista/html/custom-ui-frame-bridge.ts +92 -0
- package/src/vista/html/custom-ui-frame-contract.ts +88 -0
- package/src/vista/html/custom-ui-intents.spec.ts +133 -0
- package/src/vista/html/custom-ui-intents.ts +151 -0
- package/src/vista/html/custom-ui-srcdoc.spec.ts +151 -0
- package/src/vista/html/custom-ui-srcdoc.ts +193 -0
- package/src/vista/html/index.ts +13 -0
- package/src/vista/index.ts +52 -0
- package/src/vista/surface-catalogue.spec.ts +140 -0
- package/src/vista/surface-catalogue.ts +84 -0
- package/src/vista/surface-icons.ts +57 -0
- package/src/vista/surface-registry.ts +56 -0
- package/src/vista/surfaces/ChartSurface.tsx +34 -0
- package/src/vista/surfaces/FilesSurface.tsx +202 -0
- package/src/vista/surfaces/FormSurface.tsx +363 -0
- package/src/vista/surfaces/HtmlSurface.tsx +43 -0
- package/src/vista/surfaces/TableSurface.tsx +99 -0
- package/src/vista/surfaces/UrlSurface.tsx +40 -0
- package/src/vista/surfaces/blob-surfaces.tsx +129 -0
- package/src/vista/surfaces/elicitation-transport.spec.ts +369 -0
- package/src/vista/surfaces/elicitation-transport.ts +353 -0
- package/src/vista/surfaces/file-surface-utils.ts +62 -0
- package/src/vista/surfaces/index.ts +24 -0
- package/src/vista/surfaces/register-surfaces.tsx +137 -0
- package/src/vista/surfaces/text-surfaces.tsx +119 -0
- package/src/vista/use-vista-tabs.ts +188 -0
- package/src/vista/vista-code-renderer-context.ts +16 -0
- package/src/vista/vista-code-renderer.tsx +34 -0
- package/src/vista/vista-file-context.ts +14 -0
- package/src/vista/vista-file-source.tsx +140 -0
- package/src/vista/vista-form-context.ts +20 -0
- package/src/vista/vista-form-host.tsx +53 -0
- package/src/vista/vista-model.ts +130 -0
- package/src/vista/vista-open-context.tsx +32 -0
- package/src/vista/vista-open-state.ts +11 -0
- package/src/vista/vista-payloads.ts +512 -0
- package/src/vista/vista-tabs-manifest.ts +123 -0
- package/src/vista/vista-tools.ts +220 -0
- package/dist/lib/biome-host/response-envelope.d.ts +0 -3
- package/dist/lib/biome-host/response-envelope.d.ts.map +0 -1
- package/dist/lib/biome-host/response-envelope.js +0 -21
- package/dist/lib/biome-host/response-envelope.js.map +0 -1
- package/src/lib/biome-host/response-envelope.ts +0 -69
|
@@ -0,0 +1,353 @@
|
|
|
1
|
+
// ═══════════════════════════════════════════════════════════════════════════
|
|
2
|
+
// The `form` surface's transport — browser → owning service, direct.
|
|
3
|
+
//
|
|
4
|
+
// This module is the ONLY code that ever reads a captured field value out of
|
|
5
|
+
// the form surface, and it does exactly one thing with it: put it in the body
|
|
6
|
+
// of a `fetch` to an endpoint derived from the HOST-CONFIGURED trusted
|
|
7
|
+
// elicitation-service base URL, bearing the SUBJECT's own JWT.
|
|
8
|
+
//
|
|
9
|
+
// Three properties make "the agent cannot receive the value" structural:
|
|
10
|
+
//
|
|
11
|
+
// • the value is a PARAMETER, never a return: every exported function returns
|
|
12
|
+
// `VistaFormOutcome | null`, a closed scalar-only shape (see
|
|
13
|
+
// `../vista-form-host`). The values object is not reachable from any
|
|
14
|
+
// return, any thrown error, or any callback;
|
|
15
|
+
// • the response is PROJECTED, not passed through: `toOutcome` constructs a
|
|
16
|
+
// fresh object with exactly three keys, so a service that echoed a secret
|
|
17
|
+
// back could still not leak one through this boundary;
|
|
18
|
+
// • the payload carries only an opaque ref. It has NO network authority. This
|
|
19
|
+
// module validates the host-configured base URL and derives the exact
|
|
20
|
+
// status/submit paths before a bearer token or field value reaches fetch.
|
|
21
|
+
//
|
|
22
|
+
// Errors carry the SERVICE's message verbatim (that is how the backend's hard
|
|
23
|
+
// 400 on an empty credential form becomes readable UI copy) and never the
|
|
24
|
+
// request body.
|
|
25
|
+
// ═══════════════════════════════════════════════════════════════════════════
|
|
26
|
+
import { isValidVistaFormRef } from '../vista-payloads';
|
|
27
|
+
|
|
28
|
+
import type { VistaFormOutcome } from '../vista-form-context';
|
|
29
|
+
|
|
30
|
+
/** A non-2xx answer from the owning service, carrying its message verbatim. */
|
|
31
|
+
export class VistaFormSubmitError extends Error {
|
|
32
|
+
constructor(
|
|
33
|
+
readonly status: number,
|
|
34
|
+
message: string,
|
|
35
|
+
) {
|
|
36
|
+
super(message);
|
|
37
|
+
this.name = 'VistaFormSubmitError';
|
|
38
|
+
}
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
/** Invalid trusted-host transport configuration or unsafe path input. */
|
|
42
|
+
export class VistaFormTransportConfigError extends Error {
|
|
43
|
+
constructor(message: string) {
|
|
44
|
+
super(message);
|
|
45
|
+
this.name = 'VistaFormTransportConfigError';
|
|
46
|
+
}
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
export interface TrustedElicitationEndpoints {
|
|
50
|
+
readonly statusUrl: string;
|
|
51
|
+
readonly submitUrl: string;
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
type UnknownRecord = Readonly<Record<string, unknown>>;
|
|
55
|
+
|
|
56
|
+
function asRecord(value: unknown): UnknownRecord | null {
|
|
57
|
+
return value !== null && typeof value === 'object' && !Array.isArray(value)
|
|
58
|
+
? (value as UnknownRecord)
|
|
59
|
+
: null;
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
/**
|
|
63
|
+
* Unwrap the platform `{ data: … }` envelope when present. Total: a flat body
|
|
64
|
+
* is returned as-is, so the transport works against either wire shape without
|
|
65
|
+
* a second code path.
|
|
66
|
+
*/
|
|
67
|
+
function unwrapEnvelope(body: unknown): UnknownRecord | null {
|
|
68
|
+
const record = asRecord(body);
|
|
69
|
+
if (record === null) return null;
|
|
70
|
+
const inner = asRecord(record.data);
|
|
71
|
+
return inner ?? record;
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
/**
|
|
75
|
+
* Best-effort extraction of the SERVICE's error message. Falls back to a
|
|
76
|
+
* status-derived sentence — never to an empty string, because an empty error is
|
|
77
|
+
* indistinguishable from success in the UI.
|
|
78
|
+
*/
|
|
79
|
+
export function extractServiceMessage(body: unknown, status: number): string {
|
|
80
|
+
const record = asRecord(body);
|
|
81
|
+
const candidate =
|
|
82
|
+
record === null
|
|
83
|
+
? undefined
|
|
84
|
+
: (record.message ?? asRecord(record.error)?.message ?? record.error);
|
|
85
|
+
if (typeof candidate === 'string' && candidate.length > 0) return candidate;
|
|
86
|
+
if (Array.isArray(candidate)) {
|
|
87
|
+
const joined = candidate
|
|
88
|
+
.filter((m): m is string => typeof m === 'string')
|
|
89
|
+
.join(' ');
|
|
90
|
+
if (joined.length > 0) return joined;
|
|
91
|
+
}
|
|
92
|
+
if (typeof body === 'string' && body.length > 0) return body;
|
|
93
|
+
return `The service rejected the submission (HTTP ${status}).`;
|
|
94
|
+
}
|
|
95
|
+
|
|
96
|
+
async function readBody(response: Response): Promise<unknown> {
|
|
97
|
+
const contentType = response.headers.get('content-type');
|
|
98
|
+
try {
|
|
99
|
+
if (contentType !== null && contentType.includes('application/json')) {
|
|
100
|
+
return await response.json();
|
|
101
|
+
}
|
|
102
|
+
return await response.text();
|
|
103
|
+
} catch {
|
|
104
|
+
return null;
|
|
105
|
+
}
|
|
106
|
+
}
|
|
107
|
+
|
|
108
|
+
/**
|
|
109
|
+
* Project a service response onto {@link VistaFormOutcome}. Constructs a FRESH
|
|
110
|
+
* object with exactly three keys — nothing else from the response survives.
|
|
111
|
+
* Returns `null` when the service reports the elicitation is not settled.
|
|
112
|
+
*/
|
|
113
|
+
function toOutcome(body: unknown, ref: string): VistaFormOutcome | null {
|
|
114
|
+
const record = unwrapEnvelope(body);
|
|
115
|
+
if (record === null) return null;
|
|
116
|
+
const submitted =
|
|
117
|
+
record.submitted === true ||
|
|
118
|
+
(typeof record.status === 'string' && record.status === 'submitted');
|
|
119
|
+
if (!submitted) return null;
|
|
120
|
+
const connectionId =
|
|
121
|
+
typeof record.connectionId === 'string' && record.connectionId.length > 0
|
|
122
|
+
? record.connectionId
|
|
123
|
+
: null;
|
|
124
|
+
return { submitted: true, ref, connectionId };
|
|
125
|
+
}
|
|
126
|
+
|
|
127
|
+
/** The `Authorization`/`Content-Type` pair every request here carries. */
|
|
128
|
+
function authHeaders(
|
|
129
|
+
accessToken: string,
|
|
130
|
+
json: boolean,
|
|
131
|
+
): Record<string, string> {
|
|
132
|
+
const headers: Record<string, string> = {
|
|
133
|
+
Authorization: `Bearer ${accessToken}`,
|
|
134
|
+
Accept: 'application/json',
|
|
135
|
+
};
|
|
136
|
+
if (json) headers['Content-Type'] = 'application/json';
|
|
137
|
+
return headers;
|
|
138
|
+
}
|
|
139
|
+
|
|
140
|
+
function browserOrigin(): string | undefined {
|
|
141
|
+
return typeof globalThis.location === 'undefined'
|
|
142
|
+
? undefined
|
|
143
|
+
: globalThis.location.origin;
|
|
144
|
+
}
|
|
145
|
+
|
|
146
|
+
function isLoopbackHostname(hostname: string): boolean {
|
|
147
|
+
return (
|
|
148
|
+
hostname === 'localhost' ||
|
|
149
|
+
hostname.endsWith('.localhost') ||
|
|
150
|
+
hostname === '127.0.0.1' ||
|
|
151
|
+
hostname === '[::1]'
|
|
152
|
+
);
|
|
153
|
+
}
|
|
154
|
+
|
|
155
|
+
/**
|
|
156
|
+
* Parse the host's deploy-time trust anchor. It must be a canonical absolute
|
|
157
|
+
* HTTP(S) URL without credentials/query/fragment. HTTPS is mandatory except
|
|
158
|
+
* for loopback or same-host HTTP when the page itself is also served over HTTP.
|
|
159
|
+
*/
|
|
160
|
+
function trustedApiBaseUrl(
|
|
161
|
+
raw: string,
|
|
162
|
+
activeBrowserOrigin: string | undefined,
|
|
163
|
+
): URL {
|
|
164
|
+
if (raw.length === 0 || raw.trim() !== raw) {
|
|
165
|
+
throw new VistaFormTransportConfigError(
|
|
166
|
+
'The trusted elicitation API base URL is empty or contains whitespace.',
|
|
167
|
+
);
|
|
168
|
+
}
|
|
169
|
+
|
|
170
|
+
let url: URL;
|
|
171
|
+
try {
|
|
172
|
+
url = new URL(raw);
|
|
173
|
+
} catch {
|
|
174
|
+
throw new VistaFormTransportConfigError(
|
|
175
|
+
'The trusted elicitation API base URL must be absolute.',
|
|
176
|
+
);
|
|
177
|
+
}
|
|
178
|
+
|
|
179
|
+
if (
|
|
180
|
+
(url.protocol !== 'https:' && url.protocol !== 'http:') ||
|
|
181
|
+
url.username.length > 0 ||
|
|
182
|
+
url.password.length > 0 ||
|
|
183
|
+
url.search.length > 0 ||
|
|
184
|
+
url.hash.length > 0
|
|
185
|
+
) {
|
|
186
|
+
throw new VistaFormTransportConfigError(
|
|
187
|
+
'The trusted elicitation API base URL must use HTTP(S) and contain no credentials, query, or fragment.',
|
|
188
|
+
);
|
|
189
|
+
}
|
|
190
|
+
|
|
191
|
+
const canonicalPath =
|
|
192
|
+
url.pathname === '/' ? '' : url.pathname.replace(/\/+$/, '');
|
|
193
|
+
const canonical = `${url.origin}${canonicalPath}`;
|
|
194
|
+
const suppliedWithoutOneTrailingSlash = raw.endsWith('/')
|
|
195
|
+
? raw.slice(0, -1)
|
|
196
|
+
: raw;
|
|
197
|
+
if (suppliedWithoutOneTrailingSlash !== canonical) {
|
|
198
|
+
throw new VistaFormTransportConfigError(
|
|
199
|
+
'The trusted elicitation API base URL must be canonical and contain no traversal or ambiguous path.',
|
|
200
|
+
);
|
|
201
|
+
}
|
|
202
|
+
|
|
203
|
+
if (url.protocol === 'http:' && !isLoopbackHostname(url.hostname)) {
|
|
204
|
+
let page: URL | null = null;
|
|
205
|
+
if (activeBrowserOrigin !== undefined) {
|
|
206
|
+
try {
|
|
207
|
+
page = new URL(activeBrowserOrigin);
|
|
208
|
+
} catch {
|
|
209
|
+
page = null;
|
|
210
|
+
}
|
|
211
|
+
}
|
|
212
|
+
if (
|
|
213
|
+
page === null ||
|
|
214
|
+
page.protocol !== 'http:' ||
|
|
215
|
+
page.hostname !== url.hostname
|
|
216
|
+
) {
|
|
217
|
+
throw new VistaFormTransportConfigError(
|
|
218
|
+
'Insecure elicitation HTTP is allowed only on loopback or the same host as an HTTP development page.',
|
|
219
|
+
);
|
|
220
|
+
}
|
|
221
|
+
}
|
|
222
|
+
|
|
223
|
+
return new URL(canonical);
|
|
224
|
+
}
|
|
225
|
+
|
|
226
|
+
/**
|
|
227
|
+
* Derive the only two authenticated endpoints from trusted host configuration
|
|
228
|
+
* plus one opaque path segment. Calling this directly remains safe even if a
|
|
229
|
+
* caller bypasses the surface-payload validator.
|
|
230
|
+
*/
|
|
231
|
+
export function resolveTrustedElicitationEndpoints(
|
|
232
|
+
apiBaseUrl: string,
|
|
233
|
+
ref: string,
|
|
234
|
+
activeBrowserOrigin: string | undefined = browserOrigin(),
|
|
235
|
+
): TrustedElicitationEndpoints {
|
|
236
|
+
if (!isValidVistaFormRef(ref)) {
|
|
237
|
+
throw new VistaFormTransportConfigError(
|
|
238
|
+
'The elicitation reference is not a valid opaque base64url path segment.',
|
|
239
|
+
);
|
|
240
|
+
}
|
|
241
|
+
const base = trustedApiBaseUrl(apiBaseUrl, activeBrowserOrigin)
|
|
242
|
+
.toString()
|
|
243
|
+
.replace(/\/$/, '');
|
|
244
|
+
const statusUrl = `${base}/${ref}`;
|
|
245
|
+
return { statusUrl, submitUrl: `${statusUrl}/submit` };
|
|
246
|
+
}
|
|
247
|
+
|
|
248
|
+
/**
|
|
249
|
+
* Resolve an unauthenticated launch path under the SAME trusted service origin.
|
|
250
|
+
* Absolute/network-path URLs and dot-segment traversal fail closed.
|
|
251
|
+
*/
|
|
252
|
+
export function resolveTrustedElicitationLaunchUrl(
|
|
253
|
+
apiBaseUrl: string,
|
|
254
|
+
path: string,
|
|
255
|
+
activeBrowserOrigin: string | undefined = browserOrigin(),
|
|
256
|
+
): string {
|
|
257
|
+
const base = trustedApiBaseUrl(apiBaseUrl, activeBrowserOrigin);
|
|
258
|
+
if (
|
|
259
|
+
!path.startsWith('/') ||
|
|
260
|
+
path.startsWith('//') ||
|
|
261
|
+
path.includes('\\') ||
|
|
262
|
+
path.includes('#')
|
|
263
|
+
) {
|
|
264
|
+
throw new VistaFormTransportConfigError(
|
|
265
|
+
'The elicitation launch target must be a root-relative service path.',
|
|
266
|
+
);
|
|
267
|
+
}
|
|
268
|
+
const resolved = new URL(path, `${base.origin}/`);
|
|
269
|
+
if (
|
|
270
|
+
resolved.origin !== base.origin ||
|
|
271
|
+
`${resolved.pathname}${resolved.search}` !== path
|
|
272
|
+
) {
|
|
273
|
+
throw new VistaFormTransportConfigError(
|
|
274
|
+
'The elicitation launch path contains traversal or an ambiguous encoding.',
|
|
275
|
+
);
|
|
276
|
+
}
|
|
277
|
+
return resolved.toString();
|
|
278
|
+
}
|
|
279
|
+
|
|
280
|
+
/**
|
|
281
|
+
* POST the captured fields to the owning service.
|
|
282
|
+
*
|
|
283
|
+
* @throws {VistaFormSubmitError} on a non-2xx answer, carrying the service's
|
|
284
|
+
* own message so a hard 400 (e.g. "no credential form is declared") is what the
|
|
285
|
+
* user reads.
|
|
286
|
+
*/
|
|
287
|
+
export async function submitElicitationFields(args: {
|
|
288
|
+
readonly apiBaseUrl: string;
|
|
289
|
+
readonly ref: string;
|
|
290
|
+
readonly accessToken: string;
|
|
291
|
+
readonly fields: Readonly<Record<string, string>>;
|
|
292
|
+
}): Promise<VistaFormOutcome> {
|
|
293
|
+
const { submitUrl } = resolveTrustedElicitationEndpoints(
|
|
294
|
+
args.apiBaseUrl,
|
|
295
|
+
args.ref,
|
|
296
|
+
);
|
|
297
|
+
const response = await fetch(submitUrl, {
|
|
298
|
+
method: 'POST',
|
|
299
|
+
headers: authHeaders(args.accessToken, true),
|
|
300
|
+
body: JSON.stringify({ fields: args.fields }),
|
|
301
|
+
credentials: 'omit',
|
|
302
|
+
// A 307/308 could otherwise replay the credential body to a different
|
|
303
|
+
// origin. Authenticated elicitation endpoints must never redirect.
|
|
304
|
+
redirect: 'error',
|
|
305
|
+
});
|
|
306
|
+
const body = await readBody(response);
|
|
307
|
+
if (!response.ok) {
|
|
308
|
+
throw new VistaFormSubmitError(
|
|
309
|
+
response.status,
|
|
310
|
+
extractServiceMessage(body, response.status),
|
|
311
|
+
);
|
|
312
|
+
}
|
|
313
|
+
const outcome = toOutcome(body, args.ref);
|
|
314
|
+
if (outcome === null) {
|
|
315
|
+
throw new VistaFormSubmitError(
|
|
316
|
+
response.status,
|
|
317
|
+
'The service accepted the request but did not report the elicitation as submitted.',
|
|
318
|
+
);
|
|
319
|
+
}
|
|
320
|
+
return outcome;
|
|
321
|
+
}
|
|
322
|
+
|
|
323
|
+
/**
|
|
324
|
+
* Read the elicitation's current state. Used by the OAuth / app-install handoff,
|
|
325
|
+
* where completion happens in another window and the only signal available to
|
|
326
|
+
* this tab is the service's own record.
|
|
327
|
+
*
|
|
328
|
+
* Returns `null` while still pending — an explicit "not yet", never a guess.
|
|
329
|
+
*/
|
|
330
|
+
export async function readElicitationStatus(args: {
|
|
331
|
+
readonly apiBaseUrl: string;
|
|
332
|
+
readonly ref: string;
|
|
333
|
+
readonly accessToken: string;
|
|
334
|
+
}): Promise<VistaFormOutcome | null> {
|
|
335
|
+
const { statusUrl } = resolveTrustedElicitationEndpoints(
|
|
336
|
+
args.apiBaseUrl,
|
|
337
|
+
args.ref,
|
|
338
|
+
);
|
|
339
|
+
const response = await fetch(statusUrl, {
|
|
340
|
+
method: 'GET',
|
|
341
|
+
headers: authHeaders(args.accessToken, false),
|
|
342
|
+
credentials: 'omit',
|
|
343
|
+
redirect: 'error',
|
|
344
|
+
});
|
|
345
|
+
const body = await readBody(response);
|
|
346
|
+
if (!response.ok) {
|
|
347
|
+
throw new VistaFormSubmitError(
|
|
348
|
+
response.status,
|
|
349
|
+
extractServiceMessage(body, response.status),
|
|
350
|
+
);
|
|
351
|
+
}
|
|
352
|
+
return toOutcome(body, args.ref);
|
|
353
|
+
}
|
|
@@ -0,0 +1,62 @@
|
|
|
1
|
+
import type { VistaFileEntry } from '../vista-payloads';
|
|
2
|
+
|
|
3
|
+
interface FileExtMeta {
|
|
4
|
+
readonly color: string;
|
|
5
|
+
readonly tag: string;
|
|
6
|
+
}
|
|
7
|
+
|
|
8
|
+
const EXT_META: Readonly<Record<string, FileExtMeta>> = {
|
|
9
|
+
ts: { color: 'hsl(var(--info))', tag: 'TS' },
|
|
10
|
+
tsx: { color: 'hsl(var(--info))', tag: 'TSX' },
|
|
11
|
+
js: { color: 'hsl(var(--warning))', tag: 'JS' },
|
|
12
|
+
jsx: { color: 'hsl(var(--warning))', tag: 'JSX' },
|
|
13
|
+
json: { color: 'hsl(var(--ink-3))', tag: 'JSON' },
|
|
14
|
+
md: { color: 'hsl(var(--p-people))', tag: 'MD' },
|
|
15
|
+
css: { color: 'hsl(var(--p-sales))', tag: 'CSS' },
|
|
16
|
+
html: { color: 'hsl(var(--p-sales))', tag: 'HTML' },
|
|
17
|
+
yaml: { color: 'hsl(var(--ink-3))', tag: 'YAML' },
|
|
18
|
+
yml: { color: 'hsl(var(--ink-3))', tag: 'YAML' },
|
|
19
|
+
};
|
|
20
|
+
|
|
21
|
+
export function fileExtMeta(name: string): FileExtMeta {
|
|
22
|
+
if (/\.test\.[tj]sx?$/.test(name) || /\.spec\.[tj]sx?$/.test(name)) {
|
|
23
|
+
return { color: 'hsl(var(--success))', tag: 'TEST' };
|
|
24
|
+
}
|
|
25
|
+
const ext = name.split('.').pop() ?? '';
|
|
26
|
+
return (
|
|
27
|
+
EXT_META[ext] ?? {
|
|
28
|
+
color: 'hsl(var(--ink-4))',
|
|
29
|
+
tag: (ext || 'FILE').toUpperCase().slice(0, 4),
|
|
30
|
+
}
|
|
31
|
+
);
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
export interface VistaFileGroup {
|
|
35
|
+
readonly dir: string;
|
|
36
|
+
readonly files: readonly VistaFileEntry[];
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
function compareDirs(a: string, b: string): number {
|
|
40
|
+
if (a === '') return -1;
|
|
41
|
+
if (b === '') return 1;
|
|
42
|
+
return a.localeCompare(b);
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
export function groupFilesByFolder(
|
|
46
|
+
files: readonly VistaFileEntry[],
|
|
47
|
+
): VistaFileGroup[] {
|
|
48
|
+
const groups = new Map<string, VistaFileEntry[]>();
|
|
49
|
+
for (const file of files) {
|
|
50
|
+
const slash = file.path.lastIndexOf('/');
|
|
51
|
+
const dir = slash < 0 ? '' : file.path.slice(0, slash);
|
|
52
|
+
const bucket = groups.get(dir);
|
|
53
|
+
if (bucket) bucket.push(file);
|
|
54
|
+
else groups.set(dir, [file]);
|
|
55
|
+
}
|
|
56
|
+
return [...groups.keys()].sort(compareDirs).map((dir) => ({
|
|
57
|
+
dir,
|
|
58
|
+
files: [...(groups.get(dir) ?? [])].sort((a, b) =>
|
|
59
|
+
a.path.localeCompare(b.path),
|
|
60
|
+
),
|
|
61
|
+
}));
|
|
62
|
+
}
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
import './register-surfaces';
|
|
2
|
+
|
|
3
|
+
export { ChartSurface } from './ChartSurface';
|
|
4
|
+
export { FilesSurface } from './FilesSurface';
|
|
5
|
+
export {
|
|
6
|
+
fileExtMeta,
|
|
7
|
+
groupFilesByFolder,
|
|
8
|
+
type VistaFileGroup,
|
|
9
|
+
} from './file-surface-utils';
|
|
10
|
+
export { FormSurface } from './FormSurface';
|
|
11
|
+
export {
|
|
12
|
+
extractServiceMessage,
|
|
13
|
+
readElicitationStatus,
|
|
14
|
+
resolveTrustedElicitationEndpoints,
|
|
15
|
+
resolveTrustedElicitationLaunchUrl,
|
|
16
|
+
submitElicitationFields,
|
|
17
|
+
VistaFormSubmitError,
|
|
18
|
+
VistaFormTransportConfigError,
|
|
19
|
+
} from './elicitation-transport';
|
|
20
|
+
export { HtmlSurface } from './HtmlSurface';
|
|
21
|
+
export { TableSurface } from './TableSurface';
|
|
22
|
+
export { UrlSurface } from './UrlSurface';
|
|
23
|
+
export { CodeSurface, DiffSurface, JsonSurface } from './text-surfaces';
|
|
24
|
+
export { ImageSurface, MediaSurface, PdfSurface } from './blob-surfaces';
|
|
@@ -0,0 +1,137 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Registration of the first-party surface renderers the UI KERNEL owns.
|
|
3
|
+
*
|
|
4
|
+
* ── The partition (deliberate, and the reason there is no slot-soup) ─────────
|
|
5
|
+
* A kind is registered HERE when the kernel can render it standalone from its
|
|
6
|
+
* payload (plus, for a file-backed kind, the host's injected `VistaFileSource`):
|
|
7
|
+
*
|
|
8
|
+
* url · html · code · json · diff · table · chart · files · image · media ·
|
|
9
|
+
* pdf · form
|
|
10
|
+
*
|
|
11
|
+
* `form` (secure elicitation) belongs here even though it talks to a service:
|
|
12
|
+
* it does so through the host-supplied `VistaFormHost` seam, exactly the way a
|
|
13
|
+
* file-backed surface reads through `VistaFileSource`. The kernel owns the
|
|
14
|
+
* renderer; the host owns only the token and the outcome sink.
|
|
15
|
+
*
|
|
16
|
+
* The remaining first-party kinds are HOST-COUPLED — they need the host's
|
|
17
|
+
* router, its object views, its markdown renderer, or its biome registry — so
|
|
18
|
+
* the HOST registers them with
|
|
19
|
+
* `vistaSurfaceRegistry.registerFirstParty(...)`:
|
|
20
|
+
*
|
|
21
|
+
* markdown · web · biome-route · object · graph · app
|
|
22
|
+
*
|
|
23
|
+
* Every unregistered kind resolves to `SurfaceFallbackCard` with
|
|
24
|
+
* `unknown-kind` — visible, typed, never blank.
|
|
25
|
+
*
|
|
26
|
+
* Importing this module REGISTERS. It is imported for its side effect by
|
|
27
|
+
* `../index.ts`, so any consumer of `@xemahq/ui-kernel/vista` gets the kernel
|
|
28
|
+
* builtins wired without an explicit call.
|
|
29
|
+
*/
|
|
30
|
+
import { SurfaceKind } from '@xemahq/kernel-contracts/surface';
|
|
31
|
+
|
|
32
|
+
import { ImageSurface, MediaSurface, PdfSurface } from './blob-surfaces';
|
|
33
|
+
import { ChartSurface } from './ChartSurface';
|
|
34
|
+
import { FilesSurface } from './FilesSurface';
|
|
35
|
+
import { FormSurface } from './FormSurface';
|
|
36
|
+
import { HtmlSurface } from './HtmlSurface';
|
|
37
|
+
import { TableSurface } from './TableSurface';
|
|
38
|
+
import { CodeSurface, DiffSurface, JsonSurface } from './text-surfaces';
|
|
39
|
+
import { UrlSurface } from './UrlSurface';
|
|
40
|
+
import { vistaSurfaceRegistry } from '../surface-registry';
|
|
41
|
+
import { VISTA_SURFACE_VERSION } from '../vista-model';
|
|
42
|
+
import {
|
|
43
|
+
validateBlobPayload,
|
|
44
|
+
validateChartPayload,
|
|
45
|
+
validateDiffPayload,
|
|
46
|
+
validateFilesPayload,
|
|
47
|
+
validateFormPayload,
|
|
48
|
+
validateHtmlPayload,
|
|
49
|
+
validateJsonPayload,
|
|
50
|
+
validateTablePayload,
|
|
51
|
+
validateTextPayload,
|
|
52
|
+
validateUrlPayload,
|
|
53
|
+
type VistaBlobPayload,
|
|
54
|
+
} from '../vista-payloads';
|
|
55
|
+
|
|
56
|
+
/**
|
|
57
|
+
* `media` additionally REQUIRES `contentType`: choosing between `<audio>` and
|
|
58
|
+
* `<video>` from a URL would be a heuristic that fails on an extension-less
|
|
59
|
+
* URL, and this plane does not ship heuristics that can be wrong.
|
|
60
|
+
*/
|
|
61
|
+
function validateMediaPayload(raw: unknown): VistaBlobPayload | null {
|
|
62
|
+
const payload = validateBlobPayload(raw);
|
|
63
|
+
if (payload === null) return null;
|
|
64
|
+
return payload.contentType === undefined ? null : payload;
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
vistaSurfaceRegistry.registerFirstParty(SurfaceKind.Url, {
|
|
68
|
+
version: VISTA_SURFACE_VERSION,
|
|
69
|
+
validate: validateUrlPayload,
|
|
70
|
+
render: (payload) => <UrlSurface {...payload} />,
|
|
71
|
+
});
|
|
72
|
+
|
|
73
|
+
vistaSurfaceRegistry.registerFirstParty(SurfaceKind.Html, {
|
|
74
|
+
version: VISTA_SURFACE_VERSION,
|
|
75
|
+
validate: validateHtmlPayload,
|
|
76
|
+
render: (payload) => <HtmlSurface {...payload} />,
|
|
77
|
+
});
|
|
78
|
+
|
|
79
|
+
vistaSurfaceRegistry.registerFirstParty(SurfaceKind.Code, {
|
|
80
|
+
version: VISTA_SURFACE_VERSION,
|
|
81
|
+
validate: validateTextPayload,
|
|
82
|
+
render: (payload) => <CodeSurface {...payload} />,
|
|
83
|
+
});
|
|
84
|
+
|
|
85
|
+
vistaSurfaceRegistry.registerFirstParty(SurfaceKind.Json, {
|
|
86
|
+
version: VISTA_SURFACE_VERSION,
|
|
87
|
+
validate: validateJsonPayload,
|
|
88
|
+
render: (payload) => <JsonSurface data={payload.data} />,
|
|
89
|
+
});
|
|
90
|
+
|
|
91
|
+
vistaSurfaceRegistry.registerFirstParty(SurfaceKind.Diff, {
|
|
92
|
+
version: VISTA_SURFACE_VERSION,
|
|
93
|
+
validate: validateDiffPayload,
|
|
94
|
+
render: (payload) => <DiffSurface {...payload} />,
|
|
95
|
+
});
|
|
96
|
+
|
|
97
|
+
vistaSurfaceRegistry.registerFirstParty(SurfaceKind.Table, {
|
|
98
|
+
version: VISTA_SURFACE_VERSION,
|
|
99
|
+
validate: validateTablePayload,
|
|
100
|
+
render: (payload) => <TableSurface {...payload} />,
|
|
101
|
+
});
|
|
102
|
+
|
|
103
|
+
vistaSurfaceRegistry.registerFirstParty(SurfaceKind.Chart, {
|
|
104
|
+
version: VISTA_SURFACE_VERSION,
|
|
105
|
+
validate: validateChartPayload,
|
|
106
|
+
render: (payload) => <ChartSurface {...payload} />,
|
|
107
|
+
});
|
|
108
|
+
|
|
109
|
+
vistaSurfaceRegistry.registerFirstParty(SurfaceKind.Files, {
|
|
110
|
+
version: VISTA_SURFACE_VERSION,
|
|
111
|
+
validate: validateFilesPayload,
|
|
112
|
+
render: (payload) => <FilesSurface {...payload} />,
|
|
113
|
+
});
|
|
114
|
+
|
|
115
|
+
vistaSurfaceRegistry.registerFirstParty(SurfaceKind.Image, {
|
|
116
|
+
version: VISTA_SURFACE_VERSION,
|
|
117
|
+
validate: validateBlobPayload,
|
|
118
|
+
render: (payload) => <ImageSurface {...payload} />,
|
|
119
|
+
});
|
|
120
|
+
|
|
121
|
+
vistaSurfaceRegistry.registerFirstParty(SurfaceKind.Media, {
|
|
122
|
+
version: VISTA_SURFACE_VERSION,
|
|
123
|
+
validate: validateMediaPayload,
|
|
124
|
+
render: (payload) => <MediaSurface {...payload} />,
|
|
125
|
+
});
|
|
126
|
+
|
|
127
|
+
vistaSurfaceRegistry.registerFirstParty(SurfaceKind.Pdf, {
|
|
128
|
+
version: VISTA_SURFACE_VERSION,
|
|
129
|
+
validate: validateBlobPayload,
|
|
130
|
+
render: (payload) => <PdfSurface {...payload} />,
|
|
131
|
+
});
|
|
132
|
+
|
|
133
|
+
vistaSurfaceRegistry.registerFirstParty(SurfaceKind.Form, {
|
|
134
|
+
version: VISTA_SURFACE_VERSION,
|
|
135
|
+
validate: validateFormPayload,
|
|
136
|
+
render: (payload) => <FormSurface {...payload} />,
|
|
137
|
+
});
|
|
@@ -0,0 +1,119 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The text-bodied first-party surfaces: `code`, `json`, `diff`.
|
|
3
|
+
*
|
|
4
|
+
* Each accepts an inline `content` or a workspace `path` resolved through the
|
|
5
|
+
* host {@link VistaFileSource}, so a panel can open a file lazily without the
|
|
6
|
+
* kernel knowing anything about the host's file endpoints.
|
|
7
|
+
*
|
|
8
|
+
* `code` is a mono pane — it is also where a plain-text file lands (the legacy
|
|
9
|
+
* `plain` tab kind was collapsed into it; one kind, one renderer, no alias).
|
|
10
|
+
*/
|
|
11
|
+
|
|
12
|
+
import { useVistaCodeRenderer } from '../vista-code-renderer-context';
|
|
13
|
+
import { VistaFileText } from '../vista-file-source';
|
|
14
|
+
|
|
15
|
+
import type { VistaTextPayload } from '../vista-payloads';
|
|
16
|
+
import type { ReactElement, ReactNode } from 'react';
|
|
17
|
+
|
|
18
|
+
const PANE_STYLE = {
|
|
19
|
+
height: '100%',
|
|
20
|
+
width: '100%',
|
|
21
|
+
margin: 0,
|
|
22
|
+
overflow: 'auto',
|
|
23
|
+
padding: '14px 16px',
|
|
24
|
+
fontSize: 12,
|
|
25
|
+
lineHeight: 1.6,
|
|
26
|
+
color: 'hsl(var(--ink-2))',
|
|
27
|
+
whiteSpace: 'pre-wrap' as const,
|
|
28
|
+
};
|
|
29
|
+
|
|
30
|
+
/** Render inline content, or fetch the path first — one seam for all three. */
|
|
31
|
+
function TextBody({
|
|
32
|
+
payload,
|
|
33
|
+
render,
|
|
34
|
+
}: Readonly<{
|
|
35
|
+
payload: VistaTextPayload;
|
|
36
|
+
render: (content: string) => ReactNode;
|
|
37
|
+
}>): ReactElement {
|
|
38
|
+
if (payload.content !== undefined) return <>{render(payload.content)}</>;
|
|
39
|
+
// `validateTextPayload` guarantees exactly one of content/path.
|
|
40
|
+
return <VistaFileText path={payload.path as string} render={render} />;
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
export function CodeSurface(payload: VistaTextPayload): ReactElement {
|
|
44
|
+
// A host that ships a code editor provides it through
|
|
45
|
+
// `VistaCodeRendererProvider`; with none the mono pane below IS the intended
|
|
46
|
+
// rendering (see `vista-code-renderer.tsx`).
|
|
47
|
+
const hostRenderer = useVistaCodeRenderer();
|
|
48
|
+
return (
|
|
49
|
+
<TextBody
|
|
50
|
+
payload={payload}
|
|
51
|
+
render={(content) =>
|
|
52
|
+
hostRenderer === null ? (
|
|
53
|
+
<pre className="mono" style={PANE_STYLE}>
|
|
54
|
+
{content}
|
|
55
|
+
</pre>
|
|
56
|
+
) : (
|
|
57
|
+
hostRenderer({
|
|
58
|
+
content,
|
|
59
|
+
...(payload.path === undefined ? {} : { path: payload.path }),
|
|
60
|
+
...(payload.language === undefined
|
|
61
|
+
? {}
|
|
62
|
+
: { language: payload.language }),
|
|
63
|
+
})
|
|
64
|
+
)
|
|
65
|
+
}
|
|
66
|
+
/>
|
|
67
|
+
);
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
/**
|
|
71
|
+
* `json` — pretty-printed and inspectable. An inline payload carries parsed
|
|
72
|
+
* `data`; a path-backed one carries the raw text, which is re-serialised when it
|
|
73
|
+
* parses and shown VERBATIM when it does not (a malformed JSON file is shown as
|
|
74
|
+
* it is, never swallowed).
|
|
75
|
+
*/
|
|
76
|
+
export function JsonSurface({ data }: Readonly<{ data: unknown }>): ReactElement {
|
|
77
|
+
let text: string;
|
|
78
|
+
try {
|
|
79
|
+
text = JSON.stringify(data, null, 2) ?? String(data);
|
|
80
|
+
} catch {
|
|
81
|
+
text = String(data);
|
|
82
|
+
}
|
|
83
|
+
return (
|
|
84
|
+
<pre className="mono" style={PANE_STYLE}>
|
|
85
|
+
{text}
|
|
86
|
+
</pre>
|
|
87
|
+
);
|
|
88
|
+
}
|
|
89
|
+
|
|
90
|
+
/** Colour a unified-diff line by its leading marker. */
|
|
91
|
+
function diffLineColor(line: string): string | undefined {
|
|
92
|
+
if (line.startsWith('+++') || line.startsWith('---')) return 'hsl(var(--ink-3))';
|
|
93
|
+
if (line.startsWith('@@')) return 'hsl(var(--info))';
|
|
94
|
+
if (line.startsWith('+')) return 'hsl(var(--success))';
|
|
95
|
+
if (line.startsWith('-')) return 'hsl(var(--destructive, var(--danger)))';
|
|
96
|
+
return undefined;
|
|
97
|
+
}
|
|
98
|
+
|
|
99
|
+
export function DiffSurface(payload: VistaTextPayload): ReactElement {
|
|
100
|
+
return (
|
|
101
|
+
<TextBody
|
|
102
|
+
payload={payload}
|
|
103
|
+
render={(content) => (
|
|
104
|
+
<pre className="mono" style={PANE_STYLE}>
|
|
105
|
+
{content.split('\n').map((line, index) => (
|
|
106
|
+
<div
|
|
107
|
+
// A diff has no stable per-line identity other than its position.
|
|
108
|
+
|
|
109
|
+
key={index}
|
|
110
|
+
style={{ color: diffLineColor(line) }}
|
|
111
|
+
>
|
|
112
|
+
{line === '' ? ' ' : line}
|
|
113
|
+
</div>
|
|
114
|
+
))}
|
|
115
|
+
</pre>
|
|
116
|
+
)}
|
|
117
|
+
/>
|
|
118
|
+
);
|
|
119
|
+
}
|