@seekalfred/primitives 0.7.3 → 0.8.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 +315 -4
- package/dist/alert/alert.d.ts +2 -2
- package/dist/alert/alert.js +1 -1
- package/dist/alert/alert.js.map +1 -1
- package/dist/alert-dialog/alert-dialog.d.ts +14 -0
- package/dist/alert-dialog/alert-dialog.js +52 -27
- package/dist/alert-dialog/alert-dialog.js.map +1 -1
- package/dist/announcement-bar/announcement-bar.d.ts +15 -4
- package/dist/announcement-bar/announcement-bar.js +31 -6
- package/dist/announcement-bar/announcement-bar.js.map +1 -1
- package/dist/avatar/avatar.d.ts +7 -0
- package/dist/avatar/avatar.js +33 -12
- package/dist/avatar/avatar.js.map +1 -1
- package/dist/badge/badge.d.ts +16 -1
- package/dist/badge/badge.js +12 -5
- package/dist/badge/badge.js.map +1 -1
- package/dist/bar-chart/bar-chart-series.d.ts +75 -0
- package/dist/bar-chart/bar-chart-series.js +401 -0
- package/dist/bar-chart/bar-chart-series.js.map +1 -0
- package/dist/bar-chart/bar-chart.d.ts +25 -1
- package/dist/bar-chart/bar-chart.js +26 -1
- package/dist/bar-chart/bar-chart.js.map +1 -1
- package/dist/bar-chart/index.d.ts +2 -1
- package/dist/button/button.d.ts +24 -2
- package/dist/button/button.js +62 -13
- package/dist/button/button.js.map +1 -1
- package/dist/card/card.js +1 -1
- package/dist/card/card.js.map +1 -1
- package/dist/checkbox/checkbox.d.ts +25 -1
- package/dist/checkbox/checkbox.js +103 -28
- package/dist/checkbox/checkbox.js.map +1 -1
- package/dist/checkbox/index.d.ts +2 -2
- package/dist/checkbox/index.js +2 -2
- package/dist/chip-group/chip-group.d.ts +11 -0
- package/dist/chip-group/chip-group.js +50 -34
- package/dist/chip-group/chip-group.js.map +1 -1
- package/dist/chip-group/index.d.ts +2 -2
- package/dist/code-block/code-block.d.ts +45 -0
- package/dist/code-block/code-block.js +74 -0
- package/dist/code-block/code-block.js.map +1 -0
- package/dist/code-block/index.d.ts +2 -0
- package/dist/code-block/index.js +2 -0
- package/dist/command-palette/command-palette.d.ts +128 -0
- package/dist/command-palette/command-palette.js +371 -0
- package/dist/command-palette/command-palette.js.map +1 -0
- package/dist/command-palette/index.d.ts +2 -0
- package/dist/command-palette/index.js +2 -0
- package/dist/copy-button/copy-button.d.ts +19 -3
- package/dist/copy-button/copy-button.js +7 -4
- package/dist/copy-button/copy-button.js.map +1 -1
- package/dist/dialog/dialog.js +1 -1
- package/dist/dialog/dialog.js.map +1 -1
- package/dist/empty-state/empty-state.d.ts +17 -0
- package/dist/empty-state/empty-state.js +9 -7
- package/dist/empty-state/empty-state.js.map +1 -1
- package/dist/file-drop-zone/file-drop-zone.d.ts +29 -3
- package/dist/file-drop-zone/file-drop-zone.js +26 -8
- package/dist/file-drop-zone/file-drop-zone.js.map +1 -1
- package/dist/gauge/gauge.d.ts +18 -1
- package/dist/gauge/gauge.js +35 -21
- package/dist/gauge/gauge.js.map +1 -1
- package/dist/gauge/index.d.ts +2 -2
- package/dist/index.d.ts +14 -9
- package/dist/index.js +14 -10
- package/dist/info-tooltip/index.d.ts +2 -0
- package/dist/info-tooltip/index.js +2 -0
- package/dist/info-tooltip/info-tooltip.d.ts +35 -0
- package/dist/info-tooltip/info-tooltip.js +49 -0
- package/dist/info-tooltip/info-tooltip.js.map +1 -0
- package/dist/input/input.d.ts +7 -0
- package/dist/input/input.js +4 -2
- package/dist/input/input.js.map +1 -1
- package/dist/lib/field-shell.js +2 -6
- package/dist/lib/field-shell.js.map +1 -1
- package/dist/lib/required-marker.js +20 -0
- package/dist/lib/required-marker.js.map +1 -0
- package/dist/lib/selection-control.js +32 -1
- package/dist/lib/selection-control.js.map +1 -1
- package/dist/line-chart/index.d.ts +2 -2
- package/dist/line-chart/line-chart.d.ts +106 -3
- package/dist/line-chart/line-chart.js +185 -46
- package/dist/line-chart/line-chart.js.map +1 -1
- package/dist/mention-input/mention-input.js +1 -1
- package/dist/money-input/index.d.ts +2 -2
- package/dist/money-input/money-input.d.ts +14 -0
- package/dist/money-input/money-input.js +17 -7
- package/dist/money-input/money-input.js.map +1 -1
- package/dist/morph-select/morph-select.d.ts +8 -1
- package/dist/morph-select/morph-select.js +8 -5
- package/dist/morph-select/morph-select.js.map +1 -1
- package/dist/multi-select/multi-select.d.ts +31 -0
- package/dist/multi-select/multi-select.js +123 -6
- package/dist/multi-select/multi-select.js.map +1 -1
- package/dist/number-field/number-field.js +1 -1
- package/dist/password-field/password-field.js +1 -1
- package/dist/password-strength/password-strength.js +1 -1
- package/dist/phone-input/phone-input.js +1 -1
- package/dist/popover/popover.js +1 -1
- package/dist/popover/popover.js.map +1 -1
- package/dist/progress/index.d.ts +2 -2
- package/dist/progress/index.js +2 -2
- package/dist/progress/progress.d.ts +53 -2
- package/dist/progress/progress.js +146 -36
- package/dist/progress/progress.js.map +1 -1
- package/dist/radio-group/radio-group.d.ts +12 -3
- package/dist/radio-group/radio-group.js +62 -52
- package/dist/radio-group/radio-group.js.map +1 -1
- package/dist/rich-text-editor/rich-text-editor.js +1 -1
- package/dist/scroll-area/scroll-area.d.ts +1 -1
- package/dist/scrub-input/scrub-input.d.ts +11 -1
- package/dist/scrub-input/scrub-input.js +22 -10
- package/dist/scrub-input/scrub-input.js.map +1 -1
- package/dist/search-field/search-field.js +1 -1
- package/dist/select/select.d.ts +10 -1
- package/dist/select/select.js +4 -3
- package/dist/select/select.js.map +1 -1
- package/dist/separator/separator.d.ts +1 -1
- package/dist/shortcut-recorder/shortcut-recorder.js +1 -1
- package/dist/sparkline/sparkline.d.ts +27 -2
- package/dist/sparkline/sparkline.js +115 -18
- package/dist/sparkline/sparkline.js.map +1 -1
- package/dist/stat-card/index.d.ts +2 -2
- package/dist/stat-card/index.js +2 -2
- package/dist/stat-card/stat-card.d.ts +32 -1
- package/dist/stat-card/stat-card.js +52 -9
- package/dist/stat-card/stat-card.js.map +1 -1
- package/dist/styles.css +1 -1
- package/dist/table/index.d.ts +2 -2
- package/dist/table/index.js +2 -2
- package/dist/table/table.d.ts +211 -3
- package/dist/table/table.js +473 -93
- package/dist/table/table.js.map +1 -1
- package/dist/tabs/tabs.d.ts +4 -2
- package/dist/tabs/tabs.js +7 -5
- package/dist/tabs/tabs.js.map +1 -1
- package/dist/tag-input/tag-input.js +1 -1
- package/dist/text-shimmer/text-shimmer.d.ts +18 -2
- package/dist/text-shimmer/text-shimmer.js +5 -2
- package/dist/text-shimmer/text-shimmer.js.map +1 -1
- package/dist/textarea/textarea.d.ts +7 -0
- package/dist/textarea/textarea.js +4 -2
- package/dist/textarea/textarea.js.map +1 -1
- package/dist/toast/toast.d.ts +2 -2
- package/dist/toggle-button/index.d.ts +2 -0
- package/dist/toggle-button/index.js +2 -0
- package/dist/toggle-button/toggle-button.d.ts +93 -0
- package/dist/toggle-button/toggle-button.js +199 -0
- package/dist/toggle-button/toggle-button.js.map +1 -0
- package/package.json +19 -3
|
@@ -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":";;;;;;;;AA8FA,MAAM,MAAM;AACZ,MAAM,OAAO;AACb,MAAM,UAAU;AAChB,MAAM,YAAY;AAClB,MAAM,SAAS;AACf,MAAM,MAAM;;AAEZ,MAAM,aAAa;AACnB,MAAM,iBAAiB;AACvB,MAAM,UAAU;CAAC;CAAI;CAAI;AAAE;AAC3B,MAAM,UAAU,IAAI,KAAK,aAAa,SAAS,EAAE,uBAAuB,EAAE,CAAC;AAC3E,MAAM,UAAU,IAAI,KAAK,aAAa,SAAS;CAAE,UAAU;CAAW,uBAAuB;AAAE,CAAC;AAChG,MAAM,SAAS,OAAe,KAAa,SAAiB,KAAK,IAAI,MAAM,KAAK,IAAI,KAAK,KAAK,CAAC;AAE/F,MAAM,WAAW,MAAsB,UACrC,KAAK,UACJ,QAAQ,IACL,qBAAqB,QAAQ,EAAE,KAC/B,+CAA+C,SAAS,QAAQ,KAAK,QAAQ,QAAQ;;AAG3F,MAAM,YAAY,UAChB,OAAO,UAAU,YAAY,OAAO,SAAS,KAAK,IAAI,QAAQ;;AAGhE,SAAS,SAAS,KAAa;CAC7B,MAAM,OAAO,KAAK,IAAI,KAAK,CAAC;CAC5B,MAAM,YAAY,MAAM,KAAK,MAAM,KAAK,MAAM,OAAO,CAAC,CAAC;CACvD,KAAK,MAAM,UAAU;EAAC;EAAG;EAAG;EAAG;EAAG;CAAE,GAAG;EACrC,MAAM,OAAO,SAAS;EACtB,MAAM,OAAO,KAAK,KAAK,OAAO,IAAI;EAClC,IAAI,QAAQ,GACV,OAAO;GAAE,KAAK,OAAO;GAAM,OAAO,MAAM,KAAK,EAAE,QAAQ,OAAO,EAAE,IAAI,GAAG,QAAQ,MAAM,IAAI;EAAE;CAC/F;CACA,OAAO;EAAE,KAAK;EAAM,OAAO,CAAC,GAAG,IAAI;CAAE;AACvC;;;;;;AAOA,SAAS,QACP,UACA,OACA,MACA,MACA,IACA,OACA,MACA;CACA,MAAM,KAAK,UAAkB,MAAM,QAAQ,CAAC;CAC5C,MAAM,SAAS,KAAK;CACpB,IAAI,QAAQ,KAAK,UAAU,KAAM,OAAO;CACxC,MAAM,IAAI,QAAQ,KAAK,IAAI,QAAQ,OAAO,GAAG,MAAM,IAAI;CACvD,IAAI,UAAU;EACZ,MAAM,SAAS,OAAO;EACtB,MAAM,MAAM,OAAO;EACnB,MAAM,IAAI;EACV,OAAO,IAAI,EAAE,CAAC,EAAE,GAAG,EAAE,MAAM,EAAE,GAAG,EAAE,MAAM,CAAC,EAAE,GAAG,EAAE,CAAC,EAAE,GAAG,EAAE,CAAC,EAAE,SAAS,EAAE,IAAI,CAAC,EAAE,GAAG,EAAE,GAAG,EAAE,GAAG,EAAE,IAAI,OAAO,CAAC,EAAE,GAAG,EAAE,CAAC,EAAE,GAAG,EAAE,CAAC,EAAE,SAAS,EAAE,IAAI,IAAI,EAAE,GAAG,EAAE,MAAM,CAAC,EAAE,GAAG,EAAE,MAAM,EAAE;CAC5K;CACA,MAAM,IAAI;CACV,OAAO,IAAI,EAAE,IAAI,EAAE,GAAG,EAAE,CAAC,EAAE,GAAG,EAAE,KAAK,CAAC,EAAE,GAAG,EAAE,CAAC,EAAE,GAAG,EAAE,CAAC,EAAE,SAAS,EAAE,EAAE,EAAE,GAAG,EAAE,IAAI,CAAC,EAAE,GAAG,EAAE,IAAI,OAAO,CAAC,EAAE,GAAG,EAAE,CAAC,EAAE,GAAG,EAAE,CAAC,EAAE,SAAS,EAAE,KAAK,CAAC,EAAE,GAAG,EAAE,IAAI,IAAI,EAAE,GAAG,EAAE,IAAI,EAAE;AACrK;AAEA,MAAa,iBAAiB,WAA6C,SAAS,eAClF,EACE,MACA,QACA,OACA,QACA,SAAS,WACT,cAAc,YACd,OAAO,IACP,QAAQ,YACR,eAAe,UAAU,QAAQ,OAAO,KAAK,GAC7C,cAAc,UAAU,QAAQ,OAAO,KAAK,GAC5C,gBAAgB,YAChB,eAAe,WACf,QACA,cACA,sBAAsB,CAAC,GACvB,sBACA,aAEF,KACA;CACA,MAAM,SAAS,OAA2B,IAAI;CAC9C,MAAM,OAAO,cAAc,UAAU,KAAK,MAAM,GAAG,CAAC,GAAG,CAAC;CACxD,MAAM,OAAO,OAAuB,IAAI;CACxC,MAAM,UAAU,MAAM;CACtB,MAAM,WAAW,gBAAgB;CACjC,MAAM,UAAU,WAAW;CAC3B,MAAM,SAAS,eAAe,WAAW,MAAM,KAAK,IAAI,GAAG,KAAK,MAAM,IAAI;CAC1E,MAAM,SAAS,OAAO,IAAI,SAAS;CACnC,MAAM,QAAQ,KAAK,IAAI,KAAK,QAAQ,CAAC;CACrC,MAAM,OAAO,KAAK,SAAS;CAE3B,MAAM,CAAC,WAAW,gBAAgB,SAAS,mBAAmB;CAC9D,MAAM,SAAS,gBAAgB;CAC/B,MAAM,UAAU,QAAgB;EAC9B,MAAM,OAAO,OAAO,SAAS,GAAG,IAAI,OAAO,QAAQ,SAAS,SAAS,GAAG,IAAI,CAAC,GAAG,QAAQ,GAAG;EAC3F,IAAI,iBAAiB,KAAA,GAAW,aAAa,IAAI;EACjD,uBAAuB,IAAI;CAC7B;CACA,MAAM,UAAU,OAAO,QAAQ,SAAS,CAAC,OAAO,SAAS,KAAK,GAAG,CAAC;CAClE,MAAM,aAAa,UAAU,OAAO,SAAS;CAG7C,MAAM,OAAO,KAAK,QAAQ,KAAK,SAAS;EACtC,MAAM,SAAS,QAAQ,KAAK,SAAS,KAAK,IAAI,GAAG,SAAS,KAAK,OAAO,KAAK,IAAI,KAAK,CAAC,CAAC;EACtF,OAAO,KAAK,IACV,KACA,UAAU,OAAO,QAAQ,KAAK,UAAU,MAAM,OAAO,CAAC,IAAI,KAAK,IAAI,GAAG,GAAG,MAAM,CACjF;CACF,GAAG,CAAC;CACJ,MAAM,EAAE,KAAK,UAAU,cAAc,SAAS,IAAI,GAAG,CAAC,IAAI,CAAC;CAE3D,MAAM,CAAC,QAAQ,aAAa,SAAwB,IAAI;CACxD,MAAM,QAAQ,WAAW,OAAO,OAAO,KAAK,IAAI,QAAQ,IAAI;CAC5D,MAAM,YAAY,UAAU,QAAQ,QAAQ;CAG5C,MAAM,CAAC,OAAO,YAAY,SAAS,CAAC;CACpC,gCAAgC;EAC9B,MAAM,OAAO,KAAK;EAClB,IAAI,CAAC,MAAM;EACX,MAAM,aAAa,SAAS,KAAK,WAAW;EAC5C,KAAK;EACL,IAAI,OAAO,mBAAmB,aAAa;EAC3C,MAAM,WAAW,IAAI,eAAe,IAAI;EACxC,SAAS,QAAQ,IAAI;EACrB,aAAa,SAAS,WAAW;CACnC,GAAG,CAAC,CAAC;CAGL,MAAM,CAAC,OAAO,YAAY,SAAS,KAAK;CACxC,gBAAgB;EACd,MAAM,OAAO,OAAO;EACpB,IAAI,CAAC,QAAQ,qBAAqB,KAAK,OAAO,yBAAyB,aAAa;GAClF,SAAS,IAAI;GACb;EACF;EACA,MAAM,WAAW,IAAI,sBAClB,CAAC,WAAW;GACX,IAAI,CAAC,OAAO,gBAAgB;GAC5B,SAAS,WAAW;GACpB,SAAS,IAAI;EACf,GACA,EAAE,WAAW,IAAK,CACpB;EACA,SAAS,QAAQ,IAAI;EACrB,aAAa,SAAS,WAAW;CACnC,GAAG,CAAC,CAAC;CAGL,MAAM,QAAQ,WAAW,QAAQ;CACjC,MAAM,SAAS,KAAK,IAAI,GAAG,WAAW,SAAS,MAAM,QAAQ,GAAG;CAChE,MAAM,OAAO,QAAQ;CACrB,MAAM,YAAY,KAAK,IAAI,OAAO,OAAO,UAAU,IAAI,KAAK,IAAI,GAAG,QAAQ,MAAM,KAAK,OAAO;CAC7F,MAAM,UAAU,UACZ,YACA,KAAK,IAAI,IAAI,YAAY,aAAa,QAAQ,SAAS,MAAM,KAAK,IAAI,GAAG,QAAQ,MAAM,CAAC;CAC5F,MAAM,QAAQ,UAAmB,SAAS,OAAO,KAAM;CACvD,MAAM,OAAO,KAAK,IAAI,YAAY,iBAAiB,KAAK;CAExD,MAAM,OAAO,KAAK,SAAS,MAAM,OAAO;EACtC,MAAM,aAAa,KAAK,QAAQ,OAAO,aAAa;EACpD,IAAI,QAAQ;EACZ,MAAM,SAAS,OAAO,KAAK,UAAU;GAAE;GAAM,OAAO,SAAS,KAAK,OAAO,KAAK,IAAI;EAAE,EAAE;EAEtF,MAAM,YAAY,CAAC,GAAG,MAAM,CAAC,CAC1B,QAAQ,CAAC,CACT,MAAM,EAAE,MAAM,YAAY,CAAC,OAAO,SAAS,KAAK,GAAG,MAAM,SAAS,KAAK,CAAC,CAAC,EAAE,KAAK;EACnF,OAAO,OAAO,SAAS,EAAE,MAAM,SAAS,aAAa;GACnD,IAAI,OAAO,SAAS,KAAK,GAAG,KAAK,UAAU,QAAQ,SAAS,KAAK,CAAC,OAAO,OAAO,CAAC;GACjF,MAAM,QAAQ,QAAQ,QAAQ,IAAI;GAClC,MAAM,QAAQ,UAAU,aAAa,aAAa,SAAS,UAAU;GACrE,MAAM,OAAO,UAAU,KAAK,KAAK,IAAI;GACrC,SAAS;GACT,MAAM,KAAK,UAAU,KAAK,KAAK,IAAI,KAAK,KAAK;GAC7C,MAAM,IAAI,QACR,UACA,OACA,SACA,MACA,IACA,CAAC,WAAW,KAAK,QAAQ,WACzB,MACF;GACA,OAAO,IACH,CACE;IACE,KAAK,GAAG,KAAK,IAAI,GAAG,KAAK;IACzB,UAAU,KAAK;IACf,QAAQ,KAAK;IACb;IACA,OAAO,QAAQ,MAAM,QAAQ;IAC7B;GACF,CACF,IACA,CAAC;EACP,CAAC;CACH,CAAC;CAED,MAAM,WAAW,SAAiB,YAAoB;EACpD,MAAM,OAAO,KAAK,SAAS,sBAAsB;EACjD,IAAI,CAAC,MAAM,OAAO;EAClB,MAAM,SAAS,WAAW,UAAU,KAAK,OAAO,UAAU,KAAK;EAC/D,MAAM,OAAO,WAAW,KAAK,QAAQ,KAAK;EAC1C,IAAI,CAAC,MAAM,OAAO;EAElB,MAAM,MAAM,YAAY,KAAK,WAAW,iBAAiB,KAAK,OAAO,CAAC,CAAC,cAAc;EACrF,MAAM,KAAK,KAAK,OAAQ,MAAM,OAAO,SAAS,UAAU,OAAQ,KAAK;EACrE,OAAO,MAAM,IAAI,GAAG,IAAI;CAC1B;CACA,MAAM,aAAa,UAAyC;EAC1D,IAAI,MAAM,QAAQ,YAAY,WAAW;GACvC,MAAM,eAAe;GACrB,UAAU,IAAI;GACd;EACF;EACA,MAAM,OAAO,SAAS;EACtB,MAAM,OAAO,KAAK,IAAI,GAAG,KAAK;EAC9B,MAAM,OACJ;GACE,WAAW,OAAO;GAClB,SAAS,OAAO;GAChB,YAAY,UAAU,OAAO,IAAI,OAAO;GACxC,WAAW,UAAU,OAAO,IAAI,OAAO;GACvC,QAAQ,OAAO;GACf,UAAU,OAAO;GACjB,MAAM;GACN,KAAK;EACP,EACA,MAAM;EACR,IAAI,SAAS,KAAA,KAAa,OAAO,GAAG;EACpC,MAAM,eAAe;EACrB,UAAU,MAAM,MAAM,GAAG,IAAI,CAAC;CAChC;CAEA,MAAM,QAAQ,MAA2B,SAAyB;EAChE,MAAM,QAAQ,SAAS,KAAK,OAAO,KAAK,IAAI;EAC5C,OAAO,UAAU,OAAO,eAAe,GAAG,YAAY,OAAO,IAAI,IAAI;CACvE;CACA,MAAM,WAAW,SACf,QAAQ,QAAQ,KAAK,SAAS,OAAO,SAAS,KAAK,OAAO,KAAK,IAAI,KAAK,IAAI,CAAC;CAC/E,MAAM,UAAU,YAAY,KAAK,SAAU;CAC3C,MAAM,YAAY,UACd,GAAG,QAAQ,MAAM,IAAI,QAAQ,KAAK,SAAS,GAAG,KAAK,MAAM,GAAG,KAAK,SAAS,IAAI,GAAG,CAAC,CAAC,KAAK,IAAI,MAC5F,KAAK,SACH,GAAG,KAAK,OAAO,GAAG,cAAc,YAAY,MAC5C;CACN,MAAM,OAAO,SAAS,GAAG,MAAM,IAAI,WAAW;CAC9C,MAAM,CAAC,UAAU,aAAyD,WACtE,CACE,qCACC,WAAW,EAAE,WAAW,KAAK,SAAS,KAAK,KAAK,EAAE,IAAI,EACzD,IACA,CAAC,qCAAqC,WAAW,EAAE,kBAAkB,GAAG,KAAK,KAAK,EAAE,IAAI,EAAE;CAE9F,OACE,qBAAC,UAAD;EACE,KAAK;EACL,aAAU;EACV,eAAa;EACb,oBAAkB;EAClB,mBAAiB;EACjB,WAAW,GACT,6EACA,SACF;EATF,UAAA;GAWE,oBAAC,cAAD;IAAY,IAAI;IAAS,WAAU;IAChC,UAAA;GACS,CAAA;GACX,aACC,oBAAC,OAAD;IACE,MAAK;IACL,cAAY,GAAG,MAAM;IACrB,WAAU;IAET,UAAA,OAAO,KAAK,MAAM,OACjB,qBAAC,UAAD;KAEE,MAAK;KACL,aAAU;KACV,gBAAc,CAAC,OAAO,SAAS,KAAK,GAAG;KACvC,eAAe,OAAO,KAAK,GAAG;KAC9B,OAAO,EAAE,YAAY,QAAQ,MAAM,EAAE,EAAE;KACvC,WAAU;KAPZ,UAAA;MASE,oBAAC,QAAD;OAAM,eAAY;OAAO,WAAU;MAAoB,CAAA;MACvD,oBAAC,QAAD;OAAM,WAAU;OAAsB,UAAA,KAAK;MAAY,CAAA;MACtD,WAAW,CAAC,OAAO,SAAS,KAAK,GAAG,IACnC,oBAAC,QAAD;OACE,aAAU;OACV,eAAY;OACZ,WAAU;OAET,UAAA,KAAK,SAAS,IAAI;MACf,CAAA,IACJ;KACE;IAnBD,GAAA,KAAK,GAmBJ,CACT;GACE,CAAA,IACH;GACJ,qBAAC,OAAD;IACE,aAAU;IACV,kBAAgB,aAAa,KAAA;IAC7B,cAAY,SAAS,KAAA;IACrB,WAAW,WAAW,oBAAoB;IAJ5C,UAAA;KAOE,oBAAC,OAAD;MACE,eAAY;MACZ,aAAU;MACV,WAAW,GACT,oBACA,WAAW,oCAAoC,iBACjD;MAEC,UAAA,KAAK,KAAK,MAAM,OACf,oBAAC,QAAD;OAEE,iBAAe,KAAK;OACpB,eAAc,aAAa,UAAU,MAAO,KAAA;OAC5C,WAAU;OACV,OACE,WACI;QAAE,kBAAkB,GAAG,KAAK,KAAK;QAAK,OAAO,GAAG,KAAK;OAAI,IACzD,EAAE,QAAQ,GAAG,KAAK,IAAI;OAG5B,UAAA,oBAAC,QAAD;QAAM,WAAU;QAAY,UAAA,KAAK,aAAa,KAAK;OAAY,CAAA;MAC3D,GAXC,KAAK,GAWN,CACP;KACE,CAAA;KACL,qBAAC,OAAD;MACE,KAAK;MACL,WAAW,GAAG,oBAAoB,WAAW,oBAAoB,iBAAiB;MAClF,OAAO,EAAE,OAAO;MAHlB,UAAA,CAME,qBAAC,OAAD;OACE,OAAM;OACE;OACR,eAAY;OACZ,WAAU;OACV,WAAU;OALZ,UAAA;QAOG,MACE,MAAM,CAAC,CAAC,CACR,KAAK,UACJ,WACE,oBAAC,QAAD;SAEE,WAAU;SACV,IAAI;SACJ,IAAG;SACH,IAAI,KAAK,MAAM,SAAS,KAAK,KAAK,CAAC,IAAI;SACvC,IAAI,KAAK,MAAM,SAAS,KAAK,KAAK,CAAC,IAAI;QACxC,GANM,KAMN,IAED,oBAAC,QAAD;SAEE,WAAU;SACV,IAAI;SACJ,IAAG;SACH,IAAI,KAAK,MAAM,KAAK,KAAK,CAAC,IAAI;SAC9B,IAAI,KAAK,MAAM,KAAK,KAAK,CAAC,IAAI;QAC/B,GANM,KAMN,CAEL;QACD,KAAK,KAAK,SACT,oBAAC,QAAD;SAEE,aAAU;SACV,iBAAe,KAAK;SACpB,eAAa,KAAK;SAClB,eAAc,aAAa,UAAU,KAAK,MAAO,KAAA;SACjD,GAAG,KAAK;SACR,WAAU;SACV,OACE;UACE,YAAY,KAAK;UAEjB,iBAAiB,WAAW,KAAK,OAAO,MAAM;UAC9C,iBAAiB,QAAQ,OAAO,KAAK,KAAK,KAAK,MAAM,KAAA;SACvD;QAEH,GAfM,KAAK,GAeX,CACF;QACA,WACC,oBAAC,QAAD;SACE,WAAU;SACV,IAAI;SACJ,IAAG;SACH,IAAI,SAAS;SACb,IAAI,SAAS;QACd,CAAA,IAED,oBAAC,QAAD;SAAM,WAAU;SAAsB,IAAI;SAAG,IAAG;SAAO,IAAI;SAAK,IAAI;QAAM,CAAA;OAEzE;MAEL,CAAA,GAAA,oBAAC,OAAD;OACE,aAAU;OACV,MAAK;OACL,UAAU,KAAK,SAAS,IAAI;OAC5B,cAAY,GAAG,MAAM,eAAe,cAAc,YAAY;OAC9D,oBAAkB,WAAW,eAAe;OAC5C,iBAAe;OACf,iBAAe,KAAK,IAAI,GAAG,KAAK,MAAM;OACtC,kBAAgB,SAAS,KAAK;OAC9B,kBAAgB;OAChB,gBAAgB,UAAwC;QACtD,IAAI,MAAM,gBAAgB,SACxB,MAAM,cAAc,oBAAoB,MAAM,SAAS;QACzD,UAAU,QAAQ,MAAM,SAAS,MAAM,OAAO,CAAC;OACjD;OACA,gBAAgB,UAAwC;QACtD,IAAI,MAAM,gBAAgB,WAAW,MAAM,SACzC,UAAU,QAAQ,MAAM,SAAS,MAAM,OAAO,CAAC;OACnD;OACA,cAAc,UAAwC;QACpD,IAAI,MAAM,gBAAgB,SAAS,UAAU,IAAI;OACnD;OACA,uBAAuB,UAAU,IAAI;OACrC,iBAAiB,UAAwC;QACvD,IAAI,MAAM,gBAAgB,SAAS,UAAU,IAAI;OACnD;OACW;OACX,cAAc,UAAU,IAAI;OAC5B,UAAU,UAAU;QAClB,IAAI,MAAM,cAAc,QAAQ,gBAAgB,KAAK,QAAQ,GAC3D,WAAW,YAAY,WAAW,CAAC;OACvC;OACA,WAAU;MACX,CAAA,CACE;;KACL,oBAAC,OAAD;MAAK,eAAY;MAAO,aAAU;MAAkB,WAAW;MAC5D,UAAA,MAAM,KAAK,UACV,oBAAC,QAAD;OAEE,aAAW;OACX,WAAW,WAAW,oBAAoB;OAC1C,OAAO,UAAU,KAAK;OAEtB,UAAA,oBAAC,QAAD;QACE,WAAW,GACT,iEACA,WAAW,qBAAqB,EAClC;QAEC,UAAA,WAAW,KAAK;OACb,CAAA;MACF,GAbC,KAaD,CACP;KACE,CAAA;IACF;;GACL,oBAAC,OAAD;IAAK,WAAU;IACb,UAAA,qBAAC,SAAD,EAAA,UAAA;KACE,oBAAC,WAAD,EAAA,UAAU,KAAc,CAAA;KACxB,oBAAC,SAAD,EAAA,UACE,qBAAC,MAAD,EAAA,UAAA;MACE,oBAAC,MAAD;OAAI,OAAM;OAAO,UAAA;MAAkB,CAAA;MAClC,QAAQ,KAAK,SACZ,oBAAC,MAAD;OAAmB,OAAM;OACtB,UAAA,KAAK;MACJ,GAFK,KAAK,GAEV,CACL;MACA,WAAW,QAAQ,SAAS,IAAI,oBAAC,MAAD;OAAI,OAAM;OAAM,UAAA;MAAS,CAAA,IAAI;KAC5D,EAAA,CAAA,EACC,CAAA;KACP,oBAAC,SAAD,EAAA,UACG,KAAK,KAAK,SACT,qBAAC,MAAD,EAAA,UAAA;MACE,oBAAC,MAAD;OAAI,OAAM;OAAO,UAAA,KAAK;MAAU,CAAA;MAC/B,QAAQ,KAAK,SACZ,oBAAC,MAAD,EAAA,UAAoB,KAAK,MAAM,IAAI,EAAM,GAAhC,KAAK,GAA2B,CAC1C;MACA,WAAW,QAAQ,SAAS,IAC3B,qBAAC,MAAD,EAAA,UAAA,CACG,YAAY,QAAQ,IAAI,GAAG,QAAQ,EAAG,GACtC,MACC,EAAA,CAAA,IACF;KACF,EAAA,GAXK,KAAK,GAWV,CACL,EACI,CAAA;IACF,EAAA,CAAA;GACJ,CAAA;EACC;;AAEZ,CAAC"}
|
|
@@ -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
|
-
|
|
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
|
|
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
|
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"bar-chart.js","names":[],"sources":["../../src/bar-chart/bar-chart.tsx"],"sourcesContent":["\"use client\";\n\nimport {\n forwardRef,\n useCallback,\n useEffect,\n useId,\n useMemo,\n useRef,\n useState,\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\";\nimport { live, MORPH, retarget, SMOOTH, SNAPPY, type Live, type Spring } from \"../lib/spring-tween.js\";\nimport { SwapText } from \"../lib/swap-text.js\";\n\n/**\n * BarChart: one measure across a run of days, weeks or months, when people\n * compare each period against the rest and against the average.\n *\n * The bars grow from the baseline the first time the chart is seen, each a beat\n * after its neighbour, and the dashed average rises with them. A new range zooms\n * the time axis around the latest bar (bars that stay glide to their new slot,\n * new ones grow outward from them, leaving ones sink into the baseline) while\n * the scale and the average slide to fit. Hover, drag or the arrow keys scrub:\n * the scrubbed bar takes the full colour while the rest step back, a cursor\n * glides to it, and the headline swaps from the average to that bar.\n *\n * Plain SVG and CSS; one small spring tween drives the bars, the zoom, the\n * scale, the average and the cursor. A visually hidden table carries every\n * value, and the plot is a slider.\n */\nexport interface BarChartDatum {\n /** Stable identity, such as an ISO date. A bar whose key survives a data change keeps its place. */\n key: string;\n /** Full label for the headline and screen readers, such as \"Tue, Sep 15\". */\n label: string;\n /** Short label under the bar, such as \"T\" or \"Sep 14\". Leave it out to keep the axis quiet. */\n axisLabel?: string;\n value: number;\n}\n\nexport interface BarChartProps {\n data: BarChartDatum[];\n /** What is measured, such as \"Active minutes\". Names the chart for assistive technology. */\n label: string;\n /** The range on show, such as \"Sep 15–21, 2026\". It rests under the headline. */\n period: string;\n /** Unit after each value, such as \"min\". */\n unit?: string;\n /** Headline label at rest, above the average. @default \"Daily average\" */\n averageLabel?: string;\n /** Headline label while a bar is scrubbed. @default \"Total\" */\n valueLabel?: string;\n /** Header of the first column in the data table read by screen readers. @default \"Day\" */\n categoryLabel?: string;\n /** Draws the average as a dashed reference line. @default true */\n showAverage?: boolean;\n /** Plot height in pixels. @default 176 */\n height?: number;\n formatValue?: (value: number) => string;\n /** Extra classes for the root. Merged last. */\n className?: string;\n}\n\n/** Room above the top gridline, the share of each slot a bar fills, its widest size, and the radius of its data end. */\nconst TOP = 12;\nconst FILL = 0.58;\nconst MAX_BAR = 28;\nconst RADIUS = 4;\n/** Stagger between bars on the first reveal (seconds in the source: .035 per bar, at most .36 in all). */\nconst STAGGER_MS = 35;\nconst GROUPED = new Intl.NumberFormat(\"en-US\", { maximumFractionDigits: 0 });\nconst clamp = (value: number, low: number, high: number) => Math.min(high, Math.max(low, value));\n/** visualDuration .24s, no bounce: a leaving bar sinks a little faster than a bar grows. */\nconst COLLAPSE: Spring = {\n curve: [\n 0, 0.0484, 0.1552, 0.2816, 0.4069, 0.5207, 0.6189, 0.7009, 0.7676, 0.821, 0.8631, 0.8959, 0.9213,\n 0.9408, 0.9556, 0.9668, 0.9753, 0.9816, 0.9864, 0.9899, 0.9926, 0.9945, 0.996, 0.9971, 0.9978,\n 0.9984, 0.9988, 0.9992, 0.9994, 1,\n ],\n ms: 464,\n};\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) return { top: rows * step, ticks: Array.from({ length: rows + 1 }, (_, row) => row * step) };\n }\n return { top: safe, ticks: [0, safe] };\n}\n\n/** A column that grows from a square baseline to a softly rounded data end. */\nfunction barPath(x: number, w: number, h: number, base: number) {\n const f = (value: number) => value.toFixed(2);\n if (w <= 0 || h <= 0.01) return `M${f(x)} ${base}H${f(x + Math.max(w, 0))}Z`;\n const r = Math.min(RADIUS, w / 2, h);\n const top = base - h;\n return `M${f(x)} ${base}V${f(top + r)}A${f(r)} ${f(r)} 0 0 1 ${f(x + r)} ${f(top)}H${f(x + w - r)}A${f(r)} ${f(r)} 0 0 1 ${f(x + w)} ${f(top + r)}V${base}Z`;\n}\n\n/** Axis labels that fit once the range has settled: every label, else every second, third and so on, counted back from the latest. */\nfunction fittingLabels(data: BarChartDatum[], width: number, sizes: Record<string, number>) {\n const fitting = new Map<string, number>();\n if (!width) return fitting;\n const count = Math.max(1, data.length);\n const labels = data\n .flatMap((item, index) => {\n const size = item.axisLabel ? sizes[item.axisLabel] : undefined;\n if (size === undefined) return [];\n const natural = width - (data.length - 1 - index + 0.5) * (width / count) - size / 2;\n return [{ key: item.key, size, natural, left: clamp(natural, 0, Math.max(0, width - size)) }];\n })\n .reverse();\n for (let stride = 1; stride <= labels.length; stride++) {\n const picked = labels.filter((_, rank) => rank % stride === 0);\n if (\n stride === labels.length ||\n picked.every((label, rank) => rank === 0 || label.left + label.size + 10 <= picked[rank - 1]!.left)\n ) {\n picked.forEach((label) => fitting.set(label.key, label.left - label.natural));\n break;\n }\n }\n return fitting;\n}\n\nexport const BarChart = forwardRef<HTMLElement, BarChartProps>(function BarChart(\n {\n data,\n label,\n period,\n unit = \"\",\n averageLabel = \"Daily average\",\n valueLabel = \"Total\",\n categoryLabel = \"Day\",\n showAverage = true,\n height = 176,\n formatValue = (value) => GROUPED.format(value),\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 svg = useRef<SVGSVGElement>(null);\n const gutter = useRef<HTMLDivElement>(null);\n const axis = useRef<HTMLDivElement>(null);\n const ruler = useRef<HTMLSpanElement>(null);\n const titleId = useId();\n const count = Math.max(data.length, 1);\n const last = data.length - 1;\n const average = data.length ? data.reduce((sum, item) => sum + item.value, 0) / data.length : 0;\n const peak = data.reduce((max, item) => Math.max(max, item.value), 0);\n const { top, ticks } = useMemo(() => scaleFor(peak), [peak]);\n const suffix = unit ? ` ${unit}` : \"\";\n\n // Bars that left stay in the DOM while they sink, then go.\n const [leaving, setLeaving] = useState<string[]>([]);\n const previous = useRef(data);\n const [changes, setChanges] = useState(0);\n const [active, setActive] = useState<number | null>(null);\n const signature = data.map((item) => item.key).join(\"|\");\n const [seen, setSeen] = useState(signature);\n if (seen !== signature) {\n setSeen(signature);\n setActive(null);\n setChanges((n) => n + 1);\n }\n const index = active === null ? null : Math.min(active, last);\n const scrubbing = index !== null && last >= 0;\n const shownValue = scrubbing ? data[index]!.value : average;\n const [trend, setTrend] = useState({ value: shownValue, index, valueWay: 1, indexWay: 1 });\n if (trend.value !== shownValue || trend.index !== index) {\n setTrend({\n value: shownValue,\n index,\n valueWay: shownValue === trend.value ? trend.valueWay : shownValue > trend.value ? 1 : -1,\n indexWay: index === null || trend.index === null ? 1 : Math.sign(index - trend.index) || 1,\n });\n }\n\n // Animated state, read only by the painter.\n const width = useRef(0);\n const share = useRef(live(1 / count));\n const scale = useRef(live(top));\n const mean = useRef(live(0));\n const cursor = useRef(live(0));\n const bars = useRef(new Map<string, { place: Live; amount: Live }>());\n const [shown, setShown] = useState(false);\n const [plotWidth, setPlotWidth] = useState(0);\n const [labelSizes, setLabelSizes] = useState<Record<string, number>>({});\n\n /** One writer for every drawn attribute, straight onto the elements. */\n const paint = useCallback(() => {\n const root = svg.current;\n const w = width.current;\n if (!root || !w) return;\n const s = scale.current.value || 1;\n const rowY = (value: number) => Math.round(height - (value / s) * (height - TOP)) + 0.5;\n const slot = w * share.current.value;\n const size = Math.min(slot * FILL, MAX_BAR);\n for (const [key, bar] of bars.current) {\n const node = root.querySelector(`[data-bar=\"${CSS.escape(key)}\"]`);\n const center = w - (bar.place.value + 0.5) * slot;\n node?.setAttribute(\"d\", barPath(center - size / 2, size, Math.max(0, (bar.amount.value / s) * (height - TOP)), height));\n }\n for (const node of root.querySelectorAll<SVGLineElement>(\"[data-grid]\")) {\n const y = String(rowY(Number(node.dataset.grid)));\n node.setAttribute(\"y1\", y);\n node.setAttribute(\"y2\", y);\n }\n const meanY = rowY(mean.current.value);\n const meanLine = root.querySelector(\"[data-part=mean]\");\n meanLine?.setAttribute(\"y1\", String(meanY));\n meanLine?.setAttribute(\"y2\", String(meanY));\n const cx = String(Math.round(w - (cursor.current.value + 0.5) * slot) + 0.5);\n const cross = root.querySelector(\"[data-part=cursor]\");\n cross?.setAttribute(\"x1\", cx);\n cross?.setAttribute(\"x2\", cx);\n // Tick labels ride the scale and make way where the average label sits beside them.\n for (const node of gutter.current?.querySelectorAll<HTMLElement>(\"[data-tick]\") ?? []) {\n const y = rowY(Number(node.dataset.tick));\n node.style.translate = `0 ${y}px`;\n node.style.opacity = showAverage ? String(clamp((Math.abs(y - meanY) - 10) / 6, 0, 1)) : \"1\";\n }\n const meanLabel = gutter.current?.querySelector<HTMLElement>(\"[data-part=mean-label]\");\n if (meanLabel) {\n meanLabel.style.translate = `0 ${meanY}px`;\n const text = meanLabel.querySelector(\"[data-part=mean-text]\");\n if (text) text.textContent = `Avg ${formatValue(Math.round(mean.current.value))}`;\n }\n // Axis labels are centred under their bar and carried by the zoom.\n for (const node of axis.current?.querySelectorAll<HTMLElement>(\"[data-axis]\") ?? []) {\n const place = bars.current.get(node.dataset.axis!)?.place.value ?? 0;\n node.style.translate = `${w - (place + 0.5) * slot - Number(node.dataset.size) / 2 + Number(node.dataset.shift)}px 0`;\n }\n }, [formatValue, height, showAverage]);\n\n const go = useCallback(\n (target: Live, to: number, spring: Spring, delay = 0, done?: () => void) =>\n retarget(target, to, spring, paint, delay, done),\n [paint],\n );\n\n // The chart draws in its own pixels: measure the width and every axis label once, follow resizes.\n const labelTexts = [...new Set(data.map((item) => item.axisLabel).filter((text): text is string => !!text))].join(\"\\n\");\n useIsomorphicLayoutEffect(() => {\n const node = plot.current;\n const measure = ruler.current;\n if (!node || !measure) return;\n const read = () => {\n width.current = node.clientWidth;\n setPlotWidth(node.clientWidth);\n const sizes: Record<string, number> = {};\n measure.querySelectorAll<HTMLElement>(\"[data-text]\").forEach((item) => {\n sizes[item.dataset.text ?? \"\"] = item.offsetWidth;\n });\n setLabelSizes((current) => (Object.keys(sizes).every((text) => current[text] === sizes[text]) ? current : sizes));\n paint();\n };\n read();\n if (typeof ResizeObserver === \"undefined\") return;\n const observer = new ResizeObserver(read);\n observer.observe(node);\n return () => observer.disconnect();\n }, [labelTexts, paint]);\n const fitting = useMemo(() => fittingLabels(data, plotWidth, labelSizes), [data, plotWidth, labelSizes]);\n useIsomorphicLayoutEffect(paint);\n\n // The bars grow once the chart is a third in view.\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 // Every bar to its slot and value. The first reveal runs left to right a beat apart; later, new bars grow outward from the ones that stayed and leaving ones sink.\n const firstReveal = useRef(true);\n useEffect(() => {\n if (!shown) return;\n const first = firstReveal.current;\n firstReveal.current = false;\n const known = new Set(previous.current.map((item) => item.key));\n previous.current = data;\n const incoming = data\n .map((item, at) => ({ key: item.key, place: last - at }))\n .filter((item) => first || !known.has(item.key))\n .sort((a, b) => (first ? b.place - a.place : a.place - b.place));\n const step = Math.min(STAGGER_MS, (first ? 360 : 320) / Math.max(1, incoming.length));\n const delayOf = new Map(incoming.map((item, rank) => [item.key, rank * step]));\n const keys = new Set(data.map((item) => item.key));\n data.forEach((item, at) => {\n const place = last - at;\n let bar = bars.current.get(item.key);\n if (!bar) {\n bar = { place: live(place), amount: live(0) };\n bars.current.set(item.key, bar);\n }\n go(bar.place, place, SMOOTH);\n const fresh = delayOf.has(item.key);\n go(bar.amount, item.value, fresh ? MORPH : SMOOTH, fresh ? delayOf.get(item.key)! : 0);\n });\n const gone = [...bars.current.keys()].filter((key) => !keys.has(key));\n if (gone.length) setLeaving((current) => [...new Set([...current, ...gone])]);\n for (const key of gone) {\n const bar = bars.current.get(key)!;\n go(bar.amount, 0, COLLAPSE, 0, () => {\n bars.current.delete(key);\n setLeaving((current) => current.filter((item) => item !== key));\n });\n }\n // The time axis zooms around the latest bar, and the scale slides to fit.\n go(share.current, 1 / count, SMOOTH);\n go(scale.current, top, SMOOTH);\n // The average rises with the first bars, a beat late, then springs to each new range.\n go(mean.current, average, SMOOTH, first ? 120 : 0);\n // `data` is captured by signature and values; the springs read the rest from refs.\n // eslint-disable-next-line react-hooks/exhaustive-deps\n }, [shown, signature, data.map((item) => item.value).join(\",\"), top, average, count]);\n\n // The cursor appears on the first scrubbed bar and glides between the ones after it.\n const wasScrubbing = useRef(false);\n useEffect(() => {\n if (index === null) {\n wasScrubbing.current = false;\n return;\n }\n const place = last - index;\n if (!wasScrubbing.current) {\n wasScrubbing.current = true;\n cursor.current.stop();\n cursor.current.value = place;\n paint();\n return;\n }\n go(cursor.current, place, SNAPPY);\n }, [go, index, last, paint]);\n\n const pointAt = (clientX: number) => {\n const rect = plot.current?.getBoundingClientRect();\n if (!rect?.width) return last;\n const place = Math.floor(((rect.right - clientX) / rect.width) * count);\n return clamp(last - place, 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 ?? last + 1;\n const page = Math.min(7, count);\n const next = (\n {\n ArrowLeft: from - 1,\n ArrowDown: from - 1,\n ArrowRight: index === null ? last : from + 1,\n ArrowUp: index === null ? last : from + 1,\n PageDown: from - page,\n PageUp: 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 scrubbed = scrubbing ? data[index]! : null;\n const reading = scrubbed ?? data[last];\n const valueText = reading ? `${reading.label}: ${formatValue(reading.value)}${suffix}` : \"No data\";\n const highest = data.reduce<BarChartDatum | null>((best, item) => (!best || item.value > best.value ? item : best), null);\n const lowest = data.reduce<BarChartDatum | null>((best, item) => (!best || item.value < best.value ? item : best), null);\n const summary = `${label}, ${period}. ${averageLabel} ${formatValue(Math.round(average))}${suffix}.${\n highest ? ` Highest ${highest.label}, ${formatValue(highest.value)}${suffix}.` : \"\"\n }${lowest && lowest !== highest ? ` Lowest ${lowest.label}, ${formatValue(lowest.value)}${suffix}.` : \"\"}`;\n const headline = formatValue(scrubbing ? data[index]!.value : Math.round(average));\n const barKeys = [...data.map((item) => item.key), ...leaving.filter((key) => !data.some((item) => item.key === key))];\n\n return (\n <figure\n ref={refs}\n data-slot=\"bar-chart\"\n aria-labelledby={titleId}\n className={cn(\"m-0 grid min-w-0 gap-5 box-border font-sans text-foreground\", className)}\n >\n <figcaption id={titleId} className=\"sr-only\">\n {label}, {period}\n </figcaption>\n <div aria-hidden=\"true\" className=\"grid min-w-0 gap-0.5\">\n <span className=\"block min-h-5 text-sm text-text-secondary\">\n <SwapText swapKey={scrubbing ? valueLabel : averageLabel} motion=\"rise\" className=\"block\">\n {scrubbing ? valueLabel : averageLabel}\n </SwapText>\n </span>\n <span data-slot=\"bar-chart-value\" className=\"flex min-w-0 items-baseline gap-1.5 text-h2 font-medium tabular-nums\">\n <SwapText swapKey={headline} dir={trend.valueWay} motion=\"rise\">\n {headline}\n </SwapText>\n {unit ? <span className=\"text-base font-normal text-text-secondary\">{unit}</span> : null}\n </span>\n <span className=\"block min-h-5 text-sm text-muted-foreground\">\n <SwapText\n swapKey={scrubbed ? scrubbed.label : period}\n dir={scrubbing ? trend.indexWay : 1}\n motion=\"rise\"\n className=\"block\"\n >\n {scrubbed ? scrubbed.label : period}\n </SwapText>\n </span>\n </div>\n <div data-slot=\"bar-chart-chart\" data-scrubbing={scrubbing || undefined} data-shown={shown || undefined} className=\"bar-chart-frame\">\n <div ref={plot} className=\"relative min-w-0 [grid-area:1/1]\" style={{ height }}>\n <svg ref={svg} width=\"100%\" height={height} role=\"img\" aria-label={summary} className=\"block overflow-hidden\">\n {ticks.slice(1).map((value) => (\n <line key={value} data-grid={value} className=\"line-chart-grid motion-safe:animate-fade-in\" x1={0} x2=\"100%\" />\n ))}\n <line data-part=\"cursor\" className=\"line-chart-crosshair\" y1={TOP} y2={height} />\n {barKeys.map((key) => (\n <path\n key={key}\n data-bar={key}\n data-active={(scrubbing && data[index]?.key === key) || undefined}\n className=\"bar-chart-bar\"\n />\n ))}\n <line className=\"line-chart-baseline\" x1={0} x2=\"100%\" y1={height - 0.5} y2={height - 0.5} />\n {showAverage ? <line data-part=\"mean\" className=\"bar-chart-mean\" x1={0} x2=\"100%\" /> : null}\n </svg>\n </div>\n <div ref={gutter} aria-hidden=\"true\" className=\"relative min-w-0 [grid-area:1/2]\">\n {ticks.map((value) => (\n <span key={value} data-tick={value} className=\"line-chart-tick motion-safe:animate-fade-in\">\n <span className=\"block -translate-y-1/2 text-xs leading-none tabular-nums text-muted-foreground\">\n {formatValue(value)}\n </span>\n </span>\n ))}\n {showAverage ? (\n <span data-part=\"mean-label\" className=\"line-chart-tick bar-chart-mean-label\">\n <span data-part=\"mean-text\" className=\"block -translate-y-1/2 text-xs leading-none font-medium tabular-nums text-foreground\" />\n </span>\n ) : null}\n </div>\n <div ref={axis} aria-hidden=\"true\" className=\"relative min-w-0 overflow-hidden [grid-area:2/1]\">\n {data.map((item) =>\n item.axisLabel && fitting.has(item.key) ? (\n <span\n key={`${item.key}:${item.axisLabel}`}\n data-axis={item.key}\n data-size={labelSizes[item.axisLabel] ?? 0}\n data-shift={fitting.get(item.key) ?? 0}\n className=\"absolute start-0 top-2 whitespace-nowrap text-xs leading-none tabular-nums text-muted-foreground motion-safe:animate-fade-in\"\n >\n {item.axisLabel}\n </span>\n ) : null,\n )}\n <span ref={ruler} className=\"pointer-events-none invisible absolute start-0 top-0 flex\">\n {labelTexts\n .split(\"\\n\")\n .filter(Boolean)\n .map((text) => (\n <span key={text} data-text={text} className=\"flex-none whitespace-nowrap text-xs leading-none tabular-nums\">\n {text}\n </span>\n ))}\n </span>\n </div>\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={0}\n aria-label={`${label}, explore by ${categoryLabel.toLowerCase()}`}\n aria-orientation=\"horizontal\"\n aria-valuemin={1}\n aria-valuemax={Math.max(1, data.length)}\n aria-valuenow={(index ?? last) + 1}\n aria-valuetext={valueText}\n onPointerDown={(event: PointerEvent<HTMLDivElement>) => {\n if (event.pointerType !== \"mouse\") event.currentTarget.setPointerCapture?.(event.pointerId);\n setActive(pointAt(event.clientX));\n }}\n onPointerMove={(event: PointerEvent<HTMLDivElement>) => {\n if (event.pointerType === \"mouse\" || event.buttons) setActive(pointAt(event.clientX));\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) setActive((current) => current ?? last);\n }}\n className=\"bar-chart-scrubber\"\n />\n </div>\n <div className=\"sr-only\">\n <table>\n <caption>\n {label}, {period}\n </caption>\n <thead>\n <tr>\n <th scope=\"col\">{categoryLabel}</th>\n <th scope=\"col\">{label}</th>\n </tr>\n </thead>\n <tbody>\n {data.map((item) => (\n <tr key={item.key}>\n <th scope=\"row\">{item.label}</th>\n <td>\n {formatValue(item.value)}\n {suffix}\n </td>\n </tr>\n ))}\n </tbody>\n </table>\n </div>\n <p className=\"sr-only\" aria-live=\"polite\" aria-atomic=\"true\">\n {changes ? `${period}. ${averageLabel} ${formatValue(Math.round(average))}${suffix}.` : \"\"}\n </p>\n </figure>\n );\n});\n"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"bar-chart.js","names":[],"sources":["../../src/bar-chart/bar-chart.tsx"],"sourcesContent":["\"use client\";\n\nimport {\n forwardRef,\n useCallback,\n useEffect,\n useId,\n useMemo,\n useRef,\n useState,\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\";\nimport { live, MORPH, retarget, SMOOTH, SNAPPY, type Live, type Spring } from \"../lib/spring-tween.js\";\nimport { SwapText } from \"../lib/swap-text.js\";\nimport { SeriesBarChart, type BarChartSeriesProps } from \"./bar-chart-series.js\";\n\nexport type {\n BarChartSeries,\n BarChartSeriesDatum,\n BarChartSeriesProps,\n} from \"./bar-chart-series.js\";\n\n/**\n * BarChart: one measure across a run of days, weeks or months, when people\n * compare each period against the rest and against the average.\n *\n * The bars grow from the baseline the first time the chart is seen, each a beat\n * after its neighbour, and the dashed average rises with them. A new range zooms\n * the time axis around the latest bar (bars that stay glide to their new slot,\n * new ones grow outward from them, leaving ones sink into the baseline) while\n * the scale and the average slide to fit. Hover, drag or the arrow keys scrub:\n * the scrubbed bar takes the full colour while the rest step back, a cursor\n * glides to it, and the headline swaps from the average to that bar.\n *\n * Plain SVG and CSS; one small spring tween drives the bars, the zoom, the\n * scale, the average and the cursor. A visually hidden table carries every\n * value, and the plot is a slider.\n *\n * Pass `series` for the series mode instead: several measures per category,\n * grouped or stacked, on a categorical axis in data order, upright or as\n * horizontal rows, with a legend (see `BarChartSeriesProps`). Without\n * `series` the chart is exactly the one described above.\n */\nexport interface BarChartDatum {\n /** Stable identity, such as an ISO date. A bar whose key survives a data change keeps its place. */\n key: string;\n /** Full label for the headline and screen readers, such as \"Tue, Sep 15\". */\n label: string;\n /** Short label under the bar, such as \"T\" or \"Sep 14\". Leave it out to keep the axis quiet. */\n axisLabel?: string;\n value: number;\n}\n\nexport interface BarChartProps {\n data: BarChartDatum[];\n /** What is measured, such as \"Active minutes\". Names the chart for assistive technology. */\n label: string;\n /** The range on show, such as \"Sep 15–21, 2026\". It rests under the headline. */\n period: string;\n /** Unit after each value, such as \"min\". */\n unit?: string;\n /** Headline label at rest, above the average. @default \"Daily average\" */\n averageLabel?: string;\n /** Headline label while a bar is scrubbed. @default \"Total\" */\n valueLabel?: string;\n /** Header of the first column in the data table read by screen readers. @default \"Day\" */\n categoryLabel?: string;\n /** Draws the average as a dashed reference line. @default true */\n showAverage?: boolean;\n /** Plot height in pixels. @default 176 */\n height?: number;\n formatValue?: (value: number) => string;\n /** Extra classes for the root. Merged last. */\n className?: string;\n /** Not used in this mode: passing `series` switches to the series mode (`BarChartSeriesProps`). */\n series?: undefined;\n}\n\n/** Room above the top gridline, the share of each slot a bar fills, its widest size, and the radius of its data end. */\nconst TOP = 12;\nconst FILL = 0.58;\nconst MAX_BAR = 28;\nconst RADIUS = 4;\n/** Stagger between bars on the first reveal (seconds in the source: .035 per bar, at most .36 in all). */\nconst STAGGER_MS = 35;\nconst GROUPED = new Intl.NumberFormat(\"en-US\", { maximumFractionDigits: 0 });\nconst clamp = (value: number, low: number, high: number) => Math.min(high, Math.max(low, value));\n/** visualDuration .24s, no bounce: a leaving bar sinks a little faster than a bar grows. */\nconst COLLAPSE: Spring = {\n curve: [\n 0, 0.0484, 0.1552, 0.2816, 0.4069, 0.5207, 0.6189, 0.7009, 0.7676, 0.821, 0.8631, 0.8959, 0.9213,\n 0.9408, 0.9556, 0.9668, 0.9753, 0.9816, 0.9864, 0.9899, 0.9926, 0.9945, 0.996, 0.9971, 0.9978,\n 0.9984, 0.9988, 0.9992, 0.9994, 1,\n ],\n ms: 464,\n};\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) return { top: rows * step, ticks: Array.from({ length: rows + 1 }, (_, row) => row * step) };\n }\n return { top: safe, ticks: [0, safe] };\n}\n\n/** A column that grows from a square baseline to a softly rounded data end. */\nfunction barPath(x: number, w: number, h: number, base: number) {\n const f = (value: number) => value.toFixed(2);\n if (w <= 0 || h <= 0.01) return `M${f(x)} ${base}H${f(x + Math.max(w, 0))}Z`;\n const r = Math.min(RADIUS, w / 2, h);\n const top = base - h;\n return `M${f(x)} ${base}V${f(top + r)}A${f(r)} ${f(r)} 0 0 1 ${f(x + r)} ${f(top)}H${f(x + w - r)}A${f(r)} ${f(r)} 0 0 1 ${f(x + w)} ${f(top + r)}V${base}Z`;\n}\n\n/** Axis labels that fit once the range has settled: every label, else every second, third and so on, counted back from the latest. */\nfunction fittingLabels(data: BarChartDatum[], width: number, sizes: Record<string, number>) {\n const fitting = new Map<string, number>();\n if (!width) return fitting;\n const count = Math.max(1, data.length);\n const labels = data\n .flatMap((item, index) => {\n const size = item.axisLabel ? sizes[item.axisLabel] : undefined;\n if (size === undefined) return [];\n const natural = width - (data.length - 1 - index + 0.5) * (width / count) - size / 2;\n return [{ key: item.key, size, natural, left: clamp(natural, 0, Math.max(0, width - size)) }];\n })\n .reverse();\n for (let stride = 1; stride <= labels.length; stride++) {\n const picked = labels.filter((_, rank) => rank % stride === 0);\n if (\n stride === labels.length ||\n picked.every((label, rank) => rank === 0 || label.left + label.size + 10 <= picked[rank - 1]!.left)\n ) {\n picked.forEach((label) => fitting.set(label.key, label.left - label.natural));\n break;\n }\n }\n return fitting;\n}\n\nconst TimeBarChart = forwardRef<HTMLElement, BarChartProps>(function TimeBarChart(\n {\n data,\n label,\n period,\n unit = \"\",\n averageLabel = \"Daily average\",\n valueLabel = \"Total\",\n categoryLabel = \"Day\",\n showAverage = true,\n height = 176,\n formatValue = (value) => GROUPED.format(value),\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 svg = useRef<SVGSVGElement>(null);\n const gutter = useRef<HTMLDivElement>(null);\n const axis = useRef<HTMLDivElement>(null);\n const ruler = useRef<HTMLSpanElement>(null);\n const titleId = useId();\n const count = Math.max(data.length, 1);\n const last = data.length - 1;\n const average = data.length ? data.reduce((sum, item) => sum + item.value, 0) / data.length : 0;\n const peak = data.reduce((max, item) => Math.max(max, item.value), 0);\n const { top, ticks } = useMemo(() => scaleFor(peak), [peak]);\n const suffix = unit ? ` ${unit}` : \"\";\n\n // Bars that left stay in the DOM while they sink, then go.\n const [leaving, setLeaving] = useState<string[]>([]);\n const previous = useRef(data);\n const [changes, setChanges] = useState(0);\n const [active, setActive] = useState<number | null>(null);\n const signature = data.map((item) => item.key).join(\"|\");\n const [seen, setSeen] = useState(signature);\n if (seen !== signature) {\n setSeen(signature);\n setActive(null);\n setChanges((n) => n + 1);\n }\n const index = active === null ? null : Math.min(active, last);\n const scrubbing = index !== null && last >= 0;\n const shownValue = scrubbing ? data[index]!.value : average;\n const [trend, setTrend] = useState({ value: shownValue, index, valueWay: 1, indexWay: 1 });\n if (trend.value !== shownValue || trend.index !== index) {\n setTrend({\n value: shownValue,\n index,\n valueWay: shownValue === trend.value ? trend.valueWay : shownValue > trend.value ? 1 : -1,\n indexWay: index === null || trend.index === null ? 1 : Math.sign(index - trend.index) || 1,\n });\n }\n\n // Animated state, read only by the painter.\n const width = useRef(0);\n const share = useRef(live(1 / count));\n const scale = useRef(live(top));\n const mean = useRef(live(0));\n const cursor = useRef(live(0));\n const bars = useRef(new Map<string, { place: Live; amount: Live }>());\n const [shown, setShown] = useState(false);\n const [plotWidth, setPlotWidth] = useState(0);\n const [labelSizes, setLabelSizes] = useState<Record<string, number>>({});\n\n /** One writer for every drawn attribute, straight onto the elements. */\n const paint = useCallback(() => {\n const root = svg.current;\n const w = width.current;\n if (!root || !w) return;\n const s = scale.current.value || 1;\n const rowY = (value: number) => Math.round(height - (value / s) * (height - TOP)) + 0.5;\n const slot = w * share.current.value;\n const size = Math.min(slot * FILL, MAX_BAR);\n for (const [key, bar] of bars.current) {\n const node = root.querySelector(`[data-bar=\"${CSS.escape(key)}\"]`);\n const center = w - (bar.place.value + 0.5) * slot;\n node?.setAttribute(\"d\", barPath(center - size / 2, size, Math.max(0, (bar.amount.value / s) * (height - TOP)), height));\n }\n for (const node of root.querySelectorAll<SVGLineElement>(\"[data-grid]\")) {\n const y = String(rowY(Number(node.dataset.grid)));\n node.setAttribute(\"y1\", y);\n node.setAttribute(\"y2\", y);\n }\n const meanY = rowY(mean.current.value);\n const meanLine = root.querySelector(\"[data-part=mean]\");\n meanLine?.setAttribute(\"y1\", String(meanY));\n meanLine?.setAttribute(\"y2\", String(meanY));\n const cx = String(Math.round(w - (cursor.current.value + 0.5) * slot) + 0.5);\n const cross = root.querySelector(\"[data-part=cursor]\");\n cross?.setAttribute(\"x1\", cx);\n cross?.setAttribute(\"x2\", cx);\n // Tick labels ride the scale and make way where the average label sits beside them.\n for (const node of gutter.current?.querySelectorAll<HTMLElement>(\"[data-tick]\") ?? []) {\n const y = rowY(Number(node.dataset.tick));\n node.style.translate = `0 ${y}px`;\n node.style.opacity = showAverage ? String(clamp((Math.abs(y - meanY) - 10) / 6, 0, 1)) : \"1\";\n }\n const meanLabel = gutter.current?.querySelector<HTMLElement>(\"[data-part=mean-label]\");\n if (meanLabel) {\n meanLabel.style.translate = `0 ${meanY}px`;\n const text = meanLabel.querySelector(\"[data-part=mean-text]\");\n if (text) text.textContent = `Avg ${formatValue(Math.round(mean.current.value))}`;\n }\n // Axis labels are centred under their bar and carried by the zoom.\n for (const node of axis.current?.querySelectorAll<HTMLElement>(\"[data-axis]\") ?? []) {\n const place = bars.current.get(node.dataset.axis!)?.place.value ?? 0;\n node.style.translate = `${w - (place + 0.5) * slot - Number(node.dataset.size) / 2 + Number(node.dataset.shift)}px 0`;\n }\n }, [formatValue, height, showAverage]);\n\n const go = useCallback(\n (target: Live, to: number, spring: Spring, delay = 0, done?: () => void) =>\n retarget(target, to, spring, paint, delay, done),\n [paint],\n );\n\n // The chart draws in its own pixels: measure the width and every axis label once, follow resizes.\n const labelTexts = [...new Set(data.map((item) => item.axisLabel).filter((text): text is string => !!text))].join(\"\\n\");\n useIsomorphicLayoutEffect(() => {\n const node = plot.current;\n const measure = ruler.current;\n if (!node || !measure) return;\n const read = () => {\n width.current = node.clientWidth;\n setPlotWidth(node.clientWidth);\n const sizes: Record<string, number> = {};\n measure.querySelectorAll<HTMLElement>(\"[data-text]\").forEach((item) => {\n sizes[item.dataset.text ?? \"\"] = item.offsetWidth;\n });\n setLabelSizes((current) => (Object.keys(sizes).every((text) => current[text] === sizes[text]) ? current : sizes));\n paint();\n };\n read();\n if (typeof ResizeObserver === \"undefined\") return;\n const observer = new ResizeObserver(read);\n observer.observe(node);\n return () => observer.disconnect();\n }, [labelTexts, paint]);\n const fitting = useMemo(() => fittingLabels(data, plotWidth, labelSizes), [data, plotWidth, labelSizes]);\n useIsomorphicLayoutEffect(paint);\n\n // The bars grow once the chart is a third in view.\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 // Every bar to its slot and value. The first reveal runs left to right a beat apart; later, new bars grow outward from the ones that stayed and leaving ones sink.\n const firstReveal = useRef(true);\n useEffect(() => {\n if (!shown) return;\n const first = firstReveal.current;\n firstReveal.current = false;\n const known = new Set(previous.current.map((item) => item.key));\n previous.current = data;\n const incoming = data\n .map((item, at) => ({ key: item.key, place: last - at }))\n .filter((item) => first || !known.has(item.key))\n .sort((a, b) => (first ? b.place - a.place : a.place - b.place));\n const step = Math.min(STAGGER_MS, (first ? 360 : 320) / Math.max(1, incoming.length));\n const delayOf = new Map(incoming.map((item, rank) => [item.key, rank * step]));\n const keys = new Set(data.map((item) => item.key));\n data.forEach((item, at) => {\n const place = last - at;\n let bar = bars.current.get(item.key);\n if (!bar) {\n bar = { place: live(place), amount: live(0) };\n bars.current.set(item.key, bar);\n }\n go(bar.place, place, SMOOTH);\n const fresh = delayOf.has(item.key);\n go(bar.amount, item.value, fresh ? MORPH : SMOOTH, fresh ? delayOf.get(item.key)! : 0);\n });\n const gone = [...bars.current.keys()].filter((key) => !keys.has(key));\n if (gone.length) setLeaving((current) => [...new Set([...current, ...gone])]);\n for (const key of gone) {\n const bar = bars.current.get(key)!;\n go(bar.amount, 0, COLLAPSE, 0, () => {\n bars.current.delete(key);\n setLeaving((current) => current.filter((item) => item !== key));\n });\n }\n // The time axis zooms around the latest bar, and the scale slides to fit.\n go(share.current, 1 / count, SMOOTH);\n go(scale.current, top, SMOOTH);\n // The average rises with the first bars, a beat late, then springs to each new range.\n go(mean.current, average, SMOOTH, first ? 120 : 0);\n // `data` is captured by signature and values; the springs read the rest from refs.\n // eslint-disable-next-line react-hooks/exhaustive-deps\n }, [shown, signature, data.map((item) => item.value).join(\",\"), top, average, count]);\n\n // The cursor appears on the first scrubbed bar and glides between the ones after it.\n const wasScrubbing = useRef(false);\n useEffect(() => {\n if (index === null) {\n wasScrubbing.current = false;\n return;\n }\n const place = last - index;\n if (!wasScrubbing.current) {\n wasScrubbing.current = true;\n cursor.current.stop();\n cursor.current.value = place;\n paint();\n return;\n }\n go(cursor.current, place, SNAPPY);\n }, [go, index, last, paint]);\n\n const pointAt = (clientX: number) => {\n const rect = plot.current?.getBoundingClientRect();\n if (!rect?.width) return last;\n const place = Math.floor(((rect.right - clientX) / rect.width) * count);\n return clamp(last - place, 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 ?? last + 1;\n const page = Math.min(7, count);\n const next = (\n {\n ArrowLeft: from - 1,\n ArrowDown: from - 1,\n ArrowRight: index === null ? last : from + 1,\n ArrowUp: index === null ? last : from + 1,\n PageDown: from - page,\n PageUp: 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 scrubbed = scrubbing ? data[index]! : null;\n const reading = scrubbed ?? data[last];\n const valueText = reading ? `${reading.label}: ${formatValue(reading.value)}${suffix}` : \"No data\";\n const highest = data.reduce<BarChartDatum | null>((best, item) => (!best || item.value > best.value ? item : best), null);\n const lowest = data.reduce<BarChartDatum | null>((best, item) => (!best || item.value < best.value ? item : best), null);\n const summary = `${label}, ${period}. ${averageLabel} ${formatValue(Math.round(average))}${suffix}.${\n highest ? ` Highest ${highest.label}, ${formatValue(highest.value)}${suffix}.` : \"\"\n }${lowest && lowest !== highest ? ` Lowest ${lowest.label}, ${formatValue(lowest.value)}${suffix}.` : \"\"}`;\n const headline = formatValue(scrubbing ? data[index]!.value : Math.round(average));\n const barKeys = [...data.map((item) => item.key), ...leaving.filter((key) => !data.some((item) => item.key === key))];\n\n return (\n <figure\n ref={refs}\n data-slot=\"bar-chart\"\n aria-labelledby={titleId}\n className={cn(\"m-0 grid min-w-0 gap-5 box-border font-sans text-foreground\", className)}\n >\n <figcaption id={titleId} className=\"sr-only\">\n {label}, {period}\n </figcaption>\n <div aria-hidden=\"true\" className=\"grid min-w-0 gap-0.5\">\n <span className=\"block min-h-5 text-sm text-text-secondary\">\n <SwapText swapKey={scrubbing ? valueLabel : averageLabel} motion=\"rise\" className=\"block\">\n {scrubbing ? valueLabel : averageLabel}\n </SwapText>\n </span>\n <span data-slot=\"bar-chart-value\" className=\"flex min-w-0 items-baseline gap-1.5 text-h2 font-medium tabular-nums\">\n <SwapText swapKey={headline} dir={trend.valueWay} motion=\"rise\">\n {headline}\n </SwapText>\n {unit ? <span className=\"text-base font-normal text-text-secondary\">{unit}</span> : null}\n </span>\n <span className=\"block min-h-5 text-sm text-muted-foreground\">\n <SwapText\n swapKey={scrubbed ? scrubbed.label : period}\n dir={scrubbing ? trend.indexWay : 1}\n motion=\"rise\"\n className=\"block\"\n >\n {scrubbed ? scrubbed.label : period}\n </SwapText>\n </span>\n </div>\n <div data-slot=\"bar-chart-chart\" data-scrubbing={scrubbing || undefined} data-shown={shown || undefined} className=\"bar-chart-frame\">\n <div ref={plot} className=\"relative min-w-0 [grid-area:1/1]\" style={{ height }}>\n <svg ref={svg} width=\"100%\" height={height} role=\"img\" aria-label={summary} className=\"block overflow-hidden\">\n {ticks.slice(1).map((value) => (\n <line key={value} data-grid={value} className=\"line-chart-grid motion-safe:animate-fade-in\" x1={0} x2=\"100%\" />\n ))}\n <line data-part=\"cursor\" className=\"line-chart-crosshair\" y1={TOP} y2={height} />\n {barKeys.map((key) => (\n <path\n key={key}\n data-bar={key}\n data-active={(scrubbing && data[index]?.key === key) || undefined}\n className=\"bar-chart-bar\"\n />\n ))}\n <line className=\"line-chart-baseline\" x1={0} x2=\"100%\" y1={height - 0.5} y2={height - 0.5} />\n {showAverage ? <line data-part=\"mean\" className=\"bar-chart-mean\" x1={0} x2=\"100%\" /> : null}\n </svg>\n </div>\n <div ref={gutter} aria-hidden=\"true\" className=\"relative min-w-0 [grid-area:1/2]\">\n {ticks.map((value) => (\n <span key={value} data-tick={value} className=\"line-chart-tick motion-safe:animate-fade-in\">\n <span className=\"block -translate-y-1/2 text-xs leading-none tabular-nums text-muted-foreground\">\n {formatValue(value)}\n </span>\n </span>\n ))}\n {showAverage ? (\n <span data-part=\"mean-label\" className=\"line-chart-tick bar-chart-mean-label\">\n <span data-part=\"mean-text\" className=\"block -translate-y-1/2 text-xs leading-none font-medium tabular-nums text-foreground\" />\n </span>\n ) : null}\n </div>\n <div ref={axis} aria-hidden=\"true\" className=\"relative min-w-0 overflow-hidden [grid-area:2/1]\">\n {data.map((item) =>\n item.axisLabel && fitting.has(item.key) ? (\n <span\n key={`${item.key}:${item.axisLabel}`}\n data-axis={item.key}\n data-size={labelSizes[item.axisLabel] ?? 0}\n data-shift={fitting.get(item.key) ?? 0}\n className=\"absolute start-0 top-2 whitespace-nowrap text-xs leading-none tabular-nums text-muted-foreground motion-safe:animate-fade-in\"\n >\n {item.axisLabel}\n </span>\n ) : null,\n )}\n <span ref={ruler} className=\"pointer-events-none invisible absolute start-0 top-0 flex\">\n {labelTexts\n .split(\"\\n\")\n .filter(Boolean)\n .map((text) => (\n <span key={text} data-text={text} className=\"flex-none whitespace-nowrap text-xs leading-none tabular-nums\">\n {text}\n </span>\n ))}\n </span>\n </div>\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={0}\n aria-label={`${label}, explore by ${categoryLabel.toLowerCase()}`}\n aria-orientation=\"horizontal\"\n aria-valuemin={1}\n aria-valuemax={Math.max(1, data.length)}\n aria-valuenow={(index ?? last) + 1}\n aria-valuetext={valueText}\n onPointerDown={(event: PointerEvent<HTMLDivElement>) => {\n if (event.pointerType !== \"mouse\") event.currentTarget.setPointerCapture?.(event.pointerId);\n setActive(pointAt(event.clientX));\n }}\n onPointerMove={(event: PointerEvent<HTMLDivElement>) => {\n if (event.pointerType === \"mouse\" || event.buttons) setActive(pointAt(event.clientX));\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) setActive((current) => current ?? last);\n }}\n className=\"bar-chart-scrubber\"\n />\n </div>\n <div className=\"sr-only\">\n <table>\n <caption>\n {label}, {period}\n </caption>\n <thead>\n <tr>\n <th scope=\"col\">{categoryLabel}</th>\n <th scope=\"col\">{label}</th>\n </tr>\n </thead>\n <tbody>\n {data.map((item) => (\n <tr key={item.key}>\n <th scope=\"row\">{item.label}</th>\n <td>\n {formatValue(item.value)}\n {suffix}\n </td>\n </tr>\n ))}\n </tbody>\n </table>\n </div>\n <p className=\"sr-only\" aria-live=\"polite\" aria-atomic=\"true\">\n {changes ? `${period}. ${averageLabel} ${formatValue(Math.round(average))}${suffix}.` : \"\"}\n </p>\n </figure>\n );\n});\n\n/**\n * One measure across a run of periods (`BarChartProps`), or, with `series`,\n * several measures per category, grouped or stacked, upright or horizontal\n * (`BarChartSeriesProps`).\n *\n * @example\n * <BarChart label=\"Active minutes\" period=\"Sep 15–21, 2026\" data={week} />\n * <BarChart\n * label=\"Spend by campaign\"\n * series={[{ key: \"search\", label: \"Search\" }, { key: \"social\", label: \"Social\" }]}\n * layout=\"stacked\"\n * orientation=\"horizontal\"\n * data={campaigns}\n * />\n */\nexport const BarChart = forwardRef<HTMLElement, BarChartProps | BarChartSeriesProps>(\n function BarChart(props, ref) {\n return props.series === undefined ? (\n <TimeBarChart ref={ref} {...props} />\n ) : (\n <SeriesBarChart ref={ref} {...props} />\n );\n },\n);\n"],"mappings":"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"}
|
|
@@ -1,2 +1,3 @@
|
|
|
1
|
+
import { BarChartSeries, BarChartSeriesDatum, BarChartSeriesProps } from "./bar-chart-series.js";
|
|
1
2
|
import { BarChart, BarChartDatum, BarChartProps } from "./bar-chart.js";
|
|
2
|
-
export { BarChart, type BarChartDatum, type BarChartProps };
|
|
3
|
+
export { BarChart, type BarChartDatum, type BarChartProps, type BarChartSeries, type BarChartSeriesDatum, type BarChartSeriesProps };
|
package/dist/button/button.d.ts
CHANGED
|
@@ -3,8 +3,9 @@ import { ReactNode } from "react";
|
|
|
3
3
|
import { ButtonProps, LinkProps } from "react-aria-components";
|
|
4
4
|
//#region src/button/button.d.ts
|
|
5
5
|
export declare const buttonVariants: (props?: ({
|
|
6
|
-
variant?: "link" | "
|
|
7
|
-
size?: "sm" | "md" | "lg" | "icon" | null | undefined;
|
|
6
|
+
variant?: "link" | "outline" | "primary" | "ai" | "secondary" | "outlineNeutral" | "ghost" | "destructive" | null | undefined;
|
|
7
|
+
size?: "icon" | "sm" | "md" | "lg" | "icon-sm" | null | undefined;
|
|
8
|
+
wrap?: boolean | null | undefined;
|
|
8
9
|
} & import("class-variance-authority/types").ClassProp) | undefined) => string;
|
|
9
10
|
/**
|
|
10
11
|
* Props.
|
|
@@ -37,10 +38,29 @@ interface ButtonProps$1 extends Omit<ButtonProps, "className" | "style">, Varian
|
|
|
37
38
|
*
|
|
38
39
|
* NOT the route for `size="icon"`. An icon-only button passes its glyph as
|
|
39
40
|
* `children`, which is what gives it its single centred child.
|
|
41
|
+
*
|
|
42
|
+
* `variant="ai"` supplies a wand here when this is `undefined`. Pass your own
|
|
43
|
+
* node to replace it, or `false` (or `null`) for no icon at all. The wand is
|
|
44
|
+
* not added to `size="icon"`, whose glyph is `children`.
|
|
40
45
|
*/
|
|
41
46
|
startIcon?: ReactNode;
|
|
42
47
|
/** Icon rendered after the label. Same rules as {@link ButtonProps.startIcon}. */
|
|
43
48
|
endIcon?: ReactNode;
|
|
49
|
+
/**
|
|
50
|
+
* Let the label wrap onto more lines. For a button whose text is long and
|
|
51
|
+
* not ours (a prompt, a name): it shrinks to its container, breaks the label
|
|
52
|
+
* (even a long word with no spaces), starts the text at the leading edge, and
|
|
53
|
+
* grows taller than `size`'s height, which becomes its minimum. Off by
|
|
54
|
+
* default, and then a button is one line at a fixed height exactly as before.
|
|
55
|
+
* Pass `className="justify-start"` to start a link-style button at the
|
|
56
|
+
* leading edge of its row. A wrapping button's width does not spring when its
|
|
57
|
+
* label changes.
|
|
58
|
+
*
|
|
59
|
+
* Not for `size="icon"` or `"icon-sm"`, which have no label.
|
|
60
|
+
*
|
|
61
|
+
* @default false
|
|
62
|
+
*/
|
|
63
|
+
wrap?: boolean;
|
|
44
64
|
/**
|
|
45
65
|
* Makes the button a link. It renders React Aria's `Link` -- a real `<a>`,
|
|
46
66
|
* announced as a link -- with exactly the classes a button of the same
|
|
@@ -84,6 +104,8 @@ interface ButtonProps$1 extends Omit<ButtonProps, "className" | "style">, Varian
|
|
|
84
104
|
* <Button startIcon={<SaveIcon aria-hidden />}>Save changes</Button>
|
|
85
105
|
* <Button endIcon={<ChevronIcon aria-hidden />}>Continue</Button>
|
|
86
106
|
* <Button variant="outline" size="icon" aria-label="Close"><XIcon /></Button>
|
|
107
|
+
* <Button variant="ghost" size="icon-sm" aria-label="More information"><InfoIcon /></Button>
|
|
108
|
+
* <Button variant="link" wrap className="justify-start">A long prompt that may run over several lines</Button>
|
|
87
109
|
* <Button href="/reports" variant="outlineNeutral">View reports</Button>
|
|
88
110
|
*/
|
|
89
111
|
declare const Button$1: import("react").ForwardRefExoticComponent<ButtonProps$1 & import("react").RefAttributes<HTMLButtonElement>>;
|
package/dist/button/button.js
CHANGED
|
@@ -55,13 +55,15 @@ const buttonVariants = cva([
|
|
|
55
55
|
"data-[disabled]:opacity-(--opacity-button-disabled)"
|
|
56
56
|
],
|
|
57
57
|
ai: [
|
|
58
|
-
"bg-primary text-primary-foreground shadow-surface",
|
|
59
|
-
"ai-beam",
|
|
58
|
+
"bg-primary bg-(image:--gradient-ai) text-primary-foreground shadow-surface",
|
|
60
59
|
"motion-safe:button-motion",
|
|
61
60
|
pressScale,
|
|
62
|
-
"data-[hovered]:bg-
|
|
61
|
+
"data-[hovered]:bg-(image:--gradient-ai-hover) data-[hovered]:shadow-resting",
|
|
62
|
+
"data-[pressed]:bg-(image:--gradient-ai-pressed)",
|
|
63
63
|
"motion-safe:data-[hovered]:[&_svg]:-rotate-12",
|
|
64
|
-
"data-[
|
|
64
|
+
"data-[focus-visible]:outline-0 data-[focus-visible]:border-primary-foreground",
|
|
65
|
+
"forced-colors:data-[focus-visible]:outline-(length:--focus-ring-width)",
|
|
66
|
+
"data-[disabled]:opacity-100 data-[disabled]:bg-none data-[disabled]:bg-muted data-[disabled]:text-muted-foreground data-[disabled]:border-border data-[disabled]:shadow-none"
|
|
65
67
|
],
|
|
66
68
|
secondary: [
|
|
67
69
|
"bg-surface text-foreground border-(length:--border-width) border-border shadow-surface",
|
|
@@ -116,12 +118,35 @@ const buttonVariants = cva([
|
|
|
116
118
|
sm: "h-(--density-control-h-sm) px-4 text-sm",
|
|
117
119
|
md: "h-(--density-control-h-md) px-4 text-sm",
|
|
118
120
|
lg: "h-(--density-control-h-lg) px-(--density-control-pad-lg) text-lg",
|
|
119
|
-
icon: "size-(--density-control-h-md) px-0 text-base"
|
|
121
|
+
icon: "size-(--density-control-h-md) px-0 text-base",
|
|
122
|
+
"icon-sm": "size-6 px-0 text-base [&_svg:not([class*='size-'])]:size-3.5"
|
|
123
|
+
},
|
|
124
|
+
wrap: {
|
|
125
|
+
true: "h-auto max-w-full min-w-0 shrink whitespace-normal break-words text-start",
|
|
126
|
+
false: ""
|
|
120
127
|
}
|
|
121
128
|
},
|
|
129
|
+
compoundVariants: [
|
|
130
|
+
{
|
|
131
|
+
size: "sm",
|
|
132
|
+
wrap: true,
|
|
133
|
+
class: "min-h-(--density-control-h-sm) py-1.5"
|
|
134
|
+
},
|
|
135
|
+
{
|
|
136
|
+
size: "md",
|
|
137
|
+
wrap: true,
|
|
138
|
+
class: "min-h-(--density-control-h-md) py-2"
|
|
139
|
+
},
|
|
140
|
+
{
|
|
141
|
+
size: "lg",
|
|
142
|
+
wrap: true,
|
|
143
|
+
class: "min-h-(--density-control-h-lg) py-2.5"
|
|
144
|
+
}
|
|
145
|
+
],
|
|
122
146
|
defaultVariants: {
|
|
123
147
|
variant: "primary",
|
|
124
|
-
size: "md"
|
|
148
|
+
size: "md",
|
|
149
|
+
wrap: false
|
|
125
150
|
}
|
|
126
151
|
});
|
|
127
152
|
/** A key for the label content: text plus element names, so a new label or icon crossfades while prop-only updates stay in place. */
|
|
@@ -177,12 +202,12 @@ function Loader({ show }) {
|
|
|
177
202
|
* Nothing animates on first mount, and a prop-only update (same key) stays in
|
|
178
203
|
* place.
|
|
179
204
|
*/
|
|
180
|
-
function ButtonContent({ children, pending }) {
|
|
205
|
+
function ButtonContent({ children, pending, wrap }) {
|
|
181
206
|
const key = labelKey(children);
|
|
182
207
|
const icon = isIconKey(key);
|
|
183
208
|
const contentRef = useRef(null);
|
|
184
209
|
const phaseRef = useRef(null);
|
|
185
|
-
useMorphWidth(contentRef, key);
|
|
210
|
+
useMorphWidth(contentRef, key, !wrap);
|
|
186
211
|
const { leaving, changed, remove } = useLeavingItems(key, {
|
|
187
212
|
node: children,
|
|
188
213
|
icon
|
|
@@ -191,7 +216,7 @@ function ButtonContent({ children, pending }) {
|
|
|
191
216
|
className: cn("button-slot", pending && "opacity-0"),
|
|
192
217
|
children: /* @__PURE__ */ jsxs("span", {
|
|
193
218
|
ref: contentRef,
|
|
194
|
-
className: "inline-flex flex-none items-center",
|
|
219
|
+
className: wrap ? "inline-flex min-w-0 items-center" : "inline-flex flex-none items-center",
|
|
195
220
|
children: [leaving.map((item) => /* @__PURE__ */ jsx(LeavingPhase, {
|
|
196
221
|
phase: {
|
|
197
222
|
id: item.id,
|
|
@@ -203,13 +228,32 @@ function ButtonContent({ children, pending }) {
|
|
|
203
228
|
}, item.id)), /* @__PURE__ */ jsx("span", {
|
|
204
229
|
ref: phaseRef,
|
|
205
230
|
"data-slot": "button-label",
|
|
206
|
-
className: cn("inline-flex items-center justify-center gap-(--density-control-gap)
|
|
231
|
+
className: cn(["inline-flex items-center justify-center gap-(--density-control-gap) [&_svg]:shrink-0", wrap ? "min-w-0 whitespace-normal" : "whitespace-nowrap"], changed && (icon ? "motion-safe:animate-glyph-in motion-reduce:animate-fade-in" : "motion-safe:animate-label-in motion-reduce:animate-fade-in")),
|
|
207
232
|
children
|
|
208
233
|
}, key)]
|
|
209
234
|
})
|
|
210
235
|
})] });
|
|
211
236
|
}
|
|
212
237
|
/**
|
|
238
|
+
* The AI button's wand: a 24px outline glyph in the same stroke style as the
|
|
239
|
+
* library's other inline icons (the package ships no icon dependency). Drawn
|
|
240
|
+
* after lucide's "wand-sparkles", which is what the app's `Wand2` is.
|
|
241
|
+
*/
|
|
242
|
+
function WandIcon() {
|
|
243
|
+
return /* @__PURE__ */ jsxs("svg", {
|
|
244
|
+
viewBox: "0 0 24 24",
|
|
245
|
+
fill: "none",
|
|
246
|
+
stroke: "currentColor",
|
|
247
|
+
strokeWidth: "1.75",
|
|
248
|
+
strokeLinecap: "round",
|
|
249
|
+
strokeLinejoin: "round",
|
|
250
|
+
"aria-hidden": "true",
|
|
251
|
+
"data-slot": "button-wand",
|
|
252
|
+
children: [/* @__PURE__ */ jsx("path", { d: "m21.64 3.64-1.28-1.28a1.21 1.21 0 0 0-1.72 0L2.36 18.64a1.21 1.21 0 0 0 0 1.72l1.28 1.28a1.2 1.2 0 0 0 1.72 0L21.64 5.36a1.2 1.2 0 0 0 0-1.72" }), /* @__PURE__ */ jsx("path", { d: "m14 7 3 3M5 6v4M19 14v4M10 2v2M7 8H3M21 16h-4M11 3H9" })]
|
|
253
|
+
});
|
|
254
|
+
}
|
|
255
|
+
WandIcon.displayName = "WandIcon";
|
|
256
|
+
/**
|
|
213
257
|
* A button.
|
|
214
258
|
*
|
|
215
259
|
* A label that changes (a different text, or a different icon) crossfades, and
|
|
@@ -228,18 +272,23 @@ function ButtonContent({ children, pending }) {
|
|
|
228
272
|
* <Button startIcon={<SaveIcon aria-hidden />}>Save changes</Button>
|
|
229
273
|
* <Button endIcon={<ChevronIcon aria-hidden />}>Continue</Button>
|
|
230
274
|
* <Button variant="outline" size="icon" aria-label="Close"><XIcon /></Button>
|
|
275
|
+
* <Button variant="ghost" size="icon-sm" aria-label="More information"><InfoIcon /></Button>
|
|
276
|
+
* <Button variant="link" wrap className="justify-start">A long prompt that may run over several lines</Button>
|
|
231
277
|
* <Button href="/reports" variant="outlineNeutral">View reports</Button>
|
|
232
278
|
*/
|
|
233
|
-
const Button$1 = forwardRef(function Button$2({ className, variant, size, startIcon, endIcon, children, href, target, rel, download, ...props }, ref) {
|
|
279
|
+
const Button$1 = forwardRef(function Button$2({ className, variant, size, wrap, startIcon, endIcon, children, href, target, rel, download, ...props }, ref) {
|
|
234
280
|
const classes = cn(buttonVariants({
|
|
235
281
|
variant,
|
|
236
|
-
size
|
|
282
|
+
size,
|
|
283
|
+
wrap
|
|
237
284
|
}), className);
|
|
285
|
+
const leadingIcon = startIcon === void 0 && variant === "ai" && size !== "icon" ? /* @__PURE__ */ jsx(WandIcon, {}) : startIcon;
|
|
238
286
|
const button = useAriaBusy(props.isPending === true);
|
|
239
287
|
const content = (renderProps) => /* @__PURE__ */ jsxs(ButtonContent, {
|
|
240
288
|
pending: renderProps.isPending,
|
|
289
|
+
wrap: wrap === true,
|
|
241
290
|
children: [
|
|
242
|
-
|
|
291
|
+
leadingIcon,
|
|
243
292
|
typeof children === "function" ? children(renderProps) : children,
|
|
244
293
|
endIcon
|
|
245
294
|
]
|