@miragon/mcp-toolkit-ui 0.10.1
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 +36 -0
- package/dist/app/adapt-data-widget.d.ts +33 -0
- package/dist/app/adapt-data-widget.d.ts.map +1 -0
- package/dist/app/adapt-data-widget.js +35 -0
- package/dist/app/adapt-data-widget.js.map +1 -0
- package/dist/app/builder/CatalogueSheet.d.ts +13 -0
- package/dist/app/builder/CatalogueSheet.d.ts.map +1 -0
- package/dist/app/builder/CatalogueSheet.js +33 -0
- package/dist/app/builder/CatalogueSheet.js.map +1 -0
- package/dist/app/builder/PipelineStrip.d.ts +22 -0
- package/dist/app/builder/PipelineStrip.d.ts.map +1 -0
- package/dist/app/builder/PipelineStrip.js +31 -0
- package/dist/app/builder/PipelineStrip.js.map +1 -0
- package/dist/app/builder/PreviewPane.d.ts +13 -0
- package/dist/app/builder/PreviewPane.d.ts.map +1 -0
- package/dist/app/builder/PreviewPane.js +21 -0
- package/dist/app/builder/PreviewPane.js.map +1 -0
- package/dist/app/builder/SaveDialog.d.ts +14 -0
- package/dist/app/builder/SaveDialog.d.ts.map +1 -0
- package/dist/app/builder/SaveDialog.js +14 -0
- package/dist/app/builder/SaveDialog.js.map +1 -0
- package/dist/app/builder/Toolbar.d.ts +17 -0
- package/dist/app/builder/Toolbar.d.ts.map +1 -0
- package/dist/app/builder/Toolbar.js +15 -0
- package/dist/app/builder/Toolbar.js.map +1 -0
- package/dist/app/builder/Workspace.d.ts +28 -0
- package/dist/app/builder/Workspace.d.ts.map +1 -0
- package/dist/app/builder/Workspace.js +117 -0
- package/dist/app/builder/Workspace.js.map +1 -0
- package/dist/app/builder/builder-model.d.ts +86 -0
- package/dist/app/builder/builder-model.d.ts.map +1 -0
- package/dist/app/builder/builder-model.js +174 -0
- package/dist/app/builder/builder-model.js.map +1 -0
- package/dist/app/builder/builder-reducer.d.ts +71 -0
- package/dist/app/builder/builder-reducer.d.ts.map +1 -0
- package/dist/app/builder/builder-reducer.js +201 -0
- package/dist/app/builder/builder-reducer.js.map +1 -0
- package/dist/app/builder/labels.d.ts +78 -0
- package/dist/app/builder/labels.d.ts.map +1 -0
- package/dist/app/builder/labels.js +71 -0
- package/dist/app/builder/labels.js.map +1 -0
- package/dist/app/builder/status-chip.d.ts +10 -0
- package/dist/app/builder/status-chip.d.ts.map +1 -0
- package/dist/app/builder/status-chip.js +16 -0
- package/dist/app/builder/status-chip.js.map +1 -0
- package/dist/app/host-bridge.d.ts +211 -0
- package/dist/app/host-bridge.d.ts.map +1 -0
- package/dist/app/host-bridge.js +247 -0
- package/dist/app/host-bridge.js.map +1 -0
- package/dist/app/index.d.ts +16 -0
- package/dist/app/index.d.ts.map +1 -0
- package/dist/app/index.js +18 -0
- package/dist/app/index.js.map +1 -0
- package/dist/app/layout-builder.d.ts +48 -0
- package/dist/app/layout-builder.d.ts.map +1 -0
- package/dist/app/layout-builder.js +418 -0
- package/dist/app/layout-builder.js.map +1 -0
- package/dist/app/mcp-app-view.d.ts +43 -0
- package/dist/app/mcp-app-view.d.ts.map +1 -0
- package/dist/app/mcp-app-view.js +169 -0
- package/dist/app/mcp-app-view.js.map +1 -0
- package/dist/app/mcp-toolkit-app.d.ts +18 -0
- package/dist/app/mcp-toolkit-app.d.ts.map +1 -0
- package/dist/app/mcp-toolkit-app.js +22 -0
- package/dist/app/mcp-toolkit-app.js.map +1 -0
- package/dist/app/use-host-actions.d.ts +57 -0
- package/dist/app/use-host-actions.d.ts.map +1 -0
- package/dist/app/use-host-actions.js +42 -0
- package/dist/app/use-host-actions.js.map +1 -0
- package/dist/app/widget-fixture.d.ts +180 -0
- package/dist/app/widget-fixture.d.ts.map +1 -0
- package/dist/app/widget-fixture.js +273 -0
- package/dist/app/widget-fixture.js.map +1 -0
- package/dist/app/widget-props-sheet.d.ts +20 -0
- package/dist/app/widget-props-sheet.d.ts.map +1 -0
- package/dist/app/widget-props-sheet.js +87 -0
- package/dist/app/widget-props-sheet.js.map +1 -0
- package/dist/app/widget-renderer.d.ts +87 -0
- package/dist/app/widget-renderer.d.ts.map +1 -0
- package/dist/app/widget-renderer.js +105 -0
- package/dist/app/widget-renderer.js.map +1 -0
- package/dist/components/DrillButton.d.ts +22 -0
- package/dist/components/DrillButton.d.ts.map +1 -0
- package/dist/components/DrillButton.js +13 -0
- package/dist/components/DrillButton.js.map +1 -0
- package/dist/components/FilterBar.d.ts +28 -0
- package/dist/components/FilterBar.d.ts.map +1 -0
- package/dist/components/FilterBar.js +12 -0
- package/dist/components/FilterBar.js.map +1 -0
- package/dist/components/GridLayout.d.ts +26 -0
- package/dist/components/GridLayout.d.ts.map +1 -0
- package/dist/components/GridLayout.js +31 -0
- package/dist/components/GridLayout.js.map +1 -0
- package/dist/components/GroupCard.d.ts +21 -0
- package/dist/components/GroupCard.d.ts.map +1 -0
- package/dist/components/GroupCard.js +24 -0
- package/dist/components/GroupCard.js.map +1 -0
- package/dist/components/KpiGrid.d.ts +43 -0
- package/dist/components/KpiGrid.d.ts.map +1 -0
- package/dist/components/KpiGrid.js +35 -0
- package/dist/components/KpiGrid.js.map +1 -0
- package/dist/components/ListFooter.d.ts +22 -0
- package/dist/components/ListFooter.d.ts.map +1 -0
- package/dist/components/ListFooter.js +13 -0
- package/dist/components/ListFooter.js.map +1 -0
- package/dist/components/Pills.d.ts +25 -0
- package/dist/components/Pills.d.ts.map +1 -0
- package/dist/components/Pills.js +17 -0
- package/dist/components/Pills.js.map +1 -0
- package/dist/components/SectionHeading.d.ts +16 -0
- package/dist/components/SectionHeading.d.ts.map +1 -0
- package/dist/components/SectionHeading.js +10 -0
- package/dist/components/SectionHeading.js.map +1 -0
- package/dist/components/WidgetHeader.d.ts +21 -0
- package/dist/components/WidgetHeader.d.ts.map +1 -0
- package/dist/components/WidgetHeader.js +11 -0
- package/dist/components/WidgetHeader.js.map +1 -0
- package/dist/hooks/index.d.ts +11 -0
- package/dist/hooks/index.d.ts.map +1 -0
- package/dist/hooks/index.js +7 -0
- package/dist/hooks/index.js.map +1 -0
- package/dist/hooks/use-debounced-value.d.ts +7 -0
- package/dist/hooks/use-debounced-value.d.ts.map +1 -0
- package/dist/hooks/use-debounced-value.js +15 -0
- package/dist/hooks/use-debounced-value.js.map +1 -0
- package/dist/hooks/use-mobile.d.ts +6 -0
- package/dist/hooks/use-mobile.d.ts.map +1 -0
- package/dist/hooks/use-mobile.js +19 -0
- package/dist/hooks/use-mobile.js.map +1 -0
- package/dist/hooks/use-tool-query.d.ts +21 -0
- package/dist/hooks/use-tool-query.d.ts.map +1 -0
- package/dist/hooks/use-tool-query.js +47 -0
- package/dist/hooks/use-tool-query.js.map +1 -0
- package/dist/hooks/use-tool-result-recovery.d.ts +54 -0
- package/dist/hooks/use-tool-result-recovery.d.ts.map +1 -0
- package/dist/hooks/use-tool-result-recovery.js +93 -0
- package/dist/hooks/use-tool-result-recovery.js.map +1 -0
- package/dist/hooks/use-view-data.d.ts +19 -0
- package/dist/hooks/use-view-data.d.ts.map +1 -0
- package/dist/hooks/use-view-data.js +18 -0
- package/dist/hooks/use-view-data.js.map +1 -0
- package/dist/hooks/use-view-tool-query.d.ts +18 -0
- package/dist/hooks/use-view-tool-query.d.ts.map +1 -0
- package/dist/hooks/use-view-tool-query.js +29 -0
- package/dist/hooks/use-view-tool-query.js.map +1 -0
- package/dist/index.d.ts +47 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +56 -0
- package/dist/index.js.map +1 -0
- package/dist/lib/parse-tool-result.d.ts +39 -0
- package/dist/lib/parse-tool-result.d.ts.map +1 -0
- package/dist/lib/parse-tool-result.js +66 -0
- package/dist/lib/parse-tool-result.js.map +1 -0
- package/dist/lib/tone-utils.d.ts +18 -0
- package/dist/lib/tone-utils.d.ts.map +1 -0
- package/dist/lib/tone-utils.js +25 -0
- package/dist/lib/tone-utils.js.map +1 -0
- package/dist/lib/utils.d.ts +3 -0
- package/dist/lib/utils.d.ts.map +1 -0
- package/dist/lib/utils.js +6 -0
- package/dist/lib/utils.js.map +1 -0
- package/dist/locale/index.d.ts +3 -0
- package/dist/locale/index.d.ts.map +1 -0
- package/dist/locale/index.js +7 -0
- package/dist/locale/index.js.map +1 -0
- package/dist/locale/locale-provider.d.ts +50 -0
- package/dist/locale/locale-provider.d.ts.map +1 -0
- package/dist/locale/locale-provider.js +47 -0
- package/dist/locale/locale-provider.js.map +1 -0
- package/dist/primitives/alert.d.ts +10 -0
- package/dist/primitives/alert.d.ts.map +1 -0
- package/dist/primitives/alert.js +25 -0
- package/dist/primitives/alert.js.map +1 -0
- package/dist/primitives/badge.d.ts +8 -0
- package/dist/primitives/badge.d.ts.map +1 -0
- package/dist/primitives/badge.js +34 -0
- package/dist/primitives/badge.js.map +1 -0
- package/dist/primitives/button.d.ts +11 -0
- package/dist/primitives/button.d.ts.map +1 -0
- package/dist/primitives/button.js +36 -0
- package/dist/primitives/button.js.map +1 -0
- package/dist/primitives/card.d.ts +12 -0
- package/dist/primitives/card.d.ts.map +1 -0
- package/dist/primitives/card.js +25 -0
- package/dist/primitives/card.js.map +1 -0
- package/dist/primitives/dialog.d.ts +18 -0
- package/dist/primitives/dialog.d.ts.map +1 -0
- package/dist/primitives/dialog.js +38 -0
- package/dist/primitives/dialog.js.map +1 -0
- package/dist/primitives/input.d.ts +4 -0
- package/dist/primitives/input.d.ts.map +1 -0
- package/dist/primitives/input.js +7 -0
- package/dist/primitives/input.js.map +1 -0
- package/dist/primitives/scroll-area.d.ts +6 -0
- package/dist/primitives/scroll-area.d.ts.map +1 -0
- package/dist/primitives/scroll-area.js +11 -0
- package/dist/primitives/scroll-area.js.map +1 -0
- package/dist/primitives/select.d.ts +16 -0
- package/dist/primitives/select.d.ts.map +1 -0
- package/dist/primitives/select.js +38 -0
- package/dist/primitives/select.js.map +1 -0
- package/dist/primitives/separator.d.ts +4 -0
- package/dist/primitives/separator.d.ts.map +1 -0
- package/dist/primitives/separator.js +9 -0
- package/dist/primitives/separator.js.map +1 -0
- package/dist/primitives/sheet.d.ts +15 -0
- package/dist/primitives/sheet.d.ts.map +1 -0
- package/dist/primitives/sheet.js +41 -0
- package/dist/primitives/sheet.js.map +1 -0
- package/dist/primitives/skeleton.d.ts +3 -0
- package/dist/primitives/skeleton.d.ts.map +1 -0
- package/dist/primitives/skeleton.js +7 -0
- package/dist/primitives/skeleton.js.map +1 -0
- package/dist/primitives/switch.d.ts +5 -0
- package/dist/primitives/switch.d.ts.map +1 -0
- package/dist/primitives/switch.js +8 -0
- package/dist/primitives/switch.js.map +1 -0
- package/dist/primitives/table.d.ts +11 -0
- package/dist/primitives/table.d.ts.map +1 -0
- package/dist/primitives/table.js +28 -0
- package/dist/primitives/table.js.map +1 -0
- package/dist/primitives/tabs.d.ts +12 -0
- package/dist/primitives/tabs.d.ts.map +1 -0
- package/dist/primitives/tabs.js +29 -0
- package/dist/primitives/tabs.js.map +1 -0
- package/dist/providers/query-provider.d.ts +11 -0
- package/dist/providers/query-provider.d.ts.map +1 -0
- package/dist/providers/query-provider.js +20 -0
- package/dist/providers/query-provider.js.map +1 -0
- package/dist/theme/create-theme.d.ts +130 -0
- package/dist/theme/create-theme.d.ts.map +1 -0
- package/dist/theme/create-theme.js +65 -0
- package/dist/theme/create-theme.js.map +1 -0
- package/dist/theme/index.d.ts +7 -0
- package/dist/theme/index.d.ts.map +1 -0
- package/dist/theme/index.js +7 -0
- package/dist/theme/index.js.map +1 -0
- package/dist/theme/presets.d.ts +25 -0
- package/dist/theme/presets.d.ts.map +1 -0
- package/dist/theme/presets.js +68 -0
- package/dist/theme/presets.js.map +1 -0
- package/dist/theme/theme-provider.d.ts +69 -0
- package/dist/theme/theme-provider.d.ts.map +1 -0
- package/dist/theme/theme-provider.js +79 -0
- package/dist/theme/theme-provider.js.map +1 -0
- package/package.json +71 -0
- package/src/app/adapt-data-widget.tsx +51 -0
- package/src/app/builder/CatalogueSheet.tsx +230 -0
- package/src/app/builder/PipelineStrip.tsx +260 -0
- package/src/app/builder/PreviewPane.tsx +72 -0
- package/src/app/builder/SaveDialog.tsx +95 -0
- package/src/app/builder/Toolbar.tsx +95 -0
- package/src/app/builder/Workspace.tsx +483 -0
- package/src/app/builder/builder-model.test.ts +351 -0
- package/src/app/builder/builder-model.ts +213 -0
- package/src/app/builder/builder-reducer.test.ts +441 -0
- package/src/app/builder/builder-reducer.ts +289 -0
- package/src/app/builder/labels.ts +139 -0
- package/src/app/builder/status-chip.tsx +37 -0
- package/src/app/host-bridge.test.ts +206 -0
- package/src/app/host-bridge.tsx +371 -0
- package/src/app/index.ts +51 -0
- package/src/app/layout-builder.tsx +872 -0
- package/src/app/mcp-app-view.tsx +367 -0
- package/src/app/mcp-toolkit-app.tsx +25 -0
- package/src/app/use-host-actions.test.ts +16 -0
- package/src/app/use-host-actions.tsx +88 -0
- package/src/app/widget-fixture.test.ts +108 -0
- package/src/app/widget-fixture.tsx +441 -0
- package/src/app/widget-props-sheet.tsx +285 -0
- package/src/app/widget-renderer.test.ts +42 -0
- package/src/app/widget-renderer.tsx +200 -0
- package/src/components/DrillButton.tsx +37 -0
- package/src/components/FilterBar.tsx +68 -0
- package/src/components/GridLayout.tsx +49 -0
- package/src/components/GroupCard.tsx +52 -0
- package/src/components/KpiGrid.tsx +134 -0
- package/src/components/ListFooter.tsx +48 -0
- package/src/components/Pills.tsx +45 -0
- package/src/components/SectionHeading.tsx +26 -0
- package/src/components/WidgetHeader.tsx +51 -0
- package/src/globals.css +168 -0
- package/src/hooks/index.ts +17 -0
- package/src/hooks/use-debounced-value.ts +15 -0
- package/src/hooks/use-mobile.ts +24 -0
- package/src/hooks/use-tool-query.ts +63 -0
- package/src/hooks/use-tool-result-recovery.test.ts +65 -0
- package/src/hooks/use-tool-result-recovery.ts +144 -0
- package/src/hooks/use-view-data.ts +31 -0
- package/src/hooks/use-view-tool-query.ts +38 -0
- package/src/index.ts +134 -0
- package/src/lib/parse-tool-result.test.ts +139 -0
- package/src/lib/parse-tool-result.ts +89 -0
- package/src/lib/tone-utils.test.ts +35 -0
- package/src/lib/tone-utils.ts +38 -0
- package/src/lib/utils.ts +6 -0
- package/src/locale/index.ts +7 -0
- package/src/locale/locale-provider.tsx +81 -0
- package/src/primitives/alert.tsx +60 -0
- package/src/primitives/badge.tsx +49 -0
- package/src/primitives/button.tsx +62 -0
- package/src/primitives/card.tsx +92 -0
- package/src/primitives/dialog.tsx +144 -0
- package/src/primitives/input.tsx +21 -0
- package/src/primitives/scroll-area.tsx +54 -0
- package/src/primitives/select.tsx +173 -0
- package/src/primitives/separator.tsx +21 -0
- package/src/primitives/sheet.tsx +134 -0
- package/src/primitives/skeleton.tsx +13 -0
- package/src/primitives/switch.tsx +24 -0
- package/src/primitives/table.tsx +87 -0
- package/src/primitives/tabs.tsx +79 -0
- package/src/providers/query-provider.tsx +38 -0
- package/src/theme/create-theme.test.ts +108 -0
- package/src/theme/create-theme.ts +158 -0
- package/src/theme/index.ts +9 -0
- package/src/theme/presets.ts +82 -0
- package/src/theme/theme-provider.tsx +152 -0
- package/src/ui-catalog.test.ts +112 -0
- package/ui-catalog.json +1280 -0
|
@@ -0,0 +1,68 @@
|
|
|
1
|
+
import { createTheme } from "./create-theme.js";
|
|
2
|
+
/**
|
|
3
|
+
* Ready-made white-label themes — a demonstration of {@link createTheme} and a
|
|
4
|
+
* starting point a client can fork. Each preset sets a distinct brand `primary`,
|
|
5
|
+
* a matching `ring`/`accent`, and a `radius`, plus a `dark` override that
|
|
6
|
+
* brightens the brand colour for legibility on dark surfaces (mirroring how
|
|
7
|
+
* `globals.css` brightens tokens under `.dark`).
|
|
8
|
+
*
|
|
9
|
+
* Colours are authored in `oklch` to stay consistent with the toolkit's token
|
|
10
|
+
* palette in `globals.css`. Apply one with `<ThemeProvider theme={themePresets.violet}>`.
|
|
11
|
+
*/
|
|
12
|
+
export const themePresets = {
|
|
13
|
+
/**
|
|
14
|
+
* The toolkit's own brand: a confident indigo-blue with a slightly tighter
|
|
15
|
+
* radius. A sensible default when a client has no brand of their own yet.
|
|
16
|
+
*/
|
|
17
|
+
miragon: createTheme({
|
|
18
|
+
primary: "oklch(0.52 0.21 264)",
|
|
19
|
+
primaryForeground: "oklch(0.985 0 0)",
|
|
20
|
+
accent: "oklch(0.95 0.03 264)",
|
|
21
|
+
accentForeground: "oklch(0.32 0.12 264)",
|
|
22
|
+
ring: "oklch(0.52 0.21 264)",
|
|
23
|
+
radius: "0.5rem",
|
|
24
|
+
}, {
|
|
25
|
+
dark: {
|
|
26
|
+
primary: "oklch(0.7 0.16 264)",
|
|
27
|
+
primaryForeground: "oklch(0.18 0.02 264)",
|
|
28
|
+
accent: "oklch(0.32 0.06 264)",
|
|
29
|
+
accentForeground: "oklch(0.97 0 0)",
|
|
30
|
+
ring: "oklch(0.7 0.16 264)",
|
|
31
|
+
},
|
|
32
|
+
}),
|
|
33
|
+
/** A vivid violet brand with rounder corners — playful, consumer-facing. */
|
|
34
|
+
violet: createTheme({
|
|
35
|
+
primary: "oklch(0.55 0.24 295)",
|
|
36
|
+
primaryForeground: "oklch(0.985 0 0)",
|
|
37
|
+
accent: "oklch(0.95 0.04 295)",
|
|
38
|
+
accentForeground: "oklch(0.34 0.14 295)",
|
|
39
|
+
ring: "oklch(0.55 0.24 295)",
|
|
40
|
+
radius: "0.875rem",
|
|
41
|
+
}, {
|
|
42
|
+
dark: {
|
|
43
|
+
primary: "oklch(0.72 0.18 295)",
|
|
44
|
+
primaryForeground: "oklch(0.18 0.03 295)",
|
|
45
|
+
accent: "oklch(0.33 0.08 295)",
|
|
46
|
+
accentForeground: "oklch(0.97 0 0)",
|
|
47
|
+
ring: "oklch(0.72 0.18 295)",
|
|
48
|
+
},
|
|
49
|
+
}),
|
|
50
|
+
/** A grounded emerald brand with a crisp, near-square radius — enterprise. */
|
|
51
|
+
emerald: createTheme({
|
|
52
|
+
primary: "oklch(0.58 0.15 162)",
|
|
53
|
+
primaryForeground: "oklch(0.985 0 0)",
|
|
54
|
+
accent: "oklch(0.95 0.04 162)",
|
|
55
|
+
accentForeground: "oklch(0.34 0.1 162)",
|
|
56
|
+
ring: "oklch(0.58 0.15 162)",
|
|
57
|
+
radius: "0.375rem",
|
|
58
|
+
}, {
|
|
59
|
+
dark: {
|
|
60
|
+
primary: "oklch(0.72 0.15 162)",
|
|
61
|
+
primaryForeground: "oklch(0.17 0.03 162)",
|
|
62
|
+
accent: "oklch(0.32 0.07 162)",
|
|
63
|
+
accentForeground: "oklch(0.97 0 0)",
|
|
64
|
+
ring: "oklch(0.72 0.15 162)",
|
|
65
|
+
},
|
|
66
|
+
}),
|
|
67
|
+
};
|
|
68
|
+
//# sourceMappingURL=presets.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"presets.js","sourceRoot":"","sources":["../../src/theme/presets.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,WAAW,EAAwB,MAAM,mBAAmB,CAAA;AAErE;;;;;;;;;GASG;AACH,MAAM,CAAC,MAAM,YAAY,GAAG;IAC1B;;;OAGG;IACH,OAAO,EAAE,WAAW,CAClB;QACE,OAAO,EAAE,sBAAsB;QAC/B,iBAAiB,EAAE,kBAAkB;QACrC,MAAM,EAAE,sBAAsB;QAC9B,gBAAgB,EAAE,sBAAsB;QACxC,IAAI,EAAE,sBAAsB;QAC5B,MAAM,EAAE,QAAQ;KACjB,EACD;QACE,IAAI,EAAE;YACJ,OAAO,EAAE,qBAAqB;YAC9B,iBAAiB,EAAE,sBAAsB;YACzC,MAAM,EAAE,sBAAsB;YAC9B,gBAAgB,EAAE,iBAAiB;YACnC,IAAI,EAAE,qBAAqB;SAC5B;KACF,CACF;IAED,4EAA4E;IAC5E,MAAM,EAAE,WAAW,CACjB;QACE,OAAO,EAAE,sBAAsB;QAC/B,iBAAiB,EAAE,kBAAkB;QACrC,MAAM,EAAE,sBAAsB;QAC9B,gBAAgB,EAAE,sBAAsB;QACxC,IAAI,EAAE,sBAAsB;QAC5B,MAAM,EAAE,UAAU;KACnB,EACD;QACE,IAAI,EAAE;YACJ,OAAO,EAAE,sBAAsB;YAC/B,iBAAiB,EAAE,sBAAsB;YACzC,MAAM,EAAE,sBAAsB;YAC9B,gBAAgB,EAAE,iBAAiB;YACnC,IAAI,EAAE,sBAAsB;SAC7B;KACF,CACF;IAED,8EAA8E;IAC9E,OAAO,EAAE,WAAW,CAClB;QACE,OAAO,EAAE,sBAAsB;QAC/B,iBAAiB,EAAE,kBAAkB;QACrC,MAAM,EAAE,sBAAsB;QAC9B,gBAAgB,EAAE,qBAAqB;QACvC,IAAI,EAAE,sBAAsB;QAC5B,MAAM,EAAE,UAAU;KACnB,EACD;QACE,IAAI,EAAE;YACJ,OAAO,EAAE,sBAAsB;YAC/B,iBAAiB,EAAE,sBAAsB;YACzC,MAAM,EAAE,sBAAsB;YAC9B,gBAAgB,EAAE,iBAAiB;YACnC,IAAI,EAAE,sBAAsB;SAC7B;KACF,CACF;CACwC,CAAA"}
|
|
@@ -0,0 +1,69 @@
|
|
|
1
|
+
import { type ReactNode } from "react";
|
|
2
|
+
import type { ThemeDefinition } from "./create-theme.js";
|
|
3
|
+
/**
|
|
4
|
+
* How the `.dark` class is resolved on the theme scope:
|
|
5
|
+
* - `"light"` / `"dark"` — forced, ignores the OS preference.
|
|
6
|
+
* - `"system"` — follows `prefers-color-scheme` via `matchMedia`, updating live.
|
|
7
|
+
*
|
|
8
|
+
* A host that already knows the colour scheme (e.g. `HostBridge.theme`) can pass
|
|
9
|
+
* its value straight through as `mode` so the white-label theme tracks the host.
|
|
10
|
+
*/
|
|
11
|
+
export type ThemeMode = "light" | "dark" | "system";
|
|
12
|
+
/** The value exposed by {@link useTheme}. */
|
|
13
|
+
export interface ThemeContextValue {
|
|
14
|
+
/** The active theme definition, or `null` when only a mode is being managed. */
|
|
15
|
+
theme: ThemeDefinition | null;
|
|
16
|
+
/** The mode as requested on the provider (may be `"system"`). */
|
|
17
|
+
mode: ThemeMode;
|
|
18
|
+
/** The mode actually applied right now (`"system"` resolved to light/dark). */
|
|
19
|
+
resolvedMode: "light" | "dark";
|
|
20
|
+
}
|
|
21
|
+
/**
|
|
22
|
+
* Read the active theme/mode from the nearest {@link ThemeProvider}. Throws when
|
|
23
|
+
* called outside a provider so a missing wrapper fails loudly rather than
|
|
24
|
+
* silently rendering the default theme.
|
|
25
|
+
*/
|
|
26
|
+
export declare function useTheme(): ThemeContextValue;
|
|
27
|
+
/** Props for {@link ThemeProvider}. */
|
|
28
|
+
export interface ThemeProviderProps {
|
|
29
|
+
/**
|
|
30
|
+
* The white-label theme to apply (from {@link createTheme} or `themePresets`).
|
|
31
|
+
* Omit to manage only the light/dark `mode` against the toolkit defaults.
|
|
32
|
+
*/
|
|
33
|
+
theme?: ThemeDefinition;
|
|
34
|
+
/**
|
|
35
|
+
* Colour-scheme mode. Defaults to `"light"`. Pass `HostBridge.theme` through
|
|
36
|
+
* here to follow the host, or `"system"` to track the OS preference.
|
|
37
|
+
*/
|
|
38
|
+
mode?: ThemeMode;
|
|
39
|
+
/**
|
|
40
|
+
* The HTML element to render as the scope wrapper. Defaults to `"div"`. Use
|
|
41
|
+
* `"span"` for inline contexts; any intrinsic element with a `style`/className
|
|
42
|
+
* works.
|
|
43
|
+
*/
|
|
44
|
+
as?: "div" | "span" | "section" | "main";
|
|
45
|
+
/** Extra classes merged onto the scope wrapper. */
|
|
46
|
+
className?: string;
|
|
47
|
+
children: ReactNode;
|
|
48
|
+
}
|
|
49
|
+
/**
|
|
50
|
+
* Apply a white-label {@link ThemeDefinition} to a subtree. Renders a wrapper
|
|
51
|
+
* element carrying the theme's CSS variables as inline `style`, so they override
|
|
52
|
+
* the `:root` defaults for every descendant — `Card`, `Button`, `bg-card`,
|
|
53
|
+
* `text-primary`, and `rounded-lg` all re-skin without touching the widgets.
|
|
54
|
+
*
|
|
55
|
+
* Dark mode is handled at the scope: the `.dark` class is toggled on the wrapper
|
|
56
|
+
* (not `<html>`) per the resolved {@link ThemeMode}, and the theme's `darkVars`
|
|
57
|
+
* are layered on under it. This keeps theming local — two differently themed
|
|
58
|
+
* subtrees (e.g. a brand preview gallery) coexist on one page.
|
|
59
|
+
*
|
|
60
|
+
* Uses only React + the DOM (no `mcp-use/react`), so it ships from the root
|
|
61
|
+
* barrel and works in a host-free standalone app, a host, or SSR alike.
|
|
62
|
+
*
|
|
63
|
+
* @example
|
|
64
|
+
* <ThemeProvider theme={themePresets.violet} mode={host.theme ?? "system"}>
|
|
65
|
+
* <YourWidget />
|
|
66
|
+
* </ThemeProvider>
|
|
67
|
+
*/
|
|
68
|
+
export declare function ThemeProvider({ theme, mode, as: As, className, children, }: ThemeProviderProps): ReactNode;
|
|
69
|
+
//# sourceMappingURL=theme-provider.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"theme-provider.d.ts","sourceRoot":"","sources":["../../src/theme/theme-provider.tsx"],"names":[],"mappings":"AAAA,OAAO,EAOL,KAAK,SAAS,EACf,MAAM,OAAO,CAAA;AACd,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,mBAAmB,CAAA;AAExD;;;;;;;GAOG;AACH,MAAM,MAAM,SAAS,GAAG,OAAO,GAAG,MAAM,GAAG,QAAQ,CAAA;AAEnD,6CAA6C;AAC7C,MAAM,WAAW,iBAAiB;IAChC,gFAAgF;IAChF,KAAK,EAAE,eAAe,GAAG,IAAI,CAAA;IAC7B,iEAAiE;IACjE,IAAI,EAAE,SAAS,CAAA;IACf,+EAA+E;IAC/E,YAAY,EAAE,OAAO,GAAG,MAAM,CAAA;CAC/B;AAID;;;;GAIG;AACH,wBAAgB,QAAQ,IAAI,iBAAiB,CAM5C;AA6BD,uCAAuC;AACvC,MAAM,WAAW,kBAAkB;IACjC;;;OAGG;IACH,KAAK,CAAC,EAAE,eAAe,CAAA;IACvB;;;OAGG;IACH,IAAI,CAAC,EAAE,SAAS,CAAA;IAChB;;;;OAIG;IACH,EAAE,CAAC,EAAE,KAAK,GAAG,MAAM,GAAG,SAAS,GAAG,MAAM,CAAA;IACxC,mDAAmD;IACnD,SAAS,CAAC,EAAE,MAAM,CAAA;IAClB,QAAQ,EAAE,SAAS,CAAA;CACpB;AAED;;;;;;;;;;;;;;;;;;GAkBG;AACH,wBAAgB,aAAa,CAAC,EAC5B,KAAK,EACL,IAAc,EACd,EAAE,EAAE,EAAU,EACd,SAAS,EACT,QAAQ,GACT,EAAE,kBAAkB,GAAG,SAAS,CA8BhC"}
|
|
@@ -0,0 +1,79 @@
|
|
|
1
|
+
import { jsx as _jsx } from "react/jsx-runtime";
|
|
2
|
+
import { createContext, useContext, useEffect, useMemo, useState, } from "react";
|
|
3
|
+
const ThemeContext = createContext(null);
|
|
4
|
+
/**
|
|
5
|
+
* Read the active theme/mode from the nearest {@link ThemeProvider}. Throws when
|
|
6
|
+
* called outside a provider so a missing wrapper fails loudly rather than
|
|
7
|
+
* silently rendering the default theme.
|
|
8
|
+
*/
|
|
9
|
+
export function useTheme() {
|
|
10
|
+
const value = useContext(ThemeContext);
|
|
11
|
+
if (!value) {
|
|
12
|
+
throw new Error("useTheme() must be used within a <ThemeProvider>.");
|
|
13
|
+
}
|
|
14
|
+
return value;
|
|
15
|
+
}
|
|
16
|
+
/**
|
|
17
|
+
* Resolve `"system"` to a concrete `"light"` | `"dark"` and keep it in sync with
|
|
18
|
+
* the OS preference. SSR-safe: returns `"light"` until mounted (no `window`),
|
|
19
|
+
* then subscribes to `matchMedia` on the client. Forced modes short-circuit the
|
|
20
|
+
* media query entirely.
|
|
21
|
+
*/
|
|
22
|
+
function useResolvedMode(mode) {
|
|
23
|
+
const [systemMode, setSystemMode] = useState("light");
|
|
24
|
+
useEffect(() => {
|
|
25
|
+
if (mode !== "system")
|
|
26
|
+
return;
|
|
27
|
+
if (typeof window === "undefined" || typeof window.matchMedia !== "function")
|
|
28
|
+
return;
|
|
29
|
+
const query = window.matchMedia("(prefers-color-scheme: dark)");
|
|
30
|
+
const sync = () => {
|
|
31
|
+
setSystemMode(query.matches ? "dark" : "light");
|
|
32
|
+
};
|
|
33
|
+
sync();
|
|
34
|
+
query.addEventListener("change", sync);
|
|
35
|
+
return () => {
|
|
36
|
+
query.removeEventListener("change", sync);
|
|
37
|
+
};
|
|
38
|
+
}, [mode]);
|
|
39
|
+
return mode === "system" ? systemMode : mode;
|
|
40
|
+
}
|
|
41
|
+
/**
|
|
42
|
+
* Apply a white-label {@link ThemeDefinition} to a subtree. Renders a wrapper
|
|
43
|
+
* element carrying the theme's CSS variables as inline `style`, so they override
|
|
44
|
+
* the `:root` defaults for every descendant — `Card`, `Button`, `bg-card`,
|
|
45
|
+
* `text-primary`, and `rounded-lg` all re-skin without touching the widgets.
|
|
46
|
+
*
|
|
47
|
+
* Dark mode is handled at the scope: the `.dark` class is toggled on the wrapper
|
|
48
|
+
* (not `<html>`) per the resolved {@link ThemeMode}, and the theme's `darkVars`
|
|
49
|
+
* are layered on under it. This keeps theming local — two differently themed
|
|
50
|
+
* subtrees (e.g. a brand preview gallery) coexist on one page.
|
|
51
|
+
*
|
|
52
|
+
* Uses only React + the DOM (no `mcp-use/react`), so it ships from the root
|
|
53
|
+
* barrel and works in a host-free standalone app, a host, or SSR alike.
|
|
54
|
+
*
|
|
55
|
+
* @example
|
|
56
|
+
* <ThemeProvider theme={themePresets.violet} mode={host.theme ?? "system"}>
|
|
57
|
+
* <YourWidget />
|
|
58
|
+
* </ThemeProvider>
|
|
59
|
+
*/
|
|
60
|
+
export function ThemeProvider({ theme, mode = "light", as: As = "div", className, children, }) {
|
|
61
|
+
const resolvedMode = useResolvedMode(mode);
|
|
62
|
+
const isDark = resolvedMode === "dark";
|
|
63
|
+
// Merge the light vars with the dark overrides only when dark is active, so a
|
|
64
|
+
// dark scope gets the brand's dark palette on top of `.dark`'s defaults.
|
|
65
|
+
const style = useMemo(() => {
|
|
66
|
+
if (!theme)
|
|
67
|
+
return {};
|
|
68
|
+
if (isDark && theme.darkVars) {
|
|
69
|
+
return { ...theme.vars, ...theme.darkVars };
|
|
70
|
+
}
|
|
71
|
+
return theme.vars;
|
|
72
|
+
}, [theme, isDark]);
|
|
73
|
+
const value = useMemo(() => ({ theme: theme ?? null, mode, resolvedMode }), [theme, mode, resolvedMode]);
|
|
74
|
+
const classes = [isDark ? "dark" : undefined, "bg-background text-foreground", className]
|
|
75
|
+
.filter(Boolean)
|
|
76
|
+
.join(" ");
|
|
77
|
+
return (_jsx(ThemeContext.Provider, { value: value, children: _jsx(As, { className: classes, style: style, "data-theme-mode": resolvedMode, children: children }) }));
|
|
78
|
+
}
|
|
79
|
+
//# sourceMappingURL=theme-provider.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"theme-provider.js","sourceRoot":"","sources":["../../src/theme/theme-provider.tsx"],"names":[],"mappings":";AAAA,OAAO,EACL,aAAa,EACb,UAAU,EACV,SAAS,EACT,OAAO,EACP,QAAQ,GAGT,MAAM,OAAO,CAAA;AAuBd,MAAM,YAAY,GAAG,aAAa,CAA2B,IAAI,CAAC,CAAA;AAElE;;;;GAIG;AACH,MAAM,UAAU,QAAQ;IACtB,MAAM,KAAK,GAAG,UAAU,CAAC,YAAY,CAAC,CAAA;IACtC,IAAI,CAAC,KAAK,EAAE,CAAC;QACX,MAAM,IAAI,KAAK,CAAC,mDAAmD,CAAC,CAAA;IACtE,CAAC;IACD,OAAO,KAAK,CAAA;AACd,CAAC;AAED;;;;;GAKG;AACH,SAAS,eAAe,CAAC,IAAe;IACtC,MAAM,CAAC,UAAU,EAAE,aAAa,CAAC,GAAG,QAAQ,CAAmB,OAAO,CAAC,CAAA;IAEvE,SAAS,CAAC,GAAG,EAAE;QACb,IAAI,IAAI,KAAK,QAAQ;YAAE,OAAM;QAC7B,IAAI,OAAO,MAAM,KAAK,WAAW,IAAI,OAAO,MAAM,CAAC,UAAU,KAAK,UAAU;YAAE,OAAM;QAEpF,MAAM,KAAK,GAAG,MAAM,CAAC,UAAU,CAAC,8BAA8B,CAAC,CAAA;QAC/D,MAAM,IAAI,GAAG,GAAG,EAAE;YAChB,aAAa,CAAC,KAAK,CAAC,OAAO,CAAC,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,OAAO,CAAC,CAAA;QACjD,CAAC,CAAA;QACD,IAAI,EAAE,CAAA;QACN,KAAK,CAAC,gBAAgB,CAAC,QAAQ,EAAE,IAAI,CAAC,CAAA;QACtC,OAAO,GAAG,EAAE;YACV,KAAK,CAAC,mBAAmB,CAAC,QAAQ,EAAE,IAAI,CAAC,CAAA;QAC3C,CAAC,CAAA;IACH,CAAC,EAAE,CAAC,IAAI,CAAC,CAAC,CAAA;IAEV,OAAO,IAAI,KAAK,QAAQ,CAAC,CAAC,CAAC,UAAU,CAAC,CAAC,CAAC,IAAI,CAAA;AAC9C,CAAC;AAyBD;;;;;;;;;;;;;;;;;;GAkBG;AACH,MAAM,UAAU,aAAa,CAAC,EAC5B,KAAK,EACL,IAAI,GAAG,OAAO,EACd,EAAE,EAAE,EAAE,GAAG,KAAK,EACd,SAAS,EACT,QAAQ,GACW;IACnB,MAAM,YAAY,GAAG,eAAe,CAAC,IAAI,CAAC,CAAA;IAC1C,MAAM,MAAM,GAAG,YAAY,KAAK,MAAM,CAAA;IAEtC,8EAA8E;IAC9E,yEAAyE;IACzE,MAAM,KAAK,GAAG,OAAO,CAAgB,GAAG,EAAE;QACxC,IAAI,CAAC,KAAK;YAAE,OAAO,EAAE,CAAA;QACrB,IAAI,MAAM,IAAI,KAAK,CAAC,QAAQ,EAAE,CAAC;YAC7B,OAAO,EAAE,GAAG,KAAK,CAAC,IAAI,EAAE,GAAG,KAAK,CAAC,QAAQ,EAAE,CAAA;QAC7C,CAAC;QACD,OAAO,KAAK,CAAC,IAAI,CAAA;IACnB,CAAC,EAAE,CAAC,KAAK,EAAE,MAAM,CAAC,CAAC,CAAA;IAEnB,MAAM,KAAK,GAAG,OAAO,CACnB,GAAG,EAAE,CAAC,CAAC,EAAE,KAAK,EAAE,KAAK,IAAI,IAAI,EAAE,IAAI,EAAE,YAAY,EAAE,CAAC,EACpD,CAAC,KAAK,EAAE,IAAI,EAAE,YAAY,CAAC,CAC5B,CAAA;IAED,MAAM,OAAO,GAAG,CAAC,MAAM,CAAC,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,SAAS,EAAE,+BAA+B,EAAE,SAAS,CAAC;SACtF,MAAM,CAAC,OAAO,CAAC;SACf,IAAI,CAAC,GAAG,CAAC,CAAA;IAEZ,OAAO,CACL,KAAC,YAAY,CAAC,QAAQ,IAAC,KAAK,EAAE,KAAK,YACjC,KAAC,EAAE,IAAC,SAAS,EAAE,OAAO,EAAE,KAAK,EAAE,KAAK,qBAAmB,YAAY,YAChE,QAAQ,GACN,GACiB,CACzB,CAAA;AACH,CAAC"}
|
package/package.json
ADDED
|
@@ -0,0 +1,71 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@miragon/mcp-toolkit-ui",
|
|
3
|
+
"version": "0.10.1",
|
|
4
|
+
"description": "React UI for MCP servers: shadcn primitives, composite components, TanStack Query hooks, and the MCP App shell (McpAppView + WidgetRenderer).",
|
|
5
|
+
"type": "module",
|
|
6
|
+
"sideEffects": [
|
|
7
|
+
"**/*.css"
|
|
8
|
+
],
|
|
9
|
+
"main": "dist/index.js",
|
|
10
|
+
"types": "dist/index.d.ts",
|
|
11
|
+
"exports": {
|
|
12
|
+
".": {
|
|
13
|
+
"types": "./dist/index.d.ts",
|
|
14
|
+
"import": "./dist/index.js"
|
|
15
|
+
},
|
|
16
|
+
"./app": {
|
|
17
|
+
"types": "./dist/app/index.d.ts",
|
|
18
|
+
"import": "./dist/app/index.js"
|
|
19
|
+
},
|
|
20
|
+
"./hooks": {
|
|
21
|
+
"types": "./dist/hooks/index.d.ts",
|
|
22
|
+
"import": "./dist/hooks/index.js"
|
|
23
|
+
},
|
|
24
|
+
"./globals.css": "./src/globals.css"
|
|
25
|
+
},
|
|
26
|
+
"files": [
|
|
27
|
+
"dist",
|
|
28
|
+
"src",
|
|
29
|
+
"ui-catalog.json",
|
|
30
|
+
"README.md"
|
|
31
|
+
],
|
|
32
|
+
"publishConfig": {
|
|
33
|
+
"access": "public"
|
|
34
|
+
},
|
|
35
|
+
"peerDependencies": {
|
|
36
|
+
"mcp-use": "1.34.5",
|
|
37
|
+
"react": "19.2.8",
|
|
38
|
+
"react-dom": "19.2.8",
|
|
39
|
+
"tailwindcss": "4.3.3",
|
|
40
|
+
"@miragon/mcp-toolkit-core": "0.10.1"
|
|
41
|
+
},
|
|
42
|
+
"dependencies": {
|
|
43
|
+
"@base-ui/react": "1.6.0",
|
|
44
|
+
"@fontsource-variable/geist": "5.3.0",
|
|
45
|
+
"@tanstack/react-query": "5.101.4",
|
|
46
|
+
"class-variance-authority": "0.7.1",
|
|
47
|
+
"clsx": "2.1.1",
|
|
48
|
+
"lucide-react": "1.25.0",
|
|
49
|
+
"radix-ui": "1.6.7",
|
|
50
|
+
"tailwind-merge": "3.6.0",
|
|
51
|
+
"tw-animate-css": "1.4.0"
|
|
52
|
+
},
|
|
53
|
+
"devDependencies": {
|
|
54
|
+
"@types/react": "19.2.17",
|
|
55
|
+
"@types/react-dom": "19.2.3",
|
|
56
|
+
"mcp-use": "1.34.5",
|
|
57
|
+
"react": "19.2.8",
|
|
58
|
+
"react-dom": "19.2.8",
|
|
59
|
+
"tailwindcss": "4.3.3",
|
|
60
|
+
"typescript": "6.0.3",
|
|
61
|
+
"vitest": "4.1.10",
|
|
62
|
+
"@miragon/mcp-toolkit-core": "0.10.1"
|
|
63
|
+
},
|
|
64
|
+
"scripts": {
|
|
65
|
+
"build": "tsc -p tsconfig.build.json",
|
|
66
|
+
"typecheck": "tsc --noEmit",
|
|
67
|
+
"test": "vitest run",
|
|
68
|
+
"lint": "eslint src --max-warnings 0",
|
|
69
|
+
"lint:fix": "eslint src --fix"
|
|
70
|
+
}
|
|
71
|
+
}
|
|
@@ -0,0 +1,51 @@
|
|
|
1
|
+
import type { ComponentType } from "react"
|
|
2
|
+
import { ModelContext } from "mcp-use/react"
|
|
3
|
+
import type { WidgetProps } from "@miragon/mcp-toolkit-core"
|
|
4
|
+
import type { WidgetComponent } from "./widget-renderer.js"
|
|
5
|
+
|
|
6
|
+
/**
|
|
7
|
+
* Builds the model-context line for an adapted widget. Receives the resolved
|
|
8
|
+
* step data (never null — the adapter skips the description while loading) plus
|
|
9
|
+
* the per-cell layout props so scope filters that only travel as props (e.g.
|
|
10
|
+
* `period` / `engine` on dashboard widgets) can be reported too.
|
|
11
|
+
*/
|
|
12
|
+
export type DescribeForModel<T> = (
|
|
13
|
+
data: NonNullable<T>,
|
|
14
|
+
props: Readonly<Record<string, unknown>>,
|
|
15
|
+
) => string
|
|
16
|
+
|
|
17
|
+
/**
|
|
18
|
+
* Wraps a "single-data" widget component (signature `({ data }: { data: T | null })`)
|
|
19
|
+
* so it can be registered as a framework {@link WidgetComponent} (which receives
|
|
20
|
+
* `WidgetProps = { keys, context, widgetProps? }`). The adapter looks up the
|
|
21
|
+
* matching step result in `context.steps` by its `_dataType` and forwards
|
|
22
|
+
* `result.data` to the wrapped widget. Lets `render-view` and `*_show_*` tools
|
|
23
|
+
* (via `buildSingleWidgetView`) share the same widget components without
|
|
24
|
+
* changing their props.
|
|
25
|
+
*
|
|
26
|
+
* Per-cell `props` from the layout (`row[].props`) are spread onto the
|
|
27
|
+
* wrapped widget as named props. This lets the same widget appear multiple
|
|
28
|
+
* times in one view with different scoping (e.g. one tab per process key).
|
|
29
|
+
*
|
|
30
|
+
* When `describeForModel` is provided the adapter wraps the widget in a
|
|
31
|
+
* `ModelContext` so the model knows what the user is looking at (view identity,
|
|
32
|
+
* active filters, headline numbers) without per-widget boilerplate. The
|
|
33
|
+
* description is only rendered once the step data is present; widgets that
|
|
34
|
+
* self-fetch when the adapter has no data (cockpit views) must render their own
|
|
35
|
+
* `<ModelContext>` instead.
|
|
36
|
+
*/
|
|
37
|
+
export function adaptDataWidget<T>(
|
|
38
|
+
Widget: ComponentType<{ data: T | null } & Record<string, unknown>>,
|
|
39
|
+
dataType: string,
|
|
40
|
+
describeForModel?: DescribeForModel<T>,
|
|
41
|
+
): WidgetComponent {
|
|
42
|
+
function AdaptedWidget({ context, widgetProps }: WidgetProps) {
|
|
43
|
+
const stepResult = Object.values(context.steps).find((s) => s._dataType === dataType)
|
|
44
|
+
const data = (stepResult?.data ?? null) as T | null
|
|
45
|
+
const widget = <Widget {...(widgetProps ?? {})} data={data} />
|
|
46
|
+
if (data == null || !describeForModel) return widget
|
|
47
|
+
return <ModelContext content={describeForModel(data, widgetProps ?? {})}>{widget}</ModelContext>
|
|
48
|
+
}
|
|
49
|
+
AdaptedWidget.displayName = `Adapted(${Widget.displayName ?? Widget.name ?? "Widget"})`
|
|
50
|
+
return AdaptedWidget
|
|
51
|
+
}
|
|
@@ -0,0 +1,230 @@
|
|
|
1
|
+
import { useMemo } from "react"
|
|
2
|
+
import { ArrowDownToLine, Library, Plus } from "lucide-react"
|
|
3
|
+
import type { AvailableStep, KeyCatalogEntry, UnreachableWidget } from "@miragon/mcp-toolkit-core"
|
|
4
|
+
import { Badge } from "../../primitives/badge.js"
|
|
5
|
+
import { Button } from "../../primitives/button.js"
|
|
6
|
+
import { ScrollArea } from "../../primitives/scroll-area.js"
|
|
7
|
+
import {
|
|
8
|
+
Sheet,
|
|
9
|
+
SheetContent,
|
|
10
|
+
SheetDescription,
|
|
11
|
+
SheetHeader,
|
|
12
|
+
SheetTitle,
|
|
13
|
+
} from "../../primitives/sheet.js"
|
|
14
|
+
import { cn } from "../../lib/utils.js"
|
|
15
|
+
import type { LayoutBuilderLabels } from "./labels.js"
|
|
16
|
+
|
|
17
|
+
// -------------------------------------------------------------------------- //
|
|
18
|
+
// Catalogue Sheet — slides in from the right
|
|
19
|
+
// -------------------------------------------------------------------------- //
|
|
20
|
+
|
|
21
|
+
export function CatalogueSheet({
|
|
22
|
+
L,
|
|
23
|
+
open,
|
|
24
|
+
onOpenChange,
|
|
25
|
+
keyCatalog,
|
|
26
|
+
availableSteps,
|
|
27
|
+
unreachableWidgets,
|
|
28
|
+
onSeedKey,
|
|
29
|
+
onAddProducingStep,
|
|
30
|
+
}: {
|
|
31
|
+
L: Required<LayoutBuilderLabels>
|
|
32
|
+
open: boolean
|
|
33
|
+
onOpenChange: (open: boolean) => void
|
|
34
|
+
keyCatalog: KeyCatalogEntry[]
|
|
35
|
+
availableSteps: AvailableStep[]
|
|
36
|
+
unreachableWidgets: UnreachableWidget[]
|
|
37
|
+
onSeedKey: (name: string) => void
|
|
38
|
+
onAddProducingStep: (key: string) => void
|
|
39
|
+
}) {
|
|
40
|
+
const producerOf = useMemo(() => {
|
|
41
|
+
const map = new Map<string, string | undefined>()
|
|
42
|
+
for (const e of keyCatalog) map.set(e.key, e.producedBySteps[0])
|
|
43
|
+
return map
|
|
44
|
+
}, [keyCatalog])
|
|
45
|
+
|
|
46
|
+
return (
|
|
47
|
+
<Sheet open={open} onOpenChange={onOpenChange}>
|
|
48
|
+
<SheetContent className="w-full sm:max-w-md md:max-w-lg">
|
|
49
|
+
<SheetHeader>
|
|
50
|
+
<SheetTitle className="flex items-center gap-2 text-base">
|
|
51
|
+
<Library className="size-4" />
|
|
52
|
+
{L.catalogue}
|
|
53
|
+
</SheetTitle>
|
|
54
|
+
<SheetDescription>{L.catalogueDescription}</SheetDescription>
|
|
55
|
+
</SheetHeader>
|
|
56
|
+
|
|
57
|
+
<ScrollArea className="flex-1 px-4 pb-4">
|
|
58
|
+
<div className="flex flex-col gap-6">
|
|
59
|
+
<section className="flex flex-col gap-2">
|
|
60
|
+
<CatalogueSectionHeader title={L.catalogueKeys} count={keyCatalog.length} />
|
|
61
|
+
{keyCatalog.length === 0 ? (
|
|
62
|
+
<p className="text-muted-foreground text-xs italic">No keys registered.</p>
|
|
63
|
+
) : (
|
|
64
|
+
<ul className="flex flex-col gap-1">
|
|
65
|
+
{keyCatalog.map((entry) => (
|
|
66
|
+
<li
|
|
67
|
+
key={entry.key}
|
|
68
|
+
className="hover:bg-accent/40 flex flex-col gap-1 rounded-md border px-2 py-1.5 text-xs"
|
|
69
|
+
>
|
|
70
|
+
<div className="flex items-start justify-between gap-2">
|
|
71
|
+
<span className="truncate font-mono">{entry.key}</span>
|
|
72
|
+
<span
|
|
73
|
+
className={cn(
|
|
74
|
+
"inline-flex shrink-0 items-center gap-1 text-[10px]",
|
|
75
|
+
entry.inContext
|
|
76
|
+
? "text-emerald-600 dark:text-emerald-400"
|
|
77
|
+
: "text-muted-foreground",
|
|
78
|
+
)}
|
|
79
|
+
>
|
|
80
|
+
<span
|
|
81
|
+
className={cn(
|
|
82
|
+
"size-1.5 rounded-full",
|
|
83
|
+
entry.inContext ? "bg-emerald-500" : "bg-muted-foreground/40",
|
|
84
|
+
)}
|
|
85
|
+
/>
|
|
86
|
+
{entry.inContext ? L.catalogueLive : L.catalogueMissing}
|
|
87
|
+
</span>
|
|
88
|
+
</div>
|
|
89
|
+
{(entry.producedBySteps.length > 0 ||
|
|
90
|
+
entry.consumedBySteps.length > 0 ||
|
|
91
|
+
entry.consumedByWidgets.length > 0) && (
|
|
92
|
+
<div className="text-muted-foreground/80 flex flex-col gap-0.5 text-[10px]">
|
|
93
|
+
{entry.producedBySteps.length > 0 && (
|
|
94
|
+
<span>
|
|
95
|
+
{L.catalogueProducedBy}{" "}
|
|
96
|
+
<span className="font-mono">{entry.producedBySteps.join(", ")}</span>
|
|
97
|
+
</span>
|
|
98
|
+
)}
|
|
99
|
+
{entry.consumedBySteps.length > 0 && (
|
|
100
|
+
<span>
|
|
101
|
+
step {L.catalogueConsumedBy}{" "}
|
|
102
|
+
<span className="font-mono">{entry.consumedBySteps.join(", ")}</span>
|
|
103
|
+
</span>
|
|
104
|
+
)}
|
|
105
|
+
{entry.consumedByWidgets.length > 0 && (
|
|
106
|
+
<span>
|
|
107
|
+
widget {L.catalogueConsumedBy}{" "}
|
|
108
|
+
<span className="font-mono">
|
|
109
|
+
{entry.consumedByWidgets.join(", ")}
|
|
110
|
+
</span>
|
|
111
|
+
</span>
|
|
112
|
+
)}
|
|
113
|
+
</div>
|
|
114
|
+
)}
|
|
115
|
+
{!entry.inContext && (
|
|
116
|
+
<div className="mt-0.5 flex items-center gap-1">
|
|
117
|
+
<Button variant="ghost" size="xs" onClick={() => onSeedKey(entry.key)}>
|
|
118
|
+
<Plus /> {L.cataloguePickKey}
|
|
119
|
+
</Button>
|
|
120
|
+
{producerOf.get(entry.key) && (
|
|
121
|
+
<Button
|
|
122
|
+
variant="ghost"
|
|
123
|
+
size="xs"
|
|
124
|
+
onClick={() => onAddProducingStep(entry.key)}
|
|
125
|
+
>
|
|
126
|
+
<ArrowDownToLine /> {L.catalogueAddProducingStep}
|
|
127
|
+
</Button>
|
|
128
|
+
)}
|
|
129
|
+
</div>
|
|
130
|
+
)}
|
|
131
|
+
</li>
|
|
132
|
+
))}
|
|
133
|
+
</ul>
|
|
134
|
+
)}
|
|
135
|
+
</section>
|
|
136
|
+
|
|
137
|
+
<section className="flex flex-col gap-2">
|
|
138
|
+
<CatalogueSectionHeader title={L.catalogueSteps} count={availableSteps.length} />
|
|
139
|
+
{availableSteps.length === 0 ? (
|
|
140
|
+
<p className="text-muted-foreground text-xs italic">No steps registered.</p>
|
|
141
|
+
) : (
|
|
142
|
+
<ul className="flex flex-col gap-1">
|
|
143
|
+
{availableSteps.map((s) => (
|
|
144
|
+
<li
|
|
145
|
+
key={s.id}
|
|
146
|
+
className="flex flex-col gap-0.5 rounded-md border px-2 py-1.5 text-xs"
|
|
147
|
+
>
|
|
148
|
+
<span className="truncate font-mono">{s.id}</span>
|
|
149
|
+
<div className="text-muted-foreground/80 flex flex-wrap gap-x-3 text-[10px]">
|
|
150
|
+
<span className="font-mono">
|
|
151
|
+
← {s.requires.length ? s.requires.join(", ") : "(no inputs)"}
|
|
152
|
+
</span>
|
|
153
|
+
<span className="font-mono">
|
|
154
|
+
→ {s.produces.length ? s.produces.join(", ") : "(none)"}
|
|
155
|
+
</span>
|
|
156
|
+
</div>
|
|
157
|
+
</li>
|
|
158
|
+
))}
|
|
159
|
+
</ul>
|
|
160
|
+
)}
|
|
161
|
+
</section>
|
|
162
|
+
|
|
163
|
+
<section className="flex flex-col gap-2">
|
|
164
|
+
<CatalogueSectionHeader
|
|
165
|
+
title={L.catalogueUnreachable}
|
|
166
|
+
count={unreachableWidgets.length}
|
|
167
|
+
/>
|
|
168
|
+
{unreachableWidgets.length === 0 ? (
|
|
169
|
+
<p className="text-muted-foreground text-xs italic">
|
|
170
|
+
{L.catalogueUnreachableEmpty}
|
|
171
|
+
</p>
|
|
172
|
+
) : (
|
|
173
|
+
<ul className="flex flex-col gap-1">
|
|
174
|
+
{unreachableWidgets.map((w) => {
|
|
175
|
+
const candidate = w.missingKeys
|
|
176
|
+
.map((k) => ({ key: k, step: producerOf.get(k) }))
|
|
177
|
+
.find((c) => c.step)
|
|
178
|
+
return (
|
|
179
|
+
<li
|
|
180
|
+
key={w.id}
|
|
181
|
+
className="bg-muted/20 flex flex-col gap-1 rounded-md border px-2 py-1.5 text-xs"
|
|
182
|
+
>
|
|
183
|
+
<span className="truncate font-mono">{w.id}</span>
|
|
184
|
+
<span className="text-muted-foreground/80 text-[10px]">
|
|
185
|
+
{L.catalogueNeedsKeys}{" "}
|
|
186
|
+
<span className="font-mono">{w.missingKeys.join(", ")}</span>
|
|
187
|
+
</span>
|
|
188
|
+
<div className="mt-0.5 flex flex-wrap items-center gap-1">
|
|
189
|
+
{w.missingKeys.map((k) => (
|
|
190
|
+
<Button key={k} variant="ghost" size="xs" onClick={() => onSeedKey(k)}>
|
|
191
|
+
<Plus />
|
|
192
|
+
<span className="font-mono">{k}</span>
|
|
193
|
+
</Button>
|
|
194
|
+
))}
|
|
195
|
+
{candidate && (
|
|
196
|
+
<Button
|
|
197
|
+
variant="outline"
|
|
198
|
+
size="xs"
|
|
199
|
+
onClick={() => onAddProducingStep(candidate.key)}
|
|
200
|
+
>
|
|
201
|
+
<ArrowDownToLine /> {L.catalogueAddProducingStep}
|
|
202
|
+
</Button>
|
|
203
|
+
)}
|
|
204
|
+
</div>
|
|
205
|
+
</li>
|
|
206
|
+
)
|
|
207
|
+
})}
|
|
208
|
+
</ul>
|
|
209
|
+
)}
|
|
210
|
+
</section>
|
|
211
|
+
</div>
|
|
212
|
+
</ScrollArea>
|
|
213
|
+
</SheetContent>
|
|
214
|
+
</Sheet>
|
|
215
|
+
)
|
|
216
|
+
}
|
|
217
|
+
|
|
218
|
+
function CatalogueSectionHeader({ title, count }: { title: string; count: number }) {
|
|
219
|
+
return (
|
|
220
|
+
<div className="flex items-center gap-2">
|
|
221
|
+
<span className="text-muted-foreground text-[10px] font-semibold tracking-[0.12em] uppercase">
|
|
222
|
+
{title}
|
|
223
|
+
</span>
|
|
224
|
+
<span className="bg-border h-px flex-1" aria-hidden="true" />
|
|
225
|
+
<Badge variant="outline" className="px-1.5 text-[10px]">
|
|
226
|
+
{count}
|
|
227
|
+
</Badge>
|
|
228
|
+
</div>
|
|
229
|
+
)
|
|
230
|
+
}
|