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
|
@@ -7,7 +7,7 @@ paths:
|
|
|
7
7
|
---
|
|
8
8
|
|
|
9
9
|
<!-- basalt:coverage -->
|
|
10
|
-
<!-- GENERATED from src/surfaces.ts — `
|
|
10
|
+
<!-- GENERATED from src/surfaces.ts — `bun scripts/check-coverage.ts --write`. Do not hand-edit. -->
|
|
11
11
|
<!-- backed by: guard kinds — raw-selection-control · oxlint rules — basalt/bound-control-outside-home, basalt/control-outside-home, basalt/control-size-literal, basalt/hand-rolled-filter, basalt/responsive-twin -->
|
|
12
12
|
<!-- not guarded: C1 as a cross-file law (a control placed in one file, its home declared in another) -->
|
|
13
13
|
<!-- not guarded: hand-rolled section headings (argo writes `<Text fw={600} size="sm">` + children, which no AST heuristic matches without false positives) -->
|
|
@@ -55,21 +55,16 @@ C1's cross-file case, a hand-rolled section heading, C11 outside `BasaltDataTabl
|
|
|
55
55
|
| `SettingsRow` | `control` | Mantine `md` | ONE form field, bound to a setting |
|
|
56
56
|
| `FormRow` / `FormGroup` (`basalt-ui/forms`) | children | Mantine `md` | ONE form field or a labelled cluster |
|
|
57
57
|
|
|
58
|
-
- **Inside `BasaltShell`** both `PageBar` rows are portals
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
-
|
|
68
|
-
more than one widget it is promoted to the page bar; if it formats one widget it stays in that
|
|
69
|
-
widget's header.
|
|
70
|
-
- **An overlay rendered by the PARENT is exempt by FILENAME**: `control-outside-home` and
|
|
71
|
-
`raw-selection-control` skip a file basenamed `*-{modal,drawer,popover,panel,form}.tsx`, since no
|
|
72
|
-
scan of it sees the `<Modal>`. Outside that: `theme-allow-file control-outside-home — overlay`.
|
|
58
|
+
- **Inside `BasaltShell`** both `PageBar` rows are portals (header / the band above the scrollport)
|
|
59
|
+
— where you write `<PageBar>` never moves it. Without a shell both rows render in flow, sticky.
|
|
60
|
+
The header height is a token, never state.
|
|
61
|
+
- **The form row keeps Mantine's own `md` tier** — a raw `Select` in `SettingsRow.control` is the
|
|
62
|
+
right answer, `size` there is load-bearing. Neither `SettingsRow` nor `FormRow`/`FormGroup` is a
|
|
63
|
+
tiered slot; no filter or size rule applies to them.
|
|
64
|
+
- **A control's home is a decision about reach**: affects more than one widget → promote to the
|
|
65
|
+
page bar; formats one widget → stays in that widget's header.
|
|
66
|
+
- **An overlay rendered by the PARENT is exempt by FILENAME** — `*-{modal,drawer,popover,panel,form}.tsx`.
|
|
67
|
+
Outside that: `theme-allow-file control-outside-home — overlay`.
|
|
73
68
|
|
|
74
69
|
## The `ctl` tier — the home sizes the control
|
|
75
70
|
|
|
@@ -81,13 +76,11 @@ C1's cross-file case, a hand-rolled section heading, C11 outside `BasaltDataTabl
|
|
|
81
76
|
| `touchControlHeight` | hit area below `sm` | every home |
|
|
82
77
|
| `controlHeight` | `size="md"` | forms — unchanged |
|
|
83
78
|
|
|
84
|
-
Each home wraps its **slot** — never its body — in a hoisted theme provider
|
|
85
|
-
Mantine control inside it to `size="ctl"
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
`ChartCard.actions` lives inside the Mantine-free chart layer, so it cannot mount the slot theme —
|
|
90
|
-
it carries only the tier attribute, and the basalt controls placed there size themselves.
|
|
79
|
+
Each home wraps its **slot** — never its body — in a hoisted theme provider defaulting every
|
|
80
|
+
Mantine control inside it to `size="ctl"`. A raw `Button` in `PageBar.actions` is already the right
|
|
81
|
+
height with no prop; a `size="xs"` typed there is law C5 (`basalt/control-size-literal`). Mantine's
|
|
82
|
+
own `sm`/`xs` are NOT re-pointed elsewhere. Exception: `ChartCard.actions` is Mantine-free, so it
|
|
83
|
+
carries only the tier attribute and its controls size themselves.
|
|
91
84
|
|
|
92
85
|
## Binding a control to a store
|
|
93
86
|
|
|
@@ -106,24 +99,21 @@ import { DateRangePicker } from 'basalt-ui/controls-dates'
|
|
|
106
99
|
```
|
|
107
100
|
|
|
108
101
|
The store, its fields and their lanes are basalt-state.md. What this file adds: **the control takes
|
|
109
|
-
`field` and nothing else about state
|
|
110
|
-
|
|
111
|
-
`OverflowMenu` and `SyncButton` sit on the same subpath and take typed action DATA, never children.
|
|
102
|
+
`field` and nothing else about state** — no `value`, no `onChange`, no `size`, so a wrong call site
|
|
103
|
+
is a tsc error. `ActionGroup`/`OverflowMenu`/`SyncButton` take typed action DATA, never children.
|
|
112
104
|
|
|
113
|
-
**The date picker is injected, never imported.** `basalt-ui/controls` resolves
|
|
114
|
-
`@mantine/dates` installed
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
inside a home slot.
|
|
105
|
+
**The date picker is injected, never imported.** `basalt-ui/controls` resolves with no
|
|
106
|
+
`@mantine/dates` installed; `DateRangePicker` comes from `basalt-ui/controls-dates` through
|
|
107
|
+
`RangeFilter.customPicker`. Never import `@mantine/dates` from a shared module or reach for
|
|
108
|
+
`DateInput`/`DatePickerInput` inside a home slot.
|
|
118
109
|
|
|
119
110
|
## `FilterSet` owns the responsive story
|
|
120
111
|
|
|
121
112
|
Do not build one at the call site. Above `sm`, `FilterSet` measures its own children and folds the
|
|
122
|
-
tail into a `+N` pill
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
reset handler to extend.
|
|
113
|
+
tail into a `+N` pill. Below `sm`, the first `inline` children stay pills and one `Filters (n)`
|
|
114
|
+
pill opens a sheet where every child renders full-width and answers one `Reset all`. **`n` and
|
|
115
|
+
`Reset all` are DERIVED** from whether each field differs from its fallback — adding a filter is
|
|
116
|
+
one JSX line, no count or reset handler to maintain.
|
|
127
117
|
|
|
128
118
|
| Below `sm` | What basalt does |
|
|
129
119
|
| ---------------- | ---------------------------------------------------------------------------------------------------------------------------------- |
|
|
@@ -132,16 +122,14 @@ reset handler to extend.
|
|
|
132
122
|
| a section header | title · count · one inline action, the rest in a kebab; tabs past three become a `Select` |
|
|
133
123
|
| a widget header | value + delta wrap under the title; the sparkline drops to bleed; one `⋯` action |
|
|
134
124
|
|
|
135
|
-
Every swap is CSS inside the control (one mount), never a JS media query
|
|
136
|
-
differently on the server than on the first client paint. Two mounts under
|
|
125
|
+
Every swap is CSS inside the control (one mount), never a JS media query. Two mounts under
|
|
137
126
|
`visibleFrom`/`hiddenFrom` is `basalt/responsive-twin`.
|
|
138
127
|
|
|
139
128
|
## The aside
|
|
140
129
|
|
|
141
130
|
`PageAside` is a shell REGION, not a fourth home — C1 still names three. Its body IS a home: it
|
|
142
|
-
scopes
|
|
143
|
-
|
|
144
|
-
is read from where the control is mounted.
|
|
131
|
+
scopes children to the `panel` surface, so the same `SelectFilter` that is a pill in the page bar
|
|
132
|
+
is a ROW in the aside — never two components, the surface is read from where it's mounted.
|
|
145
133
|
|
|
146
134
|
| In the aside | Write |
|
|
147
135
|
| ---------------- | --------------------------------------------------------------------------------- |
|
|
@@ -151,35 +139,16 @@ is read from where the control is mounted.
|
|
|
151
139
|
| a group of rows | `Section` — flush inside the aside, which draws the rhythm itself |
|
|
152
140
|
| a choice | `PanelChoice` — a track only while ≤3 options AND every label fits, else `Select` |
|
|
153
141
|
|
|
154
|
-
- ONE `PageAside` per page, written AFTER the main content
|
|
155
|
-
|
|
156
|
-
- Below `sm` it projects into `PageBar` row 2 as one `Panel` pill
|
|
157
|
-
|
|
158
|
-
- A bound control
|
|
159
|
-
`
|
|
160
|
-
`PageAside` or a `PanelRow` is a home; nothing else is.
|
|
142
|
+
- ONE `PageAside` per page, written AFTER the main content — it portals into the region from `sm`
|
|
143
|
+
up, its tree position is reading order, not layout.
|
|
144
|
+
- Below `sm` it projects into `PageBar` row 2 as one `Panel` pill; with no row 2 — or shell-less —
|
|
145
|
+
it renders in flow. One node either way (C9).
|
|
146
|
+
- A bound control outside all of this is `basalt/bound-control-outside-home` — a slot prop, a
|
|
147
|
+
`FilterSet`, a `PageAside` or a `PanelRow` is a home; nothing else is.
|
|
161
148
|
|
|
162
149
|
## Sidebar blocks
|
|
163
150
|
|
|
164
151
|
A non-destination list, a progress meter or a bespoke node in the sidebar is a `SidebarBlock` —
|
|
165
|
-
declared data, three kinds (`list
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
its items. A `custom` block is desktop-only, by design.
|
|
169
|
-
|
|
170
|
-
## Anti-patterns
|
|
171
|
-
|
|
172
|
-
| Instead of | Write |
|
|
173
|
-
| ------------------------------------------------------------ | ----------------------------------------------------- |
|
|
174
|
-
| `useState` + a `SegmentedControl` in the page body | a store field + `ViewTabs` in the home's `tabs` slot |
|
|
175
|
-
| a raw `Select`/`MultiSelect`/`Chip.Group` as a filter | `SelectFilter` / `MultiSelectFilter` |
|
|
176
|
-
| a numeric threshold widened into a string enum | `field.number` + `NumberFilter` |
|
|
177
|
-
| `<X visibleFrom="sm"/>` beside `<X hiddenFrom="sm"/>` | one control — the swap is already inside it |
|
|
178
|
-
| `size="xs"` on a button in a home slot | nothing; the home sets the tier |
|
|
179
|
-
| a hand-written `presetToParams` | `field.toWindow(value)` |
|
|
180
|
-
| a hand-counted `Filters (3)` badge | nothing; `FilterSet` derives it |
|
|
181
|
-
| `overflowX: 'auto'` on a filter row | nothing; the fold is basalt's |
|
|
182
|
-
| a local `Section` / `PageHeader` / `RefreshButton` | `Section` / `PageBar` / `SyncButton` |
|
|
183
|
-
| an in-body `<Title order={1}>` | the route's breadcrumb title |
|
|
184
|
-
| the same on a shell-less surface (auth gate, error boundary) | `theme-allow in-body-page-title — shell-less surface` |
|
|
185
|
-
| a hand-built joined button row | `ControlGroup` (or `group: true` on the actions) |
|
|
152
|
+
declared data, three kinds (`list`/`progress`/`custom`), placed `'nav'`/`'bottom'`. Because it's
|
|
153
|
+
data, basalt owns what a `ReactNode` slot couldn't: a rail dot/ring when collapsed, a persisted
|
|
154
|
+
fold, one More-sheet row per block. A `custom` block is desktop-only, by design.
|
|
@@ -7,8 +7,8 @@ paths:
|
|
|
7
7
|
---
|
|
8
8
|
|
|
9
9
|
<!-- basalt:coverage -->
|
|
10
|
-
<!-- GENERATED from src/surfaces.ts — `
|
|
11
|
-
<!-- backed by: guard kinds — card-with-border, hidden-inline-style, in-body-page-title, inline-display, inline-spacing, mantine-shade-index, raw-form-control, raw-html-layout, raw-motion-value, raw-spacing, sub-16-input-font · oxlint rules — basalt/card-inset, basalt/deprecated-export, basalt/
|
|
10
|
+
<!-- GENERATED from src/surfaces.ts — `bun scripts/check-coverage.ts --write`. Do not hand-edit. -->
|
|
11
|
+
<!-- backed by: guard kinds — card-with-border, hidden-inline-style, in-body-page-title, inline-display, inline-spacing, mantine-shade-index, raw-form-control, raw-html-layout, raw-motion-value, raw-spacing, sub-16-input-font · oxlint rules — basalt/card-inset, basalt/deprecated-export, basalt/hand-rolled-shell, basalt/in-body-page-title, basalt/no-import-meta-env, basalt/page-bar-budget, basalt/provider-above-router, basalt/raw-scroll-container, basalt/shadow-basalt-export -->
|
|
12
12
|
<!-- not guarded: no second cssVariablesResolver — don't hand-build createTheme or re-add the resolver basalt already installs -->
|
|
13
13
|
<!-- /basalt:coverage -->
|
|
14
14
|
|
|
@@ -30,15 +30,13 @@ the composition in its own client file.
|
|
|
30
30
|
|
|
31
31
|
**Overlays mount exactly once, through `BasaltOverlays`** (`basalt-ui/commands`), inside
|
|
32
32
|
`BasaltProvider`: it composes `ModalsProvider`, Spotlight (against basalt's own store), the command
|
|
33
|
-
hotkeys and `<Notifications>` in one place, each disableable with `false`. `ModalsProvider` mounts
|
|
34
|
-
a **sibling** of `children`, not a wrapper — the imperative `modals.*`/`overlays.*` API works
|
|
35
|
-
untouched
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
style bundles for every `@mantine/*` battery, then `basalt-ui/styles.css` last; an unlayered Mantine
|
|
41
|
-
import outranks `@layer basalt` regardless of specificity.
|
|
33
|
+
hotkeys and `<Notifications>` in one place, each disableable with `false`. `ModalsProvider` mounts
|
|
34
|
+
as a **sibling** of `children`, not a wrapper — the imperative `modals.*`/`overlays.*` API works
|
|
35
|
+
untouched, but `useModals()`/`openContextModal` need real React context, which a sibling cannot
|
|
36
|
+
provide: pass `modals={false}` and mount your own `ModalsProvider` when you need either.
|
|
37
|
+
`<BasaltOverlays notifications />` is the ONE notifications mount; there is no standalone
|
|
38
|
+
component any more. Import the **layered** style bundle for every `@mantine/*` battery, then
|
|
39
|
+
`basalt-ui/styles.css` last.
|
|
42
40
|
|
|
43
41
|
Color scheme is read and written through `useMantineColorScheme()` only — never a client store,
|
|
44
42
|
never `localStorage.getItem('theme')` (guard-enforced; see basalt-state.md).
|
|
@@ -64,104 +62,61 @@ projection:
|
|
|
64
62
|
| `account` | `BasaltAccountProps` | the footer row, below the settings menu |
|
|
65
63
|
|
|
66
64
|
- **The router seam is ONE component, not a render callback.** `SidebarItem.Anchor` (a `NavAnchor`)
|
|
67
|
-
is the consumer's `<Link>`;
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
`
|
|
73
|
-
- **
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
**Mobile is a tab bar, not a menu.** A slot is a destination, so a tap navigates with nothing to
|
|
85
|
-
dismiss; there is no full-height mobile drawer, and everything it used to hold reaches the trailing
|
|
86
|
-
More slot. `projectMobileNav` is a PURE projection and infers the surface from row count — 0 drops
|
|
87
|
-
the slot, 1 collapses to a plain link (a group of one IS a destination), up to `menuMax` is a menu,
|
|
88
|
-
more is a bottom sheet. `SidebarItem.mobile` (`'tab'` / `'more'` / `'hidden'`) is the per-destination
|
|
89
|
-
placement; `MobileNavConfig` is the escape hatch, not the interface. Two bar rules that look like
|
|
90
|
-
bugs and are not: the active indicator is a **neutral** ink tint behind the ICON only (never the
|
|
91
|
-
identity blue, never a full-tab fill — the desktop sidebar's accent-icon rule does not apply here),
|
|
92
|
-
and the bar carries **no** `env(safe-area-inset-bottom)` padding, because Mantine's own
|
|
93
|
-
`AppShell.Footer` rule already grows the box by the inset. Search lives in the SIDEBAR, not the
|
|
94
|
-
header. Region edges come from `BasaltShell` itself — Mantine's `[data-with-border]`, coloured by
|
|
95
|
-
`--app-shell-border-color` → `--vx-divider` through the theme — never draw a border on a shell
|
|
96
|
-
region, a page-bar row or an aside panel, never pass `withBorder` to an `AppShell` section, and
|
|
97
|
-
never set `--app-shell-border-color` yourself. `--vx-divider` is the only layout-line token; the
|
|
98
|
-
sidebar's own internals still carry zero horizontal rules.
|
|
65
|
+
is the consumer's `<Link>`; absent, the row falls back to `<a href>` + `onClick`. The
|
|
66
|
+
breadcrumb's equivalent is `parentAnchor`. No `renderNavLink`/`renderBreadcrumbLink` surface.
|
|
67
|
+
- **`AppBreadcrumbs` is prop-driven** (`section`/`parent`/`parentAnchor`/`parentHref`/`page`),
|
|
68
|
+
renders `null` without `page`; `useRouterBreadcrumbs` (basalt-state.md) sources a custom trail.
|
|
69
|
+
- **Collapse persists through `createPersistedState`**, keyed `basalt:<storageKey>` — read with
|
|
70
|
+
`readPersistedValue`, never a bare `localStorage.getItem`.
|
|
71
|
+
- **The account row is presentational, provider-agnostic** — no `./auth`. Authenticated leads with
|
|
72
|
+
initials from `identity.name` (never an avatar image); unauthenticated falls back to a glyph.
|
|
73
|
+
|
|
74
|
+
**Mobile is a tab bar, not a menu.** A slot is a destination — a tap navigates with nothing to
|
|
75
|
+
dismiss, no full-height drawer. `projectMobileNav` is a PURE projection inferring the surface from
|
|
76
|
+
row count (0 drops the slot, 1 is a plain link, up to `menuMax` is a menu, more is a sheet).
|
|
77
|
+
`SidebarItem.mobile` (`'tab'`/`'more'`/`'hidden'`) is the per-destination placement. The active
|
|
78
|
+
indicator is a **neutral** ink tint behind the icon only (never the identity blue); the bar carries
|
|
79
|
+
**no** `env(safe-area-inset-bottom)` (Mantine's `AppShell.Footer` already grows the box). Region
|
|
80
|
+
edges come from `BasaltShell` itself (`--app-shell-border-color` → `--vx-divider`) — never draw a
|
|
81
|
+
border or pass `withBorder` to a shell region yourself.
|
|
99
82
|
|
|
100
83
|
## Surfaces, depth and shape
|
|
101
84
|
|
|
102
|
-
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
- **The ring must land on the box that carries the surface's `border-radius`** — it is drawn by that
|
|
119
|
-
box's own corners. `ChartCard` legitimately puts the shadow on a box with no background (an inner
|
|
120
|
-
box paints the fill, because `overflow: hidden` on the shadowed box would clip the shadow).
|
|
121
|
-
- **Use Mantine primitives, not raw HTML** — `Box`/`Flex`/`Grid`/`SimpleGrid`/`Stack`/`Group`/
|
|
122
|
-
`Paper`/`Card` instead of a `<div>` with an inline `style`. **The second sanctioned fix is a CSS
|
|
123
|
-
module**, and in row code it is the right one: what the guard objects to is the inline literal, not
|
|
124
|
-
the `<div>`, and a class reading `var(--vx-*)` costs no component instance per row. `check-theme`
|
|
125
|
-
scans `.css`, so the tokens stay policed there. Only the Mantine-free `src/charts/**` may use raw
|
|
126
|
-
`<div>` freely — still with `VX.*`.
|
|
127
|
-
- **Inputs come from `@mantine/core`**, never a native `<select>`; the theme defaults them to the
|
|
128
|
-
form tier, whose font size clears the iOS zoom threshold, and the floor in `styles.css` is
|
|
129
|
-
`!important` (`sub-16-input-font` flags a smaller one as dead code against it).
|
|
130
|
-
- **Charts measure themselves** — pass `height` / `aspectRatio` / `fill` and nothing else. Never
|
|
131
|
-
`useElementSize` inside a chart file (Mantine is banned there), never raw `@visx/responsive`
|
|
132
|
-
outside `charts/**`.
|
|
85
|
+
Depth-tier law (which token for which surface, why static, why the ring is inset) is
|
|
86
|
+
`docs/DESIGN-CORE.md` § Layout, elevation, shapes — not restated here. Mantine-specific facts only:
|
|
87
|
+
|
|
88
|
+
- **Never pass `withBorder` to a `Card`/`Paper`** — the theme pins bg/shadow/radius but does not
|
|
89
|
+
clear `border`, so `withBorder` draws a second real edge (`card-with-border` guard kind).
|
|
90
|
+
`<Card.Section withBorder>` is a section divider and fine.
|
|
91
|
+
- **The ring lands on the box carrying the surface's `border-radius`** — `ChartCard` puts the
|
|
92
|
+
shadow on a box with no background (an inner box paints the fill; `overflow: hidden` on the
|
|
93
|
+
shadowed box would clip the shadow otherwise).
|
|
94
|
+
- **Use Mantine primitives, not raw HTML** — `Box`/`Flex`/`Grid`/`Stack`/`Group`/`Paper`/`Card`
|
|
95
|
+
over a `<div>` with an inline style; a CSS module reading `var(--vx-*)` is the sanctioned second
|
|
96
|
+
fix in row code. Only Mantine-free `src/charts/**` uses raw `<div>` freely.
|
|
97
|
+
- **Inputs come from `@mantine/core`**, never a native `<select>` — the form tier's font size
|
|
98
|
+
clears the iOS zoom threshold via an `!important` floor (`sub-16-input-font` flags a smaller one).
|
|
99
|
+
- **Charts measure themselves** — pass `height`/`aspectRatio`/`fill` only; never `useElementSize`
|
|
100
|
+
in a chart file (Mantine is banned there), never raw `@visx/responsive` outside `charts/**`.
|
|
133
101
|
|
|
134
102
|
## Scroll regions
|
|
135
103
|
|
|
136
|
-
**A scroll region inside app chrome is a Mantine `ScrollArea`, not a raw `overflow: auto` box** —
|
|
137
|
-
draws its own bar inside
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
Raw `overflow: auto` stays correct where a library owns the scroll node (`BasaltStickToBottom`,
|
|
143
|
-
`BasaltVirtualList`) and for a table body, which is `Table.ScrollContainer type="native"` — a
|
|
144
|
-
`ScrollArea` viewport is the positioning context a sticky `<thead>` resolves against, so the default
|
|
145
|
-
type pins the header to the page viewport instead of the table's box.
|
|
104
|
+
**A scroll region inside app chrome is a Mantine `ScrollArea`, not a raw `overflow: auto` box** —
|
|
105
|
+
it draws its own bar inside its root, so the bar floats instead of reflowing the column
|
|
106
|
+
(`AppSidebar`'s nav is the reference: `type="hover"`, `scrollbars="y"`). Raw `overflow: auto` stays
|
|
107
|
+
correct only where a library owns the node (`BasaltStickToBottom`, `BasaltVirtualList`) and for a
|
|
108
|
+
table body (`Table.ScrollContainer type="native"` — a `ScrollArea` viewport would break a sticky
|
|
109
|
+
`<thead>`'s positioning context).
|
|
146
110
|
|
|
147
111
|
## Interaction feedback and motion
|
|
148
112
|
|
|
149
|
-
Every action button
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
`transform`, `opacity`, `color`, `background`.
|
|
160
|
-
- **Import from `motion/react`, never `framer-motion`** (`no-restricted-imports`, repo and shipped).
|
|
161
|
-
`motion` is an exact-pinned optional PEER, not a bundled dependency. Reach for Mantine's own
|
|
162
|
-
`<Transition>` for a simple mount fade; reach for `motion` when the interaction needs a crossfade
|
|
163
|
-
between two elements, spring physics or a gesture.
|
|
164
|
-
- **Always branch on `useReducedMotion`** (`@mantine/hooks`) with a real unanimated code path — no
|
|
165
|
-
`motion.*` wrapper at all, not just `duration: 0`. `ThemeToggle` is the pattern.
|
|
166
|
-
- **Restraint applies to motion too.** A state change earns a transition; idle chrome does not.
|
|
167
|
-
Never a looping or pulsing idle animation.
|
|
113
|
+
Every action button confirms itself: the `loading` prop in flight, a brief label flip
|
|
114
|
+
(`Save → Saved`) via Mantine's `<Transition>`, and a toast ONLY for an outcome the user might miss.
|
|
115
|
+
Destructive actions confirm through `modals.openConfirmModal` first.
|
|
116
|
+
|
|
117
|
+
- **Timing is a token, never a literal** — `MOTION_DURATION`/`MOTION_SPRING`/`MOTION_EASE_STANDARD`
|
|
118
|
+
(`raw-motion-value` enforces it). Animate `transform`/`opacity`/`color`, never a layout property.
|
|
119
|
+
- **Import from `motion/react`, never `framer-motion`** — exact-pinned optional PEER. Mantine's
|
|
120
|
+
`<Transition>` for a mount fade; `motion` for a crossfade, spring or gesture.
|
|
121
|
+
- **Always branch on `useReducedMotion`** with a real unanimated path, not just `duration: 0`
|
|
122
|
+
(`ThemeToggle` is the pattern). Restraint applies to motion too — no looping idle animation.
|
|
@@ -7,7 +7,7 @@ paths:
|
|
|
7
7
|
---
|
|
8
8
|
|
|
9
9
|
<!-- basalt:coverage -->
|
|
10
|
-
<!-- GENERATED from src/surfaces.ts — `
|
|
10
|
+
<!-- GENERATED from src/surfaces.ts — `bun scripts/check-coverage.ts --write`. Do not hand-edit. -->
|
|
11
11
|
<!-- backed by: guard kinds — localstorage-theme · oxlint rules — basalt/search-literal-link, basalt/use-search-from-literal -->
|
|
12
12
|
<!-- not guarded: — -->
|
|
13
13
|
<!-- /basalt:coverage -->
|
|
@@ -49,45 +49,35 @@ export const analytics = createSearchStore({
|
|
|
49
49
|
```
|
|
50
50
|
|
|
51
51
|
- **The URL is the truth; the localStorage mirror is a fallback UNDER it.** Every field resolves
|
|
52
|
-
URL ⊳ localStorage ⊳ fallback, identically for every field kind (law C4)
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
-
|
|
60
|
-
|
|
61
|
-
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
the store into it (`{ ...store.validateSearch(raw), ...rest }`) — there is no schema-backed store
|
|
65
|
-
variant, and none is coming.
|
|
66
|
-
- **A write from outside the owning route persists only**, and `validateSearch` picks it up on the
|
|
67
|
-
next visit. Two different stores using one param name on overlapping routes read as one owner;
|
|
68
|
-
presence in the search is all a store can see without the router naming the declarer.
|
|
69
|
-
- **`field.range` keeps its three URL params** (preset + from/to, renamable) so existing loaders and
|
|
70
|
-
deep links keep their shape; `handle.toWindow(value)` is the projection into query params — never a
|
|
71
|
-
hand-written `presetToParams`.
|
|
52
|
+
URL ⊳ localStorage ⊳ fallback, identically for every field kind (law C4) — a deep link wins over
|
|
53
|
+
the mirror.
|
|
54
|
+
- **Lanes are declared once, at definition**: `{ url, persist, history }`. `url: false` is
|
|
55
|
+
local-only (a per-card select); `persist: false` is URL-only (pagination, a tab that shouldn't
|
|
56
|
+
follow you elsewhere). `createLocalStore` is the same field vocabulary with no router.
|
|
57
|
+
- **Option LABELS come from `.labels()`, once, at definition** — never a per-control prop.
|
|
58
|
+
- **`validateSearch: store.validateSearch`** on the route, function form — it returns every
|
|
59
|
+
URL-lane param unconditionally. A route with a wider search shape COMPOSES the store instead
|
|
60
|
+
(`{ ...store.validateSearch(raw), ...rest }`) — there is no schema-backed store variant.
|
|
61
|
+
- **A write from outside the owning route persists only**; `validateSearch` picks it up next visit.
|
|
62
|
+
- **`field.range` keeps its three URL params** (preset + from/to); `handle.toWindow(value)` is the
|
|
63
|
+
projection into query params — never a hand-written `presetToParams`.
|
|
72
64
|
|
|
73
65
|
## Reading and writing
|
|
74
66
|
|
|
75
67
|
- **A page reads `store.useValues()`, or takes the value as a PROP.** Never
|
|
76
|
-
`useSearch({ from: '<literal>' })` — a sibling
|
|
77
|
-
`
|
|
78
|
-
|
|
79
|
-
- **A `FieldHandle` is the whole read/write surface
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
- **`set(next, { patch })`** merges sibling params the store does NOT own into the same navigate. A
|
|
90
|
-
key another field of the same store owns throws in dev — write it through that field's setter.
|
|
68
|
+
`useSearch({ from: '<literal>' })` (`basalt/use-search-from-literal`) — a sibling/child route
|
|
69
|
+
fails that `from`. Basalt controls read through `FieldHandle`, which uses the non-strict search
|
|
70
|
+
internally.
|
|
71
|
+
- **A `FieldHandle` is the whole read/write surface**: `use()` returns `[value, setValue]` and the
|
|
72
|
+
setter owns the navigate AND the persist — a control never receives `value`/`onChange` (law C2).
|
|
73
|
+
Hand-writing a navigate (a route with its own search shape) uses the reducer form,
|
|
74
|
+
`navigate({ search: (prev) => ({ ...prev, … }) })`, so unrelated params survive.
|
|
75
|
+
- **`useActiveCount()`/`useReset()`** back a `Filters (n)` pill and its `Reset all` — never
|
|
76
|
+
hand-count either.
|
|
77
|
+
- **A reset UNSETS.** `useReset()`/`field.clear()` DELETE the persisted key, never write
|
|
78
|
+
`fallback` (which would pin a thunk fallback as a value nobody chose).
|
|
79
|
+
- **`set(next, { patch })`** merges sibling params the store does NOT own into the same navigate; a
|
|
80
|
+
key another field of the same store owns throws in dev.
|
|
91
81
|
|
|
92
82
|
## Nav links carry the store BY REFERENCE
|
|
93
83
|
|
|
@@ -96,11 +86,9 @@ link: linkOptions({ to: '/dashboard', search: analytics.linkSearch })
|
|
|
96
86
|
```
|
|
97
87
|
|
|
98
88
|
**Pass the function, never call it, never inline an object.** It is a click-time thunk, so arriving
|
|
99
|
-
from anywhere restores the last selection; a module-scope literal (`search: { range: '30d' }`)
|
|
100
|
-
the fallback on every click
|
|
101
|
-
|
|
102
|
-
`basalt/search-literal-link` catches the literal, and in dev `validateSearch` warns once when the URL
|
|
103
|
-
pins the fallback, something else is persisted, and no reader has ever been called.
|
|
89
|
+
from anywhere restores the last selection; a module-scope literal (`search: { range: '30d' }`)
|
|
90
|
+
pins the fallback on every click — `basalt/search-literal-link` catches it. `search: true` is a
|
|
91
|
+
type error against a store-backed route.
|
|
104
92
|
|
|
105
93
|
## The typed nav definition
|
|
106
94
|
|
|
@@ -113,27 +101,21 @@ spread it. `navTarget(NAV, id)` is one destination's link options, typed per id,
|
|
|
113
101
|
the nav into Spotlight in one `.map()`).
|
|
114
102
|
|
|
115
103
|
- **Route options live under `link:`, wrapped in TanStack's own `linkOptions`** — never spread flat
|
|
116
|
-
onto the item
|
|
117
|
-
|
|
118
|
-
|
|
104
|
+
onto the item (a flat shape validates `to` by assignability, no excess-property checking, so a
|
|
105
|
+
typo'd metadata key compiles silently). `id`/`label`/`short`/`icon`/`mobile`/`disabled`/`exact`
|
|
106
|
+
ride outside `link`.
|
|
119
107
|
- **Nesting is `children`**; `mobile` places the destination on the bar (basalt-mantine.md).
|
|
120
108
|
- **Without the `Register` module augmentation, `defineNav` validates NOTHING and reports zero
|
|
121
|
-
errors** — `RegisteredRouter` falls back to `AnyRouter`, every `to` widens to `string
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
- Whether a MISSING `search` is caught depends on the schema's OUTPUT type: with every key required
|
|
127
|
-
(what a store or a defaulted Zod object produces) TanStack raises and the compiler catches it. With
|
|
128
|
-
every key optional, a forgotten `search` compiles — diff the target table by hand there.
|
|
129
|
-
- `staticData` (`title` / `icon` / `navSection`) drives `useRouterBreadcrumbs` and needs the
|
|
130
|
-
generated route tree; everything else in the bridge works against a hand-written router.
|
|
109
|
+
errors** — `RegisteredRouter` falls back to `AnyRouter`, every `to` widens to `string`. Verify
|
|
110
|
+
once by changing a `to` to garbage and confirming the compile error. **Never reach for
|
|
111
|
+
`as never`** to quiet one — the checking is the entire point.
|
|
112
|
+
- `staticData` (`title`/`icon`/`navSection`) drives `useRouterBreadcrumbs` and needs the generated
|
|
113
|
+
route tree.
|
|
131
114
|
|
|
132
115
|
## `createPersistedState` — the localStorage primitive
|
|
133
116
|
|
|
134
|
-
Call it once at module scope; use the returned hook anywhere,
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
fold, a sidebar block, a form draft, the notification history — persists through this one primitive.
|
|
117
|
+
Call it once at module scope; use the returned hook anywhere, no provider. SSR-safe, cross-tab via
|
|
118
|
+
the `storage` event, versioned (bump `version` on a shape change, stale values fall back to
|
|
119
|
+
`initial`). Keys are namespaced `basalt:<key>` automatically; `readPersistedValue(key, v)` is the
|
|
120
|
+
non-React read. Every basalt module that persists — shell collapse, `Section` fold, a sidebar
|
|
121
|
+
block, a form draft, notification history — goes through this one primitive.
|