@eifi1/ui-kit 0.10.0 → 0.12.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/README.md +66 -37
- package/dist/chart.d.ts +3 -1
- package/dist/chart.js +2 -0
- package/dist/chart.js.map +1 -1
- package/dist/components/account-settings-labels.d.ts +105 -0
- package/dist/components/account-settings-labels.js +81 -0
- package/dist/components/account-settings-labels.js.map +1 -0
- package/dist/components/account-settings.d.ts +36 -52
- package/dist/components/account-settings.js +44 -8
- package/dist/components/account-settings.js.map +1 -1
- package/dist/components/alert-banner.d.ts +26 -1
- package/dist/components/alert-banner.js +10 -7
- package/dist/components/alert-banner.js.map +1 -1
- package/dist/components/amount-input.d.ts +26 -4
- package/dist/components/amount-input.js +5 -2
- package/dist/components/amount-input.js.map +1 -1
- package/dist/components/authed-image.d.ts +68 -0
- package/dist/components/authed-image.js +117 -0
- package/dist/components/authed-image.js.map +1 -0
- package/dist/components/breadcrumbs.d.ts +2 -1
- package/dist/components/breadcrumbs.js +5 -2
- package/dist/components/breadcrumbs.js.map +1 -1
- package/dist/components/bulk-action-bar.d.ts +51 -5
- package/dist/components/bulk-action-bar.js +88 -41
- package/dist/components/bulk-action-bar.js.map +1 -1
- package/dist/components/button-group.d.ts +107 -3
- package/dist/components/button-group.js +60 -5
- package/dist/components/button-group.js.map +1 -1
- package/dist/components/calculator.d.ts +17 -4
- package/dist/components/calendar-heatmap.d.ts +162 -0
- package/dist/components/calendar-heatmap.js +336 -0
- package/dist/components/calendar-heatmap.js.map +1 -0
- package/dist/components/chip.d.ts +2 -1
- package/dist/components/chip.js +6 -3
- package/dist/components/chip.js.map +1 -1
- package/dist/components/choice-card.d.ts +66 -2
- package/dist/components/choice-card.js +108 -1
- package/dist/components/choice-card.js.map +1 -1
- package/dist/components/combobox-core.js +2 -0
- package/dist/components/combobox-core.js.map +1 -1
- package/dist/components/combobox.d.ts +2 -2
- package/dist/components/combobox.js +31 -9
- package/dist/components/combobox.js.map +1 -1
- package/dist/components/copy-button.d.ts +52 -70
- package/dist/components/copy-button.js +1 -1
- package/dist/components/copy-button.js.map +1 -1
- package/dist/components/data-table-cells.d.ts +63 -0
- package/dist/components/data-table-cells.js +64 -0
- package/dist/components/data-table-cells.js.map +1 -0
- package/dist/components/data-table-filter-popover.d.ts +1 -1
- package/dist/components/data-table-filters.d.ts +1 -1
- package/dist/components/data-table-filters.js +31 -1
- package/dist/components/data-table-filters.js.map +1 -1
- package/dist/components/data-table-labels.d.ts +13 -0
- package/dist/components/data-table-labels.js +8 -1
- package/dist/components/data-table-labels.js.map +1 -1
- package/dist/components/data-table.d.ts +1 -1
- package/dist/components/data-table.js +104 -12
- package/dist/components/data-table.js.map +1 -1
- package/dist/components/date-picker.d.ts +3 -1
- package/dist/components/date-picker.js +15 -2
- package/dist/components/date-picker.js.map +1 -1
- package/dist/components/description-list.d.ts +23 -3
- package/dist/components/description-list.js +23 -3
- package/dist/components/description-list.js.map +1 -1
- package/dist/components/dialog-frame.d.ts +1 -0
- package/dist/components/entity-combobox.d.ts +1 -1
- package/dist/components/entity-combobox.js +18 -3
- package/dist/components/entity-combobox.js.map +1 -1
- package/dist/components/error-boundary.d.ts +92 -0
- package/dist/components/error-boundary.js +111 -0
- package/dist/components/error-boundary.js.map +1 -0
- package/dist/components/field.d.ts +69 -0
- package/dist/components/field.js +75 -0
- package/dist/components/field.js.map +1 -0
- package/dist/components/file-button.d.ts +51 -208
- package/dist/components/file-dropzone.d.ts +50 -2
- package/dist/components/floating-panel.d.ts +156 -4
- package/dist/components/floating-panel.js +193 -29
- package/dist/components/floating-panel.js.map +1 -1
- package/dist/components/form-actions.d.ts +53 -0
- package/dist/components/form-actions.js +98 -0
- package/dist/components/form-actions.js.map +1 -0
- package/dist/components/image-grid.d.ts +67 -0
- package/dist/components/image-grid.js +112 -0
- package/dist/components/image-grid.js.map +1 -0
- package/dist/components/lightbox.d.ts +104 -0
- package/dist/components/lightbox.js +229 -0
- package/dist/components/lightbox.js.map +1 -0
- package/dist/components/line-items.d.ts +114 -0
- package/dist/components/line-items.js +238 -0
- package/dist/components/line-items.js.map +1 -0
- package/dist/components/list.d.ts +37 -3
- package/dist/components/list.js +39 -14
- package/dist/components/list.js.map +1 -1
- package/dist/components/loading-state.d.ts +24 -0
- package/dist/components/loading-state.js +32 -0
- package/dist/components/loading-state.js.map +1 -0
- package/dist/components/menu-item.d.ts +13 -2
- package/dist/components/menu-item.js +11 -2
- package/dist/components/menu-item.js.map +1 -1
- package/dist/components/mini-calendar.d.ts +82 -5
- package/dist/components/mini-calendar.js +212 -64
- package/dist/components/mini-calendar.js.map +1 -1
- package/dist/components/modal.d.ts +20 -1
- package/dist/components/modal.js +26 -2
- package/dist/components/modal.js.map +1 -1
- package/dist/components/month-picker.d.ts +21 -1
- package/dist/components/month-picker.js +139 -26
- package/dist/components/month-picker.js.map +1 -1
- package/dist/components/multi-entity-combobox.d.ts +1 -1
- package/dist/components/multi-entity-combobox.js +19 -3
- package/dist/components/multi-entity-combobox.js.map +1 -1
- package/dist/components/nav-pills.d.ts +67 -0
- package/dist/components/nav-pills.js +69 -0
- package/dist/components/nav-pills.js.map +1 -0
- package/dist/components/number-field.d.ts +26 -5
- package/dist/components/number-field.js +5 -7
- package/dist/components/number-field.js.map +1 -1
- package/dist/components/number-input.d.ts +27 -5
- package/dist/components/number-input.js +7 -1
- package/dist/components/number-input.js.map +1 -1
- package/dist/components/numpad-sheet.d.ts +17 -4
- package/dist/components/passkeys-setting.d.ts +67 -0
- package/dist/components/passkeys-setting.js +214 -0
- package/dist/components/passkeys-setting.js.map +1 -0
- package/dist/components/picker-sheet.js +2 -1
- package/dist/components/picker-sheet.js.map +1 -1
- package/dist/components/pie-chart-labels.d.ts +20 -0
- package/dist/components/pie-chart-labels.js +12 -0
- package/dist/components/pie-chart-labels.js.map +1 -0
- package/dist/components/pie-chart.d.ts +101 -0
- package/dist/components/pie-chart.js +283 -0
- package/dist/components/pie-chart.js.map +1 -0
- package/dist/components/progress-bar.d.ts +73 -3
- package/dist/components/progress-bar.js +110 -8
- package/dist/components/progress-bar.js.map +1 -1
- package/dist/components/qr-code.d.ts +34 -0
- package/dist/components/qr-code.js +57 -0
- package/dist/components/qr-code.js.map +1 -0
- package/dist/components/search-field.d.ts +15 -3
- package/dist/components/search-field.js +5 -1
- package/dist/components/search-field.js.map +1 -1
- package/dist/components/series-chart.d.ts +16 -0
- package/dist/components/series-chart.js +4 -1
- package/dist/components/series-chart.js.map +1 -1
- package/dist/components/settings-fields.d.ts +50 -1
- package/dist/components/signed-amount.d.ts +121 -0
- package/dist/components/signed-amount.js +152 -0
- package/dist/components/signed-amount.js.map +1 -0
- package/dist/components/skeleton.d.ts +10 -3
- package/dist/components/skeleton.js +12 -2
- package/dist/components/skeleton.js.map +1 -1
- package/dist/components/stat-tile.d.ts +2 -1
- package/dist/components/stat-tile.js +5 -2
- package/dist/components/stat-tile.js.map +1 -1
- package/dist/components/status-dot.d.ts +6 -2
- package/dist/components/status-dot.js +6 -1
- package/dist/components/status-dot.js.map +1 -1
- package/dist/components/table.d.ts +77 -11
- package/dist/components/table.js +85 -17
- package/dist/components/table.js.map +1 -1
- package/dist/components/text-link.d.ts +176 -0
- package/dist/components/text-link.js +109 -0
- package/dist/components/text-link.js.map +1 -0
- package/dist/components/text.d.ts +8 -1
- package/dist/components/text.js +1 -0
- package/dist/components/text.js.map +1 -1
- package/dist/components/time-input.d.ts +50 -1
- package/dist/components/toggle-group.d.ts +28 -0
- package/dist/components/toggle-group.js +58 -9
- package/dist/components/toggle-group.js.map +1 -1
- package/dist/components/toggle-legend.d.ts +36 -3
- package/dist/components/toggle-legend.js +49 -0
- package/dist/components/toggle-legend.js.map +1 -1
- package/dist/components/tooltip.d.ts +11 -3
- package/dist/components/tooltip.js +2 -0
- package/dist/components/tooltip.js.map +1 -1
- package/dist/components/ui.d.ts +52 -729
- package/dist/components/ui.js +296 -27
- package/dist/components/ui.js.map +1 -1
- package/dist/components/use-table-state.d.ts +3 -52
- package/dist/components/use-table-state.js +128 -30
- package/dist/components/use-table-state.js.map +1 -1
- package/dist/components/user-avatar.d.ts +25 -3
- package/dist/components/user-avatar.js +32 -3
- package/dist/components/user-avatar.js.map +1 -1
- package/dist/{data-table-filters-Dh9uF_S-.d.ts → data-table-Drun8Fk9.d.ts} +305 -61
- package/dist/data-table.d.ts +2 -1
- package/dist/data-table.js +5 -1
- package/dist/data-table.js.map +1 -1
- package/dist/feedback/feedback-dialog.d.ts +26 -3
- package/dist/feedback/feedback-dialog.js +16 -2
- package/dist/feedback/feedback-dialog.js.map +1 -1
- package/dist/feedback/feedback-thread.d.ts +133 -0
- package/dist/feedback/feedback-thread.js +237 -0
- package/dist/feedback/feedback-thread.js.map +1 -0
- package/dist/feedback.d.ts +2 -1
- package/dist/feedback.js +1 -0
- package/dist/feedback.js.map +1 -1
- package/dist/hooks/use-authed-src.d.ts +71 -0
- package/dist/hooks/use-authed-src.js +63 -0
- package/dist/hooks/use-authed-src.js.map +1 -0
- package/dist/hooks/use-file-drop.d.ts +50 -2
- package/dist/hooks/use-hotkey.d.ts +59 -0
- package/dist/hooks/use-hotkey.js +105 -0
- package/dist/hooks/use-hotkey.js.map +1 -0
- package/dist/hooks/use-search-param-state.d.ts +83 -0
- package/dist/hooks/use-search-param-state.js +94 -0
- package/dist/hooks/use-search-param-state.js.map +1 -0
- package/dist/i18n/defaults.d.ts +17 -4
- package/dist/i18n/defaults.js +33 -1
- package/dist/i18n/defaults.js.map +1 -1
- package/dist/i18n/kit-labels.d.ts +47 -310
- package/dist/i18n/kit-labels.js +20 -5
- package/dist/i18n/kit-labels.js.map +1 -1
- package/dist/i18n/locales/de-CH-informal.d.ts +17 -4
- package/dist/i18n/locales/de-CH.d.ts +17 -4
- package/dist/i18n/locales/de-informal.d.ts +17 -4
- package/dist/i18n/locales/de.d.ts +17 -4
- package/dist/i18n/locales/de.js +165 -4
- package/dist/i18n/locales/de.js.map +1 -1
- package/dist/i18n/locales/es.d.ts +17 -4
- package/dist/i18n/locales/es.js +162 -4
- package/dist/i18n/locales/es.js.map +1 -1
- package/dist/i18n/locales/fr.d.ts +17 -4
- package/dist/i18n/locales/fr.js +162 -4
- package/dist/i18n/locales/fr.js.map +1 -1
- package/dist/i18n/locales/hu.d.ts +17 -4
- package/dist/i18n/locales/hu.js +162 -4
- package/dist/i18n/locales/hu.js.map +1 -1
- package/dist/i18n/locales/it.d.ts +17 -4
- package/dist/i18n/locales/it.js +162 -4
- package/dist/i18n/locales/it.js.map +1 -1
- package/dist/i18n/locales/zh.d.ts +17 -4
- package/dist/i18n/locales/zh.js +162 -4
- package/dist/i18n/locales/zh.js.map +1 -1
- package/dist/index.d.ts +45 -21
- package/dist/index.js +43 -1
- package/dist/index.js.map +1 -1
- package/dist/kit-labels-v3biUF1L.d.ts +1645 -0
- package/dist/lib/clipping.d.ts +21 -5
- package/dist/lib/clipping.js +3 -0
- package/dist/lib/clipping.js.map +1 -1
- package/dist/lib/dates.d.ts +17 -1
- package/dist/lib/dates.js +19 -0
- package/dist/lib/dates.js.map +1 -1
- package/dist/lib/format.d.ts +144 -0
- package/dist/lib/format.js +149 -0
- package/dist/lib/format.js.map +1 -0
- package/dist/lib/qr-encode.d.ts +44 -0
- package/dist/lib/qr-encode.js +338 -0
- package/dist/lib/qr-encode.js.map +1 -0
- package/dist/rhf/fields.d.ts +241 -0
- package/dist/rhf/fields.js +601 -0
- package/dist/rhf/fields.js.map +1 -0
- package/dist/rhf/form.d.ts +50 -1
- package/dist/rhf/line-items.d.ts +31 -0
- package/dist/rhf/line-items.js +59 -0
- package/dist/rhf/line-items.js.map +1 -0
- package/dist/rhf/use-rhf-wizard-step.d.ts +22 -0
- package/dist/rhf/use-rhf-wizard-step.js +38 -0
- package/dist/rhf/use-rhf-wizard-step.js.map +1 -0
- package/dist/rhf.d.ts +63 -1
- package/dist/rhf.js +3 -0
- package/dist/rhf.js.map +1 -1
- package/dist/shell/app-shell.d.ts +99 -2
- package/dist/shell/app-shell.js +58 -3
- package/dist/shell/app-shell.js.map +1 -1
- package/dist/shell/auth-layout.d.ts +74 -0
- package/dist/shell/auth-layout.js +97 -0
- package/dist/shell/auth-layout.js.map +1 -0
- package/dist/shell/top-bar-brand.d.ts +81 -0
- package/dist/shell/top-bar-brand.js +47 -0
- package/dist/shell/top-bar-brand.js.map +1 -0
- package/dist/shell/topbar-action-menu.d.ts +84 -3
- package/dist/shell/topbar-action-menu.js +115 -27
- package/dist/shell/topbar-action-menu.js.map +1 -1
- package/dist/shell.d.ts +58 -2
- package/dist/shell.js +2 -0
- package/dist/shell.js.map +1 -1
- package/dist/wizard/stepper-nav.d.ts +49 -1
- package/dist/wizard/wizard-context.d.ts +30 -1
- package/dist/wizard/wizard-context.js +23 -2
- package/dist/wizard/wizard-context.js.map +1 -1
- package/dist/wizard/wizard-step.d.ts +20 -5
- package/dist/wizard/wizard-step.js +16 -3
- package/dist/wizard/wizard-step.js.map +1 -1
- package/dist/wizard.d.ts +51 -3
- package/package.json +1 -1
- package/src/chart.ts +4 -0
- package/src/components/account-settings-labels.ts +190 -0
- package/src/components/account-settings.tsx +110 -63
- package/src/components/alert-banner.tsx +36 -7
- package/src/components/amount-input.tsx +13 -1
- package/src/components/authed-image.tsx +190 -0
- package/src/components/breadcrumbs.tsx +8 -2
- package/src/components/bulk-action-bar.tsx +163 -57
- package/src/components/button-group.tsx +129 -4
- package/src/components/calendar-heatmap.tsx +599 -0
- package/src/components/chip.tsx +8 -4
- package/src/components/choice-card.tsx +208 -1
- package/src/components/combobox-core.tsx +5 -0
- package/src/components/combobox.tsx +31 -9
- package/src/components/copy-button.tsx +3 -2
- package/src/components/data-table-cells.tsx +119 -0
- package/src/components/data-table-filters.ts +77 -0
- package/src/components/data-table-labels.ts +23 -0
- package/src/components/data-table.tsx +231 -13
- package/src/components/date-picker.tsx +19 -3
- package/src/components/description-list.tsx +52 -3
- package/src/components/entity-combobox.tsx +18 -3
- package/src/components/error-boundary.tsx +216 -0
- package/src/components/field.tsx +188 -0
- package/src/components/floating-panel.tsx +380 -16
- package/src/components/form-actions.tsx +191 -0
- package/src/components/image-grid.tsx +181 -0
- package/src/components/lightbox.tsx +374 -0
- package/src/components/line-items.tsx +385 -0
- package/src/components/list.tsx +93 -18
- package/src/components/loading-state.tsx +47 -0
- package/src/components/menu-item.tsx +29 -3
- package/src/components/mini-calendar.tsx +317 -57
- package/src/components/modal.tsx +61 -3
- package/src/components/month-picker.tsx +181 -26
- package/src/components/multi-entity-combobox.tsx +19 -3
- package/src/components/nav-pills.tsx +152 -0
- package/src/components/number-field.tsx +15 -10
- package/src/components/number-input.tsx +16 -1
- package/src/components/passkeys-setting.tsx +331 -0
- package/src/components/picker-sheet.tsx +7 -1
- package/src/components/pie-chart-labels.ts +32 -0
- package/src/components/pie-chart.tsx +479 -0
- package/src/components/progress-bar.tsx +241 -13
- package/src/components/qr-code.tsx +83 -0
- package/src/components/search-field.tsx +20 -4
- package/src/components/series-chart.tsx +21 -0
- package/src/components/signed-amount.tsx +286 -0
- package/src/components/skeleton.tsx +21 -3
- package/src/components/stat-tile.tsx +8 -2
- package/src/components/status-dot.tsx +10 -2
- package/src/components/table.tsx +186 -23
- package/src/components/text-link.tsx +248 -0
- package/src/components/text.tsx +9 -1
- package/src/components/toggle-group.tsx +106 -13
- package/src/components/toggle-legend.tsx +87 -2
- package/src/components/tooltip.tsx +17 -3
- package/src/components/ui.tsx +572 -44
- package/src/components/use-table-state.ts +265 -33
- package/src/components/user-avatar.tsx +57 -3
- package/src/data-table.ts +10 -0
- package/src/feedback/feedback-dialog.tsx +42 -3
- package/src/feedback/feedback-thread.tsx +434 -0
- package/src/feedback.ts +1 -0
- package/src/hooks/use-authed-src.ts +161 -0
- package/src/hooks/use-hotkey.ts +172 -0
- package/src/hooks/use-search-param-state.ts +187 -0
- package/src/i18n/defaults.ts +32 -0
- package/src/i18n/kit-labels.tsx +104 -8
- package/src/i18n/locales/de.ts +162 -0
- package/src/i18n/locales/es.ts +159 -0
- package/src/i18n/locales/fr.ts +162 -0
- package/src/i18n/locales/hu.ts +160 -0
- package/src/i18n/locales/it.ts +160 -0
- package/src/i18n/locales/zh.ts +159 -0
- package/src/index.ts +64 -0
- package/src/lib/clipping.ts +22 -4
- package/src/lib/dates.ts +37 -0
- package/src/lib/format.ts +325 -0
- package/src/lib/qr-encode.ts +420 -0
- package/src/rhf/fields.tsx +1054 -0
- package/src/rhf/line-items.tsx +130 -0
- package/src/rhf/use-rhf-wizard-step.ts +113 -0
- package/src/rhf.ts +8 -0
- package/src/shell/app-shell.tsx +147 -2
- package/src/shell/auth-layout.tsx +190 -0
- package/src/shell/top-bar-brand.tsx +76 -0
- package/src/shell/topbar-action-menu.tsx +260 -49
- package/src/shell.ts +2 -0
- package/src/wizard/wizard-context.tsx +50 -1
- package/src/wizard/wizard-step.tsx +43 -6
- package/tokens.css +12 -0
|
@@ -288,7 +288,8 @@ function SeriesPlot({
|
|
|
288
288
|
zoom,
|
|
289
289
|
labels: labelsProp,
|
|
290
290
|
locale: localeProp,
|
|
291
|
-
className
|
|
291
|
+
className,
|
|
292
|
+
minBarLength
|
|
292
293
|
}) {
|
|
293
294
|
const labels = useKitLabels("seriesChart", DEFAULT_SERIES_CHART_LABELS, labelsProp);
|
|
294
295
|
const locale = useKitLocale(localeProp);
|
|
@@ -576,6 +577,7 @@ function SeriesPlot({
|
|
|
576
577
|
const curve = entry.step ? "stepAfter" : entry.curve ?? "monotone";
|
|
577
578
|
const width = entry.strokeWidth ?? (entry.step ? STEP_WIDTH : LINE_WIDTH);
|
|
578
579
|
if (type === "bar") {
|
|
580
|
+
const stub = entry.minBarLength ?? minBarLength;
|
|
579
581
|
return /* @__PURE__ */ jsx(
|
|
580
582
|
Bar,
|
|
581
583
|
{
|
|
@@ -585,6 +587,7 @@ function SeriesPlot({
|
|
|
585
587
|
fill: color,
|
|
586
588
|
fillOpacity: entry.fillOpacity,
|
|
587
589
|
radius: entry.stack === void 0 ? BAR_RADIUS : 0,
|
|
590
|
+
...stub ? { minPointSize: (_value, index) => finite(plotted[index]?.[entry.key]) === void 0 ? 0 : stub } : {},
|
|
588
591
|
...focusedStop?.key === entry.key ? { shape: focusedBarShape(focusedStop.index) } : {},
|
|
589
592
|
onClick: onPointClick ? (_bar, index, event) => {
|
|
590
593
|
event.stopPropagation();
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../../src/components/series-chart.tsx"],"sourcesContent":["// The measurement plot: series against a swept numeric abscissa, any number of y axes,\n// dash patterns, vertical spans, and drag-to-zoom. Lifted out of lenkbank, where every\n// chart on every screen is this one arrangement of the kit's shell — so the arrangement\n// lives here once instead of as thirteen hand-assembled copies drifting apart.\n//\n// Built on `ChartContainer` + `ChartTooltipContent`, so it themes with the rest of the\n// chart kit: series default to the `--chart-N` ramp, axis text and grid take the\n// shell's tokens. It stays domain-free — every unit, title and number format is the\n// caller's, and the few words it can say itself are the `seriesChart` label namespace.\n//\n// **Every series may keep its own scale.** Position runs in millimetres and jerk in\n// hundreds of thousands of them per second cubed; on one axis the position line is\n// flat against the bottom. Normalising each series to its peak makes the y axis mean\n// nothing, so a caller declares an axis per incomparable channel instead, and may hide\n// all but the ones worth a column of numbers.\n//\n// Charts are drawn left-to-right in every writing direction — an abscissa is a number\n// line, not text — so `orientation` below is physical, and only the HTML chrome (the\n// reset button) is placed by logical side.\n//\n// **Bars, areas and periods too (0.8.0).** keksdose drew five money charts in raw\n// recharts — net worth, investments, income/expense, grouped payees, stacked categories\n// — each re-deciding the grid, the tooltip, the axis width and the \"—\" for a gap. They\n// are the same arrangement with a different mark, so a series now says `type: \"bar\" |\n// \"area\"` (and `stack`), and the abscissa may be a row of PERIODS (`x.type:\n// \"category\"`) or real dates (`x.type: \"time\"`) instead of a number the app had to\n// invent. What each of those does to the zoom is decided in one place,\n// `defaultZoomAxes` in `chart-zoom.tsx`.\nimport { useMemo, useRef, useState } from \"react\";\nimport type { KeyboardEvent, ReactNode, RefObject } from \"react\";\nimport {\n Area,\n Bar,\n CartesianGrid,\n ComposedChart,\n Label,\n Line,\n ReferenceDot,\n ReferenceLine,\n Rectangle,\n XAxis,\n YAxis,\n usePlotArea,\n useXAxisScale,\n type BarShapeProps,\n} from \"recharts\";\nimport { ChartContainer, ChartTooltip, ChartTooltipContent, type ChartConfig } from \"./chart\";\nimport {\n DEFAULT_Y_AXIS,\n axisExtent,\n withChartZoom,\n type ZoomAxesSetting,\n type ZoomBinding,\n type ZoomFitSource,\n} from \"./chart-zoom\";\nimport { STEP_DASH, strokeDash, type LegendEntry } from \"./toggle-legend\";\nimport { DEFAULT_SERIES_CHART_LABELS, type SeriesChartLabels } from \"./series-chart-labels\";\nimport { categoryTicks, integerTicks, niceTicks, timeTicksWithUnit, type TimeTickUnit } from \"./series-chart-ticks\";\n// The tick module stays internal; the one type of it a public prop names is re-exported.\nexport type { TimeTickUnit } from \"./series-chart-ticks\";\nimport { paletteFor } from \"../theme/chart-palette\";\nimport { useKitLabels, useKitLocale } from \"../i18n/kit-labels\";\nimport { cn } from \"../lib/cn\";\n\nexport interface SeriesChartSeries {\n /** The row key this line reads — and the `--color-<key>` it is painted with, so it\n * must be a CSS identifier. Build keys out of data with {@link seriesKey}. */\n key: string;\n label: ReactNode;\n /** Any CSS colour the chart shell accepts (hex, rgb/hsl, `var(--token)`). Default:\n * the kit's categorical ramp by position, `paletteFor(index)`. */\n color?: string;\n /** Marks the PAIRED line of a pair — the return stroke against the out-stroke, the\n * reference against the measurement. Shorthand for `dash: 1`. */\n dashed?: boolean;\n /** Which of {@link STROKE_PATTERNS} this line takes, for charts where the stroke says\n * WHICH QUANTITY and the colour says WHICH MEASUREMENT.\n *\n * Or an SVG `stroke-dasharray` string of the caller's own, for a pattern the five do\n * not have: keksdose's `\"4 3\"`, a tighter dash than the ladder's `\"5 4\"` that its\n * hand-drawn recharts lines used before the kit. The legend\n * entry ({@link seriesLegendEntries}) carries the same string, so it draws the same\n * pattern. */\n dash?: number | string;\n /** `stepAfter`, for a whole-number channel that jumps rather than travels — a\n * straight line between index 0 and index 1 draws an index of 0.5, which does not\n * exist. Drawn in the {@link STEP_DASH} pattern, whatever `dash` says. */\n step?: boolean;\n /** Which of `axes` this line is measured on. Default: `\"y\"`, the single one. */\n axis?: string;\n /**\n * The mark. `\"line\"` (the default) is what every chart before 0.8.0 drew. `\"bar\"` and\n * `\"area\"` are read as a LENGTH from zero, so the axis they stand on always includes\n * zero (see `SeriesChartAxis.includeZero`) and the zoom treats them differently (see\n * `defaultZoomAxes`). Bars without a `stack` stand side by side in each slot — the\n * grouped bars of keksdose's payee report.\n */\n type?: SeriesChartType;\n /**\n * Bars or areas with the same `stack` are drawn on top of each other and the axis is\n * fitted to their SUM (positive and negative layers apart, like recharts'\n * `stackOffset=\"sign\"`). keksdose's spending-by-category area. Ignored on a line:\n * recharts cannot stack one.\n */\n stack?: string;\n /**\n * Marks on the line's (or area's) points. `true` rings every sample — the price\n * history, where a shop has a value only on the days somebody shopped there and the\n * dots are the only thing saying which points were MEASURED. A function decides per\n * point: `true` for the default dot, `false`/`null` for none, or any SVG node drawn\n * as-is at `point.cx`/`point.cy` — a buy/sell marker on keksdose's paper price.\n * Never called for a point with no value. Bars have no points, and ignore it.\n */\n dot?: boolean | ((point: SeriesChartPoint) => ReactNode);\n /** Line (or area outline) weight in px. Default 2, or 1.5 for a `step`. keksdose\n * draws the subject of a chart at 2.5 and the reference it is read against at 1.5. */\n strokeWidth?: number;\n /** `\"linear\"` for a line that must not look smoothed — keksdose's cash-buffer\n * PROJECTION, a straight extrapolation that a monotone curve would dress up as data.\n * Default `\"monotone\"`; `step` wins over both. */\n curve?: \"monotone\" | \"linear\";\n /** An area's or bar's fill opacity. Default: 1 for a bar, 0.55 for a stacked area\n * (the layers must stay tellable apart where they meet) and 0.2 for a single one. */\n fillOpacity?: number;\n /**\n * The dot that follows the pointer along a line or an area. `false` takes it off a\n * series that is not a measurement — keksdose's cash-buffer PROJECTION, where a hover\n * ring on the extrapolated line reads as a sampled value (`cash-buffer-chart.tsx`).\n * `{ r }` sets its radius. Default: recharts' dot. Bars have none, and ignore it.\n */\n activeDot?: boolean | { r?: number };\n}\n\n/** What a series draws. See {@link SeriesChartSeries.type}. */\nexport type SeriesChartType = \"line\" | \"bar\" | \"area\";\n\n/** One point of a series, as a `dot` function is handed it. */\nexport interface SeriesChartPoint {\n /** The series' key. */\n key: string;\n /** The row's position in `rows`. */\n index: number;\n /** The caller's own row, with everything the chart did not plot still in it. */\n row: SeriesChartRow;\n /** The abscissa in the caller's terms: the number, the category, or (time) a Date. */\n x: SeriesChartXValue;\n value: number;\n /** Where the point is drawn, in the chart's pixels. */\n cx: number;\n cy: number;\n /** The series' paint, `var(--color-<key>)`. */\n color: string;\n}\n\n/** A row of a series chart: one abscissa value and the series' values at it. Anything\n * else in it (a raw ISO period for a drilldown) rides along untouched and is handed\n * back in {@link SeriesChartPoint.row} and {@link SeriesChartHit.row}. */\nexport type SeriesChartRow = Readonly<Record<string, unknown>>;\n\n/** An abscissa value: a number (`x.type: \"number\"`), a category (a string, a number or\n * a Date standing for a period), or a time (a Date, epoch ms or an ISO string). */\nexport type SeriesChartXValue = number | string | Date;\n\n/** Ticks a caller decides — a list, or a function of the domain on show, so a zoom\n * window gets ticks from the same rule instead of none. */\nexport type SeriesChartTickValues<T> =\n | readonly T[]\n | ((domain: [number, number]) => readonly T[] | undefined);\n\ninterface SeriesChartAxisShape {\n id: string;\n /**\n * Which side of the plot the ticks stand on. Left unless said otherwise — and said\n * otherwise for the right-hand chart of a FACING pair (see `facingAxes`), whose\n * scales go on the outside so neither column of numbers stands between two pictures\n * being compared.\n */\n orientation?: \"left\" | \"right\";\n /** Tints the ticks — and the title too, when exactly one series is measured on this\n * axis (see {@link soleSeriesColor}). */\n color?: string;\n /** What the TICKS need, in px. The title's strip is added on top. Default 48. */\n width?: number;\n /**\n * Pin the scale instead of fitting it to this chart's data. For a ROW of charts\n * read against each other: auto-fitted, a 200 N loop and a 2000 N one draw the\n * identical picture, and the comparison the layout promises is the one it fails.\n */\n domain?: [number, number];\n /** A tick, formatted — as a BARE number. The unit is said once, in the title; the\n * tooltip gets it from `valueFormat`. Default: `Intl.NumberFormat` in the kit's\n * locale, up to two fraction digits. */\n format?: (value: number) => string;\n /**\n * The tick values, instead of the round ones the chart picks. For a grid the DATA\n * dictates — keksdose's price axes tick on whole cents (`pricePaddedDomain`), where a\n * 1/2/5 ladder would print €1.25 under a formatter that can only say €1.3. Values\n * outside the domain on show are dropped; a function is asked again for every zoom\n * window, so the cent grid can refine with it.\n */\n tickValues?: SeriesChartTickValues<number>;\n /**\n * Keep zero inside the fitted band. On by default for an axis carrying a bar or an\n * area — their length IS the value, and a truncated baseline draws 40 as three times\n * 20 — and off for lines, whose shape is the point (a stock price anchored at zero is\n * a hairline). A pinned `domain` is left alone either way.\n */\n includeZero?: boolean;\n /**\n * Tick only on whole numbers — the y counterpart of `SeriesChartX.integerTicks`, and\n * what keksdose's user-count axis (`metrics-panel.tsx`, `wholeTicks`) and its runway\n * in days (`cash-buffer-chart.tsx`, `wholeDayTicks`) each wrote by hand: a band of\n * [0, 3.1] users is ticked 0 1 2 3, not 0 0.5 1 … 3, and a short runway is not ticked\n * 0 / 0.5 / 1 under a rounding formatter that prints \"1\" twice. A (zoom) window that\n * holds no whole number falls back to the ordinary ticks rather than to none.\n *\n * AUTOMATIC by default — on when every value this axis carries is a whole number\n * (counts), because that is where a half tick is a value no sample can have, and it\n * changes nothing on a span wider than about eight, which already ticks on whole\n * steps. `true` forces it over fractional data (days of runway computed as 43.7);\n * `false` keeps fractional ticks for a continuous quantity that merely happens to be\n * whole in this sample. `tickValues` wins over either.\n */\n integerTicks?: boolean;\n}\n\n/**\n * A y axis — and a VISIBLE one says what it measures.\n *\n * A union rather than an optional field, so the rule is the type's: a column of numbers\n * whose quantity and unit are not written down is a column somebody reads as whatever\n * they expected. `title: \"\"` is the explicit opt-out (the right-hand chart of a facing\n * pair, whose neighbour already said it). A HIDDEN axis scales its lines and draws\n * nothing, so there is nowhere for a title to go.\n */\nexport type SeriesChartAxis = SeriesChartAxisShape &\n ({ title: string; hide?: false } | { title?: string; hide: true });\n\n/**\n * What a tick or the tooltip heading of the abscissa is handed besides its position —\n * the value in the caller's own terms, which on a category or time axis is not the\n * number the plot runs on.\n */\nexport interface SeriesChartXTick {\n /** The number itself, the row's category, or (time) a Date. */\n value: SeriesChartXValue;\n /** The slot, on a category axis: the row's index in `rows`. */\n index?: number;\n /** On a time axis: what one step of the ticks on show is, so a label can say as much\n * as it means — a month start as \"Mar 26\", a midnight as \"14 Mar\". */\n unit?: TimeTickUnit;\n}\n\nexport interface SeriesChartX {\n /**\n * What the abscissa is.\n *\n * - `\"number\"` (the default) — a number line, and all a chart before 0.8.0 could draw.\n * - `\"category\"` — PERIODS or names, one evenly spaced slot per row, in row order:\n * keksdose's months, quarters and budget categories, which it used to hand recharts\n * preformatted. The values stay the caller's own — `\"2026-05\"`, a Date for the\n * month, a category name — and need not be sortable, unique or numeric. The plot\n * runs on the slot INDEX, which is what lets it zoom: a drag across the third to the\n * ninth month shows those months, a tick on each whole slot and the bars clipped at\n * the edge. What else zooms depends on the MARKS, not the axis — see `zoomAxes`.\n * - `\"time\"` — real TIME: a Date, epoch ms or an ISO string per row, placed by when\n * it happened. keksdose's price history and cash buffer, where a slot per row would\n * draw two receipts a day apart and two five months apart the same width. Ticks fall\n * on calendar boundaries (midnights, Mondays, month and quarter starts, new years)\n * in local time; a date-only ISO string is LOCAL midnight, not the UTC one\n * `new Date(\"2026-05-01\")` gives, which lands on the previous day west of Greenwich.\n * Zooms like a number line.\n */\n type?: \"number\" | \"category\" | \"time\";\n /** Row key of the abscissa. Default `\"x\"`, which is what {@link mergeSeries} writes. */\n key?: string;\n /** What the abscissa is, with its unit. Drawn under the axis. */\n title?: string;\n /**\n * A tick, formatted — bare, like the y axes'.\n *\n * `value` is the POSITION on the number line the plot runs on — the number itself,\n * epoch ms, or the slot index — so the one-argument formatters every chart before\n * 0.8.0 passes keep their meaning, and a time axis' `(ms) => …` is the tickFormatter\n * keksdose already has. The caller's own value (the category, the Date) is `tick.value`.\n * Default: the kit's number format; a category as is (a number formatted, a Date as a\n * medium date); a time as much of the date as the tick step means.\n */\n format?: (value: number, tick: SeriesChartXTick) => string;\n /**\n * Whether this chart prints the abscissa's ticks. On by default; off for every chart\n * of a stack sharing one x window but the bottom one, which prints them for all. It\n * costs no alignment: the x mapping is decided by the margins and the y bands.\n */\n ticks?: boolean;\n /** The tooltip's heading. Default: `format` — or, on a time axis, a medium date (with\n * the time for hourly data), since a tick's \"Mar 26\" is not which day it was. */\n label?: (value: number, tick: SeriesChartXTick) => ReactNode;\n /** The ticks instead of the automatic ones, in the caller's terms: numbers, the\n * categories to label, or instants. See `SeriesChartAxis.tickValues`. */\n tickValues?: SeriesChartTickValues<SeriesChartXValue>;\n /**\n * Tilt the tick labels by this many degrees — negative rises to the right. For long\n * category names that do not fit side by side: keksdose's budget performance draws its\n * categories at −45° (`budget-performance-tab.tsx`). The label is anchored by its END\n * for a negative angle and its START for a positive one, so it hangs off the tick\n * instead of being centred across it; the anchor is physical, like the plot (see\n * `ChartContainer`), so it is the same in RTL. The band under the axis grows to the\n * rotated height of the longest label on show, estimated from its length (at most\n * 120 px, past which a label is clipped). Default 0.\n */\n tickAngle?: number;\n /**\n * On a `\"number\"` axis, tick only on whole numbers: a step of 1 at the least, so a\n * five-point index series reads 0 1 2 3 4 rather than 0 0.5 1 … 4 — ticks at\n * positions no row can have (keksdose's short step series). A zoom window that holds\n * no whole number falls back to the ordinary ticks rather than to none.\n *\n * AUTOMATIC by default — on when every row's x is a whole number — because that is\n * exactly the case the half ticks are wrong in, and it changes nothing elsewhere: a\n * span wider than about eight already ticks on whole steps. `false` for a continuous\n * quantity that merely happens to be sampled on whole numbers (1 Hz steps) and whose\n * zoom should still be ruled in fractions; `true` to force it over rows that are not.\n * Ignored on category (already one tick per slot) and time axes.\n */\n integerTicks?: boolean;\n}\n\n/** Room for the tooltip beyond the chart — see {@link SeriesChartProps.tooltip}. */\nexport interface SeriesChartTooltip {\n /** Let the tooltip run past the chart's own box on that axis instead of recharts\n * clamping it inside. Default: `{ x: true }` when `boundary` is set, else neither. */\n allowEscapeViewBox?: { x?: boolean; y?: boolean };\n /**\n * The element that actually CLIPS the chart — usually a horizontal-scroll wrapper\n * around a chart wider than the card. The tooltip then flips to the left of the cursor\n * when it would spill past that element's visible right edge (see\n * `ChartTooltipContent`'s `boundaryRef`), rather than against the wide chart's far edge\n * the reader has not scrolled to. keksdose's budget performance, which keeps a scroll\n * wrapper and a per-category `minWidth` (`budget-performance-tab.tsx`).\n */\n boundary?: RefObject<HTMLElement | null>;\n}\n\n/**\n * A vertical segment in data coordinates — two y at one x, which a row-per-abscissa\n * chart structurally cannot draw. For CLOSING a shape the series already drew: the\n * turnarounds of a hysteresis loop, where the abscissa stands still while the value\n * falls from one branch to the other.\n */\nexport interface SeriesChartSpan {\n /** Distinct within the chart. */\n key: string;\n /** Which y axis `from`/`to` are measured on. Default `\"y\"`. */\n axis?: string;\n x: number;\n from: number;\n to: number;\n /** Default: `var(--text-muted)`. */\n color?: string;\n}\n\n/** The colours a reference or a marker can take by name — the kit's semantic tokens,\n * so a threshold reads the same on every chart and flips with the theme. */\nexport type SeriesChartTone =\n | \"muted\"\n | \"brand\"\n | \"income\"\n | \"expense\"\n | \"net\"\n | \"success\"\n | \"warning\"\n | \"danger\"\n | \"info\";\n\nconst TONE_COLOR: Record<SeriesChartTone, string> = {\n muted: \"var(--text-muted)\",\n brand: \"var(--brand)\",\n income: \"var(--money-income)\",\n expense: \"var(--money-expense)\",\n net: \"var(--money-net)\",\n success: \"var(--success)\",\n warning: \"var(--warning)\",\n danger: \"var(--danger)\",\n info: \"var(--info)\",\n};\n\n/**\n * A line across the whole plot at one value: a threshold, a target, an event.\n *\n * keksdose's cash buffer draws \"one month of runway\" across at y = 30 and the projected\n * depletion date down at its x. Unlike a {@link SeriesChartSpan}, which closes a shape\n * in data coordinates, a reference spans the plot, whatever the zoom.\n *\n * A reference is part of the FITTED band: one outside the data widens the axis to show\n * it, because a threshold the reader cannot see is not a threshold. A pinned domain or a\n * zoom window does not widen — there it is discarded when outside, like a span.\n */\nexport interface SeriesChartReference {\n /** Distinct within the chart. Default: its position in the list. */\n key?: string;\n /** `\"x\"` for a vertical line at an abscissa, otherwise the id of the y axis the value\n * is measured on. Default `\"y\"`, the single one — so no y axis may be called `\"x\"`. */\n axis?: string;\n /** An abscissa in the x axis' own terms (a category, a Date) for `axis: \"x\"`, a\n * number on that axis otherwise. A category the rows do not have draws nothing. */\n value: SeriesChartXValue;\n /** Written along the line, inside the plot at its top-left. SVG text: a string. */\n label?: string;\n /** Default `\"muted\"`. `color` wins over it. */\n tone?: SeriesChartTone;\n color?: string;\n /** Which of `STROKE_PATTERNS`. Default 1, dashed: a reference is not data, and a\n * solid line reads as a series nobody put in the legend. */\n dash?: number;\n}\n\n/**\n * A single labelled point — today's figure on keksdose's cash buffer, the month the\n * projection runs dry. For a mark on EVERY sample, or on the samples that meet a test,\n * use the series' `dot` instead; a marker is for a point that is a fact of its own.\n * Fitted like a reference: it widens the band it would otherwise fall outside of.\n */\nexport interface SeriesChartMarker {\n /** Distinct within the chart. Default: its position in the list. */\n key?: string;\n /** In the x axis' own terms, like a reference's `value`. */\n x: SeriesChartXValue;\n y: number;\n /** The y axis `y` is measured on. Default `\"y\"`. */\n axis?: string;\n /** Written above the point. */\n label?: string;\n /** Default `\"brand\"`. `color` wins over it. */\n tone?: SeriesChartTone;\n color?: string;\n /** Radius in px. Default 4.5. */\n r?: number;\n}\n\n/** What a click on the plot picked. */\nexport interface SeriesChartHit {\n /** The row's position in `rows`. */\n index: number;\n /** The caller's own row — with its `rawPeriod`, id or whatever the drilldown needs. */\n row: SeriesChartRow;\n x: SeriesChartXValue;\n /** The series, when the click landed ON a bar. A click anywhere else picks the slot\n * (the period), not a series. */\n key?: string;\n}\n\nexport interface SeriesChartProps {\n /** One row per abscissa value. A missing key is a hole (see `connectNulls`). */\n rows: readonly SeriesChartRow[];\n series: SeriesChartSeries[];\n /** Default: one untitled axis, `\"y\"`. */\n axes?: SeriesChartAxis[];\n x?: SeriesChartX;\n /** A value in the tooltip, where a number stands on its own and needs its unit.\n * Default: `Intl.NumberFormat` in the kit's locale. */\n valueFormat?: (value: number) => string;\n /** Tailwind height class, or a height in pixels. Default `h-72`. The empty state\n * takes it too, so a chart losing its last line does not relayout the page under it.\n * A number is for a height the caller holds as a number — keksdose's report charts\n * take `height = 260` as a prop and wrap the chart in a `SizedSeriesChart` div\n * (reports/charts/networth-line.tsx) only to turn it into a style, since a class\n * cannot be built from a number Tailwind never saw. */\n height?: string | number;\n /** Bridge holes left by sources sampled on different grids. See {@link mergeSeries}. */\n connectNulls?: boolean;\n /** Shown, centred at the chart's height, instead of an empty chart. Default: the\n * `seriesChart.empty` label. `null` shows nothing. */\n empty?: ReactNode;\n /**\n * Milliseconds for a line to draw itself in. Off by default: a chart beside a live\n * editor re-renders on every keystroke, and an animation restarted mid-flight reads\n * as the curve twitching. Turn it on where series come and go by choice.\n */\n animationMs?: number;\n spans?: SeriesChartSpan[];\n /** Lines across the plot at one value. */\n references?: SeriesChartReference[];\n /** Single labelled points. */\n markers?: SeriesChartMarker[];\n /**\n * Which axes a drag may zoom: `\"both\"`, `\"x\"`, `\"y\"` or `\"none\"`. Default: read off\n * the marks — see `defaultZoomAxes` (lines both, areas x, bars none). An axis carrying\n * bars or areas never takes a DRAGGED y window: it refits to the x window, from zero.\n * Ignored by `StaticSeriesChart`, which does not zoom.\n */\n zoomAxes?: ZoomAxesSetting;\n /**\n * A click on the plot: the slot under the pointer, and the series when it landed on a\n * bar. keksdose's drilldowns — a payee's month, a budget line, a spending category.\n * A drag that zoomed is not a click.\n */\n onPointClick?: (hit: SeriesChartHit) => void;\n /** Where the tooltip may go: for a chart inside a scroll wrapper. See\n * {@link SeriesChartTooltip}. */\n tooltip?: SeriesChartTooltip;\n /** Supplied by `withChartZoom` and by nothing else. */\n zoom?: ZoomBinding;\n /** Per-chart strings over `<UiKitProvider labels={{ seriesChart }}>`. */\n labels?: Partial<SeriesChartLabels>;\n /** BCP 47 tag for the default number formats. Default: the provider's. */\n locale?: string;\n /** Onto the chart's root (`ChartContainer`) — e.g. an app's own grid ink. */\n className?: string;\n}\n\n/** How much of an axis band the rotated title takes, in px. Reserved rather than\n * shared with the ticks: a title merely offset inside the band prints on top of a\n * five-figure tick, and which gives way depends on the data. */\nexport const AXIS_TITLE_STRIP = 16;\n\n/** Where inside its strip the rotated title sits. */\nconst AXIS_TITLE_OFFSET = 10;\n\n/** The tallest band tilted x ticks reserve, in px. A category name longer than this at\n * its angle is clipped rather than squeezing the plot down to a strip. */\nconst MAX_TILTED_TICK_BAND = 120;\n\n/** What one character of a tick label is taken to be, in px, for the tilted band — the\n * shell's `text-xs`. An estimate: the SVG is not laid out yet when the band is decided. */\nconst TICK_CHAR_WIDTH = 7;\nconst TICK_LINE_HEIGHT = 12;\n/** recharts' gap between the axis line and a bottom tick's text. */\nconst TICK_GAP = 8;\n\n/**\n * The height the x axis reserves for ticks tilted by `angle` degrees: the rotated box of\n * the longest label, from its length. `undefined` for level ticks — recharts' own 30 px.\n */\nfunction tiltedTickBand(labels: readonly string[], angle: number): number | undefined {\n if (!angle) return undefined;\n const rad = (Math.abs(angle) * Math.PI) / 180;\n const longest = Math.max(0, ...labels.map((label) => label.length)) * TICK_CHAR_WIDTH;\n const band = Math.sin(rad) * longest + Math.cos(rad) * TICK_LINE_HEIGHT + TICK_GAP;\n return Math.min(MAX_TILTED_TICK_BAND, Math.max(30, Math.ceil(band)));\n}\n\n/** The width the ticks of a y axis get when a caller does not say. */\nexport const AXIS_TICK_WIDTH = 48;\n\n/**\n * How much air a FITTED axis leaves between the data and its frame, as a fraction of\n * the range. Recharts fits `[dataMin, dataMax]`, which draws a peak half a stroke\n * outside the plot and a curve running to its limit indistinguishable from the frame.\n */\nconst AUTO_PAD = 0.04;\n\n/** The band a fitted axis draws, padded — and a real band for constant data, which is\n * a zero-height domain recharts cannot scale into. `undefined` when nothing finite. */\nexport function paddedDomain(values: Iterable<number>): [number, number] | undefined {\n let low = Infinity;\n let high = -Infinity;\n for (const value of values) {\n if (!Number.isFinite(value)) continue;\n if (value < low) low = value;\n if (value > high) high = value;\n }\n return padBand(low, high);\n}\n\n/**\n * {@link paddedDomain} for a caller that has already walked its own data — so a row\n * of charts can share one scale without building an array to find two numbers in, and\n * without a second padding rule. `low > high` means \"nothing was seen\": `undefined`.\n */\nexport function padBand(low: number, high: number): [number, number] | undefined {\n if (!(low <= high)) return undefined;\n const pad = (high - low) * AUTO_PAD || Math.abs(high) * AUTO_PAD || 1;\n return [low - pad, high + pad];\n}\n\n/** The whole band a y axis occupies: its ticks, and its title when it draws one. For\n * lining a heading up over a PLOT rather than over its column. */\nexport function axisBandWidth(tickWidth: number | undefined, titled: boolean): number {\n return (tickWidth ?? AXIS_TICK_WIDTH) + (titled ? AXIS_TITLE_STRIP : 0);\n}\n\n/**\n * The colour an axis TITLE takes, or `undefined` for the neutral one.\n *\n * An axis measuring exactly one line is that line's, and saying so in the title lets a\n * reader find a channel's scale without counting axes. An axis measuring several is\n * nobody's — a title in the first one's colour would be claiming it. Counted off the\n * series, so toggling a second line onto an axis gives the colour up in the same render.\n */\nexport function soleSeriesColor(\n axis: Pick<SeriesChartAxisShape, \"id\" | \"color\">,\n series: readonly Pick<SeriesChartSeries, \"axis\">[],\n): string | undefined {\n const mine = series.filter((entry) => (entry.axis ?? DEFAULT_Y_AXIS) === axis.id);\n return mine.length === 1 ? axis.color : undefined;\n}\n\n/** The single-axis case, which is most charts. `width` is what the TICKS need;\n * `orientation` is which side they stand on. */\nexport function oneAxis(\n format: ((value: number) => string) | undefined,\n title: string,\n width?: number,\n orientation?: \"left\" | \"right\",\n): SeriesChartAxis[] {\n return [{ id: DEFAULT_Y_AXIS, format, title, width, orientation }];\n}\n\n/** One source's samples: an abscissa and the channels measured against it. */\nexport interface SeriesSource {\n x: number[];\n channels: Record<string, number[]>;\n}\n\n/**\n * Merge sources sampled on different grids into rows the chart can draw.\n *\n * Merged ON THE ABSCISSA VALUE ITSELF, never interpolated onto a common grid: a line\n * through invented points looks exactly like one through measured ones. Where a source\n * has no sample the key is absent, and `connectNulls` bridges the hole with the same\n * straight segment an interpolation would have drawn — without claiming a measurement.\n */\nexport function mergeSeries(sources: SeriesSource[]): Record<string, number>[] {\n const byAbscissa = new Map<number, Record<string, number>>();\n for (const source of sources) {\n source.x.forEach((value, index) => {\n const row = byAbscissa.get(value) ?? { x: value };\n for (const [key, channel] of Object.entries(source.channels)) row[key] = channel[index];\n byAbscissa.set(value, row);\n });\n }\n return [...byAbscissa.values()].sort((a, b) => a.x - b.x);\n}\n\n/**\n * A series key built out of parts — as a CSS identifier.\n *\n * The chart shell paints each series through `--color-<key>`, and skips (with a\n * console warning) any key that is not `[A-Za-z_][A-Za-z0-9_-]*`. A line whose colour\n * was skipped has no stroke at all: an axis, a grid and nothing between them. So a key\n * assembled out of DATA — an id, an enum, a side — goes through here: every other\n * character becomes `_`, the parts are joined with `_`, and a key that would start with\n * a digit or a hyphen gets a leading `_`.\n */\nexport function seriesKey(...parts: (string | number)[]): string {\n const key = parts.map((part) => String(part).replace(/[^A-Za-z0-9_-]/g, \"_\")).join(\"_\");\n return /^[A-Za-z_]/.test(key) ? key : `_${key}`;\n}\n\n/**\n * The band an axis carrying bars or areas draws: the data's extent with ZERO in it,\n * padded only on the sides that are not zero — bars standing on a frame's bottom edge,\n * not floating four per cent above it on a band of air nobody asked for.\n * `undefined` when there is nothing to fit.\n */\nexport function anchoredBand(extent: readonly [number, number] | undefined): [number, number] | undefined {\n if (!extent) return undefined;\n const low = Math.min(0, extent[0]);\n const high = Math.max(0, extent[1]);\n const pad = (high - low) * AUTO_PAD || 1;\n return [low < 0 ? low - pad : 0, high > 0 ? high + pad : 0];\n}\n\n/**\n * Series with their colours settled BEFORE any are switched off.\n *\n * A series with no `color` takes `paletteFor(its position)` — and a legend toggle that\n * hands the chart a shorter list moves every later series one position up, repainting\n * it in its neighbour's colour on each click. Resolving the colours on the full list\n * and filtering after keeps each series in the colour its legend entry shows.\n */\nexport function visibleSeries(\n series: readonly SeriesChartSeries[],\n hidden: ReadonlySet<string>,\n): SeriesChartSeries[] {\n return series\n .map((entry, index) => ({ ...entry, color: entry.color ?? paletteFor(index) }))\n .filter((entry) => !hidden.has(entry.key));\n}\n\n/**\n * The `ToggleLegend` entries for a chart's FULL series list — colours resolved the way\n * the chart resolves them, and a stroke mark for a line drawn in a pattern (dashed,\n * step) so the key promises the stroke the plot draws. A bar or an area is a swatch.\n * Pair with {@link visibleSeries} for the chart itself.\n */\nexport function seriesLegendEntries(series: readonly SeriesChartSeries[]): LegendEntry[] {\n return series.map((entry, index) => {\n // A custom dash array goes to the legend as it is, so the swatch draws what the plot does.\n const own = entry.dash ?? (entry.dashed ? 1 : 0);\n const dash = entry.step ? STEP_DASH : own;\n const line = (entry.type ?? \"line\") === \"line\";\n return {\n key: entry.key,\n label: entry.label,\n color: entry.color ?? paletteFor(index),\n ...(line && dash !== 0 ? { marker: \"stroke\" as const, dash } : {}),\n };\n });\n}\n\n/** The number format every default falls back to. */\nfunction useDefaultFormat(localeProp: string | undefined): (value: number) => string {\n const locale = useKitLocale(localeProp);\n return useMemo(() => {\n const format = new Intl.NumberFormat(locale, { maximumFractionDigits: 2 });\n return (value: number) => format.format(value);\n }, [locale]);\n}\n\n/** The Y-axis list a chart draws when the caller gave none. */\nconst ONE_UNTITLED_AXIS: SeriesChartAxis[] = [{ id: DEFAULT_Y_AXIS, title: \"\" }];\n\n/** Where a category or time chart keeps each row's plotted position. Not the caller's\n * key: that one still holds their own value, which `format` and a hit hand back. */\nconst PLOTTED_X = \"__seriesChartX\";\n\n/** A finite number, or `undefined` — the only thing a row cell counts as a sample. */\nconst finite = (value: unknown): number | undefined =>\n typeof value === \"number\" && Number.isFinite(value) ? value : undefined;\n\n/** A time value as epoch ms. A date-only ISO string is LOCAL midnight (see\n * `SeriesChartX.type`); anything unreadable is `undefined`, i.e. not plotted. */\nfunction toTime(value: unknown): number | undefined {\n if (value instanceof Date) return finite(value.getTime());\n if (typeof value === \"number\") return finite(value);\n if (typeof value !== \"string\") return undefined;\n const day = /^(\\d{4})-(\\d{2})(?:-(\\d{2}))?$/.exec(value);\n if (day) return new Date(Number(day[1]), Number(day[2]) - 1, Number(day[3] ?? 1)).getTime();\n return finite(Date.parse(value));\n}\n\n/** A category's identity, so a Date matches another Date of the same instant. */\nconst categoryId = (value: unknown) =>\n value instanceof Date ? `d:${value.getTime()}` : `${typeof value}:${String(value)}`;\n\n/**\n * The abscissa, reduced to a number line — which is all the plot, the ticks and the\n * zoom ever deal in. A number stays itself; a category becomes its slot index; a time\n * its epoch ms. Everything the caller sees (ticks, tooltip, hits) is turned back.\n */\ninterface XModel {\n kind: \"number\" | \"category\" | \"time\";\n /** The caller's key, still holding their value. */\n sourceKey: string;\n /** The key the plot reads. The same as `sourceKey` on a number line. */\n plotKey: string;\n /** The rows as plotted. The caller's own on a number line. */\n rows: readonly SeriesChartRow[];\n /** The caller's rows, which dots and hits hand back. */\n source: readonly SeriesChartRow[];\n position: (value: unknown) => number | undefined;\n valueAt: (position: number) => SeriesChartXValue;\n}\n\nfunction xModel(rows: readonly SeriesChartRow[], x: SeriesChartX): XModel {\n const sourceKey = x.key ?? \"x\";\n if (x.type === \"category\") {\n const slots = new Map<string, number>();\n rows.forEach((row, index) => {\n const id = categoryId(row[sourceKey]);\n if (!slots.has(id)) slots.set(id, index);\n });\n return {\n kind: \"category\",\n sourceKey,\n plotKey: PLOTTED_X,\n rows: rows.map((row, index) => ({ ...row, [PLOTTED_X]: index })),\n source: rows,\n position: (value) => slots.get(categoryId(value)),\n valueAt: (position) => rows[Math.round(position)]?.[sourceKey] as SeriesChartXValue,\n };\n }\n if (x.type === \"time\") {\n return {\n kind: \"time\",\n sourceKey,\n plotKey: PLOTTED_X,\n rows: rows.map((row) => ({ ...row, [PLOTTED_X]: toTime(row[sourceKey]) })),\n source: rows,\n position: toTime,\n valueAt: (position) => new Date(position),\n };\n }\n return {\n kind: \"number\",\n sourceKey,\n plotKey: sourceKey,\n rows,\n source: rows,\n position: finite,\n valueAt: (position) => position,\n };\n}\n\n/** Caller ticks, as positions inside the domain on show. */\nfunction resolveTicks<T>(\n values: SeriesChartTickValues<T> | undefined,\n domain: [number, number] | undefined,\n position: (value: T) => number | undefined,\n): number[] | undefined {\n if (!values || !domain) return undefined;\n const list = typeof values === \"function\" ? values(domain) : values;\n if (!list) return undefined;\n const slack = (domain[1] - domain[0]) * 1e-9;\n return list\n .map(position)\n .filter((at): at is number => at !== undefined && at >= domain[0] - slack && at <= domain[1] + slack);\n}\n\n/** A low/high pair widened by some values, or `undefined` if there is still none. */\nfunction extend(\n span: readonly [number, number] | undefined,\n values: readonly (number | undefined)[],\n): [number, number] | undefined {\n let out: [number, number] | undefined = span ? [span[0], span[1]] : undefined;\n for (const value of values) {\n if (value === undefined || !Number.isFinite(value)) continue;\n out = out ? [Math.min(out[0], value), Math.max(out[1], value)] : [value, value];\n }\n return out;\n}\n\n/** How a time tick is written, by what one step of the ticks is. */\nconst TIME_TICK_FORMAT: Record<TimeTickUnit, Intl.DateTimeFormatOptions> = {\n hour: { hour: \"2-digit\", minute: \"2-digit\" },\n day: { day: \"numeric\", month: \"short\" },\n month: { month: \"short\", year: \"2-digit\" },\n year: { year: \"numeric\" },\n};\n\n/** The two numbers every mark type needs to agree on for the chart to read as one. */\nconst LINE_WIDTH = 2;\nconst STEP_WIDTH = 1.5;\n\n/** Bars round their FREE end only, and a stacked bar has none but the top layer's —\n * which recharts cannot tell apart per cell, so stacks stay square. */\nconst BAR_RADIUS: [number, number, number, number] = [3, 3, 0, 0];\n\n/**\n * One keyboard stop of a clickable chart: a bar, or (a chart with no bars) a whole slot.\n * `from`/`to` bound its slot on the plotted number line — half way to each neighbour,\n * or to the edge of the window on show.\n */\ninterface PointStop {\n index: number;\n /** The bar's series; absent for a slot. */\n key?: string;\n from: number;\n to: number;\n /** The accessible name: where it is and what it says. */\n name: string;\n}\n\n/**\n * The shape of a series whose bar has keyboard focus: recharts' own rectangle, with an\n * outline on the one bar at `index` — drawn at the bar's exact geometry, which an\n * overlay could only guess at. Not `activeBar`: that follows the tooltip's active index,\n * which recharts stops taking from `defaultIndex` once a pointer has hovered the chart.\n */\nfunction focusedBarShape(index: number) {\n return function FocusedBar(props: BarShapeProps) {\n const focused = props.originalDataIndex === index;\n return (\n <Rectangle {...props} {...(focused ? { stroke: \"var(--text-primary)\", strokeWidth: 2 } : {})} />\n );\n };\n}\n\n/**\n * The keyboard's way onto a clickable chart (`onPointClick`): one focusable `<rect>` per\n * bar, or per slot when there are no bars, laid over the plot INSIDE the recharts chart,\n * where the x scale answers.\n *\n * keksdose drew its weekday pattern as seven real `<button>`s (spending-tab.tsx) because\n * a recharts bar is reachable by nothing but the pointer. This is that, for every chart:\n *\n * - ONE tab stop (roving `tabIndex`): Tab moves past the chart, not through 30 bars.\n * - ←/→ step through the stops in order, ↑/↓ between the bars of one slot, Home/End.\n * - ↵ and Space report the stop as a click would — with the series for a bar.\n * - Each is a `role=\"button\"` named \"period — series: value\".\n *\n * The stops take NO pointer events, so the drag-to-zoom layer, the tooltip and the\n * pointer's own clicks underneath behave exactly as they did. Focus is shown by the\n * slot tinted and, for a bar, its own outline (`focusedBarShape`) — and by the tooltip,\n * moved to the stop through `defaultIndex`, which recharts honours until a pointer has\n * hovered the chart.\n */\nfunction PointKeys({\n stops,\n current,\n label,\n onFocusStop,\n onBlurStops,\n onPick,\n}: {\n stops: readonly PointStop[];\n current: number;\n label: string;\n onFocusStop: (at: number) => void;\n onBlurStops: () => void;\n onPick: (stop: PointStop) => void;\n}) {\n const plot = usePlotArea();\n const scale = useXAxisScale();\n const refs = useRef<(SVGRectElement | null)[]>([]);\n if (!plot || !scale || plot.width <= 0 || plot.height <= 0) return null;\n\n const move = (at: number) => {\n const next = Math.max(0, Math.min(stops.length - 1, at));\n refs.current[next]?.focus();\n };\n const onKeyDown = (at: number) => (event: KeyboardEvent<SVGRectElement>) => {\n const stop = stops[at];\n // ↑/↓ stay in the slot: the next or previous bar of the same period. The stops are\n // in slot order, so a slot's bars are neighbours.\n const inSlot = (step: 1 | -1) => (stops[at + step]?.index === stop.index ? at + step : at);\n const target =\n event.key === \"ArrowRight\"\n ? at + 1\n : event.key === \"ArrowLeft\"\n ? at - 1\n : event.key === \"ArrowDown\"\n ? inSlot(1)\n : event.key === \"ArrowUp\"\n ? inSlot(-1)\n : event.key === \"Home\"\n ? 0\n : event.key === \"End\"\n ? stops.length - 1\n : undefined;\n if (target !== undefined) {\n event.preventDefault();\n move(target);\n } else if (event.key === \"Enter\" || event.key === \" \") {\n event.preventDefault();\n onPick(stop);\n }\n };\n\n const left = plot.x;\n const right = plot.x + plot.width;\n return (\n <g role=\"group\" aria-label={label}>\n {stops.map((stop, at) => {\n // An edge with no neighbour runs to the plot's edge.\n const a = finite(scale(stop.from)) ?? left;\n const b = finite(scale(stop.to)) ?? right;\n const x0 = Math.max(left, Math.min(a, b));\n const x1 = Math.min(right, Math.max(a, b));\n return (\n <rect\n key={`${stop.index}:${stop.key ?? \"\"}`}\n ref={(node) => {\n refs.current[at] = node;\n }}\n role=\"button\"\n tabIndex={at === current ? 0 : -1}\n aria-label={stop.name}\n data-point-key={stop.key}\n x={x0}\n y={plot.y}\n width={Math.max(0, x1 - x0)}\n height={plot.height}\n fill=\"transparent\"\n // Focus only: the pointer's drag, hover and click belong to what is below.\n pointerEvents=\"none\"\n strokeWidth={2}\n className={cn(\n \"outline-none focus-visible:fill-[var(--brand)]/10\",\n // A bar outlines ITSELF (see `FOCUSED_BAR`); a slot has nothing else to.\n stop.key === undefined && \"focus-visible:stroke-[var(--brand)]\",\n )}\n onFocus={() => onFocusStop(at)}\n onBlur={onBlurStops}\n onKeyDown={onKeyDown(at)}\n />\n );\n })}\n </g>\n );\n}\n\ninterface PlotProps extends Omit<SeriesChartProps, \"rows\" | \"x\"> {\n /** The rows AS PLOTTED — what the zoom fits on. The caller's are `model.source`. */\n rows: readonly SeriesChartRow[];\n /** What the zoom fits on: the plotted key. */\n x: { key: string };\n model: XModel;\n xAxis: SeriesChartX;\n}\n\n/** The chart proper, over an abscissa already reduced to numbers (see {@link XModel}). */\nfunction SeriesPlot({\n model,\n xAxis,\n series,\n axes = ONE_UNTITLED_AXIS,\n valueFormat,\n height = \"h-72\",\n connectNulls,\n empty,\n animationMs = 0,\n spans,\n references,\n markers,\n onPointClick,\n tooltip,\n zoom,\n labels: labelsProp,\n locale: localeProp,\n className,\n}: PlotProps) {\n const labels = useKitLabels(\"seriesChart\", DEFAULT_SERIES_CHART_LABELS, labelsProp);\n const locale = useKitLocale(localeProp);\n const number = useDefaultFormat(localeProp);\n // The keyboard stops' roving tab stop, and the one that has focus (see `PointKeys`).\n // Up here, above the empty state's early return, like every hook.\n const [keyStop, setKeyStop] = useState(0);\n const [keyFocus, setKeyFocus] = useState<number | undefined>(undefined);\n\n // A number is pixels, set inline; a string is a class. Either way the one value\n // sizes both the chart and its empty state.\n const heightClass = typeof height === \"string\" ? height : undefined;\n const heightStyle = typeof height === \"number\" ? { height } : undefined;\n\n // The empty state takes the chart's own height and is centred in it: a chart that\n // shrank to its \"nothing to draw\" sentence moved everything under it up the page\n // the moment a legend entry was switched off.\n if (!model.source.length || !series.length) {\n return (\n <div\n className={cn(\"flex w-full items-center justify-center px-2 text-center\", heightClass)}\n style={heightStyle}\n >\n {empty !== undefined ? (\n empty\n ) : (\n <p className=\"text-xs text-[var(--text-muted)]\">{labels.empty}</p>\n )}\n </div>\n );\n }\n\n const x = xAxis;\n const xKey = model.plotKey;\n const plotted = model.rows;\n const rows = model.source;\n const config: ChartConfig = Object.fromEntries(\n series.map((entry, index) => [\n entry.key,\n { label: entry.label, color: entry.color ?? paletteFor(index) },\n ]),\n );\n const visible = axes.filter((axis) => !axis.hide);\n // The grid hangs its horizontal rules off ONE y axis, and recharts looks for the one\n // whose id is its own default (`0`). Every axis here is named, so without saying\n // which, it finds none and draws no horizontal rules at all. The first visible axis,\n // because those are the ticks a reader puts a ruler on.\n const gridAxis = (visible[0] ?? axes[0])?.id ?? DEFAULT_Y_AXIS;\n const onLeft = visible.some((axis) => (axis.orientation ?? \"left\") === \"left\");\n const onRight = visible.some((axis) => axis.orientation === \"right\");\n // The margins are what is left once the axes have their bands: an axis band IS the\n // gutter on its side, so a margin beside one is a second gutter. What remains is the\n // overhang of the first/last x tick where no y axis covers it.\n const margin = {\n // Room for a marker's label over a point at the top of the band.\n top: markers?.some((marker) => marker.label) ? 22 : 8,\n right: onRight ? 0 : 10,\n left: onLeft ? 0 : 10,\n // Under the ticks, not under the whole axis: whatever comes next owns the gap.\n bottom: x.title ? 18 : 2,\n };\n\n const refs = references ?? [];\n const xRefs = refs.filter((ref) => ref.axis === \"x\");\n const yRefs = refs.filter((ref) => ref.axis !== \"x\");\n const xPos = (value: SeriesChartXValue) => model.position(value);\n\n // Fitted with air around it, unless the reader has zoomed or the caller pinned it.\n // Ticks are the round values INSIDE whichever domain that is (see\n // `series-chart-ticks.ts`), so a zoom window still gets round numbers, just finer.\n // A category axis is its slots, each half a slot of air either side — room for a\n // bar, and the tick under the middle of it.\n const fittedX: [number, number] | undefined =\n zoom?.xDomain ??\n (model.kind === \"category\"\n ? [-0.5, rows.length - 0.5]\n : padBand(\n ...(extend(\n undefined,\n [\n ...plotted.map((row) => finite(row[xKey])),\n ...xRefs.map((ref) => xPos(ref.value)),\n ...(markers ?? []).map((marker) => xPos(marker.x)),\n ],\n ) ?? [Infinity, -Infinity]),\n ));\n\n const timeUnit = model.kind === \"time\" ? timeTicksWithUnit(fittedX) : undefined;\n // Whole-number ticks on a number line whose rows are all whole numbers — see\n // `SeriesChartX.integerTicks`.\n const integerX =\n model.kind === \"number\" &&\n (x.integerTicks ??\n plotted.every((row) => {\n const value = finite(row[xKey]);\n return value === undefined || Number.isInteger(value);\n }));\n const xTicks =\n resolveTicks(x.tickValues, fittedX, xPos) ??\n (model.kind === \"category\"\n ? categoryTicks(fittedX, rows.length)\n : model.kind === \"time\"\n ? timeUnit?.ticks\n : integerX\n ? (integerTicks(fittedX) ?? niceTicks(fittedX))\n : niceTicks(fittedX));\n\n // Ticks and the tooltip heading, back in the caller's terms.\n const timeFormat = new Intl.DateTimeFormat(locale, TIME_TICK_FORMAT[timeUnit?.unit ?? \"day\"]);\n const dateFormat = new Intl.DateTimeFormat(locale, {\n dateStyle: \"medium\",\n ...(timeUnit?.unit === \"hour\" ? { timeStyle: \"short\" } : {}),\n });\n const categoryText = (value: SeriesChartXValue) =>\n value instanceof Date\n ? dateFormat.format(value)\n : typeof value === \"number\"\n ? number(value)\n : String(value ?? \"\");\n const tickAt = (position: number): SeriesChartXTick => ({\n value: model.valueAt(position),\n ...(model.kind === \"category\" ? { index: Math.round(position) } : {}),\n ...(timeUnit ? { unit: timeUnit.unit } : {}),\n });\n const defaultFormat = (position: number, tick: SeriesChartXTick) =>\n model.kind === \"category\"\n ? categoryText(tick.value)\n : model.kind === \"time\"\n ? timeFormat.format(position)\n : number(position);\n const format = x.format ?? defaultFormat;\n const xFormat = (position: number) => format(position, tickAt(position));\n const label =\n x.label ??\n (model.kind === \"time\" ? (position: number) => dateFormat.format(position) : format);\n const xLabel = (position: number) => label(position, tickAt(position));\n\n const tickAngle = x.ticks === false ? 0 : (x.tickAngle ?? 0);\n const tickBand = tiltedTickBand((xTicks ?? []).map((tick) => xFormat(tick)), tickAngle);\n\n const source: ZoomFitSource = {\n rows: plotted,\n series,\n axes,\n xKey,\n };\n // An axis a bar or an area stands on is read from zero (see `includeZero`).\n const anchored = (axis: SeriesChartAxis) =>\n axis.includeZero ??\n series.some(\n (entry) => (entry.axis ?? DEFAULT_Y_AXIS) === axis.id && (entry.type ?? \"line\") !== \"line\",\n );\n // Whole-number ticks on an axis whose values are all whole — see\n // `SeriesChartAxis.integerTicks`. A stack of whole layers sums to a whole number, so\n // the layers are enough to look at.\n const wholeOnly = (axis: SeriesChartAxis) =>\n axis.integerTicks ??\n series\n .filter((entry) => (entry.axis ?? DEFAULT_Y_AXIS) === axis.id)\n .every((entry) =>\n plotted.every((row) => {\n const value = finite(row[entry.key]);\n return value === undefined || Number.isInteger(value);\n }),\n );\n const onAxis = (axisId: string) => (ref: { axis?: string }) => (ref.axis ?? DEFAULT_Y_AXIS) === axisId;\n const fittedY = (axis: SeriesChartAxis): [number, number] | undefined => {\n const own = [\n ...yRefs.filter(onAxis(axis.id)).map((ref) => finite(ref.value)),\n ...(markers ?? []).filter(onAxis(axis.id)).map((marker) => finite(marker.y)),\n ];\n if (anchored(axis)) {\n // Never a dragged y window: refitted to the x window, still from zero.\n if (zoom?.xDomain) return anchoredBand(axisExtent(source, axis.id, zoom.xDomain)) ?? axis.domain;\n return axis.domain ?? anchoredBand(extend(axisExtent(source, axis.id), own));\n }\n return (\n zoom?.yDomains[axis.id] ??\n axis.domain ??\n padBand(...(extend(axisExtent(source, axis.id), own) ?? [Infinity, -Infinity]))\n );\n };\n\n // The abscissa of a row in the caller's terms: a category is its slot, which is\n // its index; a time or a number is read back from where it was plotted.\n const xOf = (index: number): SeriesChartXValue =>\n model.kind === \"category\"\n ? (rows[index][model.sourceKey] as SeriesChartXValue)\n : model.valueAt(finite(plotted[index][xKey]) ?? NaN);\n const hitAt = (index: number, key?: string): SeriesChartHit | undefined => {\n const row = rows[index];\n return row ? { index, row, x: xOf(index), key } : undefined;\n };\n\n // The keyboard stops of a clickable chart — every bar with a value, slot by slot; or,\n // with no bars, every slot with any value. Only what is inside the window on show.\n const stops: PointStop[] = [];\n if (onPointClick) {\n const valueText = valueFormat ?? number;\n const nameOf = (entry: SeriesChartSeries) =>\n typeof entry.label === \"string\" || typeof entry.label === \"number\" ? String(entry.label) : entry.key;\n const said = (entry: SeriesChartSeries, value: number) => {\n const name = nameOf(entry);\n return name ? `${name}: ${valueText(value)}` : valueText(value);\n };\n const bars = series.filter((entry) => entry.type === \"bar\");\n const [low, high] = fittedX ?? [-Infinity, Infinity];\n const placed = plotted\n .map((row, index) => ({ index, at: model.kind === \"category\" ? index : finite(row[xKey]) }))\n .filter((slot): slot is { index: number; at: number } => slot.at !== undefined && slot.at >= low && slot.at <= high)\n .sort((a, b) => a.at - b.at);\n placed.forEach(({ index, at }, k) => {\n const from = k > 0 ? (placed[k - 1].at + at) / 2 : low;\n const to = k < placed.length - 1 ? (placed[k + 1].at + at) / 2 : high;\n // The heading the tooltip would give it, when that is text; else the tick.\n const heading = xLabel(at);\n const where = typeof heading === \"string\" && heading ? heading : xFormat(at);\n const valued = (bars.length ? bars : series)\n .map((entry) => ({ entry, value: finite(rows[index]?.[entry.key]) }))\n .filter((cell): cell is { entry: SeriesChartSeries; value: number } => cell.value !== undefined);\n if (bars.length) {\n for (const { entry, value } of valued) {\n stops.push({ index, key: entry.key, from, to, name: `${where} — ${said(entry, value)}` });\n }\n } else if (valued.length) {\n stops.push({\n index,\n from,\n to,\n name: `${where} — ${valued.map(({ entry, value }) => said(entry, value)).join(\", \")}`,\n });\n }\n });\n }\n const focusedStop = keyFocus === undefined ? undefined : stops[keyFocus];\n\n const dotFor = (entry: SeriesChartSeries) => {\n const want = entry.dot;\n if (!want) return false;\n const color = `var(--color-${entry.key})`;\n return (props: { cx?: number; cy?: number; index: number }) => {\n const { cx, cy, index } = props;\n const value = finite(rows[index]?.[entry.key]);\n if (value === undefined || !Number.isFinite(cx) || !Number.isFinite(cy)) return <g />;\n const point: SeriesChartPoint = {\n key: entry.key,\n index,\n row: rows[index],\n x: xOf(index),\n value,\n cx: cx!,\n cy: cy!,\n color,\n };\n const drawn = want === true ? true : want(point);\n if (drawn === true) {\n return (\n <circle\n className=\"recharts-dot\"\n cx={cx}\n cy={cy}\n r={3}\n fill={color}\n // Ringed in the surface, so a dot on a crossing line still reads as a dot.\n stroke=\"var(--bg-surface)\"\n strokeWidth={1.5}\n />\n );\n }\n if (drawn === false || drawn == null) return <g />;\n return <g>{drawn}</g>;\n };\n };\n\n const animation = {\n isAnimationActive: animationMs > 0,\n animationDuration: animationMs,\n animationEasing: \"ease-out\" as const,\n };\n\n return (\n <ChartContainer\n config={config}\n className={cn(\"w-full\", heightClass, className, onPointClick && \"cursor-pointer\")}\n style={heightStyle}\n >\n <ComposedChart\n data={plotted as Record<string, unknown>[]}\n margin={margin}\n // Positive and negative layers stacked apart, as `axisExtent` fits them — a\n // month's expenses hang below the axis instead of eating into its income.\n stackOffset=\"sign\"\n // recharts' own keyboard layer makes the whole surface a tab stop whose arrows\n // move the tooltip — a second stop beside `PointKeys`, and one ↵ does nothing on.\n accessibilityLayer={!onPointClick}\n onClick={\n onPointClick\n ? (state) => {\n const index = Number(state?.activeTooltipIndex ?? state?.activeIndex);\n const hit = Number.isInteger(index) ? hitAt(index) : undefined;\n if (hit) onPointClick(hit);\n }\n : undefined\n }\n >\n {/* Both ways: a measurement plot is read by putting a ruler on it, and a\n horizontal-only grid answers half of those questions. */}\n <CartesianGrid yAxisId={gridAxis} />\n <XAxis\n dataKey={xKey}\n // Numeric, not categorical: a measured sweep is unevenly spaced, and a\n // category axis would straighten exactly the curvature the chart is for.\n // A category chart is numeric too — on the slot index — which is what lets\n // it zoom and keeps its ticks under the middle of each bar group.\n type=\"number\"\n domain={fittedX ?? [\"dataMin\", \"dataMax\"]}\n ticks={xTicks}\n // Clip the lines to a zoom window instead of recharts widening it back out.\n allowDataOverflow={zoom?.xDomain !== undefined || model.kind === \"category\"}\n tickLine={false}\n axisLine={false}\n minTickGap={32}\n tick={x.ticks === false ? false : undefined}\n {...(tickAngle\n ? { angle: tickAngle, textAnchor: tickAngle < 0 ? \"end\" : \"start\" }\n : {})}\n // With neither ticks nor title there is nothing to reserve the band for, and\n // recharts' own 30 px would leave a gap under every chart of a stack.\n height={x.ticks === false && !x.title ? 4 : tickBand}\n tickFormatter={(value: number) => xFormat(Number(value))}\n >\n {x.title && (\n <Label\n value={x.title}\n position=\"insideBottom\"\n offset={-12}\n className=\"fill-[var(--text-muted)] text-[11px]\"\n />\n )}\n </XAxis>\n {axes.map((axis) => {\n const domain = fittedY(axis);\n const zoomed = anchored(axis)\n ? zoom?.xDomain !== undefined\n : zoom?.yDomains[axis.id] !== undefined;\n return (\n <YAxis\n key={axis.id}\n yAxisId={axis.id}\n hide={axis.hide}\n domain={domain}\n ticks={\n resolveTicks(axis.tickValues, domain, finite) ??\n (wholeOnly(axis) ? (integerTicks(domain) ?? niceTicks(domain)) : niceTicks(domain))\n }\n allowDataOverflow={zoomed}\n orientation={axis.orientation ?? \"left\"}\n width={axisBandWidth(axis.width, Boolean(axis.title) && !axis.hide)}\n tickLine={false}\n axisLine={false}\n tickFormatter={axis.format ?? number}\n // With an axis per channel the tint is the only thing saying which\n // numbers belong to which line.\n tick={axis.color ? { fill: axis.color } : undefined}\n >\n {axis.title && !axis.hide && (\n <Label\n value={axis.title}\n // Rotated so both sides read upward from the bottom of their axis.\n angle={axis.orientation === \"right\" ? 90 : -90}\n position={axis.orientation === \"right\" ? \"insideRight\" : \"insideLeft\"}\n // Inline, so a sole series' colour beats the class's neutral fill —\n // and absent for a shared axis, so the class draws it.\n style={{ textAnchor: \"middle\", fill: soleSeriesColor(axis, series) }}\n offset={AXIS_TITLE_OFFSET}\n className=\"fill-[var(--text-muted)] text-[11px]\"\n />\n )}\n </YAxis>\n );\n })}\n <ChartTooltip\n {...(tooltip?.allowEscapeViewBox || tooltip?.boundary\n ? { allowEscapeViewBox: tooltip.allowEscapeViewBox ?? { x: true } }\n : {})}\n // The content shifts itself 12 px off the cursor (or flips) against the\n // boundary; recharts' own offset on top would double it.\n {...(tooltip?.boundary ? { offset: 0 } : {})}\n // The keyboard's stop shows its tooltip as the pointer's would.\n defaultIndex={focusedStop?.index}\n content={\n <ChartTooltipContent\n labelFormatter={(value) => xLabel(Number(value))}\n valueFormatter={valueFormat ?? number}\n boundaryRef={tooltip?.boundary}\n />\n }\n />\n {series.map((entry) => {\n const type = entry.type ?? \"line\";\n const yAxisId = entry.axis ?? DEFAULT_Y_AXIS;\n const color = `var(--color-${entry.key})`;\n const own = entry.dash ?? (entry.dashed ? 1 : 0);\n const dash = entry.step ? strokeDash(STEP_DASH) : typeof own === \"string\" ? own : strokeDash(own);\n const curve = entry.step ? \"stepAfter\" : (entry.curve ?? \"monotone\");\n const width = entry.strokeWidth ?? (entry.step ? STEP_WIDTH : LINE_WIDTH);\n if (type === \"bar\") {\n return (\n <Bar\n key={entry.key}\n yAxisId={yAxisId}\n dataKey={entry.key}\n stackId={entry.stack}\n fill={color}\n fillOpacity={entry.fillOpacity}\n radius={entry.stack === undefined ? BAR_RADIUS : 0}\n // Only the focused stop's series swaps its shape, and only for as long\n // as it has focus: every other bar keeps recharts' own.\n {...(focusedStop?.key === entry.key ? { shape: focusedBarShape(focusedStop.index) } : {})}\n onClick={\n onPointClick\n ? (_bar, index, event) => {\n // The plot's own click would report the same slot again,\n // without the series.\n event.stopPropagation();\n const hit = hitAt(index, entry.key);\n if (hit) onPointClick(hit);\n }\n : undefined\n }\n {...animation}\n />\n );\n }\n if (type === \"area\") {\n return (\n <Area\n key={entry.key}\n yAxisId={yAxisId}\n type={curve}\n dataKey={entry.key}\n stackId={entry.stack}\n stroke={color}\n strokeWidth={width}\n strokeDasharray={dash}\n fill={color}\n fillOpacity={entry.fillOpacity ?? (entry.stack !== undefined ? 0.55 : 0.2)}\n dot={dotFor(entry)}\n {...(entry.activeDot !== undefined ? { activeDot: entry.activeDot } : {})}\n connectNulls={connectNulls}\n {...animation}\n />\n );\n }\n return (\n <Line\n key={entry.key}\n yAxisId={yAxisId}\n type={curve}\n dataKey={entry.key}\n stroke={color}\n strokeWidth={width}\n strokeDasharray={dash}\n dot={dotFor(entry)}\n {...(entry.activeDot !== undefined ? { activeDot: entry.activeDot } : {})}\n connectNulls={connectNulls}\n {...animation}\n />\n );\n })}\n {spans?.map((span) => (\n <ReferenceLine\n key={span.key}\n yAxisId={span.axis ?? DEFAULT_Y_AXIS}\n segment={[\n { x: span.x, y: span.from },\n { x: span.x, y: span.to },\n ]}\n stroke={span.color ?? \"var(--text-muted)\"}\n strokeWidth={2}\n // Discarded rather than clamped when zoomed past: a span clamped to the\n // window's edge draws a vertical line at an abscissa it never stood at.\n ifOverflow=\"discard\"\n />\n ))}\n {refs.map((ref, index) => {\n const vertical = ref.axis === \"x\";\n const at = vertical ? xPos(ref.value) : finite(ref.value);\n if (at === undefined) return null;\n const color = ref.color ?? TONE_COLOR[ref.tone ?? \"muted\"];\n return (\n <ReferenceLine\n key={ref.key ?? `reference-${index}`}\n // A vertical line still needs a y axis to be drawn against, and every\n // axis here is named — the grid's is always there.\n yAxisId={vertical ? gridAxis : (ref.axis ?? DEFAULT_Y_AXIS)}\n {...(vertical ? { x: at } : { y: at })}\n stroke={color}\n strokeWidth={1}\n strokeDasharray={strokeDash(ref.dash ?? 1)}\n ifOverflow=\"discard\"\n label={\n ref.label\n ? {\n value: ref.label,\n position: \"insideTopLeft\",\n fontSize: 10,\n fill: color,\n }\n : undefined\n }\n />\n );\n })}\n {markers?.map((marker, index) => {\n const at = xPos(marker.x);\n if (at === undefined || finite(marker.y) === undefined) return null;\n const color = marker.color ?? TONE_COLOR[marker.tone ?? \"brand\"];\n return (\n <ReferenceDot\n key={marker.key ?? `marker-${index}`}\n yAxisId={marker.axis ?? DEFAULT_Y_AXIS}\n x={at}\n y={marker.y}\n r={marker.r ?? 4.5}\n fill={color}\n stroke=\"var(--bg-surface)\"\n strokeWidth={1.5}\n ifOverflow=\"discard\"\n label={\n marker.label\n ? {\n value: marker.label,\n position: \"top\",\n fontSize: 11,\n fontWeight: 600,\n fill: \"var(--text-primary)\",\n }\n : undefined\n }\n />\n );\n })}\n {stops.length > 0 && (\n <PointKeys\n stops={stops}\n current={Math.min(keyStop, stops.length - 1)}\n label={labels.points}\n onFocusStop={(at) => {\n setKeyStop(at);\n setKeyFocus(at);\n }}\n onBlurStops={() => setKeyFocus(undefined)}\n onPick={(stop) => {\n const hit = hitAt(stop.index, stop.key);\n if (hit) onPointClick?.(hit);\n }}\n />\n )}\n {zoom?.layer}\n </ComposedChart>\n </ChartContainer>\n );\n}\n\nconst ZoomablePlot = withChartZoom(SeriesPlot);\n\n/** The caller's props, with the abscissa reduced to numbers for the plot and the zoom. */\nfunction plotProps(props: SeriesChartProps): PlotProps {\n const x = props.x ?? {};\n const model = xModel(props.rows, x);\n return { ...props, rows: model.rows, x: { key: model.plotKey }, model, xAxis: x };\n}\n\n/**\n * {@link SeriesChart} without the zoom: the same picture, no drag layer, no reset\n * button. For a thumbnail, a print view, or a chart the consumer wraps in its own\n * interaction.\n */\nexport function StaticSeriesChart(props: SeriesChartProps) {\n return <SeriesPlot {...plotProps(props)} />;\n}\n\n/**\n * The series chart, zoomable. Drag across the plot to zoom (the drag's shape picks the\n * axes), double-click or press the reset button to go back; wrap several in\n * `SharedXZoom` to move their x windows together. Which axes zoom depends on the marks\n * — see {@link SeriesChartProps.zoomAxes}.\n */\nexport function SeriesChart(props: SeriesChartProps) {\n // The zoom fits the PLOTTED rows — slot indices and epoch ms, not the caller's labels.\n return <ZoomablePlot {...plotProps(props)} />;\n}\n"],"mappings":"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","names":[]}
|
|
1
|
+
{"version":3,"sources":["../../src/components/series-chart.tsx"],"sourcesContent":["// The measurement plot: series against a swept numeric abscissa, any number of y axes,\n// dash patterns, vertical spans, and drag-to-zoom. Lifted out of lenkbank, where every\n// chart on every screen is this one arrangement of the kit's shell — so the arrangement\n// lives here once instead of as thirteen hand-assembled copies drifting apart.\n//\n// Built on `ChartContainer` + `ChartTooltipContent`, so it themes with the rest of the\n// chart kit: series default to the `--chart-N` ramp, axis text and grid take the\n// shell's tokens. It stays domain-free — every unit, title and number format is the\n// caller's, and the few words it can say itself are the `seriesChart` label namespace.\n//\n// **Every series may keep its own scale.** Position runs in millimetres and jerk in\n// hundreds of thousands of them per second cubed; on one axis the position line is\n// flat against the bottom. Normalising each series to its peak makes the y axis mean\n// nothing, so a caller declares an axis per incomparable channel instead, and may hide\n// all but the ones worth a column of numbers.\n//\n// Charts are drawn left-to-right in every writing direction — an abscissa is a number\n// line, not text — so `orientation` below is physical, and only the HTML chrome (the\n// reset button) is placed by logical side.\n//\n// **Bars, areas and periods too (0.8.0).** keksdose drew five money charts in raw\n// recharts — net worth, investments, income/expense, grouped payees, stacked categories\n// — each re-deciding the grid, the tooltip, the axis width and the \"—\" for a gap. They\n// are the same arrangement with a different mark, so a series now says `type: \"bar\" |\n// \"area\"` (and `stack`), and the abscissa may be a row of PERIODS (`x.type:\n// \"category\"`) or real dates (`x.type: \"time\"`) instead of a number the app had to\n// invent. What each of those does to the zoom is decided in one place,\n// `defaultZoomAxes` in `chart-zoom.tsx`.\nimport { useMemo, useRef, useState } from \"react\";\nimport type { KeyboardEvent, ReactNode, RefObject } from \"react\";\nimport {\n Area,\n Bar,\n CartesianGrid,\n ComposedChart,\n Label,\n Line,\n ReferenceDot,\n ReferenceLine,\n Rectangle,\n XAxis,\n YAxis,\n usePlotArea,\n useXAxisScale,\n type BarShapeProps,\n} from \"recharts\";\nimport { ChartContainer, ChartTooltip, ChartTooltipContent, type ChartConfig } from \"./chart\";\nimport {\n DEFAULT_Y_AXIS,\n axisExtent,\n withChartZoom,\n type ZoomAxesSetting,\n type ZoomBinding,\n type ZoomFitSource,\n} from \"./chart-zoom\";\nimport { STEP_DASH, strokeDash, type LegendEntry } from \"./toggle-legend\";\nimport { DEFAULT_SERIES_CHART_LABELS, type SeriesChartLabels } from \"./series-chart-labels\";\nimport { categoryTicks, integerTicks, niceTicks, timeTicksWithUnit, type TimeTickUnit } from \"./series-chart-ticks\";\n// The tick module stays internal; the one type of it a public prop names is re-exported.\nexport type { TimeTickUnit } from \"./series-chart-ticks\";\nimport { paletteFor } from \"../theme/chart-palette\";\nimport { useKitLabels, useKitLocale } from \"../i18n/kit-labels\";\nimport { cn } from \"../lib/cn\";\n\nexport interface SeriesChartSeries {\n /** The row key this line reads — and the `--color-<key>` it is painted with, so it\n * must be a CSS identifier. Build keys out of data with {@link seriesKey}. */\n key: string;\n label: ReactNode;\n /** Any CSS colour the chart shell accepts (hex, rgb/hsl, `var(--token)`). Default:\n * the kit's categorical ramp by position, `paletteFor(index)`. */\n color?: string;\n /** Marks the PAIRED line of a pair — the return stroke against the out-stroke, the\n * reference against the measurement. Shorthand for `dash: 1`. */\n dashed?: boolean;\n /** Which of {@link STROKE_PATTERNS} this line takes, for charts where the stroke says\n * WHICH QUANTITY and the colour says WHICH MEASUREMENT.\n *\n * Or an SVG `stroke-dasharray` string of the caller's own, for a pattern the five do\n * not have: keksdose's `\"4 3\"`, a tighter dash than the ladder's `\"5 4\"` that its\n * hand-drawn recharts lines used before the kit. The legend\n * entry ({@link seriesLegendEntries}) carries the same string, so it draws the same\n * pattern. */\n dash?: number | string;\n /** `stepAfter`, for a whole-number channel that jumps rather than travels — a\n * straight line between index 0 and index 1 draws an index of 0.5, which does not\n * exist. Drawn in the {@link STEP_DASH} pattern, whatever `dash` says. */\n step?: boolean;\n /** Which of `axes` this line is measured on. Default: `\"y\"`, the single one. */\n axis?: string;\n /**\n * The mark. `\"line\"` (the default) is what every chart before 0.8.0 drew. `\"bar\"` and\n * `\"area\"` are read as a LENGTH from zero, so the axis they stand on always includes\n * zero (see `SeriesChartAxis.includeZero`) and the zoom treats them differently (see\n * `defaultZoomAxes`). Bars without a `stack` stand side by side in each slot — the\n * grouped bars of keksdose's payee report.\n */\n type?: SeriesChartType;\n /**\n * Bars or areas with the same `stack` are drawn on top of each other and the axis is\n * fitted to their SUM (positive and negative layers apart, like recharts'\n * `stackOffset=\"sign\"`). keksdose's spending-by-category area. Ignored on a line:\n * recharts cannot stack one.\n */\n stack?: string;\n /**\n * Marks on the line's (or area's) points. `true` rings every sample — the price\n * history, where a shop has a value only on the days somebody shopped there and the\n * dots are the only thing saying which points were MEASURED. A function decides per\n * point: `true` for the default dot, `false`/`null` for none, or any SVG node drawn\n * as-is at `point.cx`/`point.cy` — a buy/sell marker on keksdose's paper price.\n * Never called for a point with no value. Bars have no points, and ignore it.\n */\n dot?: boolean | ((point: SeriesChartPoint) => ReactNode);\n /** Line (or area outline) weight in px. Default 2, or 1.5 for a `step`. keksdose\n * draws the subject of a chart at 2.5 and the reference it is read against at 1.5. */\n strokeWidth?: number;\n /** `\"linear\"` for a line that must not look smoothed — keksdose's cash-buffer\n * PROJECTION, a straight extrapolation that a monotone curve would dress up as data.\n * Default `\"monotone\"`; `step` wins over both. */\n curve?: \"monotone\" | \"linear\";\n /** An area's or bar's fill opacity. Default: 1 for a bar, 0.55 for a stacked area\n * (the layers must stay tellable apart where they meet) and 0.2 for a single one. */\n fillOpacity?: number;\n /**\n * The dot that follows the pointer along a line or an area. `false` takes it off a\n * series that is not a measurement — keksdose's cash-buffer PROJECTION, where a hover\n * ring on the extrapolated line reads as a sampled value (`cash-buffer-chart.tsx`).\n * `{ r }` sets its radius. Default: recharts' dot. Bars have none, and ignore it.\n */\n activeDot?: boolean | { r?: number };\n /**\n * The shortest a bar of this series is drawn, in px — recharts' `minPointSize`. A\n * zero or a value too small to see keeps a visible stub, so an empty slot still reads\n * as a slot with a value rather than a gap: keksdose's weekday pattern, where a\n * Sunday with no spending drew a 2% stub by hand. Only the DRAWING changes: the axis\n * is fitted to the values, and the tooltip, the keyboard stops and every accessible\n * name still say 0. A hole (no value in the row) stays a hole. Overrides the chart's\n * {@link SeriesChartProps.minBarLength}; `0` turns it off for this series. Meant for\n * unstacked bars — in a `stack` the stub is drawn over the layer above it. Lines and\n * areas ignore it.\n */\n minBarLength?: number;\n}\n\n/** What a series draws. See {@link SeriesChartSeries.type}. */\nexport type SeriesChartType = \"line\" | \"bar\" | \"area\";\n\n/** One point of a series, as a `dot` function is handed it. */\nexport interface SeriesChartPoint {\n /** The series' key. */\n key: string;\n /** The row's position in `rows`. */\n index: number;\n /** The caller's own row, with everything the chart did not plot still in it. */\n row: SeriesChartRow;\n /** The abscissa in the caller's terms: the number, the category, or (time) a Date. */\n x: SeriesChartXValue;\n value: number;\n /** Where the point is drawn, in the chart's pixels. */\n cx: number;\n cy: number;\n /** The series' paint, `var(--color-<key>)`. */\n color: string;\n}\n\n/** A row of a series chart: one abscissa value and the series' values at it. Anything\n * else in it (a raw ISO period for a drilldown) rides along untouched and is handed\n * back in {@link SeriesChartPoint.row} and {@link SeriesChartHit.row}. */\nexport type SeriesChartRow = Readonly<Record<string, unknown>>;\n\n/** An abscissa value: a number (`x.type: \"number\"`), a category (a string, a number or\n * a Date standing for a period), or a time (a Date, epoch ms or an ISO string). */\nexport type SeriesChartXValue = number | string | Date;\n\n/** Ticks a caller decides — a list, or a function of the domain on show, so a zoom\n * window gets ticks from the same rule instead of none. */\nexport type SeriesChartTickValues<T> =\n | readonly T[]\n | ((domain: [number, number]) => readonly T[] | undefined);\n\ninterface SeriesChartAxisShape {\n id: string;\n /**\n * Which side of the plot the ticks stand on. Left unless said otherwise — and said\n * otherwise for the right-hand chart of a FACING pair (see `facingAxes`), whose\n * scales go on the outside so neither column of numbers stands between two pictures\n * being compared.\n */\n orientation?: \"left\" | \"right\";\n /** Tints the ticks — and the title too, when exactly one series is measured on this\n * axis (see {@link soleSeriesColor}). */\n color?: string;\n /** What the TICKS need, in px. The title's strip is added on top. Default 48. */\n width?: number;\n /**\n * Pin the scale instead of fitting it to this chart's data. For a ROW of charts\n * read against each other: auto-fitted, a 200 N loop and a 2000 N one draw the\n * identical picture, and the comparison the layout promises is the one it fails.\n */\n domain?: [number, number];\n /** A tick, formatted — as a BARE number. The unit is said once, in the title; the\n * tooltip gets it from `valueFormat`. Default: `Intl.NumberFormat` in the kit's\n * locale, up to two fraction digits. */\n format?: (value: number) => string;\n /**\n * The tick values, instead of the round ones the chart picks. For a grid the DATA\n * dictates — keksdose's price axes tick on whole cents (`pricePaddedDomain`), where a\n * 1/2/5 ladder would print €1.25 under a formatter that can only say €1.3. Values\n * outside the domain on show are dropped; a function is asked again for every zoom\n * window, so the cent grid can refine with it.\n */\n tickValues?: SeriesChartTickValues<number>;\n /**\n * Keep zero inside the fitted band. On by default for an axis carrying a bar or an\n * area — their length IS the value, and a truncated baseline draws 40 as three times\n * 20 — and off for lines, whose shape is the point (a stock price anchored at zero is\n * a hairline). A pinned `domain` is left alone either way.\n */\n includeZero?: boolean;\n /**\n * Tick only on whole numbers — the y counterpart of `SeriesChartX.integerTicks`, and\n * what keksdose's user-count axis (`metrics-panel.tsx`, `wholeTicks`) and its runway\n * in days (`cash-buffer-chart.tsx`, `wholeDayTicks`) each wrote by hand: a band of\n * [0, 3.1] users is ticked 0 1 2 3, not 0 0.5 1 … 3, and a short runway is not ticked\n * 0 / 0.5 / 1 under a rounding formatter that prints \"1\" twice. A (zoom) window that\n * holds no whole number falls back to the ordinary ticks rather than to none.\n *\n * AUTOMATIC by default — on when every value this axis carries is a whole number\n * (counts), because that is where a half tick is a value no sample can have, and it\n * changes nothing on a span wider than about eight, which already ticks on whole\n * steps. `true` forces it over fractional data (days of runway computed as 43.7);\n * `false` keeps fractional ticks for a continuous quantity that merely happens to be\n * whole in this sample. `tickValues` wins over either.\n */\n integerTicks?: boolean;\n}\n\n/**\n * A y axis — and a VISIBLE one says what it measures.\n *\n * A union rather than an optional field, so the rule is the type's: a column of numbers\n * whose quantity and unit are not written down is a column somebody reads as whatever\n * they expected. `title: \"\"` is the explicit opt-out (the right-hand chart of a facing\n * pair, whose neighbour already said it). A HIDDEN axis scales its lines and draws\n * nothing, so there is nowhere for a title to go.\n */\nexport type SeriesChartAxis = SeriesChartAxisShape &\n ({ title: string; hide?: false } | { title?: string; hide: true });\n\n/**\n * What a tick or the tooltip heading of the abscissa is handed besides its position —\n * the value in the caller's own terms, which on a category or time axis is not the\n * number the plot runs on.\n */\nexport interface SeriesChartXTick {\n /** The number itself, the row's category, or (time) a Date. */\n value: SeriesChartXValue;\n /** The slot, on a category axis: the row's index in `rows`. */\n index?: number;\n /** On a time axis: what one step of the ticks on show is, so a label can say as much\n * as it means — a month start as \"Mar 26\", a midnight as \"14 Mar\". */\n unit?: TimeTickUnit;\n}\n\nexport interface SeriesChartX {\n /**\n * What the abscissa is.\n *\n * - `\"number\"` (the default) — a number line, and all a chart before 0.8.0 could draw.\n * - `\"category\"` — PERIODS or names, one evenly spaced slot per row, in row order:\n * keksdose's months, quarters and budget categories, which it used to hand recharts\n * preformatted. The values stay the caller's own — `\"2026-05\"`, a Date for the\n * month, a category name — and need not be sortable, unique or numeric. The plot\n * runs on the slot INDEX, which is what lets it zoom: a drag across the third to the\n * ninth month shows those months, a tick on each whole slot and the bars clipped at\n * the edge. What else zooms depends on the MARKS, not the axis — see `zoomAxes`.\n * - `\"time\"` — real TIME: a Date, epoch ms or an ISO string per row, placed by when\n * it happened. keksdose's price history and cash buffer, where a slot per row would\n * draw two receipts a day apart and two five months apart the same width. Ticks fall\n * on calendar boundaries (midnights, Mondays, month and quarter starts, new years)\n * in local time; a date-only ISO string is LOCAL midnight, not the UTC one\n * `new Date(\"2026-05-01\")` gives, which lands on the previous day west of Greenwich.\n * Zooms like a number line.\n */\n type?: \"number\" | \"category\" | \"time\";\n /** Row key of the abscissa. Default `\"x\"`, which is what {@link mergeSeries} writes. */\n key?: string;\n /** What the abscissa is, with its unit. Drawn under the axis. */\n title?: string;\n /**\n * A tick, formatted — bare, like the y axes'.\n *\n * `value` is the POSITION on the number line the plot runs on — the number itself,\n * epoch ms, or the slot index — so the one-argument formatters every chart before\n * 0.8.0 passes keep their meaning, and a time axis' `(ms) => …` is the tickFormatter\n * keksdose already has. The caller's own value (the category, the Date) is `tick.value`.\n * Default: the kit's number format; a category as is (a number formatted, a Date as a\n * medium date); a time as much of the date as the tick step means.\n */\n format?: (value: number, tick: SeriesChartXTick) => string;\n /**\n * Whether this chart prints the abscissa's ticks. On by default; off for every chart\n * of a stack sharing one x window but the bottom one, which prints them for all. It\n * costs no alignment: the x mapping is decided by the margins and the y bands.\n */\n ticks?: boolean;\n /** The tooltip's heading. Default: `format` — or, on a time axis, a medium date (with\n * the time for hourly data), since a tick's \"Mar 26\" is not which day it was. */\n label?: (value: number, tick: SeriesChartXTick) => ReactNode;\n /** The ticks instead of the automatic ones, in the caller's terms: numbers, the\n * categories to label, or instants. See `SeriesChartAxis.tickValues`. */\n tickValues?: SeriesChartTickValues<SeriesChartXValue>;\n /**\n * Tilt the tick labels by this many degrees — negative rises to the right. For long\n * category names that do not fit side by side: keksdose's budget performance draws its\n * categories at −45° (`budget-performance-tab.tsx`). The label is anchored by its END\n * for a negative angle and its START for a positive one, so it hangs off the tick\n * instead of being centred across it; the anchor is physical, like the plot (see\n * `ChartContainer`), so it is the same in RTL. The band under the axis grows to the\n * rotated height of the longest label on show, estimated from its length (at most\n * 120 px, past which a label is clipped). Default 0.\n */\n tickAngle?: number;\n /**\n * On a `\"number\"` axis, tick only on whole numbers: a step of 1 at the least, so a\n * five-point index series reads 0 1 2 3 4 rather than 0 0.5 1 … 4 — ticks at\n * positions no row can have (keksdose's short step series). A zoom window that holds\n * no whole number falls back to the ordinary ticks rather than to none.\n *\n * AUTOMATIC by default — on when every row's x is a whole number — because that is\n * exactly the case the half ticks are wrong in, and it changes nothing elsewhere: a\n * span wider than about eight already ticks on whole steps. `false` for a continuous\n * quantity that merely happens to be sampled on whole numbers (1 Hz steps) and whose\n * zoom should still be ruled in fractions; `true` to force it over rows that are not.\n * Ignored on category (already one tick per slot) and time axes.\n */\n integerTicks?: boolean;\n}\n\n/** Room for the tooltip beyond the chart — see {@link SeriesChartProps.tooltip}. */\nexport interface SeriesChartTooltip {\n /** Let the tooltip run past the chart's own box on that axis instead of recharts\n * clamping it inside. Default: `{ x: true }` when `boundary` is set, else neither. */\n allowEscapeViewBox?: { x?: boolean; y?: boolean };\n /**\n * The element that actually CLIPS the chart — usually a horizontal-scroll wrapper\n * around a chart wider than the card. The tooltip then flips to the left of the cursor\n * when it would spill past that element's visible right edge (see\n * `ChartTooltipContent`'s `boundaryRef`), rather than against the wide chart's far edge\n * the reader has not scrolled to. keksdose's budget performance, which keeps a scroll\n * wrapper and a per-category `minWidth` (`budget-performance-tab.tsx`).\n */\n boundary?: RefObject<HTMLElement | null>;\n}\n\n/**\n * A vertical segment in data coordinates — two y at one x, which a row-per-abscissa\n * chart structurally cannot draw. For CLOSING a shape the series already drew: the\n * turnarounds of a hysteresis loop, where the abscissa stands still while the value\n * falls from one branch to the other.\n */\nexport interface SeriesChartSpan {\n /** Distinct within the chart. */\n key: string;\n /** Which y axis `from`/`to` are measured on. Default `\"y\"`. */\n axis?: string;\n x: number;\n from: number;\n to: number;\n /** Default: `var(--text-muted)`. */\n color?: string;\n}\n\n/** The colours a reference or a marker can take by name — the kit's semantic tokens,\n * so a threshold reads the same on every chart and flips with the theme. */\nexport type SeriesChartTone =\n | \"muted\"\n | \"brand\"\n | \"income\"\n | \"expense\"\n | \"net\"\n | \"success\"\n | \"warning\"\n | \"danger\"\n | \"info\";\n\nconst TONE_COLOR: Record<SeriesChartTone, string> = {\n muted: \"var(--text-muted)\",\n brand: \"var(--brand)\",\n income: \"var(--money-income)\",\n expense: \"var(--money-expense)\",\n net: \"var(--money-net)\",\n success: \"var(--success)\",\n warning: \"var(--warning)\",\n danger: \"var(--danger)\",\n info: \"var(--info)\",\n};\n\n/**\n * A line across the whole plot at one value: a threshold, a target, an event.\n *\n * keksdose's cash buffer draws \"one month of runway\" across at y = 30 and the projected\n * depletion date down at its x. Unlike a {@link SeriesChartSpan}, which closes a shape\n * in data coordinates, a reference spans the plot, whatever the zoom.\n *\n * A reference is part of the FITTED band: one outside the data widens the axis to show\n * it, because a threshold the reader cannot see is not a threshold. A pinned domain or a\n * zoom window does not widen — there it is discarded when outside, like a span.\n */\nexport interface SeriesChartReference {\n /** Distinct within the chart. Default: its position in the list. */\n key?: string;\n /** `\"x\"` for a vertical line at an abscissa, otherwise the id of the y axis the value\n * is measured on. Default `\"y\"`, the single one — so no y axis may be called `\"x\"`. */\n axis?: string;\n /** An abscissa in the x axis' own terms (a category, a Date) for `axis: \"x\"`, a\n * number on that axis otherwise. A category the rows do not have draws nothing. */\n value: SeriesChartXValue;\n /** Written along the line, inside the plot at its top-left. SVG text: a string. */\n label?: string;\n /** Default `\"muted\"`. `color` wins over it. */\n tone?: SeriesChartTone;\n color?: string;\n /** Which of `STROKE_PATTERNS`. Default 1, dashed: a reference is not data, and a\n * solid line reads as a series nobody put in the legend. */\n dash?: number;\n}\n\n/**\n * A single labelled point — today's figure on keksdose's cash buffer, the month the\n * projection runs dry. For a mark on EVERY sample, or on the samples that meet a test,\n * use the series' `dot` instead; a marker is for a point that is a fact of its own.\n * Fitted like a reference: it widens the band it would otherwise fall outside of.\n */\nexport interface SeriesChartMarker {\n /** Distinct within the chart. Default: its position in the list. */\n key?: string;\n /** In the x axis' own terms, like a reference's `value`. */\n x: SeriesChartXValue;\n y: number;\n /** The y axis `y` is measured on. Default `\"y\"`. */\n axis?: string;\n /** Written above the point. */\n label?: string;\n /** Default `\"brand\"`. `color` wins over it. */\n tone?: SeriesChartTone;\n color?: string;\n /** Radius in px. Default 4.5. */\n r?: number;\n}\n\n/** What a click on the plot picked. */\nexport interface SeriesChartHit {\n /** The row's position in `rows`. */\n index: number;\n /** The caller's own row — with its `rawPeriod`, id or whatever the drilldown needs. */\n row: SeriesChartRow;\n x: SeriesChartXValue;\n /** The series, when the click landed ON a bar. A click anywhere else picks the slot\n * (the period), not a series. */\n key?: string;\n}\n\nexport interface SeriesChartProps {\n /** One row per abscissa value. A missing key is a hole (see `connectNulls`). */\n rows: readonly SeriesChartRow[];\n series: SeriesChartSeries[];\n /** Default: one untitled axis, `\"y\"`. */\n axes?: SeriesChartAxis[];\n x?: SeriesChartX;\n /** A value in the tooltip, where a number stands on its own and needs its unit.\n * Default: `Intl.NumberFormat` in the kit's locale. */\n valueFormat?: (value: number) => string;\n /** Tailwind height class, or a height in pixels. Default `h-72`. The empty state\n * takes it too, so a chart losing its last line does not relayout the page under it.\n * A number is for a height the caller holds as a number — keksdose's report charts\n * take `height = 260` as a prop and wrap the chart in a `SizedSeriesChart` div\n * (reports/charts/networth-line.tsx) only to turn it into a style, since a class\n * cannot be built from a number Tailwind never saw. */\n height?: string | number;\n /** Bridge holes left by sources sampled on different grids. See {@link mergeSeries}. */\n connectNulls?: boolean;\n /** Shown, centred at the chart's height, instead of an empty chart. Default: the\n * `seriesChart.empty` label. `null` shows nothing. */\n empty?: ReactNode;\n /**\n * Milliseconds for a line to draw itself in. Off by default: a chart beside a live\n * editor re-renders on every keystroke, and an animation restarted mid-flight reads\n * as the curve twitching. Turn it on where series come and go by choice.\n */\n animationMs?: number;\n spans?: SeriesChartSpan[];\n /** Lines across the plot at one value. */\n references?: SeriesChartReference[];\n /** Single labelled points. */\n markers?: SeriesChartMarker[];\n /**\n * Which axes a drag may zoom: `\"both\"`, `\"x\"`, `\"y\"` or `\"none\"`. Default: read off\n * the marks — see `defaultZoomAxes` (lines both, areas x, bars none). An axis carrying\n * bars or areas never takes a DRAGGED y window: it refits to the x window, from zero.\n * Ignored by `StaticSeriesChart`, which does not zoom.\n */\n zoomAxes?: ZoomAxesSetting;\n /**\n * A click on the plot: the slot under the pointer, and the series when it landed on a\n * bar. keksdose's drilldowns — a payee's month, a budget line, a spending category.\n * A drag that zoomed is not a click.\n */\n onPointClick?: (hit: SeriesChartHit) => void;\n /** Where the tooltip may go: for a chart inside a scroll wrapper. See\n * {@link SeriesChartTooltip}. */\n tooltip?: SeriesChartTooltip;\n /** Supplied by `withChartZoom` and by nothing else. */\n zoom?: ZoomBinding;\n /** Per-chart strings over `<UiKitProvider labels={{ seriesChart }}>`. */\n labels?: Partial<SeriesChartLabels>;\n /** BCP 47 tag for the default number formats. Default: the provider's. */\n locale?: string;\n /** Onto the chart's root (`ChartContainer`) — e.g. an app's own grid ink. */\n className?: string;\n /** The shortest bar drawn, in px, for every bar series that does not set its own\n * {@link SeriesChartSeries.minBarLength}. Drawing only: domain, tooltip and names\n * keep the real value. Default: none — a zero draws nothing. */\n minBarLength?: number;\n}\n\n/** How much of an axis band the rotated title takes, in px. Reserved rather than\n * shared with the ticks: a title merely offset inside the band prints on top of a\n * five-figure tick, and which gives way depends on the data. */\nexport const AXIS_TITLE_STRIP = 16;\n\n/** Where inside its strip the rotated title sits. */\nconst AXIS_TITLE_OFFSET = 10;\n\n/** The tallest band tilted x ticks reserve, in px. A category name longer than this at\n * its angle is clipped rather than squeezing the plot down to a strip. */\nconst MAX_TILTED_TICK_BAND = 120;\n\n/** What one character of a tick label is taken to be, in px, for the tilted band — the\n * shell's `text-xs`. An estimate: the SVG is not laid out yet when the band is decided. */\nconst TICK_CHAR_WIDTH = 7;\nconst TICK_LINE_HEIGHT = 12;\n/** recharts' gap between the axis line and a bottom tick's text. */\nconst TICK_GAP = 8;\n\n/**\n * The height the x axis reserves for ticks tilted by `angle` degrees: the rotated box of\n * the longest label, from its length. `undefined` for level ticks — recharts' own 30 px.\n */\nfunction tiltedTickBand(labels: readonly string[], angle: number): number | undefined {\n if (!angle) return undefined;\n const rad = (Math.abs(angle) * Math.PI) / 180;\n const longest = Math.max(0, ...labels.map((label) => label.length)) * TICK_CHAR_WIDTH;\n const band = Math.sin(rad) * longest + Math.cos(rad) * TICK_LINE_HEIGHT + TICK_GAP;\n return Math.min(MAX_TILTED_TICK_BAND, Math.max(30, Math.ceil(band)));\n}\n\n/** The width the ticks of a y axis get when a caller does not say. */\nexport const AXIS_TICK_WIDTH = 48;\n\n/**\n * How much air a FITTED axis leaves between the data and its frame, as a fraction of\n * the range. Recharts fits `[dataMin, dataMax]`, which draws a peak half a stroke\n * outside the plot and a curve running to its limit indistinguishable from the frame.\n */\nconst AUTO_PAD = 0.04;\n\n/** The band a fitted axis draws, padded — and a real band for constant data, which is\n * a zero-height domain recharts cannot scale into. `undefined` when nothing finite. */\nexport function paddedDomain(values: Iterable<number>): [number, number] | undefined {\n let low = Infinity;\n let high = -Infinity;\n for (const value of values) {\n if (!Number.isFinite(value)) continue;\n if (value < low) low = value;\n if (value > high) high = value;\n }\n return padBand(low, high);\n}\n\n/**\n * {@link paddedDomain} for a caller that has already walked its own data — so a row\n * of charts can share one scale without building an array to find two numbers in, and\n * without a second padding rule. `low > high` means \"nothing was seen\": `undefined`.\n */\nexport function padBand(low: number, high: number): [number, number] | undefined {\n if (!(low <= high)) return undefined;\n const pad = (high - low) * AUTO_PAD || Math.abs(high) * AUTO_PAD || 1;\n return [low - pad, high + pad];\n}\n\n/** The whole band a y axis occupies: its ticks, and its title when it draws one. For\n * lining a heading up over a PLOT rather than over its column. */\nexport function axisBandWidth(tickWidth: number | undefined, titled: boolean): number {\n return (tickWidth ?? AXIS_TICK_WIDTH) + (titled ? AXIS_TITLE_STRIP : 0);\n}\n\n/**\n * The colour an axis TITLE takes, or `undefined` for the neutral one.\n *\n * An axis measuring exactly one line is that line's, and saying so in the title lets a\n * reader find a channel's scale without counting axes. An axis measuring several is\n * nobody's — a title in the first one's colour would be claiming it. Counted off the\n * series, so toggling a second line onto an axis gives the colour up in the same render.\n */\nexport function soleSeriesColor(\n axis: Pick<SeriesChartAxisShape, \"id\" | \"color\">,\n series: readonly Pick<SeriesChartSeries, \"axis\">[],\n): string | undefined {\n const mine = series.filter((entry) => (entry.axis ?? DEFAULT_Y_AXIS) === axis.id);\n return mine.length === 1 ? axis.color : undefined;\n}\n\n/** The single-axis case, which is most charts. `width` is what the TICKS need;\n * `orientation` is which side they stand on. */\nexport function oneAxis(\n format: ((value: number) => string) | undefined,\n title: string,\n width?: number,\n orientation?: \"left\" | \"right\",\n): SeriesChartAxis[] {\n return [{ id: DEFAULT_Y_AXIS, format, title, width, orientation }];\n}\n\n/** One source's samples: an abscissa and the channels measured against it. */\nexport interface SeriesSource {\n x: number[];\n channels: Record<string, number[]>;\n}\n\n/**\n * Merge sources sampled on different grids into rows the chart can draw.\n *\n * Merged ON THE ABSCISSA VALUE ITSELF, never interpolated onto a common grid: a line\n * through invented points looks exactly like one through measured ones. Where a source\n * has no sample the key is absent, and `connectNulls` bridges the hole with the same\n * straight segment an interpolation would have drawn — without claiming a measurement.\n */\nexport function mergeSeries(sources: SeriesSource[]): Record<string, number>[] {\n const byAbscissa = new Map<number, Record<string, number>>();\n for (const source of sources) {\n source.x.forEach((value, index) => {\n const row = byAbscissa.get(value) ?? { x: value };\n for (const [key, channel] of Object.entries(source.channels)) row[key] = channel[index];\n byAbscissa.set(value, row);\n });\n }\n return [...byAbscissa.values()].sort((a, b) => a.x - b.x);\n}\n\n/**\n * A series key built out of parts — as a CSS identifier.\n *\n * The chart shell paints each series through `--color-<key>`, and skips (with a\n * console warning) any key that is not `[A-Za-z_][A-Za-z0-9_-]*`. A line whose colour\n * was skipped has no stroke at all: an axis, a grid and nothing between them. So a key\n * assembled out of DATA — an id, an enum, a side — goes through here: every other\n * character becomes `_`, the parts are joined with `_`, and a key that would start with\n * a digit or a hyphen gets a leading `_`.\n */\nexport function seriesKey(...parts: (string | number)[]): string {\n const key = parts.map((part) => String(part).replace(/[^A-Za-z0-9_-]/g, \"_\")).join(\"_\");\n return /^[A-Za-z_]/.test(key) ? key : `_${key}`;\n}\n\n/**\n * The band an axis carrying bars or areas draws: the data's extent with ZERO in it,\n * padded only on the sides that are not zero — bars standing on a frame's bottom edge,\n * not floating four per cent above it on a band of air nobody asked for.\n * `undefined` when there is nothing to fit.\n */\nexport function anchoredBand(extent: readonly [number, number] | undefined): [number, number] | undefined {\n if (!extent) return undefined;\n const low = Math.min(0, extent[0]);\n const high = Math.max(0, extent[1]);\n const pad = (high - low) * AUTO_PAD || 1;\n return [low < 0 ? low - pad : 0, high > 0 ? high + pad : 0];\n}\n\n/**\n * Series with their colours settled BEFORE any are switched off.\n *\n * A series with no `color` takes `paletteFor(its position)` — and a legend toggle that\n * hands the chart a shorter list moves every later series one position up, repainting\n * it in its neighbour's colour on each click. Resolving the colours on the full list\n * and filtering after keeps each series in the colour its legend entry shows.\n */\nexport function visibleSeries(\n series: readonly SeriesChartSeries[],\n hidden: ReadonlySet<string>,\n): SeriesChartSeries[] {\n return series\n .map((entry, index) => ({ ...entry, color: entry.color ?? paletteFor(index) }))\n .filter((entry) => !hidden.has(entry.key));\n}\n\n/**\n * The `ToggleLegend` entries for a chart's FULL series list — colours resolved the way\n * the chart resolves them, and a stroke mark for a line drawn in a pattern (dashed,\n * step) so the key promises the stroke the plot draws. A bar or an area is a swatch.\n * Pair with {@link visibleSeries} for the chart itself.\n */\nexport function seriesLegendEntries(series: readonly SeriesChartSeries[]): LegendEntry[] {\n return series.map((entry, index) => {\n // A custom dash array goes to the legend as it is, so the swatch draws what the plot does.\n const own = entry.dash ?? (entry.dashed ? 1 : 0);\n const dash = entry.step ? STEP_DASH : own;\n const line = (entry.type ?? \"line\") === \"line\";\n return {\n key: entry.key,\n label: entry.label,\n color: entry.color ?? paletteFor(index),\n ...(line && dash !== 0 ? { marker: \"stroke\" as const, dash } : {}),\n };\n });\n}\n\n/** The number format every default falls back to. */\nfunction useDefaultFormat(localeProp: string | undefined): (value: number) => string {\n const locale = useKitLocale(localeProp);\n return useMemo(() => {\n const format = new Intl.NumberFormat(locale, { maximumFractionDigits: 2 });\n return (value: number) => format.format(value);\n }, [locale]);\n}\n\n/** The Y-axis list a chart draws when the caller gave none. */\nconst ONE_UNTITLED_AXIS: SeriesChartAxis[] = [{ id: DEFAULT_Y_AXIS, title: \"\" }];\n\n/** Where a category or time chart keeps each row's plotted position. Not the caller's\n * key: that one still holds their own value, which `format` and a hit hand back. */\nconst PLOTTED_X = \"__seriesChartX\";\n\n/** A finite number, or `undefined` — the only thing a row cell counts as a sample. */\nconst finite = (value: unknown): number | undefined =>\n typeof value === \"number\" && Number.isFinite(value) ? value : undefined;\n\n/** A time value as epoch ms. A date-only ISO string is LOCAL midnight (see\n * `SeriesChartX.type`); anything unreadable is `undefined`, i.e. not plotted. */\nfunction toTime(value: unknown): number | undefined {\n if (value instanceof Date) return finite(value.getTime());\n if (typeof value === \"number\") return finite(value);\n if (typeof value !== \"string\") return undefined;\n const day = /^(\\d{4})-(\\d{2})(?:-(\\d{2}))?$/.exec(value);\n if (day) return new Date(Number(day[1]), Number(day[2]) - 1, Number(day[3] ?? 1)).getTime();\n return finite(Date.parse(value));\n}\n\n/** A category's identity, so a Date matches another Date of the same instant. */\nconst categoryId = (value: unknown) =>\n value instanceof Date ? `d:${value.getTime()}` : `${typeof value}:${String(value)}`;\n\n/**\n * The abscissa, reduced to a number line — which is all the plot, the ticks and the\n * zoom ever deal in. A number stays itself; a category becomes its slot index; a time\n * its epoch ms. Everything the caller sees (ticks, tooltip, hits) is turned back.\n */\ninterface XModel {\n kind: \"number\" | \"category\" | \"time\";\n /** The caller's key, still holding their value. */\n sourceKey: string;\n /** The key the plot reads. The same as `sourceKey` on a number line. */\n plotKey: string;\n /** The rows as plotted. The caller's own on a number line. */\n rows: readonly SeriesChartRow[];\n /** The caller's rows, which dots and hits hand back. */\n source: readonly SeriesChartRow[];\n position: (value: unknown) => number | undefined;\n valueAt: (position: number) => SeriesChartXValue;\n}\n\nfunction xModel(rows: readonly SeriesChartRow[], x: SeriesChartX): XModel {\n const sourceKey = x.key ?? \"x\";\n if (x.type === \"category\") {\n const slots = new Map<string, number>();\n rows.forEach((row, index) => {\n const id = categoryId(row[sourceKey]);\n if (!slots.has(id)) slots.set(id, index);\n });\n return {\n kind: \"category\",\n sourceKey,\n plotKey: PLOTTED_X,\n rows: rows.map((row, index) => ({ ...row, [PLOTTED_X]: index })),\n source: rows,\n position: (value) => slots.get(categoryId(value)),\n valueAt: (position) => rows[Math.round(position)]?.[sourceKey] as SeriesChartXValue,\n };\n }\n if (x.type === \"time\") {\n return {\n kind: \"time\",\n sourceKey,\n plotKey: PLOTTED_X,\n rows: rows.map((row) => ({ ...row, [PLOTTED_X]: toTime(row[sourceKey]) })),\n source: rows,\n position: toTime,\n valueAt: (position) => new Date(position),\n };\n }\n return {\n kind: \"number\",\n sourceKey,\n plotKey: sourceKey,\n rows,\n source: rows,\n position: finite,\n valueAt: (position) => position,\n };\n}\n\n/** Caller ticks, as positions inside the domain on show. */\nfunction resolveTicks<T>(\n values: SeriesChartTickValues<T> | undefined,\n domain: [number, number] | undefined,\n position: (value: T) => number | undefined,\n): number[] | undefined {\n if (!values || !domain) return undefined;\n const list = typeof values === \"function\" ? values(domain) : values;\n if (!list) return undefined;\n const slack = (domain[1] - domain[0]) * 1e-9;\n return list\n .map(position)\n .filter((at): at is number => at !== undefined && at >= domain[0] - slack && at <= domain[1] + slack);\n}\n\n/** A low/high pair widened by some values, or `undefined` if there is still none. */\nfunction extend(\n span: readonly [number, number] | undefined,\n values: readonly (number | undefined)[],\n): [number, number] | undefined {\n let out: [number, number] | undefined = span ? [span[0], span[1]] : undefined;\n for (const value of values) {\n if (value === undefined || !Number.isFinite(value)) continue;\n out = out ? [Math.min(out[0], value), Math.max(out[1], value)] : [value, value];\n }\n return out;\n}\n\n/** How a time tick is written, by what one step of the ticks is. */\nconst TIME_TICK_FORMAT: Record<TimeTickUnit, Intl.DateTimeFormatOptions> = {\n hour: { hour: \"2-digit\", minute: \"2-digit\" },\n day: { day: \"numeric\", month: \"short\" },\n month: { month: \"short\", year: \"2-digit\" },\n year: { year: \"numeric\" },\n};\n\n/** The two numbers every mark type needs to agree on for the chart to read as one. */\nconst LINE_WIDTH = 2;\nconst STEP_WIDTH = 1.5;\n\n/** Bars round their FREE end only, and a stacked bar has none but the top layer's —\n * which recharts cannot tell apart per cell, so stacks stay square. */\nconst BAR_RADIUS: [number, number, number, number] = [3, 3, 0, 0];\n\n/**\n * One keyboard stop of a clickable chart: a bar, or (a chart with no bars) a whole slot.\n * `from`/`to` bound its slot on the plotted number line — half way to each neighbour,\n * or to the edge of the window on show.\n */\ninterface PointStop {\n index: number;\n /** The bar's series; absent for a slot. */\n key?: string;\n from: number;\n to: number;\n /** The accessible name: where it is and what it says. */\n name: string;\n}\n\n/**\n * The shape of a series whose bar has keyboard focus: recharts' own rectangle, with an\n * outline on the one bar at `index` — drawn at the bar's exact geometry, which an\n * overlay could only guess at. Not `activeBar`: that follows the tooltip's active index,\n * which recharts stops taking from `defaultIndex` once a pointer has hovered the chart.\n */\nfunction focusedBarShape(index: number) {\n return function FocusedBar(props: BarShapeProps) {\n const focused = props.originalDataIndex === index;\n return (\n <Rectangle {...props} {...(focused ? { stroke: \"var(--text-primary)\", strokeWidth: 2 } : {})} />\n );\n };\n}\n\n/**\n * The keyboard's way onto a clickable chart (`onPointClick`): one focusable `<rect>` per\n * bar, or per slot when there are no bars, laid over the plot INSIDE the recharts chart,\n * where the x scale answers.\n *\n * keksdose drew its weekday pattern as seven real `<button>`s (spending-tab.tsx) because\n * a recharts bar is reachable by nothing but the pointer. This is that, for every chart:\n *\n * - ONE tab stop (roving `tabIndex`): Tab moves past the chart, not through 30 bars.\n * - ←/→ step through the stops in order, ↑/↓ between the bars of one slot, Home/End.\n * - ↵ and Space report the stop as a click would — with the series for a bar.\n * - Each is a `role=\"button\"` named \"period — series: value\".\n *\n * The stops take NO pointer events, so the drag-to-zoom layer, the tooltip and the\n * pointer's own clicks underneath behave exactly as they did. Focus is shown by the\n * slot tinted and, for a bar, its own outline (`focusedBarShape`) — and by the tooltip,\n * moved to the stop through `defaultIndex`, which recharts honours until a pointer has\n * hovered the chart.\n */\nfunction PointKeys({\n stops,\n current,\n label,\n onFocusStop,\n onBlurStops,\n onPick,\n}: {\n stops: readonly PointStop[];\n current: number;\n label: string;\n onFocusStop: (at: number) => void;\n onBlurStops: () => void;\n onPick: (stop: PointStop) => void;\n}) {\n const plot = usePlotArea();\n const scale = useXAxisScale();\n const refs = useRef<(SVGRectElement | null)[]>([]);\n if (!plot || !scale || plot.width <= 0 || plot.height <= 0) return null;\n\n const move = (at: number) => {\n const next = Math.max(0, Math.min(stops.length - 1, at));\n refs.current[next]?.focus();\n };\n const onKeyDown = (at: number) => (event: KeyboardEvent<SVGRectElement>) => {\n const stop = stops[at];\n // ↑/↓ stay in the slot: the next or previous bar of the same period. The stops are\n // in slot order, so a slot's bars are neighbours.\n const inSlot = (step: 1 | -1) => (stops[at + step]?.index === stop.index ? at + step : at);\n const target =\n event.key === \"ArrowRight\"\n ? at + 1\n : event.key === \"ArrowLeft\"\n ? at - 1\n : event.key === \"ArrowDown\"\n ? inSlot(1)\n : event.key === \"ArrowUp\"\n ? inSlot(-1)\n : event.key === \"Home\"\n ? 0\n : event.key === \"End\"\n ? stops.length - 1\n : undefined;\n if (target !== undefined) {\n event.preventDefault();\n move(target);\n } else if (event.key === \"Enter\" || event.key === \" \") {\n event.preventDefault();\n onPick(stop);\n }\n };\n\n const left = plot.x;\n const right = plot.x + plot.width;\n return (\n <g role=\"group\" aria-label={label}>\n {stops.map((stop, at) => {\n // An edge with no neighbour runs to the plot's edge.\n const a = finite(scale(stop.from)) ?? left;\n const b = finite(scale(stop.to)) ?? right;\n const x0 = Math.max(left, Math.min(a, b));\n const x1 = Math.min(right, Math.max(a, b));\n return (\n <rect\n key={`${stop.index}:${stop.key ?? \"\"}`}\n ref={(node) => {\n refs.current[at] = node;\n }}\n role=\"button\"\n tabIndex={at === current ? 0 : -1}\n aria-label={stop.name}\n data-point-key={stop.key}\n x={x0}\n y={plot.y}\n width={Math.max(0, x1 - x0)}\n height={plot.height}\n fill=\"transparent\"\n // Focus only: the pointer's drag, hover and click belong to what is below.\n pointerEvents=\"none\"\n strokeWidth={2}\n className={cn(\n \"outline-none focus-visible:fill-[var(--brand)]/10\",\n // A bar outlines ITSELF (see `FOCUSED_BAR`); a slot has nothing else to.\n stop.key === undefined && \"focus-visible:stroke-[var(--brand)]\",\n )}\n onFocus={() => onFocusStop(at)}\n onBlur={onBlurStops}\n onKeyDown={onKeyDown(at)}\n />\n );\n })}\n </g>\n );\n}\n\ninterface PlotProps extends Omit<SeriesChartProps, \"rows\" | \"x\"> {\n /** The rows AS PLOTTED — what the zoom fits on. The caller's are `model.source`. */\n rows: readonly SeriesChartRow[];\n /** What the zoom fits on: the plotted key. */\n x: { key: string };\n model: XModel;\n xAxis: SeriesChartX;\n}\n\n/** The chart proper, over an abscissa already reduced to numbers (see {@link XModel}). */\nfunction SeriesPlot({\n model,\n xAxis,\n series,\n axes = ONE_UNTITLED_AXIS,\n valueFormat,\n height = \"h-72\",\n connectNulls,\n empty,\n animationMs = 0,\n spans,\n references,\n markers,\n onPointClick,\n tooltip,\n zoom,\n labels: labelsProp,\n locale: localeProp,\n className,\n minBarLength,\n}: PlotProps) {\n const labels = useKitLabels(\"seriesChart\", DEFAULT_SERIES_CHART_LABELS, labelsProp);\n const locale = useKitLocale(localeProp);\n const number = useDefaultFormat(localeProp);\n // The keyboard stops' roving tab stop, and the one that has focus (see `PointKeys`).\n // Up here, above the empty state's early return, like every hook.\n const [keyStop, setKeyStop] = useState(0);\n const [keyFocus, setKeyFocus] = useState<number | undefined>(undefined);\n\n // A number is pixels, set inline; a string is a class. Either way the one value\n // sizes both the chart and its empty state.\n const heightClass = typeof height === \"string\" ? height : undefined;\n const heightStyle = typeof height === \"number\" ? { height } : undefined;\n\n // The empty state takes the chart's own height and is centred in it: a chart that\n // shrank to its \"nothing to draw\" sentence moved everything under it up the page\n // the moment a legend entry was switched off.\n if (!model.source.length || !series.length) {\n return (\n <div\n className={cn(\"flex w-full items-center justify-center px-2 text-center\", heightClass)}\n style={heightStyle}\n >\n {empty !== undefined ? (\n empty\n ) : (\n <p className=\"text-xs text-[var(--text-muted)]\">{labels.empty}</p>\n )}\n </div>\n );\n }\n\n const x = xAxis;\n const xKey = model.plotKey;\n const plotted = model.rows;\n const rows = model.source;\n const config: ChartConfig = Object.fromEntries(\n series.map((entry, index) => [\n entry.key,\n { label: entry.label, color: entry.color ?? paletteFor(index) },\n ]),\n );\n const visible = axes.filter((axis) => !axis.hide);\n // The grid hangs its horizontal rules off ONE y axis, and recharts looks for the one\n // whose id is its own default (`0`). Every axis here is named, so without saying\n // which, it finds none and draws no horizontal rules at all. The first visible axis,\n // because those are the ticks a reader puts a ruler on.\n const gridAxis = (visible[0] ?? axes[0])?.id ?? DEFAULT_Y_AXIS;\n const onLeft = visible.some((axis) => (axis.orientation ?? \"left\") === \"left\");\n const onRight = visible.some((axis) => axis.orientation === \"right\");\n // The margins are what is left once the axes have their bands: an axis band IS the\n // gutter on its side, so a margin beside one is a second gutter. What remains is the\n // overhang of the first/last x tick where no y axis covers it.\n const margin = {\n // Room for a marker's label over a point at the top of the band.\n top: markers?.some((marker) => marker.label) ? 22 : 8,\n right: onRight ? 0 : 10,\n left: onLeft ? 0 : 10,\n // Under the ticks, not under the whole axis: whatever comes next owns the gap.\n bottom: x.title ? 18 : 2,\n };\n\n const refs = references ?? [];\n const xRefs = refs.filter((ref) => ref.axis === \"x\");\n const yRefs = refs.filter((ref) => ref.axis !== \"x\");\n const xPos = (value: SeriesChartXValue) => model.position(value);\n\n // Fitted with air around it, unless the reader has zoomed or the caller pinned it.\n // Ticks are the round values INSIDE whichever domain that is (see\n // `series-chart-ticks.ts`), so a zoom window still gets round numbers, just finer.\n // A category axis is its slots, each half a slot of air either side — room for a\n // bar, and the tick under the middle of it.\n const fittedX: [number, number] | undefined =\n zoom?.xDomain ??\n (model.kind === \"category\"\n ? [-0.5, rows.length - 0.5]\n : padBand(\n ...(extend(\n undefined,\n [\n ...plotted.map((row) => finite(row[xKey])),\n ...xRefs.map((ref) => xPos(ref.value)),\n ...(markers ?? []).map((marker) => xPos(marker.x)),\n ],\n ) ?? [Infinity, -Infinity]),\n ));\n\n const timeUnit = model.kind === \"time\" ? timeTicksWithUnit(fittedX) : undefined;\n // Whole-number ticks on a number line whose rows are all whole numbers — see\n // `SeriesChartX.integerTicks`.\n const integerX =\n model.kind === \"number\" &&\n (x.integerTicks ??\n plotted.every((row) => {\n const value = finite(row[xKey]);\n return value === undefined || Number.isInteger(value);\n }));\n const xTicks =\n resolveTicks(x.tickValues, fittedX, xPos) ??\n (model.kind === \"category\"\n ? categoryTicks(fittedX, rows.length)\n : model.kind === \"time\"\n ? timeUnit?.ticks\n : integerX\n ? (integerTicks(fittedX) ?? niceTicks(fittedX))\n : niceTicks(fittedX));\n\n // Ticks and the tooltip heading, back in the caller's terms.\n const timeFormat = new Intl.DateTimeFormat(locale, TIME_TICK_FORMAT[timeUnit?.unit ?? \"day\"]);\n const dateFormat = new Intl.DateTimeFormat(locale, {\n dateStyle: \"medium\",\n ...(timeUnit?.unit === \"hour\" ? { timeStyle: \"short\" } : {}),\n });\n const categoryText = (value: SeriesChartXValue) =>\n value instanceof Date\n ? dateFormat.format(value)\n : typeof value === \"number\"\n ? number(value)\n : String(value ?? \"\");\n const tickAt = (position: number): SeriesChartXTick => ({\n value: model.valueAt(position),\n ...(model.kind === \"category\" ? { index: Math.round(position) } : {}),\n ...(timeUnit ? { unit: timeUnit.unit } : {}),\n });\n const defaultFormat = (position: number, tick: SeriesChartXTick) =>\n model.kind === \"category\"\n ? categoryText(tick.value)\n : model.kind === \"time\"\n ? timeFormat.format(position)\n : number(position);\n const format = x.format ?? defaultFormat;\n const xFormat = (position: number) => format(position, tickAt(position));\n const label =\n x.label ??\n (model.kind === \"time\" ? (position: number) => dateFormat.format(position) : format);\n const xLabel = (position: number) => label(position, tickAt(position));\n\n const tickAngle = x.ticks === false ? 0 : (x.tickAngle ?? 0);\n const tickBand = tiltedTickBand((xTicks ?? []).map((tick) => xFormat(tick)), tickAngle);\n\n const source: ZoomFitSource = {\n rows: plotted,\n series,\n axes,\n xKey,\n };\n // An axis a bar or an area stands on is read from zero (see `includeZero`).\n const anchored = (axis: SeriesChartAxis) =>\n axis.includeZero ??\n series.some(\n (entry) => (entry.axis ?? DEFAULT_Y_AXIS) === axis.id && (entry.type ?? \"line\") !== \"line\",\n );\n // Whole-number ticks on an axis whose values are all whole — see\n // `SeriesChartAxis.integerTicks`. A stack of whole layers sums to a whole number, so\n // the layers are enough to look at.\n const wholeOnly = (axis: SeriesChartAxis) =>\n axis.integerTicks ??\n series\n .filter((entry) => (entry.axis ?? DEFAULT_Y_AXIS) === axis.id)\n .every((entry) =>\n plotted.every((row) => {\n const value = finite(row[entry.key]);\n return value === undefined || Number.isInteger(value);\n }),\n );\n const onAxis = (axisId: string) => (ref: { axis?: string }) => (ref.axis ?? DEFAULT_Y_AXIS) === axisId;\n const fittedY = (axis: SeriesChartAxis): [number, number] | undefined => {\n const own = [\n ...yRefs.filter(onAxis(axis.id)).map((ref) => finite(ref.value)),\n ...(markers ?? []).filter(onAxis(axis.id)).map((marker) => finite(marker.y)),\n ];\n if (anchored(axis)) {\n // Never a dragged y window: refitted to the x window, still from zero.\n if (zoom?.xDomain) return anchoredBand(axisExtent(source, axis.id, zoom.xDomain)) ?? axis.domain;\n return axis.domain ?? anchoredBand(extend(axisExtent(source, axis.id), own));\n }\n return (\n zoom?.yDomains[axis.id] ??\n axis.domain ??\n padBand(...(extend(axisExtent(source, axis.id), own) ?? [Infinity, -Infinity]))\n );\n };\n\n // The abscissa of a row in the caller's terms: a category is its slot, which is\n // its index; a time or a number is read back from where it was plotted.\n const xOf = (index: number): SeriesChartXValue =>\n model.kind === \"category\"\n ? (rows[index][model.sourceKey] as SeriesChartXValue)\n : model.valueAt(finite(plotted[index][xKey]) ?? NaN);\n const hitAt = (index: number, key?: string): SeriesChartHit | undefined => {\n const row = rows[index];\n return row ? { index, row, x: xOf(index), key } : undefined;\n };\n\n // The keyboard stops of a clickable chart — every bar with a value, slot by slot; or,\n // with no bars, every slot with any value. Only what is inside the window on show.\n const stops: PointStop[] = [];\n if (onPointClick) {\n const valueText = valueFormat ?? number;\n const nameOf = (entry: SeriesChartSeries) =>\n typeof entry.label === \"string\" || typeof entry.label === \"number\" ? String(entry.label) : entry.key;\n const said = (entry: SeriesChartSeries, value: number) => {\n const name = nameOf(entry);\n return name ? `${name}: ${valueText(value)}` : valueText(value);\n };\n const bars = series.filter((entry) => entry.type === \"bar\");\n const [low, high] = fittedX ?? [-Infinity, Infinity];\n const placed = plotted\n .map((row, index) => ({ index, at: model.kind === \"category\" ? index : finite(row[xKey]) }))\n .filter((slot): slot is { index: number; at: number } => slot.at !== undefined && slot.at >= low && slot.at <= high)\n .sort((a, b) => a.at - b.at);\n placed.forEach(({ index, at }, k) => {\n const from = k > 0 ? (placed[k - 1].at + at) / 2 : low;\n const to = k < placed.length - 1 ? (placed[k + 1].at + at) / 2 : high;\n // The heading the tooltip would give it, when that is text; else the tick.\n const heading = xLabel(at);\n const where = typeof heading === \"string\" && heading ? heading : xFormat(at);\n const valued = (bars.length ? bars : series)\n .map((entry) => ({ entry, value: finite(rows[index]?.[entry.key]) }))\n .filter((cell): cell is { entry: SeriesChartSeries; value: number } => cell.value !== undefined);\n if (bars.length) {\n for (const { entry, value } of valued) {\n stops.push({ index, key: entry.key, from, to, name: `${where} — ${said(entry, value)}` });\n }\n } else if (valued.length) {\n stops.push({\n index,\n from,\n to,\n name: `${where} — ${valued.map(({ entry, value }) => said(entry, value)).join(\", \")}`,\n });\n }\n });\n }\n const focusedStop = keyFocus === undefined ? undefined : stops[keyFocus];\n\n const dotFor = (entry: SeriesChartSeries) => {\n const want = entry.dot;\n if (!want) return false;\n const color = `var(--color-${entry.key})`;\n return (props: { cx?: number; cy?: number; index: number }) => {\n const { cx, cy, index } = props;\n const value = finite(rows[index]?.[entry.key]);\n if (value === undefined || !Number.isFinite(cx) || !Number.isFinite(cy)) return <g />;\n const point: SeriesChartPoint = {\n key: entry.key,\n index,\n row: rows[index],\n x: xOf(index),\n value,\n cx: cx!,\n cy: cy!,\n color,\n };\n const drawn = want === true ? true : want(point);\n if (drawn === true) {\n return (\n <circle\n className=\"recharts-dot\"\n cx={cx}\n cy={cy}\n r={3}\n fill={color}\n // Ringed in the surface, so a dot on a crossing line still reads as a dot.\n stroke=\"var(--bg-surface)\"\n strokeWidth={1.5}\n />\n );\n }\n if (drawn === false || drawn == null) return <g />;\n return <g>{drawn}</g>;\n };\n };\n\n const animation = {\n isAnimationActive: animationMs > 0,\n animationDuration: animationMs,\n animationEasing: \"ease-out\" as const,\n };\n\n return (\n <ChartContainer\n config={config}\n className={cn(\"w-full\", heightClass, className, onPointClick && \"cursor-pointer\")}\n style={heightStyle}\n >\n <ComposedChart\n data={plotted as Record<string, unknown>[]}\n margin={margin}\n // Positive and negative layers stacked apart, as `axisExtent` fits them — a\n // month's expenses hang below the axis instead of eating into its income.\n stackOffset=\"sign\"\n // recharts' own keyboard layer makes the whole surface a tab stop whose arrows\n // move the tooltip — a second stop beside `PointKeys`, and one ↵ does nothing on.\n accessibilityLayer={!onPointClick}\n onClick={\n onPointClick\n ? (state) => {\n const index = Number(state?.activeTooltipIndex ?? state?.activeIndex);\n const hit = Number.isInteger(index) ? hitAt(index) : undefined;\n if (hit) onPointClick(hit);\n }\n : undefined\n }\n >\n {/* Both ways: a measurement plot is read by putting a ruler on it, and a\n horizontal-only grid answers half of those questions. */}\n <CartesianGrid yAxisId={gridAxis} />\n <XAxis\n dataKey={xKey}\n // Numeric, not categorical: a measured sweep is unevenly spaced, and a\n // category axis would straighten exactly the curvature the chart is for.\n // A category chart is numeric too — on the slot index — which is what lets\n // it zoom and keeps its ticks under the middle of each bar group.\n type=\"number\"\n domain={fittedX ?? [\"dataMin\", \"dataMax\"]}\n ticks={xTicks}\n // Clip the lines to a zoom window instead of recharts widening it back out.\n allowDataOverflow={zoom?.xDomain !== undefined || model.kind === \"category\"}\n tickLine={false}\n axisLine={false}\n minTickGap={32}\n tick={x.ticks === false ? false : undefined}\n {...(tickAngle\n ? { angle: tickAngle, textAnchor: tickAngle < 0 ? \"end\" : \"start\" }\n : {})}\n // With neither ticks nor title there is nothing to reserve the band for, and\n // recharts' own 30 px would leave a gap under every chart of a stack.\n height={x.ticks === false && !x.title ? 4 : tickBand}\n tickFormatter={(value: number) => xFormat(Number(value))}\n >\n {x.title && (\n <Label\n value={x.title}\n position=\"insideBottom\"\n offset={-12}\n className=\"fill-[var(--text-muted)] text-[11px]\"\n />\n )}\n </XAxis>\n {axes.map((axis) => {\n const domain = fittedY(axis);\n const zoomed = anchored(axis)\n ? zoom?.xDomain !== undefined\n : zoom?.yDomains[axis.id] !== undefined;\n return (\n <YAxis\n key={axis.id}\n yAxisId={axis.id}\n hide={axis.hide}\n domain={domain}\n ticks={\n resolveTicks(axis.tickValues, domain, finite) ??\n (wholeOnly(axis) ? (integerTicks(domain) ?? niceTicks(domain)) : niceTicks(domain))\n }\n allowDataOverflow={zoomed}\n orientation={axis.orientation ?? \"left\"}\n width={axisBandWidth(axis.width, Boolean(axis.title) && !axis.hide)}\n tickLine={false}\n axisLine={false}\n tickFormatter={axis.format ?? number}\n // With an axis per channel the tint is the only thing saying which\n // numbers belong to which line.\n tick={axis.color ? { fill: axis.color } : undefined}\n >\n {axis.title && !axis.hide && (\n <Label\n value={axis.title}\n // Rotated so both sides read upward from the bottom of their axis.\n angle={axis.orientation === \"right\" ? 90 : -90}\n position={axis.orientation === \"right\" ? \"insideRight\" : \"insideLeft\"}\n // Inline, so a sole series' colour beats the class's neutral fill —\n // and absent for a shared axis, so the class draws it.\n style={{ textAnchor: \"middle\", fill: soleSeriesColor(axis, series) }}\n offset={AXIS_TITLE_OFFSET}\n className=\"fill-[var(--text-muted)] text-[11px]\"\n />\n )}\n </YAxis>\n );\n })}\n <ChartTooltip\n {...(tooltip?.allowEscapeViewBox || tooltip?.boundary\n ? { allowEscapeViewBox: tooltip.allowEscapeViewBox ?? { x: true } }\n : {})}\n // The content shifts itself 12 px off the cursor (or flips) against the\n // boundary; recharts' own offset on top would double it.\n {...(tooltip?.boundary ? { offset: 0 } : {})}\n // The keyboard's stop shows its tooltip as the pointer's would.\n defaultIndex={focusedStop?.index}\n content={\n <ChartTooltipContent\n labelFormatter={(value) => xLabel(Number(value))}\n valueFormatter={valueFormat ?? number}\n boundaryRef={tooltip?.boundary}\n />\n }\n />\n {series.map((entry) => {\n const type = entry.type ?? \"line\";\n const yAxisId = entry.axis ?? DEFAULT_Y_AXIS;\n const color = `var(--color-${entry.key})`;\n const own = entry.dash ?? (entry.dashed ? 1 : 0);\n const dash = entry.step ? strokeDash(STEP_DASH) : typeof own === \"string\" ? own : strokeDash(own);\n const curve = entry.step ? \"stepAfter\" : (entry.curve ?? \"monotone\");\n const width = entry.strokeWidth ?? (entry.step ? STEP_WIDTH : LINE_WIDTH);\n if (type === \"bar\") {\n const stub = entry.minBarLength ?? minBarLength;\n return (\n <Bar\n key={entry.key}\n yAxisId={yAxisId}\n dataKey={entry.key}\n stackId={entry.stack}\n fill={color}\n fillOpacity={entry.fillOpacity}\n radius={entry.stack === undefined ? BAR_RADIUS : 0}\n // Read off the row rather than recharts' `value`: in a stack that is the\n // layer's running top, which a hole has too — and a hole gets no stub.\n {...(stub ? { minPointSize: (_value: unknown, index: number) => (finite(plotted[index]?.[entry.key]) === undefined ? 0 : stub) } : {})}\n // Only the focused stop's series swaps its shape, and only for as long\n // as it has focus: every other bar keeps recharts' own.\n {...(focusedStop?.key === entry.key ? { shape: focusedBarShape(focusedStop.index) } : {})}\n onClick={\n onPointClick\n ? (_bar, index, event) => {\n // The plot's own click would report the same slot again,\n // without the series.\n event.stopPropagation();\n const hit = hitAt(index, entry.key);\n if (hit) onPointClick(hit);\n }\n : undefined\n }\n {...animation}\n />\n );\n }\n if (type === \"area\") {\n return (\n <Area\n key={entry.key}\n yAxisId={yAxisId}\n type={curve}\n dataKey={entry.key}\n stackId={entry.stack}\n stroke={color}\n strokeWidth={width}\n strokeDasharray={dash}\n fill={color}\n fillOpacity={entry.fillOpacity ?? (entry.stack !== undefined ? 0.55 : 0.2)}\n dot={dotFor(entry)}\n {...(entry.activeDot !== undefined ? { activeDot: entry.activeDot } : {})}\n connectNulls={connectNulls}\n {...animation}\n />\n );\n }\n return (\n <Line\n key={entry.key}\n yAxisId={yAxisId}\n type={curve}\n dataKey={entry.key}\n stroke={color}\n strokeWidth={width}\n strokeDasharray={dash}\n dot={dotFor(entry)}\n {...(entry.activeDot !== undefined ? { activeDot: entry.activeDot } : {})}\n connectNulls={connectNulls}\n {...animation}\n />\n );\n })}\n {spans?.map((span) => (\n <ReferenceLine\n key={span.key}\n yAxisId={span.axis ?? DEFAULT_Y_AXIS}\n segment={[\n { x: span.x, y: span.from },\n { x: span.x, y: span.to },\n ]}\n stroke={span.color ?? \"var(--text-muted)\"}\n strokeWidth={2}\n // Discarded rather than clamped when zoomed past: a span clamped to the\n // window's edge draws a vertical line at an abscissa it never stood at.\n ifOverflow=\"discard\"\n />\n ))}\n {refs.map((ref, index) => {\n const vertical = ref.axis === \"x\";\n const at = vertical ? xPos(ref.value) : finite(ref.value);\n if (at === undefined) return null;\n const color = ref.color ?? TONE_COLOR[ref.tone ?? \"muted\"];\n return (\n <ReferenceLine\n key={ref.key ?? `reference-${index}`}\n // A vertical line still needs a y axis to be drawn against, and every\n // axis here is named — the grid's is always there.\n yAxisId={vertical ? gridAxis : (ref.axis ?? DEFAULT_Y_AXIS)}\n {...(vertical ? { x: at } : { y: at })}\n stroke={color}\n strokeWidth={1}\n strokeDasharray={strokeDash(ref.dash ?? 1)}\n ifOverflow=\"discard\"\n label={\n ref.label\n ? {\n value: ref.label,\n position: \"insideTopLeft\",\n fontSize: 10,\n fill: color,\n }\n : undefined\n }\n />\n );\n })}\n {markers?.map((marker, index) => {\n const at = xPos(marker.x);\n if (at === undefined || finite(marker.y) === undefined) return null;\n const color = marker.color ?? TONE_COLOR[marker.tone ?? \"brand\"];\n return (\n <ReferenceDot\n key={marker.key ?? `marker-${index}`}\n yAxisId={marker.axis ?? DEFAULT_Y_AXIS}\n x={at}\n y={marker.y}\n r={marker.r ?? 4.5}\n fill={color}\n stroke=\"var(--bg-surface)\"\n strokeWidth={1.5}\n ifOverflow=\"discard\"\n label={\n marker.label\n ? {\n value: marker.label,\n position: \"top\",\n fontSize: 11,\n fontWeight: 600,\n fill: \"var(--text-primary)\",\n }\n : undefined\n }\n />\n );\n })}\n {stops.length > 0 && (\n <PointKeys\n stops={stops}\n current={Math.min(keyStop, stops.length - 1)}\n label={labels.points}\n onFocusStop={(at) => {\n setKeyStop(at);\n setKeyFocus(at);\n }}\n onBlurStops={() => setKeyFocus(undefined)}\n onPick={(stop) => {\n const hit = hitAt(stop.index, stop.key);\n if (hit) onPointClick?.(hit);\n }}\n />\n )}\n {zoom?.layer}\n </ComposedChart>\n </ChartContainer>\n );\n}\n\nconst ZoomablePlot = withChartZoom(SeriesPlot);\n\n/** The caller's props, with the abscissa reduced to numbers for the plot and the zoom. */\nfunction plotProps(props: SeriesChartProps): PlotProps {\n const x = props.x ?? {};\n const model = xModel(props.rows, x);\n return { ...props, rows: model.rows, x: { key: model.plotKey }, model, xAxis: x };\n}\n\n/**\n * {@link SeriesChart} without the zoom: the same picture, no drag layer, no reset\n * button. For a thumbnail, a print view, or a chart the consumer wraps in its own\n * interaction.\n */\nexport function StaticSeriesChart(props: SeriesChartProps) {\n return <SeriesPlot {...plotProps(props)} />;\n}\n\n/**\n * The series chart, zoomable. Drag across the plot to zoom (the drag's shape picks the\n * axes), double-click or press the reset button to go back; wrap several in\n * `SharedXZoom` to move their x windows together. Which axes zoom depends on the marks\n * — see {@link SeriesChartProps.zoomAxes}.\n */\nexport function SeriesChart(props: SeriesChartProps) {\n // The zoom fits the PLOTTED rows — slot indices and epoch ms, not the caller's labels.\n return <ZoomablePlot {...plotProps(props)} />;\n}\n"],"mappings":"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","names":[]}
|
|
@@ -1,9 +1,58 @@
|
|
|
1
1
|
import * as react from 'react';
|
|
2
2
|
import { ReactNode } from 'react';
|
|
3
|
-
import { SelectProps } from '
|
|
3
|
+
import { aH as SelectProps } from '../kit-labels-v3biUF1L.js';
|
|
4
4
|
import { ThemePreference } from '../theme/theme-store.js';
|
|
5
|
+
import './data-table-labels.js';
|
|
6
|
+
import './mini-calendar.js';
|
|
7
|
+
import './calendar-heatmap.js';
|
|
8
|
+
import './popover.js';
|
|
9
|
+
import './chip.js';
|
|
10
|
+
import 'lucide-react';
|
|
11
|
+
import './field-sync.js';
|
|
5
12
|
import './tooltip.js';
|
|
6
13
|
import '../hooks/use-anchored-rect.js';
|
|
14
|
+
import '../lib/clipping.js';
|
|
15
|
+
import '../wizard/types.js';
|
|
16
|
+
import '../tour/tour.js';
|
|
17
|
+
import '../search/command-palette.js';
|
|
18
|
+
import '../search/global-search.js';
|
|
19
|
+
import '../search/search-index.js';
|
|
20
|
+
import './month-picker.js';
|
|
21
|
+
import './page-contents.js';
|
|
22
|
+
import './series-chart-labels.js';
|
|
23
|
+
import './pie-chart-labels.js';
|
|
24
|
+
import './sparkline.js';
|
|
25
|
+
import './stat-tile.js';
|
|
26
|
+
import './signature-pad.js';
|
|
27
|
+
import './password-strength.js';
|
|
28
|
+
import './danger-confirm.js';
|
|
29
|
+
import './swatch-picker.js';
|
|
30
|
+
import './tile-radio.js';
|
|
31
|
+
import './icon-picker.js';
|
|
32
|
+
import './dialog-frame.js';
|
|
33
|
+
import './modal.js';
|
|
34
|
+
import '../hooks/use-search-param-state.js';
|
|
35
|
+
import './measured-grid.js';
|
|
36
|
+
import '../feedback/feedback-attachment.js';
|
|
37
|
+
import '../feedback/feedback-dialog.js';
|
|
38
|
+
import '../feedback/feedback-thread.js';
|
|
39
|
+
import '../feedback/feedback-inbox.js';
|
|
40
|
+
import './account-settings-labels.js';
|
|
41
|
+
import './confirm-dialog.js';
|
|
42
|
+
import './floating-panel.js';
|
|
43
|
+
import './bulk-action-bar.js';
|
|
44
|
+
import './list.js';
|
|
45
|
+
import './breadcrumbs.js';
|
|
46
|
+
import './toast.js';
|
|
47
|
+
import './description-list.js';
|
|
48
|
+
import './line-items.js';
|
|
49
|
+
import './progress-bar.js';
|
|
50
|
+
import './signed-amount.js';
|
|
51
|
+
import './error-boundary.js';
|
|
52
|
+
import './authed-image.js';
|
|
53
|
+
import '../hooks/use-authed-src.js';
|
|
54
|
+
import './image-grid.js';
|
|
55
|
+
import './lightbox.js';
|
|
7
56
|
import 'zustand/middleware';
|
|
8
57
|
import 'zustand';
|
|
9
58
|
|