basalt-ui 1.28.0 → 1.29.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/AGENTS.md +11 -18
- package/CHANGELOG.md +13 -0
- package/MIGRATING.md +151 -7
- package/README.md +23 -66
- package/agent/rules/basalt-batteries.md +59 -182
- 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/configs/oxlint-plugin.js +70 -167
- package/configs/oxlint-plugin.test.ts +20 -186
- package/configs/oxlint.json +0 -1
- 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 +28 -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.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 +16 -26
- 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 +63 -0
- package/dist/query-client.d.ts.map +1 -0
- package/dist/query-client.js +33 -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 +46 -59
- 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 +159 -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 +1 -1
- package/src/guard/index.ts +30 -56
- 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 +100 -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 +45 -60
- 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
|
@@ -9,212 +9,89 @@ paths:
|
|
|
9
9
|
---
|
|
10
10
|
|
|
11
11
|
<!-- basalt:coverage -->
|
|
12
|
-
<!-- GENERATED from src/surfaces.ts — `
|
|
12
|
+
<!-- GENERATED from src/surfaces.ts — `bun scripts/check-coverage.ts --write`. Do not hand-edit. -->
|
|
13
13
|
<!-- backed by: guard kinds — none · oxlint rules — basalt/agent-no-raw-usechat, basalt/agent-resume-guard, basalt/ai-sdk-major, basalt/forms-field-key, basalt/query-dual-import, basalt/query-fn-unwrap -->
|
|
14
14
|
<!-- not guarded: — -->
|
|
15
15
|
<!-- /basalt:coverage -->
|
|
16
16
|
|
|
17
17
|
# Basalt Batteries — the adapter surfaces
|
|
18
18
|
|
|
19
|
-
Each battery is a subpath with **one** doctrine: the shipped seam is the seam,
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
undefined `data` or an error branch, so there is nothing to decide. Suspense + an error boundary
|
|
40
|
-
and `QueryState` are the two ways to render a query; pick ONE per read. Inside a
|
|
41
|
-
loader-prefetched route, `useSuspenseQuery` + `ensureQueryData` is the pair.
|
|
42
|
-
- **`query` is a structural subset checked at runtime** — a composed or hand-rolled result passes
|
|
43
|
-
with no cast, and a missing `isError` throws naming the field rather than rendering a false claim.
|
|
44
|
-
- Decode an unknown error with `toErrorMessage(err, fallback?)` / `errorStatus(err)`; invalidate by
|
|
45
|
-
resource PREFIX after a mutation; `BasaltQueryDevtools` is lazy and production-excluded, so import
|
|
46
|
-
it unconditionally and never the raw devtools package.
|
|
19
|
+
Each battery is a subpath with **one** doctrine: the shipped seam is the seam, re-rolling it is the
|
|
20
|
+
failure this rule prevents. Every peer is OPTIONAL — install before importing. Full API: the
|
|
21
|
+
shipped types, JSDoc and `llms.txt` at the install directory — this file is only what a reader gets
|
|
22
|
+
wrong without being told.
|
|
23
|
+
|
|
24
|
+
**Not guarded, honestly**: `forms`, `notifications`, `commands`, `data` and `content` carry zero
|
|
25
|
+
guard kinds or oxlint rules — the `not guarded: —` line above is real, not aspirational. Nothing
|
|
26
|
+
fails a build if you re-roll one of these seams by hand; follow the doctrine below on trust.
|
|
27
|
+
|
|
28
|
+
**Deprecation, as a consumer sees it.** A `basalt/deprecated-export` warn means the export still
|
|
29
|
+
works but leaves in a stated `removeIn` minor (autofix renames the import, keeps your local
|
|
30
|
+
binding). The replacement and removal minor are always in `MIGRATING.md` § Unreleased the moment
|
|
31
|
+
the deprecation ships — that file, not the warning text, is where you confirm what to migrate to.
|
|
32
|
+
Maintainer mechanics: package `CLAUDE.md` § Deprecation lifecycle.
|
|
33
|
+
|
|
34
|
+
## Query — `createBasaltQueryClient`/`unwrap` (root barrel, C1: `./query` dropped)
|
|
35
|
+
|
|
36
|
+
`unwrap()` throws on the error branch AND on a `null` data with no error — both are caller bugs.
|
|
37
|
+
Render with `QueryState`, never a hand-written switch (precedence: error-without-data → empty →
|
|
38
|
+
loading → children). One factory per resource via `queryOptions`, never a raw string key.
|
|
47
39
|
|
|
48
40
|
## Eden Treaty — three silent `any`s (stated once)
|
|
49
41
|
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
whose tsconfig path aliases do not resolve identically; and a `t.Object`/`t.Union` **response schema
|
|
54
|
-
on a streaming route** (Eden #231, still open). For a stream: no response schema, an explicit
|
|
55
|
-
`: AsyncGenerator<AgentPart>` return annotation, and validation at yield time via `parseAgentPart`.
|
|
56
|
-
Check these three first whenever Eden types regress.
|
|
42
|
+
Reaches both `unwrap` and `./agent`'s transport: an un-chained route, mismatched tsconfig path
|
|
43
|
+
aliases, and a response schema on a streaming route (Eden #231) all silently degrade inference to
|
|
44
|
+
`any`. Check these three first when Eden types regress.
|
|
57
45
|
|
|
58
46
|
## `./forms` — `@mantine/form`
|
|
59
47
|
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
async one to `useFormSubmit`'s `validateAsync`.
|
|
65
|
-
- **A field is TWO calls on one line**, never one object — a spread `key` is a React 19 warning:
|
|
66
|
-
`<TextInput key={fieldKey(form, 'x')} {...inputProps(form, 'x')} />`. Dropping it is worse: the
|
|
67
|
-
field keeps its old text through `form.reset()` and nothing type-checks differently, so
|
|
68
|
-
**`basalt/forms-field-key`** guards it and autofixes it in. `field` is `@deprecated` (it
|
|
69
|
-
collides with `basalt-ui/state`'s) and NOT an alias — it still bundles `key`.
|
|
70
|
-
- **`FormRow` is law C1's form row** (label left, control right, label above below `sm`) inside a
|
|
71
|
-
**`FormSection`**, clusters in a **`FormGroup`**, **`FormActions`** at the end. `SettingsRow` is
|
|
72
|
-
the settings-page variant — pick by page, never fork a third.
|
|
73
|
-
- **`useFormSubmit` owns the submit**, not a hand-rolled `try`/`catch`: it decodes the throw into
|
|
74
|
-
the form-level `submitError`, routes a `{ fieldErrors }` envelope back onto the fields as inline
|
|
75
|
-
errors and focuses the first. Hand its `isSubmitting` to **`FormStateProvider`** and the layout
|
|
76
|
-
disables itself — never thread `disabled` per input; a custom control reads **`useFormState`**.
|
|
77
|
-
- **`useFieldArray` is the list field**; `key(index)` is positional — reorder by an item id.
|
|
78
|
-
- **`FormErrorSummary` goes at the TOP of the form** so assistive tech lands on it after a failed
|
|
79
|
-
submit. It renders `null` on a clean form, so include it unconditionally.
|
|
80
|
-
- **`useFormDraft` persists through `createPersistedState`** — `autosave: true` owns its own
|
|
81
|
-
subscription, `clearDraft()` on success, keep `key` stable (changing it loses the draft), bump
|
|
82
|
-
`version` on a shape change.
|
|
48
|
+
`useBasaltForm` (`mode: 'uncontrolled'`, `StandardSchemaV1` never `ZodSchema`) +
|
|
49
|
+
`useFormSubmit`/`useFieldArray`/`FormErrorSummary`/`useFormDraft`. A field is two calls, never one
|
|
50
|
+
object (`basalt/forms-field-key` guards + autofixes it) — dropping `key` keeps stale text through
|
|
51
|
+
`form.reset()`.
|
|
83
52
|
|
|
84
53
|
## `./notifications` — `@mantine/notifications`
|
|
85
54
|
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
**never pass a raw color instead of an intent**.
|
|
90
|
-
- **`defineNotifications` + `emit` is the typed registry**: augment `BasaltRegister.notifications`
|
|
91
|
-
once and unknown kinds become tsc errors. `defineNotification` only TYPES a single spec — only
|
|
92
|
-
`defineNotifications(map)` registers, and `emit` before that registration is a runtime no-op.
|
|
93
|
-
- **A spec carries no `title`/`icon`** by design; those stay per-call so a varying title is not
|
|
94
|
-
forced into the registry.
|
|
95
|
-
- **Colors beyond the four intents live OUTSIDE the registry** — call Mantine's raw
|
|
96
|
-
`notifications.show({ color })` directly, and accept the stated cost: a raw toast is invisible to
|
|
97
|
-
the persisted history, the bell and the center, because only `notify`/`notifyPromise` record.
|
|
98
|
-
- **`notifyUndo` is the undo window**, not a toast plus your own `setTimeout`: one number is both
|
|
99
|
-
the `Undo` affordance and the commit delay, `onExpire` is where the optimistic mutation commits,
|
|
100
|
-
`onUndo` reverts, and exactly one of the two ever runs.
|
|
101
|
-
- History is a module-level persisted ring buffer; `useNotificationHistory` reads it, and
|
|
102
|
-
`NotificationBell` (built for the shell's `globalActions`) opens a `NotificationCenter`, which also
|
|
103
|
-
mounts standalone in any Drawer or panel.
|
|
104
|
-
- The overlay MOUNT is basalt-mantine.md's — one place, one statement.
|
|
55
|
+
`notify({ intent, message })` — intent, never a raw color, drives the Mantine color AND the aria
|
|
56
|
+
`role`. `defineNotifications`/`emit` is the typed registry; only persisted-history calls
|
|
57
|
+
(`notify`/`notifyPromise`) reach the bell/center. `notifyUndo` owns the undo-window contract.
|
|
105
58
|
|
|
106
59
|
## `./commands` — the command bus
|
|
107
60
|
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
the live keys. Never hand-author a second list of the same commands.
|
|
118
|
-
- Reach for `openSpotlight`/`closeSpotlight` from `basalt-ui/commands`, not Mantine's global
|
|
119
|
-
`spotlight` — `BasaltOverlays` mounts against basalt's own store.
|
|
120
|
-
- **A confirm dialog is not an overlay you define**: `overlays.confirm` / `overlays.confirmDelete`
|
|
121
|
-
need no registry entry and resolve to the answer. `defineOverlays` is for an overlay with a
|
|
122
|
-
payload and a body of its own.
|
|
123
|
-
- **Imperative overlay vs route**: `overlays.open` for an ephemeral confirm or quick edit; a route
|
|
124
|
-
for anything that must be shareable, refreshable or back-button-addressable.
|
|
125
|
-
|
|
126
|
-
## `./data` — TanStack Table + Virtual
|
|
127
|
-
|
|
128
|
-
- **Read the props before hand-rolling anything**: title/icon/subtitle + count, an `actions`
|
|
129
|
-
toolbar slot, `facets`, global search, client- or server-side pagination, column pinning, sticky
|
|
130
|
-
header, `maxHeight`/`minWidth`, per-column `meta.align` and `meta.numeral` are all there.
|
|
131
|
-
`meta.align` is a `ColumnMeta` augmentation, so a typo is a tsc error and a bad VALUE throws naming
|
|
132
|
-
the column — declare alignment once instead of on both the `th` and the `td`.
|
|
133
|
-
- **Adopt it for ownership, not for a line count.** One consumer's port ran 29–38 lines LONGER:
|
|
134
|
-
accessor blocks cost more than bespoke `<Table.Td>` rows. What it buys is the `type="native"`
|
|
135
|
-
scroll footgun, alignment stated once, and sorting/filtering/pagination no longer being yours.
|
|
136
|
-
A table with no sorting, no pagination, no filter and no alignment to declare is a layout grid —
|
|
137
|
-
adopting the component there buys nothing.
|
|
138
|
-
- **`manualPagination` imposes a contract on every other prop**: `data` becomes one server page
|
|
139
|
-
while the bar still claims `of N`, so sorting (`manualSorting` or `enableSorting={false}`),
|
|
140
|
-
filtering (`manualFiltering`) and the count (`rowCount`) must each be resolved explicitly.
|
|
141
|
-
Unresolved, it throws in dev naming every breach and degrades to the honest table in production.
|
|
142
|
-
Read the throw; don't work around it.
|
|
143
|
-
- **The escape hatch is the same subpath**: `useReactTable`/`flexRender`/the row models are
|
|
144
|
-
re-exported, so a bespoke table needs no direct `@tanstack/react-table` import — and it scrolls
|
|
145
|
-
through the identical `Table.ScrollContainer type="native"` node.
|
|
146
|
-
- **`BasaltVirtualList` above a few hundred rows**; below that a plain `Stack`/`Table` is cheaper.
|
|
147
|
-
It sets `useFlushSync: false` for React 19 itself — do not override it.
|
|
61
|
+
`defineCommands`/`runCommand`, `defineOverlays`/`overlays.open` — call each factory once, at app
|
|
62
|
+
boot. Project via `toSpotlightActions`/`toShortcutList`/`toHotkeyBindings`, never a hand-authored
|
|
63
|
+
second list. `overlays.confirm`/`confirmDelete` need no registry entry.
|
|
64
|
+
|
|
65
|
+
## `./data/table` + `./data/virtual` — TanStack Table + Virtual (C1: no bare `./data`)
|
|
66
|
+
|
|
67
|
+
Read the props before hand-rolling anything (facets, pagination, `meta.align`/`meta.numeral`).
|
|
68
|
+
`manualPagination` imposes a contract on sorting/filtering/count — unresolved, it throws in dev.
|
|
69
|
+
`BasaltVirtualList` above a few hundred rows only.
|
|
148
70
|
|
|
149
71
|
## `./content` — prose, markdown, MDX
|
|
150
72
|
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
- **`streaming` is a RENDERING mode, not a trust claim.** `contentTrust` is the independent security
|
|
155
|
-
input and the sole input to the image-origin allowlist: **any surface rendering agent or model
|
|
156
|
-
output must pin `contentTrust="untrusted"`** — an auto-fetched image is the classic
|
|
157
|
-
prompt-injection exfiltration channel. Link/script hardening is always on, streaming or not, and
|
|
158
|
-
`sanitizeSchema` only ADDS to the default schema.
|
|
159
|
-
- **Every optional peer degrades, except one.** No `shiki` (or an unknown language) renders a plain
|
|
160
|
-
mono block; no `beautiful-mermaid` leaves the fence as code; `remend`'s streaming repair and the
|
|
161
|
-
markdown renderer resolve lazily. Six mermaid diagram types are covered — anything else is a
|
|
162
|
-
consumer escape hatch outside `Markdown`.
|
|
163
|
-
- **`ArticleLayout` is the docs frame** (meta header, sticky scroll-spy TOC, prev/next); every
|
|
164
|
-
linking content component takes `renderLink` as the router bridge and defaults to a plain anchor.
|
|
165
|
-
- **The Article model is data + pure operators**, generic over the taxonomy — the app declares which
|
|
166
|
-
categories and tags exist (`satisfies readonly Article<Cat, Tag>[]`, deliberately no factory).
|
|
167
|
-
Filter state is store fields, and the filter UI is `FilterSet`/`ViewTabs`/`MultiSelectFilter`,
|
|
168
|
-
re-exported here so a content-only consumer has one import path (basalt-controls.md).
|
|
169
|
-
- Build-time content tooling (`content-collections`) is a RECIPE, not a dependency; its vite plugin
|
|
170
|
-
must run FIRST because other transforms resolve its virtual module.
|
|
73
|
+
`Prose`/`Markdown`/`mdxComponents` share one typography layer. `streaming` is a rendering mode, not
|
|
74
|
+
a trust claim — any surface rendering agent/model output pins `contentTrust="untrusted"`. Every
|
|
75
|
+
optional peer degrades gracefully except the sanitizer, which is always on.
|
|
171
76
|
|
|
172
77
|
## `./agent` + `./agent-chat` — streaming chat
|
|
173
78
|
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
fallback; production derives `{ title, summary, status }` from the finished run. The outcome shape
|
|
186
|
-
is deliberately DIFFERENT from the transcript so raw prompts and thinking cannot leak into a feed.
|
|
187
|
-
- **Stream resumption is a client contract, not a backend**: a `StartPart` carries the token, the
|
|
188
|
-
transport implements `resume`, and a mount-time reconnect is attempted before an orphaned thread
|
|
189
|
-
falls back to interrupted. A transport that does neither behaves exactly as before.
|
|
190
|
-
- **Three lint guards protect this discipline** — an unguarded `resume`, a raw `useChat`, and an `ai`
|
|
191
|
-
major mismatch — and they honour `basalt-agent-allow`, never `theme-allow`. `doctor`'s
|
|
192
|
-
`ai-major-parity` is the cross-package counterpart, because a lint run only ever sees one
|
|
193
|
-
package's manifest.
|
|
79
|
+
`./agent` is headless/Mantine-free; `./agent-chat` is the chrome. Every `AgentPart` switch ends
|
|
80
|
+
`default: return assertNever(part)`. `useAgentStream` runs one turn, `useAgentThreadRuns` runs N by
|
|
81
|
+
thread id. Stream resumption reconnects a MOUNT (page reload mid-stream), it never continues a
|
|
82
|
+
click — `retry()`/`regenerate()` always start a fresh stream from the cached input.
|
|
83
|
+
|
|
84
|
+
**Why the three lint guards exist** (a consumer's build fails on one of these; all honour
|
|
85
|
+
`basalt-agent-allow`, never `theme-allow`): `basalt/agent-resume-guard` — an unguarded
|
|
86
|
+
`resumeStream()`/`useChat({ resume: true })` re-fires under StrictMode with no dedup, use
|
|
87
|
+
`useAgentThreadRuns` instead. `basalt/agent-no-raw-usechat` — bypassing the basalt hooks loses the
|
|
88
|
+
unmount-abort and supersede guards. `basalt/ai-sdk-major` (+ `doctor`'s `ai-major-parity`) — a v5
|
|
89
|
+
stream parsed by a v7 reader throws; nothing else pins the `ai` major across packages.
|
|
194
90
|
|
|
195
91
|
## App bootstrapping — `./vite`, CSS order, `init`
|
|
196
92
|
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
`basalt-ui/styles.css`. An unlayered Mantine import outranks `@layer basalt` regardless of
|
|
203
|
-
specificity.
|
|
204
|
-
- **Head, manifest and theme colors come from the token palette** — never hand-compute a
|
|
205
|
-
`theme-color` hex or an anti-FOUC background, and set `colorScheme` to whatever the app passes as
|
|
206
|
-
`defaultColorScheme` or you ship a flash of the wrong surface. Icons are bring-your-own: either
|
|
207
|
-
the six default filenames under `public/`, or an `icons` array naming what you actually have (an
|
|
208
|
-
entry reaches the head only when it names a `rel`; every entry becomes a manifest icon). The
|
|
209
|
-
service worker is opt-in and degrades to a warning without its peer.
|
|
210
|
-
- **`init` on an existing app is a lint-debt event, not a no-op** — the shipped preset turns on
|
|
211
|
-
whole oxlint plugins the repo was never linted against, so previously-clean code lands with real
|
|
212
|
-
findings. Triage them; do not blanket-disable a plugin. It also patches `basalt.roots` (everything
|
|
213
|
-
derives from it) and a `lint:basalt` script, and it KEEPS an existing `.oxlintrc.json`, which
|
|
214
|
-
leaves the whole basalt lint half off until you extend the preset.
|
|
215
|
-
- **The lefthook preset overrides YOU on a colliding key** — a `run:`/`glob:` under one of its
|
|
216
|
-
command names is discarded silently, while `env:`, `exclude:`, `skip:` and your own command names
|
|
217
|
-
merge; `BASALT_BIN` is the sanctioned seam. A broken `extends` target is a hard fail: lefthook
|
|
218
|
-
merges a missing target into ZERO commands and still exits 0.
|
|
219
|
-
- **Then run `doctor` and read it to the last line.** `SKIPPED` is a third outcome that exits
|
|
220
|
-
non-zero on its own — a check that could not run is not a check that passed.
|
|
93
|
+
`basaltViteConfig` is config-only; spread `basaltAppPlugin` into your own `plugins`. CSS layer
|
|
94
|
+
order is load-bearing: every `@mantine/*/styles.layer.css` first, then `basalt-ui/styles.css` — an
|
|
95
|
+
unlayered Mantine import outranks `@layer basalt` regardless of specificity. `init` on an existing
|
|
96
|
+
app is a lint-debt event, not a no-op — triage the new findings, don't blanket-disable a plugin.
|
|
97
|
+
Run `doctor` after and read it to the last line (`SKIPPED` exits non-zero on its own).
|
|
@@ -6,8 +6,8 @@ paths:
|
|
|
6
6
|
---
|
|
7
7
|
|
|
8
8
|
<!-- basalt:coverage -->
|
|
9
|
-
<!-- GENERATED from src/surfaces.ts — `
|
|
10
|
-
<!-- backed by: guard kinds — chart-missing-aria-label, raw-color-fn, raw-hex, raw-visx-axis
|
|
9
|
+
<!-- GENERATED from src/surfaces.ts — `bun scripts/check-coverage.ts --write`. Do not hand-edit. -->
|
|
10
|
+
<!-- backed by: guard kinds — chart-missing-aria-label, raw-color-fn, raw-hex, raw-visx-axis · oxlint rules — basalt/chart-in-raw-surface, basalt/chart-legend-literal, basalt/hand-rolled-plot, basalt/visx-boundary, basalt/visx-tooltip -->
|
|
11
11
|
<!-- not guarded: — -->
|
|
12
12
|
<!-- /basalt:coverage -->
|
|
13
13
|
|
|
@@ -26,21 +26,18 @@ the hover/keyboard overlay and the derived tooltip. The caller supplies `series`
|
|
|
26
26
|
render prop that draws **only marks**.
|
|
27
27
|
|
|
28
28
|
Reaching past it for an axis, a tooltip or a margin means the chart has drifted. `basalt/hand-rolled-plot`
|
|
29
|
-
enforces this per NODE
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
`
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
**A documented limit:** the rule keys on those visx primitives, so a chart drawn with DOM nodes or a
|
|
42
|
-
hand-assembled `<svg>` is structurally invisible to it. Compose the primitive because it is the
|
|
43
|
-
contract, not because lint will catch you.
|
|
29
|
+
enforces this per NODE, waived one node at a time with `theme-allow hand-rolled-plot — <why>`.
|
|
30
|
+
|
|
31
|
+
**Five shipped shapes are the declared exceptions**, by shape, not preference: `DualPanel` (two
|
|
32
|
+
panes), `MirroredBars` (two bar panes, one baseline), `BandStrip` (no y dimension), `Donut`
|
|
33
|
+
(radial), `Heatmap` (matrix). They compose `ChartFrame` + `useChartCursor` + `autoMargin` +
|
|
34
|
+
`ChartTooltipFloat` directly. The first three carry `theme-allow-file hand-rolled-plot — <why>`;
|
|
35
|
+
`Donut`/`Heatmap` render no assembly primitive, so nothing fires. A bespoke non-single-plot shape
|
|
36
|
+
declares itself the same way. `CartesianChart`'s own defining module is exempt definitionally.
|
|
37
|
+
|
|
38
|
+
**A documented limit:** the rule keys on visx primitives, so a DOM- or hand-`<svg>`-drawn chart is
|
|
39
|
+
structurally invisible to it. Compose the primitive because it's the contract, not because lint
|
|
40
|
+
catches you.
|
|
44
41
|
|
|
45
42
|
## `series` is the single source of truth
|
|
46
43
|
|
|
@@ -57,74 +54,58 @@ minus whatever the legend has toggled off, and the legend toggles by default at
|
|
|
57
54
|
|
|
58
55
|
## Boundaries (three independent rules, no escape hatch)
|
|
59
56
|
|
|
60
|
-
- **`@visx/*` only inside a `charts/` path segment** (`basalt/visx-boundary`, shipped AND
|
|
61
|
-
|
|
62
|
-
keep your bespoke chart file under a `charts/` directory.
|
|
57
|
+
- **`@visx/*` only inside a `charts/` path segment** (`basalt/visx-boundary`, shipped AND
|
|
58
|
+
repo-local) — import a raw visx primitive from `basalt-ui/charts`'s curated re-export instead.
|
|
63
59
|
- **`@visx/tooltip` is banned everywhere**, charts included (`basalt/visx-tooltip`) — use
|
|
64
|
-
`ChartTooltipFloat` + `TooltipHeader`/`TooltipRow`/`TooltipBody`.
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
`
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
boundary says nothing about one — build it wherever the rest of the app's non-chart UI lives, and
|
|
76
|
-
style its chrome with `--vx-*` so it matches.
|
|
60
|
+
`ChartTooltipFloat` + `TooltipHeader`/`TooltipRow`/`TooltipBody`. A plain `<div>` inside an
|
|
61
|
+
`<svg>` mounts in the SVG namespace, typechecks, lints, and never paints.
|
|
62
|
+
- **basalt's own `charts/`+`tokens/` import zero `@mantine/*`** (`basalt/token-layer-boundary`,
|
|
63
|
+
repo-local — a framework invariant, not an obligation on your app's own `charts/`-named dir). It
|
|
64
|
+
keeps the token layer upstream of Mantine and lets both subpaths resolve with no Mantine
|
|
65
|
+
installed.
|
|
66
|
+
- Mantine layout primitives are unreachable in a chart file, so `inline-display`/`raw-html-layout`
|
|
67
|
+
deliberately don't fire there — raw `<div>` is fine, `VX.*` tokens still mandatory
|
|
68
|
+
(`ChartCenter` to center).
|
|
69
|
+
- **Maps are not charts** — no map library is `@visx/*`, basalt ships no map kind; build one where
|
|
70
|
+
the rest of the app's non-chart UI lives, styled with `--vx-*`.
|
|
77
71
|
|
|
78
72
|
## Color, scheme and margins
|
|
79
73
|
|
|
80
|
-
- **Never a raw hex in a chart file**,
|
|
81
|
-
**pure CSS**:
|
|
82
|
-
|
|
74
|
+
- **Never a raw hex in a chart file**, never `localStorage.getItem('theme')`. Theme reactivity is
|
|
75
|
+
**pure CSS**: `--vx-*` redeclares per scheme, so toggling restyles every chart with no React
|
|
76
|
+
re-render.
|
|
83
77
|
- **Series color is consumer domain data** — one guard-exempt file per app, `defineSeries` →
|
|
84
|
-
`seriesTokens`/`groupTokens` → `buildPaletteCss` (basalt-tokens.md)
|
|
85
|
-
|
|
86
|
-
- **Margins are MEASURED, not hand-picked
|
|
87
|
-
`autoMargin`/`measureText` before layout, so `VX.margin` is a floor
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
- **
|
|
91
|
-
|
|
92
|
-
-
|
|
93
|
-
`
|
|
94
|
-
|
|
95
|
-
the plot's footprint and draws nothing that could be mistaken for a measurement.
|
|
96
|
-
- **`ChartFrame`'s container is `role="group"`, never `role="img"`.** Every descendant of a
|
|
97
|
-
`role="img"` element is presentational, which erases the hover overlay's `role="slider"` from the
|
|
98
|
-
accessibility tree — silently, and jsdom does not implement the pruning, so no `getByRole` test can
|
|
99
|
-
catch the regression. Do not "simplify" it back.
|
|
78
|
+
`seriesTokens`/`groupTokens` → `buildPaletteCss` (basalt-tokens.md), each entry a `{light,dark}`
|
|
79
|
+
pair.
|
|
80
|
+
- **Margins are MEASURED, not hand-picked** — every axis's tick labels run through
|
|
81
|
+
`autoMargin`/`measureText` before layout, so `VX.margin` is a floor. Passing `y2` is what makes a
|
|
82
|
+
chart dual-axis; `margin={{ side: n }}` overrides last. Derive constants from `VX.margin` rather
|
|
83
|
+
than copying a number into three files.
|
|
84
|
+
- **Never fake an empty dataset for a pending query** — `data ?? []` collapses "not asked yet" into
|
|
85
|
+
"measured and absent". Pass `isPending`; every kind forwards it to one pending renderer.
|
|
86
|
+
- **`ChartFrame`'s container is `role="group"`, never `role="img"`** — every descendant of a
|
|
87
|
+
`role="img"` element is presentational, which would erase the hover overlay's `role="slider"`
|
|
88
|
+
from the accessibility tree silently (jsdom doesn't implement the pruning, so no test catches it).
|
|
100
89
|
|
|
101
90
|
## Adding a chart
|
|
102
91
|
|
|
103
|
-
1. **Fits a shipped kind?** Use it
|
|
104
|
-
|
|
105
|
-
2. **Second instance of a shape with no kind?** Extract a kind
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
already exists.
|
|
109
|
-
3. **Genuinely unique?** Stay bespoke, composing `CartesianChart` (or `ChartFrame`) directly in the
|
|
92
|
+
1. **Fits a shipped kind?** Use it — declarative props (`data`, `chartId`, `getX`, `series`, one
|
|
93
|
+
`AxisConfig` per axis, zones/thresholds/refLines as plain arrays).
|
|
94
|
+
2. **Second instance of a shape with no kind?** Extract a kind (Rule of Three), migrating both call
|
|
95
|
+
sites; prove it by porting real call sites, ship the "still cannot express" list with it.
|
|
96
|
+
3. **Genuinely unique?** Stay bespoke, composing `CartesianChart`/`ChartFrame` directly in the
|
|
110
97
|
page's chart file, not in a shared kinds directory.
|
|
111
98
|
|
|
112
|
-
Sparklines are the one exemption
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
**Anti-pattern:** a single `<Chart type="…" config={…} />` that switches by kind. Prefer N small
|
|
116
|
-
kinds, and if a chart doesn't fit the primitives, **add a kind — don't loosen the primitives.**
|
|
99
|
+
Sparklines are the one exemption (no legend, no tooltip, no `CartesianChart`) — still `VX.*` only.
|
|
100
|
+
**Anti-pattern:** a single `<Chart type="…" config={…} />` switching by kind — add a kind, don't
|
|
101
|
+
loosen the primitives.
|
|
117
102
|
|
|
118
103
|
## The x axis is categorical, and the API does not say so
|
|
119
104
|
|
|
120
|
-
`CartesianChart` builds x as a point scale over domain KEYS
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
The cursor is likewise **shared page-wide by default** with no provider, resolved domain-aware
|
|
128
|
-
(nearest parsed date/number within a chart's own step, not string equality) so a chart that folds its
|
|
129
|
-
domain still tracks a sibling's hover. `ChartCursorScope` ISOLATES a subtree — it opts out of
|
|
130
|
-
sharing, never into it.
|
|
105
|
+
`CartesianChart` builds x as a point scale over domain KEYS — N evenly spaced positions whatever
|
|
106
|
+
the values behind them. Wrong for an event-shaped series: a shared crosshair marks the wrong screen
|
|
107
|
+
x against a regularly-sampled sibling, and two events at the same instant collapse onto one
|
|
108
|
+
position. `getX` returning a date string reads like a time axis and is not one.
|
|
109
|
+
|
|
110
|
+
The cursor is **shared page-wide by default**, resolved domain-aware (nearest parsed date/number
|
|
111
|
+
within a chart's own step). `ChartCursorScope` ISOLATES a subtree — opts out of sharing, never in.
|