@seekalfred/primitives 0.7.3 → 0.7.4
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +60 -1
- package/dist/alert/alert.d.ts +2 -2
- package/dist/alert-dialog/alert-dialog.d.ts +14 -0
- package/dist/alert-dialog/alert-dialog.js +51 -26
- 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 +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 +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/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/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 +8 -7
- package/dist/index.js +4 -4
- package/dist/input/input.d.ts +7 -0
- package/dist/input/input.js +3 -1
- 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/line-chart/index.d.ts +2 -2
- package/dist/line-chart/line-chart.d.ts +105 -3
- package/dist/line-chart/line-chart.js +183 -44
- package/dist/line-chart/line-chart.js.map +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 +122 -5
- package/dist/multi-select/multi-select.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 +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/select/select.d.ts +9 -0
- package/dist/select/select.js +3 -2
- package/dist/select/select.js.map +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 +114 -4
- package/dist/table/table.js +374 -94
- package/dist/table/table.js.map +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 +3 -1
- package/dist/textarea/textarea.js.map +1 -1
- package/dist/toast/toast.d.ts +2 -2
- package/package.json +3 -3
|
@@ -4,11 +4,13 @@ import { mergeRefs } from "../lib/merge-refs.js";
|
|
|
4
4
|
import { prefersReducedMotion, useIsomorphicLayoutEffect } from "../lib/motion.js";
|
|
5
5
|
import { SMOOTH, SNAPPY, tween } from "../lib/spring-tween.js";
|
|
6
6
|
import { forwardRef, useCallback, useEffect, useId, useMemo, useRef, useState } from "react";
|
|
7
|
-
import { jsx, jsxs } from "react/jsx-runtime";
|
|
7
|
+
import { Fragment as Fragment$1, jsx, jsxs } from "react/jsx-runtime";
|
|
8
8
|
//#region src/line-chart/line-chart.tsx
|
|
9
9
|
/** Room above the top gridline, and the gap between the crosshair and its tooltip. */
|
|
10
10
|
const TOP = 12;
|
|
11
11
|
const GAP = 14;
|
|
12
|
+
/** Between a point and its label. */
|
|
13
|
+
const LABEL_GAP = 6;
|
|
12
14
|
/** The first draw: 480ms x 1.75, slow at both ends. */
|
|
13
15
|
const LINE_CHART_DRAW_MS = 840;
|
|
14
16
|
const PALETTE = [
|
|
@@ -25,9 +27,9 @@ const GRID = Array.from({ length: 241 }, (_, index) => index / 240);
|
|
|
25
27
|
const clamp = (value, low, high) => Math.min(high, Math.max(low, value));
|
|
26
28
|
const colorOf = (line, index) => line.color ?? PALETTE[Math.min(index, PALETTE.length - 1)];
|
|
27
29
|
const clean = (value) => Number(value.toPrecision(12));
|
|
28
|
-
/** Clean gridlines: the smallest step of 1, 2, 2.5 or 5 that covers the data in four rows or fewer, from zero unless the data dips below it. */
|
|
29
|
-
function niceScale(low, high) {
|
|
30
|
-
const lo = Math.min(0, low);
|
|
30
|
+
/** Clean gridlines: the smallest step of 1, 2, 2.5 or 5 that covers the data in four rows or fewer, from zero unless the data dips below it (or `fromZero` is off). */
|
|
31
|
+
function niceScale(low, high, fromZero = true) {
|
|
32
|
+
const lo = fromZero ? Math.min(0, low) : low;
|
|
31
33
|
const hi = Math.max(high, lo + 1);
|
|
32
34
|
const magnitude = 10 ** Math.floor(Math.log10((hi - lo) / 4));
|
|
33
35
|
for (const factor of [
|
|
@@ -56,6 +58,23 @@ function niceScale(low, high) {
|
|
|
56
58
|
ticks: [lo, hi]
|
|
57
59
|
};
|
|
58
60
|
}
|
|
61
|
+
/** The nice scale with either end pinned: a pinned end is a tick, and the nice ticks within half a step of it give way. */
|
|
62
|
+
function pinScale(scale, min, max) {
|
|
63
|
+
if (min === void 0 && max === void 0) return scale;
|
|
64
|
+
const lo = min ?? scale.min;
|
|
65
|
+
const hi = max ?? scale.max;
|
|
66
|
+
if (!(hi > lo)) return scale;
|
|
67
|
+
const step = scale.ticks.length > 1 ? scale.ticks[1] - scale.ticks[0] : hi - lo;
|
|
68
|
+
return {
|
|
69
|
+
min: lo,
|
|
70
|
+
max: hi,
|
|
71
|
+
ticks: [
|
|
72
|
+
lo,
|
|
73
|
+
...scale.ticks.filter((tick) => tick > lo + step / 2 && tick < hi - step / 2),
|
|
74
|
+
hi
|
|
75
|
+
]
|
|
76
|
+
};
|
|
77
|
+
}
|
|
59
78
|
/** The line through every value, sampled densely on x from 0 to 1 in data units. Monotone tangents keep a smooth curve from swinging past the data. */
|
|
60
79
|
function curveFor(values, smooth) {
|
|
61
80
|
if (values.length === 0) return [];
|
|
@@ -101,18 +120,22 @@ function fillGaps(values) {
|
|
|
101
120
|
return values[before] + (values[after] - values[before]) * (index - before) / (after - before);
|
|
102
121
|
});
|
|
103
122
|
}
|
|
104
|
-
/** Where a line with missing values is not drawn: before its first value, after its last, and between two values with missing ones between them. */
|
|
105
|
-
function breaksFor(values) {
|
|
123
|
+
/** Where a line with missing values is not drawn: before its first value, after its last, and (unless it connects across them) between two values with missing ones between them. */
|
|
124
|
+
function breaksFor(values, across = false) {
|
|
106
125
|
const present = values.flatMap((value, index) => value === null ? [] : [index]);
|
|
107
126
|
if (!present.length) return values.length ? [[-Infinity, Infinity]] : [];
|
|
108
127
|
const last = values.length - 1;
|
|
109
128
|
if (last === 0) return [];
|
|
110
129
|
const breaks = [];
|
|
111
130
|
if (present[0] > 0) breaks.push([-Infinity, present[0] / last]);
|
|
112
|
-
for (let at = 1; at < present.length; at++) if (present[at] - present[at - 1] > 1) breaks.push([present[at - 1] / last, present[at] / last]);
|
|
131
|
+
for (let at = 1; at < present.length; at++) if (!across && present[at] - present[at - 1] > 1) breaks.push([present[at - 1] / last, present[at] / last]);
|
|
113
132
|
if (present[present.length - 1] < last) breaks.push([present[present.length - 1] / last, Infinity]);
|
|
114
133
|
return breaks;
|
|
115
134
|
}
|
|
135
|
+
function holesFor(values) {
|
|
136
|
+
const last = values.length - 1;
|
|
137
|
+
return values.flatMap((value, index) => value === null && last > 0 ? [index / last] : []);
|
|
138
|
+
}
|
|
116
139
|
const EDGE = 1e-9;
|
|
117
140
|
/** Radius of a lone point's dot, inside its 2px stroke. */
|
|
118
141
|
const DOT = 1.5;
|
|
@@ -167,7 +190,7 @@ function axisPicks(data, width) {
|
|
|
167
190
|
const stride = Math.ceil(labeled.length / room);
|
|
168
191
|
return labeled.reverse().filter((_, rank) => rank % stride === 0).reverse();
|
|
169
192
|
}
|
|
170
|
-
const LineChart = forwardRef(function LineChart({ data, series, label, unit = "", height = 220, formatValue, formatTick = (value) => COMPACT.format(value), hiddenSeries, defaultHiddenSeries, onHiddenSeriesChange, onActiveChange, loading = false, emptyLabel = "No data for this range", legend, categoryLabel = "Date", curve = "smooth", missing = "zero", missingLabel = "No data", references, className }, ref) {
|
|
193
|
+
const LineChart = forwardRef(function LineChart({ data, series, label, unit = "", height = 220, formatValue, formatTick = (value) => COMPACT.format(value), hiddenSeries, defaultHiddenSeries, onHiddenSeriesChange, onActiveChange, loading = false, emptyLabel = "No data for this range", legend, categoryLabel = "Date", curve = "smooth", missing = "zero", missingLabel = "No data", references, markers, reversed = false, valueDomain, bands, renderTooltip, className }, ref) {
|
|
171
194
|
const figure = useRef(null);
|
|
172
195
|
const refs = useMemo(() => mergeRefs(ref, figure), [ref]);
|
|
173
196
|
const plot = useRef(null);
|
|
@@ -186,7 +209,7 @@ const LineChart = forwardRef(function LineChart({ data, series, label, unit = ""
|
|
|
186
209
|
};
|
|
187
210
|
const visible = series.filter((line) => !hidden.includes(line.key));
|
|
188
211
|
const showLegend = legend ?? series.length > 1;
|
|
189
|
-
const gaps = missing
|
|
212
|
+
const gaps = missing !== "zero";
|
|
190
213
|
const read = (item, key) => {
|
|
191
214
|
const value = item.values[key];
|
|
192
215
|
if (!gaps) return value ?? 0;
|
|
@@ -197,7 +220,8 @@ const LineChart = forwardRef(function LineChart({ data, series, label, unit = ""
|
|
|
197
220
|
const values = data.map((item) => read(item, line.key));
|
|
198
221
|
return [line.key, {
|
|
199
222
|
shape: curveFor(fillGaps(values), curve === "smooth"),
|
|
200
|
-
breaks: breaksFor(values)
|
|
223
|
+
breaks: breaksFor(values, missing === "connect"),
|
|
224
|
+
holes: holesFor(values)
|
|
201
225
|
}];
|
|
202
226
|
})), [signature]);
|
|
203
227
|
let low = Infinity;
|
|
@@ -213,9 +237,12 @@ const LineChart = forwardRef(function LineChart({ data, series, label, unit = ""
|
|
|
213
237
|
low = Math.min(low, reference.value);
|
|
214
238
|
high = Math.max(high, reference.value);
|
|
215
239
|
}
|
|
216
|
-
const
|
|
217
|
-
const
|
|
218
|
-
|
|
240
|
+
const pinMin = Number.isFinite(valueDomain?.min) ? valueDomain.min : void 0;
|
|
241
|
+
const pinMax = Number.isFinite(valueDomain?.max) ? valueDomain.max : void 0;
|
|
242
|
+
const fit = (from, to) => pinScale(niceScale(pinMin ?? from, pinMax ?? to, pinMin === void 0), pinMin, pinMax);
|
|
243
|
+
const range = Number.isFinite(low) ? fit(low, high) : pinMin !== void 0 && pinMax !== void 0 ? fit(pinMin, pinMax) : null;
|
|
244
|
+
const [steady, setSteady] = useState(() => range ?? fit(0, 100));
|
|
245
|
+
if (range && (range.min !== steady.min || range.max !== steady.max || range.ticks.join() !== steady.ticks.join())) setSteady(range);
|
|
219
246
|
const [active, setActive] = useState(null);
|
|
220
247
|
const [seen, setSeen] = useState(signature);
|
|
221
248
|
if (seen !== signature) {
|
|
@@ -239,6 +266,9 @@ const LineChart = forwardRef(function LineChart({ data, series, label, unit = ""
|
|
|
239
266
|
return at < 0 ? void 0 : last > 0 ? at / last : .5;
|
|
240
267
|
};
|
|
241
268
|
const drawnReferences = (references ?? []).filter((reference) => referenceAt(reference) !== void 0);
|
|
269
|
+
const markerIndex = (marker) => data.findIndex((item) => item.key === marker.at);
|
|
270
|
+
const drawnMarkers = (markers ?? []).filter((marker) => markerIndex(marker) >= 0);
|
|
271
|
+
const drawnBands = (bands ?? []).filter((band) => Number.isFinite(band.from) && Number.isFinite(band.to));
|
|
242
272
|
const live = useRef({
|
|
243
273
|
series,
|
|
244
274
|
hidden
|
|
@@ -256,14 +286,15 @@ const LineChart = forwardRef(function LineChart({ data, series, label, unit = ""
|
|
|
256
286
|
if (!w || !root) return;
|
|
257
287
|
const lo = scale.current.min;
|
|
258
288
|
const span = scale.current.max - lo || 1;
|
|
259
|
-
const toY = (value) => TOP + (1 - (value - lo) / span) * (height - TOP);
|
|
289
|
+
const toY = (value) => TOP + (reversed ? (value - lo) / span : 1 - (value - lo) / span) * (height - TOP);
|
|
290
|
+
const base = reversed ? scale.current.max : lo;
|
|
260
291
|
const at = cursor.current;
|
|
261
292
|
const dotYs = [];
|
|
262
293
|
for (const line of live.current.series) {
|
|
263
294
|
const track = tracks.current.get(line.key);
|
|
264
295
|
if (!track) continue;
|
|
265
296
|
const p = track.presence;
|
|
266
|
-
const y = (value) => toY(
|
|
297
|
+
const y = (value) => toY(base + (value - base) * p);
|
|
267
298
|
const group = root.querySelector(`[data-series="${CSS.escape(line.key)}"]`);
|
|
268
299
|
if (track.breaks.length) {
|
|
269
300
|
const paths = pathsFor(track.shape, track.breaks, (x) => x * w, y, height);
|
|
@@ -277,7 +308,7 @@ const LineChart = forwardRef(function LineChart({ data, series, label, unit = ""
|
|
|
277
308
|
if (group) group.style.opacity = String(p);
|
|
278
309
|
const dot = root.querySelector(`[data-dot="${CSS.escape(line.key)}"]`);
|
|
279
310
|
if (dot && track.shape.length) {
|
|
280
|
-
const gap = inBreak(track.breaks, at);
|
|
311
|
+
const gap = inBreak(track.breaks, at) || track.holes.some((x) => Math.abs(x - at) < 1e-6);
|
|
281
312
|
const cy = y(valueAt(track.shape, at));
|
|
282
313
|
dot.setAttribute("cx", (at * w).toFixed(1));
|
|
283
314
|
dot.setAttribute("cy", cy.toFixed(1));
|
|
@@ -292,6 +323,18 @@ const LineChart = forwardRef(function LineChart({ data, series, label, unit = ""
|
|
|
292
323
|
node.setAttribute("y2", yy);
|
|
293
324
|
}
|
|
294
325
|
for (const node of gutter.current?.querySelectorAll("[data-tick]") ?? []) node.style.translate = `0 ${Math.round(toY(Number(node.dataset.tick)))}px`;
|
|
326
|
+
for (const node of root.querySelectorAll("[data-band]")) {
|
|
327
|
+
const ys = [toY(Number(node.dataset.from)), toY(Number(node.dataset.to))];
|
|
328
|
+
const top = clamp(Math.min(...ys), TOP, height);
|
|
329
|
+
const bottom = clamp(Math.max(...ys), TOP, height);
|
|
330
|
+
node.setAttribute("y", String(Math.round(top)));
|
|
331
|
+
node.setAttribute("height", String(Math.max(0, Math.round(bottom) - Math.round(top))));
|
|
332
|
+
const text = plot.current?.querySelector(`[data-band-label="${CSS.escape(node.dataset.band)}"]`);
|
|
333
|
+
if (text) {
|
|
334
|
+
text.style.translate = `0 ${Math.round(top)}px`;
|
|
335
|
+
text.style.visibility = bottom - top >= text.offsetHeight ? "" : "hidden";
|
|
336
|
+
}
|
|
337
|
+
}
|
|
295
338
|
for (const node of root.querySelectorAll("[data-reference-value]")) {
|
|
296
339
|
const yy = String(Math.round(toY(Number(node.dataset.referenceValue))) + .5);
|
|
297
340
|
node.setAttribute("y1", yy);
|
|
@@ -306,6 +349,17 @@ const LineChart = forwardRef(function LineChart({ data, series, label, unit = ""
|
|
|
306
349
|
const { referenceValue, referenceAt } = node.dataset;
|
|
307
350
|
node.style.translate = referenceValue !== void 0 ? `0 ${Math.round(toY(Number(referenceValue)))}px` : `${Math.round(Number(referenceAt) * w)}px 0`;
|
|
308
351
|
}
|
|
352
|
+
for (const node of plot.current?.querySelectorAll("[data-point-label]") ?? []) {
|
|
353
|
+
const track = tracks.current.get(node.dataset.pointLabel);
|
|
354
|
+
if (!track?.shape.length) continue;
|
|
355
|
+
const x = Number(node.dataset.x);
|
|
356
|
+
const cy = toY(base + (valueAt(track.shape, x) - base) * track.presence);
|
|
357
|
+
const lw = node.offsetWidth;
|
|
358
|
+
const lh = node.offsetHeight;
|
|
359
|
+
const top = cy - lh - LABEL_GAP < 0 ? cy + LABEL_GAP : cy - lh - LABEL_GAP;
|
|
360
|
+
node.style.translate = `${Math.round(clamp(x * w - lw / 2, 0, Math.max(0, w - lw)))}px ${Math.round(clamp(top, 0, Math.max(0, height - lh)))}px`;
|
|
361
|
+
node.style.opacity = String(track.presence);
|
|
362
|
+
}
|
|
309
363
|
const cx = Math.round(at * w) + .5;
|
|
310
364
|
const cross = root.querySelector("[data-part=crosshair]");
|
|
311
365
|
cross?.setAttribute("x1", String(cx));
|
|
@@ -319,7 +373,7 @@ const LineChart = forwardRef(function LineChart({ data, series, label, unit = ""
|
|
|
319
373
|
const middle = dotYs.length ? dotYs.reduce((sum, value) => sum + value, 0) / dotYs.length : height / 2;
|
|
320
374
|
bubble.style.translate = `${clamp(x, 0, Math.max(0, w - tw))}px ${clamp(middle - th / 2, 0, Math.max(0, height - th))}px`;
|
|
321
375
|
}
|
|
322
|
-
}, [height]);
|
|
376
|
+
}, [height, reversed]);
|
|
323
377
|
useIsomorphicLayoutEffect(() => {
|
|
324
378
|
const node = plot.current;
|
|
325
379
|
if (!node) return;
|
|
@@ -337,18 +391,20 @@ const LineChart = forwardRef(function LineChart({ data, series, label, unit = ""
|
|
|
337
391
|
useIsomorphicLayoutEffect(paint);
|
|
338
392
|
useEffect(() => {
|
|
339
393
|
const moves = [];
|
|
340
|
-
for (const [key, { shape: target, breaks }] of targets) {
|
|
394
|
+
for (const [key, { shape: target, breaks, holes }] of targets) {
|
|
341
395
|
const track = tracks.current.get(key);
|
|
342
396
|
if (!track) {
|
|
343
397
|
tracks.current.set(key, {
|
|
344
398
|
shape: target,
|
|
345
399
|
breaks,
|
|
400
|
+
holes,
|
|
346
401
|
presence: live.current.hidden.includes(key) ? 0 : 1,
|
|
347
402
|
stop: null
|
|
348
403
|
});
|
|
349
404
|
continue;
|
|
350
405
|
}
|
|
351
406
|
track.breaks = breaks;
|
|
407
|
+
track.holes = holes;
|
|
352
408
|
if (!track.shape.length || !target.length) {
|
|
353
409
|
track.shape = target;
|
|
354
410
|
continue;
|
|
@@ -479,13 +535,66 @@ const LineChart = forwardRef(function LineChart({ data, series, label, unit = ""
|
|
|
479
535
|
const onPointerMove = (event) => {
|
|
480
536
|
if (!empty && (event.pointerType === "mouse" || event.buttons)) setActive(pointAt(event.clientX));
|
|
481
537
|
};
|
|
482
|
-
const
|
|
538
|
+
const formatShort = (value, line) => formatValue ? formatValue(value, line) : GROUPED.format(value);
|
|
539
|
+
const formatNumber = (value, line) => `${formatShort(value, line)}${unit ? ` ${unit}` : ""}`;
|
|
483
540
|
const format = (value, line) => value === null ? missingLabel : formatNumber(value, line);
|
|
484
541
|
const formatReference = (value) => series[0] ? formatNumber(value, series[0]) : `${GROUPED.format(value)}${unit ? ` ${unit}` : ""}`;
|
|
485
542
|
const reading = index === null ? null : data[index];
|
|
486
543
|
const shown = reading ?? data[last];
|
|
487
|
-
const
|
|
488
|
-
const
|
|
544
|
+
const markedHere = index === null ? [] : drawnMarkers.filter((marker) => markerIndex(marker) === index);
|
|
545
|
+
const valueText = reading ? `${reading.label}: ${visible.map((line) => `${line.label} ${format(read(reading, line.key), line)}`).join(", ")}${markedHere.map((marker) => `. ${marker.description ?? marker.label}`).join("")}` : empty ? emptyLabel : `${visible.length} of ${series.length} series shown`;
|
|
546
|
+
const summary = empty ? `${label}. ${emptyLabel}.` : `${label}, ${data[0].label} to ${data[last].label}. ${visible.map((line) => `${line.label}, latest ${format(read(data[last], line.key), line)}${typeof line.endLabel === "string" ? `, ${line.endLabel}` : ""}`).join(". ")}.${drawnReferences.map((reference) => typeof reference.value === "number" ? ` ${reference.label}: ${formatReference(reference.value)}.` : ` ${reference.label}: ${data.find((item) => item.key === reference.at).label}.`).join("")}${drawnMarkers.map((marker) => ` ${marker.description ?? marker.label}: ${data[markerIndex(marker)].label}.`).join("")}${drawnBands.map((band) => ` ${band.description ?? `${band.label}: ${formatReference(Math.min(band.from, band.to))} to ${formatReference(Math.max(band.from, band.to))}`}.`).join("")}`;
|
|
547
|
+
const pointLabels = empty ? [] : series.flatMap((line) => {
|
|
548
|
+
if (!line.pointLabels && !line.endLabel) return [];
|
|
549
|
+
const present = data.flatMap((item, at) => {
|
|
550
|
+
const value = read(item, line.key);
|
|
551
|
+
return value === null ? [] : [{
|
|
552
|
+
at,
|
|
553
|
+
value
|
|
554
|
+
}];
|
|
555
|
+
});
|
|
556
|
+
const end = line.endLabel ? present.at(-1) : void 0;
|
|
557
|
+
return [...(line.pointLabels ? present.filter((point) => point !== end) : []).map((point) => ({
|
|
558
|
+
line,
|
|
559
|
+
...point,
|
|
560
|
+
end: false,
|
|
561
|
+
text: formatShort(point.value, line)
|
|
562
|
+
})), ...end ? [{
|
|
563
|
+
line,
|
|
564
|
+
...end,
|
|
565
|
+
end: true,
|
|
566
|
+
text: typeof line.endLabel === "string" ? line.endLabel : formatShort(end.value, line)
|
|
567
|
+
}] : []];
|
|
568
|
+
});
|
|
569
|
+
const readout = /* @__PURE__ */ jsxs(Fragment$1, { children: [/* @__PURE__ */ jsx("p", {
|
|
570
|
+
className: "m-0 mb-0.5 whitespace-nowrap text-xs tabular-nums text-text-secondary",
|
|
571
|
+
children: shown?.label ?? ""
|
|
572
|
+
}), visible.map((line) => /* @__PURE__ */ jsxs("p", {
|
|
573
|
+
className: "m-0 flex min-w-0 items-center gap-2 text-sm",
|
|
574
|
+
style: { "--series": colorOf(line, series.indexOf(line)) },
|
|
575
|
+
children: [
|
|
576
|
+
/* @__PURE__ */ jsx("span", {
|
|
577
|
+
"data-dashed": line.dashed || void 0,
|
|
578
|
+
className: "chart-tip-swatch"
|
|
579
|
+
}),
|
|
580
|
+
/* @__PURE__ */ jsx("span", {
|
|
581
|
+
className: "min-w-0 flex-1 truncate text-text-secondary",
|
|
582
|
+
children: line.label
|
|
583
|
+
}),
|
|
584
|
+
/* @__PURE__ */ jsx("span", {
|
|
585
|
+
className: "ms-2 flex-none whitespace-nowrap font-medium tabular-nums text-foreground",
|
|
586
|
+
children: shown ? format(read(shown, line.key), line) : format(0, line)
|
|
587
|
+
})
|
|
588
|
+
]
|
|
589
|
+
}, line.key))] });
|
|
590
|
+
const tipContent = renderTooltip && shown ? renderTooltip({
|
|
591
|
+
datum: shown,
|
|
592
|
+
index: index ?? last,
|
|
593
|
+
series: visible,
|
|
594
|
+
values: Object.fromEntries(visible.map((line) => [line.key, read(shown, line.key)])),
|
|
595
|
+
format,
|
|
596
|
+
readout
|
|
597
|
+
}) : readout;
|
|
489
598
|
const picks = axisPicks(data, plotWidth);
|
|
490
599
|
const allHidden = !empty && visible.length === 0;
|
|
491
600
|
return /* @__PURE__ */ jsxs("figure", {
|
|
@@ -570,7 +679,16 @@ const LineChart = forwardRef(function LineChart({ data, series, label, unit = ""
|
|
|
570
679
|
style: { width: drawn ? plotWidth + 16 : 0 }
|
|
571
680
|
})
|
|
572
681
|
}) }),
|
|
573
|
-
|
|
682
|
+
drawnBands.map((band) => /* @__PURE__ */ jsx("rect", {
|
|
683
|
+
"data-band": band.key,
|
|
684
|
+
"data-from": band.from,
|
|
685
|
+
"data-to": band.to,
|
|
686
|
+
"data-tone": band.tone,
|
|
687
|
+
className: "line-chart-band",
|
|
688
|
+
x: 0,
|
|
689
|
+
width: "100%"
|
|
690
|
+
}, band.key)),
|
|
691
|
+
(reversed ? steady.ticks.slice(0, -1) : steady.ticks.slice(1)).map((value) => /* @__PURE__ */ jsx("line", {
|
|
574
692
|
"data-grid": value,
|
|
575
693
|
className: "line-chart-grid",
|
|
576
694
|
x1: 0,
|
|
@@ -586,12 +704,14 @@ const LineChart = forwardRef(function LineChart({ data, series, label, unit = ""
|
|
|
586
704
|
drawnReferences.map((reference) => typeof reference.value === "number" ? /* @__PURE__ */ jsx("line", {
|
|
587
705
|
"data-reference": reference.key,
|
|
588
706
|
"data-reference-value": reference.value,
|
|
707
|
+
"data-tone": reference.tone,
|
|
589
708
|
className: "line-chart-reference",
|
|
590
709
|
x1: 0,
|
|
591
710
|
x2: "100%"
|
|
592
711
|
}, reference.key) : /* @__PURE__ */ jsx("line", {
|
|
593
712
|
"data-reference": reference.key,
|
|
594
713
|
"data-reference-at": referenceAt(reference),
|
|
714
|
+
"data-tone": reference.tone,
|
|
595
715
|
className: "line-chart-reference",
|
|
596
716
|
y1: 8,
|
|
597
717
|
y2: height
|
|
@@ -627,6 +747,14 @@ const LineChart = forwardRef(function LineChart({ data, series, label, unit = ""
|
|
|
627
747
|
}, line.key))
|
|
628
748
|
]
|
|
629
749
|
}),
|
|
750
|
+
drawnBands.map((band) => /* @__PURE__ */ jsx("span", {
|
|
751
|
+
"aria-hidden": "true",
|
|
752
|
+
"data-slot": "line-chart-band-label",
|
|
753
|
+
"data-band-label": band.key,
|
|
754
|
+
"data-tone": band.tone,
|
|
755
|
+
className: "line-chart-band-label",
|
|
756
|
+
children: band.label
|
|
757
|
+
}, band.key)),
|
|
630
758
|
drawnReferences.map((reference) => /* @__PURE__ */ jsx("span", {
|
|
631
759
|
"aria-hidden": "true",
|
|
632
760
|
"data-slot": "line-chart-reference-label",
|
|
@@ -634,35 +762,46 @@ const LineChart = forwardRef(function LineChart({ data, series, label, unit = ""
|
|
|
634
762
|
"data-reference-value": typeof reference.value === "number" ? reference.value : void 0,
|
|
635
763
|
"data-reference-at": typeof reference.value === "number" ? void 0 : referenceAt(reference),
|
|
636
764
|
"data-axis": typeof reference.value === "number" ? "value" : "category",
|
|
765
|
+
"data-tone": reference.tone,
|
|
637
766
|
className: "line-chart-reference-label",
|
|
638
767
|
children: reference.label
|
|
639
768
|
}, reference.key)),
|
|
640
|
-
|
|
769
|
+
drawnMarkers.map((marker) => {
|
|
770
|
+
const share = last > 0 ? markerIndex(marker) / last : .5;
|
|
771
|
+
return /* @__PURE__ */ jsx("span", {
|
|
772
|
+
"aria-hidden": "true",
|
|
773
|
+
"data-slot": "line-chart-marker",
|
|
774
|
+
"data-marker": marker.key,
|
|
775
|
+
"data-tone": marker.tone,
|
|
776
|
+
className: "line-chart-marker",
|
|
777
|
+
style: { left: `${share * 100}%` },
|
|
778
|
+
children: /* @__PURE__ */ jsx("span", {
|
|
779
|
+
className: "line-chart-marker-label",
|
|
780
|
+
style: { translate: `${-share * 100}% 0` },
|
|
781
|
+
children: marker.label
|
|
782
|
+
})
|
|
783
|
+
}, marker.key);
|
|
784
|
+
}),
|
|
785
|
+
pointLabels.map(({ line, at, end, text }) => /* @__PURE__ */ jsxs("span", {
|
|
786
|
+
"aria-hidden": "true",
|
|
787
|
+
"data-slot": end ? "line-chart-end-label" : "line-chart-point-label",
|
|
788
|
+
"data-point-label": line.key,
|
|
789
|
+
"data-x": last > 0 ? at / last : .5,
|
|
790
|
+
className: "line-chart-point-label",
|
|
791
|
+
"data-end": end || void 0,
|
|
792
|
+
style: { "--series": colorOf(line, series.indexOf(line)) },
|
|
793
|
+
children: [end ? /* @__PURE__ */ jsx("span", {
|
|
794
|
+
"data-dashed": line.dashed || void 0,
|
|
795
|
+
className: "chart-tip-swatch"
|
|
796
|
+
}) : null, text]
|
|
797
|
+
}, `${line.key}:${data[at].key}`)),
|
|
798
|
+
/* @__PURE__ */ jsx("div", {
|
|
641
799
|
ref: tip,
|
|
642
800
|
"aria-hidden": "true",
|
|
643
801
|
"data-slot": "line-chart-tooltip",
|
|
802
|
+
"data-empty": !tipContent || void 0,
|
|
644
803
|
className: "line-chart-tooltip",
|
|
645
|
-
children:
|
|
646
|
-
className: "m-0 mb-0.5 whitespace-nowrap text-xs tabular-nums text-text-secondary",
|
|
647
|
-
children: shown?.label ?? ""
|
|
648
|
-
}), visible.map((line) => /* @__PURE__ */ jsxs("p", {
|
|
649
|
-
className: "m-0 flex min-w-0 items-center gap-2 text-sm",
|
|
650
|
-
style: { "--series": colorOf(line, series.indexOf(line)) },
|
|
651
|
-
children: [
|
|
652
|
-
/* @__PURE__ */ jsx("span", {
|
|
653
|
-
"data-dashed": line.dashed || void 0,
|
|
654
|
-
className: "chart-tip-swatch"
|
|
655
|
-
}),
|
|
656
|
-
/* @__PURE__ */ jsx("span", {
|
|
657
|
-
className: "min-w-0 flex-1 truncate text-text-secondary",
|
|
658
|
-
children: line.label
|
|
659
|
-
}),
|
|
660
|
-
/* @__PURE__ */ jsx("span", {
|
|
661
|
-
className: "ms-2 flex-none whitespace-nowrap font-medium tabular-nums text-foreground",
|
|
662
|
-
children: shown ? format(read(shown, line.key), line) : format(0, line)
|
|
663
|
-
})
|
|
664
|
-
]
|
|
665
|
-
}, line.key))]
|
|
804
|
+
children: tipContent
|
|
666
805
|
}),
|
|
667
806
|
(empty || allHidden) && !loading ? /* @__PURE__ */ jsx("p", {
|
|
668
807
|
className: "absolute inset-0 m-0 grid place-items-center text-sm text-muted-foreground pointer-events-none motion-safe:animate-fade-in",
|