@seekalfred/primitives 0.6.0 → 0.7.1
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 +19 -11
- package/dist/activity-heatmap/activity-heatmap.d.ts +92 -0
- package/dist/activity-heatmap/activity-heatmap.js +699 -0
- package/dist/activity-heatmap/activity-heatmap.js.map +1 -0
- package/dist/activity-heatmap/index.d.ts +2 -0
- package/dist/activity-heatmap/index.js +2 -0
- package/dist/alert/alert.d.ts +5 -1
- package/dist/alert/alert.js +68 -7
- package/dist/alert/alert.js.map +1 -1
- package/dist/alert-dialog/alert-dialog.d.ts +45 -18
- package/dist/alert-dialog/alert-dialog.js +128 -9
- package/dist/alert-dialog/alert-dialog.js.map +1 -1
- package/dist/alert-dialog/index.d.ts +2 -2
- package/dist/alert-dialog/index.js +2 -2
- package/dist/animated-counter/animated-counter.d.ts +38 -0
- package/dist/animated-counter/animated-counter.js +230 -0
- package/dist/animated-counter/animated-counter.js.map +1 -0
- package/dist/animated-counter/index.d.ts +2 -0
- package/dist/animated-counter/index.js +2 -0
- package/dist/announcement-bar/announcement-bar.d.ts +67 -0
- package/dist/announcement-bar/announcement-bar.js +364 -0
- package/dist/announcement-bar/announcement-bar.js.map +1 -0
- package/dist/announcement-bar/index.d.ts +2 -0
- package/dist/announcement-bar/index.js +2 -0
- package/dist/badge/badge.d.ts +1 -1
- package/dist/bar-chart/bar-chart.d.ts +51 -0
- package/dist/bar-chart/bar-chart.js +565 -0
- package/dist/bar-chart/bar-chart.js.map +1 -0
- package/dist/bar-chart/index.d.ts +2 -0
- package/dist/bar-chart/index.js +2 -0
- package/dist/breadcrumb/breadcrumb.d.ts +2 -2
- package/dist/breadcrumb/breadcrumb.js +12 -3
- package/dist/breadcrumb/breadcrumb.js.map +1 -1
- package/dist/brush-chart/brush-chart.d.ts +64 -0
- package/dist/brush-chart/brush-chart.js +1056 -0
- package/dist/brush-chart/brush-chart.js.map +1 -0
- package/dist/brush-chart/index.d.ts +2 -0
- package/dist/brush-chart/index.js +2 -0
- package/dist/button/button.d.ts +2 -2
- package/dist/button/button.js +31 -21
- package/dist/button/button.js.map +1 -1
- package/dist/button-group/button-group.js +3 -4
- package/dist/button-group/button-group.js.map +1 -1
- package/dist/card/card.js +1 -1
- package/dist/card/card.js.map +1 -1
- package/dist/card-stack/card-stack.d.ts +54 -0
- package/dist/card-stack/card-stack.js +492 -0
- package/dist/card-stack/card-stack.js.map +1 -0
- package/dist/card-stack/index.d.ts +2 -0
- package/dist/card-stack/index.js +2 -0
- package/dist/carousel/carousel.d.ts +56 -0
- package/dist/carousel/carousel.js +389 -0
- package/dist/carousel/carousel.js.map +1 -0
- package/dist/carousel/index.d.ts +2 -0
- package/dist/carousel/index.js +2 -0
- package/dist/checkbox/checkbox.js +4 -4
- package/dist/checkbox/checkbox.js.map +1 -1
- package/dist/chip-group/chip-group.d.ts +37 -0
- package/dist/chip-group/chip-group.js +148 -0
- package/dist/chip-group/chip-group.js.map +1 -0
- package/dist/chip-group/index.d.ts +2 -0
- package/dist/chip-group/index.js +2 -0
- package/dist/countdown/countdown.d.ts +45 -0
- package/dist/countdown/countdown.js +298 -0
- package/dist/countdown/countdown.js.map +1 -0
- package/dist/countdown/index.d.ts +2 -0
- package/dist/countdown/index.js +2 -0
- package/dist/date-picker/picker-parts.js +1 -1
- package/dist/date-picker/picker-parts.js.map +1 -1
- package/dist/dialog/dialog.js +1 -1
- package/dist/dialog/dialog.js.map +1 -1
- package/dist/donut-chart/donut-chart.d.ts +64 -0
- package/dist/donut-chart/donut-chart.js +576 -0
- package/dist/donut-chart/donut-chart.js.map +1 -0
- package/dist/donut-chart/index.d.ts +2 -0
- package/dist/donut-chart/index.js +2 -0
- package/dist/empty-state/empty-state.d.ts +21 -10
- package/dist/empty-state/empty-state.js +32 -26
- package/dist/empty-state/empty-state.js.map +1 -1
- package/dist/empty-state/index.d.ts +2 -2
- package/dist/empty-state/index.js +2 -2
- package/dist/file-drop-zone/file-drop-zone.js +1 -1
- package/dist/file-drop-zone/file-drop-zone.js.map +1 -1
- package/dist/filter-bar/filter-bar.d.ts +47 -26
- package/dist/filter-bar/filter-bar.js +272 -156
- package/dist/filter-bar/filter-bar.js.map +1 -1
- package/dist/gauge/gauge.d.ts +45 -0
- package/dist/gauge/gauge.js +219 -0
- package/dist/gauge/gauge.js.map +1 -0
- package/dist/gauge/index.d.ts +2 -0
- package/dist/gauge/index.js +2 -0
- package/dist/in-view-title/in-view-title.d.ts +33 -0
- package/dist/in-view-title/in-view-title.js +119 -0
- package/dist/in-view-title/in-view-title.js.map +1 -0
- package/dist/in-view-title/index.d.ts +2 -0
- package/dist/in-view-title/index.js +2 -0
- package/dist/index.d.ts +49 -6
- package/dist/index.js +48 -8
- package/dist/lib/cn.js +11 -1
- package/dist/lib/cn.js.map +1 -1
- package/dist/lib/field-message.js +28 -10
- package/dist/lib/field-message.js.map +1 -1
- package/dist/lib/field-surface.js +9 -8
- package/dist/lib/field-surface.js.map +1 -1
- package/dist/lib/flag-emoji.js +50 -0
- package/dist/lib/flag-emoji.js.map +1 -0
- package/dist/lib/flip.js +11 -3
- package/dist/lib/flip.js.map +1 -1
- package/dist/lib/menu-highlight.js +64 -0
- package/dist/lib/menu-highlight.js.map +1 -0
- package/dist/lib/motion.js +9 -2
- package/dist/lib/motion.js.map +1 -1
- package/dist/lib/rolling-value.js +1 -1
- package/dist/lib/rolling-value.js.map +1 -1
- package/dist/lib/spring-tween.js +500 -0
- package/dist/lib/spring-tween.js.map +1 -0
- package/dist/lib/swap-text.js +3 -1
- package/dist/lib/swap-text.js.map +1 -1
- package/dist/line-chart/index.d.ts +2 -0
- package/dist/line-chart/index.js +2 -0
- package/dist/line-chart/line-chart.d.ts +76 -0
- package/dist/line-chart/line-chart.js +611 -0
- package/dist/line-chart/line-chart.js.map +1 -0
- package/dist/mention-input/index.d.ts +2 -0
- package/dist/mention-input/index.js +2 -0
- package/dist/mention-input/mention-input.d.ts +98 -0
- package/dist/mention-input/mention-input.js +576 -0
- package/dist/mention-input/mention-input.js.map +1 -0
- package/dist/menu/menu.d.ts +2 -0
- package/dist/menu/menu.js +23 -12
- package/dist/menu/menu.js.map +1 -1
- package/dist/money-input/index.d.ts +2 -0
- package/dist/money-input/index.js +2 -0
- package/dist/money-input/money-input.d.ts +65 -0
- package/dist/money-input/money-input.js +607 -0
- package/dist/money-input/money-input.js.map +1 -0
- package/dist/morph-select/index.d.ts +2 -0
- package/dist/morph-select/index.js +2 -0
- package/dist/morph-select/morph-select.d.ts +71 -0
- package/dist/morph-select/morph-select.js +693 -0
- package/dist/morph-select/morph-select.js.map +1 -0
- package/dist/multi-select/index.d.ts +2 -0
- package/dist/multi-select/index.js +2 -0
- package/dist/multi-select/multi-select.d.ts +36 -0
- package/dist/multi-select/multi-select.js +152 -0
- package/dist/multi-select/multi-select.js.map +1 -0
- package/dist/number-field/index.d.ts +2 -0
- package/dist/number-field/index.js +2 -0
- package/dist/number-field/number-field.d.ts +42 -0
- package/dist/number-field/number-field.js +199 -0
- package/dist/number-field/number-field.js.map +1 -0
- package/dist/onboarding-checklist/index.d.ts +2 -0
- package/dist/onboarding-checklist/index.js +2 -0
- package/dist/onboarding-checklist/onboarding-checklist.d.ts +55 -0
- package/dist/onboarding-checklist/onboarding-checklist.js +577 -0
- package/dist/onboarding-checklist/onboarding-checklist.js.map +1 -0
- package/dist/password-field/password-field.js +2 -2
- package/dist/password-field/password-field.js.map +1 -1
- package/dist/phone-input/index.d.ts +3 -0
- package/dist/phone-input/index.js +3 -0
- package/dist/phone-input/phone-countries.d.ts +29 -0
- package/dist/phone-input/phone-countries.js +170 -0
- package/dist/phone-input/phone-countries.js.map +1 -0
- package/dist/phone-input/phone-input.d.ts +66 -0
- package/dist/phone-input/phone-input.js +440 -0
- package/dist/phone-input/phone-input.js.map +1 -0
- package/dist/popover/popover.d.ts +12 -0
- package/dist/popover/popover.js +31 -7
- package/dist/popover/popover.js.map +1 -1
- package/dist/progress/progress.js +1 -1
- package/dist/radio-group/radio-group.js +1 -1
- package/dist/radio-group/radio-group.js.map +1 -1
- package/dist/reactions/index.d.ts +2 -0
- package/dist/reactions/index.js +2 -0
- package/dist/reactions/reactions.d.ts +50 -0
- package/dist/reactions/reactions.js +315 -0
- package/dist/reactions/reactions.js.map +1 -0
- package/dist/rich-text-editor/index.d.ts +3 -0
- package/dist/rich-text-editor/index.js +2 -0
- package/dist/rich-text-editor/rich-text-editor.d.ts +70 -0
- package/dist/rich-text-editor/rich-text-editor.js +909 -0
- package/dist/rich-text-editor/rich-text-editor.js.map +1 -0
- package/dist/rich-text-editor/rich-text-engine.d.ts +16 -0
- package/dist/rich-text-editor/rich-text-engine.js +366 -0
- package/dist/rich-text-editor/rich-text-engine.js.map +1 -0
- package/dist/rich-text-editor/rich-text-html.js +174 -0
- package/dist/rich-text-editor/rich-text-html.js.map +1 -0
- package/dist/rich-text-editor/rich-text-icons.js +43 -0
- package/dist/rich-text-editor/rich-text-icons.js.map +1 -0
- package/dist/ridgeline/index.d.ts +2 -0
- package/dist/ridgeline/index.js +2 -0
- package/dist/ridgeline/ridgeline.d.ts +55 -0
- package/dist/ridgeline/ridgeline.js +701 -0
- package/dist/ridgeline/ridgeline.js.map +1 -0
- package/dist/scroll-area/index.d.ts +2 -2
- package/dist/scroll-area/index.js +2 -2
- package/dist/scroll-area/scroll-area.d.ts +68 -31
- package/dist/scroll-area/scroll-area.js +208 -59
- package/dist/scroll-area/scroll-area.js.map +1 -1
- package/dist/scrub-input/evaluate.d.ts +14 -0
- package/dist/scrub-input/evaluate.js +72 -0
- package/dist/scrub-input/evaluate.js.map +1 -0
- package/dist/scrub-input/index.d.ts +3 -0
- package/dist/scrub-input/index.js +3 -0
- package/dist/scrub-input/scrub-input.d.ts +74 -0
- package/dist/scrub-input/scrub-input.js +486 -0
- package/dist/scrub-input/scrub-input.js.map +1 -0
- package/dist/search-field/search-field.d.ts +2 -1
- package/dist/search-field/search-field.js +4 -4
- package/dist/search-field/search-field.js.map +1 -1
- package/dist/select/select.d.ts +3 -1
- package/dist/select/select.js +20 -8
- package/dist/select/select.js.map +1 -1
- package/dist/separator/separator.d.ts +1 -1
- package/dist/sheet/sheet.js +2 -1
- package/dist/sheet/sheet.js.map +1 -1
- package/dist/shortcut-recorder/index.d.ts +3 -0
- package/dist/shortcut-recorder/index.js +3 -0
- package/dist/shortcut-recorder/shortcut-model.d.ts +27 -0
- package/dist/shortcut-recorder/shortcut-model.js +206 -0
- package/dist/shortcut-recorder/shortcut-model.js.map +1 -0
- package/dist/shortcut-recorder/shortcut-recorder.d.ts +93 -0
- package/dist/shortcut-recorder/shortcut-recorder.js +489 -0
- package/dist/shortcut-recorder/shortcut-recorder.js.map +1 -0
- package/dist/slider/index.d.ts +2 -2
- package/dist/slider/slider.d.ts +46 -14
- package/dist/slider/slider.js +151 -67
- package/dist/slider/slider.js.map +1 -1
- package/dist/slope-chart/index.d.ts +2 -0
- package/dist/slope-chart/index.js +2 -0
- package/dist/slope-chart/slope-chart.d.ts +54 -0
- package/dist/slope-chart/slope-chart.js +568 -0
- package/dist/slope-chart/slope-chart.js.map +1 -0
- package/dist/sparkline/index.d.ts +2 -0
- package/dist/sparkline/index.js +2 -0
- package/dist/sparkline/sparkline.d.ts +46 -0
- package/dist/sparkline/sparkline.js +390 -0
- package/dist/sparkline/sparkline.js.map +1 -0
- package/dist/split-bar/index.d.ts +2 -0
- package/dist/split-bar/index.js +2 -0
- package/dist/split-bar/split-bar.d.ts +62 -0
- package/dist/split-bar/split-bar.js +513 -0
- package/dist/split-bar/split-bar.js.map +1 -0
- package/dist/split-button/split-button.d.ts +1 -1
- package/dist/split-button/split-button.js +12 -11
- package/dist/split-button/split-button.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 +24 -4
- package/dist/stat-card/stat-card.js +114 -17
- package/dist/stat-card/stat-card.js.map +1 -1
- package/dist/stepper/index.d.ts +2 -0
- package/dist/stepper/index.js +2 -0
- package/dist/stepper/stepper.d.ts +51 -0
- package/dist/stepper/stepper.js +215 -0
- package/dist/stepper/stepper.js.map +1 -0
- package/dist/streamgraph/index.d.ts +2 -0
- package/dist/streamgraph/index.js +2 -0
- package/dist/streamgraph/streamgraph.d.ts +70 -0
- package/dist/streamgraph/streamgraph.js +613 -0
- package/dist/streamgraph/streamgraph.js.map +1 -0
- package/dist/styles.css +1 -1
- package/dist/swipe-actions/index.d.ts +2 -0
- package/dist/swipe-actions/index.js +2 -0
- package/dist/swipe-actions/swipe-actions.d.ts +67 -0
- package/dist/swipe-actions/swipe-actions.js +552 -0
- package/dist/swipe-actions/swipe-actions.js.map +1 -0
- package/dist/switch/switch.js +2 -2
- package/dist/switch/switch.js.map +1 -1
- package/dist/table/index.d.ts +2 -2
- package/dist/table/index.js +2 -2
- package/dist/table/table.d.ts +56 -4
- package/dist/table/table.js +340 -165
- package/dist/table/table.js.map +1 -1
- package/dist/tabs/tabs.js +2 -2
- package/dist/tabs/tabs.js.map +1 -1
- package/dist/tag-input/index.d.ts +2 -0
- package/dist/tag-input/index.js +2 -0
- package/dist/tag-input/tag-input.d.ts +40 -0
- package/dist/tag-input/tag-input.js +269 -0
- package/dist/tag-input/tag-input.js.map +1 -0
- package/dist/text-morph/index.d.ts +2 -0
- package/dist/text-morph/index.js +2 -0
- package/dist/text-morph/text-morph.d.ts +23 -0
- package/dist/text-morph/text-morph.js +21 -0
- package/dist/text-morph/text-morph.js.map +1 -0
- package/dist/text-reveal/index.d.ts +2 -0
- package/dist/text-reveal/index.js +2 -0
- package/dist/text-reveal/text-reveal.d.ts +27 -0
- package/dist/text-reveal/text-reveal.js +51 -0
- package/dist/text-reveal/text-reveal.js.map +1 -0
- package/dist/text-shimmer/index.d.ts +2 -0
- package/dist/text-shimmer/index.js +2 -0
- package/dist/text-shimmer/text-shimmer.d.ts +29 -0
- package/dist/text-shimmer/text-shimmer.js +29 -0
- package/dist/text-shimmer/text-shimmer.js.map +1 -0
- package/dist/time-picker/time-picker.js +2 -2
- package/dist/time-picker/time-picker.js.map +1 -1
- package/dist/toast/index.d.ts +2 -2
- package/dist/toast/index.js +2 -2
- package/dist/toast/toast.d.ts +6 -0
- package/dist/toast/toast.js +82 -40
- package/dist/toast/toast.js.map +1 -1
- package/dist/tooltip/tooltip.d.ts +9 -2
- package/dist/tooltip/tooltip.js +7 -7
- package/dist/tooltip/tooltip.js.map +1 -1
- package/dist/treemap/index.d.ts +2 -0
- package/dist/treemap/index.js +2 -0
- package/dist/treemap/treemap.d.ts +53 -0
- package/dist/treemap/treemap.js +699 -0
- package/dist/treemap/treemap.js.map +1 -0
- package/dist/usage-meter/index.d.ts +2 -0
- package/dist/usage-meter/index.js +2 -0
- package/dist/usage-meter/usage-meter.d.ts +50 -0
- package/dist/usage-meter/usage-meter.js +440 -0
- package/dist/usage-meter/usage-meter.js.map +1 -0
- package/dist/waffle-chart/index.d.ts +2 -0
- package/dist/waffle-chart/index.js +2 -0
- package/dist/waffle-chart/waffle-chart.d.ts +57 -0
- package/dist/waffle-chart/waffle-chart.js +426 -0
- package/dist/waffle-chart/waffle-chart.js.map +1 -0
- package/package.json +165 -3
|
@@ -0,0 +1,565 @@
|
|
|
1
|
+
"use client";
|
|
2
|
+
import { cn } from "../lib/cn.js";
|
|
3
|
+
import { mergeRefs } from "../lib/merge-refs.js";
|
|
4
|
+
import { prefersReducedMotion, useIsomorphicLayoutEffect } from "../lib/motion.js";
|
|
5
|
+
import { SwapText } from "../lib/swap-text.js";
|
|
6
|
+
import { MORPH, SMOOTH, SNAPPY, live, retarget } from "../lib/spring-tween.js";
|
|
7
|
+
import { forwardRef, useCallback, useEffect, useId, useMemo, useRef, useState } from "react";
|
|
8
|
+
import { jsx, jsxs } from "react/jsx-runtime";
|
|
9
|
+
//#region src/bar-chart/bar-chart.tsx
|
|
10
|
+
/** Room above the top gridline, the share of each slot a bar fills, its widest size, and the radius of its data end. */
|
|
11
|
+
const TOP = 12;
|
|
12
|
+
const FILL = .58;
|
|
13
|
+
const MAX_BAR = 28;
|
|
14
|
+
const RADIUS = 4;
|
|
15
|
+
/** Stagger between bars on the first reveal (seconds in the source: .035 per bar, at most .36 in all). */
|
|
16
|
+
const STAGGER_MS = 35;
|
|
17
|
+
const GROUPED = new Intl.NumberFormat("en-US", { maximumFractionDigits: 0 });
|
|
18
|
+
const clamp = (value, low, high) => Math.min(high, Math.max(low, value));
|
|
19
|
+
/** visualDuration .24s, no bounce: a leaving bar sinks a little faster than a bar grows. */
|
|
20
|
+
const COLLAPSE = {
|
|
21
|
+
curve: [
|
|
22
|
+
0,
|
|
23
|
+
.0484,
|
|
24
|
+
.1552,
|
|
25
|
+
.2816,
|
|
26
|
+
.4069,
|
|
27
|
+
.5207,
|
|
28
|
+
.6189,
|
|
29
|
+
.7009,
|
|
30
|
+
.7676,
|
|
31
|
+
.821,
|
|
32
|
+
.8631,
|
|
33
|
+
.8959,
|
|
34
|
+
.9213,
|
|
35
|
+
.9408,
|
|
36
|
+
.9556,
|
|
37
|
+
.9668,
|
|
38
|
+
.9753,
|
|
39
|
+
.9816,
|
|
40
|
+
.9864,
|
|
41
|
+
.9899,
|
|
42
|
+
.9926,
|
|
43
|
+
.9945,
|
|
44
|
+
.996,
|
|
45
|
+
.9971,
|
|
46
|
+
.9978,
|
|
47
|
+
.9984,
|
|
48
|
+
.9988,
|
|
49
|
+
.9992,
|
|
50
|
+
.9994,
|
|
51
|
+
1
|
|
52
|
+
],
|
|
53
|
+
ms: 464
|
|
54
|
+
};
|
|
55
|
+
/** Clean gridlines: the smallest step of 1, 2, 3 or 5 that covers the data in four rows or fewer. */
|
|
56
|
+
function scaleFor(max) {
|
|
57
|
+
const safe = Math.max(max, 1);
|
|
58
|
+
const magnitude = 10 ** Math.floor(Math.log10(safe / 4));
|
|
59
|
+
for (const factor of [
|
|
60
|
+
1,
|
|
61
|
+
2,
|
|
62
|
+
3,
|
|
63
|
+
5,
|
|
64
|
+
10
|
|
65
|
+
]) {
|
|
66
|
+
const step = factor * magnitude;
|
|
67
|
+
const rows = Math.ceil(safe / step);
|
|
68
|
+
if (rows <= 4) return {
|
|
69
|
+
top: rows * step,
|
|
70
|
+
ticks: Array.from({ length: rows + 1 }, (_, row) => row * step)
|
|
71
|
+
};
|
|
72
|
+
}
|
|
73
|
+
return {
|
|
74
|
+
top: safe,
|
|
75
|
+
ticks: [0, safe]
|
|
76
|
+
};
|
|
77
|
+
}
|
|
78
|
+
/** A column that grows from a square baseline to a softly rounded data end. */
|
|
79
|
+
function barPath(x, w, h, base) {
|
|
80
|
+
const f = (value) => value.toFixed(2);
|
|
81
|
+
if (w <= 0 || h <= .01) return `M${f(x)} ${base}H${f(x + Math.max(w, 0))}Z`;
|
|
82
|
+
const r = Math.min(RADIUS, w / 2, h);
|
|
83
|
+
const top = base - h;
|
|
84
|
+
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`;
|
|
85
|
+
}
|
|
86
|
+
/** Axis labels that fit once the range has settled: every label, else every second, third and so on, counted back from the latest. */
|
|
87
|
+
function fittingLabels(data, width, sizes) {
|
|
88
|
+
const fitting = /* @__PURE__ */ new Map();
|
|
89
|
+
if (!width) return fitting;
|
|
90
|
+
const count = Math.max(1, data.length);
|
|
91
|
+
const labels = data.flatMap((item, index) => {
|
|
92
|
+
const size = item.axisLabel ? sizes[item.axisLabel] : void 0;
|
|
93
|
+
if (size === void 0) return [];
|
|
94
|
+
const natural = width - (data.length - 1 - index + .5) * (width / count) - size / 2;
|
|
95
|
+
return [{
|
|
96
|
+
key: item.key,
|
|
97
|
+
size,
|
|
98
|
+
natural,
|
|
99
|
+
left: clamp(natural, 0, Math.max(0, width - size))
|
|
100
|
+
}];
|
|
101
|
+
}).reverse();
|
|
102
|
+
for (let stride = 1; stride <= labels.length; stride++) {
|
|
103
|
+
const picked = labels.filter((_, rank) => rank % stride === 0);
|
|
104
|
+
if (stride === labels.length || picked.every((label, rank) => rank === 0 || label.left + label.size + 10 <= picked[rank - 1].left)) {
|
|
105
|
+
picked.forEach((label) => fitting.set(label.key, label.left - label.natural));
|
|
106
|
+
break;
|
|
107
|
+
}
|
|
108
|
+
}
|
|
109
|
+
return fitting;
|
|
110
|
+
}
|
|
111
|
+
const BarChart = forwardRef(function BarChart({ data, label, period, unit = "", averageLabel = "Daily average", valueLabel = "Total", categoryLabel = "Day", showAverage = true, height = 176, formatValue = (value) => GROUPED.format(value), className }, ref) {
|
|
112
|
+
const figure = useRef(null);
|
|
113
|
+
const refs = useMemo(() => mergeRefs(ref, figure), [ref]);
|
|
114
|
+
const plot = useRef(null);
|
|
115
|
+
const svg = useRef(null);
|
|
116
|
+
const gutter = useRef(null);
|
|
117
|
+
const axis = useRef(null);
|
|
118
|
+
const ruler = useRef(null);
|
|
119
|
+
const titleId = useId();
|
|
120
|
+
const count = Math.max(data.length, 1);
|
|
121
|
+
const last = data.length - 1;
|
|
122
|
+
const average = data.length ? data.reduce((sum, item) => sum + item.value, 0) / data.length : 0;
|
|
123
|
+
const peak = data.reduce((max, item) => Math.max(max, item.value), 0);
|
|
124
|
+
const { top, ticks } = useMemo(() => scaleFor(peak), [peak]);
|
|
125
|
+
const suffix = unit ? ` ${unit}` : "";
|
|
126
|
+
const [leaving, setLeaving] = useState([]);
|
|
127
|
+
const previous = useRef(data);
|
|
128
|
+
const [changes, setChanges] = useState(0);
|
|
129
|
+
const [active, setActive] = useState(null);
|
|
130
|
+
const signature = data.map((item) => item.key).join("|");
|
|
131
|
+
const [seen, setSeen] = useState(signature);
|
|
132
|
+
if (seen !== signature) {
|
|
133
|
+
setSeen(signature);
|
|
134
|
+
setActive(null);
|
|
135
|
+
setChanges((n) => n + 1);
|
|
136
|
+
}
|
|
137
|
+
const index = active === null ? null : Math.min(active, last);
|
|
138
|
+
const scrubbing = index !== null && last >= 0;
|
|
139
|
+
const shownValue = scrubbing ? data[index].value : average;
|
|
140
|
+
const [trend, setTrend] = useState({
|
|
141
|
+
value: shownValue,
|
|
142
|
+
index,
|
|
143
|
+
valueWay: 1,
|
|
144
|
+
indexWay: 1
|
|
145
|
+
});
|
|
146
|
+
if (trend.value !== shownValue || trend.index !== index) setTrend({
|
|
147
|
+
value: shownValue,
|
|
148
|
+
index,
|
|
149
|
+
valueWay: shownValue === trend.value ? trend.valueWay : shownValue > trend.value ? 1 : -1,
|
|
150
|
+
indexWay: index === null || trend.index === null ? 1 : Math.sign(index - trend.index) || 1
|
|
151
|
+
});
|
|
152
|
+
const width = useRef(0);
|
|
153
|
+
const share = useRef(live(1 / count));
|
|
154
|
+
const scale = useRef(live(top));
|
|
155
|
+
const mean = useRef(live(0));
|
|
156
|
+
const cursor = useRef(live(0));
|
|
157
|
+
const bars = useRef(/* @__PURE__ */ new Map());
|
|
158
|
+
const [shown, setShown] = useState(false);
|
|
159
|
+
const [plotWidth, setPlotWidth] = useState(0);
|
|
160
|
+
const [labelSizes, setLabelSizes] = useState({});
|
|
161
|
+
/** One writer for every drawn attribute, straight onto the elements. */
|
|
162
|
+
const paint = useCallback(() => {
|
|
163
|
+
const root = svg.current;
|
|
164
|
+
const w = width.current;
|
|
165
|
+
if (!root || !w) return;
|
|
166
|
+
const s = scale.current.value || 1;
|
|
167
|
+
const rowY = (value) => Math.round(height - value / s * (height - TOP)) + .5;
|
|
168
|
+
const slot = w * share.current.value;
|
|
169
|
+
const size = Math.min(slot * FILL, MAX_BAR);
|
|
170
|
+
for (const [key, bar] of bars.current) {
|
|
171
|
+
const node = root.querySelector(`[data-bar="${CSS.escape(key)}"]`);
|
|
172
|
+
const center = w - (bar.place.value + .5) * slot;
|
|
173
|
+
node?.setAttribute("d", barPath(center - size / 2, size, Math.max(0, bar.amount.value / s * (height - TOP)), height));
|
|
174
|
+
}
|
|
175
|
+
for (const node of root.querySelectorAll("[data-grid]")) {
|
|
176
|
+
const y = String(rowY(Number(node.dataset.grid)));
|
|
177
|
+
node.setAttribute("y1", y);
|
|
178
|
+
node.setAttribute("y2", y);
|
|
179
|
+
}
|
|
180
|
+
const meanY = rowY(mean.current.value);
|
|
181
|
+
const meanLine = root.querySelector("[data-part=mean]");
|
|
182
|
+
meanLine?.setAttribute("y1", String(meanY));
|
|
183
|
+
meanLine?.setAttribute("y2", String(meanY));
|
|
184
|
+
const cx = String(Math.round(w - (cursor.current.value + .5) * slot) + .5);
|
|
185
|
+
const cross = root.querySelector("[data-part=cursor]");
|
|
186
|
+
cross?.setAttribute("x1", cx);
|
|
187
|
+
cross?.setAttribute("x2", cx);
|
|
188
|
+
for (const node of gutter.current?.querySelectorAll("[data-tick]") ?? []) {
|
|
189
|
+
const y = rowY(Number(node.dataset.tick));
|
|
190
|
+
node.style.translate = `0 ${y}px`;
|
|
191
|
+
node.style.opacity = showAverage ? String(clamp((Math.abs(y - meanY) - 10) / 6, 0, 1)) : "1";
|
|
192
|
+
}
|
|
193
|
+
const meanLabel = gutter.current?.querySelector("[data-part=mean-label]");
|
|
194
|
+
if (meanLabel) {
|
|
195
|
+
meanLabel.style.translate = `0 ${meanY}px`;
|
|
196
|
+
const text = meanLabel.querySelector("[data-part=mean-text]");
|
|
197
|
+
if (text) text.textContent = `Avg ${formatValue(Math.round(mean.current.value))}`;
|
|
198
|
+
}
|
|
199
|
+
for (const node of axis.current?.querySelectorAll("[data-axis]") ?? []) {
|
|
200
|
+
const place = bars.current.get(node.dataset.axis)?.place.value ?? 0;
|
|
201
|
+
node.style.translate = `${w - (place + .5) * slot - Number(node.dataset.size) / 2 + Number(node.dataset.shift)}px 0`;
|
|
202
|
+
}
|
|
203
|
+
}, [
|
|
204
|
+
formatValue,
|
|
205
|
+
height,
|
|
206
|
+
showAverage
|
|
207
|
+
]);
|
|
208
|
+
const go = useCallback((target, to, spring, delay = 0, done) => retarget(target, to, spring, paint, delay, done), [paint]);
|
|
209
|
+
const labelTexts = [...new Set(data.map((item) => item.axisLabel).filter((text) => !!text))].join("\n");
|
|
210
|
+
useIsomorphicLayoutEffect(() => {
|
|
211
|
+
const node = plot.current;
|
|
212
|
+
const measure = ruler.current;
|
|
213
|
+
if (!node || !measure) return;
|
|
214
|
+
const read = () => {
|
|
215
|
+
width.current = node.clientWidth;
|
|
216
|
+
setPlotWidth(node.clientWidth);
|
|
217
|
+
const sizes = {};
|
|
218
|
+
measure.querySelectorAll("[data-text]").forEach((item) => {
|
|
219
|
+
sizes[item.dataset.text ?? ""] = item.offsetWidth;
|
|
220
|
+
});
|
|
221
|
+
setLabelSizes((current) => Object.keys(sizes).every((text) => current[text] === sizes[text]) ? current : sizes);
|
|
222
|
+
paint();
|
|
223
|
+
};
|
|
224
|
+
read();
|
|
225
|
+
if (typeof ResizeObserver === "undefined") return;
|
|
226
|
+
const observer = new ResizeObserver(read);
|
|
227
|
+
observer.observe(node);
|
|
228
|
+
return () => observer.disconnect();
|
|
229
|
+
}, [labelTexts, paint]);
|
|
230
|
+
const fitting = useMemo(() => fittingLabels(data, plotWidth, labelSizes), [
|
|
231
|
+
data,
|
|
232
|
+
plotWidth,
|
|
233
|
+
labelSizes
|
|
234
|
+
]);
|
|
235
|
+
useIsomorphicLayoutEffect(paint);
|
|
236
|
+
useEffect(() => {
|
|
237
|
+
const node = figure.current;
|
|
238
|
+
if (!node || prefersReducedMotion() || typeof IntersectionObserver === "undefined") {
|
|
239
|
+
setShown(true);
|
|
240
|
+
return;
|
|
241
|
+
}
|
|
242
|
+
const observer = new IntersectionObserver(([entry]) => {
|
|
243
|
+
if (!entry?.isIntersecting) return;
|
|
244
|
+
observer.disconnect();
|
|
245
|
+
setShown(true);
|
|
246
|
+
}, { threshold: .35 });
|
|
247
|
+
observer.observe(node);
|
|
248
|
+
return () => observer.disconnect();
|
|
249
|
+
}, []);
|
|
250
|
+
const firstReveal = useRef(true);
|
|
251
|
+
useEffect(() => {
|
|
252
|
+
if (!shown) return;
|
|
253
|
+
const first = firstReveal.current;
|
|
254
|
+
firstReveal.current = false;
|
|
255
|
+
const known = new Set(previous.current.map((item) => item.key));
|
|
256
|
+
previous.current = data;
|
|
257
|
+
const incoming = data.map((item, at) => ({
|
|
258
|
+
key: item.key,
|
|
259
|
+
place: last - at
|
|
260
|
+
})).filter((item) => first || !known.has(item.key)).sort((a, b) => first ? b.place - a.place : a.place - b.place);
|
|
261
|
+
const step = Math.min(STAGGER_MS, (first ? 360 : 320) / Math.max(1, incoming.length));
|
|
262
|
+
const delayOf = new Map(incoming.map((item, rank) => [item.key, rank * step]));
|
|
263
|
+
const keys = new Set(data.map((item) => item.key));
|
|
264
|
+
data.forEach((item, at) => {
|
|
265
|
+
const place = last - at;
|
|
266
|
+
let bar = bars.current.get(item.key);
|
|
267
|
+
if (!bar) {
|
|
268
|
+
bar = {
|
|
269
|
+
place: live(place),
|
|
270
|
+
amount: live(0)
|
|
271
|
+
};
|
|
272
|
+
bars.current.set(item.key, bar);
|
|
273
|
+
}
|
|
274
|
+
go(bar.place, place, SMOOTH);
|
|
275
|
+
const fresh = delayOf.has(item.key);
|
|
276
|
+
go(bar.amount, item.value, fresh ? MORPH : SMOOTH, fresh ? delayOf.get(item.key) : 0);
|
|
277
|
+
});
|
|
278
|
+
const gone = [...bars.current.keys()].filter((key) => !keys.has(key));
|
|
279
|
+
if (gone.length) setLeaving((current) => [.../* @__PURE__ */ new Set([...current, ...gone])]);
|
|
280
|
+
for (const key of gone) {
|
|
281
|
+
const bar = bars.current.get(key);
|
|
282
|
+
go(bar.amount, 0, COLLAPSE, 0, () => {
|
|
283
|
+
bars.current.delete(key);
|
|
284
|
+
setLeaving((current) => current.filter((item) => item !== key));
|
|
285
|
+
});
|
|
286
|
+
}
|
|
287
|
+
go(share.current, 1 / count, SMOOTH);
|
|
288
|
+
go(scale.current, top, SMOOTH);
|
|
289
|
+
go(mean.current, average, SMOOTH, first ? 120 : 0);
|
|
290
|
+
}, [
|
|
291
|
+
shown,
|
|
292
|
+
signature,
|
|
293
|
+
data.map((item) => item.value).join(","),
|
|
294
|
+
top,
|
|
295
|
+
average,
|
|
296
|
+
count
|
|
297
|
+
]);
|
|
298
|
+
const wasScrubbing = useRef(false);
|
|
299
|
+
useEffect(() => {
|
|
300
|
+
if (index === null) {
|
|
301
|
+
wasScrubbing.current = false;
|
|
302
|
+
return;
|
|
303
|
+
}
|
|
304
|
+
const place = last - index;
|
|
305
|
+
if (!wasScrubbing.current) {
|
|
306
|
+
wasScrubbing.current = true;
|
|
307
|
+
cursor.current.stop();
|
|
308
|
+
cursor.current.value = place;
|
|
309
|
+
paint();
|
|
310
|
+
return;
|
|
311
|
+
}
|
|
312
|
+
go(cursor.current, place, SNAPPY);
|
|
313
|
+
}, [
|
|
314
|
+
go,
|
|
315
|
+
index,
|
|
316
|
+
last,
|
|
317
|
+
paint
|
|
318
|
+
]);
|
|
319
|
+
const pointAt = (clientX) => {
|
|
320
|
+
const rect = plot.current?.getBoundingClientRect();
|
|
321
|
+
if (!rect?.width) return last;
|
|
322
|
+
const place = Math.floor((rect.right - clientX) / rect.width * count);
|
|
323
|
+
return clamp(last - place, 0, last);
|
|
324
|
+
};
|
|
325
|
+
const onKeyDown = (event) => {
|
|
326
|
+
if (event.key === "Escape" && scrubbing) {
|
|
327
|
+
event.preventDefault();
|
|
328
|
+
setActive(null);
|
|
329
|
+
return;
|
|
330
|
+
}
|
|
331
|
+
const from = index ?? last + 1;
|
|
332
|
+
const page = Math.min(7, count);
|
|
333
|
+
const next = {
|
|
334
|
+
ArrowLeft: from - 1,
|
|
335
|
+
ArrowDown: from - 1,
|
|
336
|
+
ArrowRight: index === null ? last : from + 1,
|
|
337
|
+
ArrowUp: index === null ? last : from + 1,
|
|
338
|
+
PageDown: from - page,
|
|
339
|
+
PageUp: from + page,
|
|
340
|
+
Home: 0,
|
|
341
|
+
End: last
|
|
342
|
+
}[event.key];
|
|
343
|
+
if (next === void 0 || last < 0) return;
|
|
344
|
+
event.preventDefault();
|
|
345
|
+
setActive(clamp(next, 0, last));
|
|
346
|
+
};
|
|
347
|
+
const scrubbed = scrubbing ? data[index] : null;
|
|
348
|
+
const reading = scrubbed ?? data[last];
|
|
349
|
+
const valueText = reading ? `${reading.label}: ${formatValue(reading.value)}${suffix}` : "No data";
|
|
350
|
+
const highest = data.reduce((best, item) => !best || item.value > best.value ? item : best, null);
|
|
351
|
+
const lowest = data.reduce((best, item) => !best || item.value < best.value ? item : best, null);
|
|
352
|
+
const summary = `${label}, ${period}. ${averageLabel} ${formatValue(Math.round(average))}${suffix}.${highest ? ` Highest ${highest.label}, ${formatValue(highest.value)}${suffix}.` : ""}${lowest && lowest !== highest ? ` Lowest ${lowest.label}, ${formatValue(lowest.value)}${suffix}.` : ""}`;
|
|
353
|
+
const headline = formatValue(scrubbing ? data[index].value : Math.round(average));
|
|
354
|
+
const barKeys = [...data.map((item) => item.key), ...leaving.filter((key) => !data.some((item) => item.key === key))];
|
|
355
|
+
return /* @__PURE__ */ jsxs("figure", {
|
|
356
|
+
ref: refs,
|
|
357
|
+
"data-slot": "bar-chart",
|
|
358
|
+
"aria-labelledby": titleId,
|
|
359
|
+
className: cn("m-0 grid min-w-0 gap-5 box-border font-sans text-foreground", className),
|
|
360
|
+
children: [
|
|
361
|
+
/* @__PURE__ */ jsxs("figcaption", {
|
|
362
|
+
id: titleId,
|
|
363
|
+
className: "sr-only",
|
|
364
|
+
children: [
|
|
365
|
+
label,
|
|
366
|
+
", ",
|
|
367
|
+
period
|
|
368
|
+
]
|
|
369
|
+
}),
|
|
370
|
+
/* @__PURE__ */ jsxs("div", {
|
|
371
|
+
"aria-hidden": "true",
|
|
372
|
+
className: "grid min-w-0 gap-0.5",
|
|
373
|
+
children: [
|
|
374
|
+
/* @__PURE__ */ jsx("span", {
|
|
375
|
+
className: "block min-h-5 text-sm text-text-secondary",
|
|
376
|
+
children: /* @__PURE__ */ jsx(SwapText, {
|
|
377
|
+
swapKey: scrubbing ? valueLabel : averageLabel,
|
|
378
|
+
motion: "rise",
|
|
379
|
+
className: "block",
|
|
380
|
+
children: scrubbing ? valueLabel : averageLabel
|
|
381
|
+
})
|
|
382
|
+
}),
|
|
383
|
+
/* @__PURE__ */ jsxs("span", {
|
|
384
|
+
"data-slot": "bar-chart-value",
|
|
385
|
+
className: "flex min-w-0 items-baseline gap-1.5 text-h2 font-medium tabular-nums",
|
|
386
|
+
children: [/* @__PURE__ */ jsx(SwapText, {
|
|
387
|
+
swapKey: headline,
|
|
388
|
+
dir: trend.valueWay,
|
|
389
|
+
motion: "rise",
|
|
390
|
+
children: headline
|
|
391
|
+
}), unit ? /* @__PURE__ */ jsx("span", {
|
|
392
|
+
className: "text-base font-normal text-text-secondary",
|
|
393
|
+
children: unit
|
|
394
|
+
}) : null]
|
|
395
|
+
}),
|
|
396
|
+
/* @__PURE__ */ jsx("span", {
|
|
397
|
+
className: "block min-h-5 text-sm text-muted-foreground",
|
|
398
|
+
children: /* @__PURE__ */ jsx(SwapText, {
|
|
399
|
+
swapKey: scrubbed ? scrubbed.label : period,
|
|
400
|
+
dir: scrubbing ? trend.indexWay : 1,
|
|
401
|
+
motion: "rise",
|
|
402
|
+
className: "block",
|
|
403
|
+
children: scrubbed ? scrubbed.label : period
|
|
404
|
+
})
|
|
405
|
+
})
|
|
406
|
+
]
|
|
407
|
+
}),
|
|
408
|
+
/* @__PURE__ */ jsxs("div", {
|
|
409
|
+
"data-slot": "bar-chart-chart",
|
|
410
|
+
"data-scrubbing": scrubbing || void 0,
|
|
411
|
+
"data-shown": shown || void 0,
|
|
412
|
+
className: "bar-chart-frame",
|
|
413
|
+
children: [
|
|
414
|
+
/* @__PURE__ */ jsx("div", {
|
|
415
|
+
ref: plot,
|
|
416
|
+
className: "relative min-w-0 [grid-area:1/1]",
|
|
417
|
+
style: { height },
|
|
418
|
+
children: /* @__PURE__ */ jsxs("svg", {
|
|
419
|
+
ref: svg,
|
|
420
|
+
width: "100%",
|
|
421
|
+
height,
|
|
422
|
+
role: "img",
|
|
423
|
+
"aria-label": summary,
|
|
424
|
+
className: "block overflow-hidden",
|
|
425
|
+
children: [
|
|
426
|
+
ticks.slice(1).map((value) => /* @__PURE__ */ jsx("line", {
|
|
427
|
+
"data-grid": value,
|
|
428
|
+
className: "line-chart-grid motion-safe:animate-fade-in",
|
|
429
|
+
x1: 0,
|
|
430
|
+
x2: "100%"
|
|
431
|
+
}, value)),
|
|
432
|
+
/* @__PURE__ */ jsx("line", {
|
|
433
|
+
"data-part": "cursor",
|
|
434
|
+
className: "line-chart-crosshair",
|
|
435
|
+
y1: TOP,
|
|
436
|
+
y2: height
|
|
437
|
+
}),
|
|
438
|
+
barKeys.map((key) => /* @__PURE__ */ jsx("path", {
|
|
439
|
+
"data-bar": key,
|
|
440
|
+
"data-active": scrubbing && data[index]?.key === key || void 0,
|
|
441
|
+
className: "bar-chart-bar"
|
|
442
|
+
}, key)),
|
|
443
|
+
/* @__PURE__ */ jsx("line", {
|
|
444
|
+
className: "line-chart-baseline",
|
|
445
|
+
x1: 0,
|
|
446
|
+
x2: "100%",
|
|
447
|
+
y1: height - .5,
|
|
448
|
+
y2: height - .5
|
|
449
|
+
}),
|
|
450
|
+
showAverage ? /* @__PURE__ */ jsx("line", {
|
|
451
|
+
"data-part": "mean",
|
|
452
|
+
className: "bar-chart-mean",
|
|
453
|
+
x1: 0,
|
|
454
|
+
x2: "100%"
|
|
455
|
+
}) : null
|
|
456
|
+
]
|
|
457
|
+
})
|
|
458
|
+
}),
|
|
459
|
+
/* @__PURE__ */ jsxs("div", {
|
|
460
|
+
ref: gutter,
|
|
461
|
+
"aria-hidden": "true",
|
|
462
|
+
className: "relative min-w-0 [grid-area:1/2]",
|
|
463
|
+
children: [ticks.map((value) => /* @__PURE__ */ jsx("span", {
|
|
464
|
+
"data-tick": value,
|
|
465
|
+
className: "line-chart-tick motion-safe:animate-fade-in",
|
|
466
|
+
children: /* @__PURE__ */ jsx("span", {
|
|
467
|
+
className: "block -translate-y-1/2 text-xs leading-none tabular-nums text-muted-foreground",
|
|
468
|
+
children: formatValue(value)
|
|
469
|
+
})
|
|
470
|
+
}, value)), showAverage ? /* @__PURE__ */ jsx("span", {
|
|
471
|
+
"data-part": "mean-label",
|
|
472
|
+
className: "line-chart-tick bar-chart-mean-label",
|
|
473
|
+
children: /* @__PURE__ */ jsx("span", {
|
|
474
|
+
"data-part": "mean-text",
|
|
475
|
+
className: "block -translate-y-1/2 text-xs leading-none font-medium tabular-nums text-foreground"
|
|
476
|
+
})
|
|
477
|
+
}) : null]
|
|
478
|
+
}),
|
|
479
|
+
/* @__PURE__ */ jsxs("div", {
|
|
480
|
+
ref: axis,
|
|
481
|
+
"aria-hidden": "true",
|
|
482
|
+
className: "relative min-w-0 overflow-hidden [grid-area:2/1]",
|
|
483
|
+
children: [data.map((item) => item.axisLabel && fitting.has(item.key) ? /* @__PURE__ */ jsx("span", {
|
|
484
|
+
"data-axis": item.key,
|
|
485
|
+
"data-size": labelSizes[item.axisLabel] ?? 0,
|
|
486
|
+
"data-shift": fitting.get(item.key) ?? 0,
|
|
487
|
+
className: "absolute start-0 top-2 whitespace-nowrap text-xs leading-none tabular-nums text-muted-foreground motion-safe:animate-fade-in",
|
|
488
|
+
children: item.axisLabel
|
|
489
|
+
}, `${item.key}:${item.axisLabel}`) : null), /* @__PURE__ */ jsx("span", {
|
|
490
|
+
ref: ruler,
|
|
491
|
+
className: "pointer-events-none invisible absolute start-0 top-0 flex",
|
|
492
|
+
children: labelTexts.split("\n").filter(Boolean).map((text) => /* @__PURE__ */ jsx("span", {
|
|
493
|
+
"data-text": text,
|
|
494
|
+
className: "flex-none whitespace-nowrap text-xs leading-none tabular-nums",
|
|
495
|
+
children: text
|
|
496
|
+
}, text))
|
|
497
|
+
})]
|
|
498
|
+
}),
|
|
499
|
+
/* @__PURE__ */ jsx("div", {
|
|
500
|
+
"data-slot": "bar-chart-scrubber",
|
|
501
|
+
role: "slider",
|
|
502
|
+
tabIndex: 0,
|
|
503
|
+
"aria-label": `${label}, explore by ${categoryLabel.toLowerCase()}`,
|
|
504
|
+
"aria-orientation": "horizontal",
|
|
505
|
+
"aria-valuemin": 1,
|
|
506
|
+
"aria-valuemax": Math.max(1, data.length),
|
|
507
|
+
"aria-valuenow": (index ?? last) + 1,
|
|
508
|
+
"aria-valuetext": valueText,
|
|
509
|
+
onPointerDown: (event) => {
|
|
510
|
+
if (event.pointerType !== "mouse") event.currentTarget.setPointerCapture?.(event.pointerId);
|
|
511
|
+
setActive(pointAt(event.clientX));
|
|
512
|
+
},
|
|
513
|
+
onPointerMove: (event) => {
|
|
514
|
+
if (event.pointerType === "mouse" || event.buttons) setActive(pointAt(event.clientX));
|
|
515
|
+
},
|
|
516
|
+
onPointerUp: (event) => {
|
|
517
|
+
if (event.pointerType !== "mouse") setActive(null);
|
|
518
|
+
},
|
|
519
|
+
onPointerCancel: () => setActive(null),
|
|
520
|
+
onPointerLeave: (event) => {
|
|
521
|
+
if (event.pointerType === "mouse") setActive(null);
|
|
522
|
+
},
|
|
523
|
+
onKeyDown,
|
|
524
|
+
onBlur: () => setActive(null),
|
|
525
|
+
onFocus: (event) => {
|
|
526
|
+
if (event.currentTarget.matches(":focus-visible") && last >= 0) setActive((current) => current ?? last);
|
|
527
|
+
},
|
|
528
|
+
className: "bar-chart-scrubber"
|
|
529
|
+
})
|
|
530
|
+
]
|
|
531
|
+
}),
|
|
532
|
+
/* @__PURE__ */ jsx("div", {
|
|
533
|
+
className: "sr-only",
|
|
534
|
+
children: /* @__PURE__ */ jsxs("table", { children: [
|
|
535
|
+
/* @__PURE__ */ jsxs("caption", { children: [
|
|
536
|
+
label,
|
|
537
|
+
", ",
|
|
538
|
+
period
|
|
539
|
+
] }),
|
|
540
|
+
/* @__PURE__ */ jsx("thead", { children: /* @__PURE__ */ jsxs("tr", { children: [/* @__PURE__ */ jsx("th", {
|
|
541
|
+
scope: "col",
|
|
542
|
+
children: categoryLabel
|
|
543
|
+
}), /* @__PURE__ */ jsx("th", {
|
|
544
|
+
scope: "col",
|
|
545
|
+
children: label
|
|
546
|
+
})] }) }),
|
|
547
|
+
/* @__PURE__ */ jsx("tbody", { children: data.map((item) => /* @__PURE__ */ jsxs("tr", { children: [/* @__PURE__ */ jsx("th", {
|
|
548
|
+
scope: "row",
|
|
549
|
+
children: item.label
|
|
550
|
+
}), /* @__PURE__ */ jsxs("td", { children: [formatValue(item.value), suffix] })] }, item.key)) })
|
|
551
|
+
] })
|
|
552
|
+
}),
|
|
553
|
+
/* @__PURE__ */ jsx("p", {
|
|
554
|
+
className: "sr-only",
|
|
555
|
+
"aria-live": "polite",
|
|
556
|
+
"aria-atomic": "true",
|
|
557
|
+
children: changes ? `${period}. ${averageLabel} ${formatValue(Math.round(average))}${suffix}.` : ""
|
|
558
|
+
})
|
|
559
|
+
]
|
|
560
|
+
});
|
|
561
|
+
});
|
|
562
|
+
//#endregion
|
|
563
|
+
export { BarChart };
|
|
564
|
+
|
|
565
|
+
//# sourceMappingURL=bar-chart.js.map
|
|
@@ -0,0 +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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"}
|
|
@@ -13,8 +13,8 @@ export declare const breadcrumbLinkVariants: (props?: import("class-variance-aut
|
|
|
13
13
|
* @example
|
|
14
14
|
* <Breadcrumbs>
|
|
15
15
|
* <BreadcrumbItem href="/">Home</BreadcrumbItem>
|
|
16
|
-
* <BreadcrumbItem href="/design-thinking">Design
|
|
17
|
-
* <BreadcrumbItem>User
|
|
16
|
+
* <BreadcrumbItem href="/design-thinking">Design thinking</BreadcrumbItem>
|
|
17
|
+
* <BreadcrumbItem>User personas</BreadcrumbItem>
|
|
18
18
|
* </Breadcrumbs>
|
|
19
19
|
*/
|
|
20
20
|
interface BreadcrumbsProps$1 extends Omit<BreadcrumbsProps<object>, "className" | "style" | "children" | "items" | "dependencies"> {
|