@kind-ui/charts 0.1.1 → 0.2.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +26 -0
- package/README.md +674 -1
- package/dist/activity-rings.d.ts +2 -1
- package/dist/activity-rings.js +6 -3
- package/dist/animation.d.ts +11 -3
- package/dist/animation.js +18 -10
- package/dist/area-chart.d.ts +3 -1
- package/dist/area-chart.js +15 -10
- package/dist/area-series.d.ts +9 -1
- package/dist/area-series.js +35 -8
- package/dist/bar-chart.d.ts +10 -3
- package/dist/bar-chart.js +17 -4
- package/dist/bar-series.d.ts +11 -1
- package/dist/bar-series.js +65 -13
- package/dist/box-plot.js +2 -2
- package/dist/category-cells.d.ts +7 -1
- package/dist/category-cells.js +32 -2
- package/dist/chart-background-pattern.d.ts +23 -0
- package/dist/chart-background-pattern.js +31 -0
- package/dist/chart-context.d.ts +6 -2
- package/dist/chart-interaction.d.ts +94 -0
- package/dist/chart-interaction.js +224 -0
- package/dist/combo-chart.d.ts +8 -5
- package/dist/combo-chart.js +14 -12
- package/dist/configured-line-chart.d.ts +5 -1
- package/dist/configured-line-chart.js +8 -5
- package/dist/emphasis.d.ts +5 -2
- package/dist/emphasis.js +18 -4
- package/dist/fill-pattern.d.ts +25 -0
- package/dist/fill-pattern.js +23 -0
- package/dist/heatmap.d.ts +3 -1
- package/dist/heatmap.js +34 -12
- package/dist/histogram-chart.js +10 -3
- package/dist/index.d.ts +12 -3
- package/dist/index.js +8 -1
- package/dist/legend.d.ts +2 -0
- package/dist/legend.js +28 -7
- package/dist/line-chart.d.ts +13 -3
- package/dist/line-chart.js +54 -34
- package/dist/line-dash.d.ts +8 -0
- package/dist/line-dash.js +18 -0
- package/dist/line-series.d.ts +9 -1
- package/dist/line-series.js +38 -11
- package/dist/loading-cartesian-designs.d.ts +6 -0
- package/dist/loading-cartesian-designs.js +123 -0
- package/dist/loading-motion.d.ts +37 -0
- package/dist/loading-motion.js +88 -0
- package/dist/loading-polar-designs.d.ts +6 -0
- package/dist/loading-polar-designs.js +95 -0
- package/dist/loading-skeleton.d.ts +29 -0
- package/dist/loading-skeleton.js +143 -0
- package/dist/loading-standalone-designs.d.ts +5 -0
- package/dist/loading-standalone-designs.js +126 -0
- package/dist/percent-stack.d.ts +18 -0
- package/dist/percent-stack.js +33 -0
- package/dist/pie-chart.d.ts +7 -3
- package/dist/pie-chart.js +37 -6
- package/dist/pie-pin-identity.d.ts +4 -0
- package/dist/pie-pin-identity.js +10 -0
- package/dist/pie-series.d.ts +4 -0
- package/dist/pie-series.js +137 -14
- package/dist/pie-tooltip-pin.d.ts +4 -0
- package/dist/pie-tooltip-pin.js +52 -0
- package/dist/point-marker.d.ts +19 -0
- package/dist/point-marker.js +19 -0
- package/dist/polar-chart.d.ts +14 -5
- package/dist/polar-chart.js +41 -10
- package/dist/polar-series.js +68 -22
- package/dist/radar-interaction.js +10 -4
- package/dist/radial-category.d.ts +2 -0
- package/dist/reveal-clip.d.ts +16 -0
- package/dist/reveal-clip.js +18 -0
- package/dist/root.d.ts +5 -9
- package/dist/root.js +46 -11
- package/dist/sankey-chart.d.ts +5 -1
- package/dist/sankey-chart.js +64 -13
- package/dist/sankey-colors.d.ts +3 -0
- package/dist/sankey-interaction.d.ts +8 -0
- package/dist/sankey-interaction.js +32 -0
- package/dist/sankey-legend.d.ts +2 -1
- package/dist/sankey-legend.js +18 -3
- package/dist/sankey-node-label.d.ts +22 -0
- package/dist/sankey-node-label.js +34 -0
- package/dist/scatter-chart.d.ts +5 -3
- package/dist/scatter-chart.js +14 -4
- package/dist/scatter-series.js +5 -3
- package/dist/series-color.d.ts +10 -0
- package/dist/series-color.js +48 -0
- package/dist/series-interaction.d.ts +12 -0
- package/dist/series-interaction.js +82 -0
- package/dist/series-label.d.ts +7 -0
- package/dist/series-label.js +18 -0
- package/dist/series-paint.d.ts +8 -0
- package/dist/series-paint.js +27 -0
- package/dist/styles.css +151 -1
- package/dist/stylesheet-warning.d.ts +2 -0
- package/dist/stylesheet-warning.js +86 -0
- package/dist/tooltip-content.d.ts +8 -1
- package/dist/tooltip-content.js +15 -4
- package/dist/tooltip.d.ts +3 -1
- package/dist/tooltip.js +8 -5
- package/dist/types.d.ts +11 -2
- package/dist/waterfall-chart.d.ts +4 -0
- package/dist/waterfall-chart.js +7 -0
- package/package.json +2 -2
package/dist/emphasis.js
CHANGED
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
"use client";
|
|
2
2
|
import { jsx as _jsx } from "react/jsx-runtime";
|
|
3
3
|
import { createContext, use, useCallback, useEffect, useId, useLayoutEffect, useMemo, useRef, useState, } from "react";
|
|
4
|
+
import { useChartInteraction } from "./chart-interaction.js";
|
|
4
5
|
const Context = createContext(null);
|
|
5
6
|
const Actions = createContext(null);
|
|
6
7
|
const identity = (target) => JSON.stringify([target.kind, target.scope, target.key]);
|
|
@@ -59,6 +60,9 @@ export function EmphasisProvider({ enabled, children, }) {
|
|
|
59
60
|
const actions = useMemo(() => ({ enabled, register, set, clear, reset, clearScope }), [enabled, register, set, clear, reset, clearScope]);
|
|
60
61
|
return (_jsx(Actions, { value: actions, children: _jsx(Context, { value: active, children: children }) }));
|
|
61
62
|
}
|
|
63
|
+
export function useOptionalEmphasisActions() {
|
|
64
|
+
return use(Actions);
|
|
65
|
+
}
|
|
62
66
|
export function useEmphasisActions() {
|
|
63
67
|
const value = use(Actions);
|
|
64
68
|
if (!value)
|
|
@@ -71,7 +75,8 @@ function useEmphasisState() {
|
|
|
71
75
|
return { ...actions, active };
|
|
72
76
|
}
|
|
73
77
|
/** Explicit contract for custom and portaled marks; apply factor to an extra paint wrapper. */
|
|
74
|
-
export function useEmphasis(target, enabled = true) {
|
|
78
|
+
export function useEmphasis(target, enabled = true, persistent = true) {
|
|
79
|
+
const interaction = useChartInteraction();
|
|
75
80
|
const state = useEmphasisState();
|
|
76
81
|
const owner = useId();
|
|
77
82
|
const { kind, key, scope, seriesKey } = target;
|
|
@@ -84,7 +89,16 @@ export function useEmphasis(target, enabled = true) {
|
|
|
84
89
|
const related = active === null ||
|
|
85
90
|
(active.kind === "series" ? active.key === seriesKey : identity(active) === identity(target));
|
|
86
91
|
const applicable = active?.kind === "series" ? seriesKey !== undefined : active?.scope === scope;
|
|
87
|
-
const
|
|
92
|
+
const persistentKey = interaction.kind === "series"
|
|
93
|
+
? seriesKey
|
|
94
|
+
: target.kind === "sector" || target.kind === "category"
|
|
95
|
+
? key
|
|
96
|
+
: undefined;
|
|
97
|
+
const persistentDimmed = persistent &&
|
|
98
|
+
persistentKey !== undefined &&
|
|
99
|
+
interaction.selected !== null &&
|
|
100
|
+
persistentKey !== interaction.selected;
|
|
101
|
+
const dimmed = enabled && (active !== null ? state.enabled && applicable && !related : persistentDimmed);
|
|
88
102
|
const enter = useCallback((channel) => {
|
|
89
103
|
if (enabled && state.enabled) {
|
|
90
104
|
if (channel === "keyboard")
|
|
@@ -96,8 +110,8 @@ export function useEmphasis(target, enabled = true) {
|
|
|
96
110
|
return { active, dimmed: Boolean(dimmed), factor: dimmed ? 0.28 : 1, enter, leave };
|
|
97
111
|
}
|
|
98
112
|
/** Multiplicative paint layer; native geometry, consumer opacity and hit testing stay intact. */
|
|
99
|
-
export function EmphasisMark({ target, enabled = true, keyboardActive = false, children, ...props }) {
|
|
100
|
-
const emphasis = useEmphasis(target, enabled);
|
|
113
|
+
export function EmphasisMark({ target, enabled = true, persistent = true, keyboardActive = false, children, ...props }) {
|
|
114
|
+
const emphasis = useEmphasis(target, enabled, persistent);
|
|
101
115
|
// Only depend on identity and the engine's inspection edge, not the changing paint state.
|
|
102
116
|
useLayoutEffect(() => {
|
|
103
117
|
if (keyboardActive)
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
import { type ComponentPropsWithRef } from "react";
|
|
2
|
+
/** Static paint encoding, independent of material and chart geometry. */
|
|
3
|
+
export type FillPattern = {
|
|
4
|
+
kind: "hatch" | "stripe" | "duotone" | "dots" | "lines";
|
|
5
|
+
/** Second ink; defaults to CanvasText and follows the host's color scheme. */
|
|
6
|
+
color?: string;
|
|
7
|
+
/** Positive tile size in SVG user units (default 8). */
|
|
8
|
+
size?: number;
|
|
9
|
+
/** Positive stroke/stripe width or dot diameter, <= size (default 1; stripe 2). */
|
|
10
|
+
width?: number;
|
|
11
|
+
/** Rotation in degrees (default 45 for hatch, 0 otherwise). */
|
|
12
|
+
angle?: number;
|
|
13
|
+
};
|
|
14
|
+
export declare function patternResourceId(id: string): string;
|
|
15
|
+
export declare function FillPatternDefinition({ id, pattern, baseColor, }: {
|
|
16
|
+
id: string;
|
|
17
|
+
pattern: FillPattern;
|
|
18
|
+
baseColor: string;
|
|
19
|
+
}): import("react").JSX.Element;
|
|
20
|
+
export type FillPatternSwatchProps = Omit<ComponentPropsWithRef<"svg">, "children" | "color"> & {
|
|
21
|
+
pattern: FillPattern;
|
|
22
|
+
color: string;
|
|
23
|
+
};
|
|
24
|
+
/** Decorative marker for explicit series/consumer legends; native svg props remain available. */
|
|
25
|
+
export declare function FillPatternSwatch({ pattern, color, ...props }: FillPatternSwatchProps): import("react").JSX.Element;
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
"use client";
|
|
2
|
+
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
3
|
+
import { useId } from "react";
|
|
4
|
+
export function patternResourceId(id) {
|
|
5
|
+
return `kind-ui-pattern-${Array.from(id, (char) => char.codePointAt(0)?.toString(16)).join("-")}`;
|
|
6
|
+
}
|
|
7
|
+
export function FillPatternDefinition({ id, pattern, baseColor, }) {
|
|
8
|
+
const { kind, size = 8, width = kind === "stripe" ? 2 : 1, angle = kind === "hatch" ? 45 : 0, } = pattern;
|
|
9
|
+
if (!["hatch", "stripe", "duotone", "dots", "lines"].includes(kind) ||
|
|
10
|
+
!Number.isFinite(size) ||
|
|
11
|
+
size <= 0 ||
|
|
12
|
+
!Number.isFinite(width) ||
|
|
13
|
+
width <= 0 ||
|
|
14
|
+
width > size ||
|
|
15
|
+
!Number.isFinite(angle))
|
|
16
|
+
throw new Error("FillPattern requires a known kind, positive size/width (width <= size), and finite angle");
|
|
17
|
+
return (_jsxs("pattern", { id: id, "data-kind-ui": "fill-pattern", "data-pattern": kind, width: size, height: size, patternUnits: "userSpaceOnUse", patternTransform: `rotate(${angle})`, children: [_jsx("rect", { width: size, height: size, fill: baseColor }), kind === "dots" ? (_jsx("circle", { cx: size / 2, cy: size / 2, r: width / 2, fill: pattern.color ?? "CanvasText" })) : kind === "hatch" || kind === "lines" ? (_jsx("path", { d: `M0 0V${size} M${size} 0V${size}`, stroke: pattern.color ?? "CanvasText", strokeWidth: width })) : (_jsx("rect", { width: kind === "duotone" ? size / 2 : width, height: size, fill: pattern.color ?? "CanvasText" }))] }));
|
|
18
|
+
}
|
|
19
|
+
/** Decorative marker for explicit series/consumer legends; native svg props remain available. */
|
|
20
|
+
export function FillPatternSwatch({ pattern, color, ...props }) {
|
|
21
|
+
const id = patternResourceId(useId());
|
|
22
|
+
return (_jsxs("svg", { "aria-hidden": "true", focusable: "false", viewBox: "0 0 16 16", ...props, "data-kind-ui": "chart-indicator", "data-fill-pattern": "", children: [_jsx("defs", { children: _jsx(FillPatternDefinition, { id: id, pattern: pattern, baseColor: color }) }), _jsx("rect", { width: 16, height: 16, fill: `url(#${id})` })] }));
|
|
23
|
+
}
|
package/dist/heatmap.d.ts
CHANGED
|
@@ -7,9 +7,11 @@ export type HeatmapChartProps = ComponentPropsWithRef<"div"> & HeatmapModelOptio
|
|
|
7
7
|
missingLabel?: string;
|
|
8
8
|
/** Diagonal cell entrance; quantitative colors and table geometry are unchanged. */
|
|
9
9
|
animate?: boolean;
|
|
10
|
+
loading?: boolean | undefined;
|
|
11
|
+
loadingLabel?: string | undefined;
|
|
10
12
|
};
|
|
11
13
|
/** Native table layout owns categorical geometry. No numeric scatter approximation or SVG overlay. */
|
|
12
|
-
export declare function HeatmapChart({ rows, columns, data, duplicates, scale, formatValue, missingLabel, animate, children, onPointerLeave, ...props }: HeatmapChartProps): import("react").JSX.Element;
|
|
14
|
+
export declare function HeatmapChart({ rows, columns, data, duplicates, scale, formatValue, missingLabel, animate, loading, loadingLabel, children, onPointerLeave, ...props }: HeatmapChartProps): import("react").JSX.Element;
|
|
13
15
|
export type HeatmapCellContentProps = {
|
|
14
16
|
cell: HeatmapCell;
|
|
15
17
|
fill: string;
|
package/dist/heatmap.js
CHANGED
|
@@ -4,6 +4,8 @@ import { jsx as _jsx, jsxs as _jsxs, Fragment as _Fragment } from "react/jsx-run
|
|
|
4
4
|
import { animateMini, animate as animateValue } from "motion/react";
|
|
5
5
|
import { createContext, use, useCallback, useEffect, useId, useLayoutEffect, useMemo, useRef, useState, useSyncExternalStore, } from "react";
|
|
6
6
|
import { createHeatmapModel, } from "./heatmap-model.js";
|
|
7
|
+
import { LoadingSkeletonSurface, LoadingStatus, useLoadingSeed } from "./loading-skeleton.js";
|
|
8
|
+
import { StandaloneLoadingDesign } from "./loading-standalone-designs.js";
|
|
7
9
|
import { TooltipNumber } from "./tooltip-number.js";
|
|
8
10
|
const HeatmapContext = createContext(null);
|
|
9
11
|
function useHeatmap() {
|
|
@@ -35,16 +37,19 @@ const samePointer = (a, b) => a !== null &&
|
|
|
35
37
|
a.clientY === b.clientY;
|
|
36
38
|
const labelOf = (cell, context) => `${cell.row}, ${cell.column}: ${cell.value === null ? context.missingLabel : context.formatValue(cell.value)}`;
|
|
37
39
|
/** Native table layout owns categorical geometry. No numeric scatter approximation or SVG overlay. */
|
|
38
|
-
export function HeatmapChart({ rows, columns, data, duplicates, scale, formatValue = number, missingLabel = "Missing", animate = false, children, onPointerLeave, ...props }) {
|
|
40
|
+
export function HeatmapChart({ rows, columns, data, duplicates, scale, formatValue = number, missingLabel = "Missing", animate = false, loading, loadingLabel, children, onPointerLeave, ...props }) {
|
|
41
|
+
const loadingSeed = useLoadingSeed(loading);
|
|
39
42
|
const model = useMemo(() => createHeatmapModel({ rows, columns, data, ...(duplicates ? { duplicates } : {}) }), [rows, columns, data, duplicates]);
|
|
40
43
|
const [active, updateActive] = useState(null);
|
|
41
44
|
const pointer = useRef(null);
|
|
42
45
|
const dismissed = useRef(false);
|
|
43
46
|
const setActive = useCallback((key) => {
|
|
47
|
+
if (loading)
|
|
48
|
+
return;
|
|
44
49
|
if (key)
|
|
45
50
|
dismissed.current = false;
|
|
46
51
|
updateActive(key);
|
|
47
|
-
}, []);
|
|
52
|
+
}, [loading]);
|
|
48
53
|
const dismiss = useCallback(() => {
|
|
49
54
|
dismissed.current = true;
|
|
50
55
|
updateActive(null);
|
|
@@ -60,8 +65,20 @@ export function HeatmapChart({ rows, columns, data, duplicates, scale, formatVal
|
|
|
60
65
|
const [tooltipMounted, setTooltipMounted] = useState(false);
|
|
61
66
|
const reduced = useSyncExternalStore(subscribeReduced, reducedSnapshot, reducedServerSnapshot);
|
|
62
67
|
const [finished, setFinished] = useState(false);
|
|
63
|
-
const
|
|
64
|
-
const
|
|
68
|
+
const previousLoading = useRef(loading);
|
|
69
|
+
const completing = previousLoading.current === true && loading !== true;
|
|
70
|
+
const interrupt = useCallback(() => {
|
|
71
|
+
if (!loading)
|
|
72
|
+
setFinished(true);
|
|
73
|
+
}, [loading]);
|
|
74
|
+
const enabled = animate && !reduced && !loading;
|
|
75
|
+
useLayoutEffect(() => {
|
|
76
|
+
if (loading) {
|
|
77
|
+
setFinished(false);
|
|
78
|
+
updateActive(null);
|
|
79
|
+
pointer.current = null;
|
|
80
|
+
}
|
|
81
|
+
}, [loading]);
|
|
65
82
|
const entrance = enabled && !finished;
|
|
66
83
|
const root = useRef(null);
|
|
67
84
|
useEffect(() => {
|
|
@@ -113,11 +130,14 @@ export function HeatmapChart({ rows, columns, data, duplicates, scale, formatVal
|
|
|
113
130
|
const previousEnabled = useRef(enabled);
|
|
114
131
|
useLayoutEffect(() => {
|
|
115
132
|
const inputs = [model, scale, children];
|
|
116
|
-
if (
|
|
117
|
-
|
|
133
|
+
if (!loading &&
|
|
134
|
+
!completing &&
|
|
135
|
+
(inputs.some((value, index) => value !== previous.current[index]) ||
|
|
136
|
+
(previousEnabled.current && !enabled)))
|
|
118
137
|
interrupt();
|
|
119
138
|
previous.current = inputs;
|
|
120
139
|
previousEnabled.current = enabled;
|
|
140
|
+
previousLoading.current = loading;
|
|
121
141
|
});
|
|
122
142
|
useLayoutEffect(() => {
|
|
123
143
|
if (!entrance)
|
|
@@ -136,19 +156,21 @@ export function HeatmapChart({ rows, columns, data, duplicates, scale, formatVal
|
|
|
136
156
|
return () => document.removeEventListener("keydown", keydown);
|
|
137
157
|
}, [active, tooltipMounted, dismiss]);
|
|
138
158
|
return (_jsx(HeatmapContext, { value: {
|
|
159
|
+
loading,
|
|
160
|
+
loadingSeed,
|
|
139
161
|
model,
|
|
140
162
|
entrance,
|
|
141
163
|
scale,
|
|
142
164
|
formatValue,
|
|
143
165
|
missingLabel,
|
|
144
|
-
active,
|
|
166
|
+
active: loading ? null : active,
|
|
145
167
|
setActive,
|
|
146
168
|
dismiss,
|
|
147
169
|
inspectPointer,
|
|
148
170
|
tooltipId,
|
|
149
171
|
tooltipMounted,
|
|
150
172
|
setTooltipMounted,
|
|
151
|
-
}, children:
|
|
173
|
+
}, children: _jsxs("div", { ...props, ref: ref, "data-kind-ui": "heatmap", "aria-busy": props["aria-busy"], onFocusCapture: (event) => {
|
|
152
174
|
props.onFocusCapture?.(event);
|
|
153
175
|
interrupt();
|
|
154
176
|
}, onPointerMoveCapture: (event) => {
|
|
@@ -169,7 +191,7 @@ export function HeatmapChart({ rows, columns, data, duplicates, scale, formatVal
|
|
|
169
191
|
? model.cells.flat().find((item) => keyOf(item) === focused?.dataset.cellKey)
|
|
170
192
|
: undefined;
|
|
171
193
|
setActive(cell ? [cell.row, cell.column] : null);
|
|
172
|
-
}, children: _jsx("div", { "data-kind-ui": "heatmap-entrance", children: children }) }) }));
|
|
194
|
+
}, children: [_jsx("div", { "data-kind-ui": "heatmap-entrance", children: children }), _jsx(LoadingStatus, { loading: loading, label: loadingLabel })] }) }));
|
|
173
195
|
}
|
|
174
196
|
// A native cell keeps its styles, ref and handlers. Motion temporarily multiplies its opacity.
|
|
175
197
|
function EntranceCell({ diagonal, ...props }) {
|
|
@@ -293,7 +315,7 @@ export function HeatmapGrid({ caption, material = "plain", layout, Cell = Heatma
|
|
|
293
315
|
}
|
|
294
316
|
}
|
|
295
317
|
}
|
|
296
|
-
return (_jsxs("div", { "data-kind-ui": "heatmap-scroll", children: [_jsxs("table", { ...props, ref: (node) => {
|
|
318
|
+
return (_jsxs("div", { "data-kind-ui": "heatmap-scroll", "data-loading": context.loading || undefined, children: [_jsxs("table", { ...props, ref: (node) => {
|
|
297
319
|
table.current = node;
|
|
298
320
|
if (typeof props.ref === "function")
|
|
299
321
|
return props.ref(node);
|
|
@@ -301,7 +323,7 @@ export function HeatmapGrid({ caption, material = "plain", layout, Cell = Heatma
|
|
|
301
323
|
props.ref.current = node;
|
|
302
324
|
},
|
|
303
325
|
// biome-ignore lint/a11y/noNoninteractiveElementToInteractiveRole: WAI-ARIA APG data grid uses a native table with roving cell focus.
|
|
304
|
-
role: "grid", "aria-label": caption, "data-kind-ui": "heatmap-grid", "data-cell-sizing": layout?.cellSize === undefined ? undefined : "fixed", "data-row-labels": layout?.rowLabels, "data-column-labels": layout?.columnLabels, style: {
|
|
326
|
+
role: "grid", "aria-label": caption, "aria-busy": context.loading, "aria-hidden": context.loading || undefined, inert: context.loading || undefined, "data-kind-ui": "heatmap-grid", "data-cell-sizing": layout?.cellSize === undefined ? undefined : "fixed", "data-row-labels": layout?.rowLabels, "data-column-labels": layout?.columnLabels, style: {
|
|
305
327
|
"--heatmap-columns": model.columns.length,
|
|
306
328
|
...(layout?.cellSize === undefined
|
|
307
329
|
? {}
|
|
@@ -333,7 +355,7 @@ export function HeatmapGrid({ caption, material = "plain", layout, Cell = Heatma
|
|
|
333
355
|
context.inspectPointer(event, [cell.row, cell.column]);
|
|
334
356
|
} },
|
|
335
357
|
_jsx(Cell, { cell: cell, fill: fill, formattedValue: formattedValue })));
|
|
336
|
-
})] }, row))) })] }), model.rows.length === 0 || model.columns.length === 0 ? (_jsx("p", { "data-kind-ui": "heatmap-empty", children: "No cells in the selected domains." })) : null] }));
|
|
358
|
+
})] }, row))) })] }), context.loading && (_jsx(LoadingSkeletonSurface, { family: "heatmap", design: (seed) => _jsx(StandaloneLoadingDesign, { family: "heatmap", seed: seed }), width: "100%", height: "100%", seed: context.loadingSeed })), !context.loading && (model.rows.length === 0 || model.columns.length === 0) ? (_jsx("p", { "data-kind-ui": "heatmap-empty", children: "No cells in the selected domains." })) : null] }));
|
|
337
359
|
}
|
|
338
360
|
/** In-flow tooltip stays within narrow containers and remains available for hover, focus and touch. */
|
|
339
361
|
export function HeatmapTooltip({ Content, valueAnimation, ...props }) {
|
package/dist/histogram-chart.js
CHANGED
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
"use client";
|
|
2
|
-
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
2
|
+
import { jsx as _jsx, Fragment as _Fragment, jsxs as _jsxs } from "react/jsx-runtime";
|
|
3
3
|
import { createContext, useMemo } from "react";
|
|
4
4
|
import { XAxis, YAxis } from "recharts";
|
|
5
|
-
import {
|
|
5
|
+
import { BarChartImplementation } from "./bar-chart.js";
|
|
6
6
|
import { validateHistogram } from "./histogram-data.js";
|
|
7
7
|
export const HistogramContext = createContext(null);
|
|
8
8
|
/** Bounded vertical histogram; quantitative axes are owned here, native children compose. */
|
|
@@ -23,5 +23,12 @@ export function HistogramChart({ bins, measure, xAxisProps, yAxisProps, children
|
|
|
23
23
|
const domain = bins.length ? [bins[0]?.lower ?? 0, bins[bins.length - 1]?.upper ?? 1] : [0, 1];
|
|
24
24
|
if (!Number.isFinite((domain[1] ?? 1) - (domain[0] ?? 0)))
|
|
25
25
|
throw new Error("Histogram domain must have a finite span");
|
|
26
|
-
return (_jsx(HistogramContext, { value: measure, children:
|
|
26
|
+
return (_jsx(HistogramContext, { value: measure, children: _jsx(BarChartImplementation, { family: "histogram", chartProps: {
|
|
27
|
+
...props,
|
|
28
|
+
data,
|
|
29
|
+
layout: "horizontal",
|
|
30
|
+
barCategoryGap: 0,
|
|
31
|
+
barGap: 0,
|
|
32
|
+
children: (_jsxs(_Fragment, { children: [_jsx(XAxis, { ...xAxisProps, xAxisId: 0, dataKey: "midpoint", type: "number", scale: "linear", domain: domain, allowDataOverflow: true, reversed: false }), _jsx(YAxis, { ...yAxisProps, yAxisId: 0, type: "number", scale: "linear", domain: [0, "dataMax"], reversed: false }), children] })),
|
|
33
|
+
} }) }));
|
|
27
34
|
}
|
package/dist/index.d.ts
CHANGED
|
@@ -4,29 +4,36 @@ export { type LineAnimation, LineSeries, type LineSeriesProps, Tooltip, type Too
|
|
|
4
4
|
export { type AreaAnimation, AreaChart, type AreaChartProps } from "./area-chart.js";
|
|
5
5
|
export type { AreaMaterial } from "./area-material.js";
|
|
6
6
|
export { AreaSeries, type AreaSeriesProps } from "./area-series.js";
|
|
7
|
-
export { type BarAnimation, BarChart,
|
|
7
|
+
export { type BarAnimation, BarChart, type BarChartProps, } from "./bar-chart.js";
|
|
8
8
|
export type { BarMaterial } from "./bar-material.js";
|
|
9
|
-
export { BarSeries, type BarSeriesProps } from "./bar-series.js";
|
|
9
|
+
export { type BarProjection, BarSeries, type BarSeriesProps } from "./bar-series.js";
|
|
10
10
|
export type { BoxPlotMaterial } from "./box-material.js";
|
|
11
11
|
export { BoxPlotChart, type BoxPlotChartProps, BoxPlotMark, type BoxPlotMarkProps, BoxPlotSeries, type BoxPlotSeriesProps, type BoxPlotShapeProps, type BoxPlotSummary, boxPlotExtent, validateBoxPlotSummary, } from "./box-plot.js";
|
|
12
|
+
export { ChartBackgroundPattern, type ChartBackgroundPatternDefinition, type ChartBackgroundPatternProps, type ChartBackgroundPatternRenderProps, defineChartBackgroundPattern, } from "./chart-background-pattern.js";
|
|
13
|
+
export { type ChartIdentity, type ChartInteractionConfig, type ChartInteractionEvent, type ChartInteractionRequest, useChartInteraction, } from "./chart-interaction.js";
|
|
12
14
|
export { type ComboAnimation, ComboChart, type ComboChartProps } from "./combo-chart.js";
|
|
13
15
|
export { type ConfiguredLineChartProps, type ConfiguredLineSeries, LineChart, type LineChartProps, } from "./configured-line-chart.js";
|
|
14
16
|
export { EmphasisMark, type EmphasisMarkProps, type EmphasisTarget, useEmphasis, } from "./emphasis.js";
|
|
17
|
+
export { type FillPattern, FillPatternSwatch, type FillPatternSwatchProps, } from "./fill-pattern.js";
|
|
15
18
|
export { HeatmapCellContent, type HeatmapCellContentProps, HeatmapChart, type HeatmapChartProps, HeatmapDataTable, type HeatmapDataTableProps, HeatmapGrid, type HeatmapGridProps, HeatmapLegend, type HeatmapLegendProps, type HeatmapMaterial, HeatmapTooltip, type HeatmapTooltipProps, } from "./heatmap.js";
|
|
16
19
|
export { createHeatmapModel, createHeatmapScale, type HeatmapCell, type HeatmapDatum, type HeatmapDuplicatePolicy, type HeatmapModel, type HeatmapModelOptions, type HeatmapScale, type HeatmapScaleOptions, } from "./heatmap-model.js";
|
|
17
20
|
export { HistogramChart, type HistogramChartProps } from "./histogram-chart.js";
|
|
18
21
|
export { binHistogram, type HistogramBin, type HistogramBinningResult, type HistogramMeasure, } from "./histogram-data.js";
|
|
19
22
|
export { HistogramSeries, type HistogramSeriesProps, type HistogramShapeProps, } from "./histogram-series.js";
|
|
20
23
|
export { Legend, type LegendProps } from "./legend.js";
|
|
24
|
+
export type { LineDashAnimation } from "./line-dash.js";
|
|
21
25
|
export type { LineMaterial } from "./line-material.js";
|
|
26
|
+
export { createPercentStack, formatPercent, type NormalizedValue, type PercentStackOptions, } from "./percent-stack.js";
|
|
22
27
|
export { type PieAnimation, PieChart, type PieChartProps } from "./pie-chart.js";
|
|
23
28
|
export type { PieMaterial } from "./pie-material.js";
|
|
24
29
|
export { PieSeries, type PieSeriesProps } from "./pie-series.js";
|
|
30
|
+
export { PointMarker, type PointMarkerProps, type PointStyle } from "./point-marker.js";
|
|
25
31
|
export { type RadarAnimation, RadarChart, type RadarChartProps, type RadialBarAnimation, RadialBarChart, type RadialBarChartProps, } from "./polar-chart.js";
|
|
26
32
|
export type { PolarMaterial } from "./polar-material.js";
|
|
27
33
|
export { RadarSeries, type RadarSeriesProps, RadialBarSeries, type RadialBarSeriesProps, } from "./polar-series.js";
|
|
28
34
|
export type { RadarSelectionProps } from "./radar-interaction.js";
|
|
29
35
|
export { RadialBarLabel, type RadialBarLabelProps } from "./radial-bar-label.js";
|
|
36
|
+
export type { RevealDirection } from "./reveal-clip.js";
|
|
30
37
|
export { Root, type RootProps } from "./root.js";
|
|
31
38
|
export { type SankeyAnimation, SankeyChart, type SankeyChartProps } from "./sankey-chart.js";
|
|
32
39
|
export type { SankeyNodeConfig } from "./sankey-colors.js";
|
|
@@ -34,12 +41,14 @@ export { prepareSankeyData, type SankeyFlowData, type SankeyFlowLink, type Sanke
|
|
|
34
41
|
export type { SankeyFinish } from "./sankey-finish.js";
|
|
35
42
|
export { SankeyLegend, type SankeyLegendProps } from "./sankey-legend.js";
|
|
36
43
|
export { SankeyLink, type SankeyLinkProps, type SankeyMaterial, SankeyNode, type SankeyNodeProps, } from "./sankey-marks.js";
|
|
44
|
+
export { SankeyNodeLabel, type SankeyNodeLabelProps } from "./sankey-node-label.js";
|
|
37
45
|
export { SankeyTable, type SankeyTableProps } from "./sankey-table.js";
|
|
38
46
|
export { type ScatterAnimation, ScatterChart, type ScatterChartProps } from "./scatter-chart.js";
|
|
39
47
|
export type { ScatterMaterial } from "./scatter-material.js";
|
|
40
48
|
export { ScatterSeries, type ScatterSeriesProps } from "./scatter-series.js";
|
|
41
49
|
export { type ScatterSizeDimension, ScatterTooltip, ScatterTooltipContent, type ScatterTooltipContentProps, type ScatterTooltipProps, } from "./scatter-tooltip.js";
|
|
42
50
|
export { TooltipContent, type TooltipContentProps } from "./tooltip-content.js";
|
|
43
|
-
export type { SeriesConfig } from "./types.js";
|
|
51
|
+
export type { SeriesColor, SeriesConfig } from "./types.js";
|
|
52
|
+
export { WaterfallChart, type WaterfallChartProps } from "./waterfall-chart.js";
|
|
44
53
|
export { computeWaterfallData, type WaterfallDatum, type WaterfallEntry, } from "./waterfall-data.js";
|
|
45
54
|
export { WaterfallConnectors, type WaterfallConnectorsProps, WaterfallSeries, type WaterfallSeriesProps, } from "./waterfall-series.js";
|
package/dist/index.js
CHANGED
|
@@ -5,20 +5,25 @@ export { ActivityRings, } from "./activity-rings.js";
|
|
|
5
5
|
export { LineSeries, Tooltip, } from "./animation.js";
|
|
6
6
|
export { AreaChart } from "./area-chart.js";
|
|
7
7
|
export { AreaSeries } from "./area-series.js";
|
|
8
|
-
export { BarChart,
|
|
8
|
+
export { BarChart, } from "./bar-chart.js";
|
|
9
9
|
export { BarSeries } from "./bar-series.js";
|
|
10
10
|
export { BoxPlotChart, BoxPlotMark, BoxPlotSeries, boxPlotExtent, validateBoxPlotSummary, } from "./box-plot.js";
|
|
11
|
+
export { ChartBackgroundPattern, defineChartBackgroundPattern, } from "./chart-background-pattern.js";
|
|
12
|
+
export { useChartInteraction, } from "./chart-interaction.js";
|
|
11
13
|
export { ComboChart } from "./combo-chart.js";
|
|
12
14
|
export { LineChart, } from "./configured-line-chart.js";
|
|
13
15
|
export { EmphasisMark, useEmphasis, } from "./emphasis.js";
|
|
16
|
+
export { FillPatternSwatch, } from "./fill-pattern.js";
|
|
14
17
|
export { HeatmapCellContent, HeatmapChart, HeatmapDataTable, HeatmapGrid, HeatmapLegend, HeatmapTooltip, } from "./heatmap.js";
|
|
15
18
|
export { createHeatmapModel, createHeatmapScale, } from "./heatmap-model.js";
|
|
16
19
|
export { HistogramChart } from "./histogram-chart.js";
|
|
17
20
|
export { binHistogram, } from "./histogram-data.js";
|
|
18
21
|
export { HistogramSeries, } from "./histogram-series.js";
|
|
19
22
|
export { Legend } from "./legend.js";
|
|
23
|
+
export { createPercentStack, formatPercent, } from "./percent-stack.js";
|
|
20
24
|
export { PieChart } from "./pie-chart.js";
|
|
21
25
|
export { PieSeries } from "./pie-series.js";
|
|
26
|
+
export { PointMarker } from "./point-marker.js";
|
|
22
27
|
export { RadarChart, RadialBarChart, } from "./polar-chart.js";
|
|
23
28
|
export { RadarSeries, RadialBarSeries, } from "./polar-series.js";
|
|
24
29
|
export { RadialBarLabel } from "./radial-bar-label.js";
|
|
@@ -27,10 +32,12 @@ export { SankeyChart } from "./sankey-chart.js";
|
|
|
27
32
|
export { prepareSankeyData, } from "./sankey-data.js";
|
|
28
33
|
export { SankeyLegend } from "./sankey-legend.js";
|
|
29
34
|
export { SankeyLink, SankeyNode, } from "./sankey-marks.js";
|
|
35
|
+
export { SankeyNodeLabel } from "./sankey-node-label.js";
|
|
30
36
|
export { SankeyTable } from "./sankey-table.js";
|
|
31
37
|
export { ScatterChart } from "./scatter-chart.js";
|
|
32
38
|
export { ScatterSeries } from "./scatter-series.js";
|
|
33
39
|
export { ScatterTooltip, ScatterTooltipContent, } from "./scatter-tooltip.js";
|
|
34
40
|
export { TooltipContent } from "./tooltip-content.js";
|
|
41
|
+
export { WaterfallChart } from "./waterfall-chart.js";
|
|
35
42
|
export { computeWaterfallData, } from "./waterfall-data.js";
|
|
36
43
|
export { WaterfallConnectors, WaterfallSeries, } from "./waterfall-series.js";
|
package/dist/legend.d.ts
CHANGED
package/dist/legend.js
CHANGED
|
@@ -2,17 +2,38 @@
|
|
|
2
2
|
import { jsx as _jsx, Fragment as _Fragment, jsxs as _jsxs } from "react/jsx-runtime";
|
|
3
3
|
import { Symbols } from "recharts";
|
|
4
4
|
import { useChart } from "./chart-context.js";
|
|
5
|
+
import { useChartInteraction } from "./chart-interaction.js";
|
|
5
6
|
import { useEmphasis } from "./emphasis.js";
|
|
7
|
+
import { FillPatternSwatch } from "./fill-pattern.js";
|
|
8
|
+
import { colorStopToken } from "./series-color.js";
|
|
6
9
|
/** Displays configured series; becomes interactive only when a controlled change callback exists. */
|
|
7
10
|
export function Legend({ hideIcon = false, emphasis = "none", children, ...props }) {
|
|
8
|
-
const { config,
|
|
9
|
-
|
|
11
|
+
const { config, paints, visibleSeries } = useChart();
|
|
12
|
+
const interaction = useChartInteraction();
|
|
13
|
+
return (
|
|
14
|
+
// biome-ignore lint/a11y/useKeyWithClickEvents: Delegates clicks from native buttons, which already implement Enter and Space.
|
|
15
|
+
_jsx("ul", { "aria-label": "Chart legend", ...props, "data-kind-ui": "chart-legend", onClick: (event) => {
|
|
16
|
+
props.onClick?.(event);
|
|
17
|
+
const button = event.target.closest("button[data-legend-key]");
|
|
18
|
+
if (button?.dataset.legendKey !== undefined && event.currentTarget.contains(button))
|
|
19
|
+
interaction.activate({ kind: interaction.kind, key: button.dataset.legendKey }, "legend", event);
|
|
20
|
+
}, children: Object.entries(config).map(([key, item]) => {
|
|
10
21
|
const visible = visibleSeries?.includes(key) ?? true;
|
|
11
|
-
const marker = item.icon && !hideIcon ? (_jsx("span", { "aria-hidden": "true", "data-kind-ui": "chart-icon", children: _jsx(item.icon, {}) })) : item.legendShape && !hideIcon ? (_jsx("svg", { "aria-hidden": "true", focusable: "false", "data-kind-ui": "chart-indicator", "data-legend-shape": item.legendShape, viewBox: "-8 -8 16 16", style: {
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
22
|
+
const marker = item.icon && !hideIcon ? (_jsx("span", { "aria-hidden": "true", "data-kind-ui": "chart-icon", children: _jsx(item.icon, {}) })) : item.legendShape && !hideIcon ? (_jsx("svg", { "aria-hidden": "true", focusable: "false", "data-kind-ui": "chart-indicator", "data-legend-shape": item.legendShape, viewBox: "-8 -8 16 16", style: {
|
|
23
|
+
"--kind-ui-chart-indicator-color": paints[key],
|
|
24
|
+
}, children: _jsx(Symbols, { type: item.legendShape, cx: 0, cy: 0, size: 64 }) })) : item.pattern && !hideIcon ? (_jsx(FillPatternSwatch, { pattern: item.pattern, color: `var(--color-${key})` })) : (_jsx("span", { "aria-hidden": "true", "data-kind-ui": "chart-indicator", style: {
|
|
25
|
+
"--kind-ui-chart-indicator-color": `var(--color-${key})`,
|
|
26
|
+
"--kind-ui-chart-indicator-background": `var(${colorStopToken(key, "gradient")})`,
|
|
27
|
+
} }));
|
|
28
|
+
const content = children ? (children({
|
|
29
|
+
key,
|
|
30
|
+
label: item.label,
|
|
31
|
+
visible,
|
|
32
|
+
marker,
|
|
33
|
+
selected: interaction.selected === key,
|
|
34
|
+
mode: interaction.mode,
|
|
35
|
+
})) : (_jsxs(_Fragment, { children: [marker, item.label] }));
|
|
36
|
+
return (_jsx(LegendItem, { seriesKey: key, enabled: emphasis === "series" && visible, interactive: interaction.interactive && interaction.eligible.includes(key), children: interaction.interactive && interaction.eligible.includes(key) ? (_jsx("button", { type: "button", "aria-pressed": interaction.mode === "focus" ? interaction.selected === key : visible, "data-kind-ui": "chart-legend-button", "data-legend-key": key, children: content })) : (_jsxs("span", { children: [content, visible ? null : " (hidden)"] })) }, key));
|
|
16
37
|
}) }));
|
|
17
38
|
}
|
|
18
39
|
function LegendItem({ seriesKey, enabled, interactive, children, }) {
|
package/dist/line-chart.d.ts
CHANGED
|
@@ -1,6 +1,11 @@
|
|
|
1
1
|
import { type Attributes, type ComponentProps, type ComponentType } from "react";
|
|
2
2
|
import { LineChart as EngineLineChart, type RadarChart as EngineRadarChart } from "recharts";
|
|
3
|
-
|
|
3
|
+
import type { LoadingAnimation } from "./loading-motion.js";
|
|
4
|
+
import { type LoadingDesign, type LoadingFamily } from "./loading-skeleton.js";
|
|
5
|
+
export type LineChartProps = ComponentProps<typeof EngineLineChart> & {
|
|
6
|
+
loading?: boolean | undefined;
|
|
7
|
+
loadingLabel?: string | undefined;
|
|
8
|
+
};
|
|
4
9
|
type Point = {
|
|
5
10
|
x: number;
|
|
6
11
|
y: number;
|
|
@@ -27,7 +32,7 @@ declare function createKeyboardModality(): {
|
|
|
27
32
|
export declare function useChartKeyboard(): boolean;
|
|
28
33
|
/** Internal boundary shared by the static and optional Motion entry points. */
|
|
29
34
|
type NativeChartProps = LineChartProps | ComponentProps<typeof EngineRadarChart>;
|
|
30
|
-
export declare function LineChartFrame<Props extends NativeChartProps & Attributes = LineChartProps>({ engine: EngineChart, interrupt, clip, motionEnabled, categoryEmphasis, chartProps: props, children, }: {
|
|
35
|
+
export declare function LineChartFrame<Props extends NativeChartProps & Attributes = LineChartProps>({ engine: EngineChart, interrupt, clip, motionEnabled, categoryEmphasis, loading, loadingLabel, loadingSkeleton, loadingAnimation, loadingDesign, chartProps: props, children, }: {
|
|
31
36
|
chartProps: Props;
|
|
32
37
|
engine: ComponentType<Props>;
|
|
33
38
|
children?: Props["children"];
|
|
@@ -35,7 +40,12 @@ export declare function LineChartFrame<Props extends NativeChartProps & Attribut
|
|
|
35
40
|
clip?: string;
|
|
36
41
|
motionEnabled?: boolean;
|
|
37
42
|
categoryEmphasis?: boolean;
|
|
43
|
+
loading?: boolean | undefined;
|
|
44
|
+
loadingLabel?: string | undefined;
|
|
45
|
+
loadingSkeleton?: LoadingFamily;
|
|
46
|
+
loadingAnimation?: LoadingAnimation | undefined;
|
|
47
|
+
loadingDesign?: LoadingDesign | undefined;
|
|
38
48
|
}): import("react").JSX.Element;
|
|
39
49
|
/** Recharts owns geometry and keyboard selection; Kind shares pointer/keyboard modality. */
|
|
40
|
-
export declare function LineChart(props: LineChartProps): import("react").JSX.Element;
|
|
50
|
+
export declare function LineChart({ loading, loadingLabel, ...props }: LineChartProps): import("react").JSX.Element;
|
|
41
51
|
export {};
|
package/dist/line-chart.js
CHANGED
|
@@ -4,6 +4,8 @@ import { createContext, use, useCallback, useId, useLayoutEffect, useRef, useSta
|
|
|
4
4
|
import { LineChart as EngineLineChart, getRelativeCoordinate, useChartHeight, useChartWidth, } from "recharts";
|
|
5
5
|
import { useChart } from "./chart-context.js";
|
|
6
6
|
import { useEmphasisActions } from "./emphasis.js";
|
|
7
|
+
import { ChartLoadingSkeleton, useLoadingSeed, } from "./loading-skeleton.js";
|
|
8
|
+
import { SeriesColorDefinitions, SeriesPaintBoundary } from "./series-paint.js";
|
|
7
9
|
export const LineInteraction = createContext(null);
|
|
8
10
|
export function useLineInteraction() {
|
|
9
11
|
const value = use(LineInteraction);
|
|
@@ -53,7 +55,8 @@ function Lifecycle({ data, invalidate }) {
|
|
|
53
55
|
}, [width, height, data, visibleSeries, invalidate]);
|
|
54
56
|
return null;
|
|
55
57
|
}
|
|
56
|
-
export function LineChartFrame({ engine: EngineChart, interrupt = () => { }, clip, motionEnabled, categoryEmphasis = false, chartProps: props, children = props.children, }) {
|
|
58
|
+
export function LineChartFrame({ engine: EngineChart, interrupt = () => { }, clip, motionEnabled, categoryEmphasis = false, loading, loadingLabel, loadingSkeleton, loadingAnimation, loadingDesign, chartProps: props, children = props.children, }) {
|
|
59
|
+
const loadingSeed = useLoadingSeed(loading);
|
|
57
60
|
const { onMouseMove, onMouseLeave } = props;
|
|
58
61
|
const emphasis = useEmphasisActions();
|
|
59
62
|
const frame = useRef(null);
|
|
@@ -105,12 +108,36 @@ export function LineChartFrame({ engine: EngineChart, interrupt = () => { }, cli
|
|
|
105
108
|
return next;
|
|
106
109
|
});
|
|
107
110
|
}, []);
|
|
111
|
+
const previousLoading = useRef(loading);
|
|
112
|
+
const completing = previousLoading.current === true && loading !== true;
|
|
113
|
+
useLayoutEffect(() => {
|
|
114
|
+
previousLoading.current = loading;
|
|
115
|
+
});
|
|
108
116
|
const invalidate = useCallback(() => {
|
|
109
117
|
setPointer(null);
|
|
110
118
|
setMotionReady(false);
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
119
|
+
if (!completing)
|
|
120
|
+
interrupt();
|
|
121
|
+
}, [interrupt, completing]);
|
|
122
|
+
const chart = (_jsx(SeriesPaintBoundary, { children: _jsxs(EngineChart, { ...props, className: [
|
|
123
|
+
"kind-ui-line-chart",
|
|
124
|
+
loading !== undefined && "kind-ui-loading-chart",
|
|
125
|
+
loading && "kind-ui-loading-chart-pending",
|
|
126
|
+
props.className,
|
|
127
|
+
]
|
|
128
|
+
.filter(Boolean)
|
|
129
|
+
.join(" "), style: { ...props.style, "--kind-ui-line-clip": clip ?? "none" }, onMouseMove: (state, event) => {
|
|
130
|
+
const { relativeX, relativeY } = getRelativeCoordinate(event);
|
|
131
|
+
setKeyboard(false);
|
|
132
|
+
setMotionReady(true);
|
|
133
|
+
setPointer({ x: relativeX, y: relativeY });
|
|
134
|
+
interrupt();
|
|
135
|
+
onMouseMove?.(state, event);
|
|
136
|
+
}, onMouseLeave: (state, event) => {
|
|
137
|
+
setPointer(null);
|
|
138
|
+
onMouseLeave?.(state, event);
|
|
139
|
+
}, children: [_jsx(SeriesColorDefinitions, { viewport: true }), _jsx(Lifecycle, { data: props.data, invalidate: invalidate }), children, loading && loadingSkeleton && (_jsx(ChartLoadingSkeleton, { family: loadingSkeleton, seed: loadingSeed, animation: loadingAnimation, design: loadingDesign }))] }) }));
|
|
140
|
+
return (_jsxs(LineInteraction, { value: {
|
|
114
141
|
pointer,
|
|
115
142
|
keyboard,
|
|
116
143
|
emphasisScope,
|
|
@@ -121,40 +148,33 @@ export function LineChartFrame({ engine: EngineChart, interrupt = () => { }, cli
|
|
|
121
148
|
invalidate,
|
|
122
149
|
seriesKeys,
|
|
123
150
|
registerSeries,
|
|
124
|
-
}, children: _jsx("div", { ref: frame, "data-kind-ui": "line-frame", "data-motion": motionEnabled === undefined ? undefined : motionEnabled ? "on" : "off", style: { display: "contents" }, onFocusCapture: (event) => {
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
setKeyboard(false);
|
|
130
|
-
interrupt();
|
|
131
|
-
}, onPointerLeave: () => emphasis.clearScope(emphasisScope), onPointerCancel: () => emphasis.clearScope(emphasisScope), onPointerOverCapture: () => setKeyboard(false), onPointerMoveCapture: () => {
|
|
132
|
-
setKeyboard(false);
|
|
133
|
-
interrupt();
|
|
134
|
-
}, onKeyDownCapture: (event) => {
|
|
135
|
-
setKeyboard(event.key !== "Escape");
|
|
136
|
-
interrupt();
|
|
137
|
-
setMotionReady(true);
|
|
138
|
-
setPointer(null);
|
|
139
|
-
}, onBlurCapture: (event) => {
|
|
140
|
-
if (!event.currentTarget.contains(event.relatedTarget)) {
|
|
141
|
-
setPointer(null);
|
|
151
|
+
}, children: [_jsx("div", { ref: frame, "aria-busy": loading, "aria-hidden": loading || undefined, inert: loading || undefined, "data-kind-ui": "line-frame", "data-motion": motionEnabled === undefined ? undefined : motionEnabled ? "on" : "off", style: { display: "contents" }, onFocusCapture: (event) => {
|
|
152
|
+
interrupt();
|
|
153
|
+
if (event.target.matches(":focus-visible"))
|
|
154
|
+
setKeyboard(true);
|
|
155
|
+
}, onPointerDownCapture: () => {
|
|
142
156
|
setKeyboard(false);
|
|
143
|
-
|
|
144
|
-
}
|
|
145
|
-
}, children: _jsxs(EngineChart, { ...props, className: ["kind-ui-line-chart", props.className].filter(Boolean).join(" "), style: { ...props.style, "--kind-ui-line-clip": clip ?? "none" }, onMouseMove: (state, event) => {
|
|
146
|
-
const { relativeX, relativeY } = getRelativeCoordinate(event);
|
|
157
|
+
interrupt();
|
|
158
|
+
}, onPointerLeave: () => emphasis.clearScope(emphasisScope), onPointerCancel: () => emphasis.clearScope(emphasisScope), onPointerOverCapture: () => setKeyboard(false), onPointerMoveCapture: () => {
|
|
147
159
|
setKeyboard(false);
|
|
148
|
-
setMotionReady(true);
|
|
149
|
-
setPointer({ x: relativeX, y: relativeY });
|
|
150
160
|
interrupt();
|
|
151
|
-
|
|
152
|
-
|
|
161
|
+
}, onKeyDownCapture: (event) => {
|
|
162
|
+
if ((event.key === "Enter" || event.key === " " || event.key === "Escape") &&
|
|
163
|
+
event.target.closest('[data-kind-ui="emphasis-mark"][role="button"], [data-kind-ui="series-interaction"][role="button"]'))
|
|
164
|
+
return;
|
|
165
|
+
setKeyboard(event.key !== "Escape");
|
|
166
|
+
interrupt();
|
|
167
|
+
setMotionReady(true);
|
|
153
168
|
setPointer(null);
|
|
154
|
-
|
|
155
|
-
|
|
169
|
+
}, onBlurCapture: (event) => {
|
|
170
|
+
if (!event.currentTarget.contains(event.relatedTarget)) {
|
|
171
|
+
setPointer(null);
|
|
172
|
+
setKeyboard(false);
|
|
173
|
+
emphasis.clear("keyboard");
|
|
174
|
+
}
|
|
175
|
+
}, children: chart }), loading !== undefined && (_jsx("span", { "data-kind-ui": "chart-loading-status", role: "status", "aria-atomic": "true", children: loading ? (loadingLabel ?? "Loading chart") : "" }))] }));
|
|
156
176
|
}
|
|
157
177
|
/** Recharts owns geometry and keyboard selection; Kind shares pointer/keyboard modality. */
|
|
158
|
-
export function LineChart(props) {
|
|
159
|
-
return _jsx(LineChartFrame, { chartProps: props, engine: EngineLineChart });
|
|
178
|
+
export function LineChart({ loading, loadingLabel, ...props }) {
|
|
179
|
+
return (_jsx(LineChartFrame, { chartProps: props, engine: EngineLineChart, loading: loading, loadingLabel: loadingLabel, loadingSkeleton: "line" }));
|
|
160
180
|
}
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
/** Timing for one complete numeric dash-pattern cycle. */
|
|
2
|
+
export type LineDashAnimation = {
|
|
3
|
+
durationMs?: number;
|
|
4
|
+
direction?: "forward" | "reverse";
|
|
5
|
+
};
|
|
6
|
+
/** Unitless SVG lengths only: native CSS/percentage patterns remain consumer-owned. */
|
|
7
|
+
export declare function dashCycle(pattern: string | number | undefined): number | undefined;
|
|
8
|
+
export declare function dashDuration(options: LineDashAnimation): number | undefined;
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
/** Unitless SVG lengths only: native CSS/percentage patterns remain consumer-owned. */
|
|
2
|
+
export function dashCycle(pattern) {
|
|
3
|
+
if (pattern === undefined)
|
|
4
|
+
return undefined;
|
|
5
|
+
const tokens = String(pattern)
|
|
6
|
+
.trim()
|
|
7
|
+
.split(/[\s,]+/);
|
|
8
|
+
if (!tokens.length || tokens.some((token) => !/^(?:\d+\.?\d*|\.\d+)$/.test(token)))
|
|
9
|
+
return undefined;
|
|
10
|
+
const values = tokens.map(Number);
|
|
11
|
+
const sum = values.reduce((total, value) => total + value, 0);
|
|
12
|
+
const cycle = sum * (values.length % 2 ? 2 : 1);
|
|
13
|
+
return Number.isFinite(cycle) && cycle > 0 ? cycle : undefined;
|
|
14
|
+
}
|
|
15
|
+
export function dashDuration(options) {
|
|
16
|
+
const duration = options.durationMs ?? 1000;
|
|
17
|
+
return Number.isFinite(duration) && duration > 0 ? duration : undefined;
|
|
18
|
+
}
|