@seekalfred/primitives 0.7.1 → 0.7.4

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.
Files changed (147) hide show
  1. package/README.md +255 -5
  2. package/dist/alert/alert.d.ts +49 -4
  3. package/dist/alert/alert.js +66 -38
  4. package/dist/alert/alert.js.map +1 -1
  5. package/dist/alert/index.d.ts +2 -2
  6. package/dist/alert/index.js +2 -2
  7. package/dist/alert-dialog/alert-dialog.d.ts +31 -4
  8. package/dist/alert-dialog/alert-dialog.js +75 -26
  9. package/dist/alert-dialog/alert-dialog.js.map +1 -1
  10. package/dist/announcement-bar/announcement-bar.d.ts +15 -4
  11. package/dist/announcement-bar/announcement-bar.js +31 -6
  12. package/dist/announcement-bar/announcement-bar.js.map +1 -1
  13. package/dist/avatar/avatar.d.ts +7 -0
  14. package/dist/avatar/avatar.js +33 -12
  15. package/dist/avatar/avatar.js.map +1 -1
  16. package/dist/badge/badge.d.ts +1 -1
  17. package/dist/bar-chart/bar-chart-series.d.ts +75 -0
  18. package/dist/bar-chart/bar-chart-series.js +401 -0
  19. package/dist/bar-chart/bar-chart-series.js.map +1 -0
  20. package/dist/bar-chart/bar-chart.d.ts +25 -1
  21. package/dist/bar-chart/bar-chart.js +26 -1
  22. package/dist/bar-chart/bar-chart.js.map +1 -1
  23. package/dist/bar-chart/index.d.ts +2 -1
  24. package/dist/button/button.d.ts +1 -1
  25. package/dist/calendar/calendar.d.ts +1 -1
  26. package/dist/card/card.d.ts +22 -1
  27. package/dist/card/card.js +60 -7
  28. package/dist/card/card.js.map +1 -1
  29. package/dist/carousel/carousel.d.ts +21 -0
  30. package/dist/carousel/carousel.js +34 -8
  31. package/dist/carousel/carousel.js.map +1 -1
  32. package/dist/chip-group/chip-group.d.ts +11 -0
  33. package/dist/chip-group/chip-group.js +50 -34
  34. package/dist/chip-group/chip-group.js.map +1 -1
  35. package/dist/chip-group/index.d.ts +2 -2
  36. package/dist/copy-button/copy-button.d.ts +37 -5
  37. package/dist/copy-button/copy-button.js +35 -11
  38. package/dist/copy-button/copy-button.js.map +1 -1
  39. package/dist/donut-chart/donut-chart.d.ts +22 -0
  40. package/dist/donut-chart/donut-chart.js +35 -18
  41. package/dist/donut-chart/donut-chart.js.map +1 -1
  42. package/dist/donut-chart/index.d.ts +2 -2
  43. package/dist/empty-state/empty-state.d.ts +21 -0
  44. package/dist/empty-state/empty-state.js +16 -4
  45. package/dist/empty-state/empty-state.js.map +1 -1
  46. package/dist/empty-state/index.d.ts +2 -2
  47. package/dist/empty-state/index.js +2 -2
  48. package/dist/file-drop-zone/file-drop-zone.d.ts +29 -3
  49. package/dist/file-drop-zone/file-drop-zone.js +26 -8
  50. package/dist/file-drop-zone/file-drop-zone.js.map +1 -1
  51. package/dist/filter-bar/filter-bar.d.ts +4 -1
  52. package/dist/filter-bar/filter-bar.js +53 -9
  53. package/dist/filter-bar/filter-bar.js.map +1 -1
  54. package/dist/gauge/gauge.d.ts +18 -1
  55. package/dist/gauge/gauge.js +35 -21
  56. package/dist/gauge/gauge.js.map +1 -1
  57. package/dist/gauge/index.d.ts +2 -2
  58. package/dist/index.d.ts +15 -14
  59. package/dist/index.js +9 -9
  60. package/dist/input/input.d.ts +7 -0
  61. package/dist/input/input.js +7 -5
  62. package/dist/input/input.js.map +1 -1
  63. package/dist/lib/field-shell.js +6 -3
  64. package/dist/lib/field-shell.js.map +1 -1
  65. package/dist/lib/field-surface.js +22 -1
  66. package/dist/lib/field-surface.js.map +1 -1
  67. package/dist/lib/required-marker.js +20 -0
  68. package/dist/lib/required-marker.js.map +1 -0
  69. package/dist/lib/use-copy-feedback.js +17 -3
  70. package/dist/lib/use-copy-feedback.js.map +1 -1
  71. package/dist/line-chart/index.d.ts +2 -2
  72. package/dist/line-chart/line-chart.d.ts +144 -2
  73. package/dist/line-chart/line-chart.js +314 -46
  74. package/dist/line-chart/line-chart.js.map +1 -1
  75. package/dist/money-input/index.d.ts +2 -2
  76. package/dist/money-input/money-input.d.ts +36 -1
  77. package/dist/money-input/money-input.js +30 -14
  78. package/dist/money-input/money-input.js.map +1 -1
  79. package/dist/morph-select/morph-select.d.ts +26 -1
  80. package/dist/morph-select/morph-select.js +28 -6
  81. package/dist/morph-select/morph-select.js.map +1 -1
  82. package/dist/multi-select/index.d.ts +2 -2
  83. package/dist/multi-select/index.js +2 -2
  84. package/dist/multi-select/multi-select.d.ts +74 -2
  85. package/dist/multi-select/multi-select.js +213 -39
  86. package/dist/multi-select/multi-select.js.map +1 -1
  87. package/dist/password-field/password-field.d.ts +16 -0
  88. package/dist/password-field/password-field.js +37 -8
  89. package/dist/password-field/password-field.js.map +1 -1
  90. package/dist/popover/index.d.ts +2 -2
  91. package/dist/popover/index.js +2 -2
  92. package/dist/popover/popover.d.ts +39 -2
  93. package/dist/popover/popover.js +29 -2
  94. package/dist/popover/popover.js.map +1 -1
  95. package/dist/progress/index.d.ts +2 -2
  96. package/dist/progress/index.js +2 -2
  97. package/dist/progress/progress.d.ts +68 -3
  98. package/dist/progress/progress.js +156 -39
  99. package/dist/progress/progress.js.map +1 -1
  100. package/dist/radio-group/index.d.ts +2 -2
  101. package/dist/radio-group/index.js +2 -2
  102. package/dist/radio-group/radio-group.d.ts +33 -3
  103. package/dist/radio-group/radio-group.js +109 -9
  104. package/dist/radio-group/radio-group.js.map +1 -1
  105. package/dist/scroll-area/scroll-area.js +4 -3
  106. package/dist/scroll-area/scroll-area.js.map +1 -1
  107. package/dist/scrub-input/scrub-input.d.ts +11 -1
  108. package/dist/scrub-input/scrub-input.js +22 -10
  109. package/dist/scrub-input/scrub-input.js.map +1 -1
  110. package/dist/search-field/search-field.d.ts +22 -1
  111. package/dist/search-field/search-field.js +22 -7
  112. package/dist/search-field/search-field.js.map +1 -1
  113. package/dist/select/select.d.ts +10 -1
  114. package/dist/select/select.js +11 -8
  115. package/dist/select/select.js.map +1 -1
  116. package/dist/separator/separator.d.ts +21 -9
  117. package/dist/separator/separator.js +33 -11
  118. package/dist/separator/separator.js.map +1 -1
  119. package/dist/sparkline/sparkline.d.ts +27 -2
  120. package/dist/sparkline/sparkline.js +115 -18
  121. package/dist/sparkline/sparkline.js.map +1 -1
  122. package/dist/stat-card/index.d.ts +2 -2
  123. package/dist/stat-card/index.js +2 -2
  124. package/dist/stat-card/stat-card.d.ts +65 -1
  125. package/dist/stat-card/stat-card.js +98 -25
  126. package/dist/stat-card/stat-card.js.map +1 -1
  127. package/dist/styles.css +1 -1
  128. package/dist/table/index.d.ts +2 -2
  129. package/dist/table/index.js +2 -2
  130. package/dist/table/table.d.ts +115 -5
  131. package/dist/table/table.js +374 -94
  132. package/dist/table/table.js.map +1 -1
  133. package/dist/text-shimmer/text-shimmer.d.ts +18 -2
  134. package/dist/text-shimmer/text-shimmer.js +5 -2
  135. package/dist/text-shimmer/text-shimmer.js.map +1 -1
  136. package/dist/textarea/textarea.d.ts +7 -0
  137. package/dist/textarea/textarea.js +3 -1
  138. package/dist/textarea/textarea.js.map +1 -1
  139. package/dist/time-picker/time-picker.d.ts +36 -1
  140. package/dist/time-picker/time-picker.js +33 -5
  141. package/dist/time-picker/time-picker.js.map +1 -1
  142. package/dist/toast/toast.d.ts +2 -2
  143. package/dist/usage-meter/index.d.ts +2 -2
  144. package/dist/usage-meter/usage-meter.d.ts +30 -0
  145. package/dist/usage-meter/usage-meter.js +56 -38
  146. package/dist/usage-meter/usage-meter.js.map +1 -1
  147. package/package.json +3 -3
