basalt-ui 1.40.3 → 2.0.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 +50 -45
- package/CHANGELOG.md +543 -513
- package/MIGRATING.md +969 -37
- package/README.md +172 -367
- package/agent/rules/basalt-batteries.md +19 -74
- package/agent/rules/basalt-charts.md +21 -95
- package/agent/rules/basalt-controls.md +23 -131
- package/agent/rules/basalt-mantine.md +26 -99
- package/agent/rules/basalt-state.md +21 -103
- package/agent/rules/basalt-tokens.md +33 -114
- package/agent/skills/basalt-app/SKILL.md +229 -72
- package/agent/skills/basalt-charts/SKILL.md +23 -57
- package/agent/skills/basalt-design/SKILL.md +12 -70
- package/agent/templates/AGENTS-block.md.tpl +30 -0
- package/agent/templates/DESIGN.md.tpl +2 -2
- package/agent/templates/__root.tpl +9 -16
- package/agent/templates/main.tpl +21 -0
- package/agent/templates/nav.tpl +18 -0
- package/configs/check.yml +1 -1
- package/configs/oxlint-basalt.json +4 -10
- package/configs/oxlint-plugin.js +468 -847
- package/configs/oxlint-plugin.test.ts +662 -710
- package/configs/oxlint.json +10 -2
- package/dist/agent/ai-sdk-transport.d.ts +19 -7
- package/dist/agent/ai-sdk-transport.d.ts.map +1 -1
- package/dist/agent/ai-sdk-transport.js +10 -7
- package/dist/{agent-chat → agent/chat}/composer.d.ts +16 -16
- package/dist/agent/chat/composer.d.ts.map +1 -0
- package/dist/{agent-chat → agent/chat}/composer.js +10 -9
- package/dist/{agent-chat → agent/chat}/message-affordances.d.ts +7 -6
- package/dist/agent/chat/message-affordances.d.ts.map +1 -0
- package/dist/agent/chat/relative-time.d.ts.map +1 -0
- package/dist/{agent-chat → agent/chat}/thread-feed-row.d.ts +18 -16
- package/dist/agent/chat/thread-feed-row.d.ts.map +1 -0
- package/dist/{agent-chat → agent/chat}/thread-feed-row.js +12 -11
- package/dist/{agent-chat → agent/chat}/thread-feed.d.ts +8 -8
- package/dist/agent/chat/thread-feed.d.ts.map +1 -0
- package/dist/{agent-chat → agent/chat}/thread-feed.js +12 -10
- package/dist/{agent-chat → agent/chat}/thread-message.d.ts +12 -9
- package/dist/agent/chat/thread-message.d.ts.map +1 -0
- package/dist/{agent-chat → agent/chat}/thread-message.js +15 -13
- package/dist/{agent-chat → agent/chat}/thread-outcome-card.d.ts +2 -2
- package/dist/agent/chat/thread-outcome-card.d.ts.map +1 -0
- package/dist/{agent-chat → agent/chat}/thread-outcome-card.js +3 -3
- package/dist/{agent-chat → agent/chat}/tool-chip.d.ts +5 -5
- package/dist/agent/chat/tool-chip.d.ts.map +1 -0
- package/dist/{agent-chat → agent/chat}/tool-chip.js +4 -4
- package/dist/agent/chat/use-keyboard-inset.d.ts.map +1 -0
- package/dist/{agent-chat → agent/chat}/use-keyboard-inset.js +1 -1
- package/dist/{agent-chat → agent/chat}/virtualize.d.ts +7 -7
- package/dist/agent/chat/virtualize.d.ts.map +1 -0
- package/dist/agent/error.d.ts +31 -0
- package/dist/agent/error.d.ts.map +1 -0
- package/dist/agent/error.js +18 -0
- package/dist/agent/foreign.d.ts +3 -2
- package/dist/agent/foreign.d.ts.map +1 -1
- package/dist/agent/history.d.ts +2 -36
- package/dist/agent/history.d.ts.map +1 -1
- package/dist/agent/history.js +0 -32
- package/dist/agent/id.d.ts +4 -5
- package/dist/agent/id.d.ts.map +1 -1
- package/dist/agent/index.d.ts +19 -52
- package/dist/agent/index.d.ts.map +1 -1
- package/dist/agent/index.js +10 -32
- package/dist/agent/outcome.d.ts +3 -14
- package/dist/agent/outcome.d.ts.map +1 -1
- package/dist/agent/outcome.js +0 -30
- package/dist/agent/part-list.d.ts +3 -3
- package/dist/agent/part-list.d.ts.map +1 -1
- package/dist/agent/parts.d.ts +23 -24
- package/dist/agent/parts.d.ts.map +1 -1
- package/dist/agent/run-committer.d.ts +23 -0
- package/dist/agent/run-committer.d.ts.map +1 -0
- package/dist/agent/run-committer.js +41 -0
- package/dist/agent/run-records.d.ts +77 -0
- package/dist/agent/run-records.d.ts.map +1 -0
- package/dist/agent/run-records.js +69 -0
- package/dist/agent/thread.d.ts +23 -47
- package/dist/agent/thread.d.ts.map +1 -1
- package/dist/agent/thread.js +3 -134
- package/dist/agent/transport.d.ts +6 -69
- package/dist/agent/transport.d.ts.map +1 -1
- package/dist/agent/transport.js +0 -18
- package/dist/agent/use-agent-thread-runs.d.ts +63 -26
- package/dist/agent/use-agent-thread-runs.d.ts.map +1 -1
- package/dist/agent/use-agent-thread-runs.js +202 -66
- package/dist/charts/BandStrip.d.ts +46 -0
- package/dist/charts/BandStrip.d.ts.map +1 -0
- package/dist/charts/BandStrip.js +151 -0
- package/dist/charts/Bars.d.ts +19 -0
- package/dist/charts/Bars.d.ts.map +1 -0
- package/dist/charts/Bars.js +77 -0
- package/dist/charts/CartesianChart.d.ts +57 -0
- package/dist/charts/CartesianChart.d.ts.map +1 -0
- package/dist/charts/CartesianChart.js +121 -0
- package/dist/charts/ChartCard.d.ts +34 -0
- package/dist/charts/ChartCard.d.ts.map +1 -0
- package/dist/charts/ChartCard.js +115 -0
- package/dist/charts/Donut.d.ts +25 -0
- package/dist/charts/Donut.d.ts.map +1 -0
- package/dist/charts/Donut.js +191 -0
- package/dist/charts/DualPanel.d.ts +47 -0
- package/dist/charts/DualPanel.d.ts.map +1 -0
- package/dist/charts/DualPanel.js +214 -0
- package/dist/charts/Heatmap.d.ts +41 -0
- package/dist/charts/Heatmap.d.ts.map +1 -0
- package/dist/charts/Heatmap.js +216 -0
- package/dist/charts/Lines.d.ts +11 -0
- package/dist/charts/Lines.d.ts.map +1 -0
- package/dist/charts/Lines.js +114 -0
- package/dist/charts/MirroredBars.d.ts +44 -0
- package/dist/charts/MirroredBars.d.ts.map +1 -0
- package/dist/charts/MirroredBars.js +190 -0
- package/dist/charts/Sparkline.d.ts +22 -0
- package/dist/charts/Sparkline.d.ts.map +1 -0
- package/dist/charts/Sparkline.js +129 -0
- package/dist/charts/StackedArea.d.ts +15 -0
- package/dist/charts/StackedArea.d.ts.map +1 -0
- package/dist/charts/StackedArea.js +46 -0
- package/dist/charts/box.d.ts +38 -0
- package/dist/charts/box.d.ts.map +1 -0
- package/dist/charts/box.js +72 -0
- package/dist/charts/card-context.d.ts +3 -0
- package/dist/charts/card-context.d.ts.map +1 -0
- package/dist/charts/card-context.js +7 -0
- package/dist/charts/chart-box.module.css +64 -0
- package/{src/content/article-card.module.css.d.ts → dist/charts/chart-box.module.css.d.ts} +5 -9
- package/dist/charts/chart-card.module.css +25 -0
- package/dist/{dashboard/widget-grid.module.css.d.ts → charts/chart-card.module.css.d.ts} +1 -3
- package/dist/charts/chart-legend.module.css +38 -0
- package/{src/dashboard/widget-grid.module.css.d.ts → dist/charts/chart-legend.module.css.d.ts} +3 -3
- package/dist/charts/compile.d.ts +62 -0
- package/dist/charts/compile.d.ts.map +1 -0
- package/dist/charts/compile.js +386 -0
- package/dist/charts/cursor.d.ts +50 -0
- package/dist/charts/cursor.d.ts.map +1 -0
- package/dist/charts/cursor.js +157 -0
- package/dist/charts/curves.d.ts +12 -0
- package/dist/charts/curves.d.ts.map +1 -0
- package/dist/charts/curves.js +86 -0
- package/dist/charts/donut.module.css +54 -0
- package/dist/{content/article-card.module.css.d.ts → charts/donut.module.css.d.ts} +2 -9
- package/dist/charts/host.d.ts +17 -0
- package/dist/charts/host.d.ts.map +1 -0
- package/dist/charts/host.js +35 -0
- package/dist/charts/index.d.ts +18 -53
- package/dist/charts/index.d.ts.map +1 -1
- package/dist/charts/index.js +17 -189
- package/dist/charts/legend.d.ts +23 -0
- package/dist/charts/legend.d.ts.map +1 -0
- package/dist/charts/legend.js +160 -0
- package/dist/charts/marks.d.ts +25 -0
- package/dist/charts/marks.d.ts.map +1 -0
- package/dist/charts/marks.js +128 -0
- package/dist/charts/panel.d.ts +56 -0
- package/dist/charts/panel.d.ts.map +1 -0
- package/dist/charts/panel.js +123 -0
- package/dist/charts/scales.d.ts +44 -0
- package/dist/charts/scales.d.ts.map +1 -0
- package/dist/charts/scales.js +163 -0
- package/dist/charts/sizing.d.ts +12 -0
- package/dist/charts/sizing.d.ts.map +1 -0
- package/dist/charts/sizing.js +33 -0
- package/dist/charts/state.d.ts +17 -0
- package/dist/charts/state.d.ts.map +1 -0
- package/dist/charts/state.js +53 -0
- package/dist/charts/theme.d.ts +38 -19
- package/dist/charts/theme.d.ts.map +1 -1
- package/dist/charts/theme.js +48 -26
- package/dist/charts/types.d.ts +227 -0
- package/dist/charts/types.d.ts.map +1 -0
- package/dist/charts/types.js +4 -0
- package/dist/cli/audit-allows.d.ts +4 -17
- package/dist/cli/audit-allows.d.ts.map +1 -1
- package/dist/cli/config.d.ts +14 -43
- package/dist/cli/config.d.ts.map +1 -1
- package/dist/cli/doctor-upgrade.d.ts +31 -0
- package/dist/cli/doctor-upgrade.d.ts.map +1 -0
- package/dist/cli/doctor-upgrade.js +269 -0
- package/dist/cli/doctor.d.ts +13 -26
- package/dist/cli/doctor.d.ts.map +1 -1
- package/dist/cli/doctor.js +79 -8
- package/dist/cli/help.d.ts.map +1 -1
- package/dist/cli/help.js +2 -4
- package/dist/cli/index.d.ts +68 -135
- package/dist/cli/index.d.ts.map +1 -1
- package/dist/cli/index.js +89 -76
- package/dist/cli/init.d.ts.map +1 -1
- package/dist/cli/init.js +43 -27
- package/dist/cli/sync.d.ts +5 -21
- package/dist/cli/sync.d.ts.map +1 -1
- package/dist/cli/sync.js +4 -6
- package/dist/cli/tokens-css.d.ts +7 -28
- package/dist/cli/tokens-css.d.ts.map +1 -1
- package/dist/commands/ShortcutsHelp.d.ts.map +1 -1
- package/dist/commands/ShortcutsHelp.js +4 -5
- package/dist/commands/define-commands.d.ts +15 -31
- package/dist/commands/define-commands.d.ts.map +1 -1
- package/dist/commands/define-commands.js +1 -11
- package/dist/commands/define-overlays.d.ts +5 -19
- package/dist/commands/define-overlays.d.ts.map +1 -1
- package/dist/commands/define-overlays.js +3 -11
- package/dist/commands/index.d.ts +10 -40
- package/dist/commands/index.d.ts.map +1 -1
- package/dist/commands/index.js +9 -46
- package/dist/{notifications → commands/notifications}/bell.d.ts +1 -1
- package/dist/commands/notifications/bell.d.ts.map +1 -0
- package/dist/{notifications → commands/notifications}/center.d.ts +2 -2
- package/dist/commands/notifications/center.d.ts.map +1 -0
- package/dist/{notifications → commands/notifications}/center.js +2 -2
- package/dist/{notifications → commands/notifications}/define-notifications.d.ts +3 -3
- package/dist/commands/notifications/define-notifications.d.ts.map +1 -0
- package/dist/commands/notifications/notify.d.ts +44 -0
- package/dist/commands/notifications/notify.d.ts.map +1 -0
- package/dist/commands/notifications/notify.js +79 -0
- package/dist/{notifications → commands/notifications}/store.d.ts +2 -0
- package/dist/commands/notifications/store.d.ts.map +1 -0
- package/dist/{notifications → commands/notifications}/store.js +4 -0
- package/dist/commands/projectors.d.ts +1 -131
- package/dist/commands/projectors.d.ts.map +1 -1
- package/dist/commands/projectors.js +2 -73
- package/dist/commands/shell-bridge.d.ts +3 -3
- package/dist/commands/shortcut-format.d.ts +5 -4
- package/dist/commands/shortcut-format.d.ts.map +1 -1
- package/dist/common/errors.d.ts +3 -3
- package/dist/common/use-measured-widths.d.ts.map +1 -1
- package/dist/common/use-measured-widths.js +5 -3
- package/dist/common/validate.d.ts +2 -2
- package/dist/content/article-layout.d.ts.map +1 -1
- package/dist/content/article-layout.js +3 -3
- package/dist/content/article-model.d.ts +1 -46
- package/dist/content/article-model.d.ts.map +1 -1
- package/dist/content/article-model.js +1 -29
- package/dist/content/copy-action.d.ts +1 -1
- package/dist/content/glyphs.d.ts +1 -1
- package/dist/content/index.d.ts +11 -41
- package/dist/content/index.d.ts.map +1 -1
- package/dist/content/index.js +3 -35
- package/dist/content/markdown.d.ts +1 -1
- package/dist/content/markdown.d.ts.map +1 -1
- package/dist/content/markdown.js +1 -1
- package/dist/content/mermaid.d.ts.map +1 -1
- package/dist/content/mermaid.js +7 -7
- package/dist/content/slug.d.ts +1 -8
- package/dist/content/slug.d.ts.map +1 -1
- package/dist/content/slug.js +1 -8
- package/dist/content/url-hardening.d.ts +2 -2
- package/dist/content/url-hardening.d.ts.map +1 -1
- package/dist/content/url-hardening.js +2 -0
- package/dist/controls/actions.d.ts +16 -1
- package/dist/controls/actions.d.ts.map +1 -1
- package/dist/controls/enum-filter.d.ts +1 -1
- package/dist/controls/enum-filter.d.ts.map +1 -1
- package/dist/controls/filter-context.d.ts.map +1 -1
- package/dist/controls/filter-context.js +3 -1
- package/dist/controls/filter-set.js +4 -6
- package/dist/controls/form-layout.d.ts +1 -1
- package/dist/controls/form-layout.d.ts.map +1 -1
- package/dist/controls/form-layout.js +1 -1
- package/dist/controls/glyphs.d.ts +0 -2
- package/dist/controls/glyphs.d.ts.map +1 -1
- package/dist/controls/glyphs.js +0 -7
- package/dist/controls/index.d.ts +12 -17
- package/dist/controls/index.d.ts.map +1 -1
- package/dist/controls/index.js +5 -39
- package/dist/controls/multi-select-filter.d.ts +4 -3
- package/dist/controls/multi-select-filter.d.ts.map +1 -1
- package/dist/controls/number-filter.d.ts +4 -3
- package/dist/controls/number-filter.d.ts.map +1 -1
- package/dist/controls/number-filter.js +3 -1
- package/dist/controls/range-filter.d.ts +4 -3
- package/dist/controls/range-filter.d.ts.map +1 -1
- package/dist/controls/search-filter.d.ts +4 -3
- package/dist/controls/search-filter.d.ts.map +1 -1
- package/dist/controls/search-filter.js +19 -14
- package/dist/controls/select-filter.d.ts +4 -3
- package/dist/controls/select-filter.d.ts.map +1 -1
- package/dist/controls/sync-button.d.ts.map +1 -1
- package/dist/controls/sync-button.js +12 -15
- package/dist/controls/toggle-filter.d.ts +4 -3
- package/dist/controls/toggle-filter.d.ts.map +1 -1
- package/dist/controls/uncontrolled.d.ts +12 -0
- package/dist/controls/uncontrolled.d.ts.map +1 -0
- package/dist/controls/view-tabs.d.ts +2 -2
- package/dist/controls/view-tabs.d.ts.map +1 -1
- package/dist/controls-dates/index.d.ts +0 -1
- package/dist/controls-dates/index.d.ts.map +1 -1
- package/dist/dashboard/index.d.ts +7 -9
- package/dist/dashboard/index.d.ts.map +1 -1
- package/dist/dashboard/index.js +3 -23
- package/dist/dashboard/section.d.ts +4 -6
- package/dist/dashboard/section.d.ts.map +1 -1
- package/dist/dashboard/section.js +4 -10
- package/dist/dashboard/stat-card.d.ts +4 -4
- package/dist/dashboard/stat-card.d.ts.map +1 -1
- package/dist/dashboard/stat-card.js +3 -3
- package/dist/dashboard/widget-header.module.css +9 -7
- package/dist/dev-dock.d.ts.map +1 -1
- package/dist/dev-dock.js +6 -1
- package/dist/format/date.d.ts +0 -34
- package/dist/format/date.d.ts.map +1 -1
- package/dist/format/date.js +0 -54
- package/dist/format/index.d.ts +7 -22
- package/dist/format/index.d.ts.map +1 -1
- package/dist/format/index.js +2 -43
- package/dist/format/number.d.ts +3 -14
- package/dist/format/number.d.ts.map +1 -1
- package/dist/format/number.js +0 -13
- package/dist/format/shared.d.ts +2 -3
- package/dist/format/shared.d.ts.map +1 -1
- package/dist/forms/index.d.ts +0 -11
- package/dist/forms/index.d.ts.map +1 -1
- package/dist/forms/index.js +1 -14
- package/dist/guard/index.d.ts +6 -21
- package/dist/guard/index.d.ts.map +1 -1
- package/dist/guard/index.js +27 -115
- package/dist/guard/types.d.ts +7 -18
- package/dist/guard/types.d.ts.map +1 -1
- package/dist/index.d.ts +16 -48
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +21 -117
- package/dist/provider/create-router.d.ts +44 -0
- package/dist/provider/create-router.d.ts.map +1 -0
- package/dist/provider/create-router.js +62 -0
- package/dist/provider/hotkeys.d.ts +8 -0
- package/dist/provider/hotkeys.d.ts.map +1 -0
- package/dist/provider/hotkeys.js +50 -0
- package/dist/provider/index.d.ts +33 -110
- package/dist/provider/index.d.ts.map +1 -1
- package/dist/provider/index.js +182 -82
- package/dist/provider/lab-theme.d.ts.map +1 -1
- package/dist/provider/route-transition.d.ts +76 -0
- package/dist/provider/route-transition.d.ts.map +1 -0
- package/dist/provider/route-transition.js +98 -0
- package/dist/provider/spotlight-actions.d.ts +10 -0
- package/dist/provider/spotlight-actions.d.ts.map +1 -0
- package/dist/provider/spotlight-actions.js +55 -0
- package/dist/provider/test-router.d.ts +6 -0
- package/dist/provider/test-router.d.ts.map +1 -0
- package/dist/provider/test-router.js +18 -0
- package/dist/query-client.d.ts +4 -20
- package/dist/query-client.d.ts.map +1 -1
- package/dist/query-client.js +2 -2
- package/dist/router-tanstack/index.d.ts +18 -64
- package/dist/router-tanstack/index.d.ts.map +1 -1
- package/dist/router-tanstack/index.js +2 -16
- package/dist/router-tanstack/nav.d.ts +12 -1
- package/dist/router-tanstack/nav.d.ts.map +1 -1
- package/dist/router-tanstack/nav.js +8 -1
- package/dist/router-tanstack/search-store.d.ts +1 -1
- package/dist/router-tanstack/search-store.d.ts.map +1 -1
- package/dist/router-tanstack/use-nav.d.ts +8 -9
- package/dist/router-tanstack/use-nav.d.ts.map +1 -1
- package/dist/router-tanstack/use-nav.js +20 -1
- package/dist/shell/app-mobile-nav.d.ts.map +1 -1
- package/dist/shell/app-sidebar.js +1 -1
- package/dist/shell/index.d.ts +31 -10
- package/dist/shell/index.d.ts.map +1 -1
- package/dist/shell/index.js +14 -3
- package/dist/shell/page-aside.d.ts +2 -2
- package/dist/shell/page-aside.d.ts.map +1 -1
- package/dist/shell/page-aside.js +31 -12
- package/dist/shell/page-bar.d.ts +2 -2
- package/dist/shell/page-bar.d.ts.map +1 -1
- package/dist/shell/page-bar.js +1 -1
- package/dist/state.d.ts +10 -12
- package/dist/state.d.ts.map +1 -1
- package/dist/state.js +4 -6
- package/dist/styles.css +107 -7
- package/dist/surfaces.d.ts +28 -103
- package/dist/surfaces.d.ts.map +1 -1
- package/dist/surfaces.js +54 -143
- package/dist/{data → table}/data-table-state.d.ts +1 -1
- package/dist/table/data-table-state.d.ts.map +1 -0
- package/dist/{data → table}/data-table-state.js +4 -3
- package/dist/{data → table}/data-table.d.ts +28 -49
- package/dist/table/data-table.d.ts.map +1 -0
- package/dist/{data → table}/data-table.js +74 -60
- package/dist/table/index.d.ts +18 -0
- package/dist/table/index.d.ts.map +1 -0
- package/dist/{data/table.js → table/index.js} +1 -1
- package/dist/table/query-branch.d.ts.map +1 -0
- package/dist/table/table-features.d.ts +69 -0
- package/dist/table/table-features.d.ts.map +1 -0
- package/dist/table/table-features.js +49 -0
- package/dist/telemetry.d.ts +77 -0
- package/dist/telemetry.d.ts.map +1 -0
- package/dist/telemetry.js +33 -0
- package/dist/theme/index.d.ts +10 -21
- package/dist/theme/index.d.ts.map +1 -1
- package/dist/theme/index.js +3 -14
- package/dist/theme/theme-toggle.d.ts.map +1 -1
- package/dist/theme/theme-toggle.js +7 -33
- package/dist/theme/theme-toggle.module.css +30 -0
- package/dist/theme/theme-toggle.module.css.d.ts +10 -0
- package/dist/theme-lab/derive-controls.d.ts.map +1 -1
- package/dist/theme-lab/derive-controls.js +5 -3
- package/dist/theme-lab/derive-state.d.ts.map +1 -1
- package/dist/theme-lab/derive-state.js +2 -1
- package/dist/tokens/core.d.ts +360 -0
- package/dist/tokens/core.d.ts.map +1 -0
- package/dist/tokens/core.js +708 -0
- package/dist/tokens/derive.d.ts +1 -1
- package/dist/tokens/derive.d.ts.map +1 -1
- package/dist/tokens/index.d.ts +5 -373
- package/dist/tokens/index.d.ts.map +1 -1
- package/dist/tokens/index.js +8 -700
- package/dist/tokens/palette.d.ts +2 -6
- package/dist/tokens/palette.d.ts.map +1 -1
- package/dist/tokens/palette.js +1 -4
- package/dist/vite.d.ts +4 -3
- package/dist/vite.d.ts.map +1 -1
- package/llms.txt +43 -85
- package/package.json +77 -170
- package/src/agent/ai-sdk-transport.ts +57 -37
- package/src/{agent-chat → agent/chat}/composer.tsx +29 -30
- package/src/{agent-chat → agent/chat}/message-affordances.ts +8 -5
- package/src/{agent-chat → agent/chat}/thread-feed-row.tsx +30 -35
- package/src/{agent-chat → agent/chat}/thread-feed.tsx +40 -35
- package/src/{agent-chat → agent/chat}/thread-message.tsx +37 -35
- package/src/{agent-chat → agent/chat}/thread-outcome-card.tsx +5 -5
- package/src/{agent-chat → agent/chat}/tool-chip.tsx +12 -12
- package/src/{agent-chat → agent/chat}/use-keyboard-inset.ts +1 -1
- package/src/{agent-chat → agent/chat}/virtualize.ts +5 -5
- package/src/agent/error.ts +43 -0
- package/src/agent/foreign.ts +3 -2
- package/src/agent/history.ts +2 -107
- package/src/agent/id.ts +4 -5
- package/src/agent/index.ts +23 -112
- package/src/agent/outcome.ts +3 -56
- package/src/agent/part-list.tsx +3 -3
- package/src/agent/parts.ts +23 -22
- package/src/agent/run-committer.ts +64 -0
- package/src/agent/run-records.ts +147 -0
- package/src/agent/thread.ts +24 -231
- package/src/agent/transport.ts +6 -96
- package/src/agent/use-agent-thread-runs.ts +364 -199
- package/src/charts/BandStrip.tsx +276 -0
- package/src/charts/Bars.tsx +141 -0
- package/src/charts/CartesianChart.tsx +206 -0
- package/src/charts/ChartCard.tsx +178 -0
- package/src/charts/Donut.tsx +256 -0
- package/src/charts/DualPanel.tsx +326 -0
- package/src/charts/Heatmap.tsx +282 -0
- package/src/charts/Lines.tsx +151 -0
- package/src/charts/MirroredBars.tsx +303 -0
- package/src/charts/Sparkline.tsx +176 -0
- package/src/charts/StackedArea.tsx +80 -0
- package/src/charts/box.tsx +96 -0
- package/src/charts/card-context.ts +11 -0
- package/src/charts/chart-box.module.css +64 -0
- package/src/charts/chart-box.module.css.d.ts +12 -0
- package/src/charts/chart-card.module.css +25 -0
- package/src/charts/chart-card.module.css.d.ts +8 -0
- package/src/charts/chart-legend.module.css +38 -0
- package/src/charts/chart-legend.module.css.d.ts +10 -0
- package/src/charts/compile.ts +585 -0
- package/src/charts/cursor.ts +282 -0
- package/src/charts/curves.ts +111 -0
- package/src/charts/donut.module.css +54 -0
- package/src/charts/donut.module.css.d.ts +9 -0
- package/src/charts/host.tsx +60 -0
- package/src/charts/index.ts +41 -178
- package/src/charts/legend.tsx +204 -0
- package/src/charts/marks.ts +201 -0
- package/src/charts/panel.tsx +227 -0
- package/src/charts/scales.ts +237 -0
- package/src/charts/sizing.ts +47 -0
- package/src/charts/state.tsx +80 -0
- package/src/charts/theme.ts +65 -0
- package/src/charts/types.ts +242 -0
- package/src/cli/audit-allows.ts +8 -30
- package/src/cli/config.ts +14 -43
- package/src/cli/doctor-upgrade.ts +392 -0
- package/src/cli/doctor.ts +120 -68
- package/src/cli/help.ts +2 -4
- package/src/cli/index.ts +161 -276
- package/src/cli/init.ts +60 -37
- package/src/cli/sync.ts +13 -45
- package/src/cli/tokens-css.ts +7 -28
- package/src/commands/ShortcutsHelp.tsx +8 -9
- package/src/commands/define-commands.ts +16 -43
- package/src/commands/define-overlays.ts +12 -36
- package/src/commands/index.ts +11 -94
- package/src/{notifications → commands/notifications}/bell.tsx +2 -2
- package/src/{notifications → commands/notifications}/center.tsx +7 -5
- package/src/{notifications → commands/notifications}/define-notifications.ts +3 -3
- package/src/commands/notifications/notify.tsx +158 -0
- package/src/{notifications → commands/notifications}/store.ts +10 -2
- package/src/commands/projectors.ts +5 -225
- package/src/commands/shell-bridge.ts +5 -5
- package/src/commands/shortcut-format.ts +5 -4
- package/src/common/errors.ts +3 -3
- package/src/common/use-measured-widths.ts +6 -3
- package/src/common/validate.ts +2 -2
- package/src/content/article-layout.tsx +37 -38
- package/src/content/article-model.ts +1 -84
- package/src/content/copy-action.tsx +1 -1
- package/src/content/glyphs.tsx +1 -1
- package/src/content/index.ts +12 -83
- package/src/content/markdown.tsx +4 -3
- package/src/content/mermaid.tsx +9 -7
- package/src/content/slug.ts +1 -16
- package/src/content/url-hardening.ts +8 -2
- package/src/controls/actions.tsx +24 -1
- package/src/controls/enum-filter.tsx +1 -1
- package/src/controls/filter-context.tsx +3 -1
- package/src/controls/filter-set.tsx +5 -7
- package/src/controls/form-layout.tsx +2 -2
- package/src/controls/glyphs.tsx +0 -10
- package/src/controls/index.ts +13 -64
- package/src/controls/multi-select-filter.tsx +5 -4
- package/src/controls/number-filter.tsx +8 -4
- package/src/controls/range-filter.tsx +5 -4
- package/src/controls/search-filter.tsx +25 -19
- package/src/controls/select-filter.tsx +5 -4
- package/src/controls/sync-button.tsx +18 -20
- package/src/controls/toggle-filter.tsx +5 -4
- package/src/controls/uncontrolled.ts +12 -0
- package/src/controls/view-tabs.tsx +3 -3
- package/src/controls-dates/date-range-picker.tsx +1 -1
- package/src/controls-dates/index.ts +0 -1
- package/src/dashboard/index.ts +7 -48
- package/src/dashboard/section.tsx +11 -40
- package/src/dashboard/stat-card.tsx +14 -16
- package/src/dashboard/widget-header.module.css +9 -7
- package/src/dev-dock.tsx +14 -27
- package/src/format/date.ts +2 -92
- package/src/format/index.ts +7 -53
- package/src/format/number.ts +3 -26
- package/src/format/shared.ts +2 -3
- package/src/forms/index.ts +0 -23
- package/src/guard/index.ts +37 -192
- package/src/guard/types.ts +6 -19
- package/src/index.ts +30 -282
- package/src/provider/create-router.tsx +138 -0
- package/src/provider/hotkeys.ts +70 -0
- package/src/provider/index.tsx +260 -230
- package/src/provider/lab-theme.ts +3 -2
- package/src/provider/route-transition.ts +199 -0
- package/src/provider/spotlight-actions.tsx +69 -0
- package/src/provider/test-router.tsx +25 -0
- package/src/query-client.ts +4 -22
- package/src/router-tanstack/index.ts +18 -112
- package/src/router-tanstack/nav.ts +28 -2
- package/src/router-tanstack/search-store.ts +9 -2
- package/src/router-tanstack/use-nav.ts +47 -13
- package/src/shell/app-mobile-nav.tsx +3 -2
- package/src/shell/app-sidebar.tsx +1 -1
- package/src/shell/aside-docking.ts +1 -1
- package/src/shell/index.tsx +61 -20
- package/src/shell/page-aside.tsx +47 -23
- package/src/shell/page-bar.tsx +3 -3
- package/src/shell/page-title.tsx +1 -1
- package/src/state.ts +11 -37
- package/src/styles.css +107 -7
- package/src/surfaces.ts +56 -151
- package/src/{data → table}/data-table-state.ts +5 -4
- package/src/{data → table}/data-table.tsx +170 -161
- package/src/table/index.ts +18 -0
- package/src/table/table-features.ts +102 -0
- package/src/telemetry.ts +110 -0
- package/src/theme/index.ts +22 -47
- package/src/theme/theme-toggle.module.css +30 -0
- package/src/theme/theme-toggle.module.css.d.ts +10 -0
- package/src/theme/theme-toggle.tsx +15 -43
- package/src/theme-lab/derive-controls.tsx +5 -3
- package/src/theme-lab/derive-state.ts +2 -1
- package/src/tokens/core.ts +1163 -0
- package/src/tokens/derive.ts +1 -1
- package/src/tokens/index.ts +14 -1181
- package/src/tokens/palette.ts +3 -7
- package/src/vite.ts +3 -3
- package/agent/templates/CLAUDE-block.md.tpl +0 -40
- package/agent/templates/query-client.ts.tpl +0 -26
- package/dist/agent/adapter.d.ts +0 -150
- package/dist/agent/adapter.d.ts.map +0 -1
- package/dist/agent/adapter.js +0 -482
- package/dist/agent/use-agent-stream.d.ts +0 -35
- package/dist/agent/use-agent-stream.d.ts.map +0 -1
- package/dist/agent/use-agent-stream.js +0 -59
- package/dist/agent-chat/composer.d.ts.map +0 -1
- package/dist/agent-chat/index.d.ts +0 -31
- package/dist/agent-chat/index.d.ts.map +0 -1
- package/dist/agent-chat/index.js +0 -19
- package/dist/agent-chat/message-affordances.d.ts.map +0 -1
- package/dist/agent-chat/relative-time.d.ts.map +0 -1
- package/dist/agent-chat/thread-detail-panel.d.ts +0 -28
- package/dist/agent-chat/thread-detail-panel.d.ts.map +0 -1
- package/dist/agent-chat/thread-detail-panel.js +0 -115
- package/dist/agent-chat/thread-feed-row.d.ts.map +0 -1
- package/dist/agent-chat/thread-feed.d.ts.map +0 -1
- package/dist/agent-chat/thread-message.d.ts.map +0 -1
- package/dist/agent-chat/thread-outcome-card.d.ts.map +0 -1
- package/dist/agent-chat/thread-workspace.d.ts +0 -44
- package/dist/agent-chat/thread-workspace.d.ts.map +0 -1
- package/dist/agent-chat/thread-workspace.js +0 -153
- package/dist/agent-chat/tool-chip.d.ts.map +0 -1
- package/dist/agent-chat/use-keyboard-inset.d.ts.map +0 -1
- package/dist/agent-chat/virtualize.d.ts.map +0 -1
- package/dist/charts/cursor/resolve.d.ts +0 -75
- package/dist/charts/cursor/resolve.d.ts.map +0 -1
- package/dist/charts/cursor/resolve.js +0 -91
- package/dist/charts/cursor/scope.d.ts +0 -20
- package/dist/charts/cursor/scope.d.ts.map +0 -1
- package/dist/charts/cursor/scope.js +0 -20
- package/dist/charts/cursor/store.d.ts +0 -35
- package/dist/charts/cursor/store.d.ts.map +0 -1
- package/dist/charts/cursor/store.js +0 -25
- package/dist/charts/cursor/touch-pin.d.ts +0 -45
- package/dist/charts/cursor/touch-pin.d.ts.map +0 -1
- package/dist/charts/cursor/touch-pin.js +0 -79
- package/dist/charts/hooks/use-discrete-cursor.d.ts +0 -66
- package/dist/charts/hooks/use-discrete-cursor.d.ts.map +0 -1
- package/dist/charts/hooks/use-discrete-cursor.js +0 -198
- package/dist/charts/hooks/use-hysteresis.d.ts +0 -18
- package/dist/charts/hooks/use-hysteresis.d.ts.map +0 -1
- package/dist/charts/hooks/use-hysteresis.js +0 -12
- package/dist/charts/hooks/useBandPlot.d.ts +0 -145
- package/dist/charts/hooks/useBandPlot.d.ts.map +0 -1
- package/dist/charts/hooks/useBandPlot.js +0 -178
- package/dist/charts/hooks/useChartCursor.d.ts +0 -75
- package/dist/charts/hooks/useChartCursor.d.ts.map +0 -1
- package/dist/charts/hooks/useChartCursor.js +0 -200
- package/dist/charts/hooks/useChartSize.d.ts +0 -29
- package/dist/charts/hooks/useChartSize.d.ts.map +0 -1
- package/dist/charts/hooks/useChartSize.js +0 -8
- package/dist/charts/kinds/BandStrip.d.ts +0 -132
- package/dist/charts/kinds/BandStrip.d.ts.map +0 -1
- package/dist/charts/kinds/BandStrip.js +0 -241
- package/dist/charts/kinds/Bars.d.ts +0 -141
- package/dist/charts/kinds/Bars.d.ts.map +0 -1
- package/dist/charts/kinds/Bars.js +0 -343
- package/dist/charts/kinds/Donut.d.ts +0 -77
- package/dist/charts/kinds/Donut.d.ts.map +0 -1
- package/dist/charts/kinds/Donut.js +0 -245
- package/dist/charts/kinds/DualPanel.d.ts +0 -111
- package/dist/charts/kinds/DualPanel.d.ts.map +0 -1
- package/dist/charts/kinds/DualPanel.js +0 -471
- package/dist/charts/kinds/Heatmap.d.ts +0 -85
- package/dist/charts/kinds/Heatmap.d.ts.map +0 -1
- package/dist/charts/kinds/Heatmap.js +0 -243
- package/dist/charts/kinds/MirroredBars.d.ts +0 -98
- package/dist/charts/kinds/MirroredBars.d.ts.map +0 -1
- package/dist/charts/kinds/MirroredBars.js +0 -292
- package/dist/charts/kinds/MultiLine.d.ts +0 -87
- package/dist/charts/kinds/MultiLine.d.ts.map +0 -1
- package/dist/charts/kinds/MultiLine.js +0 -176
- package/dist/charts/kinds/StackedArea.d.ts +0 -73
- package/dist/charts/kinds/StackedArea.d.ts.map +0 -1
- package/dist/charts/kinds/StackedArea.js +0 -135
- package/dist/charts/kinds/ZonedLine.d.ts +0 -97
- package/dist/charts/kinds/ZonedLine.d.ts.map +0 -1
- package/dist/charts/kinds/ZonedLine.js +0 -155
- package/dist/charts/kinds/band-chrome.d.ts +0 -31
- package/dist/charts/kinds/band-chrome.d.ts.map +0 -1
- package/dist/charts/kinds/band-chrome.js +0 -71
- package/dist/charts/kinds/donut-layout.d.ts +0 -47
- package/dist/charts/kinds/donut-layout.d.ts.map +0 -1
- package/dist/charts/kinds/donut-layout.js +0 -52
- package/dist/charts/layout/auto-margin.d.ts +0 -122
- package/dist/charts/layout/auto-margin.d.ts.map +0 -1
- package/dist/charts/layout/auto-margin.js +0 -81
- package/dist/charts/layout/end-labels.d.ts +0 -64
- package/dist/charts/layout/end-labels.d.ts.map +0 -1
- package/dist/charts/layout/end-labels.js +0 -76
- package/dist/charts/layout/log-ticks.d.ts +0 -27
- package/dist/charts/layout/log-ticks.d.ts.map +0 -1
- package/dist/charts/layout/log-ticks.js +0 -42
- package/dist/charts/primitives/AreaGradient.d.ts +0 -18
- package/dist/charts/primitives/AreaGradient.d.ts.map +0 -1
- package/dist/charts/primitives/AreaGradient.js +0 -13
- package/dist/charts/primitives/Axes.d.ts +0 -83
- package/dist/charts/primitives/Axes.d.ts.map +0 -1
- package/dist/charts/primitives/Axes.js +0 -168
- package/dist/charts/primitives/CartesianChart.d.ts +0 -257
- package/dist/charts/primitives/CartesianChart.d.ts.map +0 -1
- package/dist/charts/primitives/CartesianChart.js +0 -549
- package/dist/charts/primitives/ChartCard.d.ts +0 -66
- package/dist/charts/primitives/ChartCard.d.ts.map +0 -1
- package/dist/charts/primitives/ChartCard.js +0 -143
- package/dist/charts/primitives/ChartFrame.d.ts +0 -156
- package/dist/charts/primitives/ChartFrame.d.ts.map +0 -1
- package/dist/charts/primitives/ChartFrame.js +0 -241
- package/dist/charts/primitives/ChartLegend.d.ts +0 -67
- package/dist/charts/primitives/ChartLegend.d.ts.map +0 -1
- package/dist/charts/primitives/ChartLegend.js +0 -292
- package/dist/charts/primitives/ChartPending.d.ts +0 -113
- package/dist/charts/primitives/ChartPending.d.ts.map +0 -1
- package/dist/charts/primitives/ChartPending.js +0 -117
- package/dist/charts/primitives/ChartTooltip.d.ts +0 -59
- package/dist/charts/primitives/ChartTooltip.d.ts.map +0 -1
- package/dist/charts/primitives/ChartTooltip.js +0 -197
- package/dist/charts/primitives/Crosshair.d.ts +0 -26
- package/dist/charts/primitives/Crosshair.d.ts.map +0 -1
- package/dist/charts/primitives/Crosshair.js +0 -23
- package/dist/charts/primitives/HatchPattern.d.ts +0 -31
- package/dist/charts/primitives/HatchPattern.d.ts.map +0 -1
- package/dist/charts/primitives/HatchPattern.js +0 -31
- package/dist/charts/primitives/HoverOverlay.d.ts +0 -45
- package/dist/charts/primitives/HoverOverlay.d.ts.map +0 -1
- package/dist/charts/primitives/HoverOverlay.js +0 -72
- package/dist/charts/primitives/HoverOverlay.module.css +0 -13
- package/dist/charts/primitives/HoverOverlay.module.css.d.ts +0 -8
- package/dist/charts/primitives/XZoneRects.d.ts +0 -54
- package/dist/charts/primitives/XZoneRects.d.ts.map +0 -1
- package/dist/charts/primitives/XZoneRects.js +0 -65
- package/dist/charts/primitives/ZoneRects.d.ts +0 -38
- package/dist/charts/primitives/ZoneRects.d.ts.map +0 -1
- package/dist/charts/primitives/ZoneRects.js +0 -30
- package/dist/charts/primitives/chart-card-context.d.ts +0 -33
- package/dist/charts/primitives/chart-card-context.d.ts.map +0 -1
- package/dist/charts/primitives/chart-card-context.js +0 -18
- package/dist/charts/primitives/chart-frame-layout.d.ts +0 -185
- package/dist/charts/primitives/chart-frame-layout.d.ts.map +0 -1
- package/dist/charts/primitives/chart-frame-layout.js +0 -175
- package/dist/charts/primitives/chart-layout.d.ts +0 -112
- package/dist/charts/primitives/chart-layout.d.ts.map +0 -1
- package/dist/charts/primitives/chart-layout.js +0 -175
- package/dist/charts/primitives/chart-tier.d.ts +0 -16
- package/dist/charts/primitives/chart-tier.d.ts.map +0 -1
- package/dist/charts/primitives/chart-tier.js +0 -44
- package/dist/charts/primitives/legend-disclosure.d.ts +0 -27
- package/dist/charts/primitives/legend-disclosure.d.ts.map +0 -1
- package/dist/charts/primitives/legend-disclosure.js +0 -153
- package/dist/charts/series.d.ts +0 -189
- package/dist/charts/series.d.ts.map +0 -1
- package/dist/charts/series.js +0 -84
- package/dist/charts/sparklines/BarSparkline.d.ts +0 -37
- package/dist/charts/sparklines/BarSparkline.d.ts.map +0 -1
- package/dist/charts/sparklines/BarSparkline.js +0 -53
- package/dist/charts/sparklines/LineSparkline.d.ts +0 -15
- package/dist/charts/sparklines/LineSparkline.d.ts.map +0 -1
- package/dist/charts/sparklines/LineSparkline.js +0 -51
- package/dist/charts/sparklines/index.d.ts +0 -3
- package/dist/charts/sparklines/index.d.ts.map +0 -1
- package/dist/charts/sparklines/index.js +0 -6
- package/dist/charts/utils/domain.d.ts +0 -35
- package/dist/charts/utils/domain.d.ts.map +0 -1
- package/dist/charts/utils/domain.js +0 -12
- package/dist/charts/utils/format.d.ts +0 -8
- package/dist/charts/utils/format.d.ts.map +0 -1
- package/dist/charts/utils/format.js +0 -20
- package/dist/charts/utils/measure-text.d.ts +0 -25
- package/dist/charts/utils/measure-text.d.ts.map +0 -1
- package/dist/charts/utils/measure-text.js +0 -64
- package/dist/charts/utils/ticks.d.ts +0 -103
- package/dist/charts/utils/ticks.d.ts.map +0 -1
- package/dist/charts/utils/ticks.js +0 -92
- package/dist/commands/overlays-mount.d.ts +0 -122
- package/dist/commands/overlays-mount.d.ts.map +0 -1
- package/dist/commands/overlays-mount.js +0 -125
- package/dist/commands/useCommandHotkeys.d.ts +0 -14
- package/dist/commands/useCommandHotkeys.d.ts.map +0 -1
- package/dist/commands/useCommandHotkeys.js +0 -45
- package/dist/content/article-actions.d.ts +0 -39
- package/dist/content/article-actions.d.ts.map +0 -1
- package/dist/content/article-actions.js +0 -28
- package/dist/content/article-card.d.ts +0 -58
- package/dist/content/article-card.d.ts.map +0 -1
- package/dist/content/article-card.js +0 -79
- package/dist/content/article-card.module.css +0 -111
- package/dist/content/mdx.d.ts +0 -20
- package/dist/content/mdx.d.ts.map +0 -1
- package/dist/content/mdx.js +0 -64
- package/dist/controls/compare-filter.d.ts +0 -42
- package/dist/controls/compare-filter.d.ts.map +0 -1
- package/dist/controls/compare-filter.js +0 -38
- package/dist/controls/slider-control.d.ts +0 -36
- package/dist/controls/slider-control.d.ts.map +0 -1
- package/dist/controls/slider-control.js +0 -64
- package/dist/dashboard/widget-grid.d.ts +0 -27
- package/dist/dashboard/widget-grid.d.ts.map +0 -1
- package/dist/dashboard/widget-grid.js +0 -40
- package/dist/dashboard/widget-grid.module.css +0 -69
- package/dist/data/data-table-state.d.ts.map +0 -1
- package/dist/data/data-table.d.ts.map +0 -1
- package/dist/data/query-branch.d.ts.map +0 -1
- package/dist/data/table.d.ts +0 -24
- package/dist/data/table.d.ts.map +0 -1
- package/dist/data/virtual-list.d.ts +0 -133
- package/dist/data/virtual-list.d.ts.map +0 -1
- package/dist/data/virtual-list.js +0 -157
- package/dist/data/virtual.d.ts +0 -21
- package/dist/data/virtual.d.ts.map +0 -1
- package/dist/data/virtual.js +0 -4
- package/dist/forms/FormErrorSummary.d.ts +0 -30
- package/dist/forms/FormErrorSummary.d.ts.map +0 -1
- package/dist/forms/FormErrorSummary.js +0 -30
- package/dist/forms/use-field-array.d.ts +0 -60
- package/dist/forms/use-field-array.d.ts.map +0 -1
- package/dist/forms/use-field-array.js +0 -20
- package/dist/forms/use-form-draft.d.ts +0 -76
- package/dist/forms/use-form-draft.d.ts.map +0 -1
- package/dist/forms/use-form-draft.js +0 -92
- package/dist/forms/use-form-submit.d.ts +0 -88
- package/dist/forms/use-form-submit.d.ts.map +0 -1
- package/dist/forms/use-form-submit.js +0 -63
- package/dist/notifications/bell.d.ts.map +0 -1
- package/dist/notifications/center.d.ts.map +0 -1
- package/dist/notifications/define-notifications.d.ts.map +0 -1
- package/dist/notifications/index.d.ts +0 -40
- package/dist/notifications/index.d.ts.map +0 -1
- package/dist/notifications/index.js +0 -54
- package/dist/notifications/mount-guard.d.ts +0 -8
- package/dist/notifications/mount-guard.d.ts.map +0 -1
- package/dist/notifications/mount-guard.js +0 -18
- package/dist/notifications/notify.d.ts +0 -149
- package/dist/notifications/notify.d.ts.map +0 -1
- package/dist/notifications/notify.js +0 -171
- package/dist/notifications/store.d.ts.map +0 -1
- package/dist/provider/connectivity-indicator.d.ts +0 -13
- package/dist/provider/connectivity-indicator.d.ts.map +0 -1
- package/dist/provider/connectivity-indicator.js +0 -205
- package/dist/provider/connectivity-provider.d.ts +0 -7
- package/dist/provider/connectivity-provider.d.ts.map +0 -1
- package/dist/provider/connectivity-provider.js +0 -128
- package/dist/provider/connectivity-types.d.ts +0 -36
- package/dist/provider/connectivity-types.d.ts.map +0 -1
- package/dist/provider/use-connectivity.d.ts +0 -3
- package/dist/provider/use-connectivity.d.ts.map +0 -1
- package/dist/provider/use-connectivity.js +0 -14
- package/dist/query-devtools.d.ts +0 -21
- package/dist/query-devtools.d.ts.map +0 -1
- package/dist/query-devtools.js +0 -13
- package/src/agent/adapter.ts +0 -945
- package/src/agent/use-agent-stream.ts +0 -154
- package/src/agent-chat/index.ts +0 -54
- package/src/agent-chat/thread-detail-panel.tsx +0 -201
- package/src/agent-chat/thread-workspace.tsx +0 -279
- package/src/charts/cursor/resolve.ts +0 -198
- package/src/charts/cursor/scope.tsx +0 -35
- package/src/charts/cursor/store.ts +0 -58
- package/src/charts/cursor/touch-pin.ts +0 -138
- package/src/charts/hooks/use-discrete-cursor.ts +0 -335
- package/src/charts/hooks/use-hysteresis.ts +0 -26
- package/src/charts/hooks/useBandPlot.ts +0 -383
- package/src/charts/hooks/useChartCursor.ts +0 -367
- package/src/charts/hooks/useChartSize.ts +0 -35
- package/src/charts/kinds/BandStrip.tsx +0 -449
- package/src/charts/kinds/Bars.tsx +0 -589
- package/src/charts/kinds/Donut.tsx +0 -368
- package/src/charts/kinds/DualPanel.tsx +0 -712
- package/src/charts/kinds/Heatmap.tsx +0 -396
- package/src/charts/kinds/MirroredBars.tsx +0 -469
- package/src/charts/kinds/MultiLine.tsx +0 -322
- package/src/charts/kinds/StackedArea.tsx +0 -267
- package/src/charts/kinds/ZonedLine.tsx +0 -301
- package/src/charts/kinds/band-chrome.tsx +0 -91
- package/src/charts/kinds/donut-layout.ts +0 -82
- package/src/charts/layout/auto-margin.ts +0 -242
- package/src/charts/layout/end-labels.ts +0 -135
- package/src/charts/layout/log-ticks.ts +0 -90
- package/src/charts/primitives/AreaGradient.tsx +0 -26
- package/src/charts/primitives/Axes.tsx +0 -271
- package/src/charts/primitives/CartesianChart.tsx +0 -1002
- package/src/charts/primitives/ChartCard.tsx +0 -280
- package/src/charts/primitives/ChartFrame.tsx +0 -493
- package/src/charts/primitives/ChartLegend.tsx +0 -422
- package/src/charts/primitives/ChartPending.tsx +0 -243
- package/src/charts/primitives/ChartTooltip.tsx +0 -265
- package/src/charts/primitives/Crosshair.tsx +0 -43
- package/src/charts/primitives/HatchPattern.tsx +0 -55
- package/src/charts/primitives/HoverOverlay.module.css +0 -13
- package/src/charts/primitives/HoverOverlay.module.css.d.ts +0 -8
- package/src/charts/primitives/HoverOverlay.tsx +0 -109
- package/src/charts/primitives/XZoneRects.tsx +0 -132
- package/src/charts/primitives/ZoneRects.tsx +0 -67
- package/src/charts/primitives/chart-card-context.ts +0 -46
- package/src/charts/primitives/chart-frame-layout.ts +0 -430
- package/src/charts/primitives/chart-layout.ts +0 -318
- package/src/charts/primitives/chart-tier.tsx +0 -76
- package/src/charts/primitives/legend-disclosure.tsx +0 -178
- package/src/charts/series.ts +0 -276
- package/src/charts/sparklines/BarSparkline.tsx +0 -94
- package/src/charts/sparklines/LineSparkline.tsx +0 -71
- package/src/charts/sparklines/index.ts +0 -2
- package/src/charts/theme.tsx +0 -53
- package/src/charts/utils/domain.ts +0 -41
- package/src/charts/utils/format.ts +0 -19
- package/src/charts/utils/measure-text.ts +0 -109
- package/src/charts/utils/ticks.ts +0 -239
- package/src/commands/overlays-mount.tsx +0 -333
- package/src/commands/useCommandHotkeys.ts +0 -114
- package/src/content/article-actions.ts +0 -72
- package/src/content/article-card.module.css +0 -111
- package/src/content/article-card.tsx +0 -174
- package/src/content/mdx.tsx +0 -127
- package/src/controls/compare-filter.tsx +0 -81
- package/src/controls/slider-control.tsx +0 -159
- package/src/dashboard/widget-grid.module.css +0 -69
- package/src/dashboard/widget-grid.tsx +0 -146
- package/src/data/table.ts +0 -39
- package/src/data/virtual-list.tsx +0 -356
- package/src/data/virtual.ts +0 -26
- package/src/forms/FormErrorSummary.tsx +0 -71
- package/src/forms/use-field-array.ts +0 -94
- package/src/forms/use-form-draft.ts +0 -262
- package/src/forms/use-form-submit.ts +0 -199
- package/src/notifications/index.ts +0 -88
- package/src/notifications/mount-guard.ts +0 -38
- package/src/notifications/notify.tsx +0 -379
- package/src/provider/connectivity-indicator.tsx +0 -267
- package/src/provider/connectivity-provider.tsx +0 -189
- package/src/provider/connectivity-types.ts +0 -42
- package/src/provider/use-connectivity.ts +0 -26
- package/src/query-devtools.tsx +0 -40
- /package/dist/{agent-chat → agent/chat}/message-affordances.js +0 -0
- /package/dist/{agent-chat → agent/chat}/relative-time.d.ts +0 -0
- /package/dist/{agent-chat → agent/chat}/relative-time.js +0 -0
- /package/dist/{agent-chat → agent/chat}/use-keyboard-inset.d.ts +0 -0
- /package/dist/{agent-chat → agent/chat}/virtualize.js +0 -0
- /package/dist/{notifications → commands/notifications}/bell.js +0 -0
- /package/dist/{notifications → commands/notifications}/define-notifications.js +0 -0
- /package/dist/{provider/connectivity-types.js → controls/uncontrolled.js} +0 -0
- /package/dist/{data → table}/data-table.module.css +0 -0
- /package/dist/{data → table}/data-table.module.css.d.ts +0 -0
- /package/dist/{data → table}/query-branch.d.ts +0 -0
- /package/dist/{data → table}/query-branch.js +0 -0
- /package/src/{agent-chat → agent/chat}/relative-time.ts +0 -0
- /package/src/{data → table}/data-table.module.css +0 -0
- /package/src/{data → table}/data-table.module.css.d.ts +0 -0
- /package/src/{data → table}/query-branch.ts +0 -0
|
@@ -1,1002 +0,0 @@
|
|
|
1
|
-
import { GridRows } from '@visx/grid'
|
|
2
|
-
import { Group } from '@visx/group'
|
|
3
|
-
import { scaleLinear, scaleLog, scalePoint } from '@visx/scale'
|
|
4
|
-
import { useMemo, useRef, useState } from 'react'
|
|
5
|
-
import type { ReactNode } from 'react'
|
|
6
|
-
import type { BasaltProps } from '../../common/props'
|
|
7
|
-
import { VX, alpha } from '../../tokens'
|
|
8
|
-
import type { ChartMargin } from '../../tokens'
|
|
9
|
-
import { classifyDomain } from '../cursor/resolve'
|
|
10
|
-
import type { CursorResolution } from '../cursor/resolve'
|
|
11
|
-
import { useChartCursor } from '../hooks/useChartCursor'
|
|
12
|
-
import { autoMargin, probeAxisLabels } from '../layout/auto-margin'
|
|
13
|
-
import type { AutoMarginInput } from '../layout/auto-margin'
|
|
14
|
-
import { END_LABEL_GAP, planEndLabels } from '../layout/end-labels'
|
|
15
|
-
import { logTickValues, niceLogDomain } from '../layout/log-ticks'
|
|
16
|
-
import { deriveLegend, deriveTooltipRows } from '../series'
|
|
17
|
-
import type { ChartLegendConfig, ChartSeries } from '../series'
|
|
18
|
-
import { padAutoLower, padAutoUpper } from '../utils/domain'
|
|
19
|
-
import { fmtAxisDate } from '../utils/format'
|
|
20
|
-
import { rotatedXLabelPx, smartTicks, smartTicksEvery, xLabelPxFor } from '../utils/ticks'
|
|
21
|
-
import { AxisBottomDate, AxisLeftNumeric, AxisRightNumeric, TICK_FONT_FAMILY } from './Axes'
|
|
22
|
-
import { ChartFrame, resolveLegend } from './ChartFrame'
|
|
23
|
-
import type { ResponsiveChartHeight } from './ChartFrame'
|
|
24
|
-
import {
|
|
25
|
-
compactNumber,
|
|
26
|
-
isTightClass,
|
|
27
|
-
planXLabels,
|
|
28
|
-
resolveMarginFloor,
|
|
29
|
-
resolveYPlacement,
|
|
30
|
-
shouldCompactYLabels,
|
|
31
|
-
yTickCount,
|
|
32
|
-
} from './chart-layout'
|
|
33
|
-
import { useChartContainerClass, useChartMetrics } from './chart-tier'
|
|
34
|
-
import type { ChartState } from './ChartPending'
|
|
35
|
-
import { ChartTooltipFloat, TooltipBody, TooltipHeader, TooltipRows } from './ChartTooltip'
|
|
36
|
-
import { Crosshair, SeriesDot } from './Crosshair'
|
|
37
|
-
import { cursorSliderProps, HoverOverlay } from './HoverOverlay'
|
|
38
|
-
import { XZoneRects } from './XZoneRects'
|
|
39
|
-
import type { XZoneSpec } from './XZoneRects'
|
|
40
|
-
import { ZoneRects } from './ZoneRects'
|
|
41
|
-
import type { ZoneSpec } from './ZoneRects'
|
|
42
|
-
|
|
43
|
-
/** Either axis kind a `y`/`y2` can resolve to. Widened from a bare `scaleLinear` return type so a
|
|
44
|
-
* log axis's `scaleLog` scale keeps assigning into `PlotContext.yScale`/`y2Scale` and into every
|
|
45
|
-
* mark renderer (`ZoneRects`, `refLines`, `Crosshair`/`SeriesDot`) that only ever calls `scale(v)`
|
|
46
|
-
* or reads `scale.domain()` — both interfaces share that shape via d3's `ScaleContinuousNumeric`. */
|
|
47
|
-
type ContinuousScale = ReturnType<typeof scaleLinear<number>> | ReturnType<typeof scaleLog<number>>
|
|
48
|
-
type PointScale = ReturnType<typeof scalePoint<string>>
|
|
49
|
-
|
|
50
|
-
const DEFAULT_AUTO_PAD = 1.1
|
|
51
|
-
|
|
52
|
-
/** Faint tint a dual-axis chart lays over its tick labels: the series colour, kept quiet. */
|
|
53
|
-
const AXIS_TINT_ALPHA = 0.8
|
|
54
|
-
|
|
55
|
-
/** One y-axis, fully described. Collapses the removed `yDomain` / `yAutoMaxFloor` / `yAutoMinCeil` /
|
|
56
|
-
* `yAutoPad` / `numTicksY` / `formatYTick` prop soup into a single object per axis. */
|
|
57
|
-
export type AxisConfig<T> = {
|
|
58
|
-
/**
|
|
59
|
-
* `'auto'` (default) derives the domain from the VISIBLE series; a tuple fixes it; a function
|
|
60
|
-
* computes it from the data — the seam a stacked chart uses to sum its bands. The function also
|
|
61
|
-
* receives the visible series, so a stacked domain SHRINKS when the legend toggles a band off
|
|
62
|
-
* (summing `props.series` there would leave a permanent gap above the stack).
|
|
63
|
-
*/
|
|
64
|
-
domain?:
|
|
65
|
-
| [number, number]
|
|
66
|
-
| 'auto'
|
|
67
|
-
| ((data: readonly T[], visible: readonly ChartSeries<T>[]) => [number, number])
|
|
68
|
-
/**
|
|
69
|
-
* When 'auto': the raw upper bound is at least this, and padding is applied AFTER — mirroring
|
|
70
|
-
* `autoMinCeil`, which clamps first and pads second. A floor that padded before the clamp used
|
|
71
|
-
* to land the axis top exactly on the floor value with zero headroom.
|
|
72
|
-
*/
|
|
73
|
-
autoMaxFloor?: number
|
|
74
|
-
/** When 'auto': the lower bound is at most this. Default 0 (forced zero baseline). `Infinity`
|
|
75
|
-
* pads down from the raw data minimum instead. Ignored when `scale: 'log'` — a log axis has no
|
|
76
|
-
* zero baseline, so its floor is always the smallest positive visible value. */
|
|
77
|
-
autoMinCeil?: number
|
|
78
|
-
/** When 'auto': padding multiplier applied away from the data. Default 1.1. */
|
|
79
|
-
autoPad?: number
|
|
80
|
-
ticks?: number
|
|
81
|
-
/** Tick + tooltip formatter for this axis. Defaults to d3's own tick format. */
|
|
82
|
-
format?: (v: number) => string
|
|
83
|
-
/** Horizontal grid rules. Default: on for the left axis, off for the right. */
|
|
84
|
-
grid?: boolean
|
|
85
|
-
/**
|
|
86
|
-
* Round the scale's domain outward to nice tick values (d3's `scale.nice()`). Threaded to BOTH
|
|
87
|
-
* `probeAxisLabels` (measurement) and the real `scaleLinear` (rendering) — they must agree, or
|
|
88
|
-
* the measured margin is computed from ticks the axis never paints.
|
|
89
|
-
*
|
|
90
|
-
* Default `false`, deliberately: flipping the default would move the domain of every
|
|
91
|
-
* already-migrated chart. Opt in per axis.
|
|
92
|
-
*/
|
|
93
|
-
nice?: boolean
|
|
94
|
-
/**
|
|
95
|
-
* `'linear'` (default) or `'log'`. On `'log'` the domain floor is the smallest positive VISIBLE
|
|
96
|
-
* value — `autoMinCeil` is ignored (documented there, not thrown on): a log axis has no zero
|
|
97
|
-
* baseline. `autoPad` still pads multiplicatively and `nice` still snaps to round bounds (decade
|
|
98
|
-
* powers instead of d3's linear-nice steps). Ticks are the 1-2-5 set from `logTickValues`
|
|
99
|
-
* (`$10,000 · $20,000 · $50,000 · $100,000`, never d3's own log ticks), and `format` is applied
|
|
100
|
-
* to those values — d3's `scale.tickFormat` is never used on a log axis.
|
|
101
|
-
*/
|
|
102
|
-
scale?: 'linear' | 'log'
|
|
103
|
-
}
|
|
104
|
-
|
|
105
|
-
/** Handed to `prependRows`/`extraRows` alongside the hovered datum — the same `visible`/`hidden`
|
|
106
|
-
* the plot itself draws from, so a hand-authored row can't structurally desync from legend
|
|
107
|
-
* toggling. */
|
|
108
|
-
export type CartesianTooltipRowContext<T> = {
|
|
109
|
-
visible: readonly ChartSeries<T>[]
|
|
110
|
-
hidden: ReadonlySet<string>
|
|
111
|
-
}
|
|
112
|
-
|
|
113
|
-
export type CartesianTooltipConfig<T> = {
|
|
114
|
-
/**
|
|
115
|
-
* Default true — the tooltip tracks the pointer. Set false to ANCHOR it to the crosshair at the
|
|
116
|
-
* plot's top edge instead, which reads better across a column of charts sharing one cursor
|
|
117
|
-
* (every tooltip then lines up on the same x). Anchoring costs one `getBoundingClientRect` per
|
|
118
|
-
* hovered frame, which is why following stays the default.
|
|
119
|
-
*/
|
|
120
|
-
follow?: boolean
|
|
121
|
-
/** Right-aligned badge in the tooltip header (e.g. a status label). */
|
|
122
|
-
label?: (d: T) => { text: string; color: string } | null
|
|
123
|
-
/**
|
|
124
|
-
* Overrides the tooltip header's date text. Default: `TooltipHeader`'s own `fmtTooltipDate`
|
|
125
|
-
* behavior, unchanged. `fmtTooltipDate` regexes `YYYY-MM-DD` out of the domain key and builds a
|
|
126
|
-
* LOCAL `Date` from it — a UTC ISO key then names the wrong day next to `formatX`, the tooltip
|
|
127
|
-
* badge, and every sibling chart, which all resolve locally. Receives the raw `getX` key
|
|
128
|
-
* alongside the hovered datum, so a caller can format from either.
|
|
129
|
-
*/
|
|
130
|
-
formatHeader?: (key: string, d: T) => string
|
|
131
|
-
/** Rows rendered BEFORE the derived per-series rows (a total, a context line). The second
|
|
132
|
-
* argument carries the same `visible`/`hidden` the plot draws from, so a hand-authored row
|
|
133
|
-
* stays in sync with legend toggling instead of naming a series the plot no longer draws. */
|
|
134
|
-
prependRows?: (d: T, ctx: CartesianTooltipRowContext<T>) => ReactNode
|
|
135
|
-
/** Rows appended after the derived per-series rows. Same `ctx` as {@link prependRows}. */
|
|
136
|
-
extraRows?: (d: T, ctx: CartesianTooltipRowContext<T>) => ReactNode
|
|
137
|
-
/**
|
|
138
|
-
* Render this chart's tooltip when it is a cursor FOLLOWER (the crosshair came from a sibling
|
|
139
|
-
* chart sharing the cursor), not only when this chart is the SOURCE. Default false — today's
|
|
140
|
-
* behaviour, nothing moves. A follower has no pointer under it, so its tooltip is always ANCHORED
|
|
141
|
-
* to the crosshair — the same positioning `follow: false` gives the source — regardless of what
|
|
142
|
-
* `follow` is set to on this chart: there is no other valid position for a chart nobody is
|
|
143
|
-
* hovering. `follow` keeps governing the SOURCE's own tooltip exactly as before; the two options
|
|
144
|
-
* only interact for a follower, where `onFollow` always wins on positioning. Only the SOURCE's
|
|
145
|
-
* tooltip is `aria-live` — followers announce nothing, so a shared-cursor page doesn't fire N
|
|
146
|
-
* live-region updates per pointer move.
|
|
147
|
-
*
|
|
148
|
-
* Cost, since it scales with the page rather than the chart: anchoring reads one
|
|
149
|
-
* `getBoundingClientRect` per hovered frame (the same cost `follow: false` documents), so N
|
|
150
|
-
* opted-in followers pay N of them per frame. That is the reason this is opt-in per chart rather
|
|
151
|
-
* than a page-level switch — turn it on for the charts a reader actually correlates.
|
|
152
|
-
*/
|
|
153
|
-
onFollow?: boolean
|
|
154
|
-
}
|
|
155
|
-
|
|
156
|
-
/** Everything a mark renderer needs. Handed to `CartesianChart`'s child on every render. */
|
|
157
|
-
export type PlotContext<T> = {
|
|
158
|
-
data: readonly T[]
|
|
159
|
-
/** Series minus the ones the legend has toggled off — draw THESE, not `props.series`. */
|
|
160
|
-
visible: ChartSeries<T>[]
|
|
161
|
-
hidden: ReadonlySet<string>
|
|
162
|
-
xScale: PointScale
|
|
163
|
-
yScale: ContinuousScale
|
|
164
|
-
/** Present only when a `y2` axis is configured. */
|
|
165
|
-
y2Scale: ContinuousScale | null
|
|
166
|
-
xMax: number
|
|
167
|
-
yMax: number
|
|
168
|
-
margin: ChartMargin
|
|
169
|
-
/** The point the shared cursor currently rests on, or null. */
|
|
170
|
-
cursorPoint: T | null
|
|
171
|
-
/** Series key the legend is hovering, for mark dimming. */
|
|
172
|
-
highlighted: string | null
|
|
173
|
-
}
|
|
174
|
-
|
|
175
|
-
export type CartesianChartProps<T> = BasaltProps & {
|
|
176
|
-
data: T[]
|
|
177
|
-
/** Stable id — identifies this chart as the cursor's source. */
|
|
178
|
-
chartId: string
|
|
179
|
-
/** Extracts the x-domain key (a date or category string) from a point. */
|
|
180
|
-
getX: (d: T) => string
|
|
181
|
-
/** The single source of truth for marks, legend entries, and tooltip rows. */
|
|
182
|
-
series: ChartSeries<T>[]
|
|
183
|
-
y?: AxisConfig<T>
|
|
184
|
-
/** Passing `y2` is what makes the chart dual-axis: it draws the right axis and widens the
|
|
185
|
-
* right margin by measurement. Series opt in with `axis: 'right'`. */
|
|
186
|
-
y2?: AxisConfig<T>
|
|
187
|
-
/** Exact number of x ticks. Default: as many as fit (`smartTicks`). Ignored when
|
|
188
|
-
* `xTickValues` is set. */
|
|
189
|
-
xTicks?: number
|
|
190
|
-
/**
|
|
191
|
-
* Which domain keys get a tick, chosen from the full key list and the resolved plot width.
|
|
192
|
-
* Takes precedence over `xTicks`; omit both for `smartTicks`.
|
|
193
|
-
*
|
|
194
|
-
* A COUNT is not always enough. `smartTicks`/`smartTicksEvery` append the final key
|
|
195
|
-
* unconditionally, so when the step does not land on the last index that appended tick sits a
|
|
196
|
-
* partial step from its neighbour — measured on a 24h window, two `DD.MM HH:MM` labels printed
|
|
197
|
-
* on top of each other at the right edge, at every tick count. The only fix a count can express
|
|
198
|
-
* is thinning the whole axis to avoid one crowded pair. A consumer whose labels are richer than
|
|
199
|
-
* the default `DD.MM` needs to pick the VALUES, which until now meant measuring the container
|
|
200
|
-
* itself with `useChartSize` to derive a count — the chart already knows its own width.
|
|
201
|
-
*
|
|
202
|
-
* `BandStrip`/`MirroredBars` take the identical prop, so the seam does not fork by kind.
|
|
203
|
-
*/
|
|
204
|
-
xTickValues?: (keys: readonly string[], xMax: number) => readonly string[]
|
|
205
|
-
/** X tick label formatter. Default `fmtAxisDate` (DD.MM). */
|
|
206
|
-
formatX?: (key: string) => string
|
|
207
|
-
/**
|
|
208
|
-
* Tilt the x tick labels by 45° or 90° (counter-clockwise, anchored at their right edge). The
|
|
209
|
-
* bottom gutter deepens by the rotated label's projected height, measured like every other side
|
|
210
|
-
* (`docs/CHARTS-SPEC.md` §1), so nothing clips.
|
|
211
|
-
*
|
|
212
|
-
* This is the phone answer to a **categorical** axis whose labels are too wide to repeat
|
|
213
|
-
* horizontally: rotating keeps every tick the axis would otherwise have to thin away — which is
|
|
214
|
-
* why, LEFT UNSET, it is now the phone tier's DEFAULT for a band domain, below
|
|
215
|
-
* `CONTAINER_CLASSES.regular` (`planXLabels`). A time or number domain never auto-rotates (or
|
|
216
|
-
* wraps) — it thins instead, however narrow the plot. Nothing changes at desktop width, and
|
|
217
|
-
* nothing changes for a chart that already passes a value.
|
|
218
|
-
*
|
|
219
|
-
* **`0` is the opt-out** — "never rotate, thin the axis instead" — and is the only way to get
|
|
220
|
-
* the pre-tier behaviour back on a phone-width categorical chart with very wide labels.
|
|
221
|
-
*/
|
|
222
|
-
xLabelRotate?: 0 | 45 | 90
|
|
223
|
-
/** Value-range bands on the left scale, drawn behind the marks. */
|
|
224
|
-
zones?: ZoneSpec[]
|
|
225
|
-
/** X-range bands (time windows), drawn behind the marks. */
|
|
226
|
-
xZones?: XZoneSpec[]
|
|
227
|
-
refLines?: { value: number; color: string; dashed?: boolean; axis?: 'left' | 'right' }[]
|
|
228
|
-
/** Height in px, or one per size step (`{ base, sm?, md?, lg? }`). Default 240. Forwarded
|
|
229
|
-
* unchanged; `ChartFrameProps.height` owns the law — steps resolve off the MEASURED width. */
|
|
230
|
-
height?: number | ResponsiveChartHeight
|
|
231
|
-
aspectRatio?: number
|
|
232
|
-
fill?: boolean
|
|
233
|
-
legend?: ChartLegendConfig | false
|
|
234
|
-
/** `false` disables the tooltip entirely (and with it the crosshair dots). */
|
|
235
|
-
tooltip?: CartesianTooltipConfig<T> | false
|
|
236
|
-
/** Per-side overrides of the measured margins — the escape hatch, applied last. */
|
|
237
|
-
margin?: Partial<ChartMargin>
|
|
238
|
-
/**
|
|
239
|
-
* Where this series' crosshair dot sits, as a value in the axis domain. Defaults to
|
|
240
|
-
* `series.getValue`, which is correct for every unstacked chart. A STACKED chart must override
|
|
241
|
-
* it with the cumulative band top — otherwise its dots sit at each band's raw value, off the
|
|
242
|
-
* line the reader is actually looking at.
|
|
243
|
-
*/
|
|
244
|
-
cursorValue?: (
|
|
245
|
-
point: T,
|
|
246
|
-
series: ChartSeries<T>,
|
|
247
|
-
visible: readonly ChartSeries<T>[],
|
|
248
|
-
) => number | null
|
|
249
|
-
/**
|
|
250
|
-
* How a sibling chart's broadcast cursor key resolves against THIS chart's points. Default
|
|
251
|
-
* `'nearest'`, correct when `getX` returns an instant. Pass `'leading'` when it returns a
|
|
252
|
-
* bucket's leading edge (a weekly series keyed by its Monday): under `'nearest'` a hover landing
|
|
253
|
-
* in the back half of a bucket resolves to the FOLLOWING bucket, so the shared crosshair sits
|
|
254
|
-
* one column right of the data the reader is pointing at.
|
|
255
|
-
*/
|
|
256
|
-
cursorResolution?: CursorResolution
|
|
257
|
-
ariaLabel?: string
|
|
258
|
-
isPending?: boolean
|
|
259
|
-
/**
|
|
260
|
-
* The three "nothing to draw" states in one prop, forwarded to `ChartFrame` — pending → error →
|
|
261
|
-
* empty, resolved by `resolveChartState`. The Mantine-free answer to `dashboard/QueryState`,
|
|
262
|
-
* which `./charts` cannot import; `isPending` remains a supported alias for
|
|
263
|
-
* `state={{ pending: true }}`.
|
|
264
|
-
*/
|
|
265
|
-
state?: ChartState
|
|
266
|
-
/** Draw ONLY the marks. Everything around them is the primitive's job. */
|
|
267
|
-
children: (ctx: PlotContext<T>) => ReactNode
|
|
268
|
-
}
|
|
269
|
-
|
|
270
|
-
/**
|
|
271
|
-
* Resolve one axis' `[min, max]` from its {@link AxisConfig} and the VISIBLE series. Exported for
|
|
272
|
-
* testing and for a hand-composed kind that needs the same auto-domain law `CartesianChart`
|
|
273
|
-
* applies (rather than reinventing the padding rules per chart).
|
|
274
|
-
*/
|
|
275
|
-
export function resolveAxisDomain<T>(
|
|
276
|
-
cfg: AxisConfig<T> | undefined,
|
|
277
|
-
data: readonly T[],
|
|
278
|
-
series: readonly ChartSeries<T>[],
|
|
279
|
-
/**
|
|
280
|
-
* Values that must stay inside the plot even though no series reports them — the bounds of the
|
|
281
|
-
* zones and reference lines pinned to THIS axis. Without them a target zone or a stretch-goal
|
|
282
|
-
* ref line sitting past the data silently clips, which is precisely the case those overlays
|
|
283
|
-
* exist for. Infinite bounds ("top/bottom of axis") are ignored: they clamp to the domain by
|
|
284
|
-
* definition and would otherwise blow it up.
|
|
285
|
-
*/
|
|
286
|
-
extraBounds: readonly number[] = [],
|
|
287
|
-
): [number, number] {
|
|
288
|
-
const domain = cfg?.domain ?? 'auto'
|
|
289
|
-
if (Array.isArray(domain)) return domain
|
|
290
|
-
if (typeof domain === 'function') return domain(data, series)
|
|
291
|
-
|
|
292
|
-
const isLog = cfg?.scale === 'log'
|
|
293
|
-
let min = Infinity
|
|
294
|
-
let max = -Infinity
|
|
295
|
-
for (const d of data) {
|
|
296
|
-
for (const s of series) {
|
|
297
|
-
const v = s.getValue(d)
|
|
298
|
-
if (v === null) continue
|
|
299
|
-
// A log axis has no zero and no negative half — a non-positive value can't sit on it, so it
|
|
300
|
-
// drops out of the domain instead of pulling the floor to (or past) zero.
|
|
301
|
-
if (isLog && v <= 0) continue
|
|
302
|
-
if (v < min) min = v
|
|
303
|
-
if (v > max) max = v
|
|
304
|
-
}
|
|
305
|
-
}
|
|
306
|
-
for (const v of extraBounds) {
|
|
307
|
-
if (!Number.isFinite(v)) continue
|
|
308
|
-
if (isLog && v <= 0) continue
|
|
309
|
-
if (v < min) min = v
|
|
310
|
-
if (v > max) max = v
|
|
311
|
-
}
|
|
312
|
-
|
|
313
|
-
const pad = cfg?.autoPad ?? DEFAULT_AUTO_PAD
|
|
314
|
-
|
|
315
|
-
if (isLog) {
|
|
316
|
-
// No zero baseline on a log axis: the floor is the smallest positive visible value, padded
|
|
317
|
-
// down with no `autoMinCeil` clamp (documented as ignored on `AxisConfig.autoMinCeil`).
|
|
318
|
-
if (min === Infinity) return [1, 10]
|
|
319
|
-
if (min === max) return [min / pad, max * pad]
|
|
320
|
-
const upper = padAutoUpper(Math.max(max, cfg?.autoMaxFloor ?? -Infinity), pad)
|
|
321
|
-
return [min / pad, upper]
|
|
322
|
-
}
|
|
323
|
-
|
|
324
|
-
if (min === Infinity) return [0, cfg?.autoMaxFloor ?? 1]
|
|
325
|
-
|
|
326
|
-
const ceil = cfg?.autoMinCeil ?? 0
|
|
327
|
-
// Symmetric with the lower bound: clamp the RAW value against the floor/ceiling first, then pad
|
|
328
|
-
// once, away from zero. Padding before the clamp (the old law) lands a floored axis top exactly
|
|
329
|
-
// on the floor with zero headroom — a target line pinned there sits glued to the plot edge.
|
|
330
|
-
const upper = padAutoUpper(Math.max(max, cfg?.autoMaxFloor ?? -Infinity), pad)
|
|
331
|
-
const lower = padAutoLower(Math.min(min, ceil), pad)
|
|
332
|
-
// A flat series (every value identical, the all-zero case included) collapses to `[n, n]`,
|
|
333
|
-
// which is a scale with no extent: every point maps to the same pixel and the line renders as a
|
|
334
|
-
// dot on the axis. Give it the same usable baseline the empty-data branch above gets.
|
|
335
|
-
if (lower === upper) return [Math.min(lower, 0), upper === 0 ? 1 : upper * pad]
|
|
336
|
-
return [lower, upper]
|
|
337
|
-
}
|
|
338
|
-
|
|
339
|
-
/**
|
|
340
|
-
* Probe one y axis' labels. With no consumer `format`, labels over 4 chars switch to the compact
|
|
341
|
-
* number format (`12500` -> `12.5k`, ladder step 1); an explicit `format` is never touched.
|
|
342
|
-
*/
|
|
343
|
-
function probeYAxis(opts: {
|
|
344
|
-
domain: [number, number]
|
|
345
|
-
ticks: number
|
|
346
|
-
nice: boolean
|
|
347
|
-
scale: 'linear' | 'log' | undefined
|
|
348
|
-
format: ((v: number) => string) | undefined
|
|
349
|
-
}): { labels: string[]; format: (v: number) => string } {
|
|
350
|
-
const { domain, ticks, nice, scale, format } = opts
|
|
351
|
-
const base = probeAxisLabels({
|
|
352
|
-
domain,
|
|
353
|
-
ticks,
|
|
354
|
-
nice,
|
|
355
|
-
...(scale !== undefined && { scale }),
|
|
356
|
-
...(format !== undefined && { format }),
|
|
357
|
-
})
|
|
358
|
-
if (format !== undefined || !shouldCompactYLabels(base.labels)) {
|
|
359
|
-
return base
|
|
360
|
-
}
|
|
361
|
-
const compact = (v: number): string => compactNumber(v) ?? base.format(v)
|
|
362
|
-
return {
|
|
363
|
-
labels: probeAxisLabels({
|
|
364
|
-
domain,
|
|
365
|
-
ticks,
|
|
366
|
-
nice,
|
|
367
|
-
format: compact,
|
|
368
|
-
...(scale !== undefined && { scale }),
|
|
369
|
-
}).labels,
|
|
370
|
-
format: compact,
|
|
371
|
-
}
|
|
372
|
-
}
|
|
373
|
-
|
|
374
|
-
/**
|
|
375
|
-
* One y-axis' real scale, built from its resolved domain — shared by the left and right axis so
|
|
376
|
-
* the log branch (`scaleLog` + `nice` + the 1-2-5 tick override) is written and commented exactly
|
|
377
|
-
* once instead of as two independently-maintained twins.
|
|
378
|
-
*/
|
|
379
|
-
function buildYScale<T>(
|
|
380
|
-
cfg: AxisConfig<T> | undefined,
|
|
381
|
-
domain: [number, number],
|
|
382
|
-
yMax: number,
|
|
383
|
-
ticks: number,
|
|
384
|
-
): ContinuousScale {
|
|
385
|
-
if (cfg?.scale === 'log') {
|
|
386
|
-
const scale = scaleLog<number>({
|
|
387
|
-
domain,
|
|
388
|
-
range: [yMax, 0],
|
|
389
|
-
...(cfg.nice === true && { nice: true }),
|
|
390
|
-
})
|
|
391
|
-
// Paint the 1-2-5 tick law instead of d3's own log ticks: `AxisLeftNumeric`/`GridRows` resolve
|
|
392
|
-
// ticks through visx's `getTicks(scale, numTicks)` -> `scale.ticks(numTicks)`, so overriding
|
|
393
|
-
// the method on this instance is the one seam that reaches both without a raw `<AxisLeft>`
|
|
394
|
-
// escape hatch. Nothing else calls `.ticks()` on the real scale (only `probeAxisLabels`' own
|
|
395
|
-
// throwaway probe does, and that stays untouched).
|
|
396
|
-
const tickDomain = cfg.nice === true ? niceLogDomain(domain) : domain
|
|
397
|
-
scale.ticks = () => logTickValues(tickDomain, ticks)
|
|
398
|
-
return scale
|
|
399
|
-
}
|
|
400
|
-
return scaleLinear<number>({
|
|
401
|
-
domain,
|
|
402
|
-
range: [yMax, 0],
|
|
403
|
-
...(cfg?.nice === true && { nice: true }),
|
|
404
|
-
})
|
|
405
|
-
}
|
|
406
|
-
|
|
407
|
-
/**
|
|
408
|
-
* The x-axis margin ladder, as one pure decision. The flat (unrotated) margin is what every case
|
|
409
|
-
* resolves to except a rotated or wrapped axis, and it is what the rotation decision itself is
|
|
410
|
-
* measured against — deciding needs an `xMax`, and `xMax` needs a margin, so the flat pass breaks
|
|
411
|
-
* the loop. An explicit `xLabelRotate` always wins — including `0`, the documented "never rotate"
|
|
412
|
-
* opt-out; unset, only a categorical (band) axis wraps, and rotates only when even wrapped it
|
|
413
|
-
* doesn't fit (`planXLabels`) — a time or number domain only thins.
|
|
414
|
-
*
|
|
415
|
-
* Per rotation: 45° reuses its pre-measured margin and measures its tick room through
|
|
416
|
-
* {@link rotatedXLabelPx} (a rotated label projects wider than its glyph box); 90° measures fresh
|
|
417
|
-
* (one line box wide, so the flat label room governs its thinning); a wrapped flat axis re-measures
|
|
418
|
-
* for its extra line(s) and thins by the wrapped width.
|
|
419
|
-
*/
|
|
420
|
-
function resolveXAxisLayout(input: {
|
|
421
|
-
marginInput: AutoMarginInput
|
|
422
|
-
flatMargin: ChartMargin
|
|
423
|
-
rotated45Margin: ChartMargin
|
|
424
|
-
flatLabelPx: number
|
|
425
|
-
xLabels: string[]
|
|
426
|
-
fontPx: number
|
|
427
|
-
plotWidth: number
|
|
428
|
-
categorical: boolean
|
|
429
|
-
xLabelRotate: 0 | 45 | 90 | undefined
|
|
430
|
-
}): {
|
|
431
|
-
baseMargin: ChartMargin
|
|
432
|
-
rotate: 0 | 45 | 90
|
|
433
|
-
wrapWidth: number | undefined
|
|
434
|
-
tickLabelPx: number
|
|
435
|
-
} {
|
|
436
|
-
const { marginInput, flatMargin, rotated45Margin, flatLabelPx, xLabels, fontPx, categorical } =
|
|
437
|
-
input
|
|
438
|
-
const flatXMax = Math.max(input.plotWidth - flatMargin.left - flatMargin.right, 0)
|
|
439
|
-
const xPlan = planXLabels({ labels: xLabels, plotWidth: flatXMax, fontPx, categorical })
|
|
440
|
-
const rotate = input.xLabelRotate ?? (categorical ? xPlan.rotate : 0)
|
|
441
|
-
if (rotate === 45) {
|
|
442
|
-
const tickLabelPx = rotatedXLabelPx(xLabels, fontPx)
|
|
443
|
-
return { baseMargin: rotated45Margin, rotate, wrapWidth: undefined, tickLabelPx }
|
|
444
|
-
}
|
|
445
|
-
if (rotate === 90) {
|
|
446
|
-
const baseMargin = autoMargin({ ...marginInput, rotate })
|
|
447
|
-
return { baseMargin, rotate, wrapWidth: undefined, tickLabelPx: flatLabelPx }
|
|
448
|
-
}
|
|
449
|
-
if (!xPlan.wrap)
|
|
450
|
-
return { baseMargin: flatMargin, rotate, wrapWidth: undefined, tickLabelPx: flatLabelPx }
|
|
451
|
-
const baseMargin = autoMargin({ ...marginInput, bottomLines: xPlan.lines })
|
|
452
|
-
return { baseMargin, rotate, wrapWidth: xPlan.wrapPx, tickLabelPx: xPlan.labelPx }
|
|
453
|
-
}
|
|
454
|
-
|
|
455
|
-
/**
|
|
456
|
-
* The cartesian chart primitive — the rung that was missing between `ChartFrame` and raw visx
|
|
457
|
-
* (`docs/CHARTS-SPEC.md` §2).
|
|
458
|
-
*
|
|
459
|
-
* It owns, once, everything every chart repeated: measured margins, both y scales and their
|
|
460
|
-
* domains, the x scale and its tick thinning, grid, zones, axes, the shared cursor, the crosshair
|
|
461
|
-
* and its per-series dots, the hover/keyboard overlay, and the derived tooltip. The child draws
|
|
462
|
-
* marks and nothing else, so two charts cannot drift apart in any of those layers — that identity
|
|
463
|
-
* IS the consistency guarantee.
|
|
464
|
-
*
|
|
465
|
-
* Margins are MEASURED from the labels that will actually be painted, so a wide tick label widens
|
|
466
|
-
* its own gutter instead of clipping or needing a hand-tuned `margin` prop.
|
|
467
|
-
*/
|
|
468
|
-
export function CartesianChart<T>({
|
|
469
|
-
data,
|
|
470
|
-
chartId,
|
|
471
|
-
getX,
|
|
472
|
-
series,
|
|
473
|
-
y,
|
|
474
|
-
y2,
|
|
475
|
-
xTicks,
|
|
476
|
-
xTickValues,
|
|
477
|
-
formatX = fmtAxisDate,
|
|
478
|
-
xLabelRotate,
|
|
479
|
-
zones,
|
|
480
|
-
xZones,
|
|
481
|
-
refLines,
|
|
482
|
-
height,
|
|
483
|
-
aspectRatio,
|
|
484
|
-
fill,
|
|
485
|
-
legend,
|
|
486
|
-
tooltip,
|
|
487
|
-
margin: marginOverride,
|
|
488
|
-
cursorValue,
|
|
489
|
-
cursorResolution,
|
|
490
|
-
ariaLabel,
|
|
491
|
-
isPending,
|
|
492
|
-
state,
|
|
493
|
-
className,
|
|
494
|
-
style,
|
|
495
|
-
children,
|
|
496
|
-
}: CartesianChartProps<T>): ReactNode {
|
|
497
|
-
const [highlighted, setHighlighted] = useState<string | null>(null)
|
|
498
|
-
|
|
499
|
-
return (
|
|
500
|
-
<ChartFrame
|
|
501
|
-
series={series}
|
|
502
|
-
chartId={chartId}
|
|
503
|
-
{...(height !== undefined && { height })}
|
|
504
|
-
{...(aspectRatio !== undefined && { aspectRatio })}
|
|
505
|
-
{...(fill !== undefined && { fill })}
|
|
506
|
-
{...(ariaLabel !== undefined && { ariaLabel })}
|
|
507
|
-
{...(isPending !== undefined && { isPending })}
|
|
508
|
-
{...(state !== undefined && { state })}
|
|
509
|
-
{...(className !== undefined && { className })}
|
|
510
|
-
{...(style !== undefined && { style })}
|
|
511
|
-
legend={resolveLegend(
|
|
512
|
-
legend,
|
|
513
|
-
{ highlighted, onHighlight: setHighlighted },
|
|
514
|
-
deriveLegend(series).length,
|
|
515
|
-
)}
|
|
516
|
-
>
|
|
517
|
-
{(plot) => (
|
|
518
|
-
<CartesianPlot
|
|
519
|
-
data={data}
|
|
520
|
-
chartId={chartId}
|
|
521
|
-
getX={getX}
|
|
522
|
-
series={series}
|
|
523
|
-
{...(y !== undefined && { y })}
|
|
524
|
-
{...(y2 !== undefined && { y2 })}
|
|
525
|
-
{...(xTicks !== undefined && { xTicks })}
|
|
526
|
-
{...(xTickValues !== undefined && { xTickValues })}
|
|
527
|
-
formatX={formatX}
|
|
528
|
-
{...(xLabelRotate !== undefined && { xLabelRotate })}
|
|
529
|
-
{...(zones !== undefined && { zones })}
|
|
530
|
-
{...(xZones !== undefined && { xZones })}
|
|
531
|
-
{...(refLines !== undefined && { refLines })}
|
|
532
|
-
{...(tooltip !== undefined && { tooltip })}
|
|
533
|
-
{...(marginOverride !== undefined && { marginOverride })}
|
|
534
|
-
{...(cursorValue !== undefined && { cursorValue })}
|
|
535
|
-
{...(cursorResolution !== undefined && { cursorResolution })}
|
|
536
|
-
{...(ariaLabel !== undefined && { ariaLabel })}
|
|
537
|
-
plot={plot}
|
|
538
|
-
highlighted={highlighted}
|
|
539
|
-
>
|
|
540
|
-
{children}
|
|
541
|
-
</CartesianPlot>
|
|
542
|
-
)}
|
|
543
|
-
</ChartFrame>
|
|
544
|
-
)
|
|
545
|
-
}
|
|
546
|
-
|
|
547
|
-
type CartesianPlotProps<T> = Omit<
|
|
548
|
-
CartesianChartProps<T>,
|
|
549
|
-
| 'height'
|
|
550
|
-
| 'aspectRatio'
|
|
551
|
-
| 'fill'
|
|
552
|
-
| 'legend'
|
|
553
|
-
| 'isPending'
|
|
554
|
-
| 'state'
|
|
555
|
-
| 'margin'
|
|
556
|
-
| 'className'
|
|
557
|
-
| 'style'
|
|
558
|
-
> & {
|
|
559
|
-
plot: { width: number; height: number; hidden: ReadonlySet<string>; legendInHeader: boolean }
|
|
560
|
-
highlighted: string | null
|
|
561
|
-
marginOverride?: Partial<ChartMargin>
|
|
562
|
-
}
|
|
563
|
-
|
|
564
|
-
/** Split from {@link CartesianChart} so scale + margin work runs only once the frame has resolved
|
|
565
|
-
* a non-empty plot rect (and so the hook order never depends on that rect). */
|
|
566
|
-
function CartesianPlot<T>({
|
|
567
|
-
data,
|
|
568
|
-
chartId,
|
|
569
|
-
getX,
|
|
570
|
-
series,
|
|
571
|
-
y,
|
|
572
|
-
y2,
|
|
573
|
-
xTicks,
|
|
574
|
-
xTickValues,
|
|
575
|
-
formatX = fmtAxisDate,
|
|
576
|
-
xLabelRotate,
|
|
577
|
-
zones,
|
|
578
|
-
xZones,
|
|
579
|
-
refLines,
|
|
580
|
-
tooltip,
|
|
581
|
-
marginOverride,
|
|
582
|
-
cursorValue,
|
|
583
|
-
cursorResolution,
|
|
584
|
-
ariaLabel,
|
|
585
|
-
plot,
|
|
586
|
-
highlighted,
|
|
587
|
-
children,
|
|
588
|
-
}: CartesianPlotProps<T>): ReactNode {
|
|
589
|
-
const { hidden } = plot
|
|
590
|
-
// The tier `ChartFrame` resolved from its own MEASURED width. Everything sized by it here is
|
|
591
|
-
// the half a hook cannot reach: the tick font the margins are MEASURED at, and the margin
|
|
592
|
-
// floors themselves (`docs/CHARTS-SPEC.md` §8).
|
|
593
|
-
const tier = useChartMetrics()
|
|
594
|
-
const containerClass = useChartContainerClass()
|
|
595
|
-
const tight = isTightClass(containerClass)
|
|
596
|
-
|
|
597
|
-
const visible = useMemo(() => series.filter((s) => !hidden.has(s.key)), [series, hidden])
|
|
598
|
-
const leftSeries = useMemo(() => visible.filter((s) => s.axis !== 'right'), [visible])
|
|
599
|
-
const rightSeries = useMemo(() => visible.filter((s) => s.axis === 'right'), [visible])
|
|
600
|
-
|
|
601
|
-
// Honest deps on the accessors, deliberately: a ref would keep the scales, ticks and margins
|
|
602
|
-
// keyed on `data` alone, and then swapping which field `getX` reads (a field picker over the
|
|
603
|
-
// same rows) would render marks through a new accessor against stale scales. The re-render this
|
|
604
|
-
// costs is narrower than it looks — a cursor move re-renders `CartesianPlot` without changing
|
|
605
|
-
// its props, so hover frames reuse these memos regardless.
|
|
606
|
-
const keys = useMemo(() => data.map(getX), [data, getX])
|
|
607
|
-
|
|
608
|
-
// ── Pass 1: domains + tick labels, both independent of the pixel range ──────────────────────
|
|
609
|
-
// This is what breaks the margin/scale circularity: a linear scale's tick VALUES depend only on
|
|
610
|
-
// its domain, so the labels can be measured before the plot rect exists.
|
|
611
|
-
// Overlay bounds per axis — see `resolveAxisDomain`'s `extraBounds`.
|
|
612
|
-
const [leftBounds, rightBounds] = useMemo(() => {
|
|
613
|
-
const left: number[] = []
|
|
614
|
-
const right: number[] = []
|
|
615
|
-
for (const z of zones ?? []) (z.axisSide === 'right' ? right : left).push(z.from, z.to)
|
|
616
|
-
for (const l of refLines ?? []) (l.axis === 'right' ? right : left).push(l.value)
|
|
617
|
-
return [left, right]
|
|
618
|
-
}, [zones, refLines])
|
|
619
|
-
|
|
620
|
-
const leftDomain = useMemo(
|
|
621
|
-
() => resolveAxisDomain(y, data, leftSeries, leftBounds),
|
|
622
|
-
[y, data, leftSeries, leftBounds],
|
|
623
|
-
)
|
|
624
|
-
const rightDomain = useMemo(
|
|
625
|
-
() => (y2 === undefined ? null : resolveAxisDomain(y2, data, rightSeries, rightBounds)),
|
|
626
|
-
[y2, data, rightSeries, rightBounds],
|
|
627
|
-
)
|
|
628
|
-
|
|
629
|
-
// Tick count is a law of the plot height (one per ~44px, 2 under `VX.minPlotHeight`), estimated
|
|
630
|
-
// from the token floors because the real margins depend on the labels these ticks produce. A
|
|
631
|
-
// consumer's `ticks` always wins.
|
|
632
|
-
const estimatedPlotHeight = plot.height - tier.margin.top - tier.margin.bottom
|
|
633
|
-
const leftTicks = y?.ticks ?? yTickCount(estimatedPlotHeight)
|
|
634
|
-
const rightTicks = y2?.ticks ?? yTickCount(estimatedPlotHeight)
|
|
635
|
-
|
|
636
|
-
const { labels: leftLabels, format: leftFormat } = useMemo(
|
|
637
|
-
() =>
|
|
638
|
-
probeYAxis({
|
|
639
|
-
domain: leftDomain,
|
|
640
|
-
ticks: leftTicks,
|
|
641
|
-
nice: y?.nice ?? false,
|
|
642
|
-
scale: y?.scale,
|
|
643
|
-
format: y?.format,
|
|
644
|
-
}),
|
|
645
|
-
[leftDomain, leftTicks, y?.format, y?.nice, y?.scale],
|
|
646
|
-
)
|
|
647
|
-
|
|
648
|
-
const { labels: rightLabels, format: rightFormat } = useMemo(
|
|
649
|
-
() =>
|
|
650
|
-
rightDomain === null
|
|
651
|
-
? { labels: [], format: (v: number) => String(v) }
|
|
652
|
-
: probeYAxis({
|
|
653
|
-
domain: rightDomain,
|
|
654
|
-
ticks: rightTicks,
|
|
655
|
-
nice: y2?.nice ?? false,
|
|
656
|
-
scale: y2?.scale,
|
|
657
|
-
format: y2?.format,
|
|
658
|
-
}),
|
|
659
|
-
[rightDomain, rightTicks, y2?.format, y2?.nice, y2?.scale],
|
|
660
|
-
)
|
|
661
|
-
|
|
662
|
-
const xLabels = useMemo(() => keys.map(formatX), [keys, formatX])
|
|
663
|
-
|
|
664
|
-
// Ladder step 5: at compact/micro the y labels sit inside the plot (micro: no y axis), so the
|
|
665
|
-
// left gutter drops to its floor. An explicit `margin.left` means the consumer laid out an
|
|
666
|
-
// outside gutter — it keeps the outside axis. `CartesianChart` always has a left axis.
|
|
667
|
-
const yPlacement = resolveYPlacement(containerClass, { marginOverrideLeft: marginOverride?.left })
|
|
668
|
-
// A whitespace test misclassified any spaced date format ("Mar 01") as categorical, which then
|
|
669
|
-
// wrapped or rotated a time axis that should only ever thin (§ ladder step 4). Domain kind is
|
|
670
|
-
// the actual law: only a band (category) domain wraps or rotates; time and number domains thin.
|
|
671
|
-
const categorical = tight && classifyDomain(keys) === 'band'
|
|
672
|
-
|
|
673
|
-
// The room one flat x tick label needs at the tick font the axis will actually paint
|
|
674
|
-
// (`docs/CHARTS-SPEC.md` §8) — keyed on the labels and font alone, so a y-label or margin change
|
|
675
|
-
// never re-measures every x label.
|
|
676
|
-
const flatLabelPx = useMemo(() => xLabelPxFor(xLabels, tier.axisFont), [xLabels, tier.axisFont])
|
|
677
|
-
|
|
678
|
-
// Everything `autoMargin` measures except the rotation, measured once for every pass so a label
|
|
679
|
-
// can never differ between the one that DECIDES and the one that PAINTS — plus the 45° margin (a
|
|
680
|
-
// rotated label reaches into the left gutter).
|
|
681
|
-
const measured = useMemo(() => {
|
|
682
|
-
const marginInput: AutoMarginInput = {
|
|
683
|
-
left: yPlacement === 'outside' ? leftLabels : [],
|
|
684
|
-
right: rightLabels,
|
|
685
|
-
bottom: xLabels,
|
|
686
|
-
fontPx: tier.axisFont,
|
|
687
|
-
// An inside-placed y label paints IN the plot, so the left gutter it used to reserve
|
|
688
|
-
// (the phone tier's own margin floor) is dead space — only the inside-label floor applies.
|
|
689
|
-
floor: resolveMarginFloor(yPlacement, tier.margin),
|
|
690
|
-
anchorTerminals: tight,
|
|
691
|
-
...(marginOverride !== undefined && { override: marginOverride }),
|
|
692
|
-
}
|
|
693
|
-
return {
|
|
694
|
-
marginInput,
|
|
695
|
-
flatMargin: autoMargin(marginInput),
|
|
696
|
-
rotated45Margin: autoMargin({ ...marginInput, rotate: 45 }),
|
|
697
|
-
}
|
|
698
|
-
}, [
|
|
699
|
-
leftLabels,
|
|
700
|
-
rightLabels,
|
|
701
|
-
xLabels,
|
|
702
|
-
tier.axisFont,
|
|
703
|
-
tier.margin,
|
|
704
|
-
marginOverride,
|
|
705
|
-
tight,
|
|
706
|
-
yPlacement,
|
|
707
|
-
])
|
|
708
|
-
const { baseMargin, rotate, wrapWidth, tickLabelPx } = useMemo(
|
|
709
|
-
() =>
|
|
710
|
-
resolveXAxisLayout({
|
|
711
|
-
...measured,
|
|
712
|
-
flatLabelPx,
|
|
713
|
-
xLabels,
|
|
714
|
-
fontPx: tier.axisFont,
|
|
715
|
-
plotWidth: plot.width,
|
|
716
|
-
categorical,
|
|
717
|
-
xLabelRotate,
|
|
718
|
-
}),
|
|
719
|
-
[measured, flatLabelPx, xLabels, tier.axisFont, plot.width, categorical, xLabelRotate],
|
|
720
|
-
)
|
|
721
|
-
|
|
722
|
-
// End-of-line labels are planned FIRST, against the base margin: the right gutter is reserved
|
|
723
|
-
// only when the labels will actually draw. `yScale` depends on the plot height alone, so it is
|
|
724
|
-
// safe to build before the right margin is settled.
|
|
725
|
-
const yMax = Math.max(plot.height - baseMargin.top - baseMargin.bottom, 0)
|
|
726
|
-
const yScale = useMemo(
|
|
727
|
-
() => buildYScale(y, leftDomain, yMax, leftTicks),
|
|
728
|
-
[y, leftDomain, yMax, leftTicks],
|
|
729
|
-
)
|
|
730
|
-
const endPlan = useMemo(
|
|
731
|
-
() =>
|
|
732
|
-
planEndLabels({
|
|
733
|
-
containerClass,
|
|
734
|
-
hasY2: y2 !== undefined,
|
|
735
|
-
hasMarginRight: marginOverride?.right !== undefined,
|
|
736
|
-
hasHeaderLegend: plot.legendInHeader,
|
|
737
|
-
visible,
|
|
738
|
-
data,
|
|
739
|
-
yScale,
|
|
740
|
-
yMax,
|
|
741
|
-
fontPx: tier.axisFont,
|
|
742
|
-
plotWidth: plot.width - baseMargin.left - baseMargin.right,
|
|
743
|
-
}),
|
|
744
|
-
[
|
|
745
|
-
containerClass,
|
|
746
|
-
y2,
|
|
747
|
-
marginOverride?.right,
|
|
748
|
-
plot.legendInHeader,
|
|
749
|
-
visible,
|
|
750
|
-
data,
|
|
751
|
-
yScale,
|
|
752
|
-
yMax,
|
|
753
|
-
tier.axisFont,
|
|
754
|
-
plot.width,
|
|
755
|
-
baseMargin.left,
|
|
756
|
-
baseMargin.right,
|
|
757
|
-
],
|
|
758
|
-
)
|
|
759
|
-
const endLabels = endPlan?.labels ?? []
|
|
760
|
-
const margin = useMemo(
|
|
761
|
-
() =>
|
|
762
|
-
endPlan === null ? baseMargin : { ...baseMargin, right: baseMargin.right + endPlan.gutter },
|
|
763
|
-
[baseMargin, endPlan],
|
|
764
|
-
)
|
|
765
|
-
|
|
766
|
-
// ── Pass 2: the real scales, now that the plot rect is known ────────────────────────────────
|
|
767
|
-
const xMax = Math.max(plot.width - margin.left - margin.right, 0)
|
|
768
|
-
|
|
769
|
-
const xScale = useMemo(
|
|
770
|
-
() => scalePoint<string>({ domain: keys, range: [0, xMax], padding: 0.5 }),
|
|
771
|
-
[keys, xMax],
|
|
772
|
-
)
|
|
773
|
-
const y2Scale = useMemo(
|
|
774
|
-
() => (rightDomain === null ? null : buildYScale(y2, rightDomain, yMax, rightTicks)),
|
|
775
|
-
[y2, rightDomain, yMax, rightTicks],
|
|
776
|
-
)
|
|
777
|
-
|
|
778
|
-
// Resolution order: explicit VALUES win, then an explicit COUNT, then as many as fit.
|
|
779
|
-
const tickValues = useMemo(() => {
|
|
780
|
-
if (xTickValues !== undefined) return [...xTickValues(keys, xMax)]
|
|
781
|
-
if (xTicks !== undefined) return smartTicksEvery(keys, xTicks)
|
|
782
|
-
// Micro: the two terminals only.
|
|
783
|
-
if (containerClass === 'micro')
|
|
784
|
-
return keys.length > 1 ? [keys[0]!, keys[keys.length - 1]!] : keys
|
|
785
|
-
return smartTicks(keys, xMax, rotate === 0 || rotate === 45 ? tickLabelPx : undefined, tight)
|
|
786
|
-
}, [keys, xMax, xTicks, xTickValues, tickLabelPx, rotate, containerClass, tight])
|
|
787
|
-
|
|
788
|
-
const svgRef = useRef<SVGSVGElement>(null)
|
|
789
|
-
const cursor = useChartCursor<T>({
|
|
790
|
-
data,
|
|
791
|
-
chartId,
|
|
792
|
-
getKey: getX,
|
|
793
|
-
xScale,
|
|
794
|
-
marginLeft: margin.left,
|
|
795
|
-
boundaryRef: svgRef,
|
|
796
|
-
...(cursorResolution !== undefined && { resolution: cursorResolution }),
|
|
797
|
-
})
|
|
798
|
-
|
|
799
|
-
const tooltipEnabled = tooltip !== false
|
|
800
|
-
const tooltipCfg = tooltip === false ? undefined : tooltip
|
|
801
|
-
const point = cursor.point
|
|
802
|
-
const cursorX = point === null ? null : (xScale(getX(point)) ?? null)
|
|
803
|
-
const badge = tooltipCfg?.label === undefined || point === null ? null : tooltipCfg.label(point)
|
|
804
|
-
const formatHeader = tooltipCfg?.formatHeader
|
|
805
|
-
|
|
806
|
-
// Each series falls back to ITS OWN axis's tick format, so a right-axis value is never
|
|
807
|
-
// formatted with the left axis's rules (an explicit per-series `formatValue` still wins).
|
|
808
|
-
const tooltipSeries = useMemo(
|
|
809
|
-
() =>
|
|
810
|
-
visible.map((s) =>
|
|
811
|
-
s.formatValue === undefined
|
|
812
|
-
? { ...s, formatValue: s.axis === 'right' ? rightFormat : leftFormat }
|
|
813
|
-
: s,
|
|
814
|
-
),
|
|
815
|
-
[visible, leftFormat, rightFormat],
|
|
816
|
-
)
|
|
817
|
-
|
|
818
|
-
// Dual axis with exactly one visible series per side: the tick labels carry that series' colour,
|
|
819
|
-
// so the axis says which line it reads. Any other split leaves both axes neutral.
|
|
820
|
-
const tintAxes = y2 !== undefined && leftSeries.length === 1 && rightSeries.length === 1
|
|
821
|
-
const leftTint = tintAxes ? alpha(leftSeries[0]!.color, AXIS_TINT_ALPHA) : undefined
|
|
822
|
-
const rightTint = tintAxes ? alpha(rightSeries[0]!.color, AXIS_TINT_ALPHA) : undefined
|
|
823
|
-
|
|
824
|
-
const rows =
|
|
825
|
-
tooltipEnabled && point !== null ? deriveTooltipRows(tooltipSeries, point, leftFormat) : []
|
|
826
|
-
|
|
827
|
-
// This chart renders its tooltip either as the cursor SOURCE (always) or, opted in via
|
|
828
|
-
// `onFollow`, as a FOLLOWER (a sibling owns the cursor). A follower has no pointer under it, so
|
|
829
|
-
// it is always positioned via the anchored (crosshair) path below, regardless of `follow`.
|
|
830
|
-
const isFollowerRender = !cursor.isSource && tooltipCfg?.onFollow === true
|
|
831
|
-
const showTooltip = tooltipEnabled && point !== null && (cursor.isSource || isFollowerRender)
|
|
832
|
-
|
|
833
|
-
// Anchored mode resolves the crosshair's plot-local x into viewport space; following mode uses
|
|
834
|
-
// the pointer position `useChartCursor` already recorded. A follower render always anchors, since
|
|
835
|
-
// `follow`'s pointer-tracking path has no pointer to read on this chart. An unset `follow` also
|
|
836
|
-
// anchors on touch (spec §5) — the readout would otherwise sit under the finger; an EXPLICIT
|
|
837
|
-
// `follow` (true or false) always wins over that default.
|
|
838
|
-
const useAnchoredPosition =
|
|
839
|
-
tooltipCfg?.follow === false ||
|
|
840
|
-
(tooltipCfg?.follow === undefined && cursor.isTouch) ||
|
|
841
|
-
isFollowerRender
|
|
842
|
-
const anchorX = useAnchoredPosition && point !== null && cursorX !== null ? cursorX : null
|
|
843
|
-
const svgRect = anchorX === null ? undefined : svgRef.current?.getBoundingClientRect()
|
|
844
|
-
const tooltipAnchor =
|
|
845
|
-
svgRect === undefined || anchorX === null
|
|
846
|
-
? cursor.anchor
|
|
847
|
-
: { x: svgRect.left + margin.left + anchorX, y: svgRect.top + margin.top }
|
|
848
|
-
|
|
849
|
-
const ctx: PlotContext<T> = {
|
|
850
|
-
data,
|
|
851
|
-
visible,
|
|
852
|
-
hidden,
|
|
853
|
-
xScale,
|
|
854
|
-
yScale,
|
|
855
|
-
y2Scale,
|
|
856
|
-
xMax,
|
|
857
|
-
yMax,
|
|
858
|
-
margin,
|
|
859
|
-
cursorPoint: point,
|
|
860
|
-
highlighted,
|
|
861
|
-
}
|
|
862
|
-
|
|
863
|
-
return (
|
|
864
|
-
<>
|
|
865
|
-
<svg
|
|
866
|
-
ref={svgRef}
|
|
867
|
-
width={plot.width}
|
|
868
|
-
height={plot.height}
|
|
869
|
-
// `touch-action` on the plot `<svg>`, not the overlay `<rect>`: Chrome ignores it on an SVG
|
|
870
|
-
// child, so a horizontal scrub was claimed as a pan and cancelled (`R2C-2`).
|
|
871
|
-
style={{ touchAction: 'pan-y' }}
|
|
872
|
-
>
|
|
873
|
-
<Group left={margin.left} top={margin.top}>
|
|
874
|
-
{(y?.grid ?? true) && (
|
|
875
|
-
<GridRows scale={yScale} width={xMax} stroke={VX.grid} numTicks={leftTicks} />
|
|
876
|
-
)}
|
|
877
|
-
{xZones !== undefined && <XZoneRects zones={xZones} height={yMax} xScale={xScale} />}
|
|
878
|
-
{zones !== undefined && (
|
|
879
|
-
<ZoneRects zones={zones} width={xMax} leftScale={yScale} rightScale={y2Scale} />
|
|
880
|
-
)}
|
|
881
|
-
|
|
882
|
-
{children(ctx)}
|
|
883
|
-
|
|
884
|
-
{refLines?.map((line, i) => {
|
|
885
|
-
const scale = line.axis === 'right' && y2Scale !== null ? y2Scale : yScale
|
|
886
|
-
return (
|
|
887
|
-
<line
|
|
888
|
-
key={`${line.axis ?? 'left'}-${line.value}-${i}`}
|
|
889
|
-
x1={0}
|
|
890
|
-
x2={xMax}
|
|
891
|
-
y1={scale(line.value)}
|
|
892
|
-
y2={scale(line.value)}
|
|
893
|
-
stroke={line.color}
|
|
894
|
-
strokeWidth={1}
|
|
895
|
-
strokeDasharray={line.dashed === true ? VX.dashArray : undefined}
|
|
896
|
-
/>
|
|
897
|
-
)
|
|
898
|
-
})}
|
|
899
|
-
|
|
900
|
-
{tooltipEnabled && point !== null && cursorX !== null && (
|
|
901
|
-
<>
|
|
902
|
-
<Crosshair x={cursorX} top={0} bottom={yMax} />
|
|
903
|
-
{visible.map((s) => {
|
|
904
|
-
// A dot on a bar is noise — the hovered column is already marked by the crosshair,
|
|
905
|
-
// and the dot would land inside the fill rather than on an edge a reader tracks.
|
|
906
|
-
if (s.mark === 'bar') return null
|
|
907
|
-
const value =
|
|
908
|
-
cursorValue === undefined ? s.getValue(point) : cursorValue(point, s, visible)
|
|
909
|
-
if (value === null) return null
|
|
910
|
-
const scale = s.axis === 'right' && y2Scale !== null ? y2Scale : yScale
|
|
911
|
-
const cy = scale(value)
|
|
912
|
-
// A non-positive value on a log axis (or any other input a scale can't place)
|
|
913
|
-
// maps to NaN — the same guard the mark layer applies (`MultiLine`'s `LinePath
|
|
914
|
-
// defined`), so a stray crosshair dot never paints at `cy="NaN"`.
|
|
915
|
-
if (!Number.isFinite(cy)) return null
|
|
916
|
-
const marker = s.getMarker?.(point)
|
|
917
|
-
return (
|
|
918
|
-
<SeriesDot
|
|
919
|
-
key={s.key}
|
|
920
|
-
cx={cursorX}
|
|
921
|
-
cy={cy}
|
|
922
|
-
color={marker?.color ?? s.color}
|
|
923
|
-
{...(marker?.r !== undefined && { r: marker.r })}
|
|
924
|
-
/>
|
|
925
|
-
)
|
|
926
|
-
})}
|
|
927
|
-
</>
|
|
928
|
-
)}
|
|
929
|
-
|
|
930
|
-
{yPlacement !== 'none' && (
|
|
931
|
-
<AxisLeftNumeric
|
|
932
|
-
scale={yScale}
|
|
933
|
-
numTicks={leftTicks}
|
|
934
|
-
tickFormat={(v) => leftFormat(Number(v))}
|
|
935
|
-
inside={yPlacement === 'inside'}
|
|
936
|
-
{...(leftTint !== undefined && { tickColor: leftTint })}
|
|
937
|
-
/>
|
|
938
|
-
)}
|
|
939
|
-
{y2Scale !== null && (
|
|
940
|
-
<AxisRightNumeric
|
|
941
|
-
scale={y2Scale}
|
|
942
|
-
left={xMax}
|
|
943
|
-
numTicks={rightTicks}
|
|
944
|
-
tickFormat={(v) => rightFormat(Number(v))}
|
|
945
|
-
{...(rightTint !== undefined && { tickColor: rightTint })}
|
|
946
|
-
/>
|
|
947
|
-
)}
|
|
948
|
-
<AxisBottomDate
|
|
949
|
-
top={yMax}
|
|
950
|
-
scale={xScale}
|
|
951
|
-
tickValues={tickValues}
|
|
952
|
-
tickFormat={(v) => formatX(String(v))}
|
|
953
|
-
{...(rotate !== 0 && { rotate })}
|
|
954
|
-
anchorTerminals={tight && rotate === 0}
|
|
955
|
-
{...(wrapWidth !== undefined && { wrapWidth })}
|
|
956
|
-
/>
|
|
957
|
-
|
|
958
|
-
{endLabels.map(({ series: s, y: labelY }) => (
|
|
959
|
-
<text
|
|
960
|
-
key={`end-${s.key}`}
|
|
961
|
-
x={xMax + END_LABEL_GAP}
|
|
962
|
-
y={labelY}
|
|
963
|
-
dy="0.35em"
|
|
964
|
-
fill={s.color}
|
|
965
|
-
fontFamily={TICK_FONT_FAMILY}
|
|
966
|
-
fontSize={tier.axisFont}
|
|
967
|
-
opacity={
|
|
968
|
-
highlighted === null || s.key === highlighted || s.parent === highlighted ? 1 : 0.25
|
|
969
|
-
}
|
|
970
|
-
pointerEvents="none"
|
|
971
|
-
>
|
|
972
|
-
{s.label}
|
|
973
|
-
</text>
|
|
974
|
-
))}
|
|
975
|
-
|
|
976
|
-
<HoverOverlay
|
|
977
|
-
width={xMax}
|
|
978
|
-
height={yMax}
|
|
979
|
-
{...cursorSliderProps({ cursor: cursor, data: data, getX, formatX, ariaLabel })}
|
|
980
|
-
/>
|
|
981
|
-
</Group>
|
|
982
|
-
</svg>
|
|
983
|
-
|
|
984
|
-
{showTooltip && (
|
|
985
|
-
<ChartTooltipFloat anchor={tooltipAnchor} ariaLive={cursor.isSource}>
|
|
986
|
-
<TooltipHeader
|
|
987
|
-
date={getX(point)}
|
|
988
|
-
{...(formatHeader !== undefined && {
|
|
989
|
-
format: (key: string) => formatHeader(key, point),
|
|
990
|
-
})}
|
|
991
|
-
{...(badge !== null && { label: badge.text, labelColor: badge.color })}
|
|
992
|
-
/>
|
|
993
|
-
<TooltipBody>
|
|
994
|
-
{tooltipCfg?.prependRows?.(point, { visible, hidden })}
|
|
995
|
-
<TooltipRows rows={rows} />
|
|
996
|
-
{tooltipCfg?.extraRows?.(point, { visible, hidden })}
|
|
997
|
-
</TooltipBody>
|
|
998
|
-
</ChartTooltipFloat>
|
|
999
|
-
)}
|
|
1000
|
-
</>
|
|
1001
|
-
)
|
|
1002
|
-
}
|