basalt-ui 1.27.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 +59 -0
- package/MIGRATING.md +613 -20
- package/README.md +33 -3
- package/agent/rules/basalt-batteries.md +25 -10
- package/agent/rules/basalt-controls.md +56 -31
- package/agent/rules/basalt-mantine.md +17 -6
- package/agent/rules/basalt-tokens.md +1 -1
- package/configs/oxlint-plugin.js +1056 -28
- package/configs/oxlint-plugin.test.ts +1066 -0
- package/configs/oxlint.json +7 -0
- 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 +3 -2
- package/dist/controls/enum-filter.d.ts.map +1 -1
- package/dist/controls/enum-filter.js +28 -13
- package/dist/controls/filter-context.d.ts +8 -4
- 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 +2 -0
- package/dist/controls/index.d.ts.map +1 -1
- package/dist/controls/index.js +4 -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 +122 -20
- package/dist/controls/number-filter.d.ts +7 -5
- package/dist/controls/number-filter.d.ts.map +1 -1
- package/dist/controls/number-filter.js +40 -11
- 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 +2 -1
- package/dist/controls/range-filter.d.ts.map +1 -1
- package/dist/controls/range-filter.js +57 -35
- 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 +25 -10
- 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 +28 -11
- 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 +7 -1
- 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 +44 -38
- package/dist/dashboard/stat-card.d.ts.map +1 -1
- package/dist/dashboard/stat-card.js +55 -42
- package/dist/dashboard/stat-card.module.css +46 -31
- package/dist/dashboard/stat-card.module.css.d.ts +1 -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 +384 -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.map +1 -1
- package/dist/guard/index.js +26 -6
- 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/search-store.d.ts.map +1 -1
- package/dist/router-tanstack/search-store.js +1 -1
- 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 +23 -3
- package/dist/state/fields.d.ts.map +1 -1
- package/dist/state/fields.js +13 -2
- 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.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 +42 -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 +69 -4
- package/dist/widget-header/widget-header.d.ts.map +1 -1
- package/dist/widget-header/widget-header.js +42 -27
- package/dist/widget-header/widget-header.module.css +72 -7
- 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 +32 -16
- package/src/controls/filter-context.tsx +14 -6
- 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 +7 -0
- package/src/controls/multi-select-filter.tsx +177 -27
- package/src/controls/number-filter.tsx +61 -23
- 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 +76 -39
- package/src/controls/search-filter.tsx +30 -12
- 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 +36 -16
- 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 +13 -1
- package/src/dashboard/query-state.tsx +154 -84
- package/src/dashboard/settings-section.tsx +87 -31
- package/src/dashboard/stat-card.module.css +46 -31
- package/src/dashboard/stat-card.module.css.d.ts +1 -0
- package/src/dashboard/stat-card.tsx +185 -127
- 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 +919 -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 +73 -18
- package/src/index.ts +74 -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 +1 -0
- package/src/router-tanstack/search-store.ts +3 -10
- 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 +43 -10
- package/src/state/persisted-or-local.ts +50 -0
- package/src/state.ts +0 -9
- package/src/surfaces.ts +42 -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 +72 -7
- package/src/widget-header/widget-header.tsx +150 -71
- 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/range-filter.type-guard.test.d.ts +0 -2
- package/dist/controls/range-filter.type-guard.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/state/persisted.test.d.ts +0 -2
- package/dist/state/persisted.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 -1053
- 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 -137
- package/src/controls/range-filter.type-guard.test.tsx +0 -122
- 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 -385
- package/src/data/data-table.test.tsx +0 -434
- package/src/guard/check-source.test.ts +0 -3388
- package/src/guard/grace.test.ts +0 -158
- 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 -882
- package/src/router-tanstack/search-store.test.ts +0 -578
- 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 -512
- package/src/state/persisted.test.ts +0 -91
- 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
|
@@ -1,10 +1,24 @@
|
|
|
1
1
|
import type { CSSProperties, ReactNode } from 'react'
|
|
2
2
|
import { useCallback, useState } from 'react'
|
|
3
|
+
import type { BasaltProps } from '../../common/props'
|
|
4
|
+
import { VX } from '../../tokens'
|
|
3
5
|
import { useChartSize } from '../hooks/useChartSize'
|
|
4
6
|
import { deriveLegend } from '../series'
|
|
5
7
|
import type { ChartLegendConfig, LegendPlacement, SeriesStyle } from '../series'
|
|
8
|
+
import {
|
|
9
|
+
chartTierMetrics,
|
|
10
|
+
legendEntryCap,
|
|
11
|
+
resolveChartTier,
|
|
12
|
+
resolvePlotRect,
|
|
13
|
+
} from './chart-frame-layout'
|
|
14
|
+
import { ChartTierProvider } from './chart-tier'
|
|
6
15
|
import { ChartLegend } from './ChartLegend'
|
|
7
|
-
import { ChartPending } from './ChartPending'
|
|
16
|
+
import { ChartEmpty, ChartError, ChartPending, resolveChartState } from './ChartPending'
|
|
17
|
+
import type { ChartState } from './ChartPending'
|
|
18
|
+
|
|
19
|
+
/** Re-exported for `ChartFrame.test.tsx` and any other consumer that previously reached these
|
|
20
|
+
* through `ChartFrame` — the layout math itself lives in `./chart-frame-layout` (pure, DOM-free). */
|
|
21
|
+
export { legendEntryCap, resolvePlotRect, resolveChartTier } from './chart-frame-layout'
|
|
8
22
|
|
|
9
23
|
const DEFAULT_HEIGHT = 240
|
|
10
24
|
const DEFAULT_MIN_WIDTH = 200
|
|
@@ -30,7 +44,7 @@ export type ChartFrameLegend = {
|
|
|
30
44
|
toggle?: boolean
|
|
31
45
|
}
|
|
32
46
|
|
|
33
|
-
export type ChartFrameProps = {
|
|
47
|
+
export type ChartFrameProps = BasaltProps & {
|
|
34
48
|
/** Series identity — drives the derived legend. Pass the SAME array the kind draws + tooltips from. */
|
|
35
49
|
series: readonly SeriesStyle[]
|
|
36
50
|
/** Fixed height in pixels. Used when neither `aspectRatio` nor `fill` is set. Default 240. */
|
|
@@ -50,8 +64,19 @@ export type ChartFrameProps = {
|
|
|
50
64
|
* three-state "nothing to draw" rationale) over the full plot rect in place of `children`,
|
|
51
65
|
* suppresses the legend entirely (a legend naming a series with nothing yet to point at is its
|
|
52
66
|
* own small lie), and marks the outer container `aria-busy="true"`.
|
|
67
|
+
*
|
|
68
|
+
* An alias for `state={{ pending: true }}` and staying that way — it predates {@link ChartState}
|
|
69
|
+
* and every kind forwards it.
|
|
53
70
|
*/
|
|
54
71
|
isPending?: boolean
|
|
72
|
+
/**
|
|
73
|
+
* The three "nothing to draw" states in one prop — the shape a query result already has. Wins
|
|
74
|
+
* over `isPending`, which stays a supported alias for `state={{ pending: true }}`. Precedence is
|
|
75
|
+
* pending → error → empty ({@link resolveChartState}); each renders its own placeholder over the
|
|
76
|
+
* full plot rect in place of `children` and suppresses the legend, and only `pending` marks the
|
|
77
|
+
* container `aria-busy`.
|
|
78
|
+
*/
|
|
79
|
+
state?: ChartState
|
|
55
80
|
/**
|
|
56
81
|
* Accessible text alternative for the chart, applied as `aria-label` (+ `role="group"`) on the
|
|
57
82
|
* outer container so screen readers announce something other than an unlabeled graphic. Every
|
|
@@ -102,12 +127,22 @@ export type ChartFrameLegendHover = {
|
|
|
102
127
|
* is the one merge every kind performs: consumer `placement`/`groups`/`maxRows` (or the defaults)
|
|
103
128
|
* plus the kind's `highlighted`/`onHighlight`, which a consumer may not set directly.
|
|
104
129
|
* `config === false` disables the legend regardless of `hover` (the sparkline escape).
|
|
130
|
+
*
|
|
131
|
+
* A single-entry legend is pure noise — it only ever restates the chart's own title ("— BTC
|
|
132
|
+
* price" under a chart already titled "BTC price"), costs a legend row of vertical space, and its
|
|
133
|
+
* one toggle can blank the whole plot. So when `seriesCount` is passed, is `<= 1`, AND the caller
|
|
134
|
+
* passed no explicit config (`undefined` — NOT `{}`, which is a deliberate opt-in), the legend is
|
|
135
|
+
* suppressed automatically. `config === undefined` is the load-bearing check: a kind that composes
|
|
136
|
+
* `ChartFrame` directly without threading `seriesCount` through (e.g. `DualPanel`) simply omits
|
|
137
|
+
* the third argument and keeps today's behaviour.
|
|
105
138
|
*/
|
|
106
139
|
export function resolveLegend(
|
|
107
140
|
config: ChartLegendConfig | false | undefined,
|
|
108
141
|
hover?: ChartFrameLegendHover,
|
|
142
|
+
seriesCount?: number,
|
|
109
143
|
): ChartFrameLegend | false {
|
|
110
144
|
if (config === false) return false
|
|
145
|
+
if (config === undefined && seriesCount !== undefined && seriesCount <= 1) return false
|
|
111
146
|
return {
|
|
112
147
|
placement: config?.placement ?? 'bottom',
|
|
113
148
|
...(config?.groups !== undefined && { groups: config.groups }),
|
|
@@ -124,7 +159,9 @@ export function resolveLegend(
|
|
|
124
159
|
* rect via a second, independent `useChartSize` on the legend's own wrapper div. The legend
|
|
125
160
|
* `<div>` wraps (`ChartLegend`'s `flexWrap`), so its measured band grows as entries wrap and the
|
|
126
161
|
* plot shrinks accordingly — the plot can never overlap the legend because the legend's measured
|
|
127
|
-
* band is always subtracted first.
|
|
162
|
+
* band is always subtracted first. It also can never shrink to nothing: {@link resolvePlotRect}
|
|
163
|
+
* floors it at `VX.minPlotHeight` and the frame grows, or under `fill` the legend rolls up
|
|
164
|
+
* ({@link legendEntryCap}).
|
|
128
165
|
*
|
|
129
166
|
* Layout-only: it does not know lines from bars (that stays in the kind), so it is not a
|
|
130
167
|
* Recharts god-component. Render the child only when the resolved plot rect is non-empty.
|
|
@@ -139,6 +176,9 @@ export function ChartFrame({
|
|
|
139
176
|
legend = {},
|
|
140
177
|
ariaLabel,
|
|
141
178
|
isPending = false,
|
|
179
|
+
state,
|
|
180
|
+
className,
|
|
181
|
+
style,
|
|
142
182
|
children,
|
|
143
183
|
}: ChartFrameProps): ReactNode {
|
|
144
184
|
const { ref: containerRef, width: containerW, height: containerH } = useChartSize()
|
|
@@ -156,7 +196,11 @@ export function ChartFrame({
|
|
|
156
196
|
|
|
157
197
|
const placement = legend === false ? 'bottom' : (legend.placement ?? 'bottom')
|
|
158
198
|
const vertical = placement === 'left' || placement === 'right'
|
|
159
|
-
|
|
199
|
+
// Every non-null state replaces the plot, and all three suppress the legend for one reason: a
|
|
200
|
+
// legend naming a series with nothing to point at is its own small lie.
|
|
201
|
+
const resolvedState = resolveChartState({ ...(state !== undefined && { state }), isPending })
|
|
202
|
+
const legendVisible = legend !== false && resolvedState === null
|
|
203
|
+
const tier = resolveChartTier(containerW)
|
|
160
204
|
|
|
161
205
|
const resolvedHeight = fill
|
|
162
206
|
? containerH
|
|
@@ -167,16 +211,46 @@ export function ChartFrame({
|
|
|
167
211
|
const sideLegendWidth = legendVisible && vertical ? legendW : 0
|
|
168
212
|
const topBottomLegendHeight = legendVisible && !vertical ? legendH : 0
|
|
169
213
|
|
|
170
|
-
const plot = {
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
214
|
+
const plot = resolvePlotRect({
|
|
215
|
+
containerW,
|
|
216
|
+
resolvedHeight,
|
|
217
|
+
minWidth,
|
|
218
|
+
sideLegendWidth,
|
|
219
|
+
topBottomLegendHeight,
|
|
220
|
+
})
|
|
174
221
|
|
|
175
222
|
const legendItems = legend === false ? [] : deriveLegend(series)
|
|
176
223
|
const togglable = legend !== false && (legend.toggle ?? legendItems.length > 1)
|
|
177
224
|
|
|
225
|
+
// A fixed-height frame grows around its legend; a `fill` one cannot, so its legend rolls up
|
|
226
|
+
// instead of eating the plot (see `legendEntryCap`). Top/bottom only — a side legend costs
|
|
227
|
+
// width, not height.
|
|
228
|
+
// The tier's own cap folds in as an upper bound BEFORE the fill measurement, so a phone-width
|
|
229
|
+
// `fill` frame can only ever roll up further, never less (`chartTierMetrics`).
|
|
230
|
+
const tierMaxRows = chartTierMetrics(tier).legendMaxRows
|
|
231
|
+
const callerMaxRows =
|
|
232
|
+
legend === false
|
|
233
|
+
? undefined
|
|
234
|
+
: legend.maxRows === undefined
|
|
235
|
+
? tierMaxRows
|
|
236
|
+
: tierMaxRows === undefined
|
|
237
|
+
? legend.maxRows
|
|
238
|
+
: Math.min(legend.maxRows, tierMaxRows)
|
|
239
|
+
|
|
240
|
+
const maxRows =
|
|
241
|
+
legend === false
|
|
242
|
+
? undefined
|
|
243
|
+
: fill && !vertical
|
|
244
|
+
? legendEntryCap({
|
|
245
|
+
items: legendItems,
|
|
246
|
+
containerW,
|
|
247
|
+
available: resolvedHeight - VX.minPlotHeight,
|
|
248
|
+
...(callerMaxRows !== undefined && { callerMaxRows }),
|
|
249
|
+
})
|
|
250
|
+
: callerMaxRows
|
|
251
|
+
|
|
178
252
|
const legendNode =
|
|
179
|
-
legend === false ||
|
|
253
|
+
legend === false || resolvedState !== null ? null : (
|
|
180
254
|
<div ref={legendRef} style={legendWrapperStyle(vertical)}>
|
|
181
255
|
<ChartLegend
|
|
182
256
|
items={legendItems}
|
|
@@ -185,7 +259,7 @@ export function ChartFrame({
|
|
|
185
259
|
{...(togglable && { onToggle: toggleKey })}
|
|
186
260
|
{...(chartId !== undefined && { chartId })}
|
|
187
261
|
{...(legend.groups !== undefined && { groups: legend.groups })}
|
|
188
|
-
{...(
|
|
262
|
+
{...(maxRows !== undefined && { maxRows })}
|
|
189
263
|
{...(legend.highlighted !== undefined && { highlighted: legend.highlighted })}
|
|
190
264
|
{...(legend.onHighlight !== undefined && { onHighlight: legend.onHighlight })}
|
|
191
265
|
/>
|
|
@@ -193,21 +267,28 @@ export function ChartFrame({
|
|
|
193
267
|
)
|
|
194
268
|
|
|
195
269
|
return (
|
|
196
|
-
<
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
|
|
208
|
-
|
|
209
|
-
|
|
210
|
-
|
|
211
|
-
|
|
270
|
+
<ChartTierProvider tier={tier}>
|
|
271
|
+
<div
|
|
272
|
+
ref={containerRef}
|
|
273
|
+
{...(className !== undefined && { className })}
|
|
274
|
+
style={{ ...outerStyle(fill, vertical), ...style }}
|
|
275
|
+
{...(ariaLabel !== undefined && { role: 'group', 'aria-label': ariaLabel })}
|
|
276
|
+
{...(resolvedState === 'pending' && { 'aria-busy': 'true' })}
|
|
277
|
+
>
|
|
278
|
+
{legendNode !== null && (placement === 'top' || placement === 'left') && legendNode}
|
|
279
|
+
{plot.width > 0 &&
|
|
280
|
+
plot.height > 0 &&
|
|
281
|
+
(resolvedState === 'pending' ? (
|
|
282
|
+
<ChartPending width={plot.width} height={plot.height} />
|
|
283
|
+
) : resolvedState === 'error' ? (
|
|
284
|
+
<ChartError width={plot.width} height={plot.height} error={state?.error} />
|
|
285
|
+
) : resolvedState === 'empty' ? (
|
|
286
|
+
<ChartEmpty width={plot.width} height={plot.height} />
|
|
287
|
+
) : (
|
|
288
|
+
children({ ...plot, hidden })
|
|
289
|
+
))}
|
|
290
|
+
{legendNode !== null && (placement === 'bottom' || placement === 'right') && legendNode}
|
|
291
|
+
</div>
|
|
292
|
+
</ChartTierProvider>
|
|
212
293
|
)
|
|
213
294
|
}
|
|
@@ -1,6 +1,9 @@
|
|
|
1
1
|
import type { CSSProperties, FocusEvent, MouseEvent, ReactNode } from 'react'
|
|
2
|
-
import {
|
|
2
|
+
import { useState } from 'react'
|
|
3
|
+
import type { BasaltProps } from '../../common/props'
|
|
4
|
+
import { alpha, VX } from '../../tokens'
|
|
3
5
|
import type { SeriesRole, LegendPlacement } from '../series'
|
|
6
|
+
import { useChartTierMetrics } from './chart-tier'
|
|
4
7
|
|
|
5
8
|
export type LegendEntry = {
|
|
6
9
|
key: string
|
|
@@ -74,7 +77,7 @@ function orderEntries(
|
|
|
74
77
|
return { entries, dividerAfter }
|
|
75
78
|
}
|
|
76
79
|
|
|
77
|
-
function wrapperStyle(placement: LegendPlacement): CSSProperties {
|
|
80
|
+
function wrapperStyle(placement: LegendPlacement, fontSize: number): CSSProperties {
|
|
78
81
|
const vertical = placement === 'left' || placement === 'right'
|
|
79
82
|
return {
|
|
80
83
|
display: 'flex',
|
|
@@ -85,7 +88,7 @@ function wrapperStyle(placement: LegendPlacement): CSSProperties {
|
|
|
85
88
|
columnGap: VX.legendGap,
|
|
86
89
|
rowGap: VX.legendGap,
|
|
87
90
|
padding: '8px 0 2px',
|
|
88
|
-
fontSize
|
|
91
|
+
fontSize,
|
|
89
92
|
color: VX.muted,
|
|
90
93
|
}
|
|
91
94
|
}
|
|
@@ -258,7 +261,17 @@ function LegendChild({ item }: { item: LegendEntry }) {
|
|
|
258
261
|
*
|
|
259
262
|
* `onToggle` makes an entry a real toggle: clicking it hides the series in the plot, the tooltip,
|
|
260
263
|
* and the auto y-domain together (`ChartFrame` owns the `hidden` set — see `docs/CHARTS-SPEC.md`
|
|
261
|
-
* §5).
|
|
264
|
+
* §5).
|
|
265
|
+
*
|
|
266
|
+
* The label font and the DEFAULT entry cap both track the ambient chart tier (§8): inside a
|
|
267
|
+
* phone-width `ChartFrame` the legend drops one type step and rolls up past two entries. An
|
|
268
|
+
* explicit `maxRows` always wins. Omit it for a static legend; a hidden entry is announced via `aria-pressed`.
|
|
269
|
+
*
|
|
270
|
+
* **The rollup is a disclosure, not a label.** A cap of two leaves six of eight plotted colours
|
|
271
|
+
* unnamed, and a `+6 more` that is a `<span>` gives a phone reader no way to learn them — a
|
|
272
|
+
* categorical encoding the chart draws and refuses to decode. The chip is a `<button>` carrying
|
|
273
|
+
* `aria-expanded`: expanded, every entry renders, the legend band grows, and `ChartFrame`'s
|
|
274
|
+
* observer re-flows the frame around it (the plot keeps `VX.minPlotHeight`).
|
|
262
275
|
*/
|
|
263
276
|
export function ChartLegend({
|
|
264
277
|
items,
|
|
@@ -270,7 +283,9 @@ export function ChartLegend({
|
|
|
270
283
|
placement = 'bottom',
|
|
271
284
|
groups = false,
|
|
272
285
|
maxRows,
|
|
273
|
-
|
|
286
|
+
className,
|
|
287
|
+
style,
|
|
288
|
+
}: BasaltProps & {
|
|
274
289
|
items: LegendEntry[]
|
|
275
290
|
highlighted?: string | null
|
|
276
291
|
onHighlight?: (key: string | null) => void
|
|
@@ -283,6 +298,8 @@ export function ChartLegend({
|
|
|
283
298
|
groups?: boolean
|
|
284
299
|
maxRows?: number
|
|
285
300
|
}) {
|
|
301
|
+
const tier = useChartTierMetrics()
|
|
302
|
+
const [expanded, setExpanded] = useState(false)
|
|
286
303
|
const handleEnter = (e: MouseEvent<HTMLButtonElement> | FocusEvent<HTMLButtonElement>) => {
|
|
287
304
|
const key = e.currentTarget.dataset['legendKey']
|
|
288
305
|
if (key !== undefined) onHighlight?.(key)
|
|
@@ -296,9 +313,9 @@ export function ChartLegend({
|
|
|
296
313
|
const idPrefix = chartId ? `${chartId}-` : ''
|
|
297
314
|
const vertical = placement === 'left' || placement === 'right'
|
|
298
315
|
const { entries, dividerAfter } = orderEntries(items, groups)
|
|
299
|
-
const
|
|
300
|
-
|
|
301
|
-
const
|
|
316
|
+
const cap = maxRows ?? tier.legendMaxRows
|
|
317
|
+
const rolledUp = cap === undefined ? 0 : Math.max(entries.length - cap, 0)
|
|
318
|
+
const visible = rolledUp > 0 && !expanded ? entries.slice(0, cap) : entries
|
|
302
319
|
|
|
303
320
|
const nodes: ReactNode[] = []
|
|
304
321
|
visible.forEach((item, i) => {
|
|
@@ -340,13 +357,26 @@ export function ChartLegend({
|
|
|
340
357
|
if (dividerAfter.has(i))
|
|
341
358
|
nodes.push(<LegendDivider key={`divider-${item.key}`} columnLayout={vertical} />)
|
|
342
359
|
})
|
|
343
|
-
if (
|
|
360
|
+
if (rolledUp > 0) {
|
|
344
361
|
nodes.push(
|
|
345
|
-
<
|
|
346
|
-
|
|
347
|
-
|
|
362
|
+
<button
|
|
363
|
+
key="legend-more"
|
|
364
|
+
type="button"
|
|
365
|
+
aria-expanded={expanded}
|
|
366
|
+
onClick={() => setExpanded((prev) => !prev)}
|
|
367
|
+
style={{ ...LEGEND_ITEM_BUTTON, cursor: 'pointer', textDecoration: 'underline' }}
|
|
368
|
+
>
|
|
369
|
+
{expanded ? 'Show less' : `+${rolledUp} more`}
|
|
370
|
+
</button>,
|
|
348
371
|
)
|
|
349
372
|
}
|
|
350
373
|
|
|
351
|
-
return
|
|
374
|
+
return (
|
|
375
|
+
<div
|
|
376
|
+
{...(className !== undefined && { className })}
|
|
377
|
+
style={{ ...wrapperStyle(placement, tier.legendFontSize), ...style }}
|
|
378
|
+
>
|
|
379
|
+
{nodes}
|
|
380
|
+
</div>
|
|
381
|
+
)
|
|
352
382
|
}
|
|
@@ -1,7 +1,8 @@
|
|
|
1
1
|
import type { CSSProperties, ReactNode } from 'react'
|
|
2
|
+
import type { BasaltProps } from '../../common/props'
|
|
2
3
|
import { VX } from '../../tokens'
|
|
3
4
|
|
|
4
|
-
export type ChartCenterProps = {
|
|
5
|
+
export type ChartCenterProps = BasaltProps & {
|
|
5
6
|
width: number
|
|
6
7
|
height: number
|
|
7
8
|
children: ReactNode
|
|
@@ -21,11 +22,24 @@ const centerStyle = (width: number, height: number): CSSProperties => ({
|
|
|
21
22
|
* there was previously nothing to reach for when a chart file needed to center something. Not a
|
|
22
23
|
* general layout system — width, height, children, nothing else.
|
|
23
24
|
*/
|
|
24
|
-
export function ChartCenter({
|
|
25
|
-
|
|
25
|
+
export function ChartCenter({
|
|
26
|
+
width,
|
|
27
|
+
height,
|
|
28
|
+
className,
|
|
29
|
+
style,
|
|
30
|
+
children,
|
|
31
|
+
}: ChartCenterProps): ReactNode {
|
|
32
|
+
return (
|
|
33
|
+
<div
|
|
34
|
+
{...(className !== undefined && { className })}
|
|
35
|
+
style={{ ...centerStyle(width, height), ...style }}
|
|
36
|
+
>
|
|
37
|
+
{children}
|
|
38
|
+
</div>
|
|
39
|
+
)
|
|
26
40
|
}
|
|
27
41
|
|
|
28
|
-
export type ChartPendingProps = {
|
|
42
|
+
export type ChartPendingProps = BasaltProps & {
|
|
29
43
|
width: number
|
|
30
44
|
height: number
|
|
31
45
|
/** Default `'Loading…'`. */
|
|
@@ -49,11 +63,175 @@ const labelStyle: CSSProperties = {
|
|
|
49
63
|
* measurement — no axes, no gridlines, no hatching, no data marks — just a faint, static, centered
|
|
50
64
|
* label. No animation: the package's motion doctrine bans looping/pulsing idle motion, so a static
|
|
51
65
|
* reserved box is the correct answer here, not a compromise.
|
|
66
|
+
*
|
|
67
|
+
* The label is `role="status"` (polite), so a screen reader hears the chart resolve through all
|
|
68
|
+
* three states rather than only its failure: `ChartError` was `role="alert"` and its two siblings
|
|
69
|
+
* were silent, which announced the one outcome and swallowed the other two. Polite, not assertive —
|
|
70
|
+
* a loading placeholder must not interrupt what the reader is already being told.
|
|
52
71
|
*/
|
|
53
|
-
export function ChartPending({
|
|
72
|
+
export function ChartPending({
|
|
73
|
+
width,
|
|
74
|
+
height,
|
|
75
|
+
label = 'Loading…',
|
|
76
|
+
className,
|
|
77
|
+
style,
|
|
78
|
+
}: ChartPendingProps): ReactNode {
|
|
79
|
+
return (
|
|
80
|
+
<ChartCenter
|
|
81
|
+
width={width}
|
|
82
|
+
height={height}
|
|
83
|
+
{...(className !== undefined && { className })}
|
|
84
|
+
{...(style !== undefined && { style })}
|
|
85
|
+
>
|
|
86
|
+
{/* `<output>` is the tag oxlint suggests, and it is the wrong one: it means "the result of
|
|
87
|
+
a calculation", owns form semantics (`form`/`name`/`for`), and this box is precisely the
|
|
88
|
+
state in which there IS no result yet. A polite live region on a plain span is the
|
|
89
|
+
standard pattern. */}
|
|
90
|
+
{/* oxlint-disable-next-line jsx-a11y/prefer-tag-over-role */}
|
|
91
|
+
<span style={labelStyle} role="status">
|
|
92
|
+
{label}
|
|
93
|
+
</span>
|
|
94
|
+
</ChartCenter>
|
|
95
|
+
)
|
|
96
|
+
}
|
|
97
|
+
|
|
98
|
+
/**
|
|
99
|
+
* The three "nothing to draw" states a chart can be in, in ONE prop — the shape a
|
|
100
|
+
* `@tanstack/react-query` result (or anything derived from one) already has.
|
|
101
|
+
*
|
|
102
|
+
* It exists because the answer that already existed, `dashboard/QueryState`, renders Mantine and
|
|
103
|
+
* therefore cannot be reached from `./charts` at all (the Mantine-free boundary). A chart consumer
|
|
104
|
+
* without that import was left writing the four-way branch by hand, which is the exact bug
|
|
105
|
+
* `QueryState` was built for: the shape suggests `empty` and a 500 renders "No data".
|
|
106
|
+
*
|
|
107
|
+
* Precedence is fixed and is the whole product: **pending → error → empty**. A refetch that is
|
|
108
|
+
* both in flight and carrying a stale error is pending, not failed; a query that errored has no
|
|
109
|
+
* standing to claim its result was empty.
|
|
110
|
+
*/
|
|
111
|
+
export type ChartState = {
|
|
112
|
+
/** The query has not resolved yet. Wins over every other flag. */
|
|
113
|
+
pending?: boolean
|
|
114
|
+
/** Truthy = the query failed. Any thrown value; an `Error`'s `message` is used as the label. */
|
|
115
|
+
error?: unknown
|
|
116
|
+
/** The query resolved and there is genuinely nothing to plot. */
|
|
117
|
+
empty?: boolean
|
|
118
|
+
}
|
|
119
|
+
|
|
120
|
+
/** Which placeholder {@link ChartState} resolves to, or `null` to draw the chart. */
|
|
121
|
+
export type ResolvedChartState = 'pending' | 'error' | 'empty' | null
|
|
122
|
+
|
|
123
|
+
/**
|
|
124
|
+
* Resolve {@link ChartState} (plus the older standalone `isPending` flag, which stays a supported
|
|
125
|
+
* alias) into the ONE placeholder to render. Pure and exported so a hand-composed plot applies the
|
|
126
|
+
* same precedence rather than re-deriving it.
|
|
127
|
+
*/
|
|
128
|
+
export function resolveChartState(input: {
|
|
129
|
+
state?: ChartState
|
|
130
|
+
isPending?: boolean
|
|
131
|
+
}): ResolvedChartState {
|
|
132
|
+
const { state, isPending } = input
|
|
133
|
+
if (isPending === true || state?.pending === true) return 'pending'
|
|
134
|
+
if (state?.error !== undefined && state.error !== null && state.error !== false) return 'error'
|
|
135
|
+
if (state?.empty === true) return 'empty'
|
|
136
|
+
return null
|
|
137
|
+
}
|
|
138
|
+
|
|
139
|
+
export type ChartEmptyProps = BasaltProps & {
|
|
140
|
+
width: number
|
|
141
|
+
height: number
|
|
142
|
+
/** Default `'No data'`. */
|
|
143
|
+
label?: string
|
|
144
|
+
/** Optional affordance under the label — a "clear filters" button, a range reset. Rendered as
|
|
145
|
+
* given: this layer is Mantine-free, so the caller owns whatever it puts here. */
|
|
146
|
+
action?: ReactNode
|
|
147
|
+
}
|
|
148
|
+
|
|
149
|
+
const stackStyle: CSSProperties = {
|
|
150
|
+
display: 'flex',
|
|
151
|
+
flexDirection: 'column',
|
|
152
|
+
alignItems: 'center',
|
|
153
|
+
gap: 8,
|
|
154
|
+
}
|
|
155
|
+
|
|
156
|
+
/**
|
|
157
|
+
* Measured and EMPTY — the query resolved and there is nothing to plot. Distinct from
|
|
158
|
+
* {@link ChartPending} ("not asked yet") and from a hatched absence ("watched, measured nothing"):
|
|
159
|
+
* collapsing any of the three into another is the honesty bug this trio exists to prevent.
|
|
160
|
+
*
|
|
161
|
+
* Same footprint discipline as `ChartPending`: it reserves the plot rect and draws nothing that
|
|
162
|
+
* could be read as a measurement — no axes, no gridlines, no marks. Announced `role="status"`
|
|
163
|
+
* (polite) like `ChartPending`, so the resolution is heard; only `ChartError` is an `alert`.
|
|
164
|
+
*/
|
|
165
|
+
export function ChartEmpty({
|
|
166
|
+
width,
|
|
167
|
+
height,
|
|
168
|
+
label = 'No data',
|
|
169
|
+
action,
|
|
170
|
+
className,
|
|
171
|
+
style,
|
|
172
|
+
}: ChartEmptyProps): ReactNode {
|
|
173
|
+
return (
|
|
174
|
+
<ChartCenter
|
|
175
|
+
width={width}
|
|
176
|
+
height={height}
|
|
177
|
+
{...(className !== undefined && { className })}
|
|
178
|
+
{...(style !== undefined && { style })}
|
|
179
|
+
>
|
|
180
|
+
{/* Same waiver, same reason, as `ChartPending` — see the comment there. */}
|
|
181
|
+
{/* oxlint-disable-next-line jsx-a11y/prefer-tag-over-role */}
|
|
182
|
+
<span style={stackStyle} role="status">
|
|
183
|
+
<span style={labelStyle}>{label}</span>
|
|
184
|
+
{action}
|
|
185
|
+
</span>
|
|
186
|
+
</ChartCenter>
|
|
187
|
+
)
|
|
188
|
+
}
|
|
189
|
+
|
|
190
|
+
export type ChartErrorProps = BasaltProps & {
|
|
191
|
+
width: number
|
|
192
|
+
height: number
|
|
193
|
+
/** Overrides the text outright. Omitted, an `Error`'s own `message` is used, else
|
|
194
|
+
* `'Could not load chart'` — a failure never borrows the empty state's copy. */
|
|
195
|
+
label?: string
|
|
196
|
+
/** The thrown value, used for the default label. */
|
|
197
|
+
error?: unknown
|
|
198
|
+
/** Optional affordance under the label — typically a retry. */
|
|
199
|
+
action?: ReactNode
|
|
200
|
+
}
|
|
201
|
+
|
|
202
|
+
/** The message an unknown thrown value gets to state for itself. Kept local rather than importing
|
|
203
|
+
* `./query`'s `toErrorMessage`: `./charts` resolves with no other basalt subpath installed, and a
|
|
204
|
+
* chart placeholder needs one line, not the HTTP-status vocabulary that helper carries. */
|
|
205
|
+
function errorLabel(error: unknown): string {
|
|
206
|
+
if (error instanceof Error && error.message !== '') return error.message
|
|
207
|
+
if (typeof error === 'string' && error !== '') return error
|
|
208
|
+
return 'Could not load chart'
|
|
209
|
+
}
|
|
210
|
+
|
|
211
|
+
/**
|
|
212
|
+
* Measured and FAILED. The branch a hand-written chart switch reliably gets wrong — a 500 rendered
|
|
213
|
+
* as "No data" is a positive claim that the server answered and had nothing, which it did not.
|
|
214
|
+
*/
|
|
215
|
+
export function ChartError({
|
|
216
|
+
width,
|
|
217
|
+
height,
|
|
218
|
+
label,
|
|
219
|
+
error,
|
|
220
|
+
action,
|
|
221
|
+
className,
|
|
222
|
+
style,
|
|
223
|
+
}: ChartErrorProps): ReactNode {
|
|
54
224
|
return (
|
|
55
|
-
<ChartCenter
|
|
56
|
-
|
|
225
|
+
<ChartCenter
|
|
226
|
+
width={width}
|
|
227
|
+
height={height}
|
|
228
|
+
{...(className !== undefined && { className })}
|
|
229
|
+
{...(style !== undefined && { style })}
|
|
230
|
+
>
|
|
231
|
+
<span style={stackStyle} role="alert">
|
|
232
|
+
<span style={labelStyle}>{label ?? errorLabel(error)}</span>
|
|
233
|
+
{action}
|
|
234
|
+
</span>
|
|
57
235
|
</ChartCenter>
|
|
58
236
|
)
|
|
59
237
|
}
|
|
@@ -1,8 +1,9 @@
|
|
|
1
1
|
import type { CSSProperties, ReactNode } from 'react'
|
|
2
|
-
import { useLayoutEffect, useRef, useState } from 'react'
|
|
2
|
+
import { useLayoutEffect, useRef, useState, useSyncExternalStore } from 'react'
|
|
3
3
|
import { createPortal } from 'react-dom'
|
|
4
4
|
import { VX } from '../../tokens'
|
|
5
5
|
import { fmtTooltipDate } from '../utils/format'
|
|
6
|
+
import { useChartTierMetrics } from './chart-tier'
|
|
6
7
|
|
|
7
8
|
// Panel bg + shadow-card, radius 8 (docs/DESIGN-SPEC.md §5's "Tooltip/popover/menu" idiom) — the
|
|
8
9
|
// same depth-via-shadow treatment as ChartCard, never a `border` property. Surfaces resolve per
|
|
@@ -18,7 +19,6 @@ const TOOLTIP_STYLES: CSSProperties = {
|
|
|
18
19
|
lineHeight: '18px',
|
|
19
20
|
color: VX.ink,
|
|
20
21
|
boxShadow: VX.shadowCard,
|
|
21
|
-
minWidth: 140,
|
|
22
22
|
}
|
|
23
23
|
|
|
24
24
|
/** Tooltip header — shows formatted date + optional right-aligned label with color. */
|
|
@@ -140,6 +140,21 @@ export function TooltipBody({ children }: { children: ReactNode }) {
|
|
|
140
140
|
return <div style={{ padding: '5px 0' }}>{children}</div>
|
|
141
141
|
}
|
|
142
142
|
|
|
143
|
+
/**
|
|
144
|
+
* "Am I on the client?", answered SYNCHRONOUSLY and hydration-safely.
|
|
145
|
+
*
|
|
146
|
+
* `useSyncExternalStore` is the one hook whose server snapshot React honours during BOTH
|
|
147
|
+
* `renderToString` and the hydration pass, so the server sees `false` and the client's very first
|
|
148
|
+
* render already sees `true` — no effect, no extra frame, and therefore no one-frame flash of a
|
|
149
|
+
* missing tooltip on a hover that has already happened. An `useEffect`-set flag would be correct
|
|
150
|
+
* on the server and a render late on the client. The store never emits, so nothing ever
|
|
151
|
+
* re-subscribes.
|
|
152
|
+
*/
|
|
153
|
+
const neverSubscribe = () => () => {}
|
|
154
|
+
const onClient = () => true
|
|
155
|
+
const onServer = () => false
|
|
156
|
+
const useIsClient = (): boolean => useSyncExternalStore(neverSubscribe, onClient, onServer)
|
|
157
|
+
|
|
143
158
|
/** Gap between the anchor point and the tooltip box, and the minimum distance kept from the
|
|
144
159
|
* viewport edge. */
|
|
145
160
|
const TOOLTIP_GAP = 12
|
|
@@ -152,6 +167,13 @@ const VIEWPORT_MARGIN = 8
|
|
|
152
167
|
*
|
|
153
168
|
* The box is measured after mount via `useLayoutEffect`, so the first paint of a given tooltip is
|
|
154
169
|
* hidden rather than misplaced — a tooltip that flashes at the wrong corner reads as a bug.
|
|
170
|
+
*
|
|
171
|
+
* **It renders NOTHING on the server.** `createPortal` throws outright in `react-dom/server`
|
|
172
|
+
* ("Portals are not currently supported by the server renderer"), and an unconditional portal made
|
|
173
|
+
* this the single component in the package that could not be server-rendered. The guard is
|
|
174
|
+
* {@link useIsClient}, not a `typeof document` check: under a DOM-preloaded test runner `document`
|
|
175
|
+
* exists while `renderToString` still refuses portals. A tooltip is a hover artifact with nothing
|
|
176
|
+
* to emit server-side, so rendering nothing is the whole fix, not a degradation.
|
|
155
177
|
*/
|
|
156
178
|
export function ChartTooltipFloat({
|
|
157
179
|
anchor,
|
|
@@ -168,6 +190,8 @@ export function ChartTooltipFloat({
|
|
|
168
190
|
}) {
|
|
169
191
|
const ref = useRef<HTMLDivElement>(null)
|
|
170
192
|
const [box, setBox] = useState<{ width: number; height: number } | null>(null)
|
|
193
|
+
const isClient = useIsClient()
|
|
194
|
+
const { tooltipMinWidth } = useChartTierMetrics()
|
|
171
195
|
|
|
172
196
|
useLayoutEffect(() => {
|
|
173
197
|
const el = ref.current
|
|
@@ -181,8 +205,10 @@ export function ChartTooltipFloat({
|
|
|
181
205
|
}, [children, anchor])
|
|
182
206
|
|
|
183
207
|
if (anchor === null) return null
|
|
184
|
-
// SSR guard
|
|
185
|
-
|
|
208
|
+
// The SSR guard — see the component doc. A `typeof document` check does NOT cover this: under a
|
|
209
|
+
// jsdom/happy-dom-preloaded test runner `document` exists while `renderToString` still refuses
|
|
210
|
+
// portals, which is exactly how this shipped.
|
|
211
|
+
if (!isClient) return null
|
|
186
212
|
|
|
187
213
|
const width = box?.width ?? 0
|
|
188
214
|
const height = box?.height ?? 0
|
|
@@ -203,7 +229,13 @@ export function ChartTooltipFloat({
|
|
|
203
229
|
ref={ref}
|
|
204
230
|
role="tooltip"
|
|
205
231
|
{...(ariaLive && { 'aria-live': 'polite' as const })}
|
|
206
|
-
style={{
|
|
232
|
+
style={{
|
|
233
|
+
...TOOLTIP_STYLES,
|
|
234
|
+
minWidth: tooltipMinWidth,
|
|
235
|
+
left,
|
|
236
|
+
top,
|
|
237
|
+
visibility: box === null ? 'hidden' : 'visible',
|
|
238
|
+
}}
|
|
207
239
|
>
|
|
208
240
|
{children}
|
|
209
241
|
</div>,
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import type { ReactNode } from 'react'
|
|
2
2
|
import { VX } from '../../tokens'
|
|
3
|
+
import { useChartTierMetrics } from './chart-tier'
|
|
3
4
|
|
|
4
5
|
/**
|
|
5
6
|
* The shared vertical hover crosshair — one implementation for what used to be five hand-rolled
|
|
@@ -22,6 +23,9 @@ export function Crosshair({
|
|
|
22
23
|
/**
|
|
23
24
|
* The punched-out hover marker: a filled circle whose stroke is the chart background color, so it
|
|
24
25
|
* reads as a "hole" cut into the line on both themes. Centralizes the `dotStroke = chart-bg` trick.
|
|
26
|
+
*
|
|
27
|
+
* The default radius tracks the ambient chart tier (`docs/CHARTS-SPEC.md` §8) — an explicit `r`
|
|
28
|
+
* (a `getMarker`'s own radius) still wins.
|
|
25
29
|
*/
|
|
26
30
|
export function SeriesDot({
|
|
27
31
|
cx,
|
|
@@ -34,7 +38,6 @@ export function SeriesDot({
|
|
|
34
38
|
color: string
|
|
35
39
|
r?: number
|
|
36
40
|
}): ReactNode {
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
)
|
|
41
|
+
const { dotR } = useChartTierMetrics()
|
|
42
|
+
return <circle cx={cx} cy={cy} r={r ?? dotR} fill={color} stroke={VX.dotStroke} strokeWidth={2} />
|
|
40
43
|
}
|