@@ -0,0 +1,401 @@
1
+ "use client";
2
+ import { cn } from "../lib/cn.js";
3
+ import { mergeRefs } from "../lib/merge-refs.js";
4
+ import { prefersReducedMotion, useIsomorphicLayoutEffect } from "../lib/motion.js";
5
+ import { forwardRef, useEffect, useId, useMemo, useRef, useState } from "react";
6
+ import { jsx, jsxs } from "react/jsx-runtime";
7
+ //#region src/bar-chart/bar-chart-series.tsx
8
+ /** Room past the top gridline, the share of a slot a category fills, the widest bar, the gap inside a group, the data-end radius, a row's default height. */
9
+ const TOP = 12;
10
+ const FILL = .62;
11
+ const MAX_BAR = 28;
12
+ const INNER_GAP = 2;
13
+ const RADIUS = 4;
14
+ const ROW = 32;
15
+ /** Stagger between categories on the first reveal, and its cap. */
16
+ const STAGGER_MS = 35;
17
+ const STAGGER_CAP_MS = 360;
18
+ const NEUTRAL = [
19
+ 56,
20
+ 42,
21
+ 32
22
+ ];
23
+ const GROUPED = new Intl.NumberFormat("en-US", { maximumFractionDigits: 1 });
24
+ const COMPACT = new Intl.NumberFormat("en-US", {
25
+ notation: "compact",
26
+ maximumFractionDigits: 1
27
+ });
28
+ const clamp = (value, low, high) => Math.min(high, Math.max(low, value));
29
+ const colorOf = (item, index) => item.color ?? (index < 4 ? `var(--color-chart-${index + 1})` : `color-mix(in oklab, var(--color-foreground) ${NEUTRAL[(index - 4) % NEUTRAL.length]}%, var(--color-surface))`);
30
+ /** The number to draw, or null when there is none. */
31
+ const numberOf = (value) => typeof value === "number" && Number.isFinite(value) ? value : null;
32
+ /** Clean gridlines: the smallest step of 1, 2, 3 or 5 that covers the data in four rows or fewer. */
33
+ function scaleFor(max) {
34
+ const safe = Math.max(max, 1);
35
+ const magnitude = 10 ** Math.floor(Math.log10(safe / 4));
36
+ for (const factor of [
37
+ 1,
38
+ 2,
39
+ 3,
40
+ 5,
41
+ 10
42
+ ]) {
43
+ const step = factor * magnitude;
44
+ const rows = Math.ceil(safe / step);
45
+ if (rows <= 4) return {
46
+ top: rows * step,
47
+ ticks: Array.from({ length: rows + 1 }, (_, row) => row * step)
48
+ };
49
+ }
50
+ return {
51
+ top: safe,
52
+ ticks: [0, safe]
53
+ };
54
+ }
55
+ /**
56
+ * One bar as a path in plot pixels: `start` along the category axis, `size`
57
+ * across it, from `from` to `to` along the value axis. Only the data end is
58
+ * rounded, and only when `round`.
59
+ */
60
+ function barPath(vertical, start, size, from, to, round, base) {
61
+ const f = (value) => value.toFixed(2);
62
+ const length = to - from;
63
+ if (size <= 0 || length <= .01) return "";
64
+ const r = round ? Math.min(RADIUS, size / 2, length) : 0;
65
+ if (vertical) {
66
+ const bottom = base - from;
67
+ const top = base - to;
68
+ const x = start;
69
+ return `M${f(x)} ${f(bottom)}V${f(top + r)}A${f(r)} ${f(r)} 0 0 1 ${f(x + r)} ${f(top)}H${f(x + size - r)}A${f(r)} ${f(r)} 0 0 1 ${f(x + size)} ${f(top + r)}V${f(bottom)}Z`;
70
+ }
71
+ const y = start;
72
+ return `M${f(from)} ${f(y)}H${f(to - r)}A${f(r)} ${f(r)} 0 0 1 ${f(to)} ${f(y + r)}V${f(y + size - r)}A${f(r)} ${f(r)} 0 0 1 ${f(to - r)} ${f(y + size)}H${f(from)}Z`;
73
+ }
74
+ const SeriesBarChart = forwardRef(function SeriesBarChart({ data, series, label, period, layout = "grouped", orientation = "vertical", unit = "", height: heightProp, formatValue = (value) => GROUPED.format(value), formatTick = (value) => COMPACT.format(value), categoryLabel = "Category", missingLabel = "No data", legend, hiddenSeries, defaultHiddenSeries = [], onHiddenSeriesChange, className }, ref) {
75
+ const figure = useRef(null);
76
+ const refs = useMemo(() => mergeRefs(ref, figure), [ref]);
77
+ const plot = useRef(null);
78
+ const titleId = useId();
79
+ const vertical = orientation === "vertical";
80
+ const stacked = layout === "stacked";
81
+ const height = heightProp ?? (vertical ? 176 : Math.max(1, data.length) * ROW);
82
+ const suffix = unit ? ` ${unit}` : "";
83
+ const count = Math.max(data.length, 1);
84
+ const last = data.length - 1;
85
+ const [ownHidden, setOwnHidden] = useState(defaultHiddenSeries);
86
+ const hidden = hiddenSeries ?? ownHidden;
87
+ const toggle = (key) => {
88
+ const next = hidden.includes(key) ? hidden.filter((item) => item !== key) : [...hidden, key];
89
+ if (hiddenSeries === void 0) setOwnHidden(next);
90
+ onHiddenSeriesChange?.(next);
91
+ };
92
+ const visible = series.filter((item) => !hidden.includes(item.key));
93
+ const showLegend = legend ?? series.length > 1;
94
+ const peak = data.reduce((max, item) => {
95
+ const values = visible.map((line) => Math.max(0, numberOf(item.values[line.key]) ?? 0));
96
+ return Math.max(max, stacked ? values.reduce((sum, value) => sum + value, 0) : Math.max(0, ...values));
97
+ }, 0);
98
+ const { top, ticks } = useMemo(() => scaleFor(peak), [peak]);
99
+ const [active, setActive] = useState(null);
100
+ const index = active === null ? null : Math.min(active, last);
101
+ const scrubbing = index !== null && last >= 0;
102
+ const [width, setWidth] = useState(0);
103
+ useIsomorphicLayoutEffect(() => {
104
+ const node = plot.current;
105
+ if (!node) return;
106
+ const read = () => setWidth(node.clientWidth);
107
+ read();
108
+ if (typeof ResizeObserver === "undefined") return;
109
+ const observer = new ResizeObserver(read);
110
+ observer.observe(node);
111
+ return () => observer.disconnect();
112
+ }, []);
113
+ const [shown, setShown] = useState(false);
114
+ useEffect(() => {
115
+ const node = figure.current;
116
+ if (!node || prefersReducedMotion() || typeof IntersectionObserver === "undefined") {
117
+ setShown(true);
118
+ return;
119
+ }
120
+ const observer = new IntersectionObserver(([entry]) => {
121
+ if (!entry?.isIntersecting) return;
122
+ observer.disconnect();
123
+ setShown(true);
124
+ }, { threshold: .35 });
125
+ observer.observe(node);
126
+ return () => observer.disconnect();
127
+ }, []);
128
+ const along = vertical ? width : height;
129
+ const length = Math.max(0, vertical ? height - TOP : width - TOP);
130
+ const slot = along / count;
131
+ const groupSize = Math.min(slot * FILL, (stacked ? 1 : Math.max(1, visible.length)) * MAX_BAR);
132
+ const barSize = stacked ? groupSize : Math.max(0, (groupSize - INNER_GAP * (visible.length - 1)) / Math.max(1, visible.length));
133
+ const toPx = (value) => value / (top || 1) * length;
134
+ const step = Math.min(STAGGER_MS, STAGGER_CAP_MS / count);
135
+ const bars = data.flatMap((item, at) => {
136
+ const groupStart = at * slot + (slot - groupSize) / 2;
137
+ let stack = 0;
138
+ const values = series.map((line) => ({
139
+ line,
140
+ value: numberOf(item.values[line.key])
141
+ }));
142
+ const outermost = [...values].reverse().find(({ line, value }) => !hidden.includes(line.key) && (value ?? 0) > 0)?.line.key;
143
+ return values.flatMap(({ line, value }, seriesAt) => {
144
+ if (hidden.includes(line.key) || value === null || value <= 0 || !width) return [];
145
+ const place = visible.indexOf(line);
146
+ const start = stacked ? groupStart : groupStart + place * (barSize + INNER_GAP);
147
+ const from = stacked ? toPx(stack) : 0;
148
+ stack += value;
149
+ const to = stacked ? toPx(stack) : toPx(value);
150
+ const d = barPath(vertical, start, barSize, from, to, !stacked || line.key === outermost, height);
151
+ return d ? [{
152
+ key: `${item.key}:${line.key}`,
153
+ category: item.key,
154
+ series: line.key,
155
+ d,
156
+ color: colorOf(line, seriesAt),
157
+ at
158
+ }] : [];
159
+ });
160
+ });
161
+ const pointAt = (clientX, clientY) => {
162
+ const rect = plot.current?.getBoundingClientRect();
163
+ if (!rect) return 0;
164
+ const offset = vertical ? clientX - rect.left : clientY - rect.top;
165
+ const size = vertical ? rect.width : rect.height;
166
+ if (!size) return 0;
167
+ const rtl = vertical && plot.current && getComputedStyle(plot.current).direction === "rtl";
168
+ const at = Math.floor((rtl ? size - offset : offset) / size * count);
169
+ return clamp(at, 0, last);
170
+ };
171
+ const onKeyDown = (event) => {
172
+ if (event.key === "Escape" && scrubbing) {
173
+ event.preventDefault();
174
+ setActive(null);
175
+ return;
176
+ }
177
+ const from = index ?? -1;
178
+ const page = Math.min(5, count);
179
+ const next = {
180
+ ArrowLeft: from - 1,
181
+ ArrowUp: from - 1,
182
+ ArrowRight: index === null ? 0 : from + 1,
183
+ ArrowDown: index === null ? 0 : from + 1,
184
+ PageUp: from - page,
185
+ PageDown: from + page,
186
+ Home: 0,
187
+ End: last
188
+ }[event.key];
189
+ if (next === void 0 || last < 0) return;
190
+ event.preventDefault();
191
+ setActive(clamp(next, 0, last));
192
+ };
193
+ const read = (item, line) => {
194
+ const value = numberOf(item.values[line.key]);
195
+ return value === null ? missingLabel : `${formatValue(value, line)}${suffix}`;
196
+ };
197
+ const totalOf = (item) => visible.reduce((sum, line) => sum + (numberOf(item.values[line.key]) ?? 0), 0);
198
+ const reading = scrubbing ? data[index] : null;
199
+ const valueText = reading ? `${reading.label}: ${visible.map((line) => `${line.label} ${read(reading, line)}`).join(", ")}` : data.length ? `${data.length} ${categoryLabel.toLowerCase()}` : "No data";
200
+ const name = period ? `${label}, ${period}` : label;
201
+ const [tickHost, tickStyle] = vertical ? ["relative min-w-0 [grid-area:1/2]", (value) => ({ translate: `0 ${height - toPx(value)}px` })] : ["relative min-w-0 [grid-area:2/2]", (value) => ({ insetInlineStart: `${toPx(value)}px` })];
202
+ return /* @__PURE__ */ jsxs("figure", {
203
+ ref: refs,
204
+ "data-slot": "bar-chart",
205
+ "data-layout": layout,
206
+ "data-orientation": orientation,
207
+ "aria-labelledby": titleId,
208
+ className: cn("m-0 grid min-w-0 content-start gap-4 box-border font-sans text-foreground", className),
209
+ children: [
210
+ /* @__PURE__ */ jsx("figcaption", {
211
+ id: titleId,
212
+ className: "sr-only",
213
+ children: name
214
+ }),
215
+ showLegend ? /* @__PURE__ */ jsx("div", {
216
+ role: "group",
217
+ "aria-label": `${label} series`,
218
+ className: "-mx-2 flex min-w-0 flex-wrap gap-x-1 gap-y-0.5",
219
+ children: series.map((line, at) => /* @__PURE__ */ jsxs("button", {
220
+ type: "button",
221
+ "data-slot": "bar-chart-toggle",
222
+ "aria-pressed": !hidden.includes(line.key),
223
+ onClick: () => toggle(line.key),
224
+ style: { "--series": colorOf(line, at) },
225
+ className: "chart-legend-toggle",
226
+ children: [
227
+ /* @__PURE__ */ jsx("span", {
228
+ "aria-hidden": "true",
229
+ className: "bar-chart-swatch"
230
+ }),
231
+ /* @__PURE__ */ jsx("span", {
232
+ className: "chart-toggle-label",
233
+ children: line.label
234
+ }),
235
+ reading && !hidden.includes(line.key) ? /* @__PURE__ */ jsx("span", {
236
+ "data-slot": "bar-chart-toggle-value",
237
+ "aria-hidden": "true",
238
+ className: "tabular-nums text-foreground",
239
+ children: read(reading, line)
240
+ }) : null
241
+ ]
242
+ }, line.key))
243
+ }) : null,
244
+ /* @__PURE__ */ jsxs("div", {
245
+ "data-slot": "bar-chart-chart",
246
+ "data-scrubbing": scrubbing || void 0,
247
+ "data-shown": shown || void 0,
248
+ className: vertical ? "bar-chart-frame" : "bar-chart-frame-horizontal",
249
+ children: [
250
+ /* @__PURE__ */ jsx("div", {
251
+ "aria-hidden": "true",
252
+ "data-slot": "bar-chart-categories",
253
+ className: cn("relative min-w-0", vertical ? "overflow-hidden [grid-area:2/1]" : "[grid-area:1/1]"),
254
+ children: data.map((item, at) => /* @__PURE__ */ jsx("span", {
255
+ "data-category": item.key,
256
+ "data-active": scrubbing && index === at || void 0,
257
+ className: "bar-chart-category",
258
+ style: vertical ? {
259
+ insetInlineStart: `${at * slot}px`,
260
+ width: `${slot}px`
261
+ } : { height: `${slot}px` },
262
+ children: /* @__PURE__ */ jsx("span", {
263
+ className: "truncate",
264
+ children: item.axisLabel ?? item.label
265
+ })
266
+ }, item.key))
267
+ }),
268
+ /* @__PURE__ */ jsxs("div", {
269
+ ref: plot,
270
+ className: cn("relative min-w-0", vertical ? "[grid-area:1/1]" : "[grid-area:1/2]"),
271
+ style: { height },
272
+ children: [/* @__PURE__ */ jsxs("svg", {
273
+ width: "100%",
274
+ height,
275
+ "aria-hidden": "true",
276
+ focusable: "false",
277
+ className: "bar-chart-plot block overflow-hidden",
278
+ children: [
279
+ ticks.slice(1).map((value) => vertical ? /* @__PURE__ */ jsx("line", {
280
+ className: "line-chart-grid",
281
+ x1: 0,
282
+ x2: "100%",
283
+ y1: Math.round(height - toPx(value)) + .5,
284
+ y2: Math.round(height - toPx(value)) + .5
285
+ }, value) : /* @__PURE__ */ jsx("line", {
286
+ className: "line-chart-grid",
287
+ y1: 0,
288
+ y2: "100%",
289
+ x1: Math.round(toPx(value)) + .5,
290
+ x2: Math.round(toPx(value)) + .5
291
+ }, value)),
292
+ bars.map((item) => /* @__PURE__ */ jsx("path", {
293
+ "data-slot": "bar-chart-bar",
294
+ "data-category": item.category,
295
+ "data-series": item.series,
296
+ "data-active": scrubbing && index === item.at || void 0,
297
+ d: item.d,
298
+ className: "bar-chart-series-bar",
299
+ style: {
300
+ "--series": item.color,
301
+ transformOrigin: vertical ? `0 ${height}px` : "0 0",
302
+ transitionDelay: shown ? `0s, ${item.at * step}ms` : void 0
303
+ }
304
+ }, item.key)),
305
+ vertical ? /* @__PURE__ */ jsx("line", {
306
+ className: "line-chart-baseline",
307
+ x1: 0,
308
+ x2: "100%",
309
+ y1: height - .5,
310
+ y2: height - .5
311
+ }) : /* @__PURE__ */ jsx("line", {
312
+ className: "line-chart-baseline",
313
+ y1: 0,
314
+ y2: "100%",
315
+ x1: .5,
316
+ x2: .5
317
+ })
318
+ ]
319
+ }), /* @__PURE__ */ jsx("div", {
320
+ "data-slot": "bar-chart-scrubber",
321
+ role: "slider",
322
+ tabIndex: data.length ? 0 : -1,
323
+ "aria-label": `${label}, explore by ${categoryLabel.toLowerCase()}`,
324
+ "aria-orientation": vertical ? "horizontal" : "vertical",
325
+ "aria-valuemin": 1,
326
+ "aria-valuemax": Math.max(1, data.length),
327
+ "aria-valuenow": (index ?? 0) + 1,
328
+ "aria-valuetext": valueText,
329
+ onPointerDown: (event) => {
330
+ if (event.pointerType !== "mouse") event.currentTarget.setPointerCapture?.(event.pointerId);
331
+ setActive(pointAt(event.clientX, event.clientY));
332
+ },
333
+ onPointerMove: (event) => {
334
+ if (event.pointerType === "mouse" || event.buttons) setActive(pointAt(event.clientX, event.clientY));
335
+ },
336
+ onPointerUp: (event) => {
337
+ if (event.pointerType !== "mouse") setActive(null);
338
+ },
339
+ onPointerCancel: () => setActive(null),
340
+ onPointerLeave: (event) => {
341
+ if (event.pointerType === "mouse") setActive(null);
342
+ },
343
+ onKeyDown,
344
+ onBlur: () => setActive(null),
345
+ onFocus: (event) => {
346
+ if (event.currentTarget.matches(":focus-visible") && last >= 0) setActive((current) => current ?? 0);
347
+ },
348
+ className: "bar-chart-scrubber"
349
+ })]
350
+ }),
351
+ /* @__PURE__ */ jsx("div", {
352
+ "aria-hidden": "true",
353
+ "data-slot": "bar-chart-ticks",
354
+ className: tickHost,
355
+ children: ticks.map((value) => /* @__PURE__ */ jsx("span", {
356
+ "data-tick": value,
357
+ className: vertical ? "line-chart-tick" : "bar-chart-tick-horizontal",
358
+ style: tickStyle(value),
359
+ children: /* @__PURE__ */ jsx("span", {
360
+ className: cn("block text-xs leading-none tabular-nums text-muted-foreground", vertical ? "-translate-y-1/2" : ""),
361
+ children: formatTick(value)
362
+ })
363
+ }, value))
364
+ })
365
+ ]
366
+ }),
367
+ /* @__PURE__ */ jsx("div", {
368
+ className: "sr-only",
369
+ children: /* @__PURE__ */ jsxs("table", { children: [
370
+ /* @__PURE__ */ jsx("caption", { children: name }),
371
+ /* @__PURE__ */ jsx("thead", { children: /* @__PURE__ */ jsxs("tr", { children: [
372
+ /* @__PURE__ */ jsx("th", {
373
+ scope: "col",
374
+ children: categoryLabel
375
+ }),
376
+ visible.map((line) => /* @__PURE__ */ jsx("th", {
377
+ scope: "col",
378
+ children: line.label
379
+ }, line.key)),
380
+ stacked && visible.length > 1 ? /* @__PURE__ */ jsx("th", {
381
+ scope: "col",
382
+ children: "Total"
383
+ }) : null
384
+ ] }) }),
385
+ /* @__PURE__ */ jsx("tbody", { children: data.map((item) => /* @__PURE__ */ jsxs("tr", { children: [
386
+ /* @__PURE__ */ jsx("th", {
387
+ scope: "row",
388
+ children: item.label
389
+ }),
390
+ visible.map((line) => /* @__PURE__ */ jsx("td", { children: read(item, line) }, line.key)),
391
+ stacked && visible.length > 1 ? /* @__PURE__ */ jsxs("td", { children: [formatValue(totalOf(item), visible[0]), suffix] }) : null
392
+ ] }, item.key)) })
393
+ ] })
394
+ })
395
+ ]
396
+ });
397
+ });
398
+ //#endregion
399
+ export { SeriesBarChart };
400
+
401
+ //# sourceMappingURL=bar-chart-series.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"bar-chart-series.js","names":[],"sources":["../../src/bar-chart/bar-chart-series.tsx"],"sourcesContent":["\"use client\";\n\nimport {\n forwardRef,\n useEffect,\n useId,\n useMemo,\n useRef,\n useState,\n type CSSProperties,\n type KeyboardEvent,\n type PointerEvent,\n} from \"react\";\n\nimport { cn } from \"../lib/cn.js\";\nimport { mergeRefs } from \"../lib/merge-refs.js\";\nimport { prefersReducedMotion, useIsomorphicLayoutEffect } from \"../lib/motion.js\";\n\n/**\n * The series mode of BarChart: several measures per category, side by side\n * (`layout=\"grouped\"`) or stacked into one bar (`layout=\"stacked\"`), on a\n * categorical axis in data order, upright (`orientation=\"vertical\"`) or as\n * ranked rows (`orientation=\"horizontal\"`). One series is a plain categorical\n * or horizontal bar chart.\n *\n * Bars grow from the baseline the first time the chart is seen, a beat apart\n * (no motion under reduced motion). Hover, drag or the arrow keys step through\n * the categories: the active category keeps its colour while the rest step\n * back, and the legend reads that category's values. The legend toggles a\n * series off and on. A visually hidden table carries every value, and the plot\n * is a slider over the categories.\n */\nexport interface BarChartSeries {\n /** Stable identity, the key of this series' number in each datum's `values`. */\n key: string;\n /** Name in the legend and the data table. */\n label: string;\n /** Any CSS colour. Defaults to chart-1 to chart-4 in series order, then neutral steps. */\n color?: string;\n}\n\nexport interface BarChartSeriesDatum {\n /** Stable identity of the category. */\n key: string;\n /** Full label for the readout and screen readers, such as \"Brand search\". */\n label: string;\n /** Short label on the category axis. Defaults to `label`. */\n axisLabel?: string;\n /**\n * One value per series key. A missing value (`undefined`, `null` or not a\n * finite number) draws no bar and reads as `missingLabel`. Negative values\n * are drawn as zero: bars rise from a zero baseline.\n */\n values: Record<string, number | null | undefined>;\n}\n\nexport interface BarChartSeriesProps {\n data: BarChartSeriesDatum[];\n /** The measures. Passing `series` is what turns on this mode. */\n series: BarChartSeries[];\n /** What is measured, such as \"Spend by campaign\". Names the chart for assistive technology. */\n label: string;\n /** The range on show, such as \"Sep 15–21, 2026\". Read with the name; not printed. */\n period?: string;\n /** Series side by side in each category, or stacked into one bar. @default \"grouped\" */\n layout?: \"grouped\" | \"stacked\";\n /** Upright columns, or rows that grow from the inline start (ranked lists). @default \"vertical\" */\n orientation?: \"vertical\" | \"horizontal\";\n /** Unit after each value in the readout and the table, such as \"min\". */\n unit?: string;\n /**\n * Plot height in pixels. Upright: @default 176. Horizontal: 32px per\n * category by default.\n */\n height?: number;\n /** Formats values in the legend readout and the data table. */\n formatValue?: (value: number, series: BarChartSeries) => string;\n /** Formats the value axis. Defaults to a compact number, such as 1.2K. */\n formatTick?: (value: number) => string;\n /** Header of the first column in the data table read by screen readers. @default \"Category\" */\n categoryLabel?: string;\n /** Read in place of a missing value. @default \"No data\" */\n missingLabel?: string;\n /** Series toggles above the plot. Shown by default when there is more than one series. */\n legend?: boolean;\n /** Controlled hidden series keys. */\n hiddenSeries?: string[];\n defaultHiddenSeries?: string[];\n onHiddenSeriesChange?: (hidden: string[]) => void;\n /** Extra classes for the root. Merged last. */\n className?: string;\n}\n\n/** Room past the top gridline, the share of a slot a category fills, the widest bar, the gap inside a group, the data-end radius, a row's default height. */\nconst TOP = 12;\nconst FILL = 0.62;\nconst MAX_BAR = 28;\nconst INNER_GAP = 2;\nconst RADIUS = 4;\nconst ROW = 32;\n/** Stagger between categories on the first reveal, and its cap. */\nconst STAGGER_MS = 35;\nconst STAGGER_CAP_MS = 360;\nconst NEUTRAL = [56, 42, 32];\nconst GROUPED = new Intl.NumberFormat(\"en-US\", { maximumFractionDigits: 1 });\nconst COMPACT = new Intl.NumberFormat(\"en-US\", { notation: \"compact\", maximumFractionDigits: 1 });\nconst clamp = (value: number, low: number, high: number) => Math.min(high, Math.max(low, value));\n\nconst colorOf = (item: BarChartSeries, index: number) =>\n item.color ??\n (index < 4\n ? `var(--color-chart-${index + 1})`\n : `color-mix(in oklab, var(--color-foreground) ${NEUTRAL[(index - 4) % NEUTRAL.length]}%, var(--color-surface))`);\n\n/** The number to draw, or null when there is none. */\nconst numberOf = (value: number | null | undefined) =>\n typeof value === \"number\" && Number.isFinite(value) ? value : null;\n\n/** Clean gridlines: the smallest step of 1, 2, 3 or 5 that covers the data in four rows or fewer. */\nfunction scaleFor(max: number) {\n const safe = Math.max(max, 1);\n const magnitude = 10 ** Math.floor(Math.log10(safe / 4));\n for (const factor of [1, 2, 3, 5, 10]) {\n const step = factor * magnitude;\n const rows = Math.ceil(safe / step);\n if (rows <= 4)\n return { top: rows * step, ticks: Array.from({ length: rows + 1 }, (_, row) => row * step) };\n }\n return { top: safe, ticks: [0, safe] };\n}\n\n/**\n * One bar as a path in plot pixels: `start` along the category axis, `size`\n * across it, from `from` to `to` along the value axis. Only the data end is\n * rounded, and only when `round`.\n */\nfunction barPath(\n vertical: boolean,\n start: number,\n size: number,\n from: number,\n to: number,\n round: boolean,\n base: number,\n) {\n const f = (value: number) => value.toFixed(2);\n const length = to - from;\n if (size <= 0 || length <= 0.01) return \"\";\n const r = round ? Math.min(RADIUS, size / 2, length) : 0;\n if (vertical) {\n const bottom = base - from;\n const top = base - to;\n const x = start;\n return `M${f(x)} ${f(bottom)}V${f(top + r)}A${f(r)} ${f(r)} 0 0 1 ${f(x + r)} ${f(top)}H${f(x + size - r)}A${f(r)} ${f(r)} 0 0 1 ${f(x + size)} ${f(top + r)}V${f(bottom)}Z`;\n }\n const y = start;\n return `M${f(from)} ${f(y)}H${f(to - r)}A${f(r)} ${f(r)} 0 0 1 ${f(to)} ${f(y + r)}V${f(y + size - r)}A${f(r)} ${f(r)} 0 0 1 ${f(to - r)} ${f(y + size)}H${f(from)}Z`;\n}\n\nexport const SeriesBarChart = forwardRef<HTMLElement, BarChartSeriesProps>(function SeriesBarChart(\n {\n data,\n series,\n label,\n period,\n layout = \"grouped\",\n orientation = \"vertical\",\n unit = \"\",\n height: heightProp,\n formatValue = (value) => GROUPED.format(value),\n formatTick = (value) => COMPACT.format(value),\n categoryLabel = \"Category\",\n missingLabel = \"No data\",\n legend,\n hiddenSeries,\n defaultHiddenSeries = [],\n onHiddenSeriesChange,\n className,\n },\n ref,\n) {\n const figure = useRef<HTMLElement | null>(null);\n const refs = useMemo(() => mergeRefs(ref, figure), [ref]);\n const plot = useRef<HTMLDivElement>(null);\n const titleId = useId();\n const vertical = orientation === \"vertical\";\n const stacked = layout === \"stacked\";\n const height = heightProp ?? (vertical ? 176 : Math.max(1, data.length) * ROW);\n const suffix = unit ? ` ${unit}` : \"\";\n const count = Math.max(data.length, 1);\n const last = data.length - 1;\n\n const [ownHidden, setOwnHidden] = useState(defaultHiddenSeries);\n const hidden = hiddenSeries ?? ownHidden;\n const toggle = (key: string) => {\n const next = hidden.includes(key) ? hidden.filter((item) => item !== key) : [...hidden, key];\n if (hiddenSeries === undefined) setOwnHidden(next);\n onHiddenSeriesChange?.(next);\n };\n const visible = series.filter((item) => !hidden.includes(item.key));\n const showLegend = legend ?? series.length > 1;\n\n // The scale covers the visible series: the tallest bar grouped, the tallest stack stacked.\n const peak = data.reduce((max, item) => {\n const values = visible.map((line) => Math.max(0, numberOf(item.values[line.key]) ?? 0));\n return Math.max(\n max,\n stacked ? values.reduce((sum, value) => sum + value, 0) : Math.max(0, ...values),\n );\n }, 0);\n const { top, ticks } = useMemo(() => scaleFor(peak), [peak]);\n\n const [active, setActive] = useState<number | null>(null);\n const index = active === null ? null : Math.min(active, last);\n const scrubbing = index !== null && last >= 0;\n\n // The plot draws in its own pixels: measure its length along the value or category axis and follow resizes.\n const [width, setWidth] = useState(0);\n useIsomorphicLayoutEffect(() => {\n const node = plot.current;\n if (!node) return;\n const read = () => setWidth(node.clientWidth);\n read();\n if (typeof ResizeObserver === \"undefined\") return;\n const observer = new ResizeObserver(read);\n observer.observe(node);\n return () => observer.disconnect();\n }, []);\n\n // The bars grow once the chart is a third in view.\n const [shown, setShown] = useState(false);\n useEffect(() => {\n const node = figure.current;\n if (!node || prefersReducedMotion() || typeof IntersectionObserver === \"undefined\") {\n setShown(true);\n return;\n }\n const observer = new IntersectionObserver(\n ([entry]) => {\n if (!entry?.isIntersecting) return;\n observer.disconnect();\n setShown(true);\n },\n { threshold: 0.35 },\n );\n observer.observe(node);\n return () => observer.disconnect();\n }, []);\n\n // Geometry. Along the category axis each category owns one slot; along the value axis `length` pixels span 0..top.\n const along = vertical ? width : height;\n const length = Math.max(0, vertical ? height - TOP : width - TOP);\n const slot = along / count;\n const groupSize = Math.min(slot * FILL, (stacked ? 1 : Math.max(1, visible.length)) * MAX_BAR);\n const barSize = stacked\n ? groupSize\n : Math.max(0, (groupSize - INNER_GAP * (visible.length - 1)) / Math.max(1, visible.length));\n const toPx = (value: number) => (value / (top || 1)) * length;\n const step = Math.min(STAGGER_MS, STAGGER_CAP_MS / count);\n\n const bars = data.flatMap((item, at) => {\n const groupStart = at * slot + (slot - groupSize) / 2;\n let stack = 0;\n const values = series.map((line) => ({ line, value: numberOf(item.values[line.key]) }));\n // In a stack only the outermost drawn segment gets the rounded data end.\n const outermost = [...values]\n .reverse()\n .find(({ line, value }) => !hidden.includes(line.key) && (value ?? 0) > 0)?.line.key;\n return values.flatMap(({ line, value }, seriesAt) => {\n if (hidden.includes(line.key) || value === null || value <= 0 || !width) return [];\n const place = visible.indexOf(line);\n const start = stacked ? groupStart : groupStart + place * (barSize + INNER_GAP);\n const from = stacked ? toPx(stack) : 0;\n stack += value;\n const to = stacked ? toPx(stack) : toPx(value);\n const d = barPath(\n vertical,\n start,\n barSize,\n from,\n to,\n !stacked || line.key === outermost,\n height,\n );\n return d\n ? [\n {\n key: `${item.key}:${line.key}`,\n category: item.key,\n series: line.key,\n d,\n color: colorOf(line, seriesAt),\n at,\n },\n ]\n : [];\n });\n });\n\n const pointAt = (clientX: number, clientY: number) => {\n const rect = plot.current?.getBoundingClientRect();\n if (!rect) return 0;\n const offset = vertical ? clientX - rect.left : clientY - rect.top;\n const size = vertical ? rect.width : rect.height;\n if (!size) return 0;\n // The category axis runs with the text direction when upright.\n const rtl = vertical && plot.current && getComputedStyle(plot.current).direction === \"rtl\";\n const at = Math.floor(((rtl ? size - offset : offset) / size) * count);\n return clamp(at, 0, last);\n };\n const onKeyDown = (event: KeyboardEvent<HTMLDivElement>) => {\n if (event.key === \"Escape\" && scrubbing) {\n event.preventDefault();\n setActive(null);\n return;\n }\n const from = index ?? -1;\n const page = Math.min(5, count);\n const next = (\n {\n ArrowLeft: from - 1,\n ArrowUp: from - 1,\n ArrowRight: index === null ? 0 : from + 1,\n ArrowDown: index === null ? 0 : from + 1,\n PageUp: from - page,\n PageDown: from + page,\n Home: 0,\n End: last,\n } as Record<string, number>\n )[event.key];\n if (next === undefined || last < 0) return;\n event.preventDefault();\n setActive(clamp(next, 0, last));\n };\n\n const read = (item: BarChartSeriesDatum, line: BarChartSeries) => {\n const value = numberOf(item.values[line.key]);\n return value === null ? missingLabel : `${formatValue(value, line)}${suffix}`;\n };\n const totalOf = (item: BarChartSeriesDatum) =>\n visible.reduce((sum, line) => sum + (numberOf(item.values[line.key]) ?? 0), 0);\n const reading = scrubbing ? data[index]! : null;\n const valueText = reading\n ? `${reading.label}: ${visible.map((line) => `${line.label} ${read(reading, line)}`).join(\", \")}`\n : data.length\n ? `${data.length} ${categoryLabel.toLowerCase()}`\n : \"No data\";\n const name = period ? `${label}, ${period}` : label;\n const [tickHost, tickStyle]: [string, (value: number) => CSSProperties] = vertical\n ? [\n \"relative min-w-0 [grid-area:1/2]\",\n (value) => ({ translate: `0 ${height - toPx(value)}px` }),\n ]\n : [\"relative min-w-0 [grid-area:2/2]\", (value) => ({ insetInlineStart: `${toPx(value)}px` })];\n\n return (\n <figure\n ref={refs}\n data-slot=\"bar-chart\"\n data-layout={layout}\n data-orientation={orientation}\n aria-labelledby={titleId}\n className={cn(\n \"m-0 grid min-w-0 content-start gap-4 box-border font-sans text-foreground\",\n className,\n )}\n >\n <figcaption id={titleId} className=\"sr-only\">\n {name}\n </figcaption>\n {showLegend ? (\n <div\n role=\"group\"\n aria-label={`${label} series`}\n className=\"-mx-2 flex min-w-0 flex-wrap gap-x-1 gap-y-0.5\"\n >\n {series.map((line, at) => (\n <button\n key={line.key}\n type=\"button\"\n data-slot=\"bar-chart-toggle\"\n aria-pressed={!hidden.includes(line.key)}\n onClick={() => toggle(line.key)}\n style={{ \"--series\": colorOf(line, at) } as CSSProperties}\n className=\"chart-legend-toggle\"\n >\n <span aria-hidden=\"true\" className=\"bar-chart-swatch\" />\n <span className=\"chart-toggle-label\">{line.label}</span>\n {reading && !hidden.includes(line.key) ? (\n <span\n data-slot=\"bar-chart-toggle-value\"\n aria-hidden=\"true\"\n className=\"tabular-nums text-foreground\"\n >\n {read(reading, line)}\n </span>\n ) : null}\n </button>\n ))}\n </div>\n ) : null}\n <div\n data-slot=\"bar-chart-chart\"\n data-scrubbing={scrubbing || undefined}\n data-shown={shown || undefined}\n className={vertical ? \"bar-chart-frame\" : \"bar-chart-frame-horizontal\"}\n >\n {/* Category labels: under the columns, or beside the rows. */}\n <div\n aria-hidden=\"true\"\n data-slot=\"bar-chart-categories\"\n className={cn(\n \"relative min-w-0\",\n vertical ? \"overflow-hidden [grid-area:2/1]\" : \"[grid-area:1/1]\",\n )}\n >\n {data.map((item, at) => (\n <span\n key={item.key}\n data-category={item.key}\n data-active={(scrubbing && index === at) || undefined}\n className=\"bar-chart-category\"\n style={\n vertical\n ? { insetInlineStart: `${at * slot}px`, width: `${slot}px` }\n : { height: `${slot}px` }\n }\n >\n <span className=\"truncate\">{item.axisLabel ?? item.label}</span>\n </span>\n ))}\n </div>\n <div\n ref={plot}\n className={cn(\"relative min-w-0\", vertical ? \"[grid-area:1/1]\" : \"[grid-area:1/2]\")}\n style={{ height }}\n >\n {/* Mirrored in right-to-left text so the categories and the rows' growth follow the reading order. */}\n <svg\n width=\"100%\"\n height={height}\n aria-hidden=\"true\"\n focusable=\"false\"\n className=\"bar-chart-plot block overflow-hidden\"\n >\n {ticks\n .slice(1)\n .map((value) =>\n vertical ? (\n <line\n key={value}\n className=\"line-chart-grid\"\n x1={0}\n x2=\"100%\"\n y1={Math.round(height - toPx(value)) + 0.5}\n y2={Math.round(height - toPx(value)) + 0.5}\n />\n ) : (\n <line\n key={value}\n className=\"line-chart-grid\"\n y1={0}\n y2=\"100%\"\n x1={Math.round(toPx(value)) + 0.5}\n x2={Math.round(toPx(value)) + 0.5}\n />\n ),\n )}\n {bars.map((item) => (\n <path\n key={item.key}\n data-slot=\"bar-chart-bar\"\n data-category={item.category}\n data-series={item.series}\n data-active={(scrubbing && index === item.at) || undefined}\n d={item.d}\n className=\"bar-chart-series-bar\"\n style={\n {\n \"--series\": item.color,\n // The growth starts at the baseline, and each category a beat after the one before.\n transformOrigin: vertical ? `0 ${height}px` : \"0 0\",\n transitionDelay: shown ? `0s, ${item.at * step}ms` : undefined,\n } as CSSProperties\n }\n />\n ))}\n {vertical ? (\n <line\n className=\"line-chart-baseline\"\n x1={0}\n x2=\"100%\"\n y1={height - 0.5}\n y2={height - 0.5}\n />\n ) : (\n <line className=\"line-chart-baseline\" y1={0} y2=\"100%\" x1={0.5} x2={0.5} />\n )}\n </svg>\n {/* The scrubber lies over the plot: hover or drag across it, or focus it and use the arrow keys. */}\n <div\n data-slot=\"bar-chart-scrubber\"\n role=\"slider\"\n tabIndex={data.length ? 0 : -1}\n aria-label={`${label}, explore by ${categoryLabel.toLowerCase()}`}\n aria-orientation={vertical ? \"horizontal\" : \"vertical\"}\n aria-valuemin={1}\n aria-valuemax={Math.max(1, data.length)}\n aria-valuenow={(index ?? 0) + 1}\n aria-valuetext={valueText}\n onPointerDown={(event: PointerEvent<HTMLDivElement>) => {\n if (event.pointerType !== \"mouse\")\n event.currentTarget.setPointerCapture?.(event.pointerId);\n setActive(pointAt(event.clientX, event.clientY));\n }}\n onPointerMove={(event: PointerEvent<HTMLDivElement>) => {\n if (event.pointerType === \"mouse\" || event.buttons)\n setActive(pointAt(event.clientX, event.clientY));\n }}\n onPointerUp={(event: PointerEvent<HTMLDivElement>) => {\n if (event.pointerType !== \"mouse\") setActive(null);\n }}\n onPointerCancel={() => setActive(null)}\n onPointerLeave={(event: PointerEvent<HTMLDivElement>) => {\n if (event.pointerType === \"mouse\") setActive(null);\n }}\n onKeyDown={onKeyDown}\n onBlur={() => setActive(null)}\n onFocus={(event) => {\n if (event.currentTarget.matches(\":focus-visible\") && last >= 0)\n setActive((current) => current ?? 0);\n }}\n className=\"bar-chart-scrubber\"\n />\n </div>\n <div aria-hidden=\"true\" data-slot=\"bar-chart-ticks\" className={tickHost}>\n {ticks.map((value) => (\n <span\n key={value}\n data-tick={value}\n className={vertical ? \"line-chart-tick\" : \"bar-chart-tick-horizontal\"}\n style={tickStyle(value)}\n >\n <span\n className={cn(\n \"block text-xs leading-none tabular-nums text-muted-foreground\",\n vertical ? \"-translate-y-1/2\" : \"\",\n )}\n >\n {formatTick(value)}\n </span>\n </span>\n ))}\n </div>\n </div>\n <div className=\"sr-only\">\n <table>\n <caption>{name}</caption>\n <thead>\n <tr>\n <th scope=\"col\">{categoryLabel}</th>\n {visible.map((line) => (\n <th key={line.key} scope=\"col\">\n {line.label}\n </th>\n ))}\n {stacked && visible.length > 1 ? <th scope=\"col\">Total</th> : null}\n </tr>\n </thead>\n <tbody>\n {data.map((item) => (\n <tr key={item.key}>\n <th scope=\"row\">{item.label}</th>\n {visible.map((line) => (\n <td key={line.key}>{read(item, line)}</td>\n ))}\n {stacked && visible.length > 1 ? (\n <td>\n {formatValue(totalOf(item), visible[0]!)}\n {suffix}\n </td>\n ) : null}\n </tr>\n ))}\n </tbody>\n </table>\n </div>\n </figure>\n );\n});\n"],"mappings":"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"}
@@ -1,3 +1,4 @@
1
+ import { BarChartSeries, BarChartSeriesDatum, BarChartSeriesProps } from "./bar-chart-series.js";
1
2
  //#region src/bar-chart/bar-chart.d.ts
