@miragon/mcp-toolkit-ui 2.7.0 → 2.8.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 +7 -4
- 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.js +1 -1
- 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 +21 -7
- 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 +11 -4
- 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/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 +2 -1
- package/dist/app/builder/PipelineStrip.d.ts.map +1 -1
- package/dist/app/builder/PipelineStrip.js +26 -13
- 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 +8 -2
- package/dist/app/builder/SaveDialog.js.map +1 -1
- package/dist/app/builder/Toolbar.d.ts +12 -4
- package/dist/app/builder/Toolbar.d.ts.map +1 -1
- package/dist/app/builder/Toolbar.js +18 -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 +143 -1
- package/dist/app/builder/builder-model.d.ts.map +1 -1
- package/dist/app/builder/builder-model.js +191 -1
- package/dist/app/builder/builder-model.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/use-builder-catalogue.d.ts +4 -1
- package/dist/app/builder/use-builder-catalogue.d.ts.map +1 -1
- package/dist/app/builder/use-builder-catalogue.js +44 -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/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 +13 -25
- package/dist/app/layout-builder.d.ts.map +1 -1
- package/dist/app/layout-builder.js +75 -81
- package/dist/app/layout-builder.js.map +1 -1
- package/dist/app/mcp-app-view-chrome.d.ts +12 -3
- package/dist/app/mcp-app-view-chrome.d.ts.map +1 -1
- package/dist/app/mcp-app-view-chrome.js +21 -5
- package/dist/app/mcp-app-view-chrome.js.map +1 -1
- package/dist/app/mcp-app-view-states.d.ts +11 -3
- package/dist/app/mcp-app-view-states.d.ts.map +1 -1
- package/dist/app/mcp-app-view-states.js +29 -8
- package/dist/app/mcp-app-view-states.js.map +1 -1
- package/dist/app/mcp-app-view.d.ts +33 -1
- package/dist/app/mcp-app-view.d.ts.map +1 -1
- package/dist/app/mcp-app-view.js +181 -127
- package/dist/app/mcp-app-view.js.map +1 -1
- package/dist/app/mcp-toolkit-app.d.ts +6 -1
- package/dist/app/mcp-toolkit-app.d.ts.map +1 -1
- package/dist/app/mcp-toolkit-app.js +8 -1
- 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 +4 -0
- package/dist/app/use-view-lifecycle.d.ts.map +1 -1
- package/dist/app/use-view-lifecycle.js +2 -0
- package/dist/app/use-view-lifecycle.js.map +1 -1
- package/dist/app/view-lifecycle.d.ts +80 -4
- package/dist/app/view-lifecycle.d.ts.map +1 -1
- package/dist/app/view-lifecycle.js +90 -3
- package/dist/app/view-lifecycle.js.map +1 -1
- 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 +3 -1
- package/dist/app/widget-props-sheet.d.ts.map +1 -1
- package/dist/app/widget-props-sheet.js +22 -10
- package/dist/app/widget-props-sheet.js.map +1 -1
- package/dist/app/widget-renderer.js +1 -1
- package/dist/app/widget-renderer.js.map +1 -1
- package/dist/components/DrillButton.d.ts +14 -6
- package/dist/components/DrillButton.d.ts.map +1 -1
- package/dist/components/DrillButton.js +14 -7
- package/dist/components/DrillButton.js.map +1 -1
- package/dist/components/EmptyState.d.ts.map +1 -1
- package/dist/components/EmptyState.js +4 -2
- package/dist/components/EmptyState.js.map +1 -1
- package/dist/components/ErrorState.d.ts +5 -2
- package/dist/components/ErrorState.d.ts.map +1 -1
- package/dist/components/ErrorState.js +25 -8
- package/dist/components/ErrorState.js.map +1 -1
- package/dist/components/FilterBar.d.ts +15 -4
- package/dist/components/FilterBar.d.ts.map +1 -1
- package/dist/components/FilterBar.js +11 -6
- package/dist/components/FilterBar.js.map +1 -1
- package/dist/components/KpiGrid.d.ts +66 -21
- package/dist/components/KpiGrid.d.ts.map +1 -1
- package/dist/components/KpiGrid.js +101 -34
- package/dist/components/KpiGrid.js.map +1 -1
- package/dist/components/ListFooter.d.ts +31 -4
- package/dist/components/ListFooter.d.ts.map +1 -1
- package/dist/components/ListFooter.js +30 -11
- 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 +27 -7
- package/dist/components/Pills.d.ts.map +1 -1
- package/dist/components/Pills.js +21 -6
- 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 +9 -3
- package/dist/components/Toast.d.ts.map +1 -1
- package/dist/components/Toast.js +31 -16
- package/dist/components/Toast.js.map +1 -1
- 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 +47 -52
- package/dist/hooks/use-tool-result-recovery.d.ts.map +1 -1
- package/dist/hooks/use-tool-result-recovery.js +58 -120
- package/dist/hooks/use-tool-result-recovery.js.map +1 -1
- package/dist/hooks/use-view-data.d.ts +52 -10
- package/dist/hooks/use-view-data.d.ts.map +1 -1
- package/dist/hooks/use-view-data.js +81 -16
- 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 +17 -10
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +18 -6
- 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/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 +41 -1
- package/dist/lib/toast-model.d.ts.map +1 -1
- package/dist/lib/toast-model.js +67 -1
- package/dist/lib/toast-model.js.map +1 -1
- package/dist/lib/tone-utils.d.ts +58 -6
- package/dist/lib/tone-utils.d.ts.map +1 -1
- package/dist/lib/tone-utils.js +66 -4
- 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 +1 -1
- package/dist/locale/index.d.ts.map +1 -1
- package/dist/locale/message-types.d.ts +117 -4
- package/dist/locale/message-types.d.ts.map +1 -1
- package/dist/locale/messages-de.d.ts.map +1 -1
- package/dist/locale/messages-de.js +44 -10
- package/dist/locale/messages-de.js.map +1 -1
- package/dist/locale/messages-en.d.ts.map +1 -1
- package/dist/locale/messages-en.js +44 -10
- package/dist/locale/messages-en.js.map +1 -1
- package/dist/locale/toolkit-messages.d.ts +19 -1
- package/dist/locale/toolkit-messages.d.ts.map +1 -1
- package/dist/locale/toolkit-messages.js +54 -1
- package/dist/locale/toolkit-messages.js.map +1 -1
- package/dist/primitives/alert.d.ts +1 -1
- package/dist/primitives/alert.d.ts.map +1 -1
- package/dist/primitives/alert.js +2 -0
- 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 +9 -4
- package/dist/primitives/badge.js.map +1 -1
- package/dist/primitives/button.d.ts +1 -1
- package/dist/primitives/button.js +1 -1
- package/dist/primitives/button.js.map +1 -1
- package/dist/primitives/dialog.d.ts +1 -1
- package/dist/primitives/dialog.d.ts.map +1 -1
- package/dist/primitives/dialog.js +10 -3
- package/dist/primitives/dialog.js.map +1 -1
- package/dist/primitives/select.js +1 -1
- package/dist/primitives/select.js.map +1 -1
- package/dist/primitives/sheet.d.ts +1 -1
- package/dist/primitives/sheet.d.ts.map +1 -1
- package/dist/primitives/sheet.js +6 -2
- package/dist/primitives/sheet.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 +30 -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/theme/create-theme.d.ts +19 -1
- package/dist/theme/create-theme.d.ts.map +1 -1
- package/dist/theme/create-theme.js +15 -0
- package/dist/theme/create-theme.js.map +1 -1
- package/package.json +5 -4
- package/src/app/adapt-data-widget.tsx +2 -42
- package/src/app/builder/BuilderBanners.tsx +1 -1
- package/src/app/builder/CanvasRow.tsx +63 -17
- package/src/app/builder/CatalogueSheet.tsx +50 -29
- package/src/app/builder/CellPropsSheet.tsx +17 -2
- package/src/app/builder/DiscardDialog.tsx +59 -0
- package/src/app/builder/LayoutSurface.tsx +206 -66
- package/src/app/builder/PipelineStrip.tsx +253 -153
- package/src/app/builder/SaveDialog.tsx +14 -2
- package/src/app/builder/Toolbar.tsx +144 -59
- package/src/app/builder/Workspace.tsx +226 -58
- package/src/app/builder/builder-model.ts +341 -2
- 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/reveal.ts +10 -0
- package/src/app/builder/use-builder-catalogue.ts +56 -19
- package/src/app/builder/use-builder-session.ts +68 -0
- package/src/app/builder/use-display-resolver.ts +24 -0
- package/src/app/index.ts +12 -2
- package/src/app/layout-builder.tsx +178 -191
- package/src/app/mcp-app-view-chrome.test.tsx +141 -1
- package/src/app/mcp-app-view-chrome.tsx +56 -6
- package/src/app/mcp-app-view-states.tsx +51 -11
- package/src/app/mcp-app-view.effects.test.tsx +292 -0
- package/src/app/mcp-app-view.test.tsx +222 -2
- package/src/app/mcp-app-view.tsx +267 -117
- package/src/app/mcp-toolkit-app.test.tsx +40 -0
- package/src/app/mcp-toolkit-app.tsx +8 -1
- 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 +6 -0
- package/src/app/view-lifecycle.test.ts +216 -0
- package/src/app/view-lifecycle.ts +165 -5
- 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 +57 -16
- package/src/app/widget-renderer.tsx +1 -1
- package/src/components/DrillButton.test.tsx +48 -0
- package/src/components/DrillButton.tsx +26 -11
- package/src/components/EmptyState.tsx +6 -4
- package/src/components/ErrorState.tsx +31 -9
- package/src/components/FilterBar.test.tsx +82 -0
- package/src/components/FilterBar.tsx +52 -26
- package/src/components/KpiGrid.test.tsx +279 -0
- package/src/components/KpiGrid.tsx +297 -90
- package/src/components/ListFooter.test.tsx +116 -0
- package/src/components/ListFooter.tsx +102 -15
- 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 +63 -10
- package/src/components/SectionHeading.tsx +9 -3
- package/src/components/Toast.tsx +37 -19
- package/src/components/WidgetHeader.test.tsx +78 -0
- package/src/components/WidgetHeader.tsx +63 -16
- package/src/components/feedback-states.test.tsx +98 -9
- package/src/components/tone-figures.test.tsx +8 -4
- 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 +3 -4
- package/src/hooks/use-tool-result-recovery.ts +84 -142
- package/src/hooks/use-view-data.test.tsx +118 -9
- package/src/hooks/use-view-data.ts +128 -18
- package/src/hooks/use-view-tool-query.ts +25 -19
- package/src/i18n-coverage.test.tsx +104 -2
- package/src/index.ts +48 -11
- package/src/lib/focus-return.test.ts +288 -0
- package/src/lib/focus-return.ts +96 -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 +166 -1
- package/src/lib/toast-model.ts +104 -2
- package/src/lib/tone-utils.test.ts +86 -10
- package/src/lib/tone-utils.ts +89 -8
- 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 +1 -0
- package/src/locale/message-types.ts +118 -2
- package/src/locale/messages-de.ts +49 -10
- package/src/locale/messages-en.ts +49 -10
- package/src/locale/toolkit-messages.test.ts +133 -0
- package/src/locale/toolkit-messages.ts +63 -2
- package/src/primitives/alert.tsx +3 -0
- package/src/primitives/badge.tsx +9 -4
- package/src/primitives/button.tsx +1 -1
- package/src/primitives/dialog.tsx +10 -1
- package/src/primitives/select.tsx +1 -1
- package/src/primitives/sheet.tsx +7 -0
- 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 +38 -6
- package/src/render-effects.tsx +96 -0
- package/src/theme/cd-tokens.test.ts +3 -1
- package/src/theme/create-theme.test.ts +10 -0
- package/src/theme/create-theme.ts +28 -0
- package/src/theme/theme-css.test.ts +51 -0
- package/src/theme.css +31 -1
- package/ui-catalog.json +448 -41
|
@@ -1,9 +1,17 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { useId, useRef, useState } from "react"
|
|
2
|
+
import { Pencil, Plus, X } from "lucide-react"
|
|
2
3
|
import { Button } from "../../primitives/button.js"
|
|
3
4
|
import { Tabs, TabsContent, TabsList, TabsTrigger } from "../../primitives/tabs.js"
|
|
5
|
+
import { FOCUS_RING } from "../../lib/focus-ring.js"
|
|
4
6
|
import { cn } from "../../lib/utils.js"
|
|
5
|
-
import
|
|
7
|
+
import {
|
|
8
|
+
createTabRefocus,
|
|
9
|
+
renameFieldKeyAction,
|
|
10
|
+
tabTriggerKeyAction,
|
|
11
|
+
type DraftLayout,
|
|
12
|
+
} from "./builder-model.js"
|
|
6
13
|
import type { LayoutBuilderLabels } from "./labels.js"
|
|
14
|
+
import { REVEAL_ON_INTENT } from "./reveal.js"
|
|
7
15
|
import { Workspace, type WorkspaceProps } from "./Workspace.js"
|
|
8
16
|
|
|
9
17
|
// -------------------------------------------------------------------------- //
|
|
@@ -14,12 +22,13 @@ import { Workspace, type WorkspaceProps } from "./Workspace.js"
|
|
|
14
22
|
/**
|
|
15
23
|
* The "Layout" view's canvas surface, extracted from `layout-builder.tsx`.
|
|
16
24
|
*
|
|
17
|
-
* Renders either a single `Workspace` (rows draft
|
|
18
|
-
* the
|
|
19
|
-
*
|
|
20
|
-
*
|
|
21
|
-
*
|
|
22
|
-
*
|
|
25
|
+
* Renders either a single `Workspace` (rows draft, with an "Add tab" next to
|
|
26
|
+
* "Add row") or the tab strip plus one `Workspace` per tab (tabs draft). A tab
|
|
27
|
+
* is renamed with F2, Enter on the active tab, a double-click or its pencil
|
|
28
|
+
* button; Enter commits, Escape cancels, and either returns focus to the tab,
|
|
29
|
+
* also when the new name remounts it (see `TabRefocus`, held here by index).
|
|
30
|
+
* All state stays in the LayoutBuilder container — rename feedback included —
|
|
31
|
+
* so unmounting this surface (e.g. switching to the data sources) loses nothing.
|
|
23
32
|
*/
|
|
24
33
|
export function LayoutSurface({
|
|
25
34
|
L,
|
|
@@ -41,13 +50,18 @@ export function LayoutSurface({
|
|
|
41
50
|
editingTabIdx: number | null
|
|
42
51
|
setEditingTabIdx: (idx: number | null) => void
|
|
43
52
|
renameRejected: boolean
|
|
44
|
-
|
|
53
|
+
/** Commits a rename; `false` when it was rejected and the field stays open. */
|
|
54
|
+
commitRename: (tabIdx: number, label: string) => boolean
|
|
45
55
|
onAddTab: () => void
|
|
46
56
|
onRemoveTab: (tabIdx: number) => void
|
|
47
|
-
workspace: Omit<WorkspaceProps, "
|
|
57
|
+
workspace: Omit<WorkspaceProps, "onAddTab">
|
|
48
58
|
}) {
|
|
59
|
+
const errorId = useId()
|
|
60
|
+
// One per surface, outside the tabs: a tab is keyed by its label, so a
|
|
61
|
+
// rename remounts it, and a focus request held by the tab would go with it.
|
|
62
|
+
const [refocus] = useState(createTabRefocus)
|
|
49
63
|
if (draft.kind !== "tabs") {
|
|
50
|
-
return <Workspace {...workspace}
|
|
64
|
+
return <Workspace {...workspace} onAddTab={onAddTab} />
|
|
51
65
|
}
|
|
52
66
|
return (
|
|
53
67
|
<Tabs
|
|
@@ -57,59 +71,29 @@ export function LayoutSurface({
|
|
|
57
71
|
if (idx >= 0) setActiveTabIndex(idx)
|
|
58
72
|
}}
|
|
59
73
|
>
|
|
60
|
-
<div className="mb-3 flex items-center gap-1">
|
|
61
|
-
<TabsList
|
|
74
|
+
<div className="mb-3 flex flex-wrap items-center gap-1">
|
|
75
|
+
<TabsList
|
|
76
|
+
aria-label={L.tabsLabel}
|
|
77
|
+
className="flex-wrap group-data-[orientation=horizontal]/tabs:h-auto"
|
|
78
|
+
>
|
|
62
79
|
{draft.tabs.map((tab, idx) => (
|
|
63
|
-
<
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
commitRename(idx, e.currentTarget.value)
|
|
81
|
-
} else if (e.key === "Escape") {
|
|
82
|
-
e.preventDefault()
|
|
83
|
-
setEditingTabIdx(null)
|
|
84
|
-
}
|
|
85
|
-
}}
|
|
86
|
-
onBlur={(e) => {
|
|
87
|
-
commitRename(idx, e.currentTarget.value)
|
|
88
|
-
}}
|
|
89
|
-
className={cn(
|
|
90
|
-
"focus-visible:ring-focus w-24 rounded-sm border-none bg-transparent p-0 text-inherit outline-hidden focus-visible:ring-2",
|
|
91
|
-
renameRejected && "text-danger-ink",
|
|
92
|
-
)}
|
|
93
|
-
size={Math.max(tab.label.length + 1, 6)}
|
|
94
|
-
/>
|
|
95
|
-
) : (
|
|
96
|
-
<span>{tab.label}</span>
|
|
97
|
-
)}
|
|
98
|
-
</TabsTrigger>
|
|
99
|
-
<button
|
|
100
|
-
type="button"
|
|
101
|
-
aria-label={L.removeTab}
|
|
102
|
-
title={L.removeTab}
|
|
103
|
-
onPointerDown={(e) => e.stopPropagation()}
|
|
104
|
-
onClick={(e) => {
|
|
105
|
-
e.stopPropagation()
|
|
106
|
-
onRemoveTab(idx)
|
|
107
|
-
}}
|
|
108
|
-
className="text-muted-foreground hover:text-foreground absolute top-1/2 right-1 -translate-y-1/2 rounded-sm p-0.5 opacity-0 transition-opacity group-hover:opacity-100 focus-visible:opacity-100 data-[state=active]:opacity-100"
|
|
109
|
-
>
|
|
110
|
-
<X className="size-3" />
|
|
111
|
-
</button>
|
|
112
|
-
</div>
|
|
80
|
+
<TabItem
|
|
81
|
+
key={tab.label}
|
|
82
|
+
L={L}
|
|
83
|
+
label={tab.label}
|
|
84
|
+
active={idx === activeTabIndex}
|
|
85
|
+
editing={editingTabIdx === idx}
|
|
86
|
+
renameRejected={renameRejected}
|
|
87
|
+
errorId={errorId}
|
|
88
|
+
onStartRename={() => {
|
|
89
|
+
setActiveTabIndex(idx)
|
|
90
|
+
setEditingTabIdx(idx)
|
|
91
|
+
}}
|
|
92
|
+
onCommitRename={(label) => commitRename(idx, label)}
|
|
93
|
+
onCancelRename={() => setEditingTabIdx(null)}
|
|
94
|
+
onRemove={() => onRemoveTab(idx)}
|
|
95
|
+
{...refocus.forTab(idx)}
|
|
96
|
+
/>
|
|
113
97
|
))}
|
|
114
98
|
</TabsList>
|
|
115
99
|
<Button
|
|
@@ -119,14 +103,14 @@ export function LayoutSurface({
|
|
|
119
103
|
aria-label={L.addTab}
|
|
120
104
|
title={L.addTab}
|
|
121
105
|
>
|
|
122
|
-
<Plus />
|
|
106
|
+
<Plus aria-hidden="true" />
|
|
123
107
|
</Button>
|
|
124
|
-
<span className="text-muted-foreground ml-2 hidden
|
|
108
|
+
<span className="text-muted-foreground text-small ml-2 hidden sm:inline">
|
|
125
109
|
{L.renameHint}
|
|
126
110
|
</span>
|
|
127
111
|
</div>
|
|
128
112
|
{renameRejected && editingTabIdx !== null && (
|
|
129
|
-
<p className="text-danger-ink -mt-1 mb-2
|
|
113
|
+
<p id={errorId} className="text-danger-ink text-small -mt-1 mb-2" role="alert">
|
|
130
114
|
{L.renameDuplicate}
|
|
131
115
|
</p>
|
|
132
116
|
)}
|
|
@@ -138,3 +122,159 @@ export function LayoutSurface({
|
|
|
138
122
|
</Tabs>
|
|
139
123
|
)
|
|
140
124
|
}
|
|
125
|
+
|
|
126
|
+
// -------------------------------------------------------------------------- //
|
|
127
|
+
// One tab: trigger (or the rename field) plus its rename and remove buttons
|
|
128
|
+
// -------------------------------------------------------------------------- //
|
|
129
|
+
|
|
130
|
+
/**
|
|
131
|
+
* One tab. It holds no state of its own (it is keyed by its label, so a
|
|
132
|
+
* rename remounts it): the focus hand-back after a keyboard rename goes
|
|
133
|
+
* through `onRefocus` and `triggerRef` to the surface's `TabRefocus`.
|
|
134
|
+
* Exported for its tests only.
|
|
135
|
+
*/
|
|
136
|
+
export function TabItem({
|
|
137
|
+
L,
|
|
138
|
+
label,
|
|
139
|
+
active,
|
|
140
|
+
editing,
|
|
141
|
+
renameRejected,
|
|
142
|
+
errorId,
|
|
143
|
+
onStartRename,
|
|
144
|
+
onCommitRename,
|
|
145
|
+
onCancelRename,
|
|
146
|
+
onRemove,
|
|
147
|
+
triggerRef,
|
|
148
|
+
onRefocus,
|
|
149
|
+
}: {
|
|
150
|
+
L: Required<LayoutBuilderLabels>
|
|
151
|
+
label: string
|
|
152
|
+
active: boolean
|
|
153
|
+
editing: boolean
|
|
154
|
+
renameRejected: boolean
|
|
155
|
+
errorId: string
|
|
156
|
+
onStartRename: () => void
|
|
157
|
+
onCommitRename: (label: string) => boolean
|
|
158
|
+
onCancelRename: () => void
|
|
159
|
+
onRemove: () => void
|
|
160
|
+
/** The trigger's ref callback: it takes the focus back after a keyboard rename. */
|
|
161
|
+
triggerRef: (el: HTMLButtonElement | null) => void
|
|
162
|
+
/** Asks for the focus to come back to this tab's trigger when it mounts again. */
|
|
163
|
+
onRefocus: () => void
|
|
164
|
+
}) {
|
|
165
|
+
return (
|
|
166
|
+
<div className="group inline-flex items-center" data-slot="builder-tab">
|
|
167
|
+
{editing ? (
|
|
168
|
+
<RenameField
|
|
169
|
+
L={L}
|
|
170
|
+
initial={label}
|
|
171
|
+
invalid={renameRejected}
|
|
172
|
+
errorId={errorId}
|
|
173
|
+
onCommit={(value, byKeyboard) => {
|
|
174
|
+
const accepted = onCommitRename(value)
|
|
175
|
+
// A pointer commit leaves the focus where the pointer went.
|
|
176
|
+
if (accepted && byKeyboard) onRefocus()
|
|
177
|
+
return accepted
|
|
178
|
+
}}
|
|
179
|
+
onCancel={() => {
|
|
180
|
+
onRefocus()
|
|
181
|
+
onCancelRename()
|
|
182
|
+
}}
|
|
183
|
+
/>
|
|
184
|
+
) : (
|
|
185
|
+
<TabsTrigger
|
|
186
|
+
ref={triggerRef}
|
|
187
|
+
value={label}
|
|
188
|
+
title={L.renameTitle}
|
|
189
|
+
onDoubleClick={onStartRename}
|
|
190
|
+
onKeyDown={(e) => {
|
|
191
|
+
if (tabTriggerKeyAction(e.key, active) !== "rename") return
|
|
192
|
+
e.preventDefault()
|
|
193
|
+
onStartRename()
|
|
194
|
+
}}
|
|
195
|
+
>
|
|
196
|
+
{label}
|
|
197
|
+
</TabsTrigger>
|
|
198
|
+
)}
|
|
199
|
+
<div
|
|
200
|
+
data-slot="builder-tab-actions"
|
|
201
|
+
className={cn("flex items-center", active ? "opacity-100" : REVEAL_ON_INTENT)}
|
|
202
|
+
>
|
|
203
|
+
{!editing && (
|
|
204
|
+
<Button
|
|
205
|
+
variant="ghost"
|
|
206
|
+
size="icon-xs"
|
|
207
|
+
aria-label={L.renameTabNamed(label)}
|
|
208
|
+
title={L.renameTab}
|
|
209
|
+
onClick={onStartRename}
|
|
210
|
+
>
|
|
211
|
+
<Pencil aria-hidden="true" />
|
|
212
|
+
</Button>
|
|
213
|
+
)}
|
|
214
|
+
<Button
|
|
215
|
+
variant="ghost"
|
|
216
|
+
size="icon-xs"
|
|
217
|
+
aria-label={L.removeTabNamed(label)}
|
|
218
|
+
title={L.removeTab}
|
|
219
|
+
onClick={onRemove}
|
|
220
|
+
>
|
|
221
|
+
<X aria-hidden="true" />
|
|
222
|
+
</Button>
|
|
223
|
+
</div>
|
|
224
|
+
</div>
|
|
225
|
+
)
|
|
226
|
+
}
|
|
227
|
+
|
|
228
|
+
/**
|
|
229
|
+
* The inline rename field, mounted for one rename. Enter commits (a rejected
|
|
230
|
+
* name keeps it open with the error), Escape cancels; leaving it by pointer
|
|
231
|
+
* commits too. A field that already ended by keyboard ignores the blur that
|
|
232
|
+
* its own unmount may fire.
|
|
233
|
+
*/
|
|
234
|
+
function RenameField({
|
|
235
|
+
L,
|
|
236
|
+
initial,
|
|
237
|
+
invalid,
|
|
238
|
+
errorId,
|
|
239
|
+
onCommit,
|
|
240
|
+
onCancel,
|
|
241
|
+
}: {
|
|
242
|
+
L: Required<LayoutBuilderLabels>
|
|
243
|
+
initial: string
|
|
244
|
+
invalid: boolean
|
|
245
|
+
errorId: string
|
|
246
|
+
onCommit: (value: string, byKeyboard: boolean) => boolean
|
|
247
|
+
onCancel: () => void
|
|
248
|
+
}) {
|
|
249
|
+
const ended = useRef(false)
|
|
250
|
+
return (
|
|
251
|
+
<input
|
|
252
|
+
// The field replaces the tab the user just chose to rename: focus follows.
|
|
253
|
+
autoFocus
|
|
254
|
+
defaultValue={initial}
|
|
255
|
+
aria-label={L.renameTab}
|
|
256
|
+
aria-invalid={invalid}
|
|
257
|
+
aria-describedby={invalid ? errorId : undefined}
|
|
258
|
+
onKeyDown={(e) => {
|
|
259
|
+
const action = renameFieldKeyAction(e.key)
|
|
260
|
+
if (action === null) return
|
|
261
|
+
e.preventDefault()
|
|
262
|
+
if (action === "cancel") {
|
|
263
|
+
ended.current = true
|
|
264
|
+
onCancel()
|
|
265
|
+
return
|
|
266
|
+
}
|
|
267
|
+
if (onCommit(e.currentTarget.value, true)) ended.current = true
|
|
268
|
+
}}
|
|
269
|
+
onBlur={(e) => {
|
|
270
|
+
if (!ended.current) onCommit(e.currentTarget.value, false)
|
|
271
|
+
}}
|
|
272
|
+
className={cn(
|
|
273
|
+
"bg-background text-foreground h-7 w-28 rounded-sm border px-1.5 text-sm",
|
|
274
|
+
FOCUS_RING,
|
|
275
|
+
invalid && "border-danger",
|
|
276
|
+
)}
|
|
277
|
+
size={Math.max(initial.length + 1, 6)}
|
|
278
|
+
/>
|
|
279
|
+
)
|
|
280
|
+
}
|