@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,211 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* A passive observer of the MCP Apps (SEP-1865) host → view lifecycle
|
|
3
|
+
* notifications, read straight off the postMessage channel the view runtime
|
|
4
|
+
* itself listens on (toolkit#176 K13, N21).
|
|
5
|
+
*
|
|
6
|
+
* mcp-use 2.x latches only a result WITH `structuredContent` (or an
|
|
7
|
+
* `isError`); a content-only result, which claude.ai and Claude Desktop send,
|
|
8
|
+
* leaves its status `"pending"` forever, and its tool input merges partial and
|
|
9
|
+
* complete arguments into one field. Watching the notifications themselves
|
|
10
|
+
* tells the three cases apart that the latch cannot:
|
|
11
|
+
*
|
|
12
|
+
* - the host delivered a STRIPPED result (re-run the tool now, with the
|
|
13
|
+
* complete arguments it was called with),
|
|
14
|
+
* - the host delivered a structured result (the latch follows; never re-run),
|
|
15
|
+
* - nothing arrived yet (a slow tool on a compliant host: keep waiting).
|
|
16
|
+
*
|
|
17
|
+
* The last case is only certain when the observer was listening before the
|
|
18
|
+
* host answered `ui/initialize` ({@link ToolObservation.sawHandshake}): hosts
|
|
19
|
+
* send the lifecycle notifications after the handshake, so an observer that
|
|
20
|
+
* saw it has seen everything sent so far. `mountMcpToolkitApp` installs it
|
|
21
|
+
* ahead of `bootstrapView` for exactly that reason.
|
|
22
|
+
*
|
|
23
|
+
* Read-only: it never sends, never answers and never stops a message.
|
|
24
|
+
*/
|
|
25
|
+
|
|
26
|
+
/** What the host's `ui/notifications/tool-result` carried. */
|
|
27
|
+
export type ObservedToolResult = "none" | "structured" | "stripped" | "error"
|
|
28
|
+
|
|
29
|
+
/** Everything the observer learned about the rendering call so far. */
|
|
30
|
+
export interface ToolObservation {
|
|
31
|
+
/**
|
|
32
|
+
* The observer saw the host answer `ui/initialize`, so it was listening
|
|
33
|
+
* before any lifecycle notification could be sent: a result it has not
|
|
34
|
+
* seen has not been delivered yet.
|
|
35
|
+
*/
|
|
36
|
+
sawHandshake: boolean
|
|
37
|
+
/**
|
|
38
|
+
* The arguments of the complete `ui/notifications/tool-input` — never a
|
|
39
|
+
* partial stream (`tool-input-partial` is ignored). `undefined` until it
|
|
40
|
+
* arrived.
|
|
41
|
+
*/
|
|
42
|
+
completeInput: Record<string, unknown> | undefined
|
|
43
|
+
/** What the first `ui/notifications/tool-result` carried. */
|
|
44
|
+
result: ObservedToolResult
|
|
45
|
+
/** The host sent `ui/notifications/tool-cancelled`. */
|
|
46
|
+
cancelled: boolean
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
export const EMPTY_TOOL_OBSERVATION: ToolObservation = Object.freeze({
|
|
50
|
+
sawHandshake: false,
|
|
51
|
+
completeInput: undefined,
|
|
52
|
+
result: "none",
|
|
53
|
+
cancelled: false,
|
|
54
|
+
})
|
|
55
|
+
|
|
56
|
+
/** A host → view message the observer acts on. */
|
|
57
|
+
export type HostLifecycleMessage =
|
|
58
|
+
| { kind: "handshake" }
|
|
59
|
+
| { kind: "tool-input"; arguments: Record<string, unknown> }
|
|
60
|
+
| { kind: "tool-result"; result: Exclude<ObservedToolResult, "none"> }
|
|
61
|
+
| { kind: "tool-cancelled" }
|
|
62
|
+
|
|
63
|
+
function isRecord(value: unknown): value is Record<string, unknown> {
|
|
64
|
+
return typeof value === "object" && value !== null && !Array.isArray(value)
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
/**
|
|
68
|
+
* Classify a tool-result notification the way mcp-use 2.x's latch does: an
|
|
69
|
+
* `isError` result is an error, a result with `structuredContent` (even
|
|
70
|
+
* `null`) latches as ready, and anything else is the stripped, content-only
|
|
71
|
+
* result the latch ignores.
|
|
72
|
+
*/
|
|
73
|
+
export function classifyToolResult(
|
|
74
|
+
params: Record<string, unknown>,
|
|
75
|
+
): Exclude<ObservedToolResult, "none"> {
|
|
76
|
+
if (params.isError === true) return "error"
|
|
77
|
+
return params.structuredContent === undefined ? "stripped" : "structured"
|
|
78
|
+
}
|
|
79
|
+
|
|
80
|
+
/** The host's answer to `ui/initialize`: a response carrying its capabilities or protocol version. */
|
|
81
|
+
function isHandshakeResponse(message: Record<string, unknown>): boolean {
|
|
82
|
+
if (!("id" in message) || !isRecord(message.result)) return false
|
|
83
|
+
return (
|
|
84
|
+
isRecord(message.result.hostCapabilities) || typeof message.result.protocolVersion === "string"
|
|
85
|
+
)
|
|
86
|
+
}
|
|
87
|
+
|
|
88
|
+
/**
|
|
89
|
+
* Decode one postMessage payload into the lifecycle message it is, or `null`
|
|
90
|
+
* for anything else (other methods, requests, responses, foreign traffic).
|
|
91
|
+
*/
|
|
92
|
+
export function classifyHostMessage(data: unknown): HostLifecycleMessage | null {
|
|
93
|
+
if (!isRecord(data) || data.jsonrpc !== "2.0") return null
|
|
94
|
+
if (typeof data.method !== "string") {
|
|
95
|
+
return isHandshakeResponse(data) ? { kind: "handshake" } : null
|
|
96
|
+
}
|
|
97
|
+
const params = isRecord(data.params) ? data.params : {}
|
|
98
|
+
switch (data.method) {
|
|
99
|
+
case "ui/notifications/tool-input":
|
|
100
|
+
return {
|
|
101
|
+
kind: "tool-input",
|
|
102
|
+
arguments: isRecord(params.arguments) ? params.arguments : {},
|
|
103
|
+
}
|
|
104
|
+
case "ui/notifications/tool-result":
|
|
105
|
+
return { kind: "tool-result", result: classifyToolResult(params) }
|
|
106
|
+
case "ui/notifications/tool-cancelled":
|
|
107
|
+
return { kind: "tool-cancelled" }
|
|
108
|
+
default:
|
|
109
|
+
return null
|
|
110
|
+
}
|
|
111
|
+
}
|
|
112
|
+
|
|
113
|
+
/**
|
|
114
|
+
* Fold one message into the observation. Like the mcp-use latch, the call
|
|
115
|
+
* settles once: after its result or cancellation, later inputs, results and
|
|
116
|
+
* cancellations change nothing.
|
|
117
|
+
*/
|
|
118
|
+
export function reduceToolObservation(
|
|
119
|
+
state: ToolObservation,
|
|
120
|
+
message: HostLifecycleMessage,
|
|
121
|
+
): ToolObservation {
|
|
122
|
+
if (message.kind === "handshake") {
|
|
123
|
+
return state.sawHandshake ? state : { ...state, sawHandshake: true }
|
|
124
|
+
}
|
|
125
|
+
if (state.result !== "none" || state.cancelled) return state
|
|
126
|
+
switch (message.kind) {
|
|
127
|
+
case "tool-input":
|
|
128
|
+
return { ...state, completeInput: message.arguments }
|
|
129
|
+
case "tool-result":
|
|
130
|
+
return { ...state, result: message.result }
|
|
131
|
+
case "tool-cancelled":
|
|
132
|
+
return { ...state, cancelled: true }
|
|
133
|
+
}
|
|
134
|
+
}
|
|
135
|
+
|
|
136
|
+
/** The `window` slice the observer listens on (any `EventTarget`, e.g. in tests). */
|
|
137
|
+
export interface MessageEventSource {
|
|
138
|
+
addEventListener(type: "message", listener: (event: Event) => void): void
|
|
139
|
+
removeEventListener(type: "message", listener: (event: Event) => void): void
|
|
140
|
+
}
|
|
141
|
+
|
|
142
|
+
/** A subscribable observation, shaped for `useSyncExternalStore`. */
|
|
143
|
+
export interface ToolResultObserver {
|
|
144
|
+
subscribe: (listener: () => void) => () => void
|
|
145
|
+
getSnapshot: () => ToolObservation
|
|
146
|
+
/** Stop listening; the last observation stays readable. */
|
|
147
|
+
dispose: () => void
|
|
148
|
+
}
|
|
149
|
+
|
|
150
|
+
/**
|
|
151
|
+
* Observe the lifecycle notifications arriving on `source`. `accept` filters
|
|
152
|
+
* the events (the view accepts only its host: `event.source === window.parent`,
|
|
153
|
+
* the same check the ext-apps transport makes).
|
|
154
|
+
*/
|
|
155
|
+
export function createToolResultObserver(
|
|
156
|
+
source: MessageEventSource,
|
|
157
|
+
accept: (event: MessageEvent) => boolean = () => true,
|
|
158
|
+
): ToolResultObserver {
|
|
159
|
+
let snapshot: ToolObservation = EMPTY_TOOL_OBSERVATION
|
|
160
|
+
const listeners = new Set<() => void>()
|
|
161
|
+
const onMessage = (received: Event) => {
|
|
162
|
+
// Only `message` events are subscribed: each one is a MessageEvent.
|
|
163
|
+
const event = received as MessageEvent
|
|
164
|
+
if (!accept(event)) return
|
|
165
|
+
const message = classifyHostMessage(event.data)
|
|
166
|
+
if (!message) return
|
|
167
|
+
const next = reduceToolObservation(snapshot, message)
|
|
168
|
+
if (next === snapshot) return
|
|
169
|
+
snapshot = next
|
|
170
|
+
for (const listener of [...listeners]) listener()
|
|
171
|
+
}
|
|
172
|
+
source.addEventListener("message", onMessage)
|
|
173
|
+
return {
|
|
174
|
+
subscribe: (listener) => {
|
|
175
|
+
listeners.add(listener)
|
|
176
|
+
return () => {
|
|
177
|
+
listeners.delete(listener)
|
|
178
|
+
}
|
|
179
|
+
},
|
|
180
|
+
getSnapshot: () => snapshot,
|
|
181
|
+
dispose: () => {
|
|
182
|
+
source.removeEventListener("message", onMessage)
|
|
183
|
+
},
|
|
184
|
+
}
|
|
185
|
+
}
|
|
186
|
+
|
|
187
|
+
let documentObserver: ToolResultObserver | null = null
|
|
188
|
+
|
|
189
|
+
/**
|
|
190
|
+
* The view document's observer: installed once and kept for the document's
|
|
191
|
+
* lifetime (one document renders one view). `null` outside a browser and in
|
|
192
|
+
* a top-level window, where no host frames the view.
|
|
193
|
+
*
|
|
194
|
+
* It must listen before the view runtime connects, so it sees the
|
|
195
|
+
* handshake. This module therefore installs it as the bundle evaluates
|
|
196
|
+
* (below), ahead of any `bootstrapView` call in the entry module, whatever
|
|
197
|
+
* the mount; `mountMcpToolkitApp` calls it again (idempotent). Installed any
|
|
198
|
+
* later, it still sees what arrives afterwards, and the recovery falls back
|
|
199
|
+
* to its grace timer for the rest.
|
|
200
|
+
*/
|
|
201
|
+
export function installToolResultObserver(): ToolResultObserver | null {
|
|
202
|
+
if (documentObserver) return documentObserver
|
|
203
|
+
if (typeof window === "undefined" || window.parent === window) return null
|
|
204
|
+
const host = window.parent
|
|
205
|
+
documentObserver = createToolResultObserver(window, (event) => event.source === host)
|
|
206
|
+
return documentObserver
|
|
207
|
+
}
|
|
208
|
+
|
|
209
|
+
// Listen from the moment the view bundle evaluates (a passive listener; a
|
|
210
|
+
// no-op outside a framed browser document).
|
|
211
|
+
installToolResultObserver()
|
|
@@ -0,0 +1,45 @@
|
|
|
1
|
+
import { describe, expect, it } from "vitest"
|
|
2
|
+
import { MICRO_LABEL, TYPE_FLOOR_PX, TYPE_SCALE, TYPE_STEPS } from "./typography.js"
|
|
3
|
+
import { cn } from "./utils.js"
|
|
4
|
+
|
|
5
|
+
describe("the type scale (CI §4)", () => {
|
|
6
|
+
it("has five steps, each its own self-named utility", () => {
|
|
7
|
+
expect(TYPE_STEPS).toEqual(["title", "section", "body", "dense", "small"])
|
|
8
|
+
expect(TYPE_SCALE).toEqual({
|
|
9
|
+
title: "text-title",
|
|
10
|
+
section: "text-section",
|
|
11
|
+
body: "text-body",
|
|
12
|
+
dense: "text-dense",
|
|
13
|
+
small: "text-small",
|
|
14
|
+
})
|
|
15
|
+
})
|
|
16
|
+
|
|
17
|
+
it("puts the floor at the CI's smallest size and micro-labels on it, in normal case", () => {
|
|
18
|
+
expect(TYPE_FLOOR_PX).toBe(13)
|
|
19
|
+
expect(MICRO_LABEL).toBe("text-small font-semibold")
|
|
20
|
+
expect(MICRO_LABEL).not.toMatch(/uppercase|text-xs|text-\[/)
|
|
21
|
+
})
|
|
22
|
+
})
|
|
23
|
+
|
|
24
|
+
describe("cn knows the type scale (tailwind-merge would drop it as a colour)", () => {
|
|
25
|
+
it("keeps a scale size next to a text colour, in either order", () => {
|
|
26
|
+
for (const size of Object.values(TYPE_SCALE)) {
|
|
27
|
+
expect(cn(size, "text-muted-foreground")).toBe(`${size} text-muted-foreground`)
|
|
28
|
+
expect(cn("text-danger-ink", size)).toBe(`text-danger-ink ${size}`)
|
|
29
|
+
}
|
|
30
|
+
})
|
|
31
|
+
|
|
32
|
+
it("lets a later size win over an earlier one, scale or Tailwind", () => {
|
|
33
|
+
expect(cn("text-sm", "text-small")).toBe("text-small")
|
|
34
|
+
expect(cn("text-small", "text-xs")).toBe("text-xs")
|
|
35
|
+
expect(cn("text-dense", "text-title")).toBe("text-title")
|
|
36
|
+
expect(cn("md:text-sm", "md:text-dense")).toBe("md:text-dense")
|
|
37
|
+
})
|
|
38
|
+
|
|
39
|
+
it("keeps a leading set after the size (a size resets the line height before it)", () => {
|
|
40
|
+
expect(cn("text-small", "leading-4")).toBe("text-small leading-4")
|
|
41
|
+
expect(cn(MICRO_LABEL, "text-muted-foreground")).toBe(
|
|
42
|
+
"text-small font-semibold text-muted-foreground",
|
|
43
|
+
)
|
|
44
|
+
})
|
|
45
|
+
})
|
|
@@ -0,0 +1,47 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The type scale of the kit (modeler-tool-design §4, adapted for embedded
|
|
3
|
+
* widgets): five steps, each a role in `theme.css` (`--text-<step>` with its
|
|
4
|
+
* line height and weight) and a Tailwind utility of the same name.
|
|
5
|
+
*
|
|
6
|
+
* | Step | Utility | Size / weight / line height | Use |
|
|
7
|
+
* | --------- | -------------- | --------------------------- | ------------------------------------------ |
|
|
8
|
+
* | `title` | `text-title` | 28 px / 700 / 1.2 | page title (the CI h2; a widget has no h1 40 px) |
|
|
9
|
+
* | `section` | `text-section` | 21 px / 600 / 1.3 | section title (CI h3) |
|
|
10
|
+
* | `body` | `text-body` | 16 px / 400 / 1.6 | running text: state and toast descriptions |
|
|
11
|
+
* | `dense` | `text-dense` | 14 px / 400 / 1.5 | dense tables and controls (inputs, chips, count pills, the inline alert box): the documented product exception, never running text |
|
|
12
|
+
* | `small` | `text-small` | 13 px / 400 / 1.5 | captions, labels, hints, meta rows: the FLOOR |
|
|
13
|
+
*
|
|
14
|
+
* Nothing renders below 13 px — no `text-xs` (12 px), no `text-[10px]`
|
|
15
|
+
* micro-labels (`examples/test/design-system.test.ts` enforces it). A label
|
|
16
|
+
* that used to be a 10–11 px uppercase caption is {@link MICRO_LABEL}: 13 px,
|
|
17
|
+
* semibold, normal case.
|
|
18
|
+
*
|
|
19
|
+
* Combine the utilities through the kit's `cn`: plain tailwind-merge does not
|
|
20
|
+
* know these sizes and would drop `text-small` next to a text colour.
|
|
21
|
+
*/
|
|
22
|
+
|
|
23
|
+
/** The five steps, smallest last. */
|
|
24
|
+
export const TYPE_STEPS = ["title", "section", "body", "dense", "small"] as const
|
|
25
|
+
|
|
26
|
+
/** One step of the type scale. */
|
|
27
|
+
export type TypeStep = (typeof TYPE_STEPS)[number]
|
|
28
|
+
|
|
29
|
+
/** The utility class per step (`TYPE_SCALE.small` → `"text-small"`). */
|
|
30
|
+
export const TYPE_SCALE: Readonly<Record<TypeStep, `text-${TypeStep}`>> = {
|
|
31
|
+
title: "text-title",
|
|
32
|
+
section: "text-section",
|
|
33
|
+
body: "text-body",
|
|
34
|
+
dense: "text-dense",
|
|
35
|
+
small: "text-small",
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
/** The smallest text the kit renders, in CSS px (CI §4 "klein"). */
|
|
39
|
+
export const TYPE_FLOOR_PX = 13
|
|
40
|
+
|
|
41
|
+
/**
|
|
42
|
+
* A caption above a value or a column: table heads, KPI labels, group
|
|
43
|
+
* labels. 13 px semibold in normal case — the CI floor, where these used to
|
|
44
|
+
* be 10–11 px uppercase. Typography only: add the colour
|
|
45
|
+
* (`text-muted-foreground`) at the call site.
|
|
46
|
+
*/
|
|
47
|
+
export const MICRO_LABEL = "text-small font-semibold"
|
package/src/lib/utils.ts
CHANGED
|
@@ -1,5 +1,16 @@
|
|
|
1
1
|
import { type ClassValue, clsx } from "clsx"
|
|
2
|
-
import {
|
|
2
|
+
import { extendTailwindMerge } from "tailwind-merge"
|
|
3
|
+
import { TYPE_STEPS } from "./typography.js"
|
|
4
|
+
|
|
5
|
+
/**
|
|
6
|
+
* tailwind-merge that knows the kit's type scale. Out of the box it reads
|
|
7
|
+
* an unknown `text-small` as a text COLOUR and drops it next to
|
|
8
|
+
* `text-muted-foreground`; registered as font sizes, `text-small` conflicts
|
|
9
|
+
* only with other sizes (`text-sm`, `text-xs`), as it should.
|
|
10
|
+
*/
|
|
11
|
+
const twMerge = extendTailwindMerge({
|
|
12
|
+
extend: { theme: { text: [...TYPE_STEPS] } },
|
|
13
|
+
})
|
|
3
14
|
|
|
4
15
|
export function cn(...inputs: ClassValue[]) {
|
|
5
16
|
return twMerge(clsx(inputs))
|
package/src/locale/index.ts
CHANGED
|
@@ -3,5 +3,18 @@
|
|
|
3
3
|
// <LocaleProvider> and reads the active locale with useLocale/useTranslate,
|
|
4
4
|
// without pulling in the host runtime. Pairs with `createTranslator` from
|
|
5
5
|
// `@miragon/mcp-toolkit-core`.
|
|
6
|
-
export { LocaleProvider, useLocale, useTranslate } from "./locale-provider.js"
|
|
6
|
+
export { LocaleProvider, useLocale, useTranslate, useToolkitMessages } from "./locale-provider.js"
|
|
7
7
|
export type { LocaleContextValue, LocaleProviderProps, BoundTranslate } from "./locale-provider.js"
|
|
8
|
+
export { TOOLKIT_MESSAGES, formatCount, resolveToolkitMessages } from "./toolkit-messages.js"
|
|
9
|
+
export type {
|
|
10
|
+
BuilderMessages,
|
|
11
|
+
CommonMessages,
|
|
12
|
+
FilterBarMessages,
|
|
13
|
+
ListFooterMessages,
|
|
14
|
+
PropsSheetMessages,
|
|
15
|
+
RendererMessages,
|
|
16
|
+
ToolkitLocale,
|
|
17
|
+
ToolkitMessages,
|
|
18
|
+
ToolkitMessagesOverride,
|
|
19
|
+
ViewMessages,
|
|
20
|
+
} from "./toolkit-messages.js"
|
|
@@ -0,0 +1,87 @@
|
|
|
1
|
+
import type { ReactNode } from "react"
|
|
2
|
+
import { renderToStaticMarkup } from "react-dom/server"
|
|
3
|
+
import { describe, expect, it } from "vitest"
|
|
4
|
+
import { ListFooter } from "../components/ListFooter.js"
|
|
5
|
+
import {
|
|
6
|
+
LocaleProvider,
|
|
7
|
+
ToolkitLocaleFallback,
|
|
8
|
+
useLocale,
|
|
9
|
+
useToolkitLocale,
|
|
10
|
+
useToolkitMessages,
|
|
11
|
+
useTranslate,
|
|
12
|
+
type LocaleContextValue,
|
|
13
|
+
} from "./locale-provider.js"
|
|
14
|
+
import { TOOLKIT_MESSAGES } from "./toolkit-messages.js"
|
|
15
|
+
|
|
16
|
+
/**
|
|
17
|
+
* The locale contract: `LocaleProvider` sets the locale for everyone; the
|
|
18
|
+
* `ToolkitLocaleFallback` McpAppView mounts with the host's locale binds ONLY
|
|
19
|
+
* the toolkit's own strings and number format, so a consumer widget's
|
|
20
|
+
* `useLocale()`/`useTranslate()` keep their outside-a-provider behaviour.
|
|
21
|
+
*/
|
|
22
|
+
|
|
23
|
+
function Probe() {
|
|
24
|
+
const messages = useToolkitMessages()
|
|
25
|
+
return (
|
|
26
|
+
<p>
|
|
27
|
+
{`locale=${useLocale()} toolkit=${useToolkitLocale()} t=${useTranslate()("k")} close=${messages.common.close}`}
|
|
28
|
+
</p>
|
|
29
|
+
)
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
const render = (node: ReactNode) => renderToStaticMarkup(node)
|
|
33
|
+
|
|
34
|
+
describe("ToolkitLocaleFallback", () => {
|
|
35
|
+
it("binds the toolkit's strings and number locale, not useLocale/useTranslate", () => {
|
|
36
|
+
expect(
|
|
37
|
+
render(
|
|
38
|
+
<ToolkitLocaleFallback locale="de-DE">
|
|
39
|
+
<Probe />
|
|
40
|
+
</ToolkitLocaleFallback>,
|
|
41
|
+
),
|
|
42
|
+
).toContain(`locale=en toolkit=de-DE t=k close=${TOOLKIT_MESSAGES.de.common.close}`)
|
|
43
|
+
})
|
|
44
|
+
|
|
45
|
+
it("yields to a LocaleProvider above or below it", () => {
|
|
46
|
+
const below = render(
|
|
47
|
+
<ToolkitLocaleFallback locale="de-DE">
|
|
48
|
+
<LocaleProvider locale="en-GB">
|
|
49
|
+
<Probe />
|
|
50
|
+
</LocaleProvider>
|
|
51
|
+
</ToolkitLocaleFallback>,
|
|
52
|
+
)
|
|
53
|
+
expect(below).toContain(
|
|
54
|
+
`locale=en-GB toolkit=en-GB t=k close=${TOOLKIT_MESSAGES.en.common.close}`,
|
|
55
|
+
)
|
|
56
|
+
const above = render(
|
|
57
|
+
<LocaleProvider locale="en">
|
|
58
|
+
<ToolkitLocaleFallback locale="de-DE">
|
|
59
|
+
<Probe />
|
|
60
|
+
</ToolkitLocaleFallback>
|
|
61
|
+
</LocaleProvider>,
|
|
62
|
+
)
|
|
63
|
+
expect(above).toContain(`locale=en toolkit=en t=k close=${TOOLKIT_MESSAGES.en.common.close}`)
|
|
64
|
+
})
|
|
65
|
+
|
|
66
|
+
it("keeps the defaults outside any provider", () => {
|
|
67
|
+
expect(render(<Probe />)).toContain(
|
|
68
|
+
`locale=en toolkit=en t=k close=${TOOLKIT_MESSAGES.en.common.close}`,
|
|
69
|
+
)
|
|
70
|
+
})
|
|
71
|
+
|
|
72
|
+
it("formats toolkit counts in the language of the sentence around them", () => {
|
|
73
|
+
const html = render(
|
|
74
|
+
<ToolkitLocaleFallback locale="de-DE">
|
|
75
|
+
<ListFooter shown={1200} total={4500} hasMore={false} onLoadMore={() => {}} />
|
|
76
|
+
</ToolkitLocaleFallback>,
|
|
77
|
+
)
|
|
78
|
+
expect(html).toContain("Zeigt 1.200 von 4.500 Zeilen")
|
|
79
|
+
})
|
|
80
|
+
})
|
|
81
|
+
|
|
82
|
+
describe("LocaleContextValue", () => {
|
|
83
|
+
it("accepts a hand-built value without messages (the field is optional)", () => {
|
|
84
|
+
const value: LocaleContextValue = { locale: "en", t: (key) => key }
|
|
85
|
+
expect(value.messages).toBeUndefined()
|
|
86
|
+
})
|
|
87
|
+
})
|
|
@@ -1,5 +1,10 @@
|
|
|
1
1
|
import { createContext, useContext, useMemo, type ReactNode } from "react"
|
|
2
2
|
import type { Translate } from "@miragon/mcp-toolkit-core"
|
|
3
|
+
import {
|
|
4
|
+
resolveToolkitMessages,
|
|
5
|
+
type ToolkitMessages,
|
|
6
|
+
type ToolkitMessagesOverride,
|
|
7
|
+
} from "./toolkit-messages.js"
|
|
3
8
|
|
|
4
9
|
/**
|
|
5
10
|
* A locale-bound translate: the active locale is already applied, so call sites
|
|
@@ -13,6 +18,14 @@ export interface LocaleContextValue {
|
|
|
13
18
|
locale: string
|
|
14
19
|
/** Translate a key in the active locale. */
|
|
15
20
|
t: BoundTranslate
|
|
21
|
+
/**
|
|
22
|
+
* The toolkit's own strings for the active locale (its shipped `en`/`de`
|
|
23
|
+
* catalog, English for any other locale) with the provider's
|
|
24
|
+
* `toolkitMessages` override applied. Read it with {@link useToolkitMessages}.
|
|
25
|
+
* Optional on the type (a hand-built value may omit it); `LocaleProvider`
|
|
26
|
+
* always sets it.
|
|
27
|
+
*/
|
|
28
|
+
messages?: ToolkitMessages
|
|
16
29
|
}
|
|
17
30
|
|
|
18
31
|
const DEFAULT_LOCALE = "en"
|
|
@@ -24,10 +37,22 @@ const DEFAULT_LOCALE = "en"
|
|
|
24
37
|
* missing wrapper echoes the key (visible + greppable) instead of crashing a
|
|
25
38
|
* widget that is perfectly renderable in English.
|
|
26
39
|
*/
|
|
27
|
-
const DEFAULT_VALUE
|
|
40
|
+
const DEFAULT_VALUE = {
|
|
41
|
+
locale: DEFAULT_LOCALE,
|
|
42
|
+
t: (key) => key,
|
|
43
|
+
messages: resolveToolkitMessages(DEFAULT_LOCALE),
|
|
44
|
+
} satisfies Required<LocaleContextValue>
|
|
28
45
|
|
|
29
46
|
const LocaleContext = createContext<LocaleContextValue | null>(null)
|
|
30
47
|
|
|
48
|
+
/** The toolkit-only locale a {@link ToolkitLocaleFallback} binds (no `t`). */
|
|
49
|
+
interface ToolkitLocaleScope {
|
|
50
|
+
locale: string
|
|
51
|
+
messages: ToolkitMessages
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
const ToolkitLocaleFallbackContext = createContext<ToolkitLocaleScope | null>(null)
|
|
55
|
+
|
|
31
56
|
/** Read the active locale tag from the nearest {@link LocaleProvider}. */
|
|
32
57
|
export function useLocale(): string {
|
|
33
58
|
return useContext(LocaleContext)?.locale ?? DEFAULT_VALUE.locale
|
|
@@ -42,6 +67,56 @@ export function useTranslate(): BoundTranslate {
|
|
|
42
67
|
return useContext(LocaleContext)?.t ?? DEFAULT_VALUE.t
|
|
43
68
|
}
|
|
44
69
|
|
|
70
|
+
/**
|
|
71
|
+
* The toolkit's own UI strings for the nearest {@link LocaleProvider}'s locale
|
|
72
|
+
* (English outside a provider). Every toolkit component reads its captions,
|
|
73
|
+
* labels and accessible names here, so a German locale renders no English
|
|
74
|
+
* toolkit chrome.
|
|
75
|
+
*/
|
|
76
|
+
export function useToolkitMessages(): ToolkitMessages {
|
|
77
|
+
const provided = useContext(LocaleContext)
|
|
78
|
+
const fallback = useContext(ToolkitLocaleFallbackContext)
|
|
79
|
+
return provided?.messages ?? fallback?.messages ?? DEFAULT_VALUE.messages
|
|
80
|
+
}
|
|
81
|
+
|
|
82
|
+
/**
|
|
83
|
+
* The locale the toolkit's own text is in: the nearest {@link LocaleProvider}'s,
|
|
84
|
+
* else a {@link ToolkitLocaleFallback}'s (the host's, inside `McpAppView`),
|
|
85
|
+
* else `"en"`. Toolkit components format their numbers with it, so a count
|
|
86
|
+
* always matches the language of the sentence around it. Internal: consumer
|
|
87
|
+
* widgets read {@link useLocale}.
|
|
88
|
+
*/
|
|
89
|
+
export function useToolkitLocale(): string {
|
|
90
|
+
const provided = useContext(LocaleContext)
|
|
91
|
+
const fallback = useContext(ToolkitLocaleFallbackContext)
|
|
92
|
+
return provided?.locale ?? fallback?.locale ?? DEFAULT_VALUE.locale
|
|
93
|
+
}
|
|
94
|
+
|
|
95
|
+
/**
|
|
96
|
+
* Binds ONLY the toolkit's own strings and number format to `locale` for a
|
|
97
|
+
* subtree — the fallback `McpAppView` mounts with the host's locale. It is not
|
|
98
|
+
* a {@link LocaleProvider}: {@link useLocale} and {@link useTranslate} keep
|
|
99
|
+
* their outside-a-provider behaviour (`"en"`, echoed keys) for consumer
|
|
100
|
+
* widgets, and any `LocaleProvider` above or below wins over it.
|
|
101
|
+
*/
|
|
102
|
+
export function ToolkitLocaleFallback({
|
|
103
|
+
locale,
|
|
104
|
+
children,
|
|
105
|
+
}: {
|
|
106
|
+
locale: string
|
|
107
|
+
children: ReactNode
|
|
108
|
+
}): ReactNode {
|
|
109
|
+
const value = useMemo<ToolkitLocaleScope>(
|
|
110
|
+
() => ({ locale, messages: resolveToolkitMessages(locale) }),
|
|
111
|
+
[locale],
|
|
112
|
+
)
|
|
113
|
+
return (
|
|
114
|
+
<ToolkitLocaleFallbackContext.Provider value={value}>
|
|
115
|
+
{children}
|
|
116
|
+
</ToolkitLocaleFallbackContext.Provider>
|
|
117
|
+
)
|
|
118
|
+
}
|
|
119
|
+
|
|
45
120
|
export interface LocaleProviderProps {
|
|
46
121
|
/** The active locale tag (e.g. `"en"`, `"de"`). */
|
|
47
122
|
locale: string
|
|
@@ -51,6 +126,12 @@ export interface LocaleProviderProps {
|
|
|
51
126
|
* consumer wires the locale before any catalog exists.
|
|
52
127
|
*/
|
|
53
128
|
translator?: Translate
|
|
129
|
+
/**
|
|
130
|
+
* Override individual toolkit strings for this subtree, per catalog section
|
|
131
|
+
* (e.g. `{ listFooter: { loadMore: "Show more" } }`). Omitted entries keep the
|
|
132
|
+
* shipped `en`/`de` catalog of `locale`.
|
|
133
|
+
*/
|
|
134
|
+
toolkitMessages?: ToolkitMessagesOverride
|
|
54
135
|
children: ReactNode
|
|
55
136
|
}
|
|
56
137
|
|
|
@@ -69,13 +150,19 @@ export interface LocaleProviderProps {
|
|
|
69
150
|
* <YourWidget />
|
|
70
151
|
* </LocaleProvider>
|
|
71
152
|
*/
|
|
72
|
-
export function LocaleProvider({
|
|
153
|
+
export function LocaleProvider({
|
|
154
|
+
locale,
|
|
155
|
+
translator,
|
|
156
|
+
toolkitMessages,
|
|
157
|
+
children,
|
|
158
|
+
}: LocaleProviderProps): ReactNode {
|
|
73
159
|
const value = useMemo<LocaleContextValue>(
|
|
74
160
|
() => ({
|
|
75
161
|
locale,
|
|
76
162
|
t: translator ? (key, params) => translator(locale, key, params) : (key) => key,
|
|
163
|
+
messages: resolveToolkitMessages(locale, toolkitMessages),
|
|
77
164
|
}),
|
|
78
|
-
[locale, translator],
|
|
165
|
+
[locale, translator, toolkitMessages],
|
|
79
166
|
)
|
|
80
167
|
return <LocaleContext.Provider value={value}>{children}</LocaleContext.Provider>
|
|
81
168
|
}
|