@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
|
@@ -1,15 +1,95 @@
|
|
|
1
1
|
import { memo } from "react"
|
|
2
|
-
import { Check,
|
|
2
|
+
import { Check, Library, LucideProvider, Save, Undo2, Wrench } from "lucide-react"
|
|
3
|
+
import { DENSE_ICON_STROKE } from "../../lib/icon-stroke.js"
|
|
4
|
+
import { FOCUS_RING } from "../../lib/focus-ring.js"
|
|
3
5
|
import { Badge } from "../../primitives/badge.js"
|
|
4
6
|
import { Button } from "../../primitives/button.js"
|
|
7
|
+
import { TONE_DOT } from "../../lib/tone-utils.js"
|
|
5
8
|
import { cn } from "../../lib/utils.js"
|
|
6
9
|
import type { LayoutBuilderLabels, RefreshStatus } from "./labels.js"
|
|
7
10
|
import { StatusChip } from "./status-chip.js"
|
|
8
11
|
|
|
9
12
|
// -------------------------------------------------------------------------- //
|
|
10
|
-
// Toolbar — sticky top
|
|
13
|
+
// Toolbar — sticky top: title + unsaved marker, then the actions
|
|
11
14
|
// -------------------------------------------------------------------------- //
|
|
12
15
|
|
|
16
|
+
export interface ToolbarProps {
|
|
17
|
+
L: Required<LayoutBuilderLabels>
|
|
18
|
+
previewMode: boolean
|
|
19
|
+
isBusy: boolean
|
|
20
|
+
status: RefreshStatus
|
|
21
|
+
liveKeys: number
|
|
22
|
+
reachableCount: number
|
|
23
|
+
unreachableCount: number
|
|
24
|
+
/** Advanced mode: shows the stats and the catalogue (the data sources tab lives below). */
|
|
25
|
+
advanced: boolean
|
|
26
|
+
onToggleAdvanced: () => void
|
|
27
|
+
/** The draft has changes that would be lost (the marker next to the title). */
|
|
28
|
+
unsaved: boolean
|
|
29
|
+
onOpenCatalogue: () => void
|
|
30
|
+
onOpenSave: () => void
|
|
31
|
+
/** Leaves the builder without the edits (or, without `onApply`, resets the draft in place). */
|
|
32
|
+
onDiscard: () => void
|
|
33
|
+
/** Shows the draft in the view and leaves the builder; absent when there is no view to apply to. */
|
|
34
|
+
onApply?: () => void
|
|
35
|
+
hasAnyCell: boolean
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
/** The live-context stats and the refresh state: data-source vocabulary, so advanced mode only. */
|
|
39
|
+
function Stats({
|
|
40
|
+
L,
|
|
41
|
+
status,
|
|
42
|
+
liveKeys,
|
|
43
|
+
reachableCount,
|
|
44
|
+
unreachableCount,
|
|
45
|
+
}: Pick<ToolbarProps, "L" | "status" | "liveKeys" | "reachableCount" | "unreachableCount">) {
|
|
46
|
+
return (
|
|
47
|
+
<div className="text-muted-foreground text-small hidden items-center gap-3 sm:flex">
|
|
48
|
+
<span className="inline-flex items-center gap-1.5">
|
|
49
|
+
<span aria-hidden="true" className={`size-1.5 rounded-full ${TONE_DOT.success}`} />
|
|
50
|
+
<span>
|
|
51
|
+
<span className="text-foreground font-medium">{liveKeys}</span> {L.statsLive}
|
|
52
|
+
</span>
|
|
53
|
+
</span>
|
|
54
|
+
<span className="bg-border h-3 w-px" aria-hidden="true" />
|
|
55
|
+
<span>
|
|
56
|
+
<span className="text-foreground font-medium">{reachableCount}</span> {L.statsReachable}
|
|
57
|
+
</span>
|
|
58
|
+
{unreachableCount > 0 && (
|
|
59
|
+
<>
|
|
60
|
+
<span className="bg-border h-3 w-px" aria-hidden="true" />
|
|
61
|
+
<span>
|
|
62
|
+
<span className="text-foreground font-medium">{unreachableCount}</span>{" "}
|
|
63
|
+
{L.statsUnreachable}
|
|
64
|
+
</span>
|
|
65
|
+
</>
|
|
66
|
+
)}
|
|
67
|
+
<StatusChip status={status} L={L} />
|
|
68
|
+
</div>
|
|
69
|
+
)
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
/**
|
|
73
|
+
* The unsaved marker. The live region is always mounted (only its content
|
|
74
|
+
* changes), so a screen reader hears the marker appear and go.
|
|
75
|
+
*/
|
|
76
|
+
function UnsavedMarker({ L, unsaved }: { L: Required<LayoutBuilderLabels>; unsaved: boolean }) {
|
|
77
|
+
return (
|
|
78
|
+
<span
|
|
79
|
+
role="status"
|
|
80
|
+
data-slot="builder-unsaved"
|
|
81
|
+
className="text-muted-foreground text-small inline-flex items-center gap-1.5"
|
|
82
|
+
>
|
|
83
|
+
{unsaved && (
|
|
84
|
+
<>
|
|
85
|
+
<span aria-hidden="true" className={`size-2 rounded-full ${TONE_DOT.warning}`} />
|
|
86
|
+
{L.unsavedChanges}
|
|
87
|
+
</>
|
|
88
|
+
)}
|
|
89
|
+
</span>
|
|
90
|
+
)
|
|
91
|
+
}
|
|
92
|
+
|
|
13
93
|
function ToolbarImpl({
|
|
14
94
|
L,
|
|
15
95
|
previewMode,
|
|
@@ -18,73 +98,81 @@ function ToolbarImpl({
|
|
|
18
98
|
liveKeys,
|
|
19
99
|
reachableCount,
|
|
20
100
|
unreachableCount,
|
|
101
|
+
advanced,
|
|
102
|
+
onToggleAdvanced,
|
|
103
|
+
unsaved,
|
|
21
104
|
onOpenCatalogue,
|
|
22
105
|
onOpenSave,
|
|
23
|
-
|
|
106
|
+
onDiscard,
|
|
107
|
+
onApply,
|
|
24
108
|
hasAnyCell,
|
|
25
|
-
}: {
|
|
26
|
-
L: Required<LayoutBuilderLabels>
|
|
27
|
-
previewMode: boolean
|
|
28
|
-
isBusy: boolean
|
|
29
|
-
status: RefreshStatus
|
|
30
|
-
liveKeys: number
|
|
31
|
-
reachableCount: number
|
|
32
|
-
unreachableCount: number
|
|
33
|
-
onOpenCatalogue: () => void
|
|
34
|
-
onOpenSave: () => void
|
|
35
|
-
onDone?: () => void
|
|
36
|
-
hasAnyCell: boolean
|
|
37
|
-
}) {
|
|
109
|
+
}: ToolbarProps) {
|
|
38
110
|
return (
|
|
39
|
-
<header className="bg-background/80 sticky top-0 z-10 -mx-1 flex flex-wrap items-center gap-3 border-b px-1 py-2 backdrop-blur">
|
|
40
|
-
<div className="flex items-center gap-2">
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
111
|
+
<header className="bg-background/80 sticky top-0 z-10 -mx-1 flex flex-wrap items-center gap-x-3 gap-y-2 border-b px-1 py-2 backdrop-blur">
|
|
112
|
+
<div className="flex min-w-0 flex-wrap items-center gap-2">
|
|
113
|
+
{/* No tinted icon tile before the title: a mode is no status, and the
|
|
114
|
+
badge next to the title already names it (anti-slop U2, CI §3.3).
|
|
115
|
+
The focus target when build mode opens (McpAppView moves focus here). */}
|
|
116
|
+
<h2
|
|
117
|
+
data-slot="builder-title"
|
|
118
|
+
tabIndex={-1}
|
|
119
|
+
className={cn("rounded-sm text-sm font-semibold tracking-tight", FOCUS_RING)}
|
|
47
120
|
>
|
|
48
|
-
{
|
|
49
|
-
</
|
|
50
|
-
<h2 className="text-sm font-semibold tracking-tight">{L.title}</h2>
|
|
121
|
+
{L.title}
|
|
122
|
+
</h2>
|
|
51
123
|
<Badge variant={previewMode ? "outline" : "secondary"} className="font-normal">
|
|
52
124
|
{previewMode ? L.previewBadge : L.builderBadge}
|
|
53
125
|
</Badge>
|
|
126
|
+
<UnsavedMarker L={L} unsaved={unsaved} />
|
|
54
127
|
</div>
|
|
55
128
|
|
|
56
|
-
|
|
57
|
-
<
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
<span className="text-foreground font-medium">{reachableCount}</span> reachable
|
|
66
|
-
</span>
|
|
67
|
-
{unreachableCount > 0 && (
|
|
68
|
-
<>
|
|
69
|
-
<span className="bg-border h-3 w-px" aria-hidden="true" />
|
|
70
|
-
<span>
|
|
71
|
-
<span className="text-foreground font-medium">{unreachableCount}</span> unreachable
|
|
72
|
-
</span>
|
|
73
|
-
</>
|
|
74
|
-
)}
|
|
75
|
-
<StatusChip status={status} L={L} />
|
|
76
|
-
</div>
|
|
129
|
+
{advanced && (
|
|
130
|
+
<Stats
|
|
131
|
+
L={L}
|
|
132
|
+
status={status}
|
|
133
|
+
liveKeys={liveKeys}
|
|
134
|
+
reachableCount={reachableCount}
|
|
135
|
+
unreachableCount={unreachableCount}
|
|
136
|
+
/>
|
|
137
|
+
)}
|
|
77
138
|
|
|
78
|
-
<div className="ml-auto flex items-center gap-1">
|
|
79
|
-
<Button
|
|
80
|
-
|
|
139
|
+
<div className="ml-auto flex flex-wrap items-center gap-1">
|
|
140
|
+
<Button
|
|
141
|
+
variant="ghost"
|
|
142
|
+
size="sm"
|
|
143
|
+
aria-pressed={advanced}
|
|
144
|
+
title={L.advancedHint}
|
|
145
|
+
onClick={onToggleAdvanced}
|
|
146
|
+
className="aria-pressed:bg-accent aria-pressed:text-accent-foreground"
|
|
147
|
+
>
|
|
148
|
+
<Wrench aria-hidden="true" /> {L.advanced}
|
|
149
|
+
</Button>
|
|
150
|
+
{advanced && (
|
|
151
|
+
<Button variant="ghost" size="sm" onClick={onOpenCatalogue}>
|
|
152
|
+
<Library aria-hidden="true" /> {L.catalogue}
|
|
153
|
+
</Button>
|
|
154
|
+
)}
|
|
155
|
+
<Button
|
|
156
|
+
variant="outline"
|
|
157
|
+
size="sm"
|
|
158
|
+
title={L.saveHint}
|
|
159
|
+
onClick={onOpenSave}
|
|
160
|
+
disabled={isBusy || !hasAnyCell}
|
|
161
|
+
>
|
|
162
|
+
<Save aria-hidden="true" /> {L.save}
|
|
81
163
|
</Button>
|
|
82
|
-
<Button
|
|
83
|
-
|
|
164
|
+
<Button
|
|
165
|
+
variant="ghost"
|
|
166
|
+
size="sm"
|
|
167
|
+
// Without Apply there is no view to leave to: Discard resets in place.
|
|
168
|
+
title={onApply ? L.discardHint : L.discardHintStandalone}
|
|
169
|
+
onClick={onDiscard}
|
|
170
|
+
>
|
|
171
|
+
<Undo2 aria-hidden="true" /> {L.discard}
|
|
84
172
|
</Button>
|
|
85
|
-
{
|
|
86
|
-
<Button
|
|
87
|
-
<Check /> {L.
|
|
173
|
+
{onApply && (
|
|
174
|
+
<Button size="sm" title={L.applyHint} onClick={onApply}>
|
|
175
|
+
<Check aria-hidden="true" /> {L.apply}
|
|
88
176
|
</Button>
|
|
89
177
|
)}
|
|
90
178
|
</div>
|
|
@@ -92,4 +180,13 @@ function ToolbarImpl({
|
|
|
92
180
|
)
|
|
93
181
|
}
|
|
94
182
|
|
|
95
|
-
|
|
183
|
+
/** A dense chrome bar: its Lucide icons draw at stroke 2 (CI §11), not the view's 2.5. */
|
|
184
|
+
function DenseToolbar(props: ToolbarProps) {
|
|
185
|
+
return (
|
|
186
|
+
<LucideProvider strokeWidth={DENSE_ICON_STROKE}>
|
|
187
|
+
<ToolbarImpl {...props} />
|
|
188
|
+
</LucideProvider>
|
|
189
|
+
)
|
|
190
|
+
}
|
|
191
|
+
|
|
192
|
+
export const Toolbar = memo(DenseToolbar)
|
|
@@ -1,13 +1,17 @@
|
|
|
1
|
-
import { memo } from "react"
|
|
2
|
-
import { GripVertical, Plus } from "lucide-react"
|
|
3
|
-
import type { ReachableWidget, RowDef, WidgetProps } from "@miragon/mcp-toolkit-core"
|
|
1
|
+
import { memo, useId } from "react"
|
|
2
|
+
import { GripVertical, Plus, SlidersHorizontal } from "lucide-react"
|
|
3
|
+
import type { DisplayText, ReachableWidget, RowDef, WidgetProps } from "@miragon/mcp-toolkit-core"
|
|
4
|
+
import { FOCUS_RING } from "../../lib/focus-ring.js"
|
|
5
|
+
import { cn } from "../../lib/utils.js"
|
|
4
6
|
import { Badge } from "../../primitives/badge.js"
|
|
5
7
|
import { Button } from "../../primitives/button.js"
|
|
6
|
-
import {
|
|
8
|
+
import { Skeleton } from "../../primitives/skeleton.js"
|
|
7
9
|
import type { WidgetComponent } from "../widget-renderer.js"
|
|
10
|
+
import { displayLabel } from "./builder-model.js"
|
|
8
11
|
import type { LayoutBuilderLabels } from "./labels.js"
|
|
9
12
|
import { WIDGET_DRAG_MIME } from "./labels.js"
|
|
10
13
|
import { CanvasRow } from "./CanvasRow.js"
|
|
14
|
+
import { useDisplayResolver } from "./use-display-resolver.js"
|
|
11
15
|
|
|
12
16
|
// -------------------------------------------------------------------------- //
|
|
13
17
|
// Workspace — palette + canvas (palette sticky on lg+)
|
|
@@ -21,7 +25,13 @@ import { CanvasRow } from "./CanvasRow.js"
|
|
|
21
25
|
export interface WorkspaceProps {
|
|
22
26
|
L: Required<LayoutBuilderLabels>
|
|
23
27
|
paletteByApp: [string, ReachableWidget[]][]
|
|
28
|
+
/** Each app's title (or its key) by app name: the palette's group headings. */
|
|
29
|
+
appDisplayByName: Map<string, DisplayText>
|
|
24
30
|
paletteCount: number
|
|
31
|
+
/** The first catalogue answer is still on its way: the palette shows a loading state. */
|
|
32
|
+
paletteLoading: boolean
|
|
33
|
+
/** The empty palette's next step: show the data sources (it turns on advanced mode). */
|
|
34
|
+
onOpenDataSources: () => void
|
|
25
35
|
activeRows: RowDef[]
|
|
26
36
|
focusedRowIndex: number
|
|
27
37
|
setFocusedRowIndex: (idx: number) => void
|
|
@@ -35,16 +45,23 @@ export interface WorkspaceProps {
|
|
|
35
45
|
onAddWidget: (widgetId: string, targetRowIdx?: number) => void
|
|
36
46
|
onConfigureCell: (rowIdx: number, cellIdx: number) => void
|
|
37
47
|
propsSchemaByWidgetId: Map<string, Record<string, unknown>>
|
|
48
|
+
/** Title, summary (or their keys) per widget id: the canvas cells' names. */
|
|
49
|
+
displayByWidgetId: Map<string, DisplayText>
|
|
50
|
+
/** Advanced mode adds the technical lines (a widget's required keys, cell ids). */
|
|
51
|
+
advanced: boolean
|
|
38
52
|
widgets: Record<string, WidgetComponent>
|
|
39
53
|
widgetProps: WidgetProps
|
|
40
|
-
|
|
54
|
+
/** Offered next to "Add row" while the draft has no tabs yet. */
|
|
41
55
|
onAddTab?: () => void
|
|
42
56
|
}
|
|
43
57
|
|
|
44
58
|
function WorkspaceImpl({
|
|
45
59
|
L,
|
|
46
60
|
paletteByApp,
|
|
61
|
+
appDisplayByName,
|
|
47
62
|
paletteCount,
|
|
63
|
+
paletteLoading,
|
|
64
|
+
onOpenDataSources,
|
|
48
65
|
activeRows,
|
|
49
66
|
focusedRowIndex,
|
|
50
67
|
setFocusedRowIndex,
|
|
@@ -58,53 +75,24 @@ function WorkspaceImpl({
|
|
|
58
75
|
onAddWidget,
|
|
59
76
|
onConfigureCell,
|
|
60
77
|
propsSchemaByWidgetId,
|
|
78
|
+
displayByWidgetId,
|
|
79
|
+
advanced,
|
|
61
80
|
widgets,
|
|
62
81
|
widgetProps,
|
|
63
|
-
showAddTabButton,
|
|
64
82
|
onAddTab,
|
|
65
83
|
}: WorkspaceProps) {
|
|
66
84
|
return (
|
|
67
85
|
<div className="grid grid-cols-12 gap-4">
|
|
68
|
-
<
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
{L.paletteEmpty}
|
|
79
|
-
</div>
|
|
80
|
-
) : (
|
|
81
|
-
<ScrollArea className="lg:max-h-[70vh]">
|
|
82
|
-
<div className="flex flex-col gap-3 pr-1">
|
|
83
|
-
{paletteByApp.map(([app, ws]) => (
|
|
84
|
-
<div key={app} className="flex flex-col gap-1">
|
|
85
|
-
<div className="text-muted-foreground/80 text-[10px] font-semibold tracking-wide uppercase">
|
|
86
|
-
{app}
|
|
87
|
-
</div>
|
|
88
|
-
{ws.map((w) => (
|
|
89
|
-
<PaletteItem key={w.id} w={w} onClick={() => onAddWidget(w.id)} />
|
|
90
|
-
))}
|
|
91
|
-
</div>
|
|
92
|
-
))}
|
|
93
|
-
</div>
|
|
94
|
-
</ScrollArea>
|
|
95
|
-
)}
|
|
96
|
-
{showAddTabButton && onAddTab && (
|
|
97
|
-
<Button
|
|
98
|
-
variant="ghost"
|
|
99
|
-
size="xs"
|
|
100
|
-
onClick={onAddTab}
|
|
101
|
-
className="text-muted-foreground hover:text-foreground mt-3"
|
|
102
|
-
>
|
|
103
|
-
<Plus /> {L.addTab}
|
|
104
|
-
</Button>
|
|
105
|
-
)}
|
|
106
|
-
</div>
|
|
107
|
-
</aside>
|
|
86
|
+
<Palette
|
|
87
|
+
L={L}
|
|
88
|
+
paletteByApp={paletteByApp}
|
|
89
|
+
appDisplayByName={appDisplayByName}
|
|
90
|
+
paletteCount={paletteCount}
|
|
91
|
+
loading={paletteLoading}
|
|
92
|
+
advanced={advanced}
|
|
93
|
+
onAddWidget={onAddWidget}
|
|
94
|
+
onOpenDataSources={onOpenDataSources}
|
|
95
|
+
/>
|
|
108
96
|
|
|
109
97
|
<section className="col-span-12 lg:col-span-9 xl:col-span-10">
|
|
110
98
|
<div className="flex flex-col gap-3">
|
|
@@ -127,13 +115,22 @@ function WorkspaceImpl({
|
|
|
127
115
|
onAddWidget={onAddWidget}
|
|
128
116
|
onConfigureCell={onConfigureCell}
|
|
129
117
|
propsSchemaByWidgetId={propsSchemaByWidgetId}
|
|
118
|
+
displayByWidgetId={displayByWidgetId}
|
|
119
|
+
advanced={advanced}
|
|
130
120
|
widgets={widgets}
|
|
131
121
|
widgetProps={widgetProps}
|
|
132
122
|
/>
|
|
133
123
|
))}
|
|
134
|
-
<
|
|
135
|
-
<
|
|
136
|
-
|
|
124
|
+
<div className="flex flex-wrap items-center gap-2">
|
|
125
|
+
<Button variant="outline" size="sm" onClick={onAddRow}>
|
|
126
|
+
<Plus aria-hidden="true" /> {L.addRow}
|
|
127
|
+
</Button>
|
|
128
|
+
{onAddTab && (
|
|
129
|
+
<Button variant="ghost" size="sm" onClick={onAddTab}>
|
|
130
|
+
<Plus aria-hidden="true" /> {L.addTab}
|
|
131
|
+
</Button>
|
|
132
|
+
)}
|
|
133
|
+
</div>
|
|
137
134
|
</div>
|
|
138
135
|
</section>
|
|
139
136
|
</div>
|
|
@@ -142,29 +139,202 @@ function WorkspaceImpl({
|
|
|
142
139
|
|
|
143
140
|
export const Workspace = memo(WorkspaceImpl)
|
|
144
141
|
|
|
142
|
+
// -------------------------------------------------------------------------- //
|
|
143
|
+
// Palette — the elements to add, grouped by app (sticky on lg+)
|
|
144
|
+
// -------------------------------------------------------------------------- //
|
|
145
|
+
|
|
146
|
+
function Palette({
|
|
147
|
+
L,
|
|
148
|
+
paletteByApp,
|
|
149
|
+
appDisplayByName,
|
|
150
|
+
paletteCount,
|
|
151
|
+
loading,
|
|
152
|
+
advanced,
|
|
153
|
+
onAddWidget,
|
|
154
|
+
onOpenDataSources,
|
|
155
|
+
}: Pick<WorkspaceProps, "L" | "paletteByApp" | "appDisplayByName" | "paletteCount" | "advanced"> & {
|
|
156
|
+
loading: boolean
|
|
157
|
+
onAddWidget: (widgetId: string) => void
|
|
158
|
+
onOpenDataSources: () => void
|
|
159
|
+
}) {
|
|
160
|
+
const headingId = useId()
|
|
161
|
+
return (
|
|
162
|
+
<aside aria-labelledby={headingId} className="col-span-12 lg:col-span-3 xl:col-span-2">
|
|
163
|
+
<div className="lg:sticky lg:top-16">
|
|
164
|
+
<h3
|
|
165
|
+
id={headingId}
|
|
166
|
+
className="text-muted-foreground text-small mb-2 flex items-center gap-2 font-semibold"
|
|
167
|
+
>
|
|
168
|
+
{L.paletteHeader}
|
|
169
|
+
{/* No count while loading: "0" would say there are none. */}
|
|
170
|
+
{!loading && (
|
|
171
|
+
<Badge variant="outline" className="px-1.5">
|
|
172
|
+
{paletteCount}
|
|
173
|
+
</Badge>
|
|
174
|
+
)}
|
|
175
|
+
</h3>
|
|
176
|
+
{loading ? (
|
|
177
|
+
<PaletteLoading L={L} />
|
|
178
|
+
) : paletteCount === 0 ? (
|
|
179
|
+
<PaletteEmpty L={L} onOpenDataSources={onOpenDataSources} />
|
|
180
|
+
) : (
|
|
181
|
+
// A native scroll box: its height is its own, so nothing after the
|
|
182
|
+
// palette can be painted over by the list (the old ScrollArea let
|
|
183
|
+
// the list overflow its max height).
|
|
184
|
+
<div className="flex flex-col gap-3 lg:max-h-[70vh] lg:overflow-y-auto lg:pr-1">
|
|
185
|
+
{paletteByApp.map(([app, ws]) => (
|
|
186
|
+
<div key={app} className="flex flex-col gap-1">
|
|
187
|
+
<PaletteGroupHeading
|
|
188
|
+
app={app}
|
|
189
|
+
display={appDisplayByName.get(app)}
|
|
190
|
+
advanced={advanced}
|
|
191
|
+
/>
|
|
192
|
+
<ul className="flex flex-col gap-1">
|
|
193
|
+
{ws.map((w) => (
|
|
194
|
+
<li key={w.id}>
|
|
195
|
+
<PaletteItem
|
|
196
|
+
L={L}
|
|
197
|
+
w={w}
|
|
198
|
+
advanced={advanced}
|
|
199
|
+
onClick={() => onAddWidget(w.id)}
|
|
200
|
+
/>
|
|
201
|
+
</li>
|
|
202
|
+
))}
|
|
203
|
+
</ul>
|
|
204
|
+
</div>
|
|
205
|
+
))}
|
|
206
|
+
</div>
|
|
207
|
+
)}
|
|
208
|
+
</div>
|
|
209
|
+
</aside>
|
|
210
|
+
)
|
|
211
|
+
}
|
|
212
|
+
|
|
213
|
+
/** The palette while the first catalogue answer is on its way (CI §9: a skeleton, not "none"). */
|
|
214
|
+
function PaletteLoading({ L }: { L: Required<LayoutBuilderLabels> }) {
|
|
215
|
+
return (
|
|
216
|
+
<div data-slot="builder-palette-loading" className="flex flex-col gap-1">
|
|
217
|
+
<Skeleton aria-hidden="true" className="h-9 w-full" />
|
|
218
|
+
<Skeleton aria-hidden="true" className="h-9 w-full" />
|
|
219
|
+
<Skeleton aria-hidden="true" className="h-9 w-3/4" />
|
|
220
|
+
<p role="status" className="text-muted-foreground text-small mt-1">
|
|
221
|
+
{L.paletteLoading}
|
|
222
|
+
</p>
|
|
223
|
+
</div>
|
|
224
|
+
)
|
|
225
|
+
}
|
|
226
|
+
|
|
227
|
+
/**
|
|
228
|
+
* The palette without any element. It speaks no data-source words (they sit
|
|
229
|
+
* behind Advanced); its one next step opens the data sources, also when the
|
|
230
|
+
* layout already has cells and the builder's empty state is not shown.
|
|
231
|
+
* Exported for its tests only.
|
|
232
|
+
*/
|
|
233
|
+
export function PaletteEmpty({
|
|
234
|
+
L,
|
|
235
|
+
onOpenDataSources,
|
|
236
|
+
}: {
|
|
237
|
+
L: Required<LayoutBuilderLabels>
|
|
238
|
+
onOpenDataSources: () => void
|
|
239
|
+
}) {
|
|
240
|
+
return (
|
|
241
|
+
<div
|
|
242
|
+
data-slot="builder-palette-empty"
|
|
243
|
+
className="text-muted-foreground text-small flex flex-col items-start gap-2 rounded-md border border-dashed p-3"
|
|
244
|
+
>
|
|
245
|
+
<p>{L.paletteEmpty}</p>
|
|
246
|
+
<Button size="sm" variant="outline" onClick={onOpenDataSources}>
|
|
247
|
+
<SlidersHorizontal aria-hidden="true" /> {L.openDataSources}
|
|
248
|
+
</Button>
|
|
249
|
+
</div>
|
|
250
|
+
)
|
|
251
|
+
}
|
|
252
|
+
|
|
253
|
+
// -------------------------------------------------------------------------- //
|
|
254
|
+
// Palette group heading
|
|
255
|
+
// -------------------------------------------------------------------------- //
|
|
256
|
+
|
|
257
|
+
/**
|
|
258
|
+
* The heading of one app's group in the palette: the app's title. Without a
|
|
259
|
+
* title the app's name is a technical namespace, so it heads the group only in
|
|
260
|
+
* advanced mode; there it also follows a title as a quiet mono hint.
|
|
261
|
+
*/
|
|
262
|
+
function PaletteGroupHeading({
|
|
263
|
+
app,
|
|
264
|
+
display,
|
|
265
|
+
advanced,
|
|
266
|
+
}: {
|
|
267
|
+
app: string
|
|
268
|
+
display: DisplayText | undefined
|
|
269
|
+
advanced: boolean
|
|
270
|
+
}) {
|
|
271
|
+
const { locale, resolveKey } = useDisplayResolver()
|
|
272
|
+
const { label, hint } = displayLabel(display ?? {}, app, locale, resolveKey)
|
|
273
|
+
if (hint === undefined && !advanced) return null
|
|
274
|
+
return (
|
|
275
|
+
<div
|
|
276
|
+
data-slot="builder-palette-group"
|
|
277
|
+
className="text-muted-foreground text-small font-semibold"
|
|
278
|
+
>
|
|
279
|
+
{label}
|
|
280
|
+
{advanced && hint && <span className="ml-1.5 font-mono font-normal">{hint}</span>}
|
|
281
|
+
</div>
|
|
282
|
+
)
|
|
283
|
+
}
|
|
284
|
+
|
|
145
285
|
// -------------------------------------------------------------------------- //
|
|
146
286
|
// Palette item
|
|
147
287
|
// -------------------------------------------------------------------------- //
|
|
148
288
|
|
|
149
|
-
|
|
289
|
+
/**
|
|
290
|
+
* One widget in the palette: its title and one-line summary, the widget id as
|
|
291
|
+
* a quiet mono line (only next to a real title), and in advanced mode the keys
|
|
292
|
+
* it needs. A click (or Enter) adds it to the target row; dragging drops it
|
|
293
|
+
* on any row.
|
|
294
|
+
*/
|
|
295
|
+
function PaletteItemImpl({
|
|
296
|
+
L,
|
|
297
|
+
w,
|
|
298
|
+
advanced,
|
|
299
|
+
onClick,
|
|
300
|
+
}: {
|
|
301
|
+
L: Required<LayoutBuilderLabels>
|
|
302
|
+
w: ReachableWidget
|
|
303
|
+
advanced: boolean
|
|
304
|
+
onClick: () => void
|
|
305
|
+
}) {
|
|
306
|
+
const { locale, resolveKey } = useDisplayResolver()
|
|
307
|
+
const { label, hint, summary } = displayLabel(w, w.id, locale, resolveKey)
|
|
308
|
+
// On the hovered --accent surface quiet text takes the surface's
|
|
309
|
+
// foreground: --muted-foreground drops to 3.66:1 there in dark.
|
|
310
|
+
const quiet = "text-muted-foreground group-hover:text-accent-foreground block w-full truncate"
|
|
150
311
|
return (
|
|
151
312
|
<button
|
|
152
313
|
type="button"
|
|
153
314
|
draggable
|
|
315
|
+
data-slot="builder-palette-item"
|
|
154
316
|
onDragStart={(e) => {
|
|
155
317
|
e.dataTransfer.setData(WIDGET_DRAG_MIME, w.id)
|
|
156
318
|
e.dataTransfer.effectAllowed = "copy"
|
|
157
319
|
}}
|
|
158
320
|
onClick={onClick}
|
|
159
|
-
className=
|
|
321
|
+
className={cn(
|
|
322
|
+
"hover:bg-accent hover:text-accent-foreground group bg-background flex w-full cursor-grab flex-col items-start gap-0.5 rounded-md border px-2 py-1.5 text-left transition-colors active:cursor-grabbing",
|
|
323
|
+
FOCUS_RING,
|
|
324
|
+
)}
|
|
160
325
|
>
|
|
161
326
|
<span className="flex w-full items-center justify-between gap-2">
|
|
162
|
-
<span className="truncate font-
|
|
163
|
-
<GripVertical
|
|
327
|
+
<span className="truncate text-sm font-medium">{label}</span>
|
|
328
|
+
<GripVertical
|
|
329
|
+
aria-hidden="true"
|
|
330
|
+
className="text-muted-foreground group-hover:text-accent-foreground size-3.5 shrink-0"
|
|
331
|
+
/>
|
|
164
332
|
</span>
|
|
165
|
-
{
|
|
166
|
-
|
|
167
|
-
|
|
333
|
+
{summary && <span className={cn(quiet, "text-small")}>{summary}</span>}
|
|
334
|
+
{hint && <span className={cn(quiet, "text-small font-mono")}>{hint}</span>}
|
|
335
|
+
{advanced && w.requires.length > 0 && (
|
|
336
|
+
<span className={cn(quiet, "text-small")}>
|
|
337
|
+
{L.catalogueNeedsKeys} <span className="font-mono">{w.requires.join(", ")}</span>
|
|
168
338
|
</span>
|
|
169
339
|
)}
|
|
170
340
|
</button>
|