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/src/state/fields.ts
CHANGED
|
@@ -10,7 +10,7 @@
|
|
|
10
10
|
* consumer.
|
|
11
11
|
*/
|
|
12
12
|
import { useSyncExternalStore } from 'react'
|
|
13
|
-
import { createPersistedState, readPersistedValue } from './persisted'
|
|
13
|
+
import { createPersistedState, readPersistedValue, writePersistedValue } from './persisted'
|
|
14
14
|
|
|
15
15
|
// ── Store fields — the vocabulary both store factories share ──────────────────────────────────
|
|
16
16
|
|
|
@@ -48,6 +48,28 @@ export type ResolveLane<L> = {
|
|
|
48
48
|
history: L extends { history: 'push' } ? 'push' : 'replace'
|
|
49
49
|
}
|
|
50
50
|
|
|
51
|
+
/**
|
|
52
|
+
* A field's fallback: the value, or a THUNK evaluated at read time (`field.string({ fallback: () =>
|
|
53
|
+
* todayIso() })`). A thunk is re-evaluated on every read while nothing is written, and is never
|
|
54
|
+
* itself persisted — a write stores the value the control produced, like any other.
|
|
55
|
+
*
|
|
56
|
+
* The LOCAL and MEMORY lanes only. `createSearchStore` throws at definition for a thunk on a
|
|
57
|
+
* URL-lane field: `validateSearch` would evaluate it on every navigation and pin the result into the
|
|
58
|
+
* URL, so a deep link would carry a value nobody chose.
|
|
59
|
+
*/
|
|
60
|
+
export type FieldFallback<T> = T | (() => T)
|
|
61
|
+
|
|
62
|
+
/** Resolves a per-preset window at call time. Returns ISO dates — what `toWindow` hands an API. */
|
|
63
|
+
export type RangeWindow = (now: Date) => { from: string; to: string }
|
|
64
|
+
|
|
65
|
+
/**
|
|
66
|
+
* Per-preset window resolvers for a range field. A preset WITH one resolves through `toWindow()` to
|
|
67
|
+
* `{ from, to }`; a preset without keeps `{ window: preset }` — which is what lets a derived preset
|
|
68
|
+
* (`3m`, `ytd`) live in the same field as a server-understood one (`7d`) instead of forcing a
|
|
69
|
+
* hand-rolled `presetToParams` beside the store.
|
|
70
|
+
*/
|
|
71
|
+
export type RangeWindows<P extends string> = Partial<Record<P, RangeWindow>>
|
|
72
|
+
|
|
51
73
|
/** The value of a range field: one preset, plus two ISO dates when the preset is `'custom'`. */
|
|
52
74
|
export type RangeValue<P extends string> = {
|
|
53
75
|
preset: P
|
|
@@ -61,14 +83,14 @@ export type RangeParams = { preset?: string; from?: string; to?: string }
|
|
|
61
83
|
export type EnumField<T extends string = string, Ln extends ResolvedLane = ResolvedLane> = {
|
|
62
84
|
readonly kind: 'enum'
|
|
63
85
|
readonly values: readonly T[]
|
|
64
|
-
readonly fallback: T
|
|
86
|
+
readonly fallback: FieldFallback<T>
|
|
65
87
|
readonly lane: Ln
|
|
66
88
|
}
|
|
67
89
|
|
|
68
90
|
export type MultiField<T extends string = string, Ln extends ResolvedLane = ResolvedLane> = {
|
|
69
91
|
readonly kind: 'multi'
|
|
70
92
|
readonly values: readonly T[]
|
|
71
|
-
readonly fallback: readonly T[]
|
|
93
|
+
readonly fallback: FieldFallback<readonly T[]>
|
|
72
94
|
readonly lane: Ln
|
|
73
95
|
}
|
|
74
96
|
|
|
@@ -77,42 +99,65 @@ export type RangeField<
|
|
|
77
99
|
C extends boolean = boolean,
|
|
78
100
|
Pm extends RangeParams = RangeParams,
|
|
79
101
|
Ln extends ResolvedLane = ResolvedLane,
|
|
102
|
+
W extends string = never,
|
|
80
103
|
> = {
|
|
81
104
|
readonly kind: 'range'
|
|
82
105
|
/** The declared presets — `'custom'` is NOT one of them, it is `custom: true`'s consequence. */
|
|
83
106
|
readonly presets: readonly P[]
|
|
84
|
-
readonly fallback: RangeValue<P
|
|
107
|
+
readonly fallback: FieldFallback<RangeValue<P>>
|
|
85
108
|
/** `true` → the preset `'custom'` plus `from`/`to` ISO dates are legal values. */
|
|
86
109
|
readonly custom: C
|
|
87
110
|
readonly params: Pm
|
|
111
|
+
/**
|
|
112
|
+
* The declared window resolvers, keyed by preset — `W` is exactly the presets that HAVE one, so
|
|
113
|
+
* `toWindow`'s return type can drop them from its `{ window }` branch and an API param type
|
|
114
|
+
* accepts the result with no cast.
|
|
115
|
+
*
|
|
116
|
+
* `W` defaults to `never` (`window: {}`), which is what keeps every `RangeField<P>` assignable to
|
|
117
|
+
* the widened `AnyField` a control's props take: a narrower resolver map is assignable to `{}`,
|
|
118
|
+
* and a widened handle's `toWindow` then excludes nothing rather than everything.
|
|
119
|
+
*/
|
|
120
|
+
readonly window: RangeWindows<W>
|
|
88
121
|
readonly lane: Ln
|
|
89
122
|
}
|
|
90
123
|
|
|
91
124
|
/**
|
|
92
125
|
* The preset union a range field's VALUES range over: the declared presets, plus `'custom'` unless
|
|
93
|
-
* the field opted out.
|
|
94
|
-
*
|
|
126
|
+
* the field opted out.
|
|
127
|
+
*
|
|
128
|
+
* `C` widened to `boolean` (a bare `RangeField<P>`) keeps `'custom'` — but a PROP typed that way
|
|
129
|
+
* accepts only a custom-capable handle, because the handle's setter is contravariant in the value:
|
|
130
|
+
* `field.range` without `custom: true` hands out a `RangeField<P, false>`, whose setter refuses a
|
|
131
|
+
* `'custom'` preset. A wrapper that must take any range handle is generic over the flag
|
|
132
|
+
* (`<P extends string, C extends boolean>` + `FieldHandle<RangeField<P, C>>`); one that only ever
|
|
133
|
+
* takes the preset-only shape pins `RangeField<P, false>`.
|
|
95
134
|
*/
|
|
96
135
|
export type RangePresets<P, C> = (P & string) | (C extends false ? never : 'custom')
|
|
97
136
|
|
|
98
137
|
export type NumberField<Ln extends ResolvedLane = ResolvedLane> = {
|
|
99
138
|
readonly kind: 'number'
|
|
100
|
-
readonly fallback: number
|
|
139
|
+
readonly fallback: FieldFallback<number>
|
|
101
140
|
readonly min: number | undefined
|
|
102
141
|
readonly max: number | undefined
|
|
103
142
|
readonly int: boolean
|
|
143
|
+
/**
|
|
144
|
+
* The declared grain, ALREADY resolved — `field.number` fills in `1` for an `int: true` field
|
|
145
|
+
* that declared none, so the "an integer field steps by one" rule lives at that one call site and
|
|
146
|
+
* every reader (the handle, `NumberFilter`, `SliderControl`) reads a single answer.
|
|
147
|
+
*/
|
|
148
|
+
readonly step: number | undefined
|
|
104
149
|
readonly lane: Ln
|
|
105
150
|
}
|
|
106
151
|
|
|
107
152
|
export type BooleanField<Ln extends ResolvedLane = ResolvedLane> = {
|
|
108
153
|
readonly kind: 'boolean'
|
|
109
|
-
readonly fallback: boolean
|
|
154
|
+
readonly fallback: FieldFallback<boolean>
|
|
110
155
|
readonly lane: Ln
|
|
111
156
|
}
|
|
112
157
|
|
|
113
158
|
export type StringField<Ln extends ResolvedLane = ResolvedLane> = {
|
|
114
159
|
readonly kind: 'string'
|
|
115
|
-
readonly fallback: string
|
|
160
|
+
readonly fallback: FieldFallback<string>
|
|
116
161
|
readonly max: number | undefined
|
|
117
162
|
readonly lane: Ln
|
|
118
163
|
}
|
|
@@ -144,6 +189,31 @@ export type FieldValue<F extends AnyField> = F extends {
|
|
|
144
189
|
? string
|
|
145
190
|
: never
|
|
146
191
|
|
|
192
|
+
/**
|
|
193
|
+
* The second, optional argument of a `FieldHandle` setter.
|
|
194
|
+
*
|
|
195
|
+
* @example field.tab.use()[1]('overview', { patch: { detailDate: undefined } })
|
|
196
|
+
*/
|
|
197
|
+
export type FieldSetOptions = {
|
|
198
|
+
/**
|
|
199
|
+
* Extra search params merged into the SAME navigate as the field's own write — the URL lane only
|
|
200
|
+
* (a local/memory-lane write has no navigate to merge into, and ignores this). For keys the STORE
|
|
201
|
+
* DOES NOT OWN: clearing a sibling param the page put there (`{ detailDate: undefined }`) used to
|
|
202
|
+
* need a second `navigate` beside the setter, which either lost the field's write or produced two
|
|
203
|
+
* history entries. The field's own params always win, so a `patch` cannot corrupt the value being
|
|
204
|
+
* set.
|
|
205
|
+
*
|
|
206
|
+
* A key ANOTHER field of the same store owns is refused — it would reach the URL while the
|
|
207
|
+
* mirror kept the old value, so the next paramless visit and every `linkSearch` link disagree
|
|
208
|
+
* with the page the write happened on. `createSearchStore` throws in dev and logs in production;
|
|
209
|
+
* write that field through its own setter instead.
|
|
210
|
+
*
|
|
211
|
+
* A write from a route that does not validate the field persists only (A1) and drops the patch
|
|
212
|
+
* with it — there is no navigate to merge into. Dev warns once per field.
|
|
213
|
+
*/
|
|
214
|
+
readonly patch?: Record<string, unknown>
|
|
215
|
+
}
|
|
216
|
+
|
|
147
217
|
/** One option of an enum / multi / range field, labelled through `store.labels()`. */
|
|
148
218
|
export type FieldOption = { value: string; label: string }
|
|
149
219
|
|
|
@@ -152,18 +222,63 @@ type RangeHandleExtras<F> = F extends {
|
|
|
152
222
|
kind: 'range'
|
|
153
223
|
presets: readonly (infer P)[]
|
|
154
224
|
custom: infer C
|
|
225
|
+
window: RangeWindows<infer W>
|
|
155
226
|
}
|
|
156
227
|
? {
|
|
157
228
|
/**
|
|
158
229
|
* The API-facing projection of a range value: a preset becomes `{ window }`, a custom range
|
|
159
230
|
* becomes `{ from, to }`. Replaces every hand-rolled `presetToParams`.
|
|
231
|
+
*
|
|
232
|
+
* A preset declared with a `window` resolver (`field.range({ window: { '3m': ... } })`)
|
|
233
|
+
* becomes `{ from, to }` too — the resolver runs at CALL time with the current `Date`, so a
|
|
234
|
+
* derived window (`3m`, `ytd`) is never stale and never leaves the store.
|
|
235
|
+
*
|
|
236
|
+
* Those presets are EXCLUDED from the `{ window }` branch, so the result assigns to an API
|
|
237
|
+
* param type that only knows the server-understood windows with no cast — which is the half
|
|
238
|
+
* that lets a consumer delete the switch rather than move it. A `custom: true` field keeps
|
|
239
|
+
* `'custom'` in the union: a custom preset with no dates resolves to `{ window: 'custom' }`,
|
|
240
|
+
* so that one still needs a guard before it reaches such a type.
|
|
160
241
|
*/
|
|
161
242
|
readonly toWindow: (
|
|
162
243
|
v: RangeValue<RangePresets<P, C>>,
|
|
163
|
-
) => { window: RangePresets<P, C> } | { from: string; to: string }
|
|
244
|
+
) => { window: Exclude<RangePresets<P, C>, W> } | { from: string; to: string }
|
|
164
245
|
}
|
|
165
246
|
: { readonly toWindow?: undefined }
|
|
166
247
|
|
|
248
|
+
/**
|
|
249
|
+
* A number handle's declared bounds, republished from the field — `RangeHandleExtras`' shape for the
|
|
250
|
+
* numeric kind, and there for the same reason: a control cannot ask the field descriptor anything,
|
|
251
|
+
* it only ever sees the handle.
|
|
252
|
+
*
|
|
253
|
+
* The codec has always CLAMPED to these on write, so before this the only way a `NumberFilter` could
|
|
254
|
+
* learn its own limits was for the call site to pass them a second time — a second answer to a
|
|
255
|
+
* question the field already owns, and one that silently stops matching the moment the field moves.
|
|
256
|
+
* With them on the handle the input can bound its own stepper, which turns the clamp from a
|
|
257
|
+
* correction the user watches happen into a value they cannot type in the first place.
|
|
258
|
+
*
|
|
259
|
+
* `int` is the third member because it is the same class of fact: it decides whether the stepper
|
|
260
|
+
* refuses decimals, and the codec already rejects a non-integer for that field. `step` is the
|
|
261
|
+
* fourth for the same reason, and it is where the "an `int` field steps by one" rule is RESOLVED —
|
|
262
|
+
* once, in `field.number`, rather than re-derived by every control that draws a stepper or a track.
|
|
263
|
+
*/
|
|
264
|
+
type NumberHandleExtras<F> = F extends { kind: 'number' }
|
|
265
|
+
? {
|
|
266
|
+
/** The field's `min`, or `undefined` when it declared none. Clamped on write regardless. */
|
|
267
|
+
readonly min: number | undefined
|
|
268
|
+
/** The field's `max`, or `undefined` when it declared none. Clamped on write regardless. */
|
|
269
|
+
readonly max: number | undefined
|
|
270
|
+
/** `field.number({ int: true })` — a non-integer is refused by the codec, not rounded. */
|
|
271
|
+
readonly int: boolean
|
|
272
|
+
/** The field's `step`, `1` for an `int` field that declared none, else `undefined`. */
|
|
273
|
+
readonly step: number | undefined
|
|
274
|
+
}
|
|
275
|
+
: {
|
|
276
|
+
readonly min?: undefined
|
|
277
|
+
readonly max?: undefined
|
|
278
|
+
readonly int?: undefined
|
|
279
|
+
readonly step?: undefined
|
|
280
|
+
}
|
|
281
|
+
|
|
167
282
|
/**
|
|
168
283
|
* The binding every basalt control takes instead of `value`/`onChange` (C2). One field, both lanes,
|
|
169
284
|
* one resolution law. Handed out by `createSearchStore().field.<name>` /
|
|
@@ -179,12 +294,97 @@ export type FieldHandle<F extends AnyField> = {
|
|
|
179
294
|
* so a control renders on a sibling or child route with no `from`), else localStorage, else the
|
|
180
295
|
* fallback. Writes navigate when the matched route validates the param, then persist.
|
|
181
296
|
*/
|
|
182
|
-
use(): readonly [FieldValue<F>, (next: FieldValue<F
|
|
297
|
+
use(): readonly [FieldValue<F>, (next: FieldValue<F>, opts?: FieldSetOptions) => void]
|
|
298
|
+
/**
|
|
299
|
+
* UNSET the field — what a control's reset calls, and deliberately not `set(fallback)`. The
|
|
300
|
+
* persist lane DELETES the field's key from the mirror, the memory lane drops its value, and the
|
|
301
|
+
* URL lane navigates back to the fallback params (plus dropping the mirror key under it).
|
|
302
|
+
*
|
|
303
|
+
* Writing the fallback instead pins it: a THUNK fallback (`() => todayIso()`) resolves at the
|
|
304
|
+
* moment of the reset, so a reader who pressed `Reset all` today was handed today's date
|
|
305
|
+
* tomorrow, with the field counted as active in `Filters (n)`. Unsetting lets the fallback keep
|
|
306
|
+
* resolving, which is what `FieldFallback`'s contract says it does.
|
|
307
|
+
*
|
|
308
|
+
* Callable outside render (an event handler is the only realistic caller); on the URL lane it
|
|
309
|
+
* navigates through the last render of `use()`, so a handle that no mount has read clears the
|
|
310
|
+
* mirror only.
|
|
311
|
+
*/
|
|
312
|
+
clear(): void
|
|
183
313
|
isDefault(v: FieldValue<F>): boolean
|
|
184
|
-
} & RangeHandleExtras<F>
|
|
314
|
+
} & RangeHandleExtras<F> &
|
|
315
|
+
NumberHandleExtras<F>
|
|
185
316
|
|
|
186
317
|
// ── field.* — declarative field builders ──────────────────────────────────────────────────────
|
|
187
318
|
|
|
319
|
+
/**
|
|
320
|
+
* `field.range`'s options. `C` is the `custom` flag, pinned per overload — never inferred; `W` is
|
|
321
|
+
* inferred from `window`'s KEYS (constrained to the declared presets, so a typo is still an error
|
|
322
|
+
* here) and is what carries the resolved presets into `toWindow`'s return type.
|
|
323
|
+
*/
|
|
324
|
+
type RangeOptions<P extends string, C extends boolean, Pm extends RangeParams, W extends P> = {
|
|
325
|
+
presets: readonly P[]
|
|
326
|
+
fallback: FieldFallback<NoInfer<P>>
|
|
327
|
+
custom?: C
|
|
328
|
+
params?: Pm
|
|
329
|
+
/** Per-preset window resolvers — the presets `toWindow()` answers with `{ from, to }`. */
|
|
330
|
+
window?: RangeWindows<W>
|
|
331
|
+
}
|
|
332
|
+
|
|
333
|
+
/**
|
|
334
|
+
* A time window: THREE URL params (preset + `from` + `to`, each renamable through `params`), so a
|
|
335
|
+
* consumer's existing deep links and loaders keep their shape. `custom: true` additionally
|
|
336
|
+
* allows the preset `'custom'` with two ISO dates. `window` resolves a DERIVED preset (`3m`, `ytd`)
|
|
337
|
+
* to `{ from, to }` through `toWindow()` while it stays one preset in the URL.
|
|
338
|
+
*
|
|
339
|
+
* A second `field.range` in the same store — or a second range store composed into the same
|
|
340
|
+
* route's `validateSearch` — MUST rename `from`/`to` via `params`: every range defaults to the
|
|
341
|
+
* literal param names `'from'`/`'to'`, and two fields silently sharing them makes the later one's
|
|
342
|
+
* `toSearch` overwrite the earlier one's dates. `createStoreCore` throws at definition for the
|
|
343
|
+
* in-store case; the cross-store case is not detectable by either store alone.
|
|
344
|
+
*
|
|
345
|
+
* THREE overloads, one per `custom` shape, because a single `custom?: C` signature is inferred
|
|
346
|
+
* against `AnyField` when the call sits inline in `createSearchStore({ fields })` — the contextual
|
|
347
|
+
* return type wins, `C` widens to `boolean`, and every value type gains a `'custom'` preset the
|
|
348
|
+
* field never allowed. Overloads have no `C` to widen: an omitted or `false` flag picks the first,
|
|
349
|
+
* a literal `true` the second, and a value typed `boolean` the third (widened, as declared).
|
|
350
|
+
*/
|
|
351
|
+
function rangeField<
|
|
352
|
+
const P extends string,
|
|
353
|
+
const Pm extends RangeParams = RangeParams,
|
|
354
|
+
const L extends FieldLane = FieldLane,
|
|
355
|
+
const W extends P = never,
|
|
356
|
+
>(o: RangeOptions<P, false, Pm, W>, lane?: L): RangeField<P, false, Pm, ResolveLane<L>, W>
|
|
357
|
+
function rangeField<
|
|
358
|
+
const P extends string,
|
|
359
|
+
const Pm extends RangeParams = RangeParams,
|
|
360
|
+
const L extends FieldLane = FieldLane,
|
|
361
|
+
const W extends P = never,
|
|
362
|
+
>(o: RangeOptions<P, true, Pm, W>, lane?: L): RangeField<P, true, Pm, ResolveLane<L>, W>
|
|
363
|
+
function rangeField<
|
|
364
|
+
const P extends string,
|
|
365
|
+
const Pm extends RangeParams = RangeParams,
|
|
366
|
+
const L extends FieldLane = FieldLane,
|
|
367
|
+
const W extends P = never,
|
|
368
|
+
>(o: RangeOptions<P, boolean, Pm, W>, lane?: L): RangeField<P, boolean, Pm, ResolveLane<L>, W>
|
|
369
|
+
function rangeField(
|
|
370
|
+
o: RangeOptions<string, boolean, RangeParams, string>,
|
|
371
|
+
lane?: FieldLane,
|
|
372
|
+
): RangeField<string, boolean, RangeParams, ResolvedLane, string> {
|
|
373
|
+
const { fallback } = o
|
|
374
|
+
return {
|
|
375
|
+
kind: 'range',
|
|
376
|
+
presets: o.presets,
|
|
377
|
+
// A thunk fallback stays a thunk — wrapped so the lazy value is read at the same moment every
|
|
378
|
+
// other lane reads one, not once here at definition.
|
|
379
|
+
fallback:
|
|
380
|
+
typeof fallback === 'function' ? () => ({ preset: fallback() }) : { preset: fallback },
|
|
381
|
+
custom: o.custom ?? false,
|
|
382
|
+
params: o.params ?? {},
|
|
383
|
+
window: o.window ?? {},
|
|
384
|
+
lane: resolveLane(lane),
|
|
385
|
+
}
|
|
386
|
+
}
|
|
387
|
+
|
|
188
388
|
/**
|
|
189
389
|
* The field vocabulary. Every builder returns plain declarative data — no closures, no router, no
|
|
190
390
|
* storage — which is what lets one field definition drive `createSearchStore` (URL + storage) and
|
|
@@ -206,7 +406,7 @@ export const field = {
|
|
|
206
406
|
/** A closed string enum — a tab, a compare mode, a single-select filter. */
|
|
207
407
|
enum<const T extends string, const L extends FieldLane = FieldLane>(
|
|
208
408
|
values: readonly T[],
|
|
209
|
-
fallback: NoInfer<T
|
|
409
|
+
fallback: FieldFallback<NoInfer<T>>,
|
|
210
410
|
lane?: L,
|
|
211
411
|
): EnumField<T, ResolveLane<L>> {
|
|
212
412
|
return { kind: 'enum', values, fallback, lane: resolveLane(lane) as ResolveLane<L> }
|
|
@@ -215,47 +415,30 @@ export const field = {
|
|
|
215
415
|
/** An any-of set over the same closed enum. Decoding is deduped and canonically re-sorted. */
|
|
216
416
|
multi<const T extends string, const L extends FieldLane = FieldLane>(
|
|
217
417
|
values: readonly T[],
|
|
218
|
-
fallback: readonly NoInfer<T>[] = [],
|
|
418
|
+
fallback: FieldFallback<readonly NoInfer<T>[]> = [],
|
|
219
419
|
lane?: L,
|
|
220
420
|
): MultiField<T, ResolveLane<L>> {
|
|
221
421
|
return { kind: 'multi', values, fallback, lane: resolveLane(lane) as ResolveLane<L> }
|
|
222
422
|
},
|
|
223
423
|
|
|
424
|
+
range: rangeField,
|
|
425
|
+
|
|
224
426
|
/**
|
|
225
|
-
* A
|
|
226
|
-
* consumer's existing deep links and loaders keep their shape. `custom: true` additionally
|
|
227
|
-
* allows the preset `'custom'` with two ISO dates.
|
|
427
|
+
* A number — pagination, a threshold, a weight. Out-of-range input clamps to `min`/`max`.
|
|
228
428
|
*
|
|
229
|
-
*
|
|
230
|
-
*
|
|
231
|
-
*
|
|
232
|
-
* `
|
|
233
|
-
* in-store case; the cross-store case is not detectable by either store alone.
|
|
429
|
+
* `step` is the grain a stepper or a slider bound to this field moves by, and it is resolved
|
|
430
|
+
* HERE rather than at either control: an `int: true` field that declares no `step` steps by 1,
|
|
431
|
+
* which is the only sane grain for a field whose codec refuses a decimal — stating it once means
|
|
432
|
+
* `NumberFilter` and `SliderControl` cannot answer it differently.
|
|
234
433
|
*/
|
|
235
|
-
range<
|
|
236
|
-
const P extends string,
|
|
237
|
-
const C extends boolean = false,
|
|
238
|
-
const Pm extends RangeParams = RangeParams,
|
|
239
|
-
const L extends FieldLane = FieldLane,
|
|
240
|
-
>(
|
|
241
|
-
o: { presets: readonly P[]; fallback: NoInfer<P>; custom?: C; params?: Pm },
|
|
242
|
-
lane?: L,
|
|
243
|
-
): RangeField<P, C, Pm, ResolveLane<L>> {
|
|
244
|
-
return {
|
|
245
|
-
kind: 'range',
|
|
246
|
-
presets: o.presets,
|
|
247
|
-
fallback: { preset: o.fallback },
|
|
248
|
-
// The only cast left, and it is narrow: `C` is inferred from this very literal, so the
|
|
249
|
-
// runtime boolean IS `C` — `?? false` is what the compiler cannot see through.
|
|
250
|
-
custom: (o.custom ?? false) as C,
|
|
251
|
-
params: (o.params ?? {}) as Pm,
|
|
252
|
-
lane: resolveLane(lane) as ResolveLane<L>,
|
|
253
|
-
}
|
|
254
|
-
},
|
|
255
|
-
|
|
256
|
-
/** A number — pagination, a threshold. Out-of-range input clamps to `min`/`max`. */
|
|
257
434
|
number<const L extends FieldLane = FieldLane>(
|
|
258
|
-
o: {
|
|
435
|
+
o: {
|
|
436
|
+
fallback: FieldFallback<number>
|
|
437
|
+
min?: number
|
|
438
|
+
max?: number
|
|
439
|
+
int?: boolean
|
|
440
|
+
step?: number
|
|
441
|
+
},
|
|
259
442
|
lane?: L,
|
|
260
443
|
): NumberField<ResolveLane<L>> {
|
|
261
444
|
return {
|
|
@@ -264,13 +447,14 @@ export const field = {
|
|
|
264
447
|
min: o.min,
|
|
265
448
|
max: o.max,
|
|
266
449
|
int: o.int === true,
|
|
450
|
+
step: o.step ?? (o.int === true ? 1 : undefined),
|
|
267
451
|
lane: resolveLane(lane) as ResolveLane<L>,
|
|
268
452
|
}
|
|
269
453
|
},
|
|
270
454
|
|
|
271
455
|
/** A toggle. Accepts `true`/`false` and the strings `'true'`/`'false'` from a hand-typed URL. */
|
|
272
456
|
boolean<const L extends FieldLane = FieldLane>(
|
|
273
|
-
fallback: boolean
|
|
457
|
+
fallback: FieldFallback<boolean>,
|
|
274
458
|
lane?: L,
|
|
275
459
|
): BooleanField<ResolveLane<L>> {
|
|
276
460
|
return { kind: 'boolean', fallback, lane: resolveLane(lane) as ResolveLane<L> }
|
|
@@ -278,7 +462,7 @@ export const field = {
|
|
|
278
462
|
|
|
279
463
|
/** Free text — a search box. Defaults to `history: 'replace'` like every other field. */
|
|
280
464
|
string<const L extends FieldLane = FieldLane>(
|
|
281
|
-
o?: { fallback?: string
|
|
465
|
+
o?: { fallback?: FieldFallback<string>; max?: number },
|
|
282
466
|
lane?: L,
|
|
283
467
|
): StringField<ResolveLane<L>> {
|
|
284
468
|
return {
|
|
@@ -358,7 +542,25 @@ export type FieldCodec = {
|
|
|
358
542
|
* route does not, and a write there persists only (A1).
|
|
359
543
|
*/
|
|
360
544
|
readonly primary: string
|
|
545
|
+
/**
|
|
546
|
+
* The fallback, ALREADY resolved — a getter, because `field.*({ fallback: () => … })` is a thunk
|
|
547
|
+
* that must run at read time and re-run while nothing is written. Every call site reads it as a
|
|
548
|
+
* plain value, which is why the laziness is invisible past this line.
|
|
549
|
+
*/
|
|
361
550
|
readonly fallback: unknown
|
|
551
|
+
/** Range only: the per-preset window resolvers `toWindow` answers a derived preset through. */
|
|
552
|
+
readonly windows?: RangeWindows<string>
|
|
553
|
+
/**
|
|
554
|
+
* Number only: the declared bounds and grain the codec clamps to, republished so `handle` can put
|
|
555
|
+
* them on the handle. The codec is the only thing that reads the field descriptor, so a control
|
|
556
|
+
* that needs a limit has to be handed it from here — see {@link NumberHandleExtras}.
|
|
557
|
+
*/
|
|
558
|
+
readonly bounds?: {
|
|
559
|
+
readonly min: number | undefined
|
|
560
|
+
readonly max: number | undefined
|
|
561
|
+
readonly int: boolean
|
|
562
|
+
readonly step: number | undefined
|
|
563
|
+
}
|
|
362
564
|
/**
|
|
363
565
|
* Validate a STORED (or caller-supplied) value. `null` = unusable.
|
|
364
566
|
*
|
|
@@ -376,6 +578,14 @@ export type FieldCodec = {
|
|
|
376
578
|
readonly optionValues: readonly string[]
|
|
377
579
|
}
|
|
378
580
|
|
|
581
|
+
/**
|
|
582
|
+
* Resolve a possibly-lazy fallback. `typeof === 'function'` is an exact discriminator here: no field
|
|
583
|
+
* kind has a function as a legal VALUE, so a function can only ever be the thunk form.
|
|
584
|
+
*/
|
|
585
|
+
function resolveFallback(raw: unknown): unknown {
|
|
586
|
+
return typeof raw === 'function' ? (raw as () => unknown)() : raw
|
|
587
|
+
}
|
|
588
|
+
|
|
379
589
|
const ISO_DATE_RE = /^\d{4}-\d{2}-\d{2}(?:T[\d:.]+(?:Z|[+-]\d{2}:\d{2})?)?$/
|
|
380
590
|
|
|
381
591
|
function isIsoDate(raw: unknown): raw is string {
|
|
@@ -467,7 +677,10 @@ export function resolveFieldCodec(
|
|
|
467
677
|
lane: f.lane,
|
|
468
678
|
params: [presetParam, fromParam, toParam],
|
|
469
679
|
primary: presetParam,
|
|
470
|
-
fallback
|
|
680
|
+
get fallback() {
|
|
681
|
+
return resolveFallback(f.fallback)
|
|
682
|
+
},
|
|
683
|
+
windows: f.window,
|
|
471
684
|
decode,
|
|
472
685
|
fromSearch: (search) =>
|
|
473
686
|
decode({
|
|
@@ -507,7 +720,13 @@ export function resolveFieldCodec(
|
|
|
507
720
|
if (f.max !== undefined && value > f.max) value = f.max
|
|
508
721
|
return value
|
|
509
722
|
}
|
|
510
|
-
|
|
723
|
+
// The same values the clamp above reads (plus the already-resolved `step`), handed on so the
|
|
724
|
+
// CONTROL can bound its input rather than watch the clamp correct it after the fact. Threaded
|
|
725
|
+
// THROUGH `single` rather than spread onto its result: `fallback` is a getter, and a spread
|
|
726
|
+
// would evaluate it once here and freeze a thunk fallback at definition.
|
|
727
|
+
return single(name, f, decode, {
|
|
728
|
+
bounds: { min: f.min, max: f.max, int: f.int, step: f.step },
|
|
729
|
+
})
|
|
511
730
|
}
|
|
512
731
|
case 'boolean': {
|
|
513
732
|
return single(name, f, decodeBoolean)
|
|
@@ -525,7 +744,14 @@ export function resolveFieldCodec(
|
|
|
525
744
|
}
|
|
526
745
|
}
|
|
527
746
|
|
|
528
|
-
/**
|
|
747
|
+
/**
|
|
748
|
+
* Codec shell for every kind that owns exactly one URL param.
|
|
749
|
+
*
|
|
750
|
+
* NEVER spread the returned object: `fallback` is a GETTER over a possibly-lazy fallback, and an
|
|
751
|
+
* object spread evaluates it once and copies the result as a plain value — which froze the number
|
|
752
|
+
* kind's thunk fallback at store definition for one minor. Anything a kind needs to add goes
|
|
753
|
+
* through `extra`.
|
|
754
|
+
*/
|
|
529
755
|
function single(
|
|
530
756
|
name: string,
|
|
531
757
|
f: AnyField,
|
|
@@ -535,6 +761,8 @@ function single(
|
|
|
535
761
|
equals?: (a: unknown, b: unknown) => boolean
|
|
536
762
|
/** URL-side decoder when it differs from the storage-side one (multi, legacy layout only). */
|
|
537
763
|
decodeUrl?: (raw: unknown) => unknown
|
|
764
|
+
/** Number only: the declared bounds and grain, republished onto the handle. */
|
|
765
|
+
bounds?: FieldCodec['bounds']
|
|
538
766
|
},
|
|
539
767
|
): FieldCodec {
|
|
540
768
|
const decodeUrl = extra?.decodeUrl ?? decode
|
|
@@ -543,7 +771,10 @@ function single(
|
|
|
543
771
|
lane: f.lane,
|
|
544
772
|
params: [name],
|
|
545
773
|
primary: name,
|
|
546
|
-
fallback
|
|
774
|
+
get fallback() {
|
|
775
|
+
return resolveFallback(f.fallback)
|
|
776
|
+
},
|
|
777
|
+
...(extra?.bounds !== undefined && { bounds: extra.bounds }),
|
|
547
778
|
decode,
|
|
548
779
|
fromSearch: (search) => decodeUrl(search[name]),
|
|
549
780
|
toSearch: (value) => ({ [name]: value }),
|
|
@@ -556,6 +787,17 @@ function single(
|
|
|
556
787
|
|
|
557
788
|
type StoreRecord = Record<string, unknown>
|
|
558
789
|
|
|
790
|
+
/**
|
|
791
|
+
* A field's write, untyped — the shape both factories build and `handle` hands out. `opts` is the
|
|
792
|
+
* public `FieldSetOptions`; only the URL lane can act on it.
|
|
793
|
+
*
|
|
794
|
+
* @internal — see `FieldCodec`.
|
|
795
|
+
*/
|
|
796
|
+
export type FieldWrite = (next: unknown, opts?: FieldSetOptions) => void
|
|
797
|
+
|
|
798
|
+
/** One field's `use()`, untyped. @internal — see `FieldCodec`. */
|
|
799
|
+
export type FieldUse = () => readonly [unknown, FieldWrite]
|
|
800
|
+
|
|
559
801
|
/** One named field plus its codec, in declaration order. @internal — see `FieldCodec`. */
|
|
560
802
|
export type StoreEntry = { readonly name: string; readonly codec: FieldCodec }
|
|
561
803
|
|
|
@@ -594,19 +836,25 @@ export type StoreCore = {
|
|
|
594
836
|
* Lives here rather than in either factory because BOTH have such a field: `createLocalStore`'s
|
|
595
837
|
* `persist: false`, and `createSearchStore`'s `{ url: false, persist: false }`.
|
|
596
838
|
*/
|
|
597
|
-
memoryUse(entry: StoreEntry):
|
|
839
|
+
memoryUse(entry: StoreEntry): FieldUse
|
|
598
840
|
/** The memory lane's value for one field, resolved — its fallback while nothing was written. */
|
|
599
841
|
readMemoryValue(entry: StoreEntry): unknown
|
|
600
842
|
/** Subscribes to the whole memory lane. The snapshot is a write counter, so it is always stable. */
|
|
601
843
|
useMemoryVersion(): number
|
|
602
844
|
/** Drops every memory value, so the next read resolves to the fallback. What `useReset` calls. */
|
|
603
845
|
resetMemory(): void
|
|
846
|
+
/**
|
|
847
|
+
* Deletes ONE field's key from the localStorage record, so the next read falls through to the
|
|
848
|
+
* live fallback. Not a hook: `FieldHandle.clear()` runs in an event handler, where the persisted
|
|
849
|
+
* setter from `usePersistedRecord()` is not in reach — it writes through the same envelope and
|
|
850
|
+
* wakes the same per-key listeners (`writePersistedValue`).
|
|
851
|
+
*/
|
|
852
|
+
clearField(name: string): void
|
|
853
|
+
/** The memory lane's half of the same: drops ONE field's value. */
|
|
854
|
+
clearMemory(name: string): void
|
|
604
855
|
/** Every stored field, flattened into URL-param shape, `undefined` entries dropped. */
|
|
605
856
|
readStoredFlat(): StoreRecord
|
|
606
|
-
handle(
|
|
607
|
-
entry: StoreEntry,
|
|
608
|
-
use: () => readonly [unknown, (next: unknown) => void],
|
|
609
|
-
): FieldHandle<AnyField>
|
|
857
|
+
handle(entry: StoreEntry, use: FieldUse, clear: () => void): FieldHandle<AnyField>
|
|
610
858
|
}
|
|
611
859
|
|
|
612
860
|
function isRecord(raw: unknown): raw is StoreRecord {
|
|
@@ -650,6 +898,7 @@ function createMemoryLane(): {
|
|
|
650
898
|
getVersion: () => number
|
|
651
899
|
resolve: (entry: StoreEntry) => unknown
|
|
652
900
|
write: (name: string, value: unknown) => void
|
|
901
|
+
remove: (name: string) => void
|
|
653
902
|
clear: () => void
|
|
654
903
|
} {
|
|
655
904
|
const values = new Map<string, unknown>()
|
|
@@ -679,6 +928,10 @@ function createMemoryLane(): {
|
|
|
679
928
|
values.set(name, value)
|
|
680
929
|
bump()
|
|
681
930
|
},
|
|
931
|
+
remove: (name) => {
|
|
932
|
+
if (!values.delete(name)) return
|
|
933
|
+
bump()
|
|
934
|
+
},
|
|
682
935
|
clear: () => {
|
|
683
936
|
if (values.size === 0) return
|
|
684
937
|
values.clear()
|
|
@@ -744,6 +997,14 @@ export function createStoreCore(o: StoreCoreOptions): StoreCore {
|
|
|
744
997
|
return entry.codec.optionValues.map((value) => ({ value, label: map?.[value] ?? value }))
|
|
745
998
|
}
|
|
746
999
|
|
|
1000
|
+
const clearField = (name: string): void => {
|
|
1001
|
+
const record = readRecord()
|
|
1002
|
+
if (!Object.hasOwn(record, name)) return
|
|
1003
|
+
const next = { ...record }
|
|
1004
|
+
delete next[name]
|
|
1005
|
+
writePersistedValue(o.key, version, fromRecord(next))
|
|
1006
|
+
}
|
|
1007
|
+
|
|
747
1008
|
const writeField = (
|
|
748
1009
|
setRecord: (next: StoreRecord) => void,
|
|
749
1010
|
name: string,
|
|
@@ -754,30 +1015,50 @@ export function createStoreCore(o: StoreCoreOptions): StoreCore {
|
|
|
754
1015
|
setRecord({ ...readRecord(), [name]: value })
|
|
755
1016
|
}
|
|
756
1017
|
|
|
757
|
-
const handle = (
|
|
758
|
-
entry: StoreEntry,
|
|
759
|
-
use: () => readonly [unknown, (next: unknown) => void],
|
|
760
|
-
): FieldHandle<AnyField> => {
|
|
1018
|
+
const handle = (entry: StoreEntry, use: FieldUse, clear: () => void): FieldHandle<AnyField> => {
|
|
761
1019
|
const { codec } = entry
|
|
762
1020
|
const built: Record<string, unknown> = {
|
|
763
1021
|
kind: codec.kind,
|
|
764
|
-
fallback: codec.fallback,
|
|
765
1022
|
use,
|
|
1023
|
+
clear,
|
|
766
1024
|
isDefault: (v: unknown) => codec.equals(v, codec.fallback),
|
|
767
1025
|
}
|
|
768
1026
|
if (codec.kind === 'range') {
|
|
769
|
-
built['toWindow'] = (v: RangeValue<string>) =>
|
|
770
|
-
v.preset === 'custom' && v.from !== undefined && v.to !== undefined
|
|
771
|
-
|
|
772
|
-
|
|
1027
|
+
built['toWindow'] = (v: RangeValue<string>) => {
|
|
1028
|
+
if (v.preset === 'custom' && v.from !== undefined && v.to !== undefined) {
|
|
1029
|
+
return { from: v.from, to: v.to }
|
|
1030
|
+
}
|
|
1031
|
+
// `Object.hasOwn`, not a bare lookup: a preset named like an Object.prototype member
|
|
1032
|
+
// (`toString`) would otherwise resolve to that method and be CALLED.
|
|
1033
|
+
const windows = codec.windows
|
|
1034
|
+
if (windows !== undefined && Object.hasOwn(windows, v.preset)) {
|
|
1035
|
+
const resolver = windows[v.preset]
|
|
1036
|
+
if (resolver !== undefined) return resolver(new Date())
|
|
1037
|
+
}
|
|
1038
|
+
return { window: v.preset }
|
|
1039
|
+
}
|
|
1040
|
+
}
|
|
1041
|
+
if (codec.kind === 'number') {
|
|
1042
|
+
// Plain properties, not getters: unlike `options` (relabelled by `labels()` after the handles
|
|
1043
|
+
// exist) and `fallback` (possibly a thunk), a field's bounds are fixed at definition.
|
|
1044
|
+
const bounds = codec.bounds
|
|
1045
|
+
built['min'] = bounds?.min
|
|
1046
|
+
built['max'] = bounds?.max
|
|
1047
|
+
built['int'] = bounds?.int ?? false
|
|
1048
|
+
built['step'] = bounds?.step
|
|
773
1049
|
}
|
|
774
|
-
//
|
|
1050
|
+
// GETTERS, not snapshots, and installed with defineProperty rather than declared in the
|
|
775
1051
|
// literal: `labels()` runs on the store after the handles exist, and an object spread would
|
|
776
|
-
// evaluate the getter once at spread time and freeze the unlabelled options.
|
|
1052
|
+
// evaluate the getter once at spread time and freeze the unlabelled options. `fallback` is a
|
|
1053
|
+
// getter for the same class of reason — a lazy fallback is resolved per read, not per handle.
|
|
777
1054
|
Object.defineProperty(built, 'options', {
|
|
778
1055
|
enumerable: true,
|
|
779
1056
|
get: (): readonly FieldOption[] => optionsFor(entry),
|
|
780
1057
|
})
|
|
1058
|
+
Object.defineProperty(built, 'fallback', {
|
|
1059
|
+
enumerable: true,
|
|
1060
|
+
get: (): unknown => codec.fallback,
|
|
1061
|
+
})
|
|
781
1062
|
return built as unknown as FieldHandle<AnyField>
|
|
782
1063
|
}
|
|
783
1064
|
|
|
@@ -802,6 +1083,8 @@ export function createStoreCore(o: StoreCoreOptions): StoreCore {
|
|
|
802
1083
|
useMemoryVersion: () =>
|
|
803
1084
|
useSyncExternalStore(memory.subscribe, memory.getVersion, memory.getVersion),
|
|
804
1085
|
resetMemory: () => memory.clear(),
|
|
1086
|
+
clearField,
|
|
1087
|
+
clearMemory: (name) => memory.remove(name),
|
|
805
1088
|
setLabels(map) {
|
|
806
1089
|
for (const [name, entry] of Object.entries(map)) {
|
|
807
1090
|
if (entry !== undefined) labels.set(name, entry)
|
|
@@ -848,6 +1131,10 @@ export type LocalStore<S extends Record<string, AnyField>> = {
|
|
|
848
1131
|
* That is the honest home for a value a reader should not be handed back tomorrow (a scratch
|
|
849
1132
|
* comparison, a temporary drill-down) without dropping to `useState` and losing the handle.
|
|
850
1133
|
*
|
|
1134
|
+
* A fallback may be a THUNK (`field.string({ fallback: () => todayIso() })`) — resolved at read
|
|
1135
|
+
* time, re-resolved while nothing is written, and never persisted on its own. Every lane here
|
|
1136
|
+
* qualifies; `createSearchStore` allows it off the URL lane only, and throws otherwise.
|
|
1137
|
+
*
|
|
851
1138
|
* @example
|
|
852
1139
|
* const chart = createLocalStore({
|
|
853
1140
|
* key: 'momentum-chart',
|
|
@@ -875,8 +1162,12 @@ export function createLocalStore<const S extends Record<string, AnyField>>(o: {
|
|
|
875
1162
|
|
|
876
1163
|
const field = {} as { [K in keyof S]: FieldHandle<S[K]> }
|
|
877
1164
|
for (const entry of core.entries) {
|
|
878
|
-
const
|
|
879
|
-
|
|
1165
|
+
const persisted = entry.codec.lane.persist
|
|
1166
|
+
const use = persisted ? persistedUse(entry) : core.memoryUse(entry)
|
|
1167
|
+
const clear = persisted ? () => core.clearField(entry.name) : () => core.clearMemory(entry.name)
|
|
1168
|
+
field[entry.name as keyof S] = core.handle(entry, use, clear) as unknown as FieldHandle<
|
|
1169
|
+
S[keyof S]
|
|
1170
|
+
>
|
|
880
1171
|
}
|
|
881
1172
|
|
|
882
1173
|
const store: LocalStore<S> = {
|