basalt-ui 1.28.0 → 1.29.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/AGENTS.md +12 -19
- package/CHANGELOG.md +23 -0
- package/MIGRATING.md +171 -7
- package/README.md +66 -105
- package/agent/rules/basalt-batteries.md +60 -183
- package/agent/rules/basalt-charts.md +56 -75
- package/agent/rules/basalt-controls.md +38 -69
- package/agent/rules/basalt-mantine.md +58 -103
- package/agent/rules/basalt-state.md +42 -60
- package/agent/rules/basalt-tokens.md +46 -67
- package/agent/skills/basalt-app/SKILL.md +2 -0
- package/agent/templates/CLAUDE-block.md.tpl +14 -14
- package/agent/templates/query-client.ts.tpl +1 -1
- package/configs/oxlint-plugin.js +84 -254
- package/configs/oxlint-plugin.test.ts +23 -266
- package/configs/oxlint.json +0 -2
- package/dist/agent/ai-sdk-transport.d.ts.map +1 -1
- package/dist/agent/ai-sdk-transport.js +7 -4
- package/dist/agent/coalesce.js +1 -1
- package/dist/agent/merge.js +1 -1
- package/dist/agent/transport.d.ts +13 -2
- package/dist/agent/transport.d.ts.map +1 -1
- package/dist/agent/use-agent-thread-runs.d.ts +12 -1
- package/dist/agent/use-agent-thread-runs.d.ts.map +1 -1
- package/dist/agent/use-agent-thread-runs.js +20 -6
- package/dist/agent-chat/index.d.ts +1 -1
- package/dist/agent-chat/index.d.ts.map +1 -1
- package/dist/agent-chat/relative-time.js +1 -1
- package/dist/agent-chat/thread-detail-panel.js +1 -1
- package/dist/agent-chat/thread-feed-row.d.ts +32 -7
- package/dist/agent-chat/thread-feed-row.d.ts.map +1 -1
- package/dist/agent-chat/thread-feed-row.js +121 -86
- package/dist/agent-chat/thread-feed.d.ts +11 -1
- package/dist/agent-chat/thread-feed.d.ts.map +1 -1
- package/dist/agent-chat/thread-feed.js +10 -6
- package/dist/agent-chat/thread-message.js +1 -1
- package/dist/agent-chat/virtualize.d.ts +39 -0
- package/dist/agent-chat/virtualize.d.ts.map +1 -1
- package/dist/agent-chat/virtualize.js +15 -0
- package/dist/charts/index.d.ts +3 -3
- package/dist/charts/index.d.ts.map +1 -1
- package/dist/charts/index.js +8 -4
- package/dist/charts/kinds/BandStrip.js +1 -1
- package/dist/charts/kinds/Bars.d.ts +1 -3
- package/dist/charts/kinds/Bars.d.ts.map +1 -1
- package/dist/charts/kinds/Bars.js +1 -1
- package/dist/charts/kinds/DualPanel.d.ts +3 -1
- package/dist/charts/kinds/DualPanel.d.ts.map +1 -1
- package/dist/charts/kinds/DualPanel.js +1 -1
- package/dist/charts/kinds/StackedArea.js +1 -1
- package/dist/charts/kinds/ZonedLine.d.ts +1 -3
- package/dist/charts/kinds/ZonedLine.d.ts.map +1 -1
- package/dist/charts/primitives/Axes.d.ts +21 -2
- package/dist/charts/primitives/Axes.d.ts.map +1 -1
- package/dist/charts/primitives/Axes.js +34 -2
- package/dist/charts/primitives/ChartCard.d.ts +20 -4
- package/dist/charts/primitives/ChartCard.d.ts.map +1 -1
- package/dist/charts/primitives/ChartCard.js +62 -33
- package/dist/charts/primitives/ChartFrame.d.ts.map +1 -1
- package/dist/charts/primitives/ChartFrame.js +8 -1
- package/dist/charts/primitives/ChartPending.d.ts +12 -6
- package/dist/charts/primitives/ChartPending.d.ts.map +1 -1
- package/dist/charts/primitives/ChartPending.js +1 -1
- package/dist/charts/utils/format.d.ts +5 -92
- package/dist/charts/utils/format.d.ts.map +1 -1
- package/dist/charts/utils/format.js +10 -80
- package/dist/cli/audit-allows.d.ts +24 -0
- package/dist/cli/audit-allows.d.ts.map +1 -0
- package/dist/cli/audit-allows.js +240 -0
- package/dist/cli/check-theme.d.ts +10 -0
- package/dist/cli/check-theme.d.ts.map +1 -0
- package/dist/cli/check-theme.js +139 -0
- package/dist/cli/doctor.d.ts +47 -0
- package/dist/cli/doctor.d.ts.map +1 -0
- package/dist/cli/doctor.js +197 -0
- package/dist/cli/guard-hook.d.ts +9 -0
- package/dist/cli/guard-hook.d.ts.map +1 -0
- package/dist/cli/guard-hook.js +93 -0
- package/dist/cli/help.d.ts +9 -0
- package/dist/cli/help.d.ts.map +1 -0
- package/dist/cli/help.js +53 -0
- package/dist/cli/index.d.ts +360 -270
- package/dist/cli/index.d.ts.map +1 -1
- package/dist/cli/index.js +85 -1901
- package/dist/cli/init.d.ts +4 -0
- package/dist/cli/init.d.ts.map +1 -0
- package/dist/cli/init.js +165 -0
- package/dist/cli/sync.d.ts +43 -0
- package/dist/cli/sync.d.ts.map +1 -0
- package/dist/cli/sync.js +206 -0
- package/dist/cli/tokens-css.d.ts +51 -0
- package/dist/cli/tokens-css.d.ts.map +1 -0
- package/dist/cli/tokens-css.js +165 -0
- package/dist/commands/define-commands.js +1 -1
- package/dist/commands/define-overlays.js +1 -1
- package/dist/commands/index.d.ts +2 -1
- package/dist/commands/index.d.ts.map +1 -1
- package/dist/commands/index.js +6 -0
- package/dist/commands/overlays-mount.d.ts +7 -9
- package/dist/commands/overlays-mount.d.ts.map +1 -1
- package/dist/commands/shell-bridge.d.ts +57 -0
- package/dist/commands/shell-bridge.d.ts.map +1 -0
- package/dist/commands/shell-bridge.js +32 -0
- package/dist/common/errors.d.ts +35 -0
- package/dist/common/errors.d.ts.map +1 -1
- package/dist/common/errors.js +29 -1
- package/dist/common/index.d.ts +2 -0
- package/dist/common/index.d.ts.map +1 -1
- package/dist/common/index.js +6 -0
- package/dist/common/is-dev.d.ts.map +1 -0
- package/dist/{motion/index.d.ts → common/motion.d.ts} +1 -1
- package/dist/common/motion.d.ts.map +1 -0
- package/dist/common/props.d.ts +1 -1
- package/dist/common/props.d.ts.map +1 -1
- package/dist/common/validate.js +1 -1
- package/dist/content/markdown.d.ts +3 -4
- package/dist/content/markdown.d.ts.map +1 -1
- package/dist/content/markdown.js +1 -4
- package/dist/controls/actions.d.ts +1 -1
- package/dist/controls/actions.d.ts.map +1 -1
- package/dist/controls/panel-row.js +1 -1
- package/dist/controls/range-filter.js +1 -1
- package/dist/dashboard/delta-badge.d.ts +18 -10
- package/dist/dashboard/delta-badge.d.ts.map +1 -1
- package/dist/dashboard/delta-badge.js +33 -1
- package/dist/dashboard/empty-state.d.ts +1 -4
- package/dist/dashboard/empty-state.d.ts.map +1 -1
- package/dist/dashboard/empty-state.js +1 -2
- package/dist/dashboard/index.d.ts +4 -2
- package/dist/dashboard/index.d.ts.map +1 -1
- package/dist/dashboard/index.js +7 -1
- package/dist/dashboard/query-state.d.ts +4 -13
- package/dist/dashboard/query-state.d.ts.map +1 -1
- package/dist/dashboard/query-state.js +4 -7
- package/dist/{section → dashboard}/section.d.ts +2 -2
- package/dist/{section → dashboard}/section.d.ts.map +1 -1
- package/dist/{section → dashboard}/section.js +2 -2
- package/dist/dashboard/settings-section.d.ts +1 -1
- package/dist/dashboard/settings-section.d.ts.map +1 -1
- package/dist/dashboard/settings-section.js +1 -1
- package/dist/dashboard/stat-card.d.ts +1 -1
- package/dist/dashboard/stat-card.d.ts.map +1 -1
- package/dist/dashboard/stat-card.js +1 -1
- package/dist/dashboard/widget-header.d.ts.map +1 -0
- package/dist/data/data-table.js +2 -2
- package/dist/data/table.d.ts +1 -1
- package/dist/data/table.d.ts.map +1 -1
- package/dist/data/table.js +2 -16
- package/dist/data/virtual.d.ts +3 -3
- package/dist/dev-dock.d.ts +26 -0
- package/dist/dev-dock.d.ts.map +1 -0
- package/dist/dev-dock.js +85 -0
- package/dist/format/date.d.ts +62 -0
- package/dist/format/date.d.ts.map +1 -0
- package/dist/format/date.js +106 -0
- package/dist/format/index.d.ts +39 -0
- package/dist/format/index.d.ts.map +1 -0
- package/dist/format/index.js +54 -0
- package/dist/format/measure.d.ts +15 -0
- package/dist/format/measure.d.ts.map +1 -0
- package/dist/format/measure.js +16 -0
- package/dist/format/number.d.ts +69 -0
- package/dist/format/number.d.ts.map +1 -0
- package/dist/format/number.js +62 -0
- package/dist/format/shared.d.ts +27 -0
- package/dist/format/shared.d.ts.map +1 -0
- package/dist/format/shared.js +29 -0
- package/dist/forms/field.d.ts +4 -20
- package/dist/forms/field.d.ts.map +1 -1
- package/dist/forms/field.js +0 -4
- package/dist/forms/form-layout.d.ts +1 -1
- package/dist/forms/form-layout.d.ts.map +1 -1
- package/dist/forms/form-layout.js +1 -1
- package/dist/forms/index.d.ts +1 -1
- package/dist/forms/index.d.ts.map +1 -1
- package/dist/forms/index.js +1 -2
- package/dist/forms/use-form-submit.d.ts +1 -1
- package/dist/forms/use-form-submit.js +1 -1
- package/dist/guard/index.d.ts +2 -9
- package/dist/guard/index.d.ts.map +1 -1
- package/dist/guard/index.js +53 -32
- package/dist/guard/types.d.ts +8 -10
- package/dist/guard/types.d.ts.map +1 -1
- package/dist/index.d.ts +16 -11
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +23 -29
- package/dist/notifications/index.d.ts +5 -5
- package/dist/notifications/index.d.ts.map +1 -1
- package/dist/notifications/index.js +0 -2
- package/dist/notifications/mount-guard.d.ts.map +1 -1
- package/dist/notifications/mount-guard.js +2 -2
- package/dist/provider/connectivity-indicator.d.ts.map +1 -0
- package/dist/{connectivity → provider}/connectivity-provider.d.ts +1 -1
- package/dist/provider/connectivity-provider.d.ts.map +1 -0
- package/dist/{connectivity/types.d.ts → provider/connectivity-types.d.ts} +1 -1
- package/dist/provider/connectivity-types.d.ts.map +1 -0
- package/dist/provider/error-fallback.module.css +21 -0
- package/dist/provider/error-fallback.module.css.d.ts +9 -0
- package/dist/provider/index.d.ts +20 -36
- package/dist/provider/index.d.ts.map +1 -1
- package/dist/provider/index.js +42 -32
- package/dist/provider/lab-theme.js +1 -1
- package/dist/provider/use-connectivity.d.ts +3 -0
- package/dist/provider/use-connectivity.d.ts.map +1 -0
- package/dist/query-client.d.ts +67 -0
- package/dist/query-client.d.ts.map +1 -0
- package/dist/query-client.js +35 -0
- package/dist/{query/devtools.d.ts → query-devtools.d.ts} +2 -2
- package/dist/query-devtools.d.ts.map +1 -0
- package/dist/register.d.ts +17 -3
- package/dist/register.d.ts.map +1 -1
- package/dist/router-tanstack/index.d.ts +4 -7
- package/dist/router-tanstack/index.d.ts.map +1 -1
- package/dist/router-tanstack/index.js +1 -9
- package/dist/router-tanstack/nav.d.ts +1 -1
- package/dist/router-tanstack/nav.d.ts.map +1 -1
- package/dist/router-tanstack/search-store.d.ts +3 -6
- package/dist/router-tanstack/search-store.d.ts.map +1 -1
- package/dist/router-tanstack/use-nav.d.ts +1 -1
- package/dist/router-tanstack/use-nav.d.ts.map +1 -1
- package/dist/shell/app-breadcrumbs.d.ts +1 -1
- package/dist/shell/app-breadcrumbs.d.ts.map +1 -1
- package/dist/shell/app-main.module.css +11 -0
- package/dist/shell/app-mobile-nav.d.ts +1 -1
- package/dist/shell/app-mobile-nav.d.ts.map +1 -1
- package/dist/shell/app-mobile-nav.js +24 -2
- package/dist/shell/app-sidebar.d.ts +1 -1
- package/dist/shell/app-sidebar.d.ts.map +1 -1
- package/dist/shell/app-sidebar.js +31 -2
- package/dist/shell/app-sidebar.module.css +10 -0
- package/dist/shell/index.d.ts +10 -4
- package/dist/shell/index.d.ts.map +1 -1
- package/dist/shell/index.js +13 -17
- package/dist/shell/mobile-nav-model.d.ts +1 -1
- package/dist/shell/mobile-nav-model.d.ts.map +1 -1
- package/dist/{nav/types.d.ts → shell/nav-types.d.ts} +1 -1
- package/dist/shell/nav-types.d.ts.map +1 -0
- package/dist/shell/page-aside.d.ts.map +1 -1
- package/dist/shell/page-aside.js +2 -29
- package/dist/shell/page-title.d.ts +14 -0
- package/dist/shell/page-title.d.ts.map +1 -0
- package/dist/shell/page-title.js +25 -0
- package/dist/shell/page-title.module.css +33 -0
- package/dist/shell/page-title.module.css.d.ts +11 -0
- package/dist/shell/sidebar-block-model.d.ts +1 -1
- package/dist/shell/sidebar-block-model.d.ts.map +1 -1
- package/dist/shell/sidebar-blocks.d.ts +1 -1
- package/dist/shell/sidebar-blocks.d.ts.map +1 -1
- package/dist/shell/use-breakpoint.d.ts +11 -0
- package/dist/shell/use-breakpoint.d.ts.map +1 -0
- package/dist/shell/use-breakpoint.js +33 -0
- package/dist/state/fields.d.ts +3 -19
- package/dist/state/fields.d.ts.map +1 -1
- package/dist/state/fields.js +6 -16
- package/dist/styles.css +36 -0
- package/dist/surfaces.d.ts +18 -41
- package/dist/surfaces.d.ts.map +1 -1
- package/dist/surfaces.js +48 -60
- package/dist/theme/index.d.ts.map +1 -1
- package/dist/{theme-toggle/index.d.ts → theme/theme-toggle.d.ts} +1 -1
- package/dist/theme/theme-toggle.d.ts.map +1 -0
- package/dist/{theme-toggle/index.js → theme/theme-toggle.js} +1 -1
- package/dist/tokens/index.d.ts +1 -0
- package/dist/tokens/index.d.ts.map +1 -1
- package/dist/tokens/index.js +10 -0
- package/dist/tokens/palette.d.ts +12 -0
- package/dist/tokens/palette.d.ts.map +1 -1
- package/dist/tokens/palette.js +13 -1
- package/dist/tokens.css +1 -0
- package/llms.txt +9 -24
- package/package.json +12 -16
- package/src/agent/ai-sdk-transport.ts +11 -4
- package/src/agent/coalesce.ts +1 -1
- package/src/agent/merge.ts +1 -1
- package/src/agent/transport.ts +15 -2
- package/src/agent/use-agent-thread-runs.ts +65 -15
- package/src/agent-chat/index.ts +6 -4
- package/src/agent-chat/relative-time.ts +1 -1
- package/src/agent-chat/thread-detail-panel.tsx +1 -1
- package/src/agent-chat/thread-feed-row.tsx +105 -30
- package/src/agent-chat/thread-feed.tsx +51 -25
- package/src/agent-chat/thread-message.tsx +1 -1
- package/src/agent-chat/virtualize.ts +48 -0
- package/src/charts/index.ts +7 -10
- package/src/charts/kinds/BandStrip.tsx +1 -1
- package/src/charts/kinds/Bars.tsx +2 -5
- package/src/charts/kinds/DualPanel.tsx +4 -3
- package/src/charts/kinds/StackedArea.tsx +1 -1
- package/src/charts/kinds/ZonedLine.tsx +1 -4
- package/src/charts/primitives/Axes.tsx +49 -0
- package/src/charts/primitives/ChartCard.tsx +49 -6
- package/src/charts/primitives/ChartFrame.tsx +5 -1
- package/src/charts/primitives/ChartPending.tsx +14 -8
- package/src/charts/utils/format.ts +17 -186
- package/src/cli/audit-allows.ts +371 -0
- package/src/cli/check-theme.ts +197 -0
- package/src/cli/doctor.ts +331 -0
- package/src/cli/guard-hook.ts +115 -0
- package/src/cli/help.ts +101 -0
- package/src/cli/index.ts +269 -3439
- package/src/cli/init.ts +247 -0
- package/src/cli/sync.ts +324 -0
- package/src/cli/tokens-css.ts +252 -0
- package/src/commands/define-commands.ts +1 -1
- package/src/commands/define-overlays.ts +1 -1
- package/src/commands/index.ts +10 -1
- package/src/commands/overlays-mount.tsx +8 -10
- package/src/commands/shell-bridge.ts +86 -0
- package/src/common/errors.ts +70 -0
- package/src/common/index.ts +2 -0
- package/src/common/props.ts +1 -1
- package/src/common/validate.ts +1 -1
- package/src/content/markdown.tsx +4 -8
- package/src/controls/actions.tsx +1 -1
- package/src/controls/panel-row.tsx +1 -1
- package/src/controls/range-filter.tsx +1 -1
- package/src/dashboard/delta-badge.tsx +74 -7
- package/src/dashboard/empty-state.tsx +2 -6
- package/src/dashboard/index.ts +11 -2
- package/src/dashboard/query-state.tsx +5 -18
- package/src/{section → dashboard}/section.tsx +4 -4
- package/src/dashboard/settings-section.tsx +2 -2
- package/src/dashboard/stat-card.tsx +2 -2
- package/src/data/data-table.tsx +3 -3
- package/src/data/table.ts +6 -25
- package/src/data/virtual-list.tsx +1 -1
- package/src/data/virtual.ts +3 -3
- package/src/dev-dock.tsx +162 -0
- package/src/format/date.ts +184 -0
- package/src/format/index.ts +69 -0
- package/src/format/measure.ts +31 -0
- package/src/format/number.ts +129 -0
- package/src/format/shared.ts +63 -0
- package/src/forms/field.ts +4 -24
- package/src/forms/form-layout.tsx +2 -2
- package/src/forms/index.ts +1 -2
- package/src/forms/use-form-submit.ts +2 -2
- package/src/guard/index.ts +80 -69
- package/src/guard/types.ts +7 -10
- package/src/index.ts +38 -29
- package/src/notifications/index.ts +5 -7
- package/src/notifications/mount-guard.ts +7 -9
- package/src/{connectivity → provider}/connectivity-indicator.tsx +1 -1
- package/src/{connectivity → provider}/connectivity-provider.tsx +1 -1
- package/src/provider/error-fallback.module.css +21 -0
- package/src/provider/error-fallback.module.css.d.ts +9 -0
- package/src/provider/index.tsx +71 -71
- package/src/provider/lab-theme.ts +1 -1
- package/src/{connectivity → provider}/use-connectivity.ts +3 -3
- package/src/query-client.ts +105 -0
- package/src/{query/devtools.tsx → query-devtools.tsx} +5 -4
- package/src/register.ts +20 -4
- package/src/router-tanstack/index.ts +4 -15
- package/src/router-tanstack/nav.ts +1 -1
- package/src/router-tanstack/search-store.ts +3 -4
- package/src/router-tanstack/use-nav.ts +1 -1
- package/src/shell/app-breadcrumbs.tsx +1 -1
- package/src/shell/app-main.module.css +11 -0
- package/src/shell/app-mobile-nav.tsx +28 -1
- package/src/shell/app-sidebar.module.css +10 -0
- package/src/shell/app-sidebar.tsx +31 -2
- package/src/shell/index.tsx +23 -28
- package/src/shell/mobile-nav-model.ts +1 -1
- package/src/shell/page-aside.tsx +2 -52
- package/src/shell/page-title.module.css +33 -0
- package/src/shell/page-title.module.css.d.ts +11 -0
- package/src/shell/page-title.tsx +57 -0
- package/src/shell/sidebar-block-model.ts +1 -1
- package/src/shell/sidebar-blocks.tsx +1 -1
- package/src/shell/use-breakpoint.ts +73 -0
- package/src/state/fields.ts +7 -43
- package/src/styles.css +36 -0
- package/src/surfaces.ts +47 -61
- package/src/theme/index.ts +7 -0
- package/src/{theme-toggle/index.tsx → theme/theme-toggle.tsx} +1 -1
- package/src/tokens/index.ts +10 -0
- package/src/tokens/palette.ts +12 -0
- package/dist/connectivity/connectivity-indicator.d.ts.map +0 -1
- package/dist/connectivity/connectivity-provider.d.ts.map +0 -1
- package/dist/connectivity/index.d.ts +0 -14
- package/dist/connectivity/index.d.ts.map +0 -1
- package/dist/connectivity/index.js +0 -8
- package/dist/connectivity/types.d.ts.map +0 -1
- package/dist/connectivity/use-connectivity.d.ts +0 -3
- package/dist/connectivity/use-connectivity.d.ts.map +0 -1
- package/dist/data/index.d.ts +0 -38
- package/dist/data/index.d.ts.map +0 -1
- package/dist/data/index.js +0 -24
- package/dist/motion/index.d.ts.map +0 -1
- package/dist/nav/types.d.ts.map +0 -1
- package/dist/notifications/overlay.d.ts +0 -20
- package/dist/notifications/overlay.d.ts.map +0 -1
- package/dist/notifications/overlay.js +0 -14
- package/dist/query/devtools.d.ts.map +0 -1
- package/dist/query/error-message.d.ts +0 -41
- package/dist/query/error-message.d.ts.map +0 -1
- package/dist/query/error-message.js +0 -30
- package/dist/query/index.d.ts +0 -47
- package/dist/query/index.d.ts.map +0 -1
- package/dist/query/index.js +0 -56
- package/dist/router-tanstack/field.d.ts +0 -14
- package/dist/router-tanstack/field.d.ts.map +0 -1
- package/dist/router-tanstack/field.js +0 -4
- package/dist/router-tanstack/multi-search-param-store.d.ts +0 -43
- package/dist/router-tanstack/multi-search-param-store.d.ts.map +0 -1
- package/dist/router-tanstack/multi-search-param-store.js +0 -30
- package/dist/router-tanstack/search-param-store.d.ts +0 -42
- package/dist/router-tanstack/search-param-store.d.ts.map +0 -1
- package/dist/router-tanstack/search-param-store.js +0 -25
- package/dist/section/index.d.ts +0 -2
- package/dist/section/index.d.ts.map +0 -1
- package/dist/section/index.js +0 -4
- package/dist/theme-toggle/index.d.ts.map +0 -1
- package/dist/utils/is-dev.d.ts.map +0 -1
- package/dist/widget-header/delta-badge.d.ts +0 -19
- package/dist/widget-header/delta-badge.d.ts.map +0 -1
- package/dist/widget-header/delta-badge.js +0 -36
- package/dist/widget-header/index.d.ts +0 -3
- package/dist/widget-header/index.d.ts.map +0 -1
- package/dist/widget-header/index.js +0 -8
- package/dist/widget-header/widget-header.d.ts.map +0 -1
- package/src/connectivity/index.ts +0 -19
- package/src/data/index.ts +0 -69
- package/src/notifications/overlay.tsx +0 -66
- package/src/query/error-message.ts +0 -70
- package/src/query/index.ts +0 -97
- package/src/router-tanstack/field.ts +0 -36
- package/src/router-tanstack/multi-search-param-store.ts +0 -106
- package/src/router-tanstack/search-param-store.ts +0 -100
- package/src/section/index.ts +0 -1
- package/src/widget-header/delta-badge.tsx +0 -77
- package/src/widget-header/index.ts +0 -10
- /package/dist/{utils → common}/is-dev.d.ts +0 -0
- /package/dist/{utils → common}/is-dev.js +0 -0
- /package/dist/{motion/index.js → common/motion.js} +0 -0
- /package/dist/{section → dashboard}/section.module.css +0 -0
- /package/dist/{section → dashboard}/section.module.css.d.ts +0 -0
- /package/dist/{widget-header → dashboard}/widget-header.d.ts +0 -0
- /package/dist/{widget-header → dashboard}/widget-header.js +0 -0
- /package/dist/{widget-header → dashboard}/widget-header.module.css +0 -0
- /package/dist/{widget-header → dashboard}/widget-header.module.css.d.ts +0 -0
- /package/dist/{connectivity → provider}/connectivity-indicator.d.ts +0 -0
- /package/dist/{connectivity → provider}/connectivity-indicator.js +0 -0
- /package/dist/{connectivity → provider}/connectivity-provider.js +0 -0
- /package/dist/{connectivity/types.js → provider/connectivity-types.js} +0 -0
- /package/dist/{connectivity → provider}/use-connectivity.js +0 -0
- /package/dist/{query/devtools.js → query-devtools.js} +0 -0
- /package/dist/{nav/types.js → shell/nav-types.js} +0 -0
- /package/src/{utils → common}/is-dev.ts +0 -0
- /package/src/{motion/index.ts → common/motion.ts} +0 -0
- /package/src/{section → dashboard}/section.module.css +0 -0
- /package/src/{section → dashboard}/section.module.css.d.ts +0 -0
- /package/src/{widget-header → dashboard}/widget-header.module.css +0 -0
- /package/src/{widget-header → dashboard}/widget-header.module.css.d.ts +0 -0
- /package/src/{widget-header → dashboard}/widget-header.tsx +0 -0
- /package/src/{connectivity/types.ts → provider/connectivity-types.ts} +0 -0
- /package/src/{nav/types.ts → shell/nav-types.ts} +0 -0
|
@@ -1,10 +1,77 @@
|
|
|
1
1
|
/**
|
|
2
|
-
*
|
|
3
|
-
*
|
|
4
|
-
*
|
|
2
|
+
* DeltaBadge — the KPI trend chip (docs/DESIGN-SPEC.md §5): mono 11.5px weight 600, status-color
|
|
3
|
+
* text on a status-13% tint, control radius, 2px/7px padding, optional ▲/▼ glyph at 9px.
|
|
4
|
+
* `polarity` decides the TONE the sign maps to — `'up-good'` (default) reads a rise as success and
|
|
5
|
+
* a fall as danger; `'up-bad'` inverts that for a metric where a rise is the worse reading (a
|
|
6
|
+
* cycle-top index, latency, error rate); `'neutral'` renders every sign in a faint, non-verdict
|
|
7
|
+
* tint. Zero is always faint with no glyph, under every polarity. The label never carries a
|
|
8
|
+
* leading "+"; pass `format` to control the magnitude string (defaults to a one-decimal percentage
|
|
9
|
+
* of the absolute value). The ▲/▼ glyph is DIRECTION, not verdict, and stays polarity-independent —
|
|
10
|
+
* governed only by `withGlyph` and the sign.
|
|
5
11
|
*
|
|
6
|
-
*
|
|
7
|
-
*
|
|
8
|
-
*
|
|
12
|
+
* Mantine-free (plain `<span>` + this folder's CSS module, docs/CONTROLS-SPEC.md §2.2) so
|
|
13
|
+
* `WidgetHeader` can compose it from inside `charts/` without tripping `basalt/token-layer-
|
|
14
|
+
* boundary` or `check-dist-layering.mjs`.
|
|
15
|
+
*
|
|
16
|
+
* @example
|
|
17
|
+
* import { DeltaBadge } from 'basalt-ui'
|
|
18
|
+
*
|
|
19
|
+
* <DeltaBadge value={12.4} /> // ▲ 12.4%, success tint
|
|
20
|
+
* <DeltaBadge value={-3.1} /> // ▼ 3.1%, danger tint
|
|
21
|
+
* <DeltaBadge value={0} /> // 0.0%, neutral faint tint, no glyph
|
|
22
|
+
* <DeltaBadge value={182} format={(v) => `${Math.abs(v)}ms`} withGlyph={false} />
|
|
23
|
+
* <DeltaBadge value={35.9} polarity="up-bad" /> // ▲ 35.9%, danger tint — a rise is bad here
|
|
9
24
|
*/
|
|
10
|
-
|
|
25
|
+
import { alpha, VX } from '../tokens'
|
|
26
|
+
import classes from './widget-header.module.css'
|
|
27
|
+
|
|
28
|
+
export type DeltaPolarity = 'up-good' | 'up-bad' | 'neutral'
|
|
29
|
+
|
|
30
|
+
export type DeltaBadgeProps = {
|
|
31
|
+
/** Signed delta driving tone (positive/negative/zero) and, by default, the label magnitude. */
|
|
32
|
+
value: number
|
|
33
|
+
/** Which sign reads as the good verdict. `'up-good'` (default) is today's behaviour — positive
|
|
34
|
+
* success, negative danger. `'up-bad'` inverts it for a metric where a rise is the worse reading.
|
|
35
|
+
* `'neutral'` renders every sign in the faint tint — a change with no verdict attached. Zero is
|
|
36
|
+
* always faint regardless. */
|
|
37
|
+
polarity?: DeltaPolarity
|
|
38
|
+
/** Formats the value into the label text. Defaults to `${Math.abs(value).toFixed(1)}%`. */
|
|
39
|
+
format?: (value: number) => string
|
|
40
|
+
/** Render the ▲/▼ direction glyph. Defaults to `true`; a zero value never shows a glyph. */
|
|
41
|
+
withGlyph?: boolean
|
|
42
|
+
/** Optional comparison timeframe rendered directly after the value in a dimmer shade of the same
|
|
43
|
+
* tone (e.g. `MoM`, `WoW`, `YTD`) — states what the delta is measured against without a hover. */
|
|
44
|
+
period?: string | undefined
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
const defaultFormat = (value: number): string => `${Math.abs(value).toFixed(1)}%`
|
|
48
|
+
|
|
49
|
+
function resolveTone(value: number, polarity: DeltaPolarity): string {
|
|
50
|
+
if (value === 0 || polarity === 'neutral') return VX.faint
|
|
51
|
+
const rose = value > 0
|
|
52
|
+
const good = polarity === 'up-good' ? rose : !rose
|
|
53
|
+
return good ? VX.status.good : VX.status.bad
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
export function DeltaBadge({
|
|
57
|
+
value,
|
|
58
|
+
polarity = 'up-good',
|
|
59
|
+
format = defaultFormat,
|
|
60
|
+
withGlyph = true,
|
|
61
|
+
period,
|
|
62
|
+
}: DeltaBadgeProps) {
|
|
63
|
+
const tone = resolveTone(value, polarity)
|
|
64
|
+
const glyph = value > 0 ? '▲' : value < 0 ? '▼' : undefined
|
|
65
|
+
const showGlyph = withGlyph && glyph !== undefined
|
|
66
|
+
|
|
67
|
+
return (
|
|
68
|
+
<span
|
|
69
|
+
className={classes.deltaBadge}
|
|
70
|
+
style={{ backgroundColor: alpha(tone, 0.13), color: tone }}
|
|
71
|
+
>
|
|
72
|
+
{showGlyph && <span className={classes.deltaGlyph}>{glyph}</span>}
|
|
73
|
+
{format(value)}
|
|
74
|
+
{period !== undefined && <span className={classes.deltaPeriod}>{period}</span>}
|
|
75
|
+
</span>
|
|
76
|
+
)
|
|
77
|
+
}
|
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
* EmptyState — a centered icon/title/description/action stack for empty data regions (no shipped
|
|
3
3
|
* illustration assets — `icon` is a plain, faint-rendered `ReactNode` slot). `tier="page"` uses
|
|
4
4
|
* generous vertical padding for a full-page empty state; `tier="section"` is compact, for an
|
|
5
|
-
* empty card/panel region
|
|
5
|
+
* empty card/panel region.
|
|
6
6
|
*
|
|
7
7
|
* @example
|
|
8
8
|
* import { EmptyState } from 'basalt-ui'
|
|
@@ -41,9 +41,6 @@ export type EmptyStateProps = BasaltProps &
|
|
|
41
41
|
/** How loud this state is: `'page'` (default) = generous padding for a full-page state;
|
|
42
42
|
* `'section'` = compact. */
|
|
43
43
|
tier?: 'page' | 'section'
|
|
44
|
-
/** @deprecated Renamed to `tier` (audit B #19) — `tier` is the package's word for "how loud is
|
|
45
|
-
* this". Still honoured; `tier` wins when both are passed. */
|
|
46
|
-
variant?: 'page' | 'section'
|
|
47
44
|
}
|
|
48
45
|
|
|
49
46
|
// The finest density-tracking rhythm step (`--vx-space-stack-xs`, 4px at level 0) scaled by an
|
|
@@ -63,12 +60,11 @@ export function EmptyState({
|
|
|
63
60
|
description,
|
|
64
61
|
action,
|
|
65
62
|
tier,
|
|
66
|
-
variant,
|
|
67
63
|
className,
|
|
68
64
|
style,
|
|
69
65
|
classNames,
|
|
70
66
|
}: EmptyStateProps) {
|
|
71
|
-
const resolved = tier ??
|
|
67
|
+
const resolved = tier ?? 'page'
|
|
72
68
|
return (
|
|
73
69
|
<Stack
|
|
74
70
|
align="center"
|
package/src/dashboard/index.ts
CHANGED
|
@@ -1,4 +1,14 @@
|
|
|
1
|
-
export {
|
|
1
|
+
export {
|
|
2
|
+
WidgetHeader,
|
|
3
|
+
type WidgetHeaderDeltaProps,
|
|
4
|
+
type WidgetHeaderMetricProps,
|
|
5
|
+
type WidgetHeaderProps,
|
|
6
|
+
type WidgetHeaderSlot,
|
|
7
|
+
type WidgetHeaderTier,
|
|
8
|
+
type WidgetHeaderTitleProps,
|
|
9
|
+
} from './widget-header'
|
|
10
|
+
export { DeltaBadge, type DeltaBadgeProps, type DeltaPolarity } from './delta-badge'
|
|
11
|
+
export { Section, type SectionProps, type SectionSlot } from './section'
|
|
2
12
|
export {
|
|
3
13
|
StatCard,
|
|
4
14
|
type StatCardBreakdownRow,
|
|
@@ -30,7 +40,6 @@ export {
|
|
|
30
40
|
type QueryStateLike,
|
|
31
41
|
type QueryStateSlot,
|
|
32
42
|
type QueryStateTier,
|
|
33
|
-
type QueryStateVariant,
|
|
34
43
|
type QueryEmptyCopy,
|
|
35
44
|
LoadingState,
|
|
36
45
|
type LoadingStateProps,
|
|
@@ -16,7 +16,7 @@
|
|
|
16
16
|
*/
|
|
17
17
|
import { Alert, Button, Center, Group, Loader, Stack, Text } from '@mantine/core'
|
|
18
18
|
import type { CSSProperties, ReactNode } from 'react'
|
|
19
|
-
import { toErrorMessage } from '../
|
|
19
|
+
import { toErrorMessage } from '../common/errors'
|
|
20
20
|
import { cx } from '../common/props'
|
|
21
21
|
import type { BasaltProps, SlotStylesProps } from '../common/props'
|
|
22
22
|
import { EmptyState } from './empty-state'
|
|
@@ -29,14 +29,10 @@ import type { QueryStateLike } from '../common/query-state-like'
|
|
|
29
29
|
*
|
|
30
30
|
* Named `tier`, not `variant` (audit B #19): `tier` is already the package's word for "how loud is
|
|
31
31
|
* this" on `WidgetHeader` and `CtlSlot`, and `'section'` meant two different things across the two
|
|
32
|
-
* spellings.
|
|
33
|
-
* under a consumer.
|
|
32
|
+
* spellings.
|
|
34
33
|
*/
|
|
35
34
|
export type QueryStateTier = 'page' | 'section'
|
|
36
35
|
|
|
37
|
-
/** The former name of {@link QueryStateTier}. Kept as an alias; prefer `QueryStateTier`. */
|
|
38
|
-
export type QueryStateVariant = QueryStateTier
|
|
39
|
-
|
|
40
36
|
/**
|
|
41
37
|
* The structural subset of a TanStack `UseQueryResult` these components read — defined in
|
|
42
38
|
* `common/query-state-like.ts` and re-exported here, where consumers have always imported it from.
|
|
@@ -61,8 +57,6 @@ export type QueryEmptyCopy = {
|
|
|
61
57
|
export type LoadingStateProps = BasaltProps & {
|
|
62
58
|
/** How loud this state is. Default `'page'`. */
|
|
63
59
|
tier?: QueryStateTier
|
|
64
|
-
/** @deprecated Renamed to `tier` — see {@link QueryStateTier}. Still honoured; `tier` wins. */
|
|
65
|
-
variant?: QueryStateTier
|
|
66
60
|
/** Accessible name for the spinner. Say what is loading. */
|
|
67
61
|
label?: string
|
|
68
62
|
}
|
|
@@ -70,12 +64,11 @@ export type LoadingStateProps = BasaltProps & {
|
|
|
70
64
|
/** A spinner on its own — `tier="page"` centres it in a generous block, `'section'` is bare. */
|
|
71
65
|
export function LoadingState({
|
|
72
66
|
tier,
|
|
73
|
-
variant,
|
|
74
67
|
label = 'Loading',
|
|
75
68
|
className,
|
|
76
69
|
style,
|
|
77
70
|
}: LoadingStateProps): ReactNode {
|
|
78
|
-
const resolved = tier ??
|
|
71
|
+
const resolved = tier ?? 'page'
|
|
79
72
|
if (resolved === 'section') {
|
|
80
73
|
return (
|
|
81
74
|
<Loader
|
|
@@ -113,8 +106,6 @@ export type ErrorStateProps = BasaltProps & {
|
|
|
113
106
|
retrying?: boolean
|
|
114
107
|
/** How loud this state is. Default `'page'`. */
|
|
115
108
|
tier?: QueryStateTier
|
|
116
|
-
/** @deprecated Renamed to `tier` — see {@link QueryStateTier}. Still honoured; `tier` wins. */
|
|
117
|
-
variant?: QueryStateTier
|
|
118
109
|
/** Extra controls beside Retry (e.g. a "Back to shares" link). */
|
|
119
110
|
action?: ReactNode
|
|
120
111
|
}
|
|
@@ -130,12 +121,11 @@ export function ErrorState({
|
|
|
130
121
|
onRetry,
|
|
131
122
|
retrying = false,
|
|
132
123
|
tier,
|
|
133
|
-
variant,
|
|
134
124
|
action,
|
|
135
125
|
className,
|
|
136
126
|
style,
|
|
137
127
|
}: ErrorStateProps): ReactNode {
|
|
138
|
-
const resolved = tier ??
|
|
128
|
+
const resolved = tier ?? 'page'
|
|
139
129
|
const alert = (
|
|
140
130
|
<Alert
|
|
141
131
|
color="red"
|
|
@@ -212,8 +202,6 @@ export type QueryStateProps<TData> = BasaltProps &
|
|
|
212
202
|
errorAction?: ReactNode
|
|
213
203
|
/** How loud every branch is. Default `'page'`. */
|
|
214
204
|
tier?: QueryStateTier
|
|
215
|
-
/** @deprecated Renamed to `tier` — see {@link QueryStateTier}. Still honoured; `tier` wins. */
|
|
216
|
-
variant?: QueryStateTier
|
|
217
205
|
/** Replace the default spinner (e.g. with a skeleton grid). */
|
|
218
206
|
loading?: ReactNode
|
|
219
207
|
}
|
|
@@ -246,14 +234,13 @@ export function QueryState<TData>({
|
|
|
246
234
|
errorFallback = 'The request failed.',
|
|
247
235
|
errorAction,
|
|
248
236
|
tier,
|
|
249
|
-
variant,
|
|
250
237
|
loading,
|
|
251
238
|
className,
|
|
252
239
|
style,
|
|
253
240
|
classNames,
|
|
254
241
|
}: QueryStateProps<TData>): ReactNode {
|
|
255
242
|
assertQueryStateLike('QueryState', query)
|
|
256
|
-
const resolvedTier = tier ??
|
|
243
|
+
const resolvedTier = tier ?? 'page'
|
|
257
244
|
// One class for every branch — see {@link QueryStateSlot}. `cx` returns `''` when both are
|
|
258
245
|
// absent, and an empty `className` on a branch that previously carried none would be a DOM diff,
|
|
259
246
|
// so it collapses back to `undefined`.
|
|
@@ -56,11 +56,11 @@ import { CtlSlot } from '../theme'
|
|
|
56
56
|
import { BarActionSlot, isBarActionList } from '../controls/actions'
|
|
57
57
|
import type { SlotActions } from '../controls/actions'
|
|
58
58
|
import { useFilterSurface } from '../controls/filter-context'
|
|
59
|
-
import { QueryState } from '
|
|
60
|
-
import type { QueryEmptyCopy, QueryStateLike } from '
|
|
59
|
+
import { QueryState } from './query-state'
|
|
60
|
+
import type { QueryEmptyCopy, QueryStateLike } from './query-state'
|
|
61
61
|
import { usePersistedOrLocal } from '../state/persisted-or-local'
|
|
62
|
-
import { WidgetHeader } from '
|
|
63
|
-
import type { WidgetHeaderProps } from '
|
|
62
|
+
import { WidgetHeader } from './widget-header'
|
|
63
|
+
import type { WidgetHeaderProps } from './widget-header'
|
|
64
64
|
import classes from './section.module.css'
|
|
65
65
|
|
|
66
66
|
/**
|
|
@@ -30,8 +30,8 @@
|
|
|
30
30
|
*/
|
|
31
31
|
import { Card, Stack } from '@mantine/core'
|
|
32
32
|
import type { ReactNode } from 'react'
|
|
33
|
-
import { WidgetHeader } from '
|
|
34
|
-
import type { WidgetHeaderTitleProps } from '
|
|
33
|
+
import { WidgetHeader } from './widget-header'
|
|
34
|
+
import type { WidgetHeaderTitleProps } from './widget-header'
|
|
35
35
|
import { CtlSlot } from '../theme'
|
|
36
36
|
import { alpha, VX } from '../tokens'
|
|
37
37
|
import { cx } from '../common/props'
|
|
@@ -95,12 +95,12 @@
|
|
|
95
95
|
import { Box, Card, VisuallyHidden } from '@mantine/core'
|
|
96
96
|
import { useEffect, useRef, useState } from 'react'
|
|
97
97
|
import type { CSSProperties, ReactNode } from 'react'
|
|
98
|
-
import { WidgetHeader } from '
|
|
98
|
+
import { WidgetHeader } from './widget-header'
|
|
99
99
|
import type {
|
|
100
100
|
WidgetHeaderDeltaProps,
|
|
101
101
|
WidgetHeaderMetricProps,
|
|
102
102
|
WidgetHeaderTitleProps,
|
|
103
|
-
} from '
|
|
103
|
+
} from './widget-header'
|
|
104
104
|
import { CtlSlot } from '../theme'
|
|
105
105
|
import { VX } from '../tokens'
|
|
106
106
|
import { cx } from '../common/props'
|
package/src/data/data-table.tsx
CHANGED
|
@@ -9,7 +9,7 @@
|
|
|
9
9
|
* exactly as before.
|
|
10
10
|
*
|
|
11
11
|
* @example
|
|
12
|
-
* import { BasaltDataTable } from 'basalt-ui/data'
|
|
12
|
+
* import { BasaltDataTable } from 'basalt-ui/data/table'
|
|
13
13
|
* import { createColumnHelper } from '@tanstack/react-table'
|
|
14
14
|
*
|
|
15
15
|
* type Row = { name: string; age: number }
|
|
@@ -88,11 +88,11 @@ import { MultiSelectFilter } from '../controls/multi-select-filter'
|
|
|
88
88
|
import { CtlSlot } from '../theme'
|
|
89
89
|
import { alpha, VX } from '../tokens'
|
|
90
90
|
import type { EnumField, FieldHandle, MultiField } from '../state'
|
|
91
|
-
import { WidgetHeader } from '../
|
|
91
|
+
import { WidgetHeader } from '../dashboard'
|
|
92
92
|
import { ErrorState } from '../dashboard/query-state'
|
|
93
93
|
import type { QueryStateLike } from '../dashboard/query-state'
|
|
94
94
|
import { dataQueryBranch } from './query-branch'
|
|
95
|
-
import { isDev } from '../
|
|
95
|
+
import { isDev } from '../common/is-dev'
|
|
96
96
|
import classes from './data-table.module.css'
|
|
97
97
|
|
|
98
98
|
// ── Column alignment ──────────────────────────────────────────────────────────
|
package/src/data/table.ts
CHANGED
|
@@ -31,28 +31,9 @@ export type {
|
|
|
31
31
|
DataTableFacetOption,
|
|
32
32
|
} from './data-table'
|
|
33
33
|
|
|
34
|
-
// ── @tanstack/react-table convenience re-
|
|
35
|
-
//
|
|
36
|
-
//
|
|
37
|
-
//
|
|
38
|
-
//
|
|
39
|
-
|
|
40
|
-
// consumer code.
|
|
41
|
-
export {
|
|
42
|
-
createColumnHelper,
|
|
43
|
-
useReactTable,
|
|
44
|
-
flexRender,
|
|
45
|
-
getCoreRowModel,
|
|
46
|
-
getSortedRowModel,
|
|
47
|
-
getFilteredRowModel,
|
|
48
|
-
getPaginationRowModel,
|
|
49
|
-
type ColumnDef,
|
|
50
|
-
type SortingState,
|
|
51
|
-
type ColumnHelper,
|
|
52
|
-
type PaginationState,
|
|
53
|
-
type ColumnPinningState,
|
|
54
|
-
// The selection map `rowSelection`/`onRowSelectionChange` speak — `Record<rowId, boolean>`.
|
|
55
|
-
type RowSelectionState,
|
|
56
|
-
// The type `onColumnFiltersChange` hands back — needed at the call site for server-side faceting.
|
|
57
|
-
type ColumnFiltersState,
|
|
58
|
-
} from '@tanstack/react-table'
|
|
34
|
+
// ── @tanstack/react-table convenience re-export ───────────────────────────────
|
|
35
|
+
// `createColumnHelper` is the one raw TanStack symbol every `BasaltDataTable` call site needs to
|
|
36
|
+
// build its `columns` array (C1 consolidation: every OTHER pass-through — `useReactTable`,
|
|
37
|
+
// `flexRender`, the row-model builders, and the type re-exports — was unused by any consumer;
|
|
38
|
+
// import TanStack directly for those).
|
|
39
|
+
export { createColumnHelper } from '@tanstack/react-table'
|
|
@@ -5,7 +5,7 @@
|
|
|
5
5
|
* set by ./agent-chat's virtualize mode (see ./data/index.ts), so do not lower it.
|
|
6
6
|
*
|
|
7
7
|
* @example
|
|
8
|
-
* import { BasaltVirtualList } from 'basalt-ui/data'
|
|
8
|
+
* import { BasaltVirtualList } from 'basalt-ui/data/virtual'
|
|
9
9
|
*
|
|
10
10
|
* const items = Array.from({ length: 10_000 }, (_, i) => ({ id: i, label: `Row ${i}` }))
|
|
11
11
|
* <BasaltVirtualList
|
package/src/data/virtual.ts
CHANGED
|
@@ -3,10 +3,10 @@
|
|
|
3
3
|
* rendered with a Mantine Box scroll container.
|
|
4
4
|
*
|
|
5
5
|
* Optional peer: @tanstack/react-virtual >=3.13.26 <4. This list works on any 3.x — the floor is
|
|
6
|
-
* set by ./agent-chat's virtualize mode
|
|
6
|
+
* set by ./agent-chat's virtualize mode, so do not lower it.
|
|
7
7
|
*
|
|
8
|
-
*
|
|
9
|
-
* —
|
|
8
|
+
* This subpath does NOT value-import @tanstack/react-table, so the data-table peer is never
|
|
9
|
+
* required — use `./data/table` when your app only needs the table.
|
|
10
10
|
*
|
|
11
11
|
* Install with:
|
|
12
12
|
* bun add @tanstack/react-virtual
|
package/src/dev-dock.tsx
ADDED
|
@@ -0,0 +1,162 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* `BasaltDevDock` — a fixed, dev-only bottom drawer hosting the in-app tooling: TanStack Router
|
|
3
|
+
* devtools, TanStack Query devtools (the embeddable `ReactQueryDevtoolsPanel` — NOT
|
|
4
|
+
* `BasaltQueryDevtools`, which wraps the floating-button `ReactQueryDevtools` and would duplicate
|
|
5
|
+
* this dock's own chrome), and the theme lab (`basalt-ui/theme-lab`'s `ThemeLabControls`). Ported
|
|
6
|
+
* from argo's `components/dev-dock.tsx` (91 lines) — same three-tool shape, same "only renders the
|
|
7
|
+
* ACTIVE panel" contract: the launcher (which tool is open) lives wherever the consumer puts it —
|
|
8
|
+
* a `SettingsMenuItem` per tool with `active` set to the currently-open one (C5's
|
|
9
|
+
* `SettingsMenuItem.active`) is the seeded pattern — this component owns only the render.
|
|
10
|
+
*
|
|
11
|
+
* Every dependency is an OPTIONAL peer, loaded lazily so importing (or even rendering, with
|
|
12
|
+
* `tool={null}`) this module never requires `@tanstack/react-router-devtools`,
|
|
13
|
+
* `@tanstack/react-query-devtools` or `@tanstack/react-router` unless a consumer actually opens
|
|
14
|
+
* that tool — same discipline as `BasaltQueryDevtools` (`query-devtools.tsx`) and
|
|
15
|
+
* `ThemeLabControls`'s own `React.lazy` wrapper here. In production this returns `null`
|
|
16
|
+
* immediately, before any dynamic import fires.
|
|
17
|
+
*
|
|
18
|
+
* @example
|
|
19
|
+
* import { BasaltDevDock, type BasaltDevDockTool } from 'basalt-ui'
|
|
20
|
+
* import { useState } from 'react'
|
|
21
|
+
* import { useRouter } from '@tanstack/react-router'
|
|
22
|
+
*
|
|
23
|
+
* function DevTools() {
|
|
24
|
+
* const [tool, setTool] = useState<BasaltDevDockTool | null>(null)
|
|
25
|
+
* const router = useRouter()
|
|
26
|
+
* return <BasaltDevDock tool={tool} onClose={() => setTool(null)} router={router} />
|
|
27
|
+
* }
|
|
28
|
+
* // wire the launchers as settings-menu entries with `active: tool === 'router'` etc.
|
|
29
|
+
*/
|
|
30
|
+
import { lazy, Suspense } from 'react'
|
|
31
|
+
import type { ReactNode } from 'react'
|
|
32
|
+
import { Box, CloseButton, Flex, Group, Text } from '@mantine/core'
|
|
33
|
+
import type { BasaltProps } from './common/props'
|
|
34
|
+
import type { ThemeLabControlsProps } from './theme-lab'
|
|
35
|
+
|
|
36
|
+
/** Which panel is open. `null` renders nothing (the dock is unmounted, not hidden). */
|
|
37
|
+
export type BasaltDevDockTool = 'router' | 'query' | 'theme'
|
|
38
|
+
|
|
39
|
+
const TOOL_TITLE: Record<BasaltDevDockTool, string> = {
|
|
40
|
+
router: 'Router Devtools',
|
|
41
|
+
query: 'Query Devtools',
|
|
42
|
+
theme: 'Theme Lab',
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
// Any non-null object — avoids a hard, eager type dependency on `@tanstack/react-router` for a
|
|
46
|
+
// consumer who never renders the `'router'` tool, while still accepting a REAL `Router` class
|
|
47
|
+
// instance with no cast. A narrower structural type (matching a `Router` field, or falling back
|
|
48
|
+
// to `Record<string, unknown>`) used to reject that instance under TS weak-type detection: a
|
|
49
|
+
// class instance declares no index signature, so it has no excess-property overlap with either
|
|
50
|
+
// branch. `TanStackRouterDevtoolsPanel` itself takes the real (much wider) `AnyRouter` type; the
|
|
51
|
+
// devtools panel is the only reader of this prop, so `object` is exactly as wide as it needs to be.
|
|
52
|
+
type DevDockRouter = object
|
|
53
|
+
|
|
54
|
+
const LazyRouterDevtoolsPanel = lazy(() =>
|
|
55
|
+
import('@tanstack/react-router-devtools').then((m) => ({
|
|
56
|
+
default: m.TanStackRouterDevtoolsPanel,
|
|
57
|
+
})),
|
|
58
|
+
)
|
|
59
|
+
Object.assign(LazyRouterDevtoolsPanel, { displayName: 'LazyRouterDevtoolsPanel' })
|
|
60
|
+
|
|
61
|
+
// The embeddable PANEL, not `ReactQueryDevtools` (`BasaltQueryDevtools`'s own wrapped export) —
|
|
62
|
+
// that one renders its own floating trigger button + auto-popup shell, which would duplicate the
|
|
63
|
+
// dock's own chrome. `query-devtools.tsx`'s `BasaltQueryDevtools` stays the answer for a consumer
|
|
64
|
+
// who wants the traditional floating-button devtools instead of a dock tab.
|
|
65
|
+
const LazyQueryDevtoolsPanel = lazy(() =>
|
|
66
|
+
import('@tanstack/react-query-devtools').then((m) => ({ default: m.ReactQueryDevtoolsPanel })),
|
|
67
|
+
)
|
|
68
|
+
Object.assign(LazyQueryDevtoolsPanel, { displayName: 'LazyQueryDevtoolsPanel' })
|
|
69
|
+
|
|
70
|
+
const LazyThemeLabControls = lazy(() =>
|
|
71
|
+
import('./theme-lab').then((m) => ({ default: m.ThemeLabControls })),
|
|
72
|
+
)
|
|
73
|
+
Object.assign(LazyThemeLabControls, { displayName: 'LazyThemeLabControls' })
|
|
74
|
+
|
|
75
|
+
export type BasaltDevDockProps = BasaltProps & {
|
|
76
|
+
/** Which panel to show. `null` renders nothing. */
|
|
77
|
+
tool: BasaltDevDockTool | null
|
|
78
|
+
/** Called when the dock's own close button fires, or a hosted panel asks to close itself
|
|
79
|
+
* (the router devtools' own `setIsOpen`, the query devtools' own `onClose`). */
|
|
80
|
+
onClose: () => void
|
|
81
|
+
/** The active TanStack `Router` instance — required only to render the `'router'` tool; a
|
|
82
|
+
* consumer that never opens it may omit this entirely. */
|
|
83
|
+
router?: DevDockRouter
|
|
84
|
+
/** Forwarded to the hosted `ThemeLabControls` (icons, the copy callback — see its own props). */
|
|
85
|
+
themeLab?: ThemeLabControlsProps
|
|
86
|
+
}
|
|
87
|
+
|
|
88
|
+
/**
|
|
89
|
+
* Lazy, production-excluded dock. Safe to mount unconditionally with `tool={null}` — the dynamic
|
|
90
|
+
* imports for whichever peer a tool needs only fire once that tool is actually selected, and
|
|
91
|
+
* never at all in production.
|
|
92
|
+
*/
|
|
93
|
+
export function BasaltDevDock({
|
|
94
|
+
tool,
|
|
95
|
+
onClose,
|
|
96
|
+
router,
|
|
97
|
+
themeLab,
|
|
98
|
+
className,
|
|
99
|
+
style,
|
|
100
|
+
}: BasaltDevDockProps): ReactNode {
|
|
101
|
+
if (process.env['NODE_ENV'] === 'production') return null
|
|
102
|
+
if (tool === null) return null
|
|
103
|
+
|
|
104
|
+
return (
|
|
105
|
+
<Flex
|
|
106
|
+
direction="column"
|
|
107
|
+
{...(className !== undefined && { className })}
|
|
108
|
+
style={{
|
|
109
|
+
position: 'fixed',
|
|
110
|
+
left: 0,
|
|
111
|
+
right: 0,
|
|
112
|
+
bottom: 0,
|
|
113
|
+
height: '42vh',
|
|
114
|
+
zIndex: 400,
|
|
115
|
+
background: 'var(--mantine-color-body)',
|
|
116
|
+
borderTop: '1px solid var(--mantine-color-default-border)',
|
|
117
|
+
// Floating tier: a fixed dock sits above the page like a menu/drawer, so it takes
|
|
118
|
+
// basalt's overlay depth token rather than Mantine's raw shadow ramp.
|
|
119
|
+
boxShadow: 'var(--vx-shadow-overlay)',
|
|
120
|
+
...style,
|
|
121
|
+
}}
|
|
122
|
+
>
|
|
123
|
+
<Group
|
|
124
|
+
justify="space-between"
|
|
125
|
+
px="sm"
|
|
126
|
+
py={6}
|
|
127
|
+
style={{ borderBottom: '1px solid var(--mantine-color-default-border)' }}
|
|
128
|
+
>
|
|
129
|
+
<Text size="xs" fw={600} tt="uppercase" c="dimmed">
|
|
130
|
+
{TOOL_TITLE[tool]}
|
|
131
|
+
</Text>
|
|
132
|
+
<CloseButton size="sm" onClick={onClose} aria-label="Close devtools" />
|
|
133
|
+
</Group>
|
|
134
|
+
{/* theme-allow raw-scroll-container — hosts third-party devtools panels sized to
|
|
135
|
+
height: 100%; they need a real overflow ancestor, not ScrollArea's custom viewport. */}
|
|
136
|
+
<Box style={{ flex: 1, minHeight: 0, overflow: 'auto' }}>
|
|
137
|
+
<Suspense fallback={null}>
|
|
138
|
+
{tool === 'router' && router !== undefined && (
|
|
139
|
+
<LazyRouterDevtoolsPanel
|
|
140
|
+
// The devtools panel's own `router` prop takes the real `AnyRouter` type;
|
|
141
|
+
// `DevDockRouter` is deliberately the widest structural stand-in (`object`) so this
|
|
142
|
+
// module never eagerly imports the router's types.
|
|
143
|
+
// oxlint-disable-next-line typescript/no-explicit-any -- see above
|
|
144
|
+
router={router as any}
|
|
145
|
+
isOpen
|
|
146
|
+
setIsOpen={onClose}
|
|
147
|
+
style={{ height: '100%' }}
|
|
148
|
+
/>
|
|
149
|
+
)}
|
|
150
|
+
{tool === 'query' && (
|
|
151
|
+
<LazyQueryDevtoolsPanel onClose={onClose} style={{ height: '100%' }} />
|
|
152
|
+
)}
|
|
153
|
+
{tool === 'theme' && (
|
|
154
|
+
<Box p="md">
|
|
155
|
+
<LazyThemeLabControls {...themeLab} />
|
|
156
|
+
</Box>
|
|
157
|
+
)}
|
|
158
|
+
</Suspense>
|
|
159
|
+
</Box>
|
|
160
|
+
</Flex>
|
|
161
|
+
)
|
|
162
|
+
}
|