@miragon/mcp-toolkit-ui 2.6.0 → 2.8.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +14 -5
- package/dist/app/adapt-data-widget.d.ts +1 -22
- package/dist/app/adapt-data-widget.d.ts.map +1 -1
- package/dist/app/adapt-data-widget.js +1 -35
- package/dist/app/adapt-data-widget.js.map +1 -1
- package/dist/app/builder/BuilderBanners.d.ts +7 -2
- package/dist/app/builder/BuilderBanners.d.ts.map +1 -1
- package/dist/app/builder/BuilderBanners.js +8 -3
- package/dist/app/builder/BuilderBanners.js.map +1 -1
- package/dist/app/builder/CanvasRow.d.ts +4 -2
- package/dist/app/builder/CanvasRow.d.ts.map +1 -1
- package/dist/app/builder/CanvasRow.js +29 -17
- package/dist/app/builder/CanvasRow.js.map +1 -1
- package/dist/app/builder/CatalogueSheet.d.ts.map +1 -1
- package/dist/app/builder/CatalogueSheet.js +14 -6
- package/dist/app/builder/CatalogueSheet.js.map +1 -1
- package/dist/app/builder/CellPropsSheet.d.ts +7 -3
- package/dist/app/builder/CellPropsSheet.d.ts.map +1 -1
- package/dist/app/builder/CellPropsSheet.js +10 -3
- package/dist/app/builder/CellPropsSheet.js.map +1 -1
- package/dist/app/builder/DiscardDialog.d.ts +18 -0
- package/dist/app/builder/DiscardDialog.d.ts.map +1 -0
- package/dist/app/builder/DiscardDialog.js +18 -0
- package/dist/app/builder/DiscardDialog.js.map +1 -0
- package/dist/app/builder/EmptyHint.d.ts +4 -0
- package/dist/app/builder/EmptyHint.d.ts.map +1 -1
- package/dist/app/builder/EmptyHint.js +6 -1
- package/dist/app/builder/EmptyHint.js.map +1 -1
- package/dist/app/builder/LayoutSurface.d.ts +33 -9
- package/dist/app/builder/LayoutSurface.d.ts.map +1 -1
- package/dist/app/builder/LayoutSurface.js +74 -23
- package/dist/app/builder/LayoutSurface.js.map +1 -1
- package/dist/app/builder/PipelineStrip.d.ts +5 -2
- package/dist/app/builder/PipelineStrip.d.ts.map +1 -1
- package/dist/app/builder/PipelineStrip.js +33 -15
- package/dist/app/builder/PipelineStrip.js.map +1 -1
- package/dist/app/builder/SaveDialog.d.ts +9 -1
- package/dist/app/builder/SaveDialog.d.ts.map +1 -1
- package/dist/app/builder/SaveDialog.js +9 -3
- package/dist/app/builder/SaveDialog.js.map +1 -1
- package/dist/app/builder/Toolbar.d.ts +14 -4
- package/dist/app/builder/Toolbar.d.ts.map +1 -1
- package/dist/app/builder/Toolbar.js +24 -7
- package/dist/app/builder/Toolbar.js.map +1 -1
- package/dist/app/builder/Workspace.d.ts +23 -3
- package/dist/app/builder/Workspace.d.ts.map +1 -1
- package/dist/app/builder/Workspace.js +58 -8
- package/dist/app/builder/Workspace.js.map +1 -1
- package/dist/app/builder/builder-model.d.ts +146 -3
- package/dist/app/builder/builder-model.d.ts.map +1 -1
- package/dist/app/builder/builder-model.js +196 -5
- package/dist/app/builder/builder-model.js.map +1 -1
- package/dist/app/builder/labels.d.ts +13 -62
- package/dist/app/builder/labels.d.ts.map +1 -1
- package/dist/app/builder/labels.js +9 -58
- package/dist/app/builder/labels.js.map +1 -1
- package/dist/app/builder/reveal.d.ts +10 -0
- package/dist/app/builder/reveal.d.ts.map +1 -0
- package/dist/app/builder/reveal.js +10 -0
- package/dist/app/builder/reveal.js.map +1 -0
- package/dist/app/builder/status-chip.d.ts.map +1 -1
- package/dist/app/builder/status-chip.js +3 -2
- package/dist/app/builder/status-chip.js.map +1 -1
- package/dist/app/builder/use-builder-catalogue.d.ts +5 -1
- package/dist/app/builder/use-builder-catalogue.d.ts.map +1 -1
- package/dist/app/builder/use-builder-catalogue.js +50 -17
- package/dist/app/builder/use-builder-catalogue.js.map +1 -1
- package/dist/app/builder/use-builder-session.d.ts +30 -0
- package/dist/app/builder/use-builder-session.d.ts.map +1 -0
- package/dist/app/builder/use-builder-session.js +58 -0
- package/dist/app/builder/use-builder-session.js.map +1 -0
- package/dist/app/builder/use-display-resolver.d.ts +17 -0
- package/dist/app/builder/use-display-resolver.d.ts.map +1 -0
- package/dist/app/builder/use-display-resolver.js +16 -0
- package/dist/app/builder/use-display-resolver.js.map +1 -0
- package/dist/app/builder/use-save-dashboard.d.ts +3 -1
- package/dist/app/builder/use-save-dashboard.d.ts.map +1 -1
- package/dist/app/builder/use-save-dashboard.js +3 -1
- package/dist/app/builder/use-save-dashboard.js.map +1 -1
- package/dist/app/index.d.ts +8 -3
- package/dist/app/index.d.ts.map +1 -1
- package/dist/app/index.js +8 -2
- package/dist/app/index.js.map +1 -1
- package/dist/app/layout-builder.d.ts +18 -25
- package/dist/app/layout-builder.d.ts.map +1 -1
- package/dist/app/layout-builder.js +84 -78
- package/dist/app/layout-builder.js.map +1 -1
- package/dist/app/mcp-app-view-chrome.d.ts +103 -20
- package/dist/app/mcp-app-view-chrome.d.ts.map +1 -1
- package/dist/app/mcp-app-view-chrome.js +125 -40
- package/dist/app/mcp-app-view-chrome.js.map +1 -1
- package/dist/app/mcp-app-view-states.d.ts +23 -0
- package/dist/app/mcp-app-view-states.d.ts.map +1 -0
- package/dist/app/mcp-app-view-states.js +55 -0
- package/dist/app/mcp-app-view-states.js.map +1 -0
- package/dist/app/mcp-app-view.d.ts +72 -5
- package/dist/app/mcp-app-view.d.ts.map +1 -1
- package/dist/app/mcp-app-view.js +241 -141
- package/dist/app/mcp-app-view.js.map +1 -1
- package/dist/app/mcp-toolkit-app.d.ts +8 -2
- package/dist/app/mcp-toolkit-app.d.ts.map +1 -1
- package/dist/app/mcp-toolkit-app.js +33 -4
- package/dist/app/mcp-toolkit-app.js.map +1 -1
- package/dist/app/mcp-use-host-bridge.d.ts +15 -6
- package/dist/app/mcp-use-host-bridge.d.ts.map +1 -1
- package/dist/app/mcp-use-host-bridge.js +51 -22
- package/dist/app/mcp-use-host-bridge.js.map +1 -1
- package/dist/app/model-context.d.ts +71 -0
- package/dist/app/model-context.d.ts.map +1 -0
- package/dist/app/model-context.js +101 -0
- package/dist/app/model-context.js.map +1 -0
- package/dist/app/use-build-mode-focus.d.ts +33 -0
- package/dist/app/use-build-mode-focus.d.ts.map +1 -0
- package/dist/app/use-build-mode-focus.js +59 -0
- package/dist/app/use-build-mode-focus.js.map +1 -0
- package/dist/app/use-view-actions.d.ts +31 -0
- package/dist/app/use-view-actions.d.ts.map +1 -0
- package/dist/app/use-view-actions.js +81 -0
- package/dist/app/use-view-actions.js.map +1 -0
- package/dist/app/use-view-lifecycle.d.ts +42 -0
- package/dist/app/use-view-lifecycle.d.ts.map +1 -0
- package/dist/app/use-view-lifecycle.js +81 -0
- package/dist/app/use-view-lifecycle.js.map +1 -0
- package/dist/app/view-lifecycle.d.ts +185 -0
- package/dist/app/view-lifecycle.d.ts.map +1 -0
- package/dist/app/view-lifecycle.js +207 -0
- package/dist/app/view-lifecycle.js.map +1 -0
- package/dist/app/widget-fixture.d.ts +10 -3
- package/dist/app/widget-fixture.d.ts.map +1 -1
- package/dist/app/widget-fixture.js +21 -8
- package/dist/app/widget-fixture.js.map +1 -1
- package/dist/app/widget-props-sheet.d.ts +6 -10
- package/dist/app/widget-props-sheet.d.ts.map +1 -1
- package/dist/app/widget-props-sheet.js +25 -20
- package/dist/app/widget-props-sheet.js.map +1 -1
- package/dist/app/widget-renderer.d.ts +41 -1
- package/dist/app/widget-renderer.d.ts.map +1 -1
- package/dist/app/widget-renderer.js +82 -31
- package/dist/app/widget-renderer.js.map +1 -1
- package/dist/components/DrillButton.d.ts +9 -6
- package/dist/components/DrillButton.d.ts.map +1 -1
- package/dist/components/DrillButton.js +9 -6
- package/dist/components/DrillButton.js.map +1 -1
- package/dist/components/EmptyState.d.ts +33 -0
- package/dist/components/EmptyState.d.ts.map +1 -0
- package/dist/components/EmptyState.js +19 -0
- package/dist/components/EmptyState.js.map +1 -0
- package/dist/components/ErrorState.d.ts +53 -0
- package/dist/components/ErrorState.d.ts.map +1 -0
- package/dist/components/ErrorState.js +77 -0
- package/dist/components/ErrorState.js.map +1 -0
- package/dist/components/FilterBar.d.ts +16 -5
- package/dist/components/FilterBar.d.ts.map +1 -1
- package/dist/components/FilterBar.js +13 -5
- package/dist/components/FilterBar.js.map +1 -1
- package/dist/components/GroupCard.d.ts.map +1 -1
- package/dist/components/GroupCard.js +2 -1
- package/dist/components/GroupCard.js.map +1 -1
- package/dist/components/KpiGrid.d.ts +70 -18
- package/dist/components/KpiGrid.d.ts.map +1 -1
- package/dist/components/KpiGrid.js +112 -23
- package/dist/components/KpiGrid.js.map +1 -1
- package/dist/components/ListFooter.d.ts +32 -4
- package/dist/components/ListFooter.d.ts.map +1 -1
- package/dist/components/ListFooter.js +35 -6
- package/dist/components/ListFooter.js.map +1 -1
- package/dist/components/PagedListFooter.d.ts +57 -0
- package/dist/components/PagedListFooter.d.ts.map +1 -0
- package/dist/components/PagedListFooter.js +27 -0
- package/dist/components/PagedListFooter.js.map +1 -0
- package/dist/components/Pills.d.ts +36 -12
- package/dist/components/Pills.d.ts.map +1 -1
- package/dist/components/Pills.js +29 -8
- package/dist/components/Pills.js.map +1 -1
- package/dist/components/SectionHeading.d.ts +3 -1
- package/dist/components/SectionHeading.d.ts.map +1 -1
- package/dist/components/SectionHeading.js +6 -2
- package/dist/components/SectionHeading.js.map +1 -1
- package/dist/components/Toast.d.ts +43 -0
- package/dist/components/Toast.d.ts.map +1 -0
- package/dist/components/Toast.js +106 -0
- package/dist/components/Toast.js.map +1 -0
- package/dist/components/WidgetHeader.d.ts +34 -10
- package/dist/components/WidgetHeader.d.ts.map +1 -1
- package/dist/components/WidgetHeader.js +11 -6
- package/dist/components/WidgetHeader.js.map +1 -1
- package/dist/hooks/index.d.ts +4 -4
- package/dist/hooks/index.d.ts.map +1 -1
- package/dist/hooks/index.js +1 -1
- package/dist/hooks/index.js.map +1 -1
- package/dist/hooks/tool-result-recovery-model.d.ts +155 -0
- package/dist/hooks/tool-result-recovery-model.d.ts.map +1 -0
- package/dist/hooks/tool-result-recovery-model.js +273 -0
- package/dist/hooks/tool-result-recovery-model.js.map +1 -0
- package/dist/hooks/use-tool-query.d.ts +56 -14
- package/dist/hooks/use-tool-query.d.ts.map +1 -1
- package/dist/hooks/use-tool-query.js +102 -25
- package/dist/hooks/use-tool-query.js.map +1 -1
- package/dist/hooks/use-tool-result-recovery.d.ts +61 -44
- package/dist/hooks/use-tool-result-recovery.d.ts.map +1 -1
- package/dist/hooks/use-tool-result-recovery.js +62 -110
- package/dist/hooks/use-tool-result-recovery.js.map +1 -1
- package/dist/hooks/use-view-data.d.ts +55 -7
- package/dist/hooks/use-view-data.d.ts.map +1 -1
- package/dist/hooks/use-view-data.js +81 -11
- package/dist/hooks/use-view-data.js.map +1 -1
- package/dist/hooks/use-view-tool-query.d.ts +12 -7
- package/dist/hooks/use-view-tool-query.d.ts.map +1 -1
- package/dist/hooks/use-view-tool-query.js +15 -14
- package/dist/hooks/use-view-tool-query.js.map +1 -1
- package/dist/index.d.ts +27 -13
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +29 -7
- package/dist/index.js.map +1 -1
- package/dist/lib/focus-return.d.ts +61 -0
- package/dist/lib/focus-return.d.ts.map +1 -0
- package/dist/lib/focus-return.js +46 -0
- package/dist/lib/focus-return.js.map +1 -0
- package/dist/lib/focus-ring.d.ts +18 -0
- package/dist/lib/focus-ring.d.ts.map +1 -0
- package/dist/lib/focus-ring.js +18 -0
- package/dist/lib/focus-ring.js.map +1 -0
- package/dist/lib/icon-stroke.d.ts +12 -0
- package/dist/lib/icon-stroke.d.ts.map +1 -0
- package/dist/lib/icon-stroke.js +12 -0
- package/dist/lib/icon-stroke.js.map +1 -0
- package/dist/lib/parse-tool-result.d.ts +23 -1
- package/dist/lib/parse-tool-result.d.ts.map +1 -1
- package/dist/lib/parse-tool-result.js +38 -2
- package/dist/lib/parse-tool-result.js.map +1 -1
- package/dist/lib/toast-model.d.ts +86 -0
- package/dist/lib/toast-model.d.ts.map +1 -0
- package/dist/lib/toast-model.js +102 -0
- package/dist/lib/toast-model.js.map +1 -0
- package/dist/lib/tone-utils.d.ts +95 -9
- package/dist/lib/tone-utils.d.ts.map +1 -1
- package/dist/lib/tone-utils.js +100 -9
- package/dist/lib/tone-utils.js.map +1 -1
- package/dist/lib/tool-query.d.ts +107 -0
- package/dist/lib/tool-query.d.ts.map +1 -0
- package/dist/lib/tool-query.js +182 -0
- package/dist/lib/tool-query.js.map +1 -0
- package/dist/lib/tool-result-observer.d.ts +108 -0
- package/dist/lib/tool-result-observer.d.ts.map +1 -0
- package/dist/lib/tool-result-observer.js +158 -0
- package/dist/lib/tool-result-observer.js.map +1 -0
- package/dist/lib/typography.d.ts +37 -0
- package/dist/lib/typography.d.ts.map +1 -0
- package/dist/lib/typography.js +41 -0
- package/dist/lib/typography.js.map +1 -0
- package/dist/lib/utils.d.ts.map +1 -1
- package/dist/lib/utils.js +11 -1
- package/dist/lib/utils.js.map +1 -1
- package/dist/locale/index.d.ts +3 -1
- package/dist/locale/index.d.ts.map +1 -1
- package/dist/locale/index.js +2 -1
- package/dist/locale/index.js.map +1 -1
- package/dist/locale/locale-provider.d.ts +42 -1
- package/dist/locale/locale-provider.d.ts.map +1 -1
- package/dist/locale/locale-provider.js +44 -3
- package/dist/locale/locale-provider.js.map +1 -1
- package/dist/locale/message-types.d.ts +336 -0
- package/dist/locale/message-types.d.ts.map +1 -0
- package/dist/locale/message-types.js +7 -0
- package/dist/locale/message-types.js.map +1 -0
- package/dist/locale/messages-de.d.ts +9 -0
- package/dist/locale/messages-de.d.ts.map +1 -0
- package/dist/locale/messages-de.js +185 -0
- package/dist/locale/messages-de.js.map +1 -0
- package/dist/locale/messages-en.d.ts +8 -0
- package/dist/locale/messages-en.d.ts.map +1 -0
- package/dist/locale/messages-en.js +184 -0
- package/dist/locale/messages-en.js.map +1 -0
- package/dist/locale/toolkit-messages.d.ts +57 -0
- package/dist/locale/toolkit-messages.d.ts.map +1 -0
- package/dist/locale/toolkit-messages.js +103 -0
- package/dist/locale/toolkit-messages.js.map +1 -0
- package/dist/primitives/alert.d.ts +1 -1
- package/dist/primitives/alert.d.ts.map +1 -1
- package/dist/primitives/alert.js +6 -2
- package/dist/primitives/alert.js.map +1 -1
- package/dist/primitives/badge.d.ts +1 -1
- package/dist/primitives/badge.d.ts.map +1 -1
- package/dist/primitives/badge.js +19 -6
- package/dist/primitives/badge.js.map +1 -1
- package/dist/primitives/button.d.ts +1 -1
- package/dist/primitives/button.d.ts.map +1 -1
- package/dist/primitives/button.js +12 -8
- package/dist/primitives/button.js.map +1 -1
- package/dist/primitives/card.js +4 -4
- package/dist/primitives/card.js.map +1 -1
- package/dist/primitives/dialog.d.ts +7 -3
- package/dist/primitives/dialog.d.ts.map +1 -1
- package/dist/primitives/dialog.js +22 -8
- package/dist/primitives/dialog.js.map +1 -1
- package/dist/primitives/input.d.ts.map +1 -1
- package/dist/primitives/input.js +4 -1
- package/dist/primitives/input.js.map +1 -1
- package/dist/primitives/scroll-area.js +1 -1
- package/dist/primitives/scroll-area.js.map +1 -1
- package/dist/primitives/select.d.ts.map +1 -1
- package/dist/primitives/select.js +6 -3
- package/dist/primitives/select.js.map +1 -1
- package/dist/primitives/sheet.d.ts +3 -1
- package/dist/primitives/sheet.d.ts.map +1 -1
- package/dist/primitives/sheet.js +17 -7
- package/dist/primitives/sheet.js.map +1 -1
- package/dist/primitives/skeleton.js +1 -1
- package/dist/primitives/skeleton.js.map +1 -1
- package/dist/primitives/switch.d.ts.map +1 -1
- package/dist/primitives/switch.js +2 -1
- package/dist/primitives/switch.js.map +1 -1
- package/dist/primitives/tabs.d.ts.map +1 -1
- package/dist/primitives/tabs.js +5 -3
- package/dist/primitives/tabs.js.map +1 -1
- package/dist/providers/query-provider.d.ts +32 -1
- package/dist/providers/query-provider.d.ts.map +1 -1
- package/dist/providers/query-provider.js +53 -4
- package/dist/providers/query-provider.js.map +1 -1
- package/dist/render-cases-primitives.js +1 -1
- package/dist/render-cases-primitives.js.map +1 -1
- package/dist/render-cases.d.ts.map +1 -1
- package/dist/render-cases.js +48 -6
- package/dist/render-cases.js.map +1 -1
- package/dist/render-effects.d.ts +42 -0
- package/dist/render-effects.d.ts.map +1 -0
- package/dist/render-effects.js +81 -0
- package/dist/render-effects.js.map +1 -0
- package/dist/render-scan.d.ts +25 -0
- package/dist/render-scan.d.ts.map +1 -0
- package/dist/render-scan.js +66 -0
- package/dist/render-scan.js.map +1 -0
- package/dist/theme/cd-tokens.d.ts +66 -0
- package/dist/theme/cd-tokens.d.ts.map +1 -0
- package/dist/theme/cd-tokens.js +64 -0
- package/dist/theme/cd-tokens.js.map +1 -0
- package/dist/theme/create-theme.d.ts +214 -39
- package/dist/theme/create-theme.d.ts.map +1 -1
- package/dist/theme/create-theme.js +204 -13
- package/dist/theme/create-theme.js.map +1 -1
- package/dist/theme/fonts.d.ts +38 -0
- package/dist/theme/fonts.d.ts.map +1 -0
- package/dist/theme/fonts.js +56 -0
- package/dist/theme/fonts.js.map +1 -0
- package/dist/theme/host-fonts.d.ts +39 -0
- package/dist/theme/host-fonts.d.ts.map +1 -0
- package/dist/theme/host-fonts.js +44 -0
- package/dist/theme/host-fonts.js.map +1 -0
- package/dist/theme/index.d.ts +8 -1
- package/dist/theme/index.d.ts.map +1 -1
- package/dist/theme/index.js +5 -1
- package/dist/theme/index.js.map +1 -1
- package/dist/theme/portal-container.d.ts +16 -0
- package/dist/theme/portal-container.d.ts.map +1 -0
- package/dist/theme/portal-container.js +19 -0
- package/dist/theme/portal-container.js.map +1 -0
- package/dist/theme/presets.d.ts +24 -9
- package/dist/theme/presets.d.ts.map +1 -1
- package/dist/theme/presets.js +44 -11
- package/dist/theme/presets.js.map +1 -1
- package/dist/theme/theme-provider.d.ts +27 -9
- package/dist/theme/theme-provider.d.ts.map +1 -1
- package/dist/theme/theme-provider.js +42 -20
- package/dist/theme/theme-provider.js.map +1 -1
- package/package.json +11 -5
- package/src/app/adapt-data-widget.tsx +2 -42
- package/src/app/builder/BuilderBanners.tsx +26 -13
- package/src/app/builder/CanvasRow.tsx +79 -32
- package/src/app/builder/CatalogueSheet.tsx +58 -35
- package/src/app/builder/CellPropsSheet.tsx +17 -2
- package/src/app/builder/DiscardDialog.tsx +59 -0
- package/src/app/builder/EmptyHint.tsx +16 -11
- package/src/app/builder/LayoutSurface.tsx +207 -67
- package/src/app/builder/PipelineStrip.tsx +265 -156
- package/src/app/builder/SaveDialog.tsx +25 -14
- package/src/app/builder/Toolbar.tsx +154 -57
- package/src/app/builder/Workspace.tsx +226 -56
- package/src/app/builder/builder-feedback.test.tsx +75 -0
- package/src/app/builder/builder-model.test.ts +5 -0
- package/src/app/builder/builder-model.ts +346 -6
- package/src/app/builder/builder-model.ux.test.ts +456 -0
- package/src/app/builder/builder-ux.test.tsx +844 -0
- package/src/app/builder/labels.ts +15 -121
- package/src/app/builder/reveal.ts +10 -0
- package/src/app/builder/status-chip.tsx +8 -4
- package/src/app/builder/use-builder-catalogue.ts +62 -19
- package/src/app/builder/use-builder-session.ts +68 -0
- package/src/app/builder/use-display-resolver.ts +24 -0
- package/src/app/builder/use-save-dashboard.ts +5 -0
- package/src/app/index.ts +20 -3
- package/src/app/layout-builder.tsx +193 -186
- package/src/app/mcp-app-view-chrome.test.tsx +487 -14
- package/src/app/mcp-app-view-chrome.tsx +328 -100
- package/src/app/mcp-app-view-states.tsx +140 -0
- package/src/app/mcp-app-view.effects.test.tsx +292 -0
- package/src/app/mcp-app-view.test.tsx +478 -0
- package/src/app/mcp-app-view.tsx +447 -190
- package/src/app/mcp-toolkit-app.test.tsx +40 -0
- package/src/app/mcp-toolkit-app.tsx +39 -8
- package/src/app/mcp-use-host-bridge.test.tsx +180 -0
- package/src/app/mcp-use-host-bridge.tsx +67 -24
- package/src/app/model-context.test.tsx +116 -0
- package/src/app/model-context.tsx +125 -0
- package/src/app/use-build-mode-focus.ts +62 -0
- package/src/app/use-view-actions.ts +89 -0
- package/src/app/use-view-lifecycle.ts +122 -0
- package/src/app/view-lifecycle.test.ts +443 -0
- package/src/app/view-lifecycle.ts +334 -0
- package/src/app/widget-fixture.effects.test.tsx +51 -0
- package/src/app/widget-fixture.render.test.tsx +81 -0
- package/src/app/widget-fixture.tsx +34 -11
- package/src/app/widget-props-sheet.tsx +67 -39
- package/src/app/widget-renderer.render.test.tsx +131 -0
- package/src/app/widget-renderer.tsx +136 -38
- package/src/components/DrillButton.tsx +24 -10
- package/src/components/EmptyState.tsx +83 -0
- package/src/components/ErrorState.tsx +204 -0
- package/src/components/FilterBar.test.tsx +82 -0
- package/src/components/FilterBar.tsx +56 -27
- package/src/components/GroupCard.tsx +3 -2
- package/src/components/KpiGrid.test.tsx +279 -0
- package/src/components/KpiGrid.tsx +329 -91
- package/src/components/ListFooter.test.tsx +116 -0
- package/src/components/ListFooter.tsx +110 -12
- package/src/components/PagedListFooter.test.tsx +140 -0
- package/src/components/PagedListFooter.tsx +107 -0
- package/src/components/Pills.test.tsx +77 -0
- package/src/components/Pills.tsx +78 -16
- package/src/components/SectionHeading.tsx +9 -3
- package/src/components/Toast.tsx +206 -0
- package/src/components/WidgetHeader.test.tsx +78 -0
- package/src/components/WidgetHeader.tsx +63 -16
- package/src/components/feedback-states.test.tsx +314 -0
- package/src/components/tone-figures.test.tsx +58 -0
- package/src/fonts.css +19 -0
- package/src/globals.css +9 -165
- package/src/hooks/index.ts +6 -3
- package/src/hooks/tool-result-recovery-model.test.ts +744 -0
- package/src/hooks/tool-result-recovery-model.ts +418 -0
- package/src/hooks/use-tool-query.effects.test.tsx +205 -0
- package/src/hooks/use-tool-query.ts +156 -33
- package/src/hooks/use-tool-result-recovery.effects.test.tsx +141 -0
- package/src/hooks/use-tool-result-recovery.test.ts +28 -5
- package/src/hooks/use-tool-result-recovery.ts +101 -131
- package/src/hooks/use-view-data.test.tsx +169 -0
- package/src/hooks/use-view-data.ts +131 -10
- package/src/hooks/use-view-tool-query.ts +25 -19
- package/src/i18n-coverage.test.tsx +425 -0
- package/src/index.ts +102 -13
- package/src/lib/focus-return.test.ts +288 -0
- package/src/lib/focus-return.ts +96 -0
- package/src/lib/focus-ring.ts +20 -0
- package/src/lib/icon-stroke.test.ts +59 -0
- package/src/lib/icon-stroke.ts +13 -0
- package/src/lib/parse-tool-result.test.ts +46 -1
- package/src/lib/parse-tool-result.ts +40 -2
- package/src/lib/toast-model.test.ts +233 -0
- package/src/lib/toast-model.ts +165 -0
- package/src/lib/tone-utils.test.ts +125 -16
- package/src/lib/tone-utils.ts +144 -15
- package/src/lib/tool-query.test.ts +569 -0
- package/src/lib/tool-query.ts +253 -0
- package/src/lib/tool-result-observer.test.ts +296 -0
- package/src/lib/tool-result-observer.ts +211 -0
- package/src/lib/typography.test.ts +45 -0
- package/src/lib/typography.ts +47 -0
- package/src/lib/utils.ts +12 -1
- package/src/locale/index.ts +14 -1
- package/src/locale/locale-provider.test.tsx +87 -0
- package/src/locale/locale-provider.tsx +90 -3
- package/src/locale/message-types.ts +337 -0
- package/src/locale/messages-de.ts +198 -0
- package/src/locale/messages-en.ts +196 -0
- package/src/locale/toolkit-messages.test.ts +349 -0
- package/src/locale/toolkit-messages.ts +143 -0
- package/src/no-hardcoded-copy.test.ts +432 -0
- package/src/primitives/alert.tsx +7 -2
- package/src/primitives/badge.tsx +19 -7
- package/src/primitives/button.tsx +13 -8
- package/src/primitives/card.tsx +4 -4
- package/src/primitives/dialog.tsx +42 -8
- package/src/primitives/input.tsx +5 -3
- package/src/primitives/scroll-area.tsx +1 -1
- package/src/primitives/select.tsx +7 -4
- package/src/primitives/sheet.tsx +33 -6
- package/src/primitives/skeleton.tsx +1 -1
- package/src/primitives/switch.tsx +4 -2
- package/src/primitives/tabs.tsx +9 -6
- package/src/providers/query-provider.test.tsx +154 -0
- package/src/providers/query-provider.tsx +66 -5
- package/src/render-cases-primitives.tsx +1 -1
- package/src/render-cases.tsx +82 -6
- package/src/render-effects.tsx +96 -0
- package/src/render-scan.ts +75 -0
- package/src/theme/cd-tokens.generated.css +48 -0
- package/src/theme/cd-tokens.test.ts +109 -0
- package/src/theme/cd-tokens.ts +67 -0
- package/src/theme/create-theme.test.ts +253 -5
- package/src/theme/create-theme.ts +341 -41
- package/src/theme/fonts.test.ts +85 -0
- package/src/theme/fonts.ts +72 -0
- package/src/theme/host-fonts.test.ts +135 -0
- package/src/theme/host-fonts.ts +52 -0
- package/src/theme/index.ts +15 -1
- package/src/theme/portal-container.ts +20 -0
- package/src/theme/presets.ts +44 -11
- package/src/theme/theme-css.test.ts +619 -0
- package/src/theme/theme-provider.test.tsx +82 -0
- package/src/theme/theme-provider.tsx +60 -24
- package/src/theme.css +344 -0
- package/ui-catalog.json +783 -49
|
@@ -0,0 +1,206 @@
|
|
|
1
|
+
import {
|
|
2
|
+
createContext,
|
|
3
|
+
useCallback,
|
|
4
|
+
useContext,
|
|
5
|
+
useEffect,
|
|
6
|
+
useMemo,
|
|
7
|
+
useReducer,
|
|
8
|
+
useRef,
|
|
9
|
+
type FocusEvent,
|
|
10
|
+
type ReactNode,
|
|
11
|
+
} from "react"
|
|
12
|
+
import { CircleAlert, CircleCheck, Info, TriangleAlert, X, type LucideIcon } from "lucide-react"
|
|
13
|
+
import { useToolkitMessages } from "../locale/locale-provider.js"
|
|
14
|
+
import { FOCUS_RING } from "../lib/focus-ring.js"
|
|
15
|
+
import { TONE_ICON } from "../lib/tone-utils.js"
|
|
16
|
+
import { cn } from "../lib/utils.js"
|
|
17
|
+
import {
|
|
18
|
+
createToast,
|
|
19
|
+
createToastTimer,
|
|
20
|
+
toastReducer,
|
|
21
|
+
type ToastItem,
|
|
22
|
+
type ToastOptions,
|
|
23
|
+
type ToastTimer,
|
|
24
|
+
type ToastTone,
|
|
25
|
+
} from "../lib/toast-model.js"
|
|
26
|
+
|
|
27
|
+
export type { ToastOptions, ToastTone } from "../lib/toast-model.js"
|
|
28
|
+
|
|
29
|
+
/** What {@link useToast} returns. */
|
|
30
|
+
export interface ToastApi {
|
|
31
|
+
/** Show a toast; returns its id (for an early {@link ToastApi.dismiss}). */
|
|
32
|
+
show: (options: ToastOptions) => number
|
|
33
|
+
/** Remove a toast before its timer runs out. */
|
|
34
|
+
dismiss: (id: number) => void
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
const ToastContext = createContext<ToastApi | null>(null)
|
|
38
|
+
|
|
39
|
+
/** Outside a provider `useToast()` degrades to a no-op instead of throwing. */
|
|
40
|
+
const NOOP_TOASTS: ToastApi = { show: () => -1, dismiss: () => {} }
|
|
41
|
+
|
|
42
|
+
/**
|
|
43
|
+
* Raise toasts from anywhere below a {@link ToastProvider}: `show({ tone,
|
|
44
|
+
* title })` after a write succeeded or failed, never a silent `console` line.
|
|
45
|
+
* Outside a provider it returns a no-op API, so a widget rendered in a bare
|
|
46
|
+
* fixture never crashes on feedback.
|
|
47
|
+
*/
|
|
48
|
+
export function useToast(): ToastApi {
|
|
49
|
+
return useContext(ToastContext) ?? NOOP_TOASTS
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
/**
|
|
53
|
+
* Status edge per tone — the status colour as border, never as text. Repeated
|
|
54
|
+
* under `dark:` so the card's dark 3:1 rim (`dark:border-input`, a later rule)
|
|
55
|
+
* does not paint over it.
|
|
56
|
+
*/
|
|
57
|
+
const TONE_EDGE: Record<ToastTone, string> = {
|
|
58
|
+
success: "border-l-success dark:border-l-success",
|
|
59
|
+
warning: "border-l-warning dark:border-l-warning",
|
|
60
|
+
danger: "border-l-danger dark:border-l-danger",
|
|
61
|
+
info: "border-l-info dark:border-l-info",
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
/**
|
|
65
|
+
* Lucide icon per tone, drawn in the tone colour (`TONE_ICON`, CI §3.3: status
|
|
66
|
+
* as edge and icon). The title next to it carries the message, so success and
|
|
67
|
+
* warning stay CI-exempt from 3:1 on light like every other status icon.
|
|
68
|
+
*/
|
|
69
|
+
const TOAST_ICON: Record<ToastTone, LucideIcon> = {
|
|
70
|
+
success: CircleCheck,
|
|
71
|
+
warning: TriangleAlert,
|
|
72
|
+
danger: CircleAlert,
|
|
73
|
+
info: Info,
|
|
74
|
+
}
|
|
75
|
+
|
|
76
|
+
/**
|
|
77
|
+
* The stack of toasts — a presentational view over a list (the provider owns
|
|
78
|
+
* the state). The container is ONE persistent live region
|
|
79
|
+
* (`aria-live="polite"`, mounted before the first toast so that toast is
|
|
80
|
+
* announced, each new toast on its own: `aria-atomic="false"`), without
|
|
81
|
+
* stealing focus. Its attributes never change: a role or name that switched
|
|
82
|
+
* on with the first toast would make the browser rebuild the region in the
|
|
83
|
+
* same commit that inserts the toast, and a region created with its content
|
|
84
|
+
* already in it is not announced. So it carries no role (a generic element
|
|
85
|
+
* takes no name either): an idle stack is no second "status" next to a view's
|
|
86
|
+
* own loading status. Bottom centre, above dialogs (z 60), per CI §5/§8.
|
|
87
|
+
*/
|
|
88
|
+
export function ToastViewport({
|
|
89
|
+
toasts,
|
|
90
|
+
onDismiss,
|
|
91
|
+
}: {
|
|
92
|
+
toasts: readonly ToastItem[]
|
|
93
|
+
onDismiss: (id: number) => void
|
|
94
|
+
}) {
|
|
95
|
+
const messages = useToolkitMessages()
|
|
96
|
+
return (
|
|
97
|
+
<div
|
|
98
|
+
data-slot="toast-viewport"
|
|
99
|
+
aria-live="polite"
|
|
100
|
+
aria-atomic="false"
|
|
101
|
+
className="pointer-events-none fixed inset-x-0 bottom-4 z-60 flex flex-col items-center gap-2 px-4"
|
|
102
|
+
>
|
|
103
|
+
{toasts.map((toast) => (
|
|
104
|
+
<ToastCard
|
|
105
|
+
key={toast.id}
|
|
106
|
+
toast={toast}
|
|
107
|
+
dismissLabel={messages.common.dismiss}
|
|
108
|
+
onDismiss={onDismiss}
|
|
109
|
+
/>
|
|
110
|
+
))}
|
|
111
|
+
</div>
|
|
112
|
+
)
|
|
113
|
+
}
|
|
114
|
+
|
|
115
|
+
function ToastCard({
|
|
116
|
+
toast,
|
|
117
|
+
dismissLabel,
|
|
118
|
+
onDismiss,
|
|
119
|
+
}: {
|
|
120
|
+
toast: ToastItem
|
|
121
|
+
dismissLabel: string
|
|
122
|
+
onDismiss: (id: number) => void
|
|
123
|
+
}) {
|
|
124
|
+
// Hover or keyboard focus holds the toast; on leave it resumes with the
|
|
125
|
+
// time that was LEFT (createToastTimer), never a fresh full duration.
|
|
126
|
+
const timer = useRef<ToastTimer | null>(null)
|
|
127
|
+
useEffect(() => {
|
|
128
|
+
const countdown = createToastTimer(toast.duration, () => onDismiss(toast.id))
|
|
129
|
+
timer.current = countdown
|
|
130
|
+
return () => {
|
|
131
|
+
countdown.cancel()
|
|
132
|
+
timer.current = null
|
|
133
|
+
}
|
|
134
|
+
}, [onDismiss, toast.id, toast.duration])
|
|
135
|
+
const releaseFocus = (event: FocusEvent<HTMLDivElement>) => {
|
|
136
|
+
// Focus moving inside the toast (card → close button) keeps the hold.
|
|
137
|
+
if (!event.currentTarget.contains(event.relatedTarget)) {
|
|
138
|
+
timer.current?.release("focus")
|
|
139
|
+
}
|
|
140
|
+
}
|
|
141
|
+
const Icon = TOAST_ICON[toast.tone]
|
|
142
|
+
return (
|
|
143
|
+
<div
|
|
144
|
+
data-slot="toast"
|
|
145
|
+
data-tone={toast.tone}
|
|
146
|
+
onMouseEnter={() => timer.current?.hold("pointer")}
|
|
147
|
+
onMouseLeave={() => timer.current?.release("pointer")}
|
|
148
|
+
onFocus={() => timer.current?.hold("focus")}
|
|
149
|
+
onBlur={releaseFocus}
|
|
150
|
+
className={cn(
|
|
151
|
+
// An overlay like Dialog/Sheet: shadow-2 on light, the 3:1 input rim on
|
|
152
|
+
// dark (shadows vanish on the ground). Its words are running text (16 px).
|
|
153
|
+
"bg-popover text-popover-foreground dark:border-input shadow-2 text-body pointer-events-auto flex w-full max-w-sm items-start gap-3 rounded-md border border-l-4 px-4 py-3",
|
|
154
|
+
"motion-safe:animate-in motion-safe:fade-in-0 motion-safe:slide-in-from-bottom-2 motion-safe:duration-(--motion-base) motion-safe:ease-(--ease)",
|
|
155
|
+
TONE_EDGE[toast.tone],
|
|
156
|
+
)}
|
|
157
|
+
>
|
|
158
|
+
{/* mt-1 centres the 16 px icon on the first 16/1.6 line. */}
|
|
159
|
+
<Icon aria-hidden="true" className={cn("mt-1 size-4 shrink-0", TONE_ICON[toast.tone])} />
|
|
160
|
+
<div className="min-w-0 flex-1">
|
|
161
|
+
<p className="font-medium break-words">{toast.title}</p>
|
|
162
|
+
{toast.description && (
|
|
163
|
+
<p className="text-muted-foreground mt-0.5 break-words">{toast.description}</p>
|
|
164
|
+
)}
|
|
165
|
+
</div>
|
|
166
|
+
<button
|
|
167
|
+
type="button"
|
|
168
|
+
aria-label={dismissLabel}
|
|
169
|
+
onClick={() => onDismiss(toast.id)}
|
|
170
|
+
className={`text-muted-foreground hover:text-foreground -mr-1 inline-flex size-6 shrink-0 items-center justify-center rounded-sm ${FOCUS_RING}`}
|
|
171
|
+
>
|
|
172
|
+
<X aria-hidden="true" className="size-4" />
|
|
173
|
+
</button>
|
|
174
|
+
</div>
|
|
175
|
+
)
|
|
176
|
+
}
|
|
177
|
+
|
|
178
|
+
function ToastRoot({ children }: { children: ReactNode }) {
|
|
179
|
+
const [toasts, dispatch] = useReducer(toastReducer, [])
|
|
180
|
+
const nextId = useRef(0)
|
|
181
|
+
const dismiss = useCallback((id: number) => dispatch({ type: "dismiss", id }), [])
|
|
182
|
+
const show = useCallback((options: ToastOptions) => {
|
|
183
|
+
nextId.current += 1
|
|
184
|
+
const id = nextId.current
|
|
185
|
+
dispatch({ type: "add", toast: createToast(id, options) })
|
|
186
|
+
return id
|
|
187
|
+
}, [])
|
|
188
|
+
const api = useMemo<ToastApi>(() => ({ show, dismiss }), [show, dismiss])
|
|
189
|
+
return (
|
|
190
|
+
<ToastContext.Provider value={api}>
|
|
191
|
+
{children}
|
|
192
|
+
<ToastViewport toasts={toasts} onDismiss={dismiss} />
|
|
193
|
+
</ToastContext.Provider>
|
|
194
|
+
)
|
|
195
|
+
}
|
|
196
|
+
|
|
197
|
+
/**
|
|
198
|
+
* Provide toasts to a subtree and render their stack. Idempotent: nested
|
|
199
|
+
* inside another `ToastProvider` it adds nothing, so the app shell and an
|
|
200
|
+
* embedded builder share one stack and one live region. `McpAppView` mounts
|
|
201
|
+
* one for you.
|
|
202
|
+
*/
|
|
203
|
+
export function ToastProvider({ children }: { children: ReactNode }) {
|
|
204
|
+
const parent = useContext(ToastContext)
|
|
205
|
+
return parent ? children : <ToastRoot>{children}</ToastRoot>
|
|
206
|
+
}
|
|
@@ -0,0 +1,78 @@
|
|
|
1
|
+
import { renderToStaticMarkup } from "react-dom/server"
|
|
2
|
+
import { describe, expect, it } from "vitest"
|
|
3
|
+
import { MICRO_LABEL } from "../lib/typography.js"
|
|
4
|
+
import { attribute, openingTags } from "../render-scan.js"
|
|
5
|
+
import { StatusBadge } from "./Pills.js"
|
|
6
|
+
import { SectionHeading } from "./SectionHeading.js"
|
|
7
|
+
import { WidgetHeader, type WidgetHeadingLevel } from "./WidgetHeader.js"
|
|
8
|
+
|
|
9
|
+
const classOf = (tag: string | undefined) => attribute(tag ?? "", "class") ?? ""
|
|
10
|
+
|
|
11
|
+
describe("WidgetHeader: one title at the level of its surface", () => {
|
|
12
|
+
it("is an h1 at the page-title size by default", () => {
|
|
13
|
+
const html = renderToStaticMarkup(<WidgetHeader title="Incidents" />)
|
|
14
|
+
expect(html).toMatch(/<h1 class="[^"]*text-title[^"]*">Incidents<\/h1>/)
|
|
15
|
+
expect(html).not.toMatch(/text-3xl|text-xs/)
|
|
16
|
+
})
|
|
17
|
+
|
|
18
|
+
it.each(["h2", "h3", "h4", "h5", "h6"] satisfies WidgetHeadingLevel[])(
|
|
19
|
+
"takes the heading level %s from `as`, keeping the size",
|
|
20
|
+
(level) => {
|
|
21
|
+
const html = renderToStaticMarkup(<WidgetHeader as={level} title="Incidents" />)
|
|
22
|
+
expect(html).toMatch(
|
|
23
|
+
new RegExp(`<${level} class="[^"]*text-title[^"]*">Incidents</${level}>`),
|
|
24
|
+
)
|
|
25
|
+
expect(html).not.toContain("<h1")
|
|
26
|
+
},
|
|
27
|
+
)
|
|
28
|
+
|
|
29
|
+
it("renders the compact detail size at the section step", () => {
|
|
30
|
+
const html = renderToStaticMarkup(<WidgetHeader as="h2" size="detail" title="Instance" />)
|
|
31
|
+
expect(classOf(openingTags(html, "h2")[0])).toContain("text-section")
|
|
32
|
+
expect(classOf(openingTags(html, "h2")[0])).not.toContain("text-title")
|
|
33
|
+
})
|
|
34
|
+
|
|
35
|
+
it("puts a state badge above the title and a suffix inside the heading", () => {
|
|
36
|
+
const html = renderToStaticMarkup(
|
|
37
|
+
<WidgetHeader
|
|
38
|
+
title="Invoice"
|
|
39
|
+
titleSuffix={<span>v3</span>}
|
|
40
|
+
badge={<StatusBadge tone="warning">Suspended</StatusBadge>}
|
|
41
|
+
sub="Updated 14:32"
|
|
42
|
+
actions={<button type="button">Refresh</button>}
|
|
43
|
+
/>,
|
|
44
|
+
)
|
|
45
|
+
expect(html.indexOf("Suspended")).toBeLessThan(html.indexOf("<h1"))
|
|
46
|
+
expect(html).toMatch(/<h1[^>]*>Invoice<span>v3<\/span><\/h1>/)
|
|
47
|
+
expect(html).toContain("Updated 14:32")
|
|
48
|
+
expect(html).toContain("Refresh</button>")
|
|
49
|
+
expect(html).not.toContain("size-11")
|
|
50
|
+
// The meta row is a caption at the 13 px step, not running text in the
|
|
51
|
+
// dense-table size.
|
|
52
|
+
const meta = openingTags(html, "div").find((t) => /flex-wrap items-center gap-2/.test(t))
|
|
53
|
+
expect(classOf(meta)).toMatch(/(^| )text-small( |$)/)
|
|
54
|
+
expect(html).not.toMatch(/\btext-dense\b/)
|
|
55
|
+
})
|
|
56
|
+
|
|
57
|
+
it("still renders the deprecated icon tile, hidden from assistive tech", () => {
|
|
58
|
+
const html = renderToStaticMarkup(<WidgetHeader icon={<svg />} iconTone="info" title="Tasks" />)
|
|
59
|
+
const tile = openingTags(html, "div").find((t) => /size-11/.test(t))
|
|
60
|
+
expect(attribute(tile ?? "", "aria-hidden")).toBe("true")
|
|
61
|
+
expect(classOf(tile)).toContain("bg-info-soft")
|
|
62
|
+
})
|
|
63
|
+
|
|
64
|
+
it("merges a className onto the header", () => {
|
|
65
|
+
const html = renderToStaticMarkup(<WidgetHeader title="x" className="mb-6" />)
|
|
66
|
+
expect(classOf(openingTags(html, "header")[0])).toContain("mb-6")
|
|
67
|
+
})
|
|
68
|
+
})
|
|
69
|
+
|
|
70
|
+
describe("SectionHeading: a block label inside a widget body", () => {
|
|
71
|
+
it("is a 13 px caption (MICRO_LABEL), never in the dense-table size", () => {
|
|
72
|
+
const html = renderToStaticMarkup(<SectionHeading title="Recent" hint="3 new" />)
|
|
73
|
+
const row = classOf(openingTags(html, "div")[0])
|
|
74
|
+
expect(row).toContain(MICRO_LABEL)
|
|
75
|
+
expect(row).toContain("text-muted-foreground")
|
|
76
|
+
expect(html).not.toMatch(/\btext-dense\b/)
|
|
77
|
+
})
|
|
78
|
+
})
|
|
@@ -1,46 +1,93 @@
|
|
|
1
1
|
import type { ReactNode } from "react"
|
|
2
|
-
import { TONE_SOFT, type
|
|
2
|
+
import { resolveTone, TONE_SOFT, type ToneName } from "../lib/tone-utils.js"
|
|
3
|
+
import { cn } from "../lib/utils.js"
|
|
4
|
+
|
|
5
|
+
/** Heading element of a {@link WidgetHeader} title. */
|
|
6
|
+
export type WidgetHeadingLevel = "h1" | "h2" | "h3" | "h4" | "h5" | "h6"
|
|
3
7
|
|
|
4
8
|
export interface WidgetHeaderProps {
|
|
5
|
-
/** Optional icon/glyph rendered in a tinted tile above the title. */
|
|
6
|
-
icon?: ReactNode
|
|
7
|
-
/** Tone for the icon tile. Default `"neutral"`. */
|
|
8
|
-
iconTone?: ToneVariant
|
|
9
9
|
/** The widget title. */
|
|
10
10
|
title: ReactNode
|
|
11
|
-
/**
|
|
11
|
+
/**
|
|
12
|
+
* Heading element of the title. Default `"h1"`: the widget is the page.
|
|
13
|
+
* Pick the level that keeps ONE outline per view — below a toolbar title
|
|
14
|
+
* (`McpAppView` `titleMode="show"`, an h2 by default) use `"h3"`, inside a
|
|
15
|
+
* composed view under its own heading one level below it. The size follows
|
|
16
|
+
* `size`, not the level.
|
|
17
|
+
*/
|
|
18
|
+
as?: WidgetHeadingLevel
|
|
19
|
+
/**
|
|
20
|
+
* `"default"`: the page title (28 px / 700, the CI h2 style). `"detail"`:
|
|
21
|
+
* the compact detail-page title (21 px / 600, the CI h3 style).
|
|
22
|
+
*/
|
|
23
|
+
size?: "default" | "detail"
|
|
24
|
+
/** Inline after the title inside the heading (e.g. a version chip). */
|
|
25
|
+
titleSuffix?: ReactNode
|
|
26
|
+
/** Above the title — a `StatusBadge` that says the state in words. */
|
|
27
|
+
badge?: ReactNode
|
|
28
|
+
/** Subtitle/meta row under the title (e.g. a live pill + counts), a 13 px caption row. */
|
|
12
29
|
sub?: ReactNode
|
|
13
30
|
/** Right-aligned actions slot (buttons, drill controls). */
|
|
14
31
|
actions?: ReactNode
|
|
32
|
+
/**
|
|
33
|
+
* @deprecated A glyph in a tinted tile above every title is the icon-tile
|
|
34
|
+
* pattern the CI rules out (anti-slop U2). Say a state in words with a
|
|
35
|
+
* `StatusBadge` in {@link WidgetHeaderProps.badge}. Still rendered when set.
|
|
36
|
+
*/
|
|
37
|
+
icon?: ReactNode
|
|
38
|
+
/** @deprecated Tone of the deprecated {@link WidgetHeaderProps.icon} tile. */
|
|
39
|
+
iconTone?: ToneName
|
|
40
|
+
className?: string
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
const TITLE_SIZE: Record<NonNullable<WidgetHeaderProps["size"]>, string> = {
|
|
44
|
+
default: "text-title",
|
|
45
|
+
detail: "text-section",
|
|
15
46
|
}
|
|
16
47
|
|
|
17
48
|
/**
|
|
18
|
-
* Page-level header
|
|
19
|
-
*
|
|
20
|
-
* Use once per widget surface to anchor it.
|
|
49
|
+
* Page-level header at the top of a widget: an optional state badge, the
|
|
50
|
+
* title (heading level per `as`, size per `size`), a subtitle/meta row and a
|
|
51
|
+
* right-aligned actions slot. Use once per widget surface to anchor it.
|
|
21
52
|
*/
|
|
22
53
|
export function WidgetHeader({
|
|
23
|
-
icon,
|
|
24
|
-
iconTone = "neutral",
|
|
25
54
|
title,
|
|
55
|
+
as: Heading = "h1",
|
|
56
|
+
size = "default",
|
|
57
|
+
titleSuffix,
|
|
58
|
+
badge,
|
|
26
59
|
sub,
|
|
27
60
|
actions,
|
|
61
|
+
icon,
|
|
62
|
+
iconTone = "neutral",
|
|
63
|
+
className,
|
|
28
64
|
}: WidgetHeaderProps) {
|
|
29
65
|
return (
|
|
30
|
-
<header
|
|
66
|
+
<header
|
|
67
|
+
data-slot="widget-header"
|
|
68
|
+
className={cn("flex flex-wrap items-start justify-between gap-4", className)}
|
|
69
|
+
>
|
|
31
70
|
<div className="min-w-0">
|
|
32
71
|
{icon && (
|
|
33
72
|
<div
|
|
34
|
-
|
|
73
|
+
aria-hidden="true"
|
|
74
|
+
className={cn(
|
|
75
|
+
"text-section mb-3.5 grid size-11 place-items-center rounded-md",
|
|
76
|
+
TONE_SOFT[resolveTone(iconTone)],
|
|
77
|
+
)}
|
|
35
78
|
>
|
|
36
79
|
{icon}
|
|
37
80
|
</div>
|
|
38
81
|
)}
|
|
39
|
-
<
|
|
82
|
+
{badge && <div className="mb-3">{badge}</div>}
|
|
83
|
+
<Heading
|
|
84
|
+
className={cn("text-foreground mb-1.5 tracking-tight break-words", TITLE_SIZE[size])}
|
|
85
|
+
>
|
|
40
86
|
{title}
|
|
41
|
-
|
|
87
|
+
{titleSuffix}
|
|
88
|
+
</Heading>
|
|
42
89
|
{sub && (
|
|
43
|
-
<div className="text-muted-foreground flex flex-wrap items-center gap-2
|
|
90
|
+
<div className="text-muted-foreground text-small flex flex-wrap items-center gap-2">
|
|
44
91
|
{sub}
|
|
45
92
|
</div>
|
|
46
93
|
)}
|