basalt-ui 1.26.0 → 1.28.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 +23 -23
- package/CHANGELOG.md +67 -0
- package/MIGRATING.md +896 -37
- package/README.md +33 -3
- package/agent/rules/basalt-batteries.md +25 -10
- package/agent/rules/basalt-controls.md +73 -43
- package/agent/rules/basalt-mantine.md +17 -6
- package/agent/rules/basalt-state.md +5 -0
- package/agent/rules/basalt-tokens.md +1 -1
- package/configs/oxlint-plugin.js +1286 -73
- package/configs/oxlint-plugin.test.ts +1338 -29
- package/configs/oxlint.json +12 -5
- package/dist/agent/coalesce.d.ts.map +1 -1
- package/dist/agent/coalesce.js +2 -1
- package/dist/agent/merge.d.ts.map +1 -1
- package/dist/agent/merge.js +2 -1
- package/dist/agent/part-list.d.ts.map +1 -1
- package/dist/agent/part-list.js +2 -0
- package/dist/agent/stick-to-bottom.d.ts +3 -6
- package/dist/agent/stick-to-bottom.d.ts.map +1 -1
- package/dist/agent/stick-to-bottom.js +6 -3
- package/dist/agent-chat/composer.d.ts +6 -2
- package/dist/agent-chat/composer.d.ts.map +1 -1
- package/dist/agent-chat/composer.js +49 -33
- package/dist/agent-chat/relative-time.d.ts +0 -9
- package/dist/agent-chat/relative-time.d.ts.map +1 -1
- package/dist/agent-chat/relative-time.js +2 -1
- package/dist/agent-chat/thread-detail-panel.d.ts +3 -2
- package/dist/agent-chat/thread-detail-panel.d.ts.map +1 -1
- package/dist/agent-chat/thread-detail-panel.js +8 -5
- package/dist/agent-chat/thread-feed-row.d.ts +2 -1
- package/dist/agent-chat/thread-feed-row.d.ts.map +1 -1
- package/dist/agent-chat/thread-feed-row.js +92 -92
- package/dist/agent-chat/thread-feed.d.ts +3 -2
- package/dist/agent-chat/thread-feed.d.ts.map +1 -1
- package/dist/agent-chat/thread-feed.js +8 -3
- package/dist/agent-chat/thread-message.d.ts +4 -3
- package/dist/agent-chat/thread-message.d.ts.map +1 -1
- package/dist/agent-chat/thread-message.js +70 -31
- package/dist/agent-chat/thread-outcome-card.d.ts +3 -2
- package/dist/agent-chat/thread-outcome-card.d.ts.map +1 -1
- package/dist/agent-chat/thread-outcome-card.js +9 -2
- package/dist/agent-chat/thread-workspace.d.ts +7 -2
- package/dist/agent-chat/thread-workspace.d.ts.map +1 -1
- package/dist/agent-chat/thread-workspace.js +62 -29
- package/dist/agent-chat/tool-chip.d.ts +3 -2
- package/dist/agent-chat/tool-chip.d.ts.map +1 -1
- package/dist/agent-chat/tool-chip.js +7 -2
- package/dist/charts/hooks/useBandPlot.d.ts.map +1 -1
- package/dist/charts/hooks/useBandPlot.js +15 -8
- package/dist/charts/index.d.ts +8 -7
- package/dist/charts/index.d.ts.map +1 -1
- package/dist/charts/index.js +45 -5
- package/dist/charts/kinds/BandStrip.d.ts +10 -7
- package/dist/charts/kinds/BandStrip.d.ts.map +1 -1
- package/dist/charts/kinds/BandStrip.js +12 -7
- package/dist/charts/kinds/Bars.d.ts +12 -6
- package/dist/charts/kinds/Bars.d.ts.map +1 -1
- package/dist/charts/kinds/Bars.js +37 -11
- package/dist/charts/kinds/Donut.d.ts +6 -5
- package/dist/charts/kinds/Donut.d.ts.map +1 -1
- package/dist/charts/kinds/Donut.js +19 -2
- package/dist/charts/kinds/DualPanel.d.ts +6 -5
- package/dist/charts/kinds/DualPanel.d.ts.map +1 -1
- package/dist/charts/kinds/DualPanel.js +36 -8
- package/dist/charts/kinds/Heatmap.d.ts +10 -6
- package/dist/charts/kinds/Heatmap.d.ts.map +1 -1
- package/dist/charts/kinds/Heatmap.js +58 -31
- package/dist/charts/kinds/MirroredBars.d.ts +6 -5
- package/dist/charts/kinds/MirroredBars.d.ts.map +1 -1
- package/dist/charts/kinds/MirroredBars.js +9 -2
- package/dist/charts/kinds/MultiLine.d.ts +11 -6
- package/dist/charts/kinds/MultiLine.d.ts.map +1 -1
- package/dist/charts/kinds/MultiLine.js +24 -15
- package/dist/charts/kinds/StackedArea.d.ts +18 -8
- package/dist/charts/kinds/StackedArea.d.ts.map +1 -1
- package/dist/charts/kinds/StackedArea.js +29 -4
- package/dist/charts/kinds/ZonedLine.d.ts +12 -8
- package/dist/charts/kinds/ZonedLine.d.ts.map +1 -1
- package/dist/charts/kinds/ZonedLine.js +33 -23
- package/dist/charts/layout/auto-margin.d.ts +65 -8
- package/dist/charts/layout/auto-margin.d.ts.map +1 -1
- package/dist/charts/layout/auto-margin.js +45 -10
- package/dist/charts/layout/log-ticks.d.ts +27 -0
- package/dist/charts/layout/log-ticks.d.ts.map +1 -0
- package/dist/charts/layout/log-ticks.js +42 -0
- package/dist/charts/primitives/Axes.d.ts +11 -2
- package/dist/charts/primitives/Axes.d.ts.map +1 -1
- package/dist/charts/primitives/Axes.js +15 -5
- package/dist/charts/primitives/CartesianChart.d.ts +45 -7
- package/dist/charts/primitives/CartesianChart.d.ts.map +1 -1
- package/dist/charts/primitives/CartesianChart.js +86 -28
- package/dist/charts/primitives/ChartCard.d.ts +27 -2
- package/dist/charts/primitives/ChartCard.d.ts.map +1 -1
- package/dist/charts/primitives/ChartCard.js +37 -17
- package/dist/charts/primitives/ChartFrame.d.ts +30 -4
- package/dist/charts/primitives/ChartFrame.d.ts.map +1 -1
- package/dist/charts/primitives/ChartFrame.js +45 -15
- package/dist/charts/primitives/ChartLegend.d.ts +13 -2
- package/dist/charts/primitives/ChartLegend.d.ts.map +1 -1
- package/dist/charts/primitives/ChartLegend.js +33 -13
- package/dist/charts/primitives/ChartPending.d.ts +77 -4
- package/dist/charts/primitives/ChartPending.d.ts.map +1 -1
- package/dist/charts/primitives/ChartPending.js +100 -6
- package/dist/charts/primitives/ChartTooltip.d.ts +7 -0
- package/dist/charts/primitives/ChartTooltip.d.ts.map +1 -1
- package/dist/charts/primitives/ChartTooltip.js +18 -5
- package/dist/charts/primitives/Crosshair.d.ts +3 -0
- package/dist/charts/primitives/Crosshair.d.ts.map +1 -1
- package/dist/charts/primitives/Crosshair.js +3 -1
- package/dist/charts/primitives/chart-frame-layout.d.ts +95 -0
- package/dist/charts/primitives/chart-frame-layout.d.ts.map +1 -0
- package/dist/charts/primitives/chart-frame-layout.js +89 -0
- package/dist/charts/primitives/chart-tier.d.ts +16 -0
- package/dist/charts/primitives/chart-tier.d.ts.map +1 -0
- package/dist/charts/primitives/chart-tier.js +20 -0
- package/dist/charts/series.d.ts +55 -1
- package/dist/charts/series.d.ts.map +1 -1
- package/dist/charts/series.js +27 -1
- package/dist/charts/sparklines/BarSparkline.d.ts +3 -3
- package/dist/charts/sparklines/BarSparkline.d.ts.map +1 -1
- package/dist/charts/sparklines/BarSparkline.js +9 -3
- package/dist/charts/sparklines/LineSparkline.d.ts +3 -3
- package/dist/charts/sparklines/LineSparkline.d.ts.map +1 -1
- package/dist/charts/sparklines/LineSparkline.js +15 -3
- package/dist/charts/sparklines/index.d.ts +2 -2
- package/dist/charts/sparklines/index.d.ts.map +1 -1
- package/dist/charts/utils/format.d.ts +92 -2
- package/dist/charts/utils/format.d.ts.map +1 -1
- package/dist/charts/utils/format.js +64 -1
- package/dist/charts/utils/ticks.d.ts +81 -2
- package/dist/charts/utils/ticks.d.ts.map +1 -1
- package/dist/charts/utils/ticks.js +54 -4
- package/dist/cli/index.d.ts.map +1 -1
- package/dist/cli/index.js +2 -2
- package/dist/commands/ShortcutsHelp.d.ts +3 -2
- package/dist/commands/ShortcutsHelp.d.ts.map +1 -1
- package/dist/commands/ShortcutsHelp.js +8 -2
- package/dist/commands/define-commands.d.ts.map +1 -1
- package/dist/commands/define-commands.js +2 -2
- package/dist/commands/define-overlays.d.ts +102 -0
- package/dist/commands/define-overlays.d.ts.map +1 -1
- package/dist/commands/define-overlays.js +102 -2
- package/dist/commands/index.d.ts +10 -1
- package/dist/commands/index.d.ts.map +1 -1
- package/dist/commands/index.js +3 -1
- package/dist/commands/overlays-mount.d.ts +13 -6
- package/dist/commands/overlays-mount.d.ts.map +1 -1
- package/dist/commands/overlays-mount.js +23 -14
- package/dist/common/errors.d.ts +34 -0
- package/dist/common/errors.d.ts.map +1 -0
- package/dist/common/errors.js +36 -0
- package/dist/common/index.d.ts +15 -0
- package/dist/common/index.d.ts.map +1 -0
- package/dist/common/index.js +29 -0
- package/dist/common/props.d.ts +63 -0
- package/dist/common/props.d.ts.map +1 -0
- package/dist/common/props.js +6 -0
- package/dist/common/query-state-like.d.ts +43 -0
- package/dist/common/query-state-like.d.ts.map +1 -0
- package/dist/common/query-state-like.js +20 -0
- package/dist/common/refs.d.ts +29 -0
- package/dist/common/refs.d.ts.map +1 -0
- package/dist/common/refs.js +29 -0
- package/dist/common/scroll-parent.d.ts +23 -0
- package/dist/common/scroll-parent.d.ts.map +1 -0
- package/dist/common/scroll-parent.js +21 -0
- package/dist/common/validate.d.ts +38 -0
- package/dist/common/validate.d.ts.map +1 -0
- package/dist/common/validate.js +36 -0
- package/dist/connectivity/connectivity-indicator.d.ts +3 -1
- package/dist/connectivity/connectivity-indicator.d.ts.map +1 -1
- package/dist/connectivity/connectivity-indicator.js +3 -1
- package/dist/connectivity/connectivity-provider.d.ts.map +1 -1
- package/dist/connectivity/connectivity-provider.js +4 -1
- package/dist/connectivity/index.d.ts +1 -0
- package/dist/connectivity/index.d.ts.map +1 -1
- package/dist/connectivity/types.d.ts +2 -2
- package/dist/connectivity/types.d.ts.map +1 -1
- package/dist/connectivity/use-connectivity.d.ts.map +1 -1
- package/dist/content/article-layout.module.css +11 -4
- package/dist/content/callout.d.ts +8 -4
- package/dist/content/callout.d.ts.map +1 -1
- package/dist/content/callout.js +15 -8
- package/dist/content/guide.d.ts +5 -4
- package/dist/content/guide.d.ts.map +1 -1
- package/dist/content/guide.js +13 -4
- package/dist/content/heading-anchor.d.ts +24 -2
- package/dist/content/heading-anchor.d.ts.map +1 -1
- package/dist/content/heading-anchor.js +23 -9
- package/dist/content/index.d.ts.map +1 -1
- package/dist/content/markdown.d.ts.map +1 -1
- package/dist/content/markdown.js +2 -0
- package/dist/content/prose.module.css +9 -7
- package/dist/content/reading-progress.d.ts +10 -4
- package/dist/content/reading-progress.d.ts.map +1 -1
- package/dist/content/reading-progress.js +26 -10
- package/dist/content/slug.d.ts +4 -0
- package/dist/content/slug.d.ts.map +1 -1
- package/dist/content/toc.d.ts +11 -0
- package/dist/content/toc.d.ts.map +1 -1
- package/dist/content/toc.js +23 -10
- package/dist/controls/actions.d.ts +49 -6
- package/dist/controls/actions.d.ts.map +1 -1
- package/dist/controls/actions.js +39 -8
- package/dist/controls/compare-filter.d.ts +3 -2
- package/dist/controls/compare-filter.d.ts.map +1 -1
- package/dist/controls/compare-filter.js +17 -2
- package/dist/controls/control-group.d.ts +3 -3
- package/dist/controls/control-group.d.ts.map +1 -1
- package/dist/controls/control-group.js +9 -2
- package/dist/controls/controls.module.css +169 -186
- package/dist/controls/controls.module.css.d.ts +9 -11
- package/dist/controls/enum-filter.d.ts +13 -3
- package/dist/controls/enum-filter.d.ts.map +1 -1
- package/dist/controls/enum-filter.js +32 -15
- package/dist/controls/filter-context.d.ts +15 -6
- package/dist/controls/filter-context.d.ts.map +1 -1
- package/dist/controls/filter-pill.d.ts +3 -3
- package/dist/controls/filter-pill.d.ts.map +1 -1
- package/dist/controls/filter-pill.js +4 -1
- package/dist/controls/filter-set.d.ts +3 -2
- package/dist/controls/filter-set.d.ts.map +1 -1
- package/dist/controls/filter-set.js +66 -41
- package/dist/controls/filter-sheet.d.ts +20 -80
- package/dist/controls/filter-sheet.d.ts.map +1 -1
- package/dist/controls/filter-sheet.js +9 -95
- package/dist/controls/index.d.ts +3 -0
- package/dist/controls/index.d.ts.map +1 -1
- package/dist/controls/index.js +6 -0
- package/dist/controls/multi-select-filter.d.ts +18 -2
- package/dist/controls/multi-select-filter.d.ts.map +1 -1
- package/dist/controls/multi-select-filter.js +124 -22
- package/dist/controls/number-filter.d.ts +28 -0
- package/dist/controls/number-filter.d.ts.map +1 -0
- package/dist/controls/number-filter.js +172 -0
- package/dist/controls/panel-row.d.ts +132 -0
- package/dist/controls/panel-row.d.ts.map +1 -0
- package/dist/controls/panel-row.js +173 -0
- package/dist/controls/panel-row.module.css +86 -0
- package/dist/controls/panel-row.module.css.d.ts +13 -0
- package/dist/controls/range-filter.d.ts +20 -5
- package/dist/controls/range-filter.d.ts.map +1 -1
- package/dist/controls/range-filter.js +75 -38
- package/dist/controls/search-filter.d.ts +3 -2
- package/dist/controls/search-filter.d.ts.map +1 -1
- package/dist/controls/search-filter.js +26 -11
- package/dist/controls/select-filter.d.ts +2 -1
- package/dist/controls/select-filter.d.ts.map +1 -1
- package/dist/controls/select-filter.js +4 -0
- package/dist/controls/slider-control.d.ts +36 -0
- package/dist/controls/slider-control.d.ts.map +1 -0
- package/dist/controls/slider-control.js +64 -0
- package/dist/controls/sync-button.d.ts +3 -2
- package/dist/controls/sync-button.d.ts.map +1 -1
- package/dist/controls/sync-button.js +16 -3
- package/dist/controls/toggle-filter.d.ts +3 -2
- package/dist/controls/toggle-filter.d.ts.map +1 -1
- package/dist/controls/toggle-filter.js +29 -12
- package/dist/controls/view-tabs.d.ts +3 -2
- package/dist/controls/view-tabs.d.ts.map +1 -1
- package/dist/controls/view-tabs.js +43 -11
- package/dist/controls-dates/date-range-picker.d.ts +1 -1
- package/dist/controls-dates/date-range-picker.d.ts.map +1 -1
- package/dist/controls-dates/date-range-picker.js +6 -1
- package/dist/dashboard/delta-badge.d.ts +5 -1
- package/dist/dashboard/delta-badge.d.ts.map +1 -1
- package/dist/dashboard/empty-state.d.ts +10 -3
- package/dist/dashboard/empty-state.d.ts.map +1 -1
- package/dist/dashboard/empty-state.js +37 -6
- package/dist/dashboard/index.d.ts +6 -4
- package/dist/dashboard/index.d.ts.map +1 -1
- package/dist/dashboard/index.js +10 -2
- package/dist/dashboard/query-state.d.ts +48 -27
- package/dist/dashboard/query-state.d.ts.map +1 -1
- package/dist/dashboard/query-state.js +111 -57
- package/dist/dashboard/settings-section.d.ts +19 -9
- package/dist/dashboard/settings-section.d.ts.map +1 -1
- package/dist/dashboard/settings-section.js +74 -25
- package/dist/dashboard/stat-card.d.ts +76 -19
- package/dist/dashboard/stat-card.d.ts.map +1 -1
- package/dist/dashboard/stat-card.js +78 -38
- package/dist/dashboard/stat-card.module.css +112 -26
- package/dist/dashboard/stat-card.module.css.d.ts +5 -0
- package/dist/dashboard/stat-group.d.ts +41 -0
- package/dist/dashboard/stat-group.d.ts.map +1 -0
- package/dist/dashboard/stat-group.js +30 -0
- package/dist/dashboard/stat-group.module.css +66 -0
- package/dist/dashboard/stat-group.module.css.d.ts +8 -0
- package/dist/dashboard/widget-grid.d.ts +27 -0
- package/dist/dashboard/widget-grid.d.ts.map +1 -0
- package/dist/dashboard/widget-grid.js +41 -0
- package/dist/dashboard/widget-grid.module.css +53 -0
- package/dist/dashboard/widget-grid.module.css.d.ts +9 -0
- package/dist/data/data-table.d.ts +151 -12
- package/dist/data/data-table.d.ts.map +1 -1
- package/dist/data/data-table.js +392 -138
- package/dist/data/data-table.module.css +64 -0
- package/dist/data/data-table.module.css.d.ts +11 -0
- package/dist/data/index.d.ts +2 -2
- package/dist/data/index.d.ts.map +1 -1
- package/dist/data/index.js +24 -2
- package/dist/data/query-branch.d.ts +28 -0
- package/dist/data/query-branch.d.ts.map +1 -0
- package/dist/data/query-branch.js +10 -0
- package/dist/data/table.d.ts +2 -2
- package/dist/data/table.d.ts.map +1 -1
- package/dist/data/virtual-list.d.ts +65 -6
- package/dist/data/virtual-list.d.ts.map +1 -1
- package/dist/data/virtual-list.js +89 -38
- package/dist/data/virtual.d.ts +1 -1
- package/dist/data/virtual.d.ts.map +1 -1
- package/dist/forms/FormErrorSummary.d.ts +4 -3
- package/dist/forms/FormErrorSummary.d.ts.map +1 -1
- package/dist/forms/FormErrorSummary.js +6 -4
- package/dist/forms/create-form.d.ts +2 -2
- package/dist/forms/field.d.ts +46 -6
- package/dist/forms/field.d.ts.map +1 -1
- package/dist/forms/field.js +10 -5
- package/dist/forms/form-layout.d.ts +142 -0
- package/dist/forms/form-layout.d.ts.map +1 -0
- package/dist/forms/form-layout.js +110 -0
- package/dist/forms/form-layout.module.css +145 -0
- package/dist/forms/form-layout.module.css.d.ts +20 -0
- package/dist/forms/form-state.d.ts +42 -0
- package/dist/forms/form-state.d.ts.map +1 -0
- package/dist/forms/form-state.js +26 -0
- package/dist/forms/index.d.ts +22 -6
- package/dist/forms/index.d.ts.map +1 -1
- package/dist/forms/index.js +19 -3
- package/dist/forms/use-field-array.d.ts +60 -0
- package/dist/forms/use-field-array.d.ts.map +1 -0
- package/dist/forms/use-field-array.js +20 -0
- package/dist/forms/use-form-draft.d.ts +25 -10
- package/dist/forms/use-form-draft.d.ts.map +1 -1
- package/dist/forms/use-form-draft.js +55 -18
- package/dist/forms/use-form-submit.d.ts +88 -0
- package/dist/forms/use-form-submit.d.ts.map +1 -0
- package/dist/forms/use-form-submit.js +63 -0
- package/dist/guard/index.d.ts +1 -1
- package/dist/guard/index.d.ts.map +1 -1
- package/dist/guard/index.js +27 -11
- package/dist/index.d.ts +10 -8
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +44 -4
- package/dist/nav/types.d.ts +15 -6
- package/dist/nav/types.d.ts.map +1 -1
- package/dist/notifications/bell.d.ts +3 -2
- package/dist/notifications/bell.d.ts.map +1 -1
- package/dist/notifications/bell.js +73 -56
- package/dist/notifications/center.d.ts +15 -4
- package/dist/notifications/center.d.ts.map +1 -1
- package/dist/notifications/center.js +5 -2
- package/dist/notifications/define-notifications.d.ts +56 -14
- package/dist/notifications/define-notifications.d.ts.map +1 -1
- package/dist/notifications/define-notifications.js +2 -1
- package/dist/notifications/index.d.ts +6 -2
- package/dist/notifications/index.d.ts.map +1 -1
- package/dist/notifications/index.js +5 -1
- package/dist/notifications/mount-guard.d.ts +8 -0
- package/dist/notifications/mount-guard.d.ts.map +1 -0
- package/dist/notifications/mount-guard.js +19 -0
- package/dist/notifications/notify.d.ts +58 -1
- package/dist/notifications/notify.d.ts.map +1 -1
- package/dist/notifications/notify.js +46 -2
- package/dist/notifications/overlay.d.ts.map +1 -1
- package/dist/notifications/overlay.js +2 -0
- package/dist/notifications/store.d.ts +7 -0
- package/dist/notifications/store.d.ts.map +1 -1
- package/dist/provider/index.d.ts +37 -5
- package/dist/provider/index.d.ts.map +1 -1
- package/dist/provider/index.js +66 -28
- package/dist/provider/lab-theme.d.ts.map +1 -1
- package/dist/provider/lab-theme.js +2 -1
- package/dist/query/devtools.d.ts.map +1 -1
- package/dist/query/devtools.js +1 -0
- package/dist/router-tanstack/field.d.ts +1 -1
- package/dist/router-tanstack/field.d.ts.map +1 -1
- package/dist/router-tanstack/index.d.ts +1 -1
- package/dist/router-tanstack/index.d.ts.map +1 -1
- package/dist/router-tanstack/search-store.d.ts +4 -1
- package/dist/router-tanstack/search-store.d.ts.map +1 -1
- package/dist/router-tanstack/search-store.js +92 -8
- package/dist/router-tanstack/use-nav.d.ts.map +1 -1
- package/dist/router-tanstack/use-nav.js +1 -1
- package/dist/section/index.d.ts +1 -1
- package/dist/section/index.d.ts.map +1 -1
- package/dist/section/section.d.ts +36 -2
- package/dist/section/section.d.ts.map +1 -1
- package/dist/section/section.js +49 -57
- package/dist/section/section.module.css +11 -0
- package/dist/shell/account-types.d.ts +5 -2
- package/dist/shell/account-types.d.ts.map +1 -1
- package/dist/shell/app-brand.d.ts +13 -0
- package/dist/shell/app-brand.d.ts.map +1 -0
- package/dist/shell/app-brand.js +94 -0
- package/dist/shell/app-brand.module.css +109 -0
- package/dist/shell/app-brand.module.css.d.ts +14 -0
- package/dist/shell/app-breadcrumbs.d.ts +4 -2
- package/dist/shell/app-breadcrumbs.d.ts.map +1 -1
- package/dist/shell/app-breadcrumbs.js +33 -22
- package/dist/shell/app-header.module.css +10 -5
- package/dist/shell/app-main.module.css +107 -0
- package/dist/shell/app-main.module.css.d.ts +11 -0
- package/dist/shell/app-mobile-nav.d.ts +3 -2
- package/dist/shell/app-mobile-nav.d.ts.map +1 -1
- package/dist/shell/app-mobile-nav.js +29 -15
- package/dist/shell/app-mobile-nav.module.css +48 -27
- package/dist/shell/app-mobile-nav.module.css.d.ts +0 -1
- package/dist/shell/app-sidebar-account.d.ts +2 -1
- package/dist/shell/app-sidebar-account.d.ts.map +1 -1
- package/dist/shell/app-sidebar-account.js +57 -22
- package/dist/shell/app-sidebar.d.ts +9 -3
- package/dist/shell/app-sidebar.d.ts.map +1 -1
- package/dist/shell/app-sidebar.js +55 -109
- package/dist/shell/app-sidebar.module.css +53 -96
- package/dist/shell/app-sidebar.module.css.d.ts +0 -5
- package/dist/shell/index.d.ts +14 -6
- package/dist/shell/index.d.ts.map +1 -1
- package/dist/shell/index.js +47 -12
- package/dist/shell/isomorphic-layout-effect.d.ts +14 -0
- package/dist/shell/isomorphic-layout-effect.d.ts.map +1 -0
- package/dist/shell/isomorphic-layout-effect.js +5 -0
- package/dist/shell/mobile-nav-model.d.ts.map +1 -1
- package/dist/shell/mobile-nav-model.js +27 -6
- package/dist/shell/nav-count-badge.d.ts +5 -3
- package/dist/shell/nav-count-badge.d.ts.map +1 -1
- package/dist/shell/nav-count-badge.js +3 -1
- package/dist/shell/page-aside.d.ts +43 -0
- package/dist/shell/page-aside.d.ts.map +1 -0
- package/dist/shell/page-aside.js +202 -0
- package/dist/shell/page-aside.module.css +174 -0
- package/dist/shell/page-aside.module.css.d.ts +14 -0
- package/dist/shell/page-bar.d.ts +55 -15
- package/dist/shell/page-bar.d.ts.map +1 -1
- package/dist/shell/page-bar.js +130 -41
- package/dist/shell/page-bar.module.css +107 -13
- package/dist/shell/page-bar.module.css.d.ts +4 -1
- package/dist/shell/sidebar-search.d.ts +4 -2
- package/dist/shell/sidebar-search.d.ts.map +1 -1
- package/dist/shell/sidebar-search.js +9 -4
- package/dist/shell/sidebar-search.module.css +1 -1
- package/dist/state/fields.d.ts +227 -34
- package/dist/state/fields.d.ts.map +1 -1
- package/dist/state/fields.js +77 -30
- package/dist/state/persisted-or-local.d.ts +9 -0
- package/dist/state/persisted-or-local.d.ts.map +1 -0
- package/dist/state/persisted-or-local.js +24 -0
- package/dist/state/persisted.d.ts +12 -0
- package/dist/state/persisted.d.ts.map +1 -1
- package/dist/state/persisted.js +36 -18
- package/dist/state.d.ts +1 -1
- package/dist/state.d.ts.map +1 -1
- package/dist/state.js +2 -6
- package/dist/surfaces.d.ts +12 -11
- package/dist/surfaces.d.ts.map +1 -1
- package/dist/surfaces.js +43 -12
- package/dist/theme/ctl-theme.d.ts.map +1 -1
- package/dist/theme/index.d.ts.map +1 -1
- package/dist/theme/index.js +102 -17
- package/dist/theme/nav-link.module.css +37 -26
- package/dist/theme/segmented-control.module.css +22 -0
- package/dist/theme/segmented-control.module.css.d.ts +1 -0
- package/dist/theme-lab/boot.d.ts +66 -0
- package/dist/theme-lab/boot.d.ts.map +1 -0
- package/dist/theme-lab/boot.js +82 -0
- package/dist/theme-lab/index.d.ts +4 -43
- package/dist/theme-lab/index.d.ts.map +1 -1
- package/dist/theme-lab/index.js +9 -69
- package/dist/theme-toggle/index.d.ts +3 -2
- package/dist/theme-toggle/index.d.ts.map +1 -1
- package/dist/theme-toggle/index.js +8 -2
- package/dist/tokens/index.d.ts +42 -0
- package/dist/tokens/index.d.ts.map +1 -1
- package/dist/tokens/index.js +35 -6
- package/dist/tokens/palette.d.ts +45 -25
- package/dist/tokens/palette.d.ts.map +1 -1
- package/dist/tokens/palette.js +31 -14
- package/dist/tokens.css +4 -5
- package/dist/utils/is-dev.d.ts +3 -0
- package/dist/utils/is-dev.d.ts.map +1 -0
- package/dist/utils/is-dev.js +6 -0
- package/dist/widget-header/delta-badge.d.ts +7 -1
- package/dist/widget-header/delta-badge.d.ts.map +1 -1
- package/dist/widget-header/delta-badge.js +8 -1
- package/dist/widget-header/index.d.ts +2 -2
- package/dist/widget-header/index.d.ts.map +1 -1
- package/dist/widget-header/index.js +3 -1
- package/dist/widget-header/widget-header.d.ts +99 -4
- package/dist/widget-header/widget-header.d.ts.map +1 -1
- package/dist/widget-header/widget-header.js +45 -18
- package/dist/widget-header/widget-header.module.css +87 -7
- package/dist/widget-header/widget-header.module.css.d.ts +1 -0
- package/llms.txt +6 -6
- package/package.json +49 -25
- package/src/agent/coalesce.ts +2 -1
- package/src/agent/merge.ts +2 -1
- package/src/agent/part-list.tsx +2 -0
- package/src/agent/stick-to-bottom.tsx +9 -11
- package/src/agent-chat/composer.tsx +124 -103
- package/src/agent-chat/relative-time.ts +2 -1
- package/src/agent-chat/thread-detail-panel.tsx +9 -5
- package/src/agent-chat/thread-feed-row.tsx +17 -9
- package/src/agent-chat/thread-feed.tsx +9 -3
- package/src/agent-chat/thread-message.tsx +48 -13
- package/src/agent-chat/thread-outcome-card.tsx +9 -1
- package/src/agent-chat/thread-workspace.tsx +72 -33
- package/src/agent-chat/tool-chip.tsx +8 -2
- package/src/charts/hooks/useBandPlot.ts +26 -8
- package/src/charts/index.ts +39 -4
- package/src/charts/kinds/BandStrip.tsx +36 -14
- package/src/charts/kinds/Bars.tsx +67 -16
- package/src/charts/kinds/Donut.tsx +30 -3
- package/src/charts/kinds/DualPanel.tsx +56 -10
- package/src/charts/kinds/Heatmap.tsx +90 -33
- package/src/charts/kinds/MirroredBars.tsx +21 -3
- package/src/charts/kinds/MultiLine.tsx +61 -18
- package/src/charts/kinds/StackedArea.tsx +77 -6
- package/src/charts/kinds/ZonedLine.tsx +71 -31
- package/src/charts/layout/auto-margin.ts +134 -21
- package/src/charts/layout/log-ticks.ts +90 -0
- package/src/charts/primitives/Axes.tsx +33 -5
- package/src/charts/primitives/CartesianChart.tsx +194 -41
- package/src/charts/primitives/ChartCard.tsx +66 -25
- package/src/charts/primitives/ChartFrame.tsx +107 -26
- package/src/charts/primitives/ChartLegend.tsx +43 -13
- package/src/charts/primitives/ChartPending.tsx +185 -7
- package/src/charts/primitives/ChartTooltip.tsx +37 -5
- package/src/charts/primitives/Crosshair.tsx +6 -3
- package/src/charts/primitives/chart-frame-layout.ts +212 -0
- package/src/charts/primitives/chart-tier.tsx +37 -0
- package/src/charts/series.ts +77 -1
- package/src/charts/sparklines/BarSparkline.tsx +11 -3
- package/src/charts/sparklines/LineSparkline.tsx +18 -4
- package/src/charts/sparklines/index.ts +2 -2
- package/src/charts/utils/format.ts +163 -2
- package/src/charts/utils/ticks.ts +149 -4
- package/src/cli/index.ts +8 -3
- package/src/commands/ShortcutsHelp.tsx +10 -3
- package/src/commands/define-commands.ts +2 -2
- package/src/commands/define-overlays.ts +216 -1
- package/src/commands/index.ts +12 -0
- package/src/commands/overlays-mount.tsx +60 -26
- package/src/common/errors.ts +73 -0
- package/src/common/index.ts +21 -0
- package/src/common/props.ts +71 -0
- package/src/common/query-state-like.ts +64 -0
- package/src/common/refs.ts +58 -0
- package/src/common/scroll-parent.ts +42 -0
- package/src/common/validate.ts +94 -0
- package/src/connectivity/connectivity-indicator.tsx +6 -1
- package/src/connectivity/connectivity-provider.tsx +4 -1
- package/src/connectivity/index.ts +1 -0
- package/src/connectivity/types.ts +5 -2
- package/src/connectivity/use-connectivity.ts +3 -2
- package/src/content/article-layout.module.css +11 -4
- package/src/content/callout.tsx +13 -7
- package/src/content/guide.tsx +14 -4
- package/src/content/heading-anchor.tsx +14 -3
- package/src/content/index.ts +2 -0
- package/src/content/markdown.tsx +2 -0
- package/src/content/prose.module.css +9 -7
- package/src/content/reading-progress.tsx +40 -15
- package/src/content/slug.ts +4 -0
- package/src/content/toc.tsx +47 -10
- package/src/controls/actions.tsx +89 -9
- package/src/controls/compare-filter.tsx +20 -3
- package/src/controls/control-group.tsx +11 -4
- package/src/controls/controls.module.css +169 -186
- package/src/controls/controls.module.css.d.ts +9 -11
- package/src/controls/enum-filter.tsx +46 -19
- package/src/controls/filter-context.tsx +21 -8
- package/src/controls/filter-pill.tsx +6 -3
- package/src/controls/filter-set.tsx +32 -13
- package/src/controls/filter-sheet.tsx +44 -194
- package/src/controls/index.ts +8 -0
- package/src/controls/multi-select-filter.tsx +179 -29
- package/src/controls/number-filter.tsx +329 -0
- package/src/controls/panel-row.module.css +86 -0
- package/src/controls/panel-row.module.css.d.ts +13 -0
- package/src/controls/panel-row.tsx +392 -0
- package/src/controls/range-filter.tsx +133 -43
- package/src/controls/search-filter.tsx +31 -13
- package/src/controls/select-filter.tsx +11 -1
- package/src/controls/slider-control.tsx +159 -0
- package/src/controls/sync-button.tsx +13 -3
- package/src/controls/toggle-filter.tsx +37 -17
- package/src/controls/view-tabs.tsx +63 -11
- package/src/controls-dates/date-range-picker.tsx +8 -1
- package/src/dashboard/delta-badge.tsx +5 -1
- package/src/dashboard/empty-state.tsx +72 -25
- package/src/dashboard/index.ts +19 -2
- package/src/dashboard/query-state.tsx +154 -84
- package/src/dashboard/settings-section.tsx +87 -31
- package/src/dashboard/stat-card.module.css +112 -26
- package/src/dashboard/stat-card.module.css.d.ts +5 -0
- package/src/dashboard/stat-card.tsx +207 -68
- package/src/dashboard/stat-group.module.css +66 -0
- package/src/dashboard/stat-group.module.css.d.ts +8 -0
- package/src/dashboard/stat-group.tsx +74 -0
- package/src/dashboard/widget-grid.module.css +53 -0
- package/src/dashboard/widget-grid.module.css.d.ts +9 -0
- package/src/dashboard/widget-grid.tsx +127 -0
- package/src/data/data-table.module.css +64 -0
- package/src/data/data-table.module.css.d.ts +11 -0
- package/src/data/data-table.tsx +927 -346
- package/src/data/index.ts +30 -2
- package/src/data/query-branch.ts +53 -0
- package/src/data/table.ts +5 -0
- package/src/data/virtual-list.tsx +189 -55
- package/src/data/virtual.ts +5 -1
- package/src/forms/FormErrorSummary.tsx +13 -6
- package/src/forms/create-form.ts +2 -2
- package/src/forms/field.ts +60 -11
- package/src/forms/form-layout.module.css +145 -0
- package/src/forms/form-layout.module.css.d.ts +20 -0
- package/src/forms/form-layout.tsx +305 -0
- package/src/forms/form-state.tsx +94 -0
- package/src/forms/index.ts +38 -7
- package/src/forms/use-field-array.ts +94 -0
- package/src/forms/use-form-draft.ts +145 -53
- package/src/forms/use-form-submit.ts +199 -0
- package/src/guard/index.ts +91 -23
- package/src/index.ts +79 -10
- package/src/nav/types.ts +15 -6
- package/src/notifications/bell.tsx +18 -4
- package/src/notifications/center.tsx +18 -5
- package/src/notifications/define-notifications.ts +64 -18
- package/src/notifications/index.ts +12 -1
- package/src/notifications/mount-guard.ts +41 -0
- package/src/notifications/notify.tsx +122 -3
- package/src/notifications/overlay.tsx +2 -0
- package/src/notifications/store.ts +7 -0
- package/src/provider/index.tsx +101 -13
- package/src/provider/lab-theme.ts +2 -1
- package/src/query/devtools.tsx +1 -0
- package/src/router-tanstack/field.ts +5 -0
- package/src/router-tanstack/index.ts +4 -0
- package/src/router-tanstack/search-store.ts +171 -12
- package/src/router-tanstack/use-nav.ts +18 -13
- package/src/section/index.ts +1 -1
- package/src/section/section.module.css +11 -0
- package/src/section/section.tsx +163 -96
- package/src/shell/account-types.ts +5 -2
- package/src/shell/app-brand.module.css +109 -0
- package/src/shell/app-brand.module.css.d.ts +14 -0
- package/src/shell/app-brand.tsx +140 -0
- package/src/shell/app-breadcrumbs.tsx +19 -9
- package/src/shell/app-header.module.css +10 -5
- package/src/shell/app-main.module.css +107 -0
- package/src/shell/app-main.module.css.d.ts +11 -0
- package/src/shell/app-mobile-nav.module.css +48 -27
- package/src/shell/app-mobile-nav.module.css.d.ts +0 -1
- package/src/shell/app-mobile-nav.tsx +43 -11
- package/src/shell/app-sidebar-account.tsx +29 -6
- package/src/shell/app-sidebar.module.css +53 -96
- package/src/shell/app-sidebar.module.css.d.ts +0 -5
- package/src/shell/app-sidebar.tsx +40 -113
- package/src/shell/index.tsx +156 -65
- package/src/shell/isomorphic-layout-effect.ts +14 -0
- package/src/shell/mobile-nav-model.ts +66 -10
- package/src/shell/nav-count-badge.tsx +6 -1
- package/src/shell/page-aside.module.css +174 -0
- package/src/shell/page-aside.module.css.d.ts +14 -0
- package/src/shell/page-aside.tsx +377 -0
- package/src/shell/page-bar.module.css +107 -13
- package/src/shell/page-bar.module.css.d.ts +4 -1
- package/src/shell/page-bar.tsx +294 -94
- package/src/shell/sidebar-search.module.css +1 -1
- package/src/shell/sidebar-search.tsx +13 -4
- package/src/state/fields.ts +360 -69
- package/src/state/persisted-or-local.ts +50 -0
- package/src/state/persisted.ts +76 -26
- package/src/state.ts +4 -7
- package/src/surfaces.ts +43 -12
- package/src/theme/ctl-theme.tsx +10 -0
- package/src/theme/index.ts +129 -16
- package/src/theme/nav-link.module.css +37 -26
- package/src/theme/segmented-control.module.css +22 -0
- package/src/theme/segmented-control.module.css.d.ts +1 -0
- package/src/theme-lab/boot.ts +140 -0
- package/src/theme-lab/index.tsx +21 -112
- package/src/theme-toggle/index.tsx +10 -3
- package/src/tokens/index.ts +50 -6
- package/src/tokens/palette.ts +58 -30
- package/src/utils/is-dev.ts +4 -0
- package/src/widget-header/delta-badge.tsx +25 -5
- package/src/widget-header/index.ts +10 -2
- package/src/widget-header/widget-header.module.css +87 -7
- package/src/widget-header/widget-header.module.css.d.ts +1 -0
- package/src/widget-header/widget-header.tsx +166 -42
- package/dist/agent/adapter.test.d.ts +0 -2
- package/dist/agent/adapter.test.d.ts.map +0 -1
- package/dist/agent/ai-sdk-transport.test.d.ts +0 -2
- package/dist/agent/ai-sdk-transport.test.d.ts.map +0 -1
- package/dist/agent/coalesce.test.d.ts +0 -2
- package/dist/agent/coalesce.test.d.ts.map +0 -1
- package/dist/agent/foreign.test.d.ts +0 -2
- package/dist/agent/foreign.test.d.ts.map +0 -1
- package/dist/agent/id.test.d.ts +0 -2
- package/dist/agent/id.test.d.ts.map +0 -1
- package/dist/agent/merge.test.d.ts +0 -2
- package/dist/agent/merge.test.d.ts.map +0 -1
- package/dist/agent/part-list.test.d.ts +0 -2
- package/dist/agent/part-list.test.d.ts.map +0 -1
- package/dist/agent/parts.test.d.ts +0 -2
- package/dist/agent/parts.test.d.ts.map +0 -1
- package/dist/agent/thread.test.d.ts +0 -2
- package/dist/agent/thread.test.d.ts.map +0 -1
- package/dist/agent/transport.test.d.ts +0 -2
- package/dist/agent/transport.test.d.ts.map +0 -1
- package/dist/agent/use-agent-stream.test.d.ts +0 -2
- package/dist/agent/use-agent-stream.test.d.ts.map +0 -1
- package/dist/agent/use-agent-thread-runs.foreign.test.d.ts +0 -2
- package/dist/agent/use-agent-thread-runs.foreign.test.d.ts.map +0 -1
- package/dist/agent/use-agent-thread-runs.resume.test.d.ts +0 -2
- package/dist/agent/use-agent-thread-runs.resume.test.d.ts.map +0 -1
- package/dist/agent/use-agent-thread-runs.test.d.ts +0 -2
- package/dist/agent/use-agent-thread-runs.test.d.ts.map +0 -1
- package/dist/agent/use-agent-thread-runs.wedge.test.d.ts +0 -2
- package/dist/agent/use-agent-thread-runs.wedge.test.d.ts.map +0 -1
- package/dist/agent-chat/composer.test.d.ts +0 -2
- package/dist/agent-chat/composer.test.d.ts.map +0 -1
- package/dist/agent-chat/relative-time.test.d.ts +0 -2
- package/dist/agent-chat/relative-time.test.d.ts.map +0 -1
- package/dist/agent-chat/thread-feed-row.test.d.ts +0 -2
- package/dist/agent-chat/thread-feed-row.test.d.ts.map +0 -1
- package/dist/agent-chat/thread-feed.test.d.ts +0 -2
- package/dist/agent-chat/thread-feed.test.d.ts.map +0 -1
- package/dist/agent-chat/thread-message.test.d.ts +0 -2
- package/dist/agent-chat/thread-message.test.d.ts.map +0 -1
- package/dist/agent-chat/thread-workspace.test.d.ts +0 -2
- package/dist/agent-chat/thread-workspace.test.d.ts.map +0 -1
- package/dist/agent-chat/tool-chip.test.d.ts +0 -2
- package/dist/agent-chat/tool-chip.test.d.ts.map +0 -1
- package/dist/agent-chat/virtualize.type-guard.test.d.ts +0 -2
- package/dist/agent-chat/virtualize.type-guard.test.d.ts.map +0 -1
- package/dist/charts/cursor/resolve.test.d.ts +0 -2
- package/dist/charts/cursor/resolve.test.d.ts.map +0 -1
- package/dist/charts/cursor/store.test.d.ts +0 -2
- package/dist/charts/cursor/store.test.d.ts.map +0 -1
- package/dist/charts/kinds/BandStrip.test.d.ts +0 -2
- package/dist/charts/kinds/BandStrip.test.d.ts.map +0 -1
- package/dist/charts/kinds/Bars.test.d.ts +0 -2
- package/dist/charts/kinds/Bars.test.d.ts.map +0 -1
- package/dist/charts/kinds/DualPanel.test.d.ts +0 -2
- package/dist/charts/kinds/DualPanel.test.d.ts.map +0 -1
- package/dist/charts/kinds/MirroredBars.test.d.ts +0 -2
- package/dist/charts/kinds/MirroredBars.test.d.ts.map +0 -1
- package/dist/charts/kinds/MultiLine.test.d.ts +0 -2
- package/dist/charts/kinds/MultiLine.test.d.ts.map +0 -1
- package/dist/charts/kinds/StackedArea.test.d.ts +0 -2
- package/dist/charts/kinds/StackedArea.test.d.ts.map +0 -1
- package/dist/charts/kinds/ZonedLine.test.d.ts +0 -2
- package/dist/charts/kinds/ZonedLine.test.d.ts.map +0 -1
- package/dist/charts/layout/auto-margin.test.d.ts +0 -2
- package/dist/charts/layout/auto-margin.test.d.ts.map +0 -1
- package/dist/charts/primitives/CartesianChart.test.d.ts +0 -2
- package/dist/charts/primitives/CartesianChart.test.d.ts.map +0 -1
- package/dist/charts/primitives/ChartCard.test.d.ts +0 -2
- package/dist/charts/primitives/ChartCard.test.d.ts.map +0 -1
- package/dist/charts/primitives/ChartFrame.test.d.ts +0 -2
- package/dist/charts/primitives/ChartFrame.test.d.ts.map +0 -1
- package/dist/charts/primitives/ChartLegend.test.d.ts +0 -2
- package/dist/charts/primitives/ChartLegend.test.d.ts.map +0 -1
- package/dist/charts/primitives/ChartTooltip.test.d.ts +0 -2
- package/dist/charts/primitives/ChartTooltip.test.d.ts.map +0 -1
- package/dist/charts/primitives/XZoneRects.test.d.ts +0 -2
- package/dist/charts/primitives/XZoneRects.test.d.ts.map +0 -1
- package/dist/charts/series.test.d.ts +0 -2
- package/dist/charts/series.test.d.ts.map +0 -1
- package/dist/charts/utils/domain.test.d.ts +0 -2
- package/dist/charts/utils/domain.test.d.ts.map +0 -1
- package/dist/charts/utils/measure-text.test.d.ts +0 -2
- package/dist/charts/utils/measure-text.test.d.ts.map +0 -1
- package/dist/cli/check-coverage.test.d.ts +0 -2
- package/dist/cli/check-coverage.test.d.ts.map +0 -1
- package/dist/cli/check-theme.test.d.ts +0 -2
- package/dist/cli/check-theme.test.d.ts.map +0 -1
- package/dist/cli/help.test.d.ts +0 -2
- package/dist/cli/help.test.d.ts.map +0 -1
- package/dist/cli/init-sync.test.d.ts +0 -2
- package/dist/cli/init-sync.test.d.ts.map +0 -1
- package/dist/cli/placement-engine.test.d.ts +0 -2
- package/dist/cli/placement-engine.test.d.ts.map +0 -1
- package/dist/cli/shipped-versions.test.d.ts +0 -2
- package/dist/cli/shipped-versions.test.d.ts.map +0 -1
- package/dist/cli/tarball-parity.test.d.ts +0 -2
- package/dist/cli/tarball-parity.test.d.ts.map +0 -1
- package/dist/cli/template-format.test.d.ts +0 -2
- package/dist/cli/template-format.test.d.ts.map +0 -1
- package/dist/cli/template-ledger.test.d.ts +0 -2
- package/dist/cli/template-ledger.test.d.ts.map +0 -1
- package/dist/cli/tokens-css.test.d.ts +0 -2
- package/dist/cli/tokens-css.test.d.ts.map +0 -1
- package/dist/cli/toolchain-wiring.test.d.ts +0 -2
- package/dist/cli/toolchain-wiring.test.d.ts.map +0 -1
- package/dist/cli/waiver-audit.test.d.ts +0 -2
- package/dist/cli/waiver-audit.test.d.ts.map +0 -1
- package/dist/content/article-actions.test.d.ts +0 -2
- package/dist/content/article-actions.test.d.ts.map +0 -1
- package/dist/content/article-model.test.d.ts +0 -2
- package/dist/content/article-model.test.d.ts.map +0 -1
- package/dist/content/block-split.test.d.ts +0 -2
- package/dist/content/block-split.test.d.ts.map +0 -1
- package/dist/content/heading-components.test.d.ts +0 -2
- package/dist/content/heading-components.test.d.ts.map +0 -1
- package/dist/content/markdown.test.d.ts +0 -2
- package/dist/content/markdown.test.d.ts.map +0 -1
- package/dist/content/prose.module.css.test.d.ts +0 -2
- package/dist/content/prose.module.css.test.d.ts.map +0 -1
- package/dist/content/sanitize.test.d.ts +0 -2
- package/dist/content/sanitize.test.d.ts.map +0 -1
- package/dist/content/slug.test.d.ts +0 -2
- package/dist/content/slug.test.d.ts.map +0 -1
- package/dist/controls/actions.test.d.ts +0 -2
- package/dist/controls/actions.test.d.ts.map +0 -1
- package/dist/controls/actions.type-guard.test.d.ts +0 -2
- package/dist/controls/actions.type-guard.test.d.ts.map +0 -1
- package/dist/controls/control-group.test.d.ts +0 -2
- package/dist/controls/control-group.test.d.ts.map +0 -1
- package/dist/controls/controls.router.test.d.ts +0 -2
- package/dist/controls/controls.router.test.d.ts.map +0 -1
- package/dist/controls/filter-set.test.d.ts +0 -2
- package/dist/controls/filter-set.test.d.ts.map +0 -1
- package/dist/controls/peer-boundary.test.d.ts +0 -2
- package/dist/controls/peer-boundary.test.d.ts.map +0 -1
- package/dist/controls/props-contract.test.d.ts +0 -2
- package/dist/controls/props-contract.test.d.ts.map +0 -1
- package/dist/controls/sync-button.test.d.ts +0 -2
- package/dist/controls/sync-button.test.d.ts.map +0 -1
- package/dist/dashboard/query-state.test.d.ts +0 -2
- package/dist/dashboard/query-state.test.d.ts.map +0 -1
- package/dist/dashboard/settings-section.test.d.ts +0 -2
- package/dist/dashboard/settings-section.test.d.ts.map +0 -1
- package/dist/dashboard/stat-card.test.d.ts +0 -2
- package/dist/dashboard/stat-card.test.d.ts.map +0 -1
- package/dist/data/data-table.test.d.ts +0 -2
- package/dist/data/data-table.test.d.ts.map +0 -1
- package/dist/guard/check-source.test.d.ts +0 -2
- package/dist/guard/check-source.test.d.ts.map +0 -1
- package/dist/guard/grace.test.d.ts +0 -20
- package/dist/guard/grace.test.d.ts.map +0 -1
- package/dist/guard/guard-hook.test.d.ts +0 -2
- package/dist/guard/guard-hook.test.d.ts.map +0 -1
- package/dist/provider/index.test.d.ts +0 -2
- package/dist/provider/index.test.d.ts.map +0 -1
- package/dist/provider/lab-theme.test.d.ts +0 -2
- package/dist/provider/lab-theme.test.d.ts.map +0 -1
- package/dist/query/error-message.test.d.ts +0 -2
- package/dist/query/error-message.test.d.ts.map +0 -1
- package/dist/router-tanstack/multi-search-param-store.test.d.ts +0 -2
- package/dist/router-tanstack/multi-search-param-store.test.d.ts.map +0 -1
- package/dist/router-tanstack/nav.test.d.ts +0 -2
- package/dist/router-tanstack/nav.test.d.ts.map +0 -1
- package/dist/router-tanstack/search-param-store.test.d.ts +0 -2
- package/dist/router-tanstack/search-param-store.test.d.ts.map +0 -1
- package/dist/router-tanstack/search-store.router.test.d.ts +0 -2
- package/dist/router-tanstack/search-store.router.test.d.ts.map +0 -1
- package/dist/router-tanstack/search-store.test.d.ts +0 -2
- package/dist/router-tanstack/search-store.test.d.ts.map +0 -1
- package/dist/router-tanstack/use-nav.test.d.ts +0 -2
- package/dist/router-tanstack/use-nav.test.d.ts.map +0 -1
- package/dist/section/section.test.d.ts +0 -2
- package/dist/section/section.test.d.ts.map +0 -1
- package/dist/shell/app-mobile-nav.test.d.ts +0 -2
- package/dist/shell/app-mobile-nav.test.d.ts.map +0 -1
- package/dist/shell/app-sidebar.test.d.ts +0 -2
- package/dist/shell/app-sidebar.test.d.ts.map +0 -1
- package/dist/shell/index.test.d.ts +0 -2
- package/dist/shell/index.test.d.ts.map +0 -1
- package/dist/shell/mobile-nav-model.test.d.ts +0 -2
- package/dist/shell/mobile-nav-model.test.d.ts.map +0 -1
- package/dist/shell/page-bar.test.d.ts +0 -2
- package/dist/shell/page-bar.test.d.ts.map +0 -1
- package/dist/state/fields.test.d.ts +0 -2
- package/dist/state/fields.test.d.ts.map +0 -1
- package/dist/styles.floor.test.d.ts +0 -2
- package/dist/styles.floor.test.d.ts.map +0 -1
- package/dist/theme/border-coverage.test.d.ts +0 -18
- package/dist/theme/border-coverage.test.d.ts.map +0 -1
- package/dist/theme/contrast.test.d.ts +0 -2
- package/dist/theme/contrast.test.d.ts.map +0 -1
- package/dist/theme/ctl-theme.test.d.ts +0 -2
- package/dist/theme/ctl-theme.test.d.ts.map +0 -1
- package/dist/theme/ctl-tier-coverage.test.d.ts +0 -2
- package/dist/theme/ctl-tier-coverage.test.d.ts.map +0 -1
- package/dist/theme/density-option.test.d.ts +0 -2
- package/dist/theme/density-option.test.d.ts.map +0 -1
- package/dist/theme/density-relations.test.d.ts +0 -2
- package/dist/theme/density-relations.test.d.ts.map +0 -1
- package/dist/theme/derive-theme.test.d.ts +0 -2
- package/dist/theme/derive-theme.test.d.ts.map +0 -1
- package/dist/theme/divider-law.test.d.ts +0 -2
- package/dist/theme/divider-law.test.d.ts.map +0 -1
- package/dist/theme/fonts-option.test.d.ts +0 -2
- package/dist/theme/fonts-option.test.d.ts.map +0 -1
- package/dist/theme/icon-slot.test.d.ts +0 -2
- package/dist/theme/icon-slot.test.d.ts.map +0 -1
- package/dist/theme/layout-rhythm-css.test.d.ts +0 -2
- package/dist/theme/layout-rhythm-css.test.d.ts.map +0 -1
- package/dist/theme/radius-option.test.d.ts +0 -2
- package/dist/theme/radius-option.test.d.ts.map +0 -1
- package/dist/theme/radius.test.d.ts +0 -2
- package/dist/theme/radius.test.d.ts.map +0 -1
- package/dist/theme/shadow-surfaces.test.d.ts +0 -26
- package/dist/theme/shadow-surfaces.test.d.ts.map +0 -1
- package/dist/theme/spacing.test.d.ts +0 -2
- package/dist/theme/spacing.test.d.ts.map +0 -1
- package/dist/theme/use-basalt-spacing.test.d.ts +0 -2
- package/dist/theme/use-basalt-spacing.test.d.ts.map +0 -1
- package/dist/theme-lab/derive-controls.test.d.ts +0 -2
- package/dist/theme-lab/derive-controls.test.d.ts.map +0 -1
- package/dist/theme-lab/derive-state.test.d.ts +0 -2
- package/dist/theme-lab/derive-state.test.d.ts.map +0 -1
- package/dist/theme-lab/theme-lab.test.d.ts +0 -2
- package/dist/theme-lab/theme-lab.test.d.ts.map +0 -1
- package/dist/tokens/build-fonts-css.test.d.ts +0 -2
- package/dist/tokens/build-fonts-css.test.d.ts.map +0 -1
- package/dist/tokens/build-radius-css.test.d.ts +0 -2
- package/dist/tokens/build-radius-css.test.d.ts.map +0 -1
- package/dist/tokens/chart-margin.test.d.ts +0 -2
- package/dist/tokens/chart-margin.test.d.ts.map +0 -1
- package/dist/tokens/density.test.d.ts +0 -2
- package/dist/tokens/density.test.d.ts.map +0 -1
- package/dist/tokens/derive-radius.test.d.ts +0 -2
- package/dist/tokens/derive-radius.test.d.ts.map +0 -1
- package/dist/tokens/derive.test.d.ts +0 -2
- package/dist/tokens/derive.test.d.ts.map +0 -1
- package/dist/tokens/palette.test.d.ts +0 -2
- package/dist/tokens/palette.test.d.ts.map +0 -1
- package/dist/tokens/text-scale.test.d.ts +0 -2
- package/dist/tokens/text-scale.test.d.ts.map +0 -1
- package/dist/vite-color-mix.test.d.ts +0 -2
- package/dist/vite-color-mix.test.d.ts.map +0 -1
- package/dist/vite.test.d.ts +0 -2
- package/dist/vite.test.d.ts.map +0 -1
- package/dist/widget-header/delta-badge.test.d.ts +0 -2
- package/dist/widget-header/delta-badge.test.d.ts.map +0 -1
- package/dist/widget-header/no-mantine.test.d.ts +0 -2
- package/dist/widget-header/no-mantine.test.d.ts.map +0 -1
- package/dist/widget-header/widget-header.test.d.ts +0 -2
- package/dist/widget-header/widget-header.test.d.ts.map +0 -1
- package/src/agent/adapter.test.ts +0 -1640
- package/src/agent/ai-sdk-transport.test.ts +0 -658
- package/src/agent/coalesce.test.ts +0 -387
- package/src/agent/foreign.test.ts +0 -51
- package/src/agent/id.test.ts +0 -169
- package/src/agent/merge.test.ts +0 -206
- package/src/agent/part-list.test.tsx +0 -112
- package/src/agent/parts.test.ts +0 -720
- package/src/agent/thread.test.ts +0 -220
- package/src/agent/transport.test.ts +0 -70
- package/src/agent/use-agent-stream.test.tsx +0 -287
- package/src/agent/use-agent-thread-runs.foreign.test.tsx +0 -138
- package/src/agent/use-agent-thread-runs.resume.test.tsx +0 -294
- package/src/agent/use-agent-thread-runs.test.tsx +0 -1120
- package/src/agent/use-agent-thread-runs.wedge.test.tsx +0 -387
- package/src/agent-chat/composer.test.tsx +0 -924
- package/src/agent-chat/relative-time.test.ts +0 -95
- package/src/agent-chat/thread-feed-row.test.tsx +0 -510
- package/src/agent-chat/thread-feed.test.tsx +0 -241
- package/src/agent-chat/thread-message.test.tsx +0 -1285
- package/src/agent-chat/thread-workspace.test.tsx +0 -169
- package/src/agent-chat/tool-chip.test.tsx +0 -139
- package/src/agent-chat/virtualize.type-guard.test.ts +0 -49
- package/src/charts/cursor/resolve.test.ts +0 -151
- package/src/charts/cursor/store.test.ts +0 -64
- package/src/charts/kinds/BandStrip.test.tsx +0 -282
- package/src/charts/kinds/Bars.test.tsx +0 -183
- package/src/charts/kinds/DualPanel.test.tsx +0 -527
- package/src/charts/kinds/MirroredBars.test.tsx +0 -232
- package/src/charts/kinds/MultiLine.test.tsx +0 -218
- package/src/charts/kinds/StackedArea.test.tsx +0 -114
- package/src/charts/kinds/ZonedLine.test.tsx +0 -147
- package/src/charts/layout/auto-margin.test.ts +0 -42
- package/src/charts/primitives/CartesianChart.test.tsx +0 -647
- package/src/charts/primitives/ChartCard.test.tsx +0 -66
- package/src/charts/primitives/ChartFrame.test.tsx +0 -142
- package/src/charts/primitives/ChartLegend.test.tsx +0 -78
- package/src/charts/primitives/ChartTooltip.test.tsx +0 -44
- package/src/charts/primitives/XZoneRects.test.tsx +0 -123
- package/src/charts/series.test.ts +0 -112
- package/src/charts/utils/domain.test.ts +0 -54
- package/src/charts/utils/measure-text.test.ts +0 -36
- package/src/cli/check-coverage.test.ts +0 -297
- package/src/cli/check-theme.test.ts +0 -837
- package/src/cli/help.test.ts +0 -170
- package/src/cli/init-sync.test.ts +0 -343
- package/src/cli/placement-engine.test.ts +0 -298
- package/src/cli/shipped-versions.test.ts +0 -83
- package/src/cli/tarball-parity.test.ts +0 -44
- package/src/cli/template-format.test.ts +0 -64
- package/src/cli/template-ledger.test.ts +0 -219
- package/src/cli/tokens-css.test.ts +0 -249
- package/src/cli/toolchain-wiring.test.ts +0 -1358
- package/src/cli/waiver-audit.test.ts +0 -215
- package/src/content/article-actions.test.ts +0 -78
- package/src/content/article-model.test.ts +0 -119
- package/src/content/block-split.test.ts +0 -75
- package/src/content/heading-components.test.tsx +0 -65
- package/src/content/markdown.test.tsx +0 -603
- package/src/content/prose.module.css.test.ts +0 -39
- package/src/content/sanitize.test.ts +0 -659
- package/src/content/slug.test.ts +0 -62
- package/src/controls/actions.test.tsx +0 -252
- package/src/controls/actions.type-guard.test.ts +0 -63
- package/src/controls/control-group.test.tsx +0 -229
- package/src/controls/controls.router.test.tsx +0 -637
- package/src/controls/filter-set.test.tsx +0 -472
- package/src/controls/peer-boundary.test.ts +0 -85
- package/src/controls/props-contract.test.tsx +0 -106
- package/src/controls/sync-button.test.tsx +0 -183
- package/src/dashboard/query-state.test.tsx +0 -152
- package/src/dashboard/settings-section.test.tsx +0 -56
- package/src/dashboard/stat-card.test.tsx +0 -154
- package/src/data/data-table.test.tsx +0 -434
- package/src/guard/check-source.test.ts +0 -3355
- package/src/guard/grace.test.ts +0 -149
- package/src/guard/guard-hook.test.ts +0 -203
- package/src/provider/index.test.tsx +0 -101
- package/src/provider/lab-theme.test.ts +0 -147
- package/src/query/error-message.test.ts +0 -67
- package/src/router-tanstack/multi-search-param-store.test.ts +0 -124
- package/src/router-tanstack/nav.test.ts +0 -111
- package/src/router-tanstack/search-param-store.test.ts +0 -135
- package/src/router-tanstack/search-store.router.test.tsx +0 -661
- package/src/router-tanstack/search-store.test.ts +0 -418
- package/src/router-tanstack/use-nav.test.tsx +0 -187
- package/src/section/section.test.tsx +0 -204
- package/src/shell/app-mobile-nav.test.tsx +0 -403
- package/src/shell/app-sidebar.test.tsx +0 -509
- package/src/shell/index.test.tsx +0 -428
- package/src/shell/mobile-nav-model.test.ts +0 -517
- package/src/shell/page-bar.test.tsx +0 -316
- package/src/state/fields.test.tsx +0 -258
- package/src/styles.floor.test.ts +0 -36
- package/src/theme/border-coverage.test.ts +0 -272
- package/src/theme/contrast.test.ts +0 -354
- package/src/theme/ctl-theme.test.tsx +0 -275
- package/src/theme/ctl-tier-coverage.test.ts +0 -170
- package/src/theme/density-option.test.ts +0 -96
- package/src/theme/density-relations.test.ts +0 -506
- package/src/theme/derive-theme.test.ts +0 -101
- package/src/theme/divider-law.test.ts +0 -259
- package/src/theme/fonts-option.test.ts +0 -75
- package/src/theme/icon-slot.test.tsx +0 -275
- package/src/theme/layout-rhythm-css.test.ts +0 -72
- package/src/theme/radius-option.test.ts +0 -86
- package/src/theme/radius.test.ts +0 -142
- package/src/theme/shadow-surfaces.test.ts +0 -488
- package/src/theme/spacing.test.ts +0 -495
- package/src/theme/use-basalt-spacing.test.tsx +0 -55
- package/src/theme-lab/derive-controls.test.ts +0 -94
- package/src/theme-lab/derive-state.test.ts +0 -71
- package/src/theme-lab/theme-lab.test.ts +0 -46
- package/src/tokens/build-fonts-css.test.ts +0 -52
- package/src/tokens/build-radius-css.test.ts +0 -25
- package/src/tokens/chart-margin.test.ts +0 -39
- package/src/tokens/density.test.ts +0 -259
- package/src/tokens/derive-radius.test.ts +0 -62
- package/src/tokens/derive.test.ts +0 -30
- package/src/tokens/palette.test.ts +0 -114
- package/src/tokens/text-scale.test.ts +0 -51
- package/src/vite-color-mix.test.ts +0 -46
- package/src/vite.test.ts +0 -423
- package/src/widget-header/delta-badge.test.tsx +0 -60
- package/src/widget-header/no-mantine.test.ts +0 -33
- package/src/widget-header/widget-header.test.tsx +0 -187
package/MIGRATING.md
CHANGED
|
@@ -32,6 +32,855 @@ at 1.3.0, `./agent-chat` at 1.10.0.
|
|
|
32
32
|
|
|
33
33
|
## Unreleased
|
|
34
34
|
|
|
35
|
+
**Nothing removed, and ONE thing changed shape: `inputProps` no longer returns `key`** — a silent
|
|
36
|
+
behaviour change at every field call site, caught by the new `basalt/forms-field-key` and described
|
|
37
|
+
in its own § below. Read that one before upgrading; the rest of the minor is additive, with
|
|
38
|
+
enforcement tightened: five oxlint rules plus one guard
|
|
39
|
+
kind became `error`, and new rule ids shipped at `warn`. The store half of this minor also
|
|
40
|
+
fixed four inference and notification defects consumers hit while porting, plus two ways a fallback
|
|
41
|
+
got pinned into localStorage — see § Stores below. Every level change honours the `theme-allow`
|
|
42
|
+
grammar unchanged; only the severity of an unwaived finding moves.
|
|
43
|
+
|
|
44
|
+
**One behaviour change with a blast radius past this package: `AppShell.Main` is now the
|
|
45
|
+
scrollport, and the WINDOW no longer scrolls inside a `BasaltShell`.** Nothing was removed or
|
|
46
|
+
renamed, but four things a consumer may be doing stop working, and all four have a one-line remedy —
|
|
47
|
+
see § The shell scrollport below.
|
|
48
|
+
|
|
49
|
+
What is new, one line each — nothing here renames or removes anything:
|
|
50
|
+
|
|
51
|
+
- **`scrollParentOf` / `SCROLLPORT_ATTRIBUTE`** (`basalt-ui`) — resolve which box actually scrolls an
|
|
52
|
+
element (`null` = the document). The seam behind the shell scrollport change below.
|
|
53
|
+
- **`PageAside`** (`basalt-ui`) — the right-hand aside REGION a route claims, with the panel filter
|
|
54
|
+
surface in its body and a mobile projection into `PageBar` row 2 (`docs/ASIDE-SPEC.md`).
|
|
55
|
+
- **`PanelRow`** (`basalt-ui/controls`) — the aside's inspector/facet row: label above, control
|
|
56
|
+
below, `end` for a control that rides the label line. Every bound control renders one on the
|
|
57
|
+
`panel` surface.
|
|
58
|
+
- **`SliderControl`** (`basalt-ui/controls`) — a `field.number`-bound track for a weight or a
|
|
59
|
+
threshold. It always renders a `PanelRow`, so unlike the pill filters a `Section` body is a
|
|
60
|
+
legitimate home for it and `basalt/bound-control-outside-home` does not police it.
|
|
61
|
+
- **`MultiSelectFilter.counts` / `.max`** — per-option counts (a mono number plus a proportional
|
|
62
|
+
bar) and the panel facet cut-off before the `Show more` fold. Both optional; omitted is today's
|
|
63
|
+
rendering.
|
|
64
|
+
- **`field.number({ step })`** — the declared grain, republished on the handle. `field.number`
|
|
65
|
+
resolves `1` for an `int: true` field that declared none, so `NumberFilter` and `SliderControl`
|
|
66
|
+
cannot answer it differently.
|
|
67
|
+
- **`basalt/bound-control-outside-home`** — a NEW rule id at `warn` (grace to 1.30.0): a bound
|
|
68
|
+
basalt control written into a `Section` body or a page stack renders as a stray pill.
|
|
69
|
+
`control-outside-home` matches raw Mantine tags only, so this half of law C1 was unguarded. Homes
|
|
70
|
+
are the slot props plus the `FilterSet` / `PageAside` / `PanelRow` subtrees; the escape is
|
|
71
|
+
`theme-allow bound-control-outside-home — <why>`.
|
|
72
|
+
- **The chart phone tier** (`basalt-ui/charts`) — `resolveChartTier` / `chartTierMetrics` /
|
|
73
|
+
`useChartTier` / `useChartTierMetrics`, plus `VX.phoneChartWidth` (480). Below that MEASURED
|
|
74
|
+
container width (never a media query — a chart in a narrow grid cell on a desktop is as narrow as
|
|
75
|
+
one on a phone) a chart drops the legend and tick fonts one type step, tightens the `VX.margin`
|
|
76
|
+
FLOORS to 0.75×, shrinks the crosshair dot, narrows the tooltip 140 → 110, and caps the legend at
|
|
77
|
+
two entries with a `+N more` rollup. **This moves rendering, but only below 480px of measured
|
|
78
|
+
width** — nothing at desktop width changes. Opt back out per chart with an explicit
|
|
79
|
+
`legend.maxRows` / `margin` override. `docs/CHARTS-SPEC.md` §8.
|
|
80
|
+
- **`xLabelRotate` accepts `0`**, and left UNSET now auto-rotates to 45 at the phone tier when the
|
|
81
|
+
measured labels cannot fit three ticks side by side. `0` is the documented opt-out. Also on every
|
|
82
|
+
rotated axis, at every width: the LEFT margin now clears the rotated label's leftward projection
|
|
83
|
+
(`width × cos(angle)`), which previously ran the first label off the plot, and `smartTicks` drops
|
|
84
|
+
the grid tick before an appended final one when the two would overlap. Both are corrections to
|
|
85
|
+
§1's measured-gutter law, so a rotated or a densely-labelled axis will lay out slightly
|
|
86
|
+
differently; an explicit `margin` / `xTicks` / `xTickValues` still wins.
|
|
87
|
+
- **`SeriesStyle.curve`** (`basalt-ui/charts`) — `'monotone' | 'linear' | 'step' | 'stepAfter' |
|
|
88
|
+
'stepBefore'`, plus the `curveFor` mapper and the newly re-exported `curveStep`/`curveStepBefore`.
|
|
89
|
+
Default `'monotone'`, which is what every kind hard-coded, so an omitted `curve` moves nothing.
|
|
90
|
+
Honoured by `MultiLine`, `DualPanel`, `ZonedLine`, `StackedArea` and `BarsLine.curve`. Two of
|
|
91
|
+
those read ONE curve for a whole shape rather than one per series: `ZonedLine` takes the PRIMARY
|
|
92
|
+
series' (its band, area and line are one reading), and `StackedArea` takes the TOPMOST VISIBLE
|
|
93
|
+
band that declares one — the last such entry in your `series` array (`AreaStack`'s bands share
|
|
94
|
+
their boundaries, so two curves would leave gaps between them). A hidden band's curve is ignored
|
|
95
|
+
either way, so a legend toggle can hand a stack to the next declarer down.
|
|
96
|
+
- **Single-series legend suppressed by default** (`basalt-ui/charts`) — since commit `5e0ade1`, a
|
|
97
|
+
chart with exactly one visible series and no `legend` prop renders no legend. Pass `legend={{}}`
|
|
98
|
+
(or any explicit config) to keep it.
|
|
99
|
+
- **`Bars`' baseline is now the axis' domain floor**, not `yScale(0)` — previously a y domain that
|
|
100
|
+
did not reach 0 drew the bar off the bottom of the plot; now it stops at the domain's own floor,
|
|
101
|
+
which also makes a log y-axis usable on `Bars`. A domain that includes 0 is unchanged.
|
|
102
|
+
- **Number formatters** (`basalt-ui/charts`) — `fmtCompact`, `fmtPercent`, `fmtCurrency`, `fmtInt`
|
|
103
|
+
and the `formatters` bundle, all `Intl`-backed with an explicit `locale` defaulting to the
|
|
104
|
+
runtime's. `utils/format.ts` shipped only two DATE formatters, so every call site hand-rolled
|
|
105
|
+
`` `$${v}k` ``. **Every formatter — the two date ones included — now returns an em dash for
|
|
106
|
+
non-finite input** (`NaN`, `±Infinity`, an `Invalid Date`) instead of `Intl`'s own `NaN` / `∞`.
|
|
107
|
+
A collapsed domain therefore stops painting its arithmetic accident as a tick label.
|
|
108
|
+
- **`ChartEmpty` / `ChartError` / `state` / `resolveChartState`** (`basalt-ui/charts`) — the chart
|
|
109
|
+
layer's own three-state placeholder set. `state?: { pending?, error?, empty? }` on
|
|
110
|
+
`CartesianChart` / `ChartFrame` / every kind resolves pending → error → empty, so a consumer no
|
|
111
|
+
longer needs the Mantine-coupled `QueryState` (unreachable from `./charts`) to tell a 500 apart
|
|
112
|
+
from an empty result. **`isPending` still works and is not deprecated** — it is an alias for
|
|
113
|
+
`state={{ pending: true }}`. `ChartError` announces as `role="alert"`; `ChartPending` and
|
|
114
|
+
`ChartEmpty` as `role="status"`, so a screen reader hears the resolution and not only the failure.
|
|
115
|
+
- **`BasaltProps` on every exported chart component** — `className` and `style` now reach the root
|
|
116
|
+
element of every kind, sparkline and primitive; `ChartCard` also takes
|
|
117
|
+
`classNames={{ root, header, body }}`. Additive: a component that ignored `className` now honours
|
|
118
|
+
it, so a stylesheet that previously had no effect starts having one.
|
|
119
|
+
- **`ChartTooltipFloat` server-renders.** It was the one `renderToString` casualty in the package
|
|
120
|
+
(an unconditional `createPortal`); it now emits nothing on the server and is unchanged in the
|
|
121
|
+
browser. Consumers carrying an SSR workaround around a chart tooltip can drop it.
|
|
122
|
+
- **`BREAKPOINTS`** (`basalt-ui/tokens`) — `{ article: 1200 }`. The one `@media` literal in the
|
|
123
|
+
package that was not derived from anything now has a named, testable counterpart; a `@media`
|
|
124
|
+
condition cannot read a custom property, so the literal stays and a test holds the two together.
|
|
125
|
+
- **`theme-lab/boot.ts`** — `applyOverrides`/`loadOverrides`/`readVar` moved into their own
|
|
126
|
+
Mantine-free, SSR-safe module (no-op / empty result with no `document`, instead of throwing).
|
|
127
|
+
`basalt-ui/theme-lab` still resolves all three, unchanged, alongside `ThemeLabControls` and
|
|
128
|
+
`DeriveControls` — nothing renamed or removed, and no new subpath was added.
|
|
129
|
+
- **`basalt/raw-size-literal` / `basalt/no-raw-font-size`** — no longer exempt a consumer's own
|
|
130
|
+
`src/tokens/` directory. The exemption was basalt-internal (the derive engine's own hardcoded
|
|
131
|
+
scale values) and leaked to any package with a same-named directory. Consumers with raw sizes
|
|
132
|
+
there move them to `--vx-*` tokens, or add a `theme-allow` waiver.
|
|
133
|
+
- **`BasaltProvider connectivity` prop** — `Omit<ConnectivityProviderProps, 'children'>`, threaded
|
|
134
|
+
straight through to the auto-mounted `ConnectivityProvider`. Reaches `override` for the first
|
|
135
|
+
time (the only prior route was mounting a second, shadowing `ConnectivityProvider`) — see
|
|
136
|
+
§ BasaltProvider below.
|
|
137
|
+
- **Six new oxlint rule ids, all `warn`** — `basalt/provider-above-router`,
|
|
138
|
+
`basalt/duplicate-notifications-mount`, `basalt/query-dual-import`, `basalt/query-fn-unwrap`,
|
|
139
|
+
`basalt/forms-field-key` (grace to 1.30.0) and `basalt/deprecated-export` (permanently
|
|
140
|
+
advisory). `forms-field-key` is the one that matters most in this minor — it is the only thing
|
|
141
|
+
that reports the `inputProps` call sites below, which a compiler cannot see; see § `inputProps`.
|
|
142
|
+
The first four guard
|
|
143
|
+
four doctrines that shipped stated-but-unguarded under a `not guarded:` banner — the provider/
|
|
144
|
+
router mount order, the `BasaltOverlays` XOR `BasaltNotifications` double-mount, the
|
|
145
|
+
`basalt-ui/query` import seam, and `queryFn` wrapping in `unwrap()`. Each is honest about its
|
|
146
|
+
reach in its own message and its grace entry: all four read ONE file, and the two query rules
|
|
147
|
+
carry a documented text heuristic. Escape with `theme-allow <rule> — <why>` as usual. Nothing
|
|
148
|
+
fails a build: every one is `warn` in the shipped preset.
|
|
149
|
+
- **`basalt/deprecated-export`** — nudges an import or a prop basalt has deprecated but still ships,
|
|
150
|
+
reading the `DEPRECATED_EXPORTS` ledger beside the plugin. Today that is `field` from
|
|
151
|
+
`basalt-ui/forms` (autofixed to `inputProps as field`, so no call site moves) and the three
|
|
152
|
+
flattened `BasaltProvider` connectivity props. Permanently `warn` — a deprecation is a schedule,
|
|
153
|
+
not a defect. **On the `field` row, take the two fixes in order**: that rename lands the new
|
|
154
|
+
`inputProps` shape, which has no `key`, and `basalt/forms-field-key` then reports the same line
|
|
155
|
+
and inserts the `key`. Two `--fix` passes, or one manual edit writing both.
|
|
156
|
+
- **Dev-only duplicate-mount warnings** — `BasaltProvider` now warns when a second instance mounts
|
|
157
|
+
while the first is still mounted; `<BasaltOverlays notifications />` and `<BasaltNotifications />`
|
|
158
|
+
now warn when BOTH are mounted at once (previously prose-only in both cases). Both are
|
|
159
|
+
`console.warn`, dev builds only, no behavior change.
|
|
160
|
+
- **`WidgetGrid` + `WidgetGrid.Item` and `StatGroup`** (`basalt-ui`) — the dashboard column law,
|
|
161
|
+
owned once. `cols` is the DESKTOP count and the only number you state: `WidgetGrid` resolves
|
|
162
|
+
`base 1 → sm min(cols, 2) → lg cols`; `StatGroup` (the KPI row) resolves
|
|
163
|
+
`base 2 → sm min(cols, 3) → lg cols`. `<WidgetGrid.Item span={2}>` widens one cell and is clamped
|
|
164
|
+
to the live count at each breakpoint. `StatGroup divided` swaps the column gap for a hairline rail. **These two are the only
|
|
165
|
+
place `lg` exists in the package** — `sm` remains the only breakpoint a consumer writes
|
|
166
|
+
(`docs/CONTROLS-SPEC.md` §2). Replaces hand-written `SimpleGrid cols={{ base, md }}` /
|
|
167
|
+
`Grid.Col span={{ base: 12, md: 8 }}`; Mantine's responsive `cols` object is deliberately not a
|
|
168
|
+
prop.
|
|
169
|
+
- **`StatCard.query`** — `QueryStateLike`, the same structural subset `QueryState` takes. Supplied,
|
|
170
|
+
the card renders its pending / error / empty branch through `QueryState` at the `'section'` tier
|
|
171
|
+
INSIDE the body, directly under the header, which stays put. Omitted, nothing changes. `value` is
|
|
172
|
+
still yours to format — pass a placeholder while the query is pending.
|
|
173
|
+
- **`WidgetHeaderTitleProps` / `WidgetHeaderMetricProps` / `WidgetHeaderDeltaProps`** (`basalt-ui`)
|
|
174
|
+
— the named `Pick` slices of `WidgetHeaderProps` its composers share, cut along the three rows the
|
|
175
|
+
header paints. `StatCardProps` and `SettingsSectionProps` now compose them instead of re-declaring
|
|
176
|
+
props one at a time; **both gained props as a result** — `SettingsSection`/`DangerZone` now accept
|
|
177
|
+
and FORWARD `icon` and `info`. Nothing was removed from either (pinned by
|
|
178
|
+
`src/dashboard/stat-card-props.test.ts`). `Section` and `ChartCard` still cut their own subsets.
|
|
179
|
+
- **`tier` replaces `variant` on `QueryState` / `LoadingState` / `ErrorState` / `EmptyState`** —
|
|
180
|
+
`tier` is the package's word for "how loud is this" (`WidgetHeader`, `CtlSlot`), and `'section'`
|
|
181
|
+
meant two different things across the two spellings. `variant` is `@deprecated` and still
|
|
182
|
+
honoured; resolution is `tier ?? variant ?? 'page'`, so nothing moves until you change the prop.
|
|
183
|
+
`QueryStateTier` is the new type name; `QueryStateVariant` stays exported as an alias. No removal
|
|
184
|
+
is scheduled — this is a preferred spelling, not a sunset.
|
|
185
|
+
- **`WidgetHeader` and `QueryState` gained slot classes** — `classNames={{ root, title, metric,
|
|
186
|
+
icon }}` on the first, `classNames={{ root }}` on the second (the branch that is live). Additive.
|
|
187
|
+
`Section` now OMITS `classNames` from the `WidgetHeaderProps` it re-publishes, so its slot union
|
|
188
|
+
stays exactly `root | header | body` — a `<Section classNames={{ metric: … }}>` that used to
|
|
189
|
+
type-check (and do nothing) is now a compile error. Reach the header's own slots on a
|
|
190
|
+
`WidgetHeader`.
|
|
191
|
+
- **`Callout` extends `BasaltProps`** — `className`/`style` were already accepted and are now the
|
|
192
|
+
shared members, so `exactOptionalPropertyTypes` consumers can forward an `string | undefined`
|
|
193
|
+
through. No rendering change.
|
|
194
|
+
- **`PageAside` throws on a missing `title`** — it is both the header text and the region's
|
|
195
|
+
`aria-label`, so an omitted one shipped a nameless landmark rather than a crash. Now
|
|
196
|
+
`[basalt] PageAside: prop "title" is required — …`, in every build. `title` was never optional in
|
|
197
|
+
the type; this only reaches untyped JS and runtime-built props objects.
|
|
198
|
+
- **`BasaltDataTable` warns (dev only) when `stickyHeaderOffset` meets `maxHeight`/`minWidth`** —
|
|
199
|
+
the offset has always been DROPPED there (the sticky `<thead>` anchors to the scroll container's
|
|
200
|
+
own top edge, not the window). The behaviour is unchanged; it just says so now.
|
|
201
|
+
- **`query` on `Section`, `BasaltDataTable` and `BasaltVirtualList`** — law C3's uniform container
|
|
202
|
+
contract. Pass a `QueryStateLike` (a TanStack `UseQueryResult` is one) and the container resolves
|
|
203
|
+
the body: pending → its own placeholder (`QueryState`'s section-tier spinner / the table's
|
|
204
|
+
skeleton rows / the list's skeleton rows), error with no data → an `ErrorState` with the query's
|
|
205
|
+
own `refetch` behind Retry, anything else → the content, or the empty branch. **The table and the
|
|
206
|
+
list had NO error branch at all**, so a 500 rendered _No data to display._ / a blank box — the
|
|
207
|
+
false claim `QueryState` exists to delete. Additive: omit `query` and nothing changes.
|
|
208
|
+
`Section` also gains `empty?: QueryEmptyCopy` (copy for that branch, `QueryState`'s own type) and
|
|
209
|
+
`BasaltVirtualList` gains `emptyState?: ReactNode` (which works with or without `query`).
|
|
210
|
+
`isLoading` still works on both containers and is NOT deprecated; passing it beside `query` lets
|
|
211
|
+
`query` win and warns once in dev. The chrome stays drawn through every branch — a table keeps its
|
|
212
|
+
`<thead>`, toolbar and pagination bar, a `Section` keeps its header, chevron and `summary` — which
|
|
213
|
+
is why this is not `QueryState` wrapped around the container. A refetch that fails over rows
|
|
214
|
+
already on screen keeps the rows with no banner; compose `QueryState` AROUND the container for
|
|
215
|
+
that.
|
|
216
|
+
- **`BasaltDataTable.onRowActivate`** — `(row: T) => void`, fired by a click on the row and by Enter
|
|
217
|
+
on a focused one. The row → detail hook that pairs with `PageAside`. The row keeps its native
|
|
218
|
+
`<tr>` semantics and takes `tabIndex=0` + `data-activatable` rather than `role="button"` (a role
|
|
219
|
+
swap costs the column-header announcement that is the reason the data is in a table); the cursor
|
|
220
|
+
and focus ring come from a module class. A click originating inside the selection checkbox does
|
|
221
|
+
not activate.
|
|
222
|
+
- **`BasaltDataTable` row selection** — `enableRowSelection` prepends a checkbox column (header =
|
|
223
|
+
select-all on the page) and arms TanStack's row-selection feature; `rowSelection` /
|
|
224
|
+
`onRowSelectionChange` are the controlled pair over TanStack's own `RowSelectionState` (now
|
|
225
|
+
re-exported from `basalt-ui/data` and `basalt-ui/data/table`), and `getRowId` makes a selection
|
|
226
|
+
survive a re-sort or a refetch (the default id is the row INDEX). `bulkActions` renders a bar
|
|
227
|
+
above the table while ≥1 row is selected — the count, then the actions, through the SAME
|
|
228
|
+
`BarAction[]` vocabulary `PageBar` uses, so the ≤3-inline fold and the mobile kebab are basalt's
|
|
229
|
+
here too. **Its signature is `(rows: T[]) => BarAction[]`, a function and not a bare array**, and
|
|
230
|
+
deliberately: `BarActionItem.onClick` stays `() => void` (one unforked vocabulary across every
|
|
231
|
+
home), so the selected rows reach a handler through the closure you write — and an UNCONTROLLED
|
|
232
|
+
table can offer bulk actions at all, since the selection lives inside it.
|
|
233
|
+
- **`Section.actions` and `BasaltDataTable.actions` accept `BarAction[] | ReactNode`** — law C15.
|
|
234
|
+
Handed typed data, basalt owns the C6 budget and the C7 overflow fold (≤3 inline, the rest behind
|
|
235
|
+
`More`, one kebab below `sm`) exactly as `PageBar` does; handed a node, rendering is byte-for-byte
|
|
236
|
+
what it was. Every entry lands in `secondary` — a `BarAction[]` carries no primary marker, and C6's
|
|
237
|
+
"exactly one primary" stays the page bar's rule. `Section`'s ≤3 dev warning now counts an array
|
|
238
|
+
EXACTLY (`Children.count` read one as a single child). Both slots were `ReactNode` before, so no
|
|
239
|
+
call site moves.
|
|
240
|
+
- **`overlays.confirm` / `overlays.confirmDelete`** (`basalt-ui/commands`) — the two-button dialog
|
|
241
|
+
every consumer was registering as a `defineOverlays` entry with its own button pair, now
|
|
242
|
+
registry-free: `confirm({ title, body?, confirmLabel?, cancelLabel?, danger?, onConfirm,
|
|
243
|
+
onCancel? })` resolves `true`/`false` and fires exactly one callback, whichever exit the user takes
|
|
244
|
+
(cancel, escape, click-outside and the close button all count as `false`). `danger` paints the
|
|
245
|
+
confirm button in the theme's derived destructive family. `confirmDelete({ subject, count?,
|
|
246
|
+
onConfirm })` is the counted one-liner over it ("Delete 3 items?"). Both REJECT with a named
|
|
247
|
+
`[basalt] overlays.confirm: …` error when the `@mantine/modals` peer is absent, or when no
|
|
248
|
+
`ModalsProvider` is live — previously either returned a promise nothing would ever settle, because
|
|
249
|
+
the imperative API is a window event bus with nothing subscribed. `@mantine/modals` stays lazily
|
|
250
|
+
imported, so the peer is still optional. Additive: `defineOverlays` and `overlays.open` are
|
|
251
|
+
unchanged.
|
|
252
|
+
- **`registerModalsProvider()`** (`basalt-ui/commands`) — how a consumer who mounts
|
|
253
|
+
`<ModalsProvider>` THEMSELVES (with `<BasaltOverlays modals={false}>`, or with no `BasaltOverlays`
|
|
254
|
+
at all) tells `overlays.confirm` the layer is up. `<BasaltOverlays>` registers its own provider, so
|
|
255
|
+
the default path needs nothing. Call it from an effect and return its result as the cleanup:
|
|
256
|
+
|
|
257
|
+
```tsx
|
|
258
|
+
useEffect(() => registerModalsProvider(), [])
|
|
259
|
+
```
|
|
260
|
+
|
|
261
|
+
Availability is a COUNTER of live providers, not a flag, so two overlapping mounts (a route swap
|
|
262
|
+
mounting the next shell before unmounting the last) never report "no layer" while one is serving.
|
|
263
|
+
There is no way to detect the provider from outside React — its context is only readable through
|
|
264
|
+
`useModals()`, and `confirm` is an imperative call with no component to read it from — so the
|
|
265
|
+
registration is explicit and unregistered is indistinguishable from absent.
|
|
266
|
+
|
|
267
|
+
- **`notifyUndo` / `notifyUndoable`** (`basalt-ui/notifications`) — an undo window on top of the
|
|
268
|
+
existing toast machinery: `notifyUndo({ message, onUndo, window = 6000, onExpire })` shows a toast
|
|
269
|
+
carrying an `Undo` button and returns `{ id, dismiss() }`. The affordance and the grace period are
|
|
270
|
+
ONE number (`autoClose === window`), and exactly one of `onUndo` / `onExpire` runs, exactly once —
|
|
271
|
+
`onExpire` is where the optimistic mutation COMMITS. `dismiss()` settles the window immediately
|
|
272
|
+
(running `onExpire`), so a dismissed toast can never strand an uncommitted change.
|
|
273
|
+
`notifyUndoable(mutate, undo, opts)` is the same thing spelled for the optimistic shape. No new
|
|
274
|
+
store — the toast is recorded to the notification history like any other.
|
|
275
|
+
- **`NotifyOptions.historyMessage`** — what the persisted history records when `message` is a
|
|
276
|
+
composed ReactNode the store cannot stringify (`String(<Group/>)` is `[object Object]`). Defaults
|
|
277
|
+
to today's `String(message)`, so nothing moves unless you pass it. `notifyUndo` uses it.
|
|
278
|
+
- **`missingLayer`** (`basalt-ui`) — a message builder beside `requiredProp`/`oneOf`/`duplicateMount`
|
|
279
|
+
for "this call needs a layer that is not mounted or not installed". Additive.
|
|
280
|
+
- **`emit`'s payload now narrows per kind** (`basalt-ui/notifications`) — `NotificationSpec<P>` and
|
|
281
|
+
`NotificationAction<P>` are generic, `P` inferred from `toMessage`/`action.run`'s parameter, the
|
|
282
|
+
same mechanism `Overlay<P>` uses for `render`. Annotate the payload shape and `emit('kind', …)`
|
|
283
|
+
requires it, a wrong shape is a tsc error. A kind that annotates neither function keeps today's
|
|
284
|
+
`payload?: unknown` — additive, no existing `defineNotifications` call needs a change.
|
|
285
|
+
- **The form layer** (`basalt-ui/forms`) — `./forms` was an adapter with no layout, no submit
|
|
286
|
+
lifecycle, no array helper and no disabled propagation (audit B #5). Seven new exports, all
|
|
287
|
+
additive; `useBasaltForm`, `FormErrorSummary` and `useFormDraft`'s existing signature are
|
|
288
|
+
untouched. `inputProps` is the one exception, and it is not additive — see § `inputProps` no
|
|
289
|
+
longer returns `key` below.
|
|
290
|
+
- **`FormSection` / `FormRow` / `FormGroup` / `FormActions`** — the layout. `FormRow` IS law C1's
|
|
291
|
+
third home, the form row: label left / control right, label above below `sm`, the swap in CSS
|
|
292
|
+
(law C9). It does NOT replace `SettingsRow` — that stays the settings-page variant, and both
|
|
293
|
+
keep Mantine's `md` tier rather than mounting a `CtlSlot`. `FormActions` takes the same
|
|
294
|
+
`BarAction[] | ReactNode` union law C15 gave `Section.actions`.
|
|
295
|
+
- **`useFormSubmit(form, handler, options?)`** — `{ submit, isSubmitting, submitError, reset }`.
|
|
296
|
+
Catches the handler's throw and decodes it through `toErrorMessage` (override with `mapError`),
|
|
297
|
+
routes a thrown `{ fieldErrors }` envelope onto the fields via `form.setErrors`, and focuses the
|
|
298
|
+
first errored field on BOTH failure paths. `isSubmitting` is Mantine's own `form.submitting`,
|
|
299
|
+
not a second flag beside it.
|
|
300
|
+
- **`options.validateAsync`** — the async validation rule `useBasaltForm` has no room for:
|
|
301
|
+
`schemaResolver(schema, { sync: true })` is still hard-coded, so `validate()`/`isValid()` stay
|
|
302
|
+
synchronous, and the async rule runs at submit time after the schema and before the handler.
|
|
303
|
+
- **`FormStateProvider` / `useFormState`** — `{ disabled, submitting }`. The layout primitives
|
|
304
|
+
read it and disable their control region through a native `<fieldset disabled>`, so nothing has
|
|
305
|
+
to be threaded to each input and no child is cloned. Nesting ORs; it cannot re-enable.
|
|
306
|
+
- **`useFieldArray(form, path)`** — `{ items, append, remove, move, key }` over
|
|
307
|
+
`insertListItem`/`removeListItem`/`reorderListItem` + `form.key`. `key(index)` is POSITIONAL
|
|
308
|
+
(Mantine's list actions do not rotate the form key generation) — a user-reorderable list still
|
|
309
|
+
wants an id on the item.
|
|
310
|
+
- **`useFormDraft(form, { autosave })`** — `true`, or `{ debounceMs }`. The hook now owns its own
|
|
311
|
+
`form.watch` subscription, replacing the documented `saveDraftRef` + `onValuesChange` dance. It
|
|
312
|
+
is OFF by default and READ ONCE at mount (the watch set is a hook count), so every existing call
|
|
313
|
+
site behaves exactly as before. `DEFAULT_AUTOSAVE_DEBOUNCE_MS` is exported.
|
|
314
|
+
- **Still subpath-only.** The root barrel re-exports none of this, so a consumer without
|
|
315
|
+
`@mantine/form` is unaffected by importing `basalt-ui`.
|
|
316
|
+
- **Mobile "More" sheet rows now 40px with the sidebar's own insets** — `--vx-space-mobile-nav-row-
|
|
317
|
+
height` 44 → 40 (WCAG 2.5.5 AA touch floor, not the AAA figure the bar's own `mobileNavBarHeight`
|
|
318
|
+
still holds to). The rows themselves no longer force a bespoke touch padding over the theme's
|
|
319
|
+
`NavLink` styling; they now render with the SAME `--vx-space-row-inset-y`/`-x` padding and
|
|
320
|
+
`VX.text.md` the desktop sidebar row does. A nested (child) row gains the sidebar's own child
|
|
321
|
+
indent — a 1px `--vx-divider` left guide. Purely visual; no prop, export or behaviour changed.
|
|
322
|
+
- **`NotificationCenter` defaults to `width: '100%'`, not a hardcoded `320`** — it now sizes to its
|
|
323
|
+
host instead of assuming it always sits inside its own 320px popover. `NotificationBell` fixes the
|
|
324
|
+
320px width at the `Popover` itself (`<Popover width={320}>`) instead, so nothing changes for that
|
|
325
|
+
call path; a consumer mounting `NotificationCenter` directly (a Drawer, an inline card) now gets a
|
|
326
|
+
component that shrinks to its container rather than overflowing it. `style` still merges over the
|
|
327
|
+
default, so `style={{ width: 280 }}` still wins.
|
|
328
|
+
|
|
329
|
+
### `inputProps` no longer returns `key` — pair it with the new `fieldKey`
|
|
330
|
+
|
|
331
|
+
**This is the one thing in the minor that needs a code change at every call site, and the compiler
|
|
332
|
+
will not tell you about a single one of them.** It is a one-line-per-field edit:
|
|
333
|
+
|
|
334
|
+
```tsx
|
|
335
|
+
/* before (1.27) */ <TextInput {...inputProps(form, 'email')} />
|
|
336
|
+
/* after */ <TextInput key={fieldKey(form, 'email')} {...inputProps(form, 'email')} />
|
|
337
|
+
```
|
|
338
|
+
|
|
339
|
+
**Exactly what changed.** In 1.27 `inputProps(form, path)` returned `form.getInputProps(path)` **and
|
|
340
|
+
`key`** in one object, so a single spread covered both. It now returns `form.getInputProps(path)`
|
|
341
|
+
and nothing else; `fieldKey(form, path)` is the other half, written as a real JSX `key` attribute.
|
|
342
|
+
The bundle was basalt's own invention, and React 19 logs `A props object containing a "key" prop is
|
|
343
|
+
being spread into JSX` on every render of it — three fields, three warnings per page.
|
|
344
|
+
`key={form.key(path)} {...form.getInputProps(path)}` is Mantine's own documented idiom; `fieldKey` +
|
|
345
|
+
`inputProps` is that idiom with basalt's names.
|
|
346
|
+
|
|
347
|
+
**What breaks if you only upgrade and do nothing.** Nothing type-checks differently, nothing throws
|
|
348
|
+
and no warning is logged — the 1.27 call site is still a valid spread of a valid object. The element
|
|
349
|
+
simply has no `key` any more, so React reuses the DOM node and an uncontrolled input keeps its old
|
|
350
|
+
text through `form.reset()`, `form.setValues()` and a removed list row. That is the entire failure
|
|
351
|
+
mode: a form that stops resetting, with no signal anywhere.
|
|
352
|
+
|
|
353
|
+
**What catches it: `basalt/forms-field-key`**, new in this minor at `warn` (grace to 1.30.0). It
|
|
354
|
+
reports every `{...inputProps(…)}` spread whose element carries no sibling `key`, and it
|
|
355
|
+
**autofixes** — inserting `key={fieldKey(<same args>)}` and adding `fieldKey` to the existing
|
|
356
|
+
`basalt-ui/forms` import. Run `oxlint --fix` over the app and read the diff; the escape hatch for an
|
|
357
|
+
element genuinely remounted by its parent is `theme-allow forms-field-key — <why>`.
|
|
358
|
+
|
|
359
|
+
**The deprecated `field` alias did NOT follow `inputProps` here.** It is no longer
|
|
360
|
+
`export const field = inputProps`: it keeps the 1.27 return shape, `key` included, so
|
|
361
|
+
`{...field(form, 'x')}` behaves in 1.28.0 byte for byte as it did in 1.27 — including the React 19
|
|
362
|
+
key-spread warning. An alias would have changed what every existing call site DOES without changing
|
|
363
|
+
whether it compiles, and a deprecation is a schedule, not a behaviour change. `forms-field-key`
|
|
364
|
+
reports the `field(` spread too, with its own message pointing here; the alias itself is removed in
|
|
365
|
+
`1.29.0`.
|
|
366
|
+
|
|
367
|
+
### `BasaltDataTable` — the root is a `<div>`, not a Fragment
|
|
368
|
+
|
|
369
|
+
**One structural change, no prop change.** The component returned a Fragment, so the header row, the
|
|
370
|
+
table (or its scroll container) and the pagination bar were DIRECT CHILDREN of whatever the caller
|
|
371
|
+
rendered it into. It now always renders a wrapper:
|
|
372
|
+
|
|
373
|
+
```html
|
|
374
|
+
<div class="{classNames.root} {className}" style="{style}">
|
|
375
|
+
…header row… …table / Table.ScrollContainer… …pagination bar…
|
|
376
|
+
</div>
|
|
377
|
+
```
|
|
378
|
+
|
|
379
|
+
A `className` needs a root to live on (`common/props.ts`), and a Fragment has none — so the wrapper
|
|
380
|
+
is what `className`, `style` and `classNames.root` all resolve against. It is unconditional: a table
|
|
381
|
+
with no title, no toolbar and no pagination still renders it.
|
|
382
|
+
|
|
383
|
+
**What breaks:** any CSS or test selector written against the OLD flat structure. A
|
|
384
|
+
`.page-grid > table`, a `:first-child` rule aimed at the table, an `:nth-child` counting the header
|
|
385
|
+
row and the pagination bar as siblings of your own content, or a flex/grid parent that laid those
|
|
386
|
+
three boxes out itself — all now see one child. Target the wrapper instead, and give it the layout:
|
|
387
|
+
|
|
388
|
+
```css
|
|
389
|
+
/* before */ .page-grid > table { … }
|
|
390
|
+
/* after */ .page-grid > div > table { … } /* or: <BasaltDataTable classNames={{ root: 'my-table' }} /> */
|
|
391
|
+
```
|
|
392
|
+
|
|
393
|
+
Pinned by `src/data/data-table.test.tsx` ("the root is one div carrying classNames.root, wrapping
|
|
394
|
+
the table and the pagination bar"), so it cannot revert silently.
|
|
395
|
+
|
|
396
|
+
### BasaltProvider — a `connectivity` object replaces three flattened props
|
|
397
|
+
|
|
398
|
+
`sseUrl` / `healthUrl` / `healthIntervalMs` on `BasaltProvider` are now `@deprecated` aliases for
|
|
399
|
+
the corresponding fields on the new `connectivity` prop — **removed in 1.29.0**. `connectivity`
|
|
400
|
+
wins WHOLESALE once supplied, not per-key: passing `connectivity` at all makes basalt ignore the
|
|
401
|
+
three deprecated props entirely, even ones `connectivity` itself leaves unset. Supplying both logs a
|
|
402
|
+
dev-only warning. Move every deprecated field to `connectivity` in one pass, not one field at a time.
|
|
403
|
+
|
|
404
|
+
| Removed / deprecated | Replacement |
|
|
405
|
+
| ----------------------------------------- | ----------------------------------------------------------------------------------------------------------------------------------- |
|
|
406
|
+
| `<BasaltProvider sseUrl={…} />` | `<BasaltProvider connectivity={{ sseUrl: … }} />` — `@deprecated`, removed 1.29.0 |
|
|
407
|
+
| `<BasaltProvider healthUrl={…} />` | `<BasaltProvider connectivity={{ healthUrl: … }} />` — `@deprecated`, removed 1.29.0 |
|
|
408
|
+
| `<BasaltProvider healthIntervalMs={…} />` | `<BasaltProvider connectivity={{ healthIntervalMs: … }} />` — `@deprecated`, removed 1.29.0 |
|
|
409
|
+
| (unreachable before this minor) | `<BasaltProvider connectivity={{ override: {…} }} />` — simulate a signal for testing/demo, no second `ConnectivityProvider` needed |
|
|
410
|
+
|
|
411
|
+
**`cssVariablesResolver` can no longer reach `BasaltProvider` through the passthrough
|
|
412
|
+
`MantineProviderProps` rest** — it was silently spreadable and would override basalt's own resolver
|
|
413
|
+
(the one thing the provider exists to install). `Omit`ted from the accepted prop type; pass any
|
|
414
|
+
palette customization through `createBasaltTheme(overrides, { derive, fonts, radius, density })`
|
|
415
|
+
instead.
|
|
416
|
+
|
|
417
|
+
### `basalt-ui/connectivity` — `queryOnline` narrowed to `boolean`
|
|
418
|
+
|
|
419
|
+
`ConnectivitySnapshot['details'].queryOnline` and `ConnectivityOverride.queryOnline` drop the
|
|
420
|
+
`| null` arm. The JSDoc used to claim null meant "QueryClient not mounted", but `onlineManager` is a
|
|
421
|
+
module-level singleton read with no such check — the only null this field ever carried was the
|
|
422
|
+
pre-hydration SSR snapshot, which now reports an optimistic `true` (matching `browserOnline`'s own
|
|
423
|
+
SSR default) instead. Code branching on `queryOnline === null` was already dead; delete it.
|
|
424
|
+
|
|
425
|
+
### `basalt-ui/state` — eight internal symbols dropped from the barrel
|
|
426
|
+
|
|
427
|
+
| Removed / renamed | Replacement | Note |
|
|
428
|
+
| ---------------------------------------------------------------------------------------------------------------- | ----------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
|
|
429
|
+
| `createStoreCore`, `resolveFieldCodec` (`basalt-ui/state`) | none | Both were `@internal` — the seam `createSearchStore` is built on, not a consumer API — and were never meant to be a public contract. No replacement needed. |
|
|
430
|
+
| `FieldCodec`, `StoreEntry`, `StoreCoreOptions`, `StoreCore`, `FieldUse`, `FieldWrite` (types, `basalt-ui/state`) | none | Also `@internal` — the supporting types behind `createStoreCore`/`resolveFieldCodec`, dropped alongside the two functions for the same reason. No replacement needed. |
|
|
431
|
+
|
|
432
|
+
### `basalt-ui/forms` — `field` renamed to `inputProps`
|
|
433
|
+
|
|
434
|
+
Two unrelated exports shared the name `field`: the forms adapter's `getInputProps`+`key` bundler and
|
|
435
|
+
the `field.enum/multi/range/number/boolean/string` store-field builder in `basalt-ui/state` and
|
|
436
|
+
`basalt-ui/router-tanstack`. A page combining a form and a filter store had to alias one on import.
|
|
437
|
+
|
|
438
|
+
| Removed / renamed | Replacement | Note |
|
|
439
|
+
| --------------------------- | ------------ | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
|
|
440
|
+
| `field` (`basalt-ui/forms`) | `inputProps` | Same signature — `inputProps(form, path)`. `field` still resolves from `basalt-ui/forms` as a `@deprecated` alias, so nothing breaks; the alias goes away the next time the forms surface changes, and that removal ships as a plain `feat:`, never a major. **Since the Unreleased minor the two are no longer the same function**: `inputProps` dropped `key` from its return and `field` did not — see § `inputProps` no longer returns `key`. |
|
|
441
|
+
|
|
442
|
+
The `field.*` store builder (`basalt-ui/state`, `basalt-ui/router-tanstack`) is untouched.
|
|
443
|
+
|
|
444
|
+
### Shell — region seams, and what moved with them
|
|
445
|
+
|
|
446
|
+
**Every `AppShell` region now ends in a real, themed 1px `--vx-divider` line on its Main-facing
|
|
447
|
+
edge, with no opt-out** (`docs/DESIGN-SPEC.md` §5 "Region seams", §8 inversion #12): sidebar|main
|
|
448
|
+
(full height, under `layout="alt"` it owns the top-left corner), header|main (main column only),
|
|
449
|
+
main|aside (full height, absent when the aside is unclaimed), main|mobile-nav (below `sm`). Mantine
|
|
450
|
+
draws all four itself through `[data-with-border]`; the colour is one theme var,
|
|
451
|
+
`AppShell.extend({ vars: () => ({ root: { '--app-shell-border-color': 'var(--vx-divider)' } }) })`.
|
|
452
|
+
The aside's shell-form header also carries its own `border-bottom: 1px solid var(--vx-divider)`, so
|
|
453
|
+
the top belt's seam closes across the panel instead of dead-ending at the aside column.
|
|
454
|
+
**Delete any hand-drawn twin**: a `border-left` on your own aside-shaped panel, a `border-bottom`
|
|
455
|
+
under `PageBar` via `className`, a `withBorder` or a `--app-shell-border-color` override on your own
|
|
456
|
+
`AppShell` sections — the theme only pins the COLOUR; `withBorder` still adds or removes the edge
|
|
457
|
+
per section (Mantine gates the border CSS on `[data-with-border]`), so a leftover `withBorder={false}`
|
|
458
|
+
still suppresses the seam and must be deleted to get it, and a leftover `withBorder={true}` is
|
|
459
|
+
redundant (Mantine's own default).
|
|
460
|
+
|
|
461
|
+
- **`--vx-divider` moved.** Light is now `rgba(<derived ink>, 0.09)` (was
|
|
462
|
+
`color-mix(in srgb, #e5e5e5 65%, transparent)`) — visibly darker on light, tracks a non-default
|
|
463
|
+
`neutral`/`lightLevel` where the old hex did not, and never flips polarity at `lightLevel <= -3`
|
|
464
|
+
the way the fixed hex did. Dark moved too: `color-mix(in srgb, #ffffff 6%, transparent)` →
|
|
465
|
+
`rgba(255, 255, 255, 0.08)`.
|
|
466
|
+
- **The header's horizontal inset moved from `md` to `sm`**, so the breadcrumb's left edge and the
|
|
467
|
+
global actions' right edge land on the card column's edges. The sidebar brand row and the aside's
|
|
468
|
+
header now sit at the SAME `appShellHeaderHeight` band, so their centrelines meet the header's
|
|
469
|
+
across the seams. `SPACE_STEP.sidebarBrandInsetTop` / `--vx-space-sidebar-brand-inset-top` are
|
|
470
|
+
deleted with no replacement — the row IS the band now, not an inset inside it.
|
|
471
|
+
`PageAside`'s title renders the head-font `--vx-text-md`/550/ink title treatment, not the old mono
|
|
472
|
+
micro-label.
|
|
473
|
+
- **[S2] `PageBar` row 2 below `sm`** is two declared lines — the tabs, then the pill row — instead
|
|
474
|
+
of one overflowing `nowrap` line. `--basalt-page-bar-h` grows to match, and the `className` JSDoc
|
|
475
|
+
no longer suggests drawing a hairline under the bar.
|
|
476
|
+
- **[S3] `DeltaBadge.polarity` and `deltaPolarity`** on `WidgetHeader`/`StatCard`/`ChartCard` —
|
|
477
|
+
`'up-good'` (default, today's tone), `'up-bad'`, `'neutral'`. And `WidgetHeader tier="group"` — a
|
|
478
|
+
`Section` mounted inside `PageAside` now resolves it automatically and renders a mono micro-label
|
|
479
|
+
`h3` with a zero-gap row body; outside an aside nothing changes.
|
|
480
|
+
- **[S4] `AxisConfig.scale: 'log'`** on `CartesianChart` — 1-2-5 mantissa ticks, `autoMinCeil`
|
|
481
|
+
ignored on a log axis. Honoured by every kind whose domain isn't anchored at zero (`MultiLine`,
|
|
482
|
+
`ZonedLine`, un-stacked `Bars`); `StackedArea` and stacked `Bars` install a domain function with a
|
|
483
|
+
hard `0` floor and their marks anchor at the baseline, so a log scale on either yields `NaN`
|
|
484
|
+
geometry — don't opt in there. Additive; omitted stays linear.
|
|
485
|
+
|
|
486
|
+
### Stores — the `custom` flag, patched writes, lazy fallbacks, derived windows
|
|
487
|
+
|
|
488
|
+
**Additive, except one type that got narrower on purpose.** `field.range({ presets, fallback })`
|
|
489
|
+
written INLINE inside `createSearchStore({ fields })` used to infer `custom` as `boolean` — the
|
|
490
|
+
contextual `AnyField` return type won over the argument — so every value and search type carried a
|
|
491
|
+
`'custom'` preset the field itself rejects at runtime, and `RangeFilter field={…}` needed a cast or
|
|
492
|
+
an explicit `custom: false`. `field.range` is now three overloads: an omitted or `false` flag is
|
|
493
|
+
`false`, a literal `true` is `true`, a value typed `boolean` stays widened.
|
|
494
|
+
|
|
495
|
+
- **Delete the workaround, not the field.** An explicit `custom: false` still works (same
|
|
496
|
+
overload); a cast on `<RangeFilter field={…} />` can go, and `RangeFilterProps<P, C>` is generic
|
|
497
|
+
over the flag so a preset-only handle binds directly.
|
|
498
|
+
- **What can newly type-error:** code that read `'custom'` out of a range whose field never declared
|
|
499
|
+
it — `if (search.range === 'custom')` on a preset-only field, or a `RangeValue<P | 'custom'>`
|
|
500
|
+
annotation over one. That branch was always dead at runtime; the type just stopped pretending.
|
|
501
|
+
- **…and one more, in a consumer's own WRAPPER.** A prop typed `FieldHandle<RangeField<P>>` — `C`
|
|
502
|
+
defaulting to `boolean` — no longer accepts a handle from a `field.range` without `custom: true`,
|
|
503
|
+
because that handle's setter is now `RangeValue<P>`-typed and a setter is contravariant. Pin
|
|
504
|
+
`FieldHandle<RangeField<P, false>>` for the preset-only shape, `RangeField<P, true>` for a
|
|
505
|
+
picker-backed one, or make the wrapper generic over the flag
|
|
506
|
+
(`<P extends string, C extends boolean>` + `FieldHandle<RangeField<P, C>>`), which is what
|
|
507
|
+
`RangeFilter` does. An existing `as FieldHandle<RangeField<P>>` cast keeps compiling.
|
|
508
|
+
|
|
509
|
+
**`toWindow()` resolves derived presets.** `field.range({ window: { '3m': (now) => ({ from, to }) } })`
|
|
510
|
+
makes `toWindow({ preset: '3m' })` return `{ from, to }` (ISO dates, resolved at call time with the
|
|
511
|
+
current `Date`) while `3m` stays one preset in the URL. A preset with no resolver keeps
|
|
512
|
+
`{ window: preset }`, in the same field — which is what retires the last hand-rolled
|
|
513
|
+
`presetToParams` a consumer kept beside the store for `3m` / `6m` / `1y` / `ytd`.
|
|
514
|
+
|
|
515
|
+
**The resolved presets are gone from the return TYPE too**, which is the half that decides whether
|
|
516
|
+
the switch is deleted or the cast just moves: the field now carries its resolver keys (`RangeField`'s
|
|
517
|
+
fifth type parameter, inferred from `window`), and `toWindow` returns
|
|
518
|
+
`{ window: Exclude<P, W> } | { from; to }`. A `resolveWindow` whose target is
|
|
519
|
+
`{ window: '7d' | '30d' | '90d' | 'all' } | { from; to }` becomes a one-line delegation with no
|
|
520
|
+
`as`. One guard survives on a `custom: true` field: a `'custom'` preset that arrives WITHOUT dates
|
|
521
|
+
resolves to `{ window: 'custom' }`, so `'custom'` stays in the union by construction.
|
|
522
|
+
|
|
523
|
+
**A field setter takes an optional second argument.** `set(next, { patch })` merges extra search
|
|
524
|
+
params into the SAME navigate — URL lane only, for keys the store does not own (`{ patch: {
|
|
525
|
+
detailDate: undefined } }` clears a sibling param the page put there). The field's own params always
|
|
526
|
+
win over the patch, so it cannot corrupt the value being set. A local/memory-lane write has no
|
|
527
|
+
navigate to merge into and ignores it.
|
|
528
|
+
|
|
529
|
+
Two limits are now enforced rather than documented. A patch key **another field of the same store
|
|
530
|
+
owns** is refused — it would reach the URL while the store's own write path never touched the mirror,
|
|
531
|
+
so the next paramless visit and every `linkSearch` link resolve the OLD value: `createSearchStore`
|
|
532
|
+
throws in dev, and in production keeps the write and logs it once. Write that field through its own
|
|
533
|
+
setter instead. And a patched write **from a route that does not validate the field** persists (A1)
|
|
534
|
+
but drops the patch with it — there is no navigate to merge into — which now warns once per field in
|
|
535
|
+
dev instead of doing nothing.
|
|
536
|
+
|
|
537
|
+
**A fallback may be a thunk.** `field.*({ fallback: () => T })` (every kind — `field.number`'s codec
|
|
538
|
+
froze its thunk at store definition in the first cut of this minor and does not now) is resolved at
|
|
539
|
+
READ time and re-resolved while nothing is written, and is never persisted on its own — a write
|
|
540
|
+
stores what the control produced, as before. **Local and memory lanes only:** `createSearchStore` now
|
|
541
|
+
THROWS at definition for a thunk on a URL-lane field, because `validateSearch` would evaluate it on
|
|
542
|
+
every navigation and pin the result into the URL. Move the field off the URL lane (`{ url: false }`,
|
|
543
|
+
or `createLocalStore`) or pass a value.
|
|
544
|
+
|
|
545
|
+
**`FieldHandle` gained `clear()`, and a reset now UNSETS.** `useReset()` used to write
|
|
546
|
+
`entry.codec.fallback` into the mirror for every persisted field, and every control's reset called
|
|
547
|
+
`setValue(field.fallback)` — both of which pin a RESOLVED thunk: pressing `Reset all` over
|
|
548
|
+
`field.string({ fallback: () => todayIso() }, { url: false })` stored today's date, so tomorrow the
|
|
549
|
+
field read a value nobody chose and counted as active in `Filters (n)`. Both paths now delete the
|
|
550
|
+
key instead (the memory lane always did), and `clear()` is the per-field door: the persist lane
|
|
551
|
+
deletes its key, the memory lane drops its value, the URL lane navigates back to the fallback
|
|
552
|
+
params.
|
|
553
|
+
|
|
554
|
+
Nothing to change at a call site — every shipped control's reset calls it. A consumer that
|
|
555
|
+
hand-rolled a reset should swap `setValue(field.fallback)` for `field.clear()`; a hand-built
|
|
556
|
+
`FieldHandle` (a facet column, a test double) must add the member, which is the one type-error this
|
|
557
|
+
adds.
|
|
558
|
+
|
|
559
|
+
**`createPersistedState` notifies across instances (bug fix).** Two instances over one key — a
|
|
560
|
+
page's store and a widget's own state naming the same key, or a store re-exported from two modules —
|
|
561
|
+
kept per-instance listener sets, so a write through one left the other's components rendering the
|
|
562
|
+
stale value **in the same tab** while the cross-tab `storage` path worked. Subscribers are now
|
|
563
|
+
registered per storage key. No API change; if you were re-rendering something by hand to work around
|
|
564
|
+
this, delete it.
|
|
565
|
+
|
|
566
|
+
**`RangeFilter` warns once in dev** when the field declares `custom: true` and no `customPicker` was
|
|
567
|
+
injected: the custom window is then unreachable (no popover picker, no `Custom range…` row in the
|
|
568
|
+
sheet). Preset-only remains a legal configuration — the picker is injected precisely because
|
|
569
|
+
`@mantine/dates` may be absent — so this is a warning, not a type error.
|
|
570
|
+
|
|
571
|
+
### Controls — `NumberFilter`, the `field.number` lane
|
|
572
|
+
|
|
573
|
+
**One export added, nothing removed.** `field.number` has existed since the store landed and had no
|
|
574
|
+
control, so both consumers that needed one wrote around it in opposite directions: linewatch kept a
|
|
575
|
+
raw `SegmentedControl` over `minDuration` (a `control-outside-home` warn, law C1), and argo widened
|
|
576
|
+
`nights` into a string enum — which puts `'3'` in the URL and makes every downstream comparison a
|
|
577
|
+
parse.
|
|
578
|
+
|
|
579
|
+
```tsx
|
|
580
|
+
import { NumberFilter } from 'basalt-ui/controls'
|
|
581
|
+
|
|
582
|
+
// A preset set — a pill plus a radio list, the same body every enum filter renders.
|
|
583
|
+
<NumberFilter field={booking.field.nights} label="Nights"
|
|
584
|
+
options={[{ value: 1, label: '1 night' }, { value: 7, label: 'A week' }]} />
|
|
585
|
+
|
|
586
|
+
// No `options` → a pill whose popover holds a `ctl` NumberInput; the sheet renders it full-width.
|
|
587
|
+
<NumberFilter field={lines.field.minDuration} label="Min duration" step={30} />
|
|
588
|
+
```
|
|
589
|
+
|
|
590
|
+
Three properties worth knowing before porting a call site:
|
|
591
|
+
|
|
592
|
+
- **The URL keeps a NUMBER.** `options` takes `{ value: number; label: string }`, and a numeral
|
|
593
|
+
STRING there is a type error — the whole reason to stop widening a threshold into an enum.
|
|
594
|
+
- **The stepper applies on blur or Enter, never per keystroke.** A number is typed digit by digit, so
|
|
595
|
+
a live write would navigate on `4`, `42`, `420` — three loader runs for one intended threshold,
|
|
596
|
+
two of them values nobody meant. `SearchFilter` debounces; a number has an explicit commit point.
|
|
597
|
+
- **`min`/`max`/`int` come off the HANDLE, not the call site.** They are deliberately not props: the
|
|
598
|
+
field is what validates the URL, and a second copy at the call site is a second answer to the same
|
|
599
|
+
question. The number handle republishes all three (see § Stores — the number handle below), so the
|
|
600
|
+
stepper stops at the field's limit and an `int` field refuses decimals outright. A TYPED value is
|
|
601
|
+
clamped to those bounds when it commits, so the box reads what the store holds even when the store
|
|
602
|
+
does not move — a second out-of-range `9999` against `max: 600` over a stored `600` writes nothing,
|
|
603
|
+
and the readout still corrects itself to `600`. The codec's clamp stays the backstop for a value
|
|
604
|
+
that never came through the box at all — a hand-typed URL, a stale deep link.
|
|
605
|
+
|
|
606
|
+
### Stores — the number handle republishes its bounds
|
|
607
|
+
|
|
608
|
+
**Three members added to `FieldHandle<NumberField>`, nothing removed.** `min`, `max` and `int` now
|
|
609
|
+
sit on the handle, filled from the field declaration (`NumberHandleExtras`, the shape
|
|
610
|
+
`RangeHandleExtras`/`toWindow` already had). A control never sees the field descriptor — only the
|
|
611
|
+
handle — so before this the only way one could learn its own limits was for the call site to pass
|
|
612
|
+
them a second time.
|
|
613
|
+
|
|
614
|
+
```ts
|
|
615
|
+
const nights = store.field.nights // field.number({ fallback: 2, min: 1, max: 14, int: true })
|
|
616
|
+
nights.min // 1 — `undefined` when the field declared none
|
|
617
|
+
nights.max // 14
|
|
618
|
+
nights.int // true — `false`, never `undefined`, on a number handle
|
|
619
|
+
```
|
|
620
|
+
|
|
621
|
+
Non-number handles carry all three as `undefined`, the same way `toWindow` is `undefined` off a
|
|
622
|
+
range handle. That is a type-level fact, not just a runtime one, and it matters for one collision in
|
|
623
|
+
particular: `StringField` has its own `max`, which is NOT republished — a string handle's `max` is
|
|
624
|
+
`undefined`.
|
|
625
|
+
|
|
626
|
+
Nothing about the clamp changed. The codec has always clamped a number to the declared bounds on
|
|
627
|
+
write, and still does; the handle is a readout of that law, which is what lets `NumberFilter` bound
|
|
628
|
+
its stepper instead of letting the user watch the correction happen.
|
|
629
|
+
|
|
630
|
+
### `StatCard` — `unit`, `breakdown` and the delta's own format
|
|
631
|
+
|
|
632
|
+
**Four props added, nothing removed or renamed; every one defaults to today's rendering when
|
|
633
|
+
omitted.**
|
|
634
|
+
`value` is a pre-formatted `string`, so a card had exactly one text channel under the hero row
|
|
635
|
+
(`subtitle`) and three consumers wanting a unit AND a basis AND a split hand-rolled the card instead
|
|
636
|
+
— which is the fork `shadow-basalt-export` reports as a `HeroCard`.
|
|
637
|
+
|
|
638
|
+
| Prop | Type | Renders |
|
|
639
|
+
| ------------- | ------------------------------------------------------------------ | ----------------------------------------------------------------------------- |
|
|
640
|
+
| `unit` | `string` | after the value on the hero row — muted, mono, `--vx-text-sm` |
|
|
641
|
+
| `breakdown` | `readonly { label: string; value: string; tone?: StatCardTone }[]` | compact rows under the hero, one `controlHeightTag` line each |
|
|
642
|
+
| `deltaFormat` | `(delta: number) => string` | the delta chip's label. Default unchanged: `Math.abs(delta).toFixed(1) + '%'` |
|
|
643
|
+
| `deltaGlyph` | `boolean` | the chip's ▲/▼. Default `true`; a zero delta never shows one |
|
|
644
|
+
|
|
645
|
+
`unit` is forwarded to `WidgetHeader`, which gained the same prop, so `ChartCard` and `Section`
|
|
646
|
+
headers get it too. It is NOT the basis: `412` + `TSS` is the pair, and `7-day rolling` is still
|
|
647
|
+
`subtitle`. A thousands separator, a currency symbol or a `%` still belong in `value`.
|
|
648
|
+
|
|
649
|
+
`breakdown` draws **no hairlines** — §2.1 puts a horizontal rule between OPTION rows and nowhere
|
|
650
|
+
else, and `theme/divider-law.test.ts` inventories every one basalt draws. The rows separate by
|
|
651
|
+
weight (muted label, mono ink value) instead. Keep it to two or three: past that the card is a
|
|
652
|
+
table, and a table is `BasaltDataTable` in a `Section`. A row's `tone` reads the same per-scheme
|
|
653
|
+
`--vx-status-*` solid the card's own rail does, and omitting it is untinted, never `'good'`.
|
|
654
|
+
|
|
655
|
+
`deltaFormat` exists because **a delta is not always a percentage, and `StatCard` claimed it was**:
|
|
656
|
+
`delta={0.3}` on a pace or speed card rendered `▲0.3%`, a wrong unit on a KPI — worse than no chip —
|
|
657
|
+
so the one consumer that needed it kept the card hand-rolled and took the `shadow-basalt-export` warn
|
|
658
|
+
instead. `DeltaBadge` had `format` all along; neither `WidgetHeader` nor `StatCard` forwarded it. Both now do.
|
|
659
|
+
`ChartCard`/`Section` are unchanged: each declares its own header props and forwards them one by
|
|
660
|
+
one, so a delta-bearing `ChartCard` or `Section` still prints the percentage — ask if you need it
|
|
661
|
+
there.
|
|
662
|
+
|
|
663
|
+
```tsx
|
|
664
|
+
// A percentage, unchanged — no prop, no move.
|
|
665
|
+
<StatCard title="Volume" value="1,204" delta={4.2} deltaPeriod="WoW" />
|
|
666
|
+
|
|
667
|
+
// An absolute delta. The formatter gets the SIGNED number, so it may print the sign itself;
|
|
668
|
+
// `deltaGlyph={false}` then stops the ▼ saying the same thing twice. No `deltaLabel` prop exists —
|
|
669
|
+
// the function IS the escape hatch, and `delta` stays the number that drives the tone.
|
|
670
|
+
<StatCard title="Pace" value="5:31" unit="/km" delta={-12} deltaGlyph={false}
|
|
671
|
+
deltaFormat={(s) => `${s < 0 ? '−' : '+'}0:${String(Math.abs(s)).padStart(2, '0')} /km`} />
|
|
672
|
+
```
|
|
673
|
+
|
|
674
|
+
### Guards — the 1.27.0 promotions, one narrowing and one new exemption
|
|
675
|
+
|
|
676
|
+
**Five plugin rules and one guard kind became `error` in the shipped preset.** Their
|
|
677
|
+
`PLUGIN_RULE_GRACE` / `GRACE_PERIOD_KINDS` entries are deleted, which IS the promotion (C16). A
|
|
678
|
+
`theme-allow` written against any of them still works unchanged; only the severity of an UNWAIVED
|
|
679
|
+
finding moves.
|
|
680
|
+
|
|
681
|
+
| Promoted to `error` | Waiver, if the finding is deliberate |
|
|
682
|
+
| -------------------------------- | --------------------------------------------------------------------------------------------- |
|
|
683
|
+
| `basalt/control-size-literal` | `theme-allow control-size-literal — <why>` above the node, or `theme-allow-file` for the file |
|
|
684
|
+
| `basalt/in-body-page-title` | `theme-allow in-body-page-title — <why>` — ONE id, so it waives the guard kind's lane too |
|
|
685
|
+
| `in-body-page-title` (kind) | the same annotation; the two lanes share the id by construction |
|
|
686
|
+
| `basalt/responsive-twin` | `theme-allow responsive-twin — <why>`; the real fix is deleting one mount |
|
|
687
|
+
| `basalt/search-literal-link` | `theme-allow search-literal-link — <why>`; the real fix is `search: <store>.linkSearch` |
|
|
688
|
+
| `basalt/use-search-from-literal` | `theme-allow use-search-from-literal — <why>`; the real fix is the param as a prop |
|
|
689
|
+
|
|
690
|
+
The commonest in-body-title case that is NOT a defect: **a shell-less surface naming itself** — an
|
|
691
|
+
auth gate, an error boundary, a print view. There is no breadcrumb to carry the name, so write
|
|
692
|
+
`theme-allow in-body-page-title — shell-less surface`.
|
|
693
|
+
|
|
694
|
+
**`control-size-literal` also gained one exemption in the same minor, and it removes a waiver rather
|
|
695
|
+
than adding one: a slot owned by `ChartCard` no longer reports.** `ChartCard` lives inside the
|
|
696
|
+
Mantine-free chart layer, so its `actions` slot writes `data-basalt-tier` by hand and cannot mount
|
|
697
|
+
the tier theme at all — a `Switch` there with no `size` renders at Mantine's default, not at `ctl`.
|
|
698
|
+
The rule's message ("the HOME sets the tier, drop the prop") was simply false in that one slot, and
|
|
699
|
+
because the rule fires on the `size` ATTRIBUTE it could not tell a correct `size="ctl"` from the
|
|
700
|
+
`size="xs"` it exists to catch. Every other home still reports, and the owner test reads the
|
|
701
|
+
IMPORTED name so `ChartCard as Card` is exempt too. `hand-rolled-filter` is deliberately NOT
|
|
702
|
+
exempted there: a raw `Select` in `ChartCard.actions` is still a filter that should take a `field`.
|
|
703
|
+
A HOISTED binding is exempt only when EVERY basalt home it was handed to is `ChartCard` — one
|
|
704
|
+
`const acts = <Button size="xs"/>` given to both `<ChartCard actions>` and `<Section actions>` still
|
|
705
|
+
renders in a tiered slot, and keying the exemption on a single owner made the verdict depend on which
|
|
706
|
+
attribute came later in the file.
|
|
707
|
+
|
|
708
|
+
**`basalt/control-outside-home` and `raw-selection-control` did NOT promote. They are re-dated to
|
|
709
|
+
1.30.0, and the reason is a measurement rather than caution:** the wave-7 consumer run left 9 warns
|
|
710
|
+
in argo, and every one is a control inside a modal/form module whose `<Modal>` is rendered by the
|
|
711
|
+
PARENT route — law C1's cross-file case, which is advisory by declaration because no scan of one
|
|
712
|
+
file can see it. Both lanes now exempt a file whose BASENAME matches
|
|
713
|
+
`*-{modal,drawer,popover,panel,form}.tsx`, which is the convention those nine already follow.
|
|
714
|
+
Outside the convention, an overlay body declares itself:
|
|
715
|
+
`theme-allow-file control-outside-home — overlay`. The trade is stated plainly: a whole file goes
|
|
716
|
+
unscanned on a naming convention, so a `Select` that genuinely belongs in a page bar goes unreported
|
|
717
|
+
if it lives in `filters-panel.tsx` — the same bargain the `@mantine/form` exemption already buys,
|
|
718
|
+
and a smaller one than promoting a rule with 9 known false positives.
|
|
719
|
+
|
|
720
|
+
**`basalt/shadow-basalt-export` narrowed, and it stays a permanent advisory `warn`.** An ALIAS hit is
|
|
721
|
+
now skipped when the file imports the basalt export it renames **and REFERENCES that binding as a
|
|
722
|
+
value**: a `HeroCard` that composes `StatCard` is a wrapper, not a fork, and it was already following
|
|
723
|
+
the advice the message gives. Composition, not import — three shapes stay reported, and they are the
|
|
724
|
+
ones a fork actually writes: a type-only `import type { StatCard }` (or an inline `type` specifier)
|
|
725
|
+
feeding `ComponentProps<typeof StatCard>`, a VALUE import used only in a type position, and a dead
|
|
726
|
+
import left behind after the body was re-rolled. None of them render anything. A reference does not
|
|
727
|
+
have to be a JSX tag — `component={StatCard}` and `createElement(StatCard)` compose it too. The
|
|
728
|
+
provenance test reads the IMPORTED name, so `import { StatCard as Base }` counts. The name-COLLISION
|
|
729
|
+
half is deliberately NOT exempted the same way — a local `StatCard` beside an
|
|
730
|
+
`import { StatCard as Base }` kept the name AND a piece of the original, which is the fork shape this
|
|
731
|
+
rule most wants to see.
|
|
732
|
+
|
|
733
|
+
### `basalt-ui/data` — a typed facet id, and a required `getItemKey`
|
|
734
|
+
|
|
735
|
+
**`BasaltDataTable`: a mistyped `facets[].columnId` used to render no pill, silently — `if
|
|
736
|
+
(!column) return null`.** It now throws in dev, naming the id and every known column id
|
|
737
|
+
(`facet columnId "…" matches no column`); production still degrades to no pill for that one facet.
|
|
738
|
+
`DataTableFacet` also gained a type parameter — `DataTableFacet<T = unknown>` — so `columnId` is
|
|
739
|
+
typed off the row shape wherever TanStack's `accessor`/manual `id` inference allows it
|
|
740
|
+
(`Extract<keyof T, string> | (string & {})`); the default keeps a bare `DataTableFacet[]`
|
|
741
|
+
compiling unchanged. `BasaltDataTableProps.facets` is now `DataTableFacet<T>[]`, and
|
|
742
|
+
`initialColumnPinning` moved from TanStack's own `ColumnPinningState` to a new, `T`-derived
|
|
743
|
+
`DataTableColumnPinning<T>` (structurally assignable to `ColumnPinningState`, so no cast is
|
|
744
|
+
needed at either end). Both are additive for existing call sites — an id that was already a real
|
|
745
|
+
column keeps compiling and rendering exactly as before.
|
|
746
|
+
|
|
747
|
+
**`BasaltVirtualList.getItemKey` is now required.** The index fallback hid stale rows across a
|
|
748
|
+
mutation: an insert/delete shifts every index below it, so the OLD item kept rendering at each
|
|
749
|
+
shifted index until an unrelated re-render happened to catch it up — in the one component whose
|
|
750
|
+
job is a long mutable list. Pass a real per-item key (`(item) => item.id`); there is no
|
|
751
|
+
replacement for the index fallback.
|
|
752
|
+
|
|
753
|
+
**`BasaltVirtualList` gained a ref.** `ref?: Ref<BasaltVirtualListHandle>` exposes
|
|
754
|
+
`scrollToIndex`/`scrollToOffset`/`scrollToEnd` (delegating to the internal
|
|
755
|
+
`@tanstack/react-virtual` instance) plus `getVirtualizer()` as the full escape hatch — mirrors
|
|
756
|
+
`./data/table`'s `useReactTable` re-export as the table's own. Additive; omitting `ref` changes
|
|
757
|
+
nothing.
|
|
758
|
+
|
|
759
|
+
### `basalt-ui/commands` — `BasaltOverlays` no longer WRAPS your app in `ModalsProvider`
|
|
760
|
+
|
|
761
|
+
**Same props, same imperative API, one structural change: every layer — `ModalsProvider`
|
|
762
|
+
included — now renders as a SIBLING of `children` instead of an ancestor.** The old shape put the
|
|
763
|
+
whole app under a `React.lazy` Suspense boundary (`<Suspense fallback={<>{app}</>}>
|
|
764
|
+
<LazyModalsProvider>{app}</LazyModalsProvider></Suspense>`), and `React.lazy` suspends on its first
|
|
765
|
+
render even when the module is already warm. Two consequences, both real: the app's FIRST COMMIT was
|
|
766
|
+
deferred past a microtask — long enough for TanStack Router's async `loadMatches` to `setState` onto
|
|
767
|
+
a not-yet-mounted fiber ("Can't perform a React state update on a component that hasn't mounted
|
|
768
|
+
yet", once per full page load) — and the app tree mounted TWICE, once inside the fallback and once
|
|
769
|
+
resolved, so every effect in the app ran twice on boot.
|
|
770
|
+
|
|
771
|
+
Nothing to change for the overlay APIs. `modals.open` / `modals.openConfirmModal` (and so basalt's
|
|
772
|
+
own `overlays.open` / `overlays.close`) go through `@mantine/modals`' window CustomEvent bus, which
|
|
773
|
+
`ModalsProvider` subscribes to — being inside it was never a requirement, and the provider renders
|
|
774
|
+
its own managed `Modal` regardless of where it sits.
|
|
775
|
+
|
|
776
|
+
**The one thing a sibling cannot serve is React CONTEXT**: `useModals()` from `@mantine/modals`
|
|
777
|
+
called inside your app now throws its "was called outside of context" error. If you use it (or
|
|
778
|
+
`openContextModal`, which needs the provider's `modals` map that `BasaltOverlays` never passed
|
|
779
|
+
anyway), mount your own provider and turn basalt's off — two providers would both answer the event
|
|
780
|
+
bus and open every modal twice:
|
|
781
|
+
|
|
782
|
+
```tsx
|
|
783
|
+
<BasaltOverlays modals={false}>
|
|
784
|
+
<ModalsProvider modals={CONTEXT_MODALS}>
|
|
785
|
+
<App />
|
|
786
|
+
</ModalsProvider>
|
|
787
|
+
</BasaltOverlays>
|
|
788
|
+
```
|
|
789
|
+
|
|
790
|
+
### `basalt-ui/controls` — the mobile `Filters (n)` sheet renders panel rows, not its own list
|
|
791
|
+
|
|
792
|
+
**The sheet's `SheetOptionList` (44px rows, a hairline between them, one per option) is gone.**
|
|
793
|
+
`useFilterSurface() === 'sheet'` now resolves to the SAME `PanelRow`/`PanelChoice`/facet-list body
|
|
794
|
+
`'panel'` already renders (`docs/CONTROLS-SPEC.md` §3: "sheet = panel rows inside a Drawer") — label
|
|
795
|
+
above, full-width control below, folding past `PANEL_TRACK_MAX` (3, a `Select`) or `max` (a
|
|
796
|
+
`MultiSelectFilter`'s `Show N more`) the same way the aside already did. A set with many options no
|
|
797
|
+
longer grows the sheet to a full column of option rows. `RangeFilter`'s sheet form is the panel's one
|
|
798
|
+
`Select` (presets plus a `Custom range…` row revealing the injected picker) instead of a
|
|
799
|
+
`SheetOptionList` with the picker behind a separate disclosure row.
|
|
800
|
+
|
|
801
|
+
Also fixed in the same pass: a `fullWidth` `SegmentedControl` (`PanelChoice`'s ≤3-option form, and
|
|
802
|
+
`ViewTabs`) now splits its options EVENLY — Mantine's own `.control` carries no `min-width`
|
|
803
|
+
override, so the initial `auto` floored each option at its content width and a `fullWidth` track
|
|
804
|
+
split unevenly; a long label now ellipsizes inside its equal share instead of forcing the column
|
|
805
|
+
wide. The active segment's fill is a second ink-mix step
|
|
806
|
+
(`color-mix(in srgb, var(--vx-ink) 12%, var(--vx-surface-panel))`), not a flat `--vx-surface-panel`,
|
|
807
|
+
so it stays visible against its own track when the whole control sits on a panel-coloured surface (a
|
|
808
|
+
`PanelRow`), where a flat panel fill read as barely-there next to the 6%-tinted track around it.
|
|
809
|
+
|
|
810
|
+
| Removed | Replacement | Note |
|
|
811
|
+
| ---------------------------------------------------------------------------------------------------------------------------- | ----------------------------------------------------------- | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
|
|
812
|
+
| `SheetOptionList`, `SheetField`, `SheetDisclosure` (`basalt-ui/controls`) | `PanelRow` / `PanelChoice` (already exported) | Were never part of the public `./controls` barrel — internal to `filter-sheet.tsx` — so this only breaks a consumer test that imported them directly out of `basalt-ui/controls/filter-sheet` or hooked a `role="radio"` `<fieldset>` DOM shape inside the sheet (now a `PanelChoice` `SegmentedControl`, `role="radiogroup"`, or a `Select`). |
|
|
813
|
+
| `SheetRow`, `sheetRowClassNames` (`basalt-ui/controls`) | none | Also internal-only. `ToggleFilter`'s sheet form is now a `PanelRow` whose `Switch` rides the label line, the same shape the panel surface always used. |
|
|
814
|
+
| `.sheetOption` / `.sheetList` / `.sheetField` / `.sheetRow` / `.sheetDisclosureBody` / `.sheetLabel` (`controls.module.css`) | `panel-row.module.css`'s `.row`/`.head`/`.control`/`.label` | CSS-module classes were never a public contract; named for a consumer that vendored a copy of the sheet's old CSS. |
|
|
815
|
+
|
|
816
|
+
### The shell scrollport — Main scrolls, not the window
|
|
817
|
+
|
|
818
|
+
`BasaltShell` dropped Mantine's `layout="alt"` (the header now spans the full viewport width, above
|
|
819
|
+
the sidebar and the aside, instead of being inset beside the sidebar) and gave `AppShell.Main` a
|
|
820
|
+
bounded height with `overflow: auto`. Main is therefore THE scrolling element: the document's
|
|
821
|
+
`scrollHeight` equals the viewport height, the browser scrollbar sits on Main's own right edge
|
|
822
|
+
(inside the aside, where the content is) instead of at the far edge of the window, and
|
|
823
|
+
`window.scrollY` is pinned at 0.
|
|
824
|
+
|
|
825
|
+
Main carries two handles: `data-basalt-scrollport` (basalt's own, and what `scrollParentOf` looks
|
|
826
|
+
for) and `data-scroll-restoration-id="basalt-main"` (the attribute `@tanstack/router-core`'s scroll
|
|
827
|
+
restoration reads, so a router-driven app restores this element rather than the window).
|
|
828
|
+
|
|
829
|
+
What to change in a consumer:
|
|
830
|
+
|
|
831
|
+
| If your app… | Do this |
|
|
832
|
+
| ------------------------------------------------------------------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
|
|
833
|
+
| reads `window.scrollY` / listens for `scroll` on `window` | `const port = scrollParentOf(el)` and read `port.scrollTop` / listen on `port` — `null` still means the window, so shell-less code is unchanged |
|
|
834
|
+
| scrolls with `window.scrollTo` / `document.scrollingElement` | target `document.querySelector('[data-basalt-scrollport]')` first, with the document as the fallback |
|
|
835
|
+
| uses window-based scroll restoration | point it at `[data-scroll-restoration-id="basalt-main"]`; TanStack Router picks it up with no config |
|
|
836
|
+
| overrides `--vx-space-sticky-header-clearance` | the token NO LONGER includes the app-shell header height — it is `anchors.stackMd` (12px at level 0), pure breathing room, because BOTH the header and the page-bar band are regions outside the scrollport |
|
|
837
|
+
| passes `BasaltDataTable stickyHeaderOffset` inside a shell | drop it entirely. Nothing overhangs the scrollport any more, so a sticky table head wants `top: 0`, which is the default |
|
|
838
|
+
| computes a viewport-filling body from `--basalt-page-bar-h` | inside a shell that is just `100%` now — the band is outside Main rather than scrolling with it. The var is still published |
|
|
839
|
+
| passes `mobileNav.getScrollElement` only to reach the page scroller | you can drop it — the default resolves the scrollport now |
|
|
840
|
+
|
|
841
|
+
Three rendering changes ride along, all visible without any code change:
|
|
842
|
+
|
|
843
|
+
- **The brand moved out of the sidebar and into the header.** The header spans the full viewport
|
|
844
|
+
width now, so the sidebar's `appShellHeaderHeight` brand row painted as a SECOND 48px band under
|
|
845
|
+
the header seam. It is the header's leading zone instead — `--app-shell-navbar-offset` wide, so it
|
|
846
|
+
still tracks the rail collapse and still ends on the sidebar\|main seam — and the sidebar column
|
|
847
|
+
starts at `SidebarSearch`. `brand`, `brand.menu` and the collapse toggle are unchanged; only the
|
|
848
|
+
markup's home moved. Two consequences for a consumer mounting `AppSidebar` DIRECTLY (rather than
|
|
849
|
+
through `BasaltShell`, which is the supported path): it no longer paints a brand row, and its
|
|
850
|
+
`onToggleCollapse` prop is no longer read there — `BasaltShell` feeds it to the header instead.
|
|
851
|
+
- **`PageBar` row 2 is a shell-owned BAND**, not a row in the page: it portals into an outlet
|
|
852
|
+
`BasaltShell` renders between the header and the scrollport, exactly as row 1 portals into the
|
|
853
|
+
header. It spans Main's width, carries `--vx-surface-bg` and one `--vx-divider` hairline, and is a
|
|
854
|
+
zero-height, seam-less box on a route with no `PageBar`. It is no longer sticky and no longer
|
|
855
|
+
depends on where you wrote `<PageBar>` — nested in a `Stack` or written as Main's direct child now
|
|
856
|
+
produce identical geometry. Its padding-block tightened from `--vx-space-stack-sm` to
|
|
857
|
+
`--vx-space-stack-xs`, so the bar is 8px shorter.
|
|
858
|
+
- **`BasaltDataTable` contains itself horizontally by default.** A table with neither `maxHeight`
|
|
859
|
+
nor `minWidth` used to render a bare `<table>`, which sizes to its own min-content — a five-column
|
|
860
|
+
table measured 448px inside a 390px viewport and dragged the whole page sideways. Every table now
|
|
861
|
+
renders inside `Table.ScrollContainer type="native"` (`minWidth: 0` when you set none), so a wide
|
|
862
|
+
table scrolls inside its own card. `stickyHeader` with neither prop cannot take that container —
|
|
863
|
+
an `overflow-x` box computes `overflow-y` to `auto` and becomes the header's scrollport, and with
|
|
864
|
+
no height cap it has no scroll range, so the header would go inert — so it takes a wrapper whose
|
|
865
|
+
overflow is **measured** instead: while the table fits its container the wrapper declares no
|
|
866
|
+
overflow at all and the page-sticky header sticks exactly as before; once the table is wider the
|
|
867
|
+
wrapper flips to `overflow-x: auto`, the columns stay reachable, and the header is inert at that
|
|
868
|
+
width. The flip is a live `ResizeObserver` reading in both directions, so the wrapper goes back to
|
|
869
|
+
bare when the space returns (the window widened, the sidebar collapsed, the aside closed), and it
|
|
870
|
+
publishes `data-contained="true|false"`. The dev warning on that shape now states the trade rather
|
|
871
|
+
than a defect and points at `maxHeight` for a table that must both scroll and stick. Pinning takes
|
|
872
|
+
the same wrapper: the `overflow-x: auto` `Box` a pinned, uncapped, sticky table used to get is
|
|
873
|
+
gone, because it was the inert-header shape it was meant to avoid. **The TOOLBAR was the other
|
|
874
|
+
half of the same defect and is fixed with it**: the toolbar `Group` is the header row's flex item
|
|
875
|
+
(`CtlSlot` between them is `display: contents`) and carried `flex: 0 0 auto`, so a 220px search
|
|
876
|
+
beside a 230px facet pill row was an unshrinkable 461px box in a 302px column — `AppShell.Main`
|
|
877
|
+
measured `scrollWidth` 505 against `clientWidth` 390 at 390x844. It is now `flex: 0 1 auto` with
|
|
878
|
+
`min-width: 0`, and the search's `w={220}` became a flex BASIS (`flex: 0 1 220px`, floored at
|
|
879
|
+
`12ch`, capped at `100%`). The field still resolves to 220px wherever 220 fits and still never
|
|
880
|
+
grows with the table; below that the search and the pills wrap onto their own lines.
|
|
881
|
+
|
|
882
|
+
## 1.26.0 — the control tier, the page bar and the store
|
|
883
|
+
|
|
35
884
|
**One export removed and two deprecated — see § Stores below; two shell PROPS removed — see
|
|
36
885
|
§ Sidebar. Two other behaviour changes: the grace ledgers changed shape, and nine
|
|
37
886
|
long-stale entries (D4, `docs/archive/CONTROLS-SYNTHESIS.md`) are promoted.** C16
|
|
@@ -48,7 +897,8 @@ happened to the nine rows below.
|
|
|
48
897
|
(the table below) or moved to the new, permanent `PLUGIN_RULE_ADVISORY` ledger
|
|
49
898
|
(`shadow-basalt-export`). Both ledgers now hold only the wave-6 control guards listed under
|
|
50
899
|
§ Guards — six plugin rules and two guard kinds, each `{ since: '1.26.0', promote: '1.27.0' }` —
|
|
51
|
-
which the C16 gate
|
|
900
|
+
which the C16 gate forced to promote or be deleted at 1.27.0. Five rules and one kind promoted there;
|
|
901
|
+
the C1 pair was re-dated to 1.30.0 against a measurement (see `## Unreleased` above). A theme-allow escape written against
|
|
52
902
|
any of these still works unchanged; only the SEVERITY of an unwaived finding moves from `warn` to
|
|
53
903
|
`error`.
|
|
54
904
|
|
|
@@ -357,22 +1207,23 @@ A consumer that uses `DateRangePicker` installs `@mantine/dates` and imports
|
|
|
357
1207
|
|
|
358
1208
|
### Guards — the control rules (docs/CONTROLS-SPEC.md §6)
|
|
359
1209
|
|
|
360
|
-
**Nothing removed. Eight new oxlint rules and two new guard kinds
|
|
361
|
-
|
|
1210
|
+
**Nothing removed. Eight new oxlint rules and two new guard kinds. `Ships` below is the level as of
|
|
1211
|
+
THIS minor** — eight land `error`, and the C1 pair (`control-outside-home` and its text lane) is the
|
|
1212
|
+
only grace left, re-dated to 1.30.0 on a measurement (see § Guards — the promotions).\*\* Every one honours `theme-allow <id> — <why>` on the
|
|
362
1213
|
node and `theme-allow-file <id> — <why>` on the file, the same grammar as the rest.
|
|
363
1214
|
|
|
364
|
-
| Rule / kind | Fires on
|
|
365
|
-
| ------------------------------------ |
|
|
366
|
-
| `basalt/hand-rolled-filter` | A raw Mantine `Select`/`SegmentedControl`/… handed to a TIERED home slot (`actions`/`filters`/`tabs`/`sync`/`filtersEnd` on `PageBar`/`Section`/`WidgetHeader`/`ChartCard`/`StatCard`/`BasaltDataTable`/`SettingsSection`/`FilterSet`)
|
|
367
|
-
| `basalt/page-bar-budget` | A second `PageBar` in the SAME returned tree, >4 `actions.secondary`, >3 `Section` actions, a second filled `Button`/`ActionIcon` in one slot (outside an overlay)
|
|
368
|
-
| `basalt/control-outside-home` | The same raw control with no home at all — exempt under a settings row / overlay / composer, in an `@mantine/form` file,
|
|
369
|
-
| `basalt/control-size-literal` | `size`/`w`/`fullWidth`/`visibleFrom`/`hiddenFrom` on anything inside a home slot (the slot sets the tier)
|
|
370
|
-
| `basalt/in-body-page-title` | `<Title order={1\|2}>` outside prose/overlay context and outside a `content/` path
|
|
371
|
-
| `basalt/responsive-twin` | The same control mounted twice, one `visibleFrom="X"` and one `hiddenFrom="X"`
|
|
372
|
-
| `basalt/search-literal-link` | A `search:` object literal in a `linkOptions()` inside `defineNav()`/`navGroup()`
|
|
373
|
-
| `basalt/use-search-from-literal` | `useSearch({ from: '<route>' })`
|
|
374
|
-
| `in-body-page-title` (guard kind) | The text lane of the same law — SAME id, so one annotation waives both lanes
|
|
375
|
-
| `raw-selection-control` (guard kind) | The text lane of `control-outside-home`, approximated by a 12-line host-tag window
|
|
1215
|
+
| Rule / kind | Fires on | Ships |
|
|
1216
|
+
| ------------------------------------ | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ | ------------- |
|
|
1217
|
+
| `basalt/hand-rolled-filter` | A raw Mantine `Select`/`SegmentedControl`/… handed to a TIERED home slot (`actions`/`filters`/`tabs`/`sync`/`filtersEnd` on `PageBar`/`Section`/`WidgetHeader`/`ChartCard`/`StatCard`/`BasaltDataTable`/`SettingsSection`/`FilterSet`) | error |
|
|
1218
|
+
| `basalt/page-bar-budget` | A second `PageBar` in the SAME returned tree, >4 `actions.secondary`, >3 `Section` actions, a second filled `Button`/`ActionIcon` in one slot (outside an overlay) | error |
|
|
1219
|
+
| `basalt/control-outside-home` | The same raw control with no home at all — exempt under a settings row / overlay / composer, in an `@mantine/form` file, in a file that DEFINES a basalt control (and imports no `basalt-ui`), or in a file basenamed `*-{modal,drawer,popover,panel,form}.tsx` / `<Subject>{Modal,Drawer,Popover,Panel,Form}.tsx` | warn → 1.30.0 |
|
|
1220
|
+
| `basalt/control-size-literal` | `size`/`w`/`fullWidth`/`visibleFrom`/`hiddenFrom` on anything inside a home slot (the slot sets the tier) | **error** |
|
|
1221
|
+
| `basalt/in-body-page-title` | `<Title order={1\|2}>` outside prose/overlay context and outside a `content/` path | **error** |
|
|
1222
|
+
| `basalt/responsive-twin` | The same control mounted twice, one `visibleFrom="X"` and one `hiddenFrom="X"` | **error** |
|
|
1223
|
+
| `basalt/search-literal-link` | A `search:` object literal in a `linkOptions()` inside `defineNav()`/`navGroup()` | **error** |
|
|
1224
|
+
| `basalt/use-search-from-literal` | `useSearch({ from: '<route>' })` | **error** |
|
|
1225
|
+
| `in-body-page-title` (guard kind) | The text lane of the same law — SAME id, so one annotation waives both lanes | **error** |
|
|
1226
|
+
| `raw-selection-control` (guard kind) | The text lane of `control-outside-home`, approximated by a 12-line host-tag window, plus the same overlay-basename exemption | warn → 1.30.0 |
|
|
376
1227
|
|
|
377
1228
|
**A `SettingsRow`'s `control` is not a tiered slot, so nothing in this table fires inside one.**
|
|
378
1229
|
It is law C1's third home — the form row — and a form keeps Mantine's `md` tier
|
|
@@ -741,7 +1592,7 @@ instead of dumping help and letting the dump read like a choice.
|
|
|
741
1592
|
- **`tokens:css --check` blanks the provenance line (line 2) before comparing**, so a version bump
|
|
742
1593
|
alone no longer forces a no-op commit in a tokens-only consumer, where the gate is byte-equality.
|
|
743
1594
|
A stale provenance line is now a note on an otherwise-passing check. The `@generated` header is
|
|
744
|
-
still emitted byte-identical — the line stays, it just stops gating. **Superseded
|
|
1595
|
+
still emitted byte-identical — the line stays, it just stops gating. **Superseded at 1.26.0:
|
|
745
1596
|
blanking the WHOLE line also stopped gating the regeneration command it carries. Only the version
|
|
746
1597
|
token is neutralized now.**
|
|
747
1598
|
|
|
@@ -912,7 +1763,7 @@ icons — it is not yet **sufficient**. If you went hybrid over the 404s, droppi
|
|
|
912
1763
|
half here costs you every icon unless your `public/` matches basalt's six filenames: at this
|
|
913
1764
|
release `icons` was still `false | { dir?: string }` over those six, so an app whose icon is
|
|
914
1765
|
`favicon.svg` could pick between a manifest naming two PNGs it never builds and a manifest with no
|
|
915
|
-
`icons` member at all. The array form that fixes it is in `##
|
|
1766
|
+
`icons` member at all. The array form that fixes it is in `## 1.26.0`. The option's JSDoc said
|
|
916
1767
|
"skips the head `<link>` icons"; it now says what the option does.
|
|
917
1768
|
|
|
918
1769
|
**Two `theme-allow` comment shapes were silently broken and now work.** Plainly: this is the fourth
|
|
@@ -920,7 +1771,7 @@ hole found in this one contract in three rounds. A thirteen-shape matrix — eve
|
|
|
920
1771
|
had been SEEN to write — is pinned in both halves, `src/guard/check-source.test.ts` and
|
|
921
1772
|
`configs/oxlint-plugin.test.ts`. **The claim that followed it here, that the two parsers could
|
|
922
1773
|
therefore no longer disagree, was false when it was written**: a list of collected anecdotes cannot
|
|
923
|
-
close a contract. Three more holes were open at this release. See `##
|
|
1774
|
+
close a contract. Three more holes were open at this release. See `## 1.26.0`.
|
|
924
1775
|
|
|
925
1776
|
| Shape | What it did | Now |
|
|
926
1777
|
| --------------------------------------------- | -------------------------------------------------------------------------------------------------------------------------- | --------------------------------------- |
|
|
@@ -1207,35 +2058,43 @@ live in `configs/oxlint.json`, and since 1.20.0 their grace is tracked by `PLUGI
|
|
|
1207
2058
|
named export beside the plugin — a test asserts it against the shipped preset in both directions, so
|
|
1208
2059
|
deleting an entry forces the level flip in the same commit.
|
|
1209
2060
|
|
|
1210
|
-
| Rule | Landed | Became `error`
|
|
1211
|
-
| -------------------------------------- | ---------------- |
|
|
1212
|
-
| `mantine-shade-index` (guard kind) | 1.7.0 as `warn` | **1.11.0**
|
|
1213
|
-
| `basalt/raw-scroll-container` | ≤1.2.0 as `off` | `warn` 1.10.0 → **`error` 1.13.0**
|
|
1214
|
-
| `basalt/ai-sdk-major` | 1.10.0 as `warn` | **1.13.0**
|
|
1215
|
-
| `basalt/agent-no-raw-usechat` | 1.10.0 as `warn` | **1.13.0**
|
|
1216
|
-
| `basalt/agent-resume-guard` | 1.10.0 as `warn` | **1.13.0**
|
|
1217
|
-
| `basalt/raw-size-literal` | 1.7.0 as `warn` | **1.20.0**
|
|
1218
|
-
| `basalt/hand-rolled-plot` | 1.21.0 as `warn` | **
|
|
1219
|
-
| `basalt/chart-legend-literal` | 1.20.0 as `warn` | **
|
|
1220
|
-
| `basalt/shadow-basalt-export` | 1.20.0 as `warn` | ADVISORY — permanent `warn`, see below, never subject to the C16 gate
|
|
1221
|
-
| `basalt/hand-rolled-shell` | 1.20.0 as `warn` | **
|
|
1222
|
-
| `theme-allow-unscoped` (guard kind) | 1.20.0 as `warn` | **
|
|
1223
|
-
| `surface-shadow-override` (guard kind) | 1.20.0 as `warn` | **
|
|
1224
|
-
| `css-raw-surface` (guard kind) | 1.20.0 as `warn` | **
|
|
1225
|
-
| `inline-font-size` (guard kind) | 1.20.0 as `warn` | **
|
|
1226
|
-
| `hidden-inline-style` (guard kind) | 1.20.0 as `warn` | **
|
|
2061
|
+
| Rule | Landed | Became `error` |
|
|
2062
|
+
| -------------------------------------- | ---------------- | ------------------------------------------------------------------------------------------- |
|
|
2063
|
+
| `mantine-shade-index` (guard kind) | 1.7.0 as `warn` | **1.11.0** |
|
|
2064
|
+
| `basalt/raw-scroll-container` | ≤1.2.0 as `off` | `warn` 1.10.0 → **`error` 1.13.0** |
|
|
2065
|
+
| `basalt/ai-sdk-major` | 1.10.0 as `warn` | **1.13.0** |
|
|
2066
|
+
| `basalt/agent-no-raw-usechat` | 1.10.0 as `warn` | **1.13.0** |
|
|
2067
|
+
| `basalt/agent-resume-guard` | 1.10.0 as `warn` | **1.13.0** |
|
|
2068
|
+
| `basalt/raw-size-literal` | 1.7.0 as `warn` | **1.20.0** |
|
|
2069
|
+
| `basalt/hand-rolled-plot` | 1.21.0 as `warn` | **1.26.0** (grace had restarted at the 1.21.0 widening) |
|
|
2070
|
+
| `basalt/chart-legend-literal` | 1.20.0 as `warn` | **1.26.0** |
|
|
2071
|
+
| `basalt/shadow-basalt-export` | 1.20.0 as `warn` | ADVISORY — permanent `warn`, see below, never subject to the C16 gate |
|
|
2072
|
+
| `basalt/hand-rolled-shell` | 1.20.0 as `warn` | **1.26.0** |
|
|
2073
|
+
| `theme-allow-unscoped` (guard kind) | 1.20.0 as `warn` | **1.26.0** |
|
|
2074
|
+
| `surface-shadow-override` (guard kind) | 1.20.0 as `warn` | **1.26.0** |
|
|
2075
|
+
| `css-raw-surface` (guard kind) | 1.20.0 as `warn` | **1.26.0** |
|
|
2076
|
+
| `inline-font-size` (guard kind) | 1.20.0 as `warn` | **1.26.0** |
|
|
2077
|
+
| `hidden-inline-style` (guard kind) | 1.20.0 as `warn` | **1.26.0** |
|
|
2078
|
+
| `basalt/control-size-literal` | 1.26.0 as `warn` | **1.27.0** |
|
|
2079
|
+
| `basalt/in-body-page-title` | 1.26.0 as `warn` | **1.27.0** |
|
|
2080
|
+
| `in-body-page-title` (guard kind) | 1.26.0 as `warn` | **1.27.0** — same id as the rule above, so one waiver covers both |
|
|
2081
|
+
| `basalt/responsive-twin` | 1.26.0 as `warn` | **1.27.0** |
|
|
2082
|
+
| `basalt/search-literal-link` | 1.26.0 as `warn` | **1.27.0** |
|
|
2083
|
+
| `basalt/use-search-from-literal` | 1.26.0 as `warn` | **1.27.0** |
|
|
2084
|
+
| `basalt/control-outside-home` | 1.26.0 as `warn` | still `warn`, `promote: '1.30.0'` — re-dated on 9 measured cross-file overlay warns in argo |
|
|
2085
|
+
| `raw-selection-control` (guard kind) | 1.26.0 as `warn` | still `warn`, `promote: '1.30.0'` — the text lane of the row above |
|
|
1227
2086
|
|
|
1228
2087
|
`card-with-border`, `inline-display`, `raw-html-layout`, `raw-form-control`, `raw-font-family` and
|
|
1229
2088
|
the other original guard kinds have been `error` since before 1.2.0 — they never had a grace minor.
|
|
1230
2089
|
Guard findings only gained a severity field at all in 1.4.0; before that every finding was fatal.
|
|
1231
2090
|
|
|
1232
|
-
**Both ledgers changed shape
|
|
2091
|
+
**Both ledgers changed shape at 1.26.0 (C16, `docs/CONTROLS-SPEC.md` §1).** An entry
|
|
1233
2092
|
used to be a bare promotion-note string with no expiry a machine could check — which is exactly how
|
|
1234
2093
|
the nine rows above sat at `warn` for five minors although the doctrine below says "one minor". Both
|
|
1235
2094
|
`PLUGIN_RULE_GRACE` (`configs/oxlint-plugin.js`) and `GRACE_PERIOD_KINDS` (`src/guard/index.ts`) now
|
|
1236
2095
|
hold `{ since, promote, why }` (semver strings), and a version-gated test fails the build once
|
|
1237
2096
|
`package.json`'s version reaches an entry's `promote` while the entry is still there — see
|
|
1238
|
-
"
|
|
2097
|
+
"1.26.0" above for the full change. `shadow-basalt-export` moved to a sibling ledger,
|
|
1239
2098
|
`PLUGIN_RULE_ADVISORY`, which the gate never checks: it was already documented as a possible
|
|
1240
2099
|
permanent `warn`, and the version-gate doctrine only fits an entry that has an honest promotion
|
|
1241
2100
|
date.
|