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
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Typed CSS-module declaration (the S4 CSS-modules path). Named string props — not an index
|
|
3
|
+
* signature — so dot access stays verbatim under the package's strict flags.
|
|
4
|
+
*/
|
|
5
|
+
declare const classes: {
|
|
6
|
+
readonly row: string
|
|
7
|
+
readonly head: string
|
|
8
|
+
readonly label: string
|
|
9
|
+
readonly readout: string
|
|
10
|
+
readonly end: string
|
|
11
|
+
readonly control: string
|
|
12
|
+
}
|
|
13
|
+
export default classes
|
|
@@ -0,0 +1,392 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* `PanelRow` — the inspector/facet ROW every control renders on the `panel` surface, and on the
|
|
3
|
+
* mobile `sheet` surface too (`docs/ASIDE-SPEC.md` §1 "Inspector", §3; `docs/CONTROLS-SPEC.md` §3:
|
|
4
|
+
* "sheet = panel rows inside a Drawer") — a labelled block around one control, and a HOME: it wraps
|
|
5
|
+
* its slots in `CtlSlot`, so a control inside carries no `size` of its own (law C5).
|
|
6
|
+
*
|
|
7
|
+
* **Label above, never beside (G4).** At an aside's ~300px, label · control · readout on one line
|
|
8
|
+
* leaves the control about 90px — under 12px per step for a 20-step slider, which is why the CBBI
|
|
9
|
+
* page hand-rolled two-line rows before this existed. The ONE exception is `end`: a control that
|
|
10
|
+
* rides the label line because it is atomic and needs no width (a `Switch`).
|
|
11
|
+
*
|
|
12
|
+
* The skeleton is plain elements plus one CSS module — no Mantine `Group`/`Stack`. A row is drawn
|
|
13
|
+
* dozens of times in one column, and the hairline/inset law it carries (`.row + .row`) is a
|
|
14
|
+
* SIBLING relationship, which a `Stack`'s gap cannot express.
|
|
15
|
+
*
|
|
16
|
+
* @example
|
|
17
|
+
* <PanelRow label="Pi Cycle Top" hint="The 111DMA / 350DMA×2 crossover." readout="0.62">
|
|
18
|
+
* <SliderControl field={weights.field.piCycle} label="Pi Cycle Top" />
|
|
19
|
+
* </PanelRow>
|
|
20
|
+
*
|
|
21
|
+
* @example
|
|
22
|
+
* // A toggle: one line, the control on the label line, no control line at all.
|
|
23
|
+
* <PanelRow label="Reweighted" end={<Switch checked={on} onChange={…} />} />
|
|
24
|
+
*/
|
|
25
|
+
import { SegmentedControl, Select } from '@mantine/core'
|
|
26
|
+
import { useLayoutEffect, useRef, useState } from 'react'
|
|
27
|
+
import type { ReactNode, RefObject } from 'react'
|
|
28
|
+
import { cx } from '../common/props'
|
|
29
|
+
import type { BasaltProps } from '../common/props'
|
|
30
|
+
import { CtlSlot } from '../theme'
|
|
31
|
+
import { InfoGlyph } from '../widget-header/widget-header'
|
|
32
|
+
import classes from './panel-row.module.css'
|
|
33
|
+
|
|
34
|
+
/**
|
|
35
|
+
* Past three options a panel row's choice is a `Select`, not a track. Same arithmetic as
|
|
36
|
+
* `ViewTabs`' phone form, against the aside's ~300px rather than a phone's: a four-segment track at
|
|
37
|
+
* that width gives each label ~60px, which truncates every word longer than "Previous".
|
|
38
|
+
*
|
|
39
|
+
* **The count, not the whole law.** Three options at three WORDS' worth of label is not the same
|
|
40
|
+
* claim as three options at three SENTENCES' worth — "Same period last year" clipped mid-word
|
|
41
|
+
* inside its equal third even at a set of exactly three. `PANEL_TRACK_MAX` is the cheap first gate;
|
|
42
|
+
* `useTrackFits` (below) is the actual width check that decides whether the track renders at all.
|
|
43
|
+
*/
|
|
44
|
+
export const PANEL_TRACK_MAX = 3
|
|
45
|
+
|
|
46
|
+
export type PanelRowProps = BasaltProps & {
|
|
47
|
+
/** The row's name. Rendered above the control, `xs`/550 — never inside it. */
|
|
48
|
+
readonly label: string
|
|
49
|
+
/** Info glyph + tooltip beside the label — the same affordance `WidgetHeader.info` draws. */
|
|
50
|
+
readonly hint?: string
|
|
51
|
+
/**
|
|
52
|
+
* The current value, mono and right-aligned on the label line. A slider's readout, a range's
|
|
53
|
+
* resolved window — anything the control itself does not print.
|
|
54
|
+
*/
|
|
55
|
+
readonly readout?: ReactNode
|
|
56
|
+
/**
|
|
57
|
+
* A control that rides the LABEL line instead of taking one of its own — a `Switch`, and by
|
|
58
|
+
* design almost nothing else. Anything with a width belongs in `children`.
|
|
59
|
+
*/
|
|
60
|
+
readonly end?: ReactNode
|
|
61
|
+
/** Dims the row. The control inside keeps its own `disabled` — this is the visual half. */
|
|
62
|
+
readonly disabled?: boolean
|
|
63
|
+
/**
|
|
64
|
+
* Stamped on the label so the control can point `aria-labelledby` at it. The CONTROL owns the id
|
|
65
|
+
* (it renders this row), so an id published downward could never reach it — see
|
|
66
|
+
* `useControlName`'s doc.
|
|
67
|
+
*/
|
|
68
|
+
readonly labelId?: string
|
|
69
|
+
/**
|
|
70
|
+
* When set, renders the label as a `<label htmlFor={htmlFor}>` instead of a bare `<span>`, so
|
|
71
|
+
* clicking the label text also activates the control — the affordance Mantine's own labelled
|
|
72
|
+
* inputs give for free. Pass the `end` control's id (a `Switch`, typically).
|
|
73
|
+
*/
|
|
74
|
+
readonly htmlFor?: string
|
|
75
|
+
/** The full-width control line. Omitted for a row whose control rides `end`. */
|
|
76
|
+
readonly children?: ReactNode
|
|
77
|
+
}
|
|
78
|
+
|
|
79
|
+
export function PanelRow({
|
|
80
|
+
label,
|
|
81
|
+
hint,
|
|
82
|
+
readout,
|
|
83
|
+
end,
|
|
84
|
+
disabled,
|
|
85
|
+
labelId,
|
|
86
|
+
htmlFor,
|
|
87
|
+
children,
|
|
88
|
+
className,
|
|
89
|
+
style,
|
|
90
|
+
}: PanelRowProps): ReactNode {
|
|
91
|
+
return (
|
|
92
|
+
<div
|
|
93
|
+
className={cx(classes.row, className)}
|
|
94
|
+
{...(disabled === true && { 'data-disabled': true })}
|
|
95
|
+
{...(style !== undefined && { style })}
|
|
96
|
+
>
|
|
97
|
+
{/* ONE slot for the whole row, not one per line: `CtlSlot`'s marker is `display: contents`,
|
|
98
|
+
so both lines stay flex children of `.row` and the tier reaches `end` and `children`
|
|
99
|
+
through a single provider. */}
|
|
100
|
+
<CtlSlot>
|
|
101
|
+
<div className={classes.head}>
|
|
102
|
+
{htmlFor !== undefined ? (
|
|
103
|
+
<label
|
|
104
|
+
htmlFor={htmlFor}
|
|
105
|
+
className={classes.label}
|
|
106
|
+
{...(labelId !== undefined && { id: labelId })}
|
|
107
|
+
>
|
|
108
|
+
{label}
|
|
109
|
+
</label>
|
|
110
|
+
) : (
|
|
111
|
+
<span className={classes.label} {...(labelId !== undefined && { id: labelId })}>
|
|
112
|
+
{label}
|
|
113
|
+
</span>
|
|
114
|
+
)}
|
|
115
|
+
{hint !== undefined && <InfoGlyph text={hint} />}
|
|
116
|
+
{readout !== undefined && <span className={classes.readout}>{readout}</span>}
|
|
117
|
+
{end !== undefined && <span className={classes.end}>{end}</span>}
|
|
118
|
+
</div>
|
|
119
|
+
{children !== undefined && <div className={classes.control}>{children}</div>}
|
|
120
|
+
</CtlSlot>
|
|
121
|
+
</div>
|
|
122
|
+
)
|
|
123
|
+
}
|
|
124
|
+
|
|
125
|
+
/** One option as both surfaces render it — `disabled` is the `SegmentedControl` half. */
|
|
126
|
+
export type PanelChoiceOption = {
|
|
127
|
+
readonly value: string
|
|
128
|
+
readonly label: string
|
|
129
|
+
readonly disabled?: boolean
|
|
130
|
+
}
|
|
131
|
+
|
|
132
|
+
export type PanelChoiceProps = {
|
|
133
|
+
/** The control's accessible name, as `useControlName` resolved it for this surface. */
|
|
134
|
+
readonly nameProps: { 'aria-labelledby': string } | { 'aria-label': string }
|
|
135
|
+
readonly value: string
|
|
136
|
+
readonly options: readonly PanelChoiceOption[]
|
|
137
|
+
/** Numeric labels (`7d` / `30d`) get the mono treatment `segmented-control.module.css` owns. */
|
|
138
|
+
readonly numeric?: boolean
|
|
139
|
+
readonly onChange: (next: string) => void
|
|
140
|
+
}
|
|
141
|
+
|
|
142
|
+
/**
|
|
143
|
+
* The nearest ANCESTOR that actually occupies layout space — skipping every `display: contents`
|
|
144
|
+
* box on the way up. Every home in this package wraps its slot in `CtlSlot` (`theme/ctl-theme.tsx`)
|
|
145
|
+
* to reach the `ctl` tier, and `CtlSlot`'s own marker is a `display: contents` `Box` (deliberately —
|
|
146
|
+
* it must stay out of the slot's own flex/grid layout). A `display: contents` element generates NO
|
|
147
|
+
* box of its own, so its `clientWidth` is always `0` — reading `root.parentElement.clientWidth`
|
|
148
|
+
* directly would report "zero room" for every control mounted straight into a slot (`ViewTabs`'
|
|
149
|
+
* desktop form, `PageBar`'s `actions`), which is not the constraint being measured at all.
|
|
150
|
+
*/
|
|
151
|
+
function layoutParent(el: HTMLElement): HTMLElement | null {
|
|
152
|
+
let parent = el.parentElement
|
|
153
|
+
while (parent !== null && getComputedStyle(parent).display === 'contents') {
|
|
154
|
+
parent = parent.parentElement
|
|
155
|
+
}
|
|
156
|
+
return parent
|
|
157
|
+
}
|
|
158
|
+
|
|
159
|
+
/**
|
|
160
|
+
* A `SegmentedControl`'s own semantic class for a rendered option's label (`__staticSelector`,
|
|
161
|
+
* present on every Mantine styles-api part regardless of the CSS-module hash) — stable across a
|
|
162
|
+
* version bump the way a generated `_label_1pq5d_5` class is not.
|
|
163
|
+
*/
|
|
164
|
+
const TRACK_LABEL_SELECTOR = '.mantine-SegmentedControl-label'
|
|
165
|
+
|
|
166
|
+
/**
|
|
167
|
+
* The authoritative check, meaningful only while the track is actually mounted — TWO signals, not
|
|
168
|
+
* one, because they catch two DIFFERENT ways a track fails to fit and neither subsumes the other:
|
|
169
|
+
*
|
|
170
|
+
* 1. **Root vs parent** (`root.offsetWidth > parent.clientWidth`) — the track's OWN root refuses to
|
|
171
|
+
* shrink below `min-width: max-content` (`theme/index.ts`'s `SegmentedControl.extend`), so a
|
|
172
|
+
* too-narrow ANCESTOR (a header's `actions` slot squeezing a non-`fullWidth` two-option track)
|
|
173
|
+
* shows up as the root overflowing its container.
|
|
174
|
+
* 2. **Per-label overflow** (`label.scrollWidth > label.clientWidth`) — the ctl-tier `fullWidth`
|
|
175
|
+
* label carries `width: 100%` (`theme/index.ts`, so it fills its equal `.control` share for
|
|
176
|
+
* ellipsis to work at all — `PanelChoice`'s doc). A `width: 100%` CHILD cannot contribute an
|
|
177
|
+
* intrinsic size to its ancestor's max-content computation (percentages are undefined until the
|
|
178
|
+
* container's own size is known, so the browser treats it as contributing ~nothing) — which is
|
|
179
|
+
* why `min-width: max-content` on the root measurably FAILS to grow past its available space at
|
|
180
|
+
* the phone tier: "Week"/"Absolute" clipped inside their equal column ("Wee", "Absolut") while
|
|
181
|
+
* `root.offsetWidth` still read as fitting its parent. Signal 1 cannot see this at all; only
|
|
182
|
+
* reading each rendered label directly can.
|
|
183
|
+
*
|
|
184
|
+
* Both signals require REAL layout, so `unknown` (parent not yet settled) takes priority over
|
|
185
|
+
* either — see `useTrackFits`'s own doc for why a `0` reading is not evidence of overflow.
|
|
186
|
+
*/
|
|
187
|
+
function measureMounted(root: HTMLElement, parent: HTMLElement): 'fits' | 'overflow' | 'unknown' {
|
|
188
|
+
if (parent.clientWidth === 0) return 'unknown'
|
|
189
|
+
if (root.offsetWidth > parent.clientWidth) return 'overflow'
|
|
190
|
+
const labels = root.querySelectorAll<HTMLElement>(TRACK_LABEL_SELECTOR)
|
|
191
|
+
for (const label of labels) {
|
|
192
|
+
if (label.scrollWidth > label.clientWidth) return 'overflow'
|
|
193
|
+
}
|
|
194
|
+
return 'fits'
|
|
195
|
+
}
|
|
196
|
+
|
|
197
|
+
/**
|
|
198
|
+
* Fit-checks a full-width track: {@link PANEL_TRACK_MAX} (and `ViewTabs`' own `PHONE_TRACK_MAX`) is
|
|
199
|
+
* the cheap COUNT gate, not the whole law — three short labels and three long ones are not the same
|
|
200
|
+
* claim at a ~300px column or a phone sheet ("Same period last year" clipped mid-word inside its
|
|
201
|
+
* equal third even though the set was exactly three; "Week"/"Absolute" clipped inside their equal
|
|
202
|
+
* column at the phone tier even though the ROOT read as fitting its parent — see
|
|
203
|
+
* {@link measureMounted}'s doc for why that needs a second signal). This hook is the width gate
|
|
204
|
+
* underneath the count cap, shared so `PanelChoice` and `ViewTabs`' phone form cannot drift the way
|
|
205
|
+
* their two hand-rolled ternaries already had once (`PanelChoice`'s own doc).
|
|
206
|
+
*
|
|
207
|
+
* **A LIVE toggle, not a one-way latch — it reverts.** The moment the track overflows, `PanelChoice`
|
|
208
|
+
* swaps it for a `Select`, which un-mounts the only element `measureMounted` could otherwise read.
|
|
209
|
+
* Two refs survive that swap on purpose: `trackWidthRef` remembers the track's own last-measured
|
|
210
|
+
* width (refreshed live whenever it IS mounted, used only as a cheap pre-filter — see below — never
|
|
211
|
+
* as the final answer), and `parentRef` holds the layout parent found once, at the FIRST mount — the
|
|
212
|
+
* same DOM node hosts either form (`PanelChoice`/`ViewTabs` return one or the other as their sole
|
|
213
|
+
* element, never a wrapper that differs between them), so it is never itself removed by the swap.
|
|
214
|
+
* The `ResizeObserver` therefore never watches a node this hook is about to lose: it observes the
|
|
215
|
+
* PARENT for the whole hook's lifetime and the TRACK only while it exists.
|
|
216
|
+
*
|
|
217
|
+
* While `Select` is showing, an observer tick with room to spare (`parent.clientWidth` at or past
|
|
218
|
+
* the remembered `trackWidthRef`) SPECULATIVELY re-mounts the track rather than trying to predict
|
|
219
|
+
* the exact threshold from a cached number — the two-signal check above cannot be run without a
|
|
220
|
+
* live root, and a WRONG guess here is not user-visible: the second effect below re-verifies with
|
|
221
|
+
* `measureMounted` the instant the fresh root exists, inside the SAME `useLayoutEffect` pass, and
|
|
222
|
+
* reverts synchronously before paint if the speculation was wrong. Nothing here can loop — a
|
|
223
|
+
* `ResizeObserver` only fires again on a GENUINE subsequent size change, not because React
|
|
224
|
+
* re-rendered.
|
|
225
|
+
*
|
|
226
|
+
* A SECOND, dependency-free `useLayoutEffect` is what performs that verification (and, on the
|
|
227
|
+
* ordinary growth-first-detected-while-mounted path, is also what re-arms the observer on the
|
|
228
|
+
* track's own root once it exists) — the FIRST effect only runs once per `[countFits, dataKey]`,
|
|
229
|
+
* but the track itself mounts and unmounts every time `fits` changes, and a `ResizeObserver` has to
|
|
230
|
+
* be told about each new node explicitly; this second effect runs after every render and is a
|
|
231
|
+
* no-op unless `rootRef.current` is a node it is not already watching.
|
|
232
|
+
*
|
|
233
|
+
* The check is THREE-VALUED, not two — `unknown` alongside `fits`/`overflow` — because a
|
|
234
|
+
* `clientWidth` of `0` is not evidence of overflow, it is evidence the ancestor chain has not been
|
|
235
|
+
* LAID OUT yet: the aside animates its width in from 0 while `PageAside` claims the region
|
|
236
|
+
* (`docs/ASIDE-SPEC.md` §0), and every ancestor up to the aside panel itself reads `0` for one or
|
|
237
|
+
* more layout passes while that transition is in flight. `unknown` updates nothing — it is simply
|
|
238
|
+
* not yet an answer, and the observer keeps watching for the ancestor chain to settle.
|
|
239
|
+
*
|
|
240
|
+
* `useLayoutEffect` runs BEFORE the browser paints, so a CONFIDENT overflow reading is never
|
|
241
|
+
* actually shown as a track first: the synchronous `setState` for it lands before paint, not after.
|
|
242
|
+
*
|
|
243
|
+
* `dataKey` is a caller-built string identifying the CURRENT option set (not read inside the effect
|
|
244
|
+
* body, just what forces it to re-run — a fresh mount, a fresh `parentRef`/`trackWidthRef` — when
|
|
245
|
+
* the rendered labels change) — primitive on purpose, so it is an honest `useLayoutEffect`
|
|
246
|
+
* dependency rather than a fresh array reference on every render.
|
|
247
|
+
*/
|
|
248
|
+
export function useTrackFits(
|
|
249
|
+
countFits: boolean,
|
|
250
|
+
dataKey: string,
|
|
251
|
+
): { rootRef: RefObject<HTMLDivElement | null>; fits: boolean } {
|
|
252
|
+
const rootRef = useRef<HTMLDivElement>(null)
|
|
253
|
+
const [rootFits, setRootFits] = useState(true)
|
|
254
|
+
const observerRef = useRef<ResizeObserver | null>(null)
|
|
255
|
+
const parentRef = useRef<HTMLElement | null>(null)
|
|
256
|
+
const trackWidthRef = useRef(0)
|
|
257
|
+
const observedRootRef = useRef<HTMLElement | null>(null)
|
|
258
|
+
|
|
259
|
+
useLayoutEffect(() => {
|
|
260
|
+
if (!countFits) return
|
|
261
|
+
const root = rootRef.current
|
|
262
|
+
if (root === null) return
|
|
263
|
+
const parent = layoutParent(root)
|
|
264
|
+
if (parent === null) return
|
|
265
|
+
parentRef.current = parent
|
|
266
|
+
trackWidthRef.current = root.offsetWidth
|
|
267
|
+
|
|
268
|
+
const resolve = (): void => {
|
|
269
|
+
const p = parentRef.current
|
|
270
|
+
if (p === null) return
|
|
271
|
+
const liveRoot = rootRef.current
|
|
272
|
+
|
|
273
|
+
if (liveRoot !== null) {
|
|
274
|
+
const result = measureMounted(liveRoot, p)
|
|
275
|
+
trackWidthRef.current = liveRoot.offsetWidth
|
|
276
|
+
if (result === 'unknown') return
|
|
277
|
+
const fits = result === 'fits'
|
|
278
|
+
setRootFits((current) => (current === fits ? current : fits))
|
|
279
|
+
return
|
|
280
|
+
}
|
|
281
|
+
|
|
282
|
+
// `Select` is mounted — speculate rather than measure (see this hook's own doc). No-op
|
|
283
|
+
// while shrinking or unmeasured: only an actual increase past the last known track width is
|
|
284
|
+
// worth a remount attempt.
|
|
285
|
+
if (p.clientWidth === 0 || trackWidthRef.current === 0) return
|
|
286
|
+
if (p.clientWidth >= trackWidthRef.current) setRootFits(true)
|
|
287
|
+
}
|
|
288
|
+
|
|
289
|
+
if (typeof ResizeObserver === 'undefined') {
|
|
290
|
+
// No recovery path exists without an observer, so a same-tick confident read is the only
|
|
291
|
+
// chance this environment gets.
|
|
292
|
+
resolve()
|
|
293
|
+
return
|
|
294
|
+
}
|
|
295
|
+
|
|
296
|
+
const observer = new ResizeObserver(resolve)
|
|
297
|
+
observerRef.current = observer
|
|
298
|
+
observer.observe(parent)
|
|
299
|
+
observer.observe(root)
|
|
300
|
+
observedRootRef.current = root
|
|
301
|
+
|
|
302
|
+
// Resolve once, synchronously, so a track that is ALREADY confidently measurable (its
|
|
303
|
+
// ancestors settled before this component even mounted — the common case) decides before
|
|
304
|
+
// paint instead of waiting for the observer's first async tick.
|
|
305
|
+
resolve()
|
|
306
|
+
|
|
307
|
+
return () => {
|
|
308
|
+
observer.disconnect()
|
|
309
|
+
observerRef.current = null
|
|
310
|
+
observedRootRef.current = null
|
|
311
|
+
}
|
|
312
|
+
}, [countFits, dataKey])
|
|
313
|
+
|
|
314
|
+
// Re-arms the SAME observer on a fresh track root whenever one (re)mounts, AND is what actually
|
|
315
|
+
// VERIFIES a speculative remount (see this hook's own doc) — a wrong guess reverts here,
|
|
316
|
+
// synchronously, before this render ever paints. A no-op on every render where the track is
|
|
317
|
+
// absent (`Select` showing) or already the node being watched — deliberately NO dependency
|
|
318
|
+
// array, since a `ResizeObserver` has to be told about each fresh root explicitly and a fresh
|
|
319
|
+
// root can appear on any render. Cannot loop: every `setRootFits` call below is a functional
|
|
320
|
+
// update gated on the value actually CHANGING, so a render this effect does not alter never
|
|
321
|
+
// re-triggers it.
|
|
322
|
+
// oxlint-disable-next-line react-hooks/exhaustive-deps -- deliberately runs every render, see above
|
|
323
|
+
useLayoutEffect(() => {
|
|
324
|
+
const observer = observerRef.current
|
|
325
|
+
const root = rootRef.current
|
|
326
|
+
const parent = parentRef.current
|
|
327
|
+
if (observer === null || root === null || observedRootRef.current === root) return
|
|
328
|
+
if (observedRootRef.current !== null) observer.unobserve(observedRootRef.current)
|
|
329
|
+
observer.observe(root)
|
|
330
|
+
observedRootRef.current = root
|
|
331
|
+
trackWidthRef.current = root.offsetWidth
|
|
332
|
+
|
|
333
|
+
if (parent === null) return
|
|
334
|
+
const result = measureMounted(root, parent)
|
|
335
|
+
if (result === 'unknown') return
|
|
336
|
+
const fits = result === 'fits'
|
|
337
|
+
setRootFits((current) => (current === fits ? current : fits))
|
|
338
|
+
})
|
|
339
|
+
|
|
340
|
+
return { rootRef, fits: countFits && rootFits }
|
|
341
|
+
}
|
|
342
|
+
|
|
343
|
+
/**
|
|
344
|
+
* The single-choice control a panel row draws: a full-width track while the set fits both
|
|
345
|
+
* {@link PANEL_TRACK_MAX} and the width check {@link useTrackFits} runs, a `Select` past either.
|
|
346
|
+
*
|
|
347
|
+
* Internal, and one component rather than the same ternary in each control: `EnumFilter` and
|
|
348
|
+
* `ViewTabs` both wrote it out and had already drifted — `ViewTabs`' copy lost `data-numeric`, so a
|
|
349
|
+
* numeric tab set rendered proportional in the aside and mono everywhere else. The split point is
|
|
350
|
+
* the geometry of a ~300px column, which is a property of the ROW, not of any one filter, so it
|
|
351
|
+
* belongs beside the row that imposes it.
|
|
352
|
+
*/
|
|
353
|
+
export function PanelChoice({
|
|
354
|
+
nameProps,
|
|
355
|
+
value,
|
|
356
|
+
options,
|
|
357
|
+
numeric,
|
|
358
|
+
onChange,
|
|
359
|
+
}: PanelChoiceProps): ReactNode {
|
|
360
|
+
const data = options.map((option) => ({
|
|
361
|
+
value: option.value,
|
|
362
|
+
label: option.label,
|
|
363
|
+
disabled: option.disabled === true,
|
|
364
|
+
}))
|
|
365
|
+
const countFits = options.length <= PANEL_TRACK_MAX
|
|
366
|
+
const { rootRef, fits } = useTrackFits(countFits, data.map((d) => d.value).join('|'))
|
|
367
|
+
|
|
368
|
+
if (fits) {
|
|
369
|
+
return (
|
|
370
|
+
<SegmentedControl
|
|
371
|
+
ref={rootRef}
|
|
372
|
+
{...nameProps}
|
|
373
|
+
fullWidth
|
|
374
|
+
value={value}
|
|
375
|
+
data={data}
|
|
376
|
+
{...(numeric === true && { 'data-numeric': true })}
|
|
377
|
+
onChange={onChange}
|
|
378
|
+
/>
|
|
379
|
+
)
|
|
380
|
+
}
|
|
381
|
+
return (
|
|
382
|
+
<Select
|
|
383
|
+
{...nameProps}
|
|
384
|
+
value={value}
|
|
385
|
+
allowDeselect={false}
|
|
386
|
+
data={data}
|
|
387
|
+
onChange={(next) => {
|
|
388
|
+
if (next !== null) onChange(next)
|
|
389
|
+
}}
|
|
390
|
+
/>
|
|
391
|
+
)
|
|
392
|
+
}
|
|
@@ -10,11 +10,12 @@
|
|
|
10
10
|
* `theme/segmented-control.module.css` owns; that attribute is what retired the per-consumer
|
|
11
11
|
* `theme-allow` + inline `fontFamily` hack (C7).
|
|
12
12
|
*
|
|
13
|
-
* In the
|
|
14
|
-
* `
|
|
15
|
-
*
|
|
16
|
-
*
|
|
17
|
-
*
|
|
13
|
+
* In the PANEL and the SHEET (`docs/CONTROLS-SPEC.md` §3: "sheet = panel rows inside a Drawer")
|
|
14
|
+
* they render as one `Select` — label above, the presets plus a `Custom range…` ROW inside the same
|
|
15
|
+
* list, which reveals the SAME injected picker underneath. A track cannot hold five date presets at
|
|
16
|
+
* ~300px (or across a bottom drawer, where a vertical `SegmentedControl` read as a broken control
|
|
17
|
+
* rather than a choice), and a second control beside the choice would cost the column — or an
|
|
18
|
+
* unconditional calendar pushed below every OTHER filter in the sheet — a row it does not have.
|
|
18
19
|
*
|
|
19
20
|
* The custom picker is INJECTED, never imported: `basalt-ui/controls-dates` holds the
|
|
20
21
|
* `@mantine/dates` implementation, and this module must resolve for a consumer who has no
|
|
@@ -26,21 +27,50 @@
|
|
|
26
27
|
* // range: field.range({ presets: ['7d', '30d', '90d', 'ytd'], fallback: '30d', custom: true })
|
|
27
28
|
* <RangeFilter field={analytics.field.range} customPicker={DateRangePicker} />
|
|
28
29
|
*/
|
|
29
|
-
import { SegmentedControl, Stack } from '@mantine/core'
|
|
30
|
-
import { useState } from 'react'
|
|
30
|
+
import { SegmentedControl, Select, Stack } from '@mantine/core'
|
|
31
|
+
import { useEffect, useRef, useState } from 'react'
|
|
31
32
|
import type { ComponentType, ReactNode } from 'react'
|
|
33
|
+
import type { BasaltProps } from '../common/props'
|
|
34
|
+
import { assertRequiredProps } from '../common/validate'
|
|
35
|
+
import { isDev } from '../utils/is-dev'
|
|
32
36
|
import type { FieldHandle, RangeField, RangeValue } from '../state'
|
|
33
37
|
import classes from './controls.module.css'
|
|
34
38
|
import { useFilterRegistration, useFilterSurface } from './filter-context'
|
|
35
39
|
import { FilterPill } from './filter-pill'
|
|
36
40
|
import { CalendarGlyph } from './glyphs'
|
|
37
|
-
import {
|
|
41
|
+
import { useControlName } from './filter-sheet'
|
|
42
|
+
import { PanelRow } from './panel-row'
|
|
38
43
|
|
|
39
44
|
/** Past four presets the track goes vertical. */
|
|
40
45
|
const VERTICAL_FROM = 5
|
|
46
|
+
/** The panel `Select`'s last row — the same wording the sheet's disclosure uses, and the same
|
|
47
|
+
* `'custom'` preset value the field already declares, so no synthetic option value exists. */
|
|
48
|
+
const CUSTOM_ROW_LABEL = 'Custom range…'
|
|
41
49
|
/** `7d`, `30d`, `24h`, `90` — a label the mono numeric treatment is for. */
|
|
42
50
|
const NUMERIC_LABEL = /^\d/
|
|
43
51
|
|
|
52
|
+
/** Once per label — a filter renders on every navigation, and the wiring is fixed at definition. */
|
|
53
|
+
const noPickerWarned = new Set<string>()
|
|
54
|
+
|
|
55
|
+
/**
|
|
56
|
+
* Dev-only: the field declares `custom: true` and no picker was injected, so the custom window is
|
|
57
|
+
* unreachable — the popover shows presets only and the sheet's `Custom range…` row never renders.
|
|
58
|
+
* A warning rather than a type error: `custom: true` with presets only is a legal (and tested)
|
|
59
|
+
* configuration, and the picker is INJECTED precisely because `@mantine/dates` may be absent, so
|
|
60
|
+
* the type cannot tell "deliberately preset-only" from "forgot the import".
|
|
61
|
+
*/
|
|
62
|
+
function warnCustomWithoutPicker(label: string, unreachable: boolean): void {
|
|
63
|
+
if (!unreachable || !isDev() || noPickerWarned.has(label)) return
|
|
64
|
+
noPickerWarned.add(label)
|
|
65
|
+
// oxlint-disable-next-line no-console -- a dev-time wiring warning has no other channel
|
|
66
|
+
console.warn(
|
|
67
|
+
`[basalt-ui] RangeFilter('${label}'): the field declares \`custom: true\` but no ` +
|
|
68
|
+
'`customPicker` was injected, so the custom window cannot be reached. Pass ' +
|
|
69
|
+
'`customPicker={DateRangePicker}` (`basalt-ui/controls-dates`), or drop `custom: true` from ' +
|
|
70
|
+
'the field. (dev only)',
|
|
71
|
+
)
|
|
72
|
+
}
|
|
73
|
+
|
|
44
74
|
/**
|
|
45
75
|
* The contract a custom-range picker satisfies — `basalt-ui/controls-dates`' `DateRangePicker`, or a
|
|
46
76
|
* consumer's own. Dates are ISO (`YYYY-MM-DD`), the same shape `field.range` stores and
|
|
@@ -51,28 +81,59 @@ export type RangeCustomPickerProps = {
|
|
|
51
81
|
readonly onChange: (next: { from: string; to: string }) => void
|
|
52
82
|
}
|
|
53
83
|
|
|
54
|
-
|
|
55
|
-
|
|
84
|
+
/** Everything about the props that does not depend on the field's `custom` flag. */
|
|
85
|
+
type RangeFilterBase<P extends string, C extends boolean> = BasaltProps & {
|
|
86
|
+
/**
|
|
87
|
+
* A range handle from either store factory. Generic over the field's `custom` flag so a
|
|
88
|
+
* `field.range({ ... })` WITHOUT `custom` (whose handle is `RangeField<P, false>`, and whose
|
|
89
|
+
* values therefore never include `'custom'`) binds with no cast — pinning `C` to its default
|
|
90
|
+
* `boolean` here made the setter contravariantly incompatible and forced one at every call site.
|
|
91
|
+
*/
|
|
92
|
+
readonly field: FieldHandle<RangeField<P, C>>
|
|
56
93
|
/** Leading pill icon. Defaults to a calendar glyph — a range filter reads as a date control, so
|
|
57
94
|
* the glyph is part of the control's identity, not a per-call-site decision. */
|
|
58
95
|
readonly icon?: ReactNode
|
|
59
|
-
/** Rendered when the field declares `custom: true`. Omitted → presets only. */
|
|
60
|
-
readonly customPicker?: ComponentType<RangeCustomPickerProps>
|
|
61
96
|
/** Sheet-form heading. The pill's own label is the VALUE, which is what a bar reads. @default 'Range' */
|
|
62
97
|
readonly label?: string
|
|
63
98
|
}
|
|
64
99
|
|
|
65
|
-
export
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
100
|
+
export type RangeFilterProps<P extends string, C extends boolean = boolean> = RangeFilterBase<
|
|
101
|
+
P,
|
|
102
|
+
C
|
|
103
|
+
> & {
|
|
104
|
+
/**
|
|
105
|
+
* Rendered when the field declares `custom: true`. Omitted → presets only, which stays LEGAL
|
|
106
|
+
* (a range that only ever shows presets is a real configuration) but warns once in dev when the
|
|
107
|
+
* field allows a custom window: the affordance is then unreachable, and nothing else says so.
|
|
108
|
+
*/
|
|
109
|
+
readonly customPicker?: ComponentType<RangeCustomPickerProps>
|
|
110
|
+
}
|
|
111
|
+
|
|
112
|
+
export function RangeFilter<P extends string, C extends boolean = boolean>(
|
|
113
|
+
props: RangeFilterProps<P, C>,
|
|
114
|
+
): ReactNode {
|
|
115
|
+
// F-ERR-1 — without this a missing `field` surfaces as `undefined is not an object
|
|
116
|
+
// (evaluating 'field.use')`, caught by `BasaltErrorBoundary`.
|
|
117
|
+
assertRequiredProps('RangeFilter', props, ['field'], {
|
|
118
|
+
field: 'bind it to a store field (`store.field.<name>`), never a value/onChange pair.',
|
|
119
|
+
})
|
|
120
|
+
const {
|
|
121
|
+
field,
|
|
122
|
+
icon,
|
|
123
|
+
customPicker,
|
|
124
|
+
label = 'Range',
|
|
125
|
+
className,
|
|
126
|
+
style,
|
|
127
|
+
// One cast, at the one boundary a generic `C` cannot be read through: `C` only ever describes
|
|
128
|
+
// the FIELD's custom flag, and the body handles both.
|
|
129
|
+
} = props as unknown as RangeFilterBase<P, boolean> & {
|
|
130
|
+
readonly customPicker?: ComponentType<RangeCustomPickerProps>
|
|
131
|
+
}
|
|
71
132
|
const [value, setValue] = field.use()
|
|
72
133
|
const surface = useFilterSurface()
|
|
73
134
|
const isDefault = field.isDefault(value)
|
|
74
135
|
useFilterRegistration(!isDefault, () => {
|
|
75
|
-
|
|
136
|
+
field.clear()
|
|
76
137
|
})
|
|
77
138
|
|
|
78
139
|
const options = field.options
|
|
@@ -80,48 +141,75 @@ export function RangeFilter<P extends string>({
|
|
|
80
141
|
const allowsCustom = options.length !== presets.length
|
|
81
142
|
const numeric = presets.length > 0 && presets.every((option) => NUMERIC_LABEL.test(option.label))
|
|
82
143
|
const inSheet = surface === 'sheet'
|
|
144
|
+
const inPanel = surface === 'panel'
|
|
83
145
|
const Picker = customPicker
|
|
146
|
+
warnCustomWithoutPicker(label, allowsCustom && Picker === undefined)
|
|
84
147
|
// The track is a `radiogroup`; without this it announces unnamed, and the pill it hangs off reads
|
|
85
148
|
// the VALUE (`30d`), not the filter.
|
|
86
|
-
const { labelId, nameProps } = useControlName(label, inSheet)
|
|
149
|
+
const { labelId, nameProps } = useControlName(label, inSheet || inPanel)
|
|
87
150
|
// Expanded when the field ALREADY holds a custom window — a reader who deep-linked one must see
|
|
88
151
|
// it without hunting for the row that holds it. Local, because it is an overlay's open flag and
|
|
89
152
|
// not a filter value (the same line `FilterPill`'s `opened` state draws).
|
|
90
153
|
const [customOpen, setCustomOpen] = useState(value.preset === 'custom')
|
|
154
|
+
// …and RE-SYNCED whenever the preset moves under it. Seeded once, the flag survived a write this
|
|
155
|
+
// control did not make: a `Reset all` or a `field.clear()` from a `FilterSet` put the field back
|
|
156
|
+
// on `30d` while the panel's Select still read `Custom range…` with the picker open beneath it.
|
|
157
|
+
// Tracked against the LAST SEEN preset (`search-filter.tsx`'s `useDebouncedField` idiom) rather
|
|
158
|
+
// than against `value.preset` alone, because the just-clicked `Custom range…` transient is
|
|
159
|
+
// exactly the state where the flag is true and the preset has not moved yet.
|
|
160
|
+
const seenPreset = useRef(value.preset)
|
|
161
|
+
useEffect(() => {
|
|
162
|
+
if (seenPreset.current === value.preset) return
|
|
163
|
+
seenPreset.current = value.preset
|
|
164
|
+
setCustomOpen(value.preset === 'custom')
|
|
165
|
+
}, [value.preset])
|
|
91
166
|
const showPicker = allowsCustom && Picker !== undefined
|
|
92
167
|
|
|
93
|
-
|
|
168
|
+
// The sheet form is the panel form (`docs/CONTROLS-SPEC.md` §3: "sheet = panel rows inside a
|
|
169
|
+
// Drawer") — one `Select` holding the presets plus a `Custom range…` row, which reveals the same
|
|
170
|
+
// injected picker underneath. It used to be a `SheetOptionList` with the picker behind a separate
|
|
171
|
+
// `SheetDisclosure` row; the `Select` already folds both into one control, so the disclosure had
|
|
172
|
+
// no job left.
|
|
173
|
+
if (inPanel || inSheet) {
|
|
94
174
|
return (
|
|
95
|
-
<
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
175
|
+
<PanelRow
|
|
176
|
+
label={label}
|
|
177
|
+
labelId={labelId}
|
|
178
|
+
{...(className !== undefined && { className })}
|
|
179
|
+
{...(style !== undefined && { style })}
|
|
180
|
+
>
|
|
181
|
+
<Select
|
|
182
|
+
{...nameProps}
|
|
183
|
+
allowDeselect={false}
|
|
184
|
+
// `customOpen` is what the row reads while the picker is open but no window has been
|
|
185
|
+
// picked yet — selecting `Custom range…` reveals the calendar, it does not write a
|
|
186
|
+
// half-built `{ preset: 'custom' }` the codec would have to guess at.
|
|
187
|
+
value={customOpen ? 'custom' : value.preset}
|
|
188
|
+
data={[
|
|
189
|
+
...presets.map((option) => ({ value: option.value, label: option.label })),
|
|
190
|
+
...(showPicker ? [{ value: 'custom', label: CUSTOM_ROW_LABEL }] : []),
|
|
191
|
+
]}
|
|
192
|
+
onChange={(next) => {
|
|
193
|
+
if (next === null) return
|
|
194
|
+
if (next === 'custom') {
|
|
195
|
+
setCustomOpen(true)
|
|
196
|
+
return
|
|
197
|
+
}
|
|
102
198
|
setCustomOpen(false)
|
|
103
199
|
// Rendered from `field.options`, so `next` is always a declared preset — the cast
|
|
104
200
|
// restores what the codec already guarantees.
|
|
105
201
|
setValue({ preset: next } as RangeValue<P | 'custom'>)
|
|
106
202
|
}}
|
|
107
203
|
/>
|
|
108
|
-
{showPicker && (
|
|
109
|
-
<
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
setCustomOpen((open) => !open)
|
|
204
|
+
{showPicker && customOpen && (
|
|
205
|
+
<Picker
|
|
206
|
+
value={{ from: value.from, to: value.to }}
|
|
207
|
+
onChange={({ from, to }) => {
|
|
208
|
+
setValue({ preset: 'custom', from, to } as RangeValue<P | 'custom'>)
|
|
114
209
|
}}
|
|
115
|
-
|
|
116
|
-
<Picker
|
|
117
|
-
value={{ from: value.from, to: value.to }}
|
|
118
|
-
onChange={({ from, to }) => {
|
|
119
|
-
setValue({ preset: 'custom', from, to } as RangeValue<P | 'custom'>)
|
|
120
|
-
}}
|
|
121
|
-
/>
|
|
122
|
-
</SheetDisclosure>
|
|
210
|
+
/>
|
|
123
211
|
)}
|
|
124
|
-
</
|
|
212
|
+
</PanelRow>
|
|
125
213
|
)
|
|
126
214
|
}
|
|
127
215
|
|
|
@@ -157,6 +245,8 @@ export function RangeFilter<P extends string>({
|
|
|
157
245
|
active={!isDefault}
|
|
158
246
|
numeric={numeric && value.preset !== 'custom'}
|
|
159
247
|
icon={icon ?? <CalendarGlyph />}
|
|
248
|
+
{...(className !== undefined && { className })}
|
|
249
|
+
{...(style !== undefined && { style })}
|
|
160
250
|
>
|
|
161
251
|
<div className={classes.optionList}>{body}</div>
|
|
162
252
|
</FilterPill>
|