2
3
  /**
3
4
  * BarChart: one measure across a run of days, weeks or months, when people
@@ -14,6 +15,11 @@
14
15
  * Plain SVG and CSS; one small spring tween drives the bars, the zoom, the
15
16
  * scale, the average and the cursor. A visually hidden table carries every
16
17
  * value, and the plot is a slider.
18
+ *
19
+ * Pass `series` for the series mode instead: several measures per category,
20
+ * grouped or stacked, on a categorical axis in data order, upright or as
21
+ * horizontal rows, with a legend (see `BarChartSeriesProps`). Without
22
+ * `series` the chart is exactly the one described above.
17
23
  */
18
24
  export interface BarChartDatum {
19
25
  /** Stable identity, such as an ISO date. A bar whose key survives a data change keeps its place. */
@@ -45,7 +51,25 @@ export interface BarChartProps {
45
51
  formatValue?: (value: number) => string;
46
52
  /** Extra classes for the root. Merged last. */
47
53
  className?: string;
54
+ /** Not used in this mode: passing `series` switches to the series mode (`BarChartSeriesProps`). */
55
+ series?: undefined;
48
56
  }
49
- export declare const BarChart: import("react").ForwardRefExoticComponent<BarChartProps & import("react").RefAttributes<HTMLElement>>;
57
+ /**
58
+ * One measure across a run of periods (`BarChartProps`), or, with `series`,
59
+ * several measures per category, grouped or stacked, upright or horizontal
60
+ * (`BarChartSeriesProps`).
61
+ *
62
+ * @example
63
+ * <BarChart label="Active minutes" period="Sep 15–21, 2026" data={week} />
64
+ * <BarChart
65
+ * label="Spend by campaign"
66
+ * series={[{ key: "search", label: "Search" }, { key: "social", label: "Social" }]}
67
+ * layout="stacked"
68
+ * orientation="horizontal"
69
+ * data={campaigns}
70
+ * />
71
+ */
72
+ export declare const BarChart: import("react").ForwardRefExoticComponent<(BarChartProps | BarChartSeriesProps) & import("react").RefAttributes<HTMLElement>>;
50
73
  //#endregion
74
+ export type { BarChartSeries, BarChartSeriesDatum, BarChartSeriesProps };
51
75
  //# sourceMappingURL=bar-chart.d.ts.map
@@ -4,6 +4,7 @@ import { mergeRefs } from "../lib/merge-refs.js";
4
4
  import { prefersReducedMotion, useIsomorphicLayoutEffect } from "../lib/motion.js";
5
5
  import { SwapText } from "../lib/swap-text.js";
6
6
  import { MORPH, SMOOTH, SNAPPY, live, retarget } from "../lib/spring-tween.js";
7
+ import { SeriesBarChart } from "./bar-chart-series.js";
7
8
  import { forwardRef, useCallback, useEffect, useId, useMemo, useRef, useState } from "react";
8
9
  import { jsx, jsxs } from "react/jsx-runtime";
9
10
  //#region src/bar-chart/bar-chart.tsx
@@ -108,7 +109,7 @@ function fittingLabels(data, width, sizes) {
108
109
  }
109
110
  return fitting;
110
111
  }
111
- const BarChart = forwardRef(function BarChart({ data, label, period, unit = "", averageLabel = "Daily average", valueLabel = "Total", categoryLabel = "Day", showAverage = true, height = 176, formatValue = (value) => GROUPED.format(value), className }, ref) {
112
+ const TimeBarChart = forwardRef(function TimeBarChart({ data, label, period, unit = "", averageLabel = "Daily average", valueLabel = "Total", categoryLabel = "Day", showAverage = true, height = 176, formatValue = (value) => GROUPED.format(value), className }, ref) {
112
113
  const figure = useRef(null);
113
114
  const refs = useMemo(() => mergeRefs(ref, figure), [ref]);
114
115
  const plot = useRef(null);
@@ -559,6 +560,30 @@ const BarChart = forwardRef(function BarChart({ data, label, period, unit = "",
559
560
  ]
560
561
  });
561
562
  });
563
+ /**
564
+ * One measure across a run of periods (`BarChartProps`), or, with `series`,
565
+ * several measures per category, grouped or stacked, upright or horizontal
566
+ * (`BarChartSeriesProps`).
567
+ *
568
+ * @example
569
+ * <BarChart label="Active minutes" period="Sep 15–21, 2026" data={week} />
570
+ * <BarChart
571
+ * label="Spend by campaign"
572
+ * series={[{ key: "search", label: "Search" }, { key: "social", label: "Social" }]}
573
+ * layout="stacked"
574
+ * orientation="horizontal"
575
+ * data={campaigns}
576
+ * />
577
+ */
578
+ const BarChart = forwardRef(function BarChart(props, ref) {
579
+ return props.series === void 0 ? /* @__PURE__ */ jsx(TimeBarChart, {
580
+ ref,
581
+ ...props
582
+ }) : /* @__PURE__ */ jsx(SeriesBarChart, {
583
+ ref,
584
+ ...props
585
+ });
586
+ });
562
587
  //#endregion
563
588
  export { BarChart };
564
589