@wallarm-org/design-system 0.35.1-rc-feature-AS-1005.1 → 0.36.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.
Files changed (89) hide show
  1. package/dist/components/SimpleCharts/LineChart/LineChart.d.ts +70 -0
  2. package/dist/components/SimpleCharts/LineChart/LineChart.figma.d.ts +1 -0
  3. package/dist/components/SimpleCharts/LineChart/LineChart.figma.js +163 -0
  4. package/dist/components/SimpleCharts/LineChart/LineChart.js +136 -0
  5. package/dist/components/SimpleCharts/LineChart/LineChartBody.d.ts +12 -0
  6. package/dist/components/SimpleCharts/LineChart/LineChartBody.js +66 -0
  7. package/dist/components/SimpleCharts/LineChart/LineChartContext.d.ts +151 -0
  8. package/dist/components/SimpleCharts/LineChart/LineChartContext.js +16 -0
  9. package/dist/components/SimpleCharts/LineChart/LineChartEmpty.d.ts +15 -0
  10. package/dist/components/SimpleCharts/LineChart/LineChartEmpty.js +71 -0
  11. package/dist/components/SimpleCharts/LineChart/LineChartGrid.d.ts +19 -0
  12. package/dist/components/SimpleCharts/LineChart/LineChartGrid.js +17 -0
  13. package/dist/components/SimpleCharts/LineChart/LineChartHoverPopover.d.ts +5 -0
  14. package/dist/components/SimpleCharts/LineChart/LineChartHoverPopover.js +14 -0
  15. package/dist/components/SimpleCharts/LineChart/LineChartHoverPopoverDot.d.ts +14 -0
  16. package/dist/components/SimpleCharts/LineChart/LineChartHoverPopoverDot.js +20 -0
  17. package/dist/components/SimpleCharts/LineChart/LineChartHoverPopoverRow.d.ts +12 -0
  18. package/dist/components/SimpleCharts/LineChart/LineChartHoverPopoverRow.js +33 -0
  19. package/dist/components/SimpleCharts/LineChart/LineChartHoverPopoverTimestamp.d.ts +5 -0
  20. package/dist/components/SimpleCharts/LineChart/LineChartHoverPopoverTimestamp.js +12 -0
  21. package/dist/components/SimpleCharts/LineChart/LineChartLegend.d.ts +15 -0
  22. package/dist/components/SimpleCharts/LineChart/LineChartLegend.js +19 -0
  23. package/dist/components/SimpleCharts/LineChart/LineChartLegendItem.d.ts +14 -0
  24. package/dist/components/SimpleCharts/LineChart/LineChartLegendItem.js +112 -0
  25. package/dist/components/SimpleCharts/LineChart/LineChartLine.d.ts +17 -0
  26. package/dist/components/SimpleCharts/LineChart/LineChartLine.js +57 -0
  27. package/dist/components/SimpleCharts/LineChart/LineChartTooltip.d.ts +31 -0
  28. package/dist/components/SimpleCharts/LineChart/LineChartTooltip.js +75 -0
  29. package/dist/components/SimpleCharts/LineChart/LineChartXAxis.d.ts +51 -0
  30. package/dist/components/SimpleCharts/LineChart/LineChartXAxis.js +34 -0
  31. package/dist/components/SimpleCharts/LineChart/LineChartYAxis.d.ts +24 -0
  32. package/dist/components/SimpleCharts/LineChart/LineChartYAxis.js +30 -0
  33. package/dist/components/SimpleCharts/LineChart/LineChartZoomBrush.d.ts +32 -0
  34. package/dist/components/SimpleCharts/LineChart/LineChartZoomBrush.js +104 -0
  35. package/dist/components/SimpleCharts/LineChart/LineChartZoomPopover.d.ts +5 -0
  36. package/dist/components/SimpleCharts/LineChart/LineChartZoomPopover.js +14 -0
  37. package/dist/components/SimpleCharts/LineChart/LineChartZoomPopoverConfirm.d.ts +5 -0
  38. package/dist/components/SimpleCharts/LineChart/LineChartZoomPopoverConfirm.js +14 -0
  39. package/dist/components/SimpleCharts/LineChart/LineChartZoomPopoverRange.d.ts +5 -0
  40. package/dist/components/SimpleCharts/LineChart/LineChartZoomPopoverRange.js +12 -0
  41. package/dist/components/SimpleCharts/LineChart/classes.d.ts +28 -0
  42. package/dist/components/SimpleCharts/LineChart/classes.js +95 -0
  43. package/dist/components/SimpleCharts/LineChart/constants.d.ts +25 -0
  44. package/dist/components/SimpleCharts/LineChart/constants.js +26 -0
  45. package/dist/components/SimpleCharts/LineChart/hooks/index.d.ts +5 -0
  46. package/dist/components/SimpleCharts/LineChart/hooks/index.js +6 -0
  47. package/dist/components/SimpleCharts/LineChart/hooks/useLineChartActiveKey.d.ts +33 -0
  48. package/dist/components/SimpleCharts/LineChart/hooks/useLineChartActiveKey.js +33 -0
  49. package/dist/components/SimpleCharts/LineChart/hooks/useLineChartDataWarnings.d.ts +18 -0
  50. package/dist/components/SimpleCharts/LineChart/hooks/useLineChartDataWarnings.js +47 -0
  51. package/dist/components/SimpleCharts/LineChart/hooks/useLineChartZoomState.d.ts +37 -0
  52. package/dist/components/SimpleCharts/LineChart/hooks/useLineChartZoomState.js +111 -0
  53. package/dist/components/SimpleCharts/LineChart/hooks/useZoomDragListeners.d.ts +16 -0
  54. package/dist/components/SimpleCharts/LineChart/hooks/useZoomDragListeners.js +27 -0
  55. package/dist/components/SimpleCharts/LineChart/hooks/useZoomPendingListeners.d.ts +21 -0
  56. package/dist/components/SimpleCharts/LineChart/hooks/useZoomPendingListeners.js +35 -0
  57. package/dist/components/SimpleCharts/LineChart/index.d.ts +19 -0
  58. package/dist/components/SimpleCharts/LineChart/index.js +19 -0
  59. package/dist/components/SimpleCharts/LineChart/lib/dropEdgeGridLines.d.ts +30 -0
  60. package/dist/components/SimpleCharts/LineChart/lib/dropEdgeGridLines.js +48 -0
  61. package/dist/components/SimpleCharts/LineChart/lib/formatRange.d.ts +9 -0
  62. package/dist/components/SimpleCharts/LineChart/lib/formatRange.js +7 -0
  63. package/dist/components/SimpleCharts/LineChart/lib/sampleData.d.ts +15 -0
  64. package/dist/components/SimpleCharts/LineChart/lib/sampleData.js +109 -0
  65. package/dist/components/SimpleCharts/LineChart/lib/tickHorizontalCoordinates.d.ts +15 -0
  66. package/dist/components/SimpleCharts/LineChart/lib/tickHorizontalCoordinates.js +13 -0
  67. package/dist/components/SimpleCharts/LineChart/lib/warn.d.ts +4 -0
  68. package/dist/components/SimpleCharts/LineChart/lib/warn.js +6 -0
  69. package/dist/components/SimpleCharts/PieChart/PieChartContext.js +5 -2
  70. package/dist/components/SimpleCharts/PieChart/constants.d.ts +1 -2
  71. package/dist/components/SimpleCharts/PieChart/constants.js +2 -15
  72. package/dist/components/SimpleCharts/hooks/index.d.ts +1 -0
  73. package/dist/components/SimpleCharts/hooks/index.js +2 -0
  74. package/dist/components/SimpleCharts/hooks/useChartTimeFormatters.d.ts +21 -0
  75. package/dist/components/SimpleCharts/hooks/useChartTimeFormatters.js +33 -0
  76. package/dist/components/SimpleCharts/index.d.ts +3 -0
  77. package/dist/components/SimpleCharts/index.js +4 -1
  78. package/dist/components/SimpleCharts/lib/chartPalette.d.ts +10 -0
  79. package/dist/components/SimpleCharts/lib/chartPalette.js +20 -0
  80. package/dist/components/SimpleCharts/lib/hoverSync.d.ts +9 -0
  81. package/dist/components/SimpleCharts/lib/hoverSync.js +5 -0
  82. package/dist/components/SimpleCharts/lib/index.d.ts +2 -0
  83. package/dist/components/SimpleCharts/lib/index.js +3 -0
  84. package/dist/components/SimpleCharts/lib/timeFormatters.d.ts +25 -0
  85. package/dist/components/SimpleCharts/lib/timeFormatters.js +57 -0
  86. package/dist/metadata/components.json +3664 -1
  87. package/dist/utils/formatDateTime.d.ts +4 -0
  88. package/dist/utils/formatDateTime.js +1 -1
  89. package/package.json +1 -1
@@ -0,0 +1,70 @@
1
+ import { type HTMLAttributes, type ReactElement, type Ref } from 'react';
2
+ import type { SyncMethod } from 'recharts/types/synchronisation/types';
3
+ import { type TestableProps } from '../../../utils/testId';
4
+ import { type LineChartDatum, type LineChartSeries, type LineChartZoomRange } from './LineChartContext';
5
+ /**
6
+ * Generic over the datum shape so `xKey` and `series[].key` are checked at
7
+ * compile time against the actual data interface. When `T` is left at the
8
+ * default `LineChartDatum`, the constraints collapse to `string` and the API
9
+ * keeps its untyped form — the safety only kicks in when callers pass a
10
+ * concrete datum interface.
11
+ *
12
+ * ```ts
13
+ * interface RequestRow { timestamp: number; requests: number; errors: number }
14
+ *
15
+ * <LineChart<RequestRow>
16
+ * data={rows}
17
+ * xKey='timestamp' // ✅ valid keyof T
18
+ * series={[{ key: 'errors', label: 'Errors' }]} // ✅ valid keyof T
19
+ * />
20
+ * <LineChart<RequestRow> data={rows} xKey='timetamp' /> // ❌ Type error
21
+ * ```
22
+ */
23
+ export interface LineChartProps<T extends LineChartDatum = LineChartDatum> extends HTMLAttributes<HTMLDivElement>, TestableProps {
24
+ ref?: Ref<HTMLDivElement>;
25
+ /** Long-form data array, one entry per X position. */
26
+ data: T[];
27
+ /** Schema describing each line drawn from `data`. */
28
+ series: LineChartSeries<Extract<keyof T, string>>[];
29
+ /**
30
+ * Key on each datum used as the X-axis value. Required — a silent fallback
31
+ * would hide key-name typos until the chart renders empty.
32
+ */
33
+ xKey: Extract<keyof T, string>;
34
+ /**
35
+ * Controlled hover key — pass alongside `onActiveKeyChange` for cross-chart
36
+ * sync.
37
+ *
38
+ * **Heads-up:** if the controlled value points at a series key that no
39
+ * longer exists in `series` (filter, schema change, refresh), the chart
40
+ * pushes `null` back through `onActiveKeyChange` so sibling charts stop
41
+ * highlighting a stale key. If you wire `activeKey` to external state, the
42
+ * snap-to-null write will arrive as a normal state change — do not be
43
+ * surprised when your value resets after a series disappears.
44
+ */
45
+ activeKey?: string | null;
46
+ onActiveKeyChange?: (key: string | null) => void;
47
+ /** Controlled set of `series.key` values to hide from the plot. */
48
+ filteredKeys?: string[];
49
+ /** Fired after the user confirms a brush selection. */
50
+ onZoomChange?: (range: LineChartZoomRange | null) => void;
51
+ /**
52
+ * Charts that share a `syncId` synchronise their tooltip cursor and brush
53
+ * via recharts' built-in middleware — hovering one chart highlights the
54
+ * matching X on every sibling chart with the same id. Pair with `activeKey`
55
+ * + `onActiveKeyChange` if you also want the *series* highlight to sync.
56
+ */
57
+ syncId?: string | number;
58
+ /**
59
+ * How sibling `syncId` charts match X positions. Defaults to `'index'`
60
+ * (Recharts' default). Use `'value'` when the synced charts have different
61
+ * dataset lengths but share categorical X values.
62
+ *
63
+ * @see {@link https://recharts.github.io/en-US/examples/SynchronizedAreaChart/ Recharts synchronisation example}
64
+ */
65
+ syncMethod?: SyncMethod;
66
+ }
67
+ export declare function LineChart<T extends LineChartDatum = LineChartDatum>({ data, series, xKey, activeKey: controlledActiveKey, onActiveKeyChange, filteredKeys, onZoomChange, syncId, syncMethod, className, children, ref, 'data-testid': testId, ...props }: LineChartProps<T>): ReactElement;
68
+ export declare namespace LineChart {
69
+ var displayName: string;
70
+ }
@@ -0,0 +1,163 @@
1
+ import { jsx, jsxs } from "react/jsx-runtime";
2
+ import code_connect from "@figma/code-connect";
3
+ import { Chart } from "../Chart/Chart.js";
4
+ import { ChartHeader } from "../Chart/ChartHeader.js";
5
+ import { ChartTitle } from "../Chart/ChartTitle.js";
6
+ import { formatChartHour } from "../lib/timeFormatters.js";
7
+ import { LineChart } from "./LineChart.js";
8
+ import { LineChartBody } from "./LineChartBody.js";
9
+ import { LineChartGrid } from "./LineChartGrid.js";
10
+ import { LineChartHoverPopoverDot } from "./LineChartHoverPopoverDot.js";
11
+ import { LineChartLegend } from "./LineChartLegend.js";
12
+ import { LineChartLegendItem } from "./LineChartLegendItem.js";
13
+ import { LineChartLine } from "./LineChartLine.js";
14
+ import { LineChartTooltip } from "./LineChartTooltip.js";
15
+ import { LineChartXAxis } from "./LineChartXAxis.js";
16
+ import { LineChartYAxis } from "./LineChartYAxis.js";
17
+ import { LineChartZoomBrush } from "./LineChartZoomBrush.js";
18
+ const figmaNodeUrl = 'https://www.figma.com/design/VKb5gW46uSGw0rqrhZsbXT/WADS-Components?node-id=7490-123142&m=dev';
19
+ const figmaMultiNodeUrl = 'https://www.figma.com/design/VKb5gW46uSGw0rqrhZsbXT/WADS-Components?node-id=7509-2354&m=dev';
20
+ const sampleData = Array.from({
21
+ length: 24
22
+ }, (_, i)=>{
23
+ const t = Date.UTC(2025, 0, 1, i, 0, 0);
24
+ const requests = Math.round(120 + 60 * Math.sin(i / 3));
25
+ const errors = Math.round(20 + 12 * Math.cos(i / 4));
26
+ const latency = Math.round(80 + 20 * Math.sin(i / 5));
27
+ return {
28
+ timestamp: t,
29
+ requests,
30
+ errors,
31
+ latency
32
+ };
33
+ });
34
+ const singleSeries = [
35
+ {
36
+ key: 'requests',
37
+ label: 'Requests',
38
+ color: 'brand'
39
+ }
40
+ ];
41
+ const multiSeries = [
42
+ {
43
+ key: 'requests',
44
+ label: 'Requests',
45
+ color: 'brand'
46
+ },
47
+ {
48
+ key: 'errors',
49
+ label: 'Errors',
50
+ color: 'red'
51
+ },
52
+ {
53
+ key: 'latency',
54
+ label: 'Latency',
55
+ color: 'blue'
56
+ }
57
+ ];
58
+ const formatXTick = (value)=>formatChartHour(value);
59
+ const formatYTick = (value)=>Number(value).toLocaleString('en-US');
60
+ code_connect.connect(LineChart, figmaNodeUrl, {
61
+ props: {
62
+ title: code_connect.string('Title'),
63
+ state: code_connect["enum"]('State', {
64
+ Default: 'default',
65
+ Hovered: 'hovered',
66
+ Zooming: 'zooming'
67
+ })
68
+ },
69
+ example: ({ title, state })=>/*#__PURE__*/ jsxs(Chart, {
70
+ children: [
71
+ /*#__PURE__*/ jsx(ChartHeader, {
72
+ children: /*#__PURE__*/ jsx(ChartTitle, {
73
+ children: title
74
+ })
75
+ }),
76
+ /*#__PURE__*/ jsx(LineChart, {
77
+ data: sampleData,
78
+ series: singleSeries,
79
+ xKey: "timestamp",
80
+ children: /*#__PURE__*/ jsxs(LineChartBody, {
81
+ children: [
82
+ /*#__PURE__*/ jsx(LineChartGrid, {}),
83
+ /*#__PURE__*/ jsx(LineChartXAxis, {
84
+ tickFormatter: formatXTick,
85
+ minTickGap: 32
86
+ }),
87
+ /*#__PURE__*/ jsx(LineChartYAxis, {
88
+ tickFormatter: formatYTick
89
+ }),
90
+ /*#__PURE__*/ jsx(LineChartLine, {
91
+ seriesKey: "requests"
92
+ }),
93
+ /*#__PURE__*/ jsx(LineChartTooltip, {
94
+ xTickFormatter: formatChartHour
95
+ }),
96
+ 'zooming' === state && /*#__PURE__*/ jsx(LineChartZoomBrush, {})
97
+ ]
98
+ })
99
+ })
100
+ ]
101
+ })
102
+ });
103
+ code_connect.connect(LineChart, figmaMultiNodeUrl, {
104
+ props: {
105
+ title: code_connect.string('Title'),
106
+ state: code_connect["enum"]('State', {
107
+ Default: 'default',
108
+ Hovered: 'hovered',
109
+ Filtered: 'filtered'
110
+ })
111
+ },
112
+ example: ({ title, state })=>/*#__PURE__*/ jsxs(Chart, {
113
+ children: [
114
+ /*#__PURE__*/ jsx(ChartHeader, {
115
+ children: /*#__PURE__*/ jsx(ChartTitle, {
116
+ children: title
117
+ })
118
+ }),
119
+ /*#__PURE__*/ jsxs(LineChart, {
120
+ data: sampleData,
121
+ series: multiSeries,
122
+ xKey: "timestamp",
123
+ filteredKeys: 'filtered' === state ? [
124
+ 'latency'
125
+ ] : [],
126
+ children: [
127
+ /*#__PURE__*/ jsx(LineChartLegend, {
128
+ children: multiSeries.map((s)=>/*#__PURE__*/ jsxs(LineChartLegendItem, {
129
+ seriesKey: s.key,
130
+ children: [
131
+ /*#__PURE__*/ jsx(LineChartHoverPopoverDot, {
132
+ color: s.color
133
+ }),
134
+ /*#__PURE__*/ jsx("span", {
135
+ className: "text-xs font-mono text-text-primary",
136
+ children: s.label
137
+ })
138
+ ]
139
+ }, s.key))
140
+ }),
141
+ /*#__PURE__*/ jsxs(LineChartBody, {
142
+ children: [
143
+ /*#__PURE__*/ jsx(LineChartGrid, {}),
144
+ /*#__PURE__*/ jsx(LineChartXAxis, {
145
+ tickFormatter: formatXTick,
146
+ minTickGap: 32
147
+ }),
148
+ /*#__PURE__*/ jsx(LineChartYAxis, {
149
+ tickFormatter: formatYTick
150
+ }),
151
+ multiSeries.map((s)=>/*#__PURE__*/ jsx(LineChartLine, {
152
+ seriesKey: s.key
153
+ }, s.key)),
154
+ /*#__PURE__*/ jsx(LineChartTooltip, {
155
+ xTickFormatter: formatChartHour
156
+ })
157
+ ]
158
+ })
159
+ ]
160
+ })
161
+ ]
162
+ })
163
+ });
@@ -0,0 +1,136 @@
1
+ import { jsx } from "react/jsx-runtime";
2
+ import { useCallback, useMemo, useRef } from "react";
3
+ import { cn } from "../../../utils/cn.js";
4
+ import { TestIdProvider } from "../../../utils/testId.js";
5
+ import { lineChartRootClasses } from "./classes.js";
6
+ import { useLineChartActiveKey } from "./hooks/useLineChartActiveKey.js";
7
+ import { useLineChartDataWarnings } from "./hooks/useLineChartDataWarnings.js";
8
+ import { useLineChartZoomState } from "./hooks/useLineChartZoomState.js";
9
+ import { EMPTY_HIDDEN_SET, LineChartActiveContext, LineChartDataContext, LineChartSelectionContext, LineChartZoomContext } from "./LineChartContext.js";
10
+ function LineChart({ data, series, xKey, activeKey: controlledActiveKey, onActiveKeyChange, filteredKeys, onZoomChange, syncId, syncMethod, className, children, ref, 'data-testid': testId, ...props }) {
11
+ const seriesByKey = useMemo(()=>{
12
+ const map = new Map();
13
+ for (const s of series)map.set(s.key, s);
14
+ return map;
15
+ }, [
16
+ series
17
+ ]);
18
+ useLineChartDataWarnings({
19
+ data,
20
+ series,
21
+ xKey
22
+ });
23
+ const { activeKey, setActiveKey } = useLineChartActiveKey({
24
+ controlledActiveKey,
25
+ onActiveKeyChange,
26
+ seriesByKey
27
+ });
28
+ const emitZoom = useCallback((range)=>{
29
+ onZoomChange?.(range);
30
+ }, [
31
+ onZoomChange
32
+ ]);
33
+ const zoom = useLineChartZoomState({
34
+ data,
35
+ xKey,
36
+ onZoomChange
37
+ });
38
+ const hiddenSet = useMemo(()=>{
39
+ if (!filteredKeys?.length) return EMPTY_HIDDEN_SET;
40
+ const set = new Set();
41
+ for (const key of filteredKeys)if (seriesByKey.has(key)) set.add(key);
42
+ return set.size > 0 ? set : EMPTY_HIDDEN_SET;
43
+ }, [
44
+ filteredKeys,
45
+ seriesByKey
46
+ ]);
47
+ const dataValue = useMemo(()=>({
48
+ data,
49
+ series,
50
+ seriesByKey,
51
+ xKey,
52
+ hiddenSet,
53
+ setActiveKey,
54
+ emitZoom,
55
+ syncId,
56
+ syncMethod
57
+ }), [
58
+ data,
59
+ series,
60
+ seriesByKey,
61
+ xKey,
62
+ hiddenSet,
63
+ setActiveKey,
64
+ emitZoom,
65
+ syncId,
66
+ syncMethod
67
+ ]);
68
+ const activeKeyContextValue = useMemo(()=>({
69
+ activeKey
70
+ }), [
71
+ activeKey
72
+ ]);
73
+ const selectionValue = useMemo(()=>({
74
+ hiddenSet
75
+ }), [
76
+ hiddenSet
77
+ ]);
78
+ const rootRef = useRef(null);
79
+ const setRootRef = useCallback((node)=>{
80
+ rootRef.current = node;
81
+ if ('function' == typeof ref) ref(node);
82
+ else if (ref) ref.current = node;
83
+ }, [
84
+ ref
85
+ ]);
86
+ const { enabled: zoomEnabled, drag: zoomDrag, pending: zoomPending, registerEnabled, startDrag, updateDrag, endDrag, cancelDrag, confirmZoom, cancelPending } = zoom;
87
+ const zoomContextValue = useMemo(()=>({
88
+ enabled: zoomEnabled,
89
+ drag: zoomDrag,
90
+ pending: zoomPending,
91
+ rootRef,
92
+ registerEnabled,
93
+ startDrag,
94
+ updateDrag,
95
+ endDrag,
96
+ cancelDrag,
97
+ confirmZoom,
98
+ cancelPending
99
+ }), [
100
+ zoomEnabled,
101
+ zoomDrag,
102
+ zoomPending,
103
+ registerEnabled,
104
+ startDrag,
105
+ updateDrag,
106
+ endDrag,
107
+ cancelDrag,
108
+ confirmZoom,
109
+ cancelPending
110
+ ]);
111
+ return /*#__PURE__*/ jsx(LineChartDataContext.Provider, {
112
+ value: dataValue,
113
+ children: /*#__PURE__*/ jsx(LineChartActiveContext.Provider, {
114
+ value: activeKeyContextValue,
115
+ children: /*#__PURE__*/ jsx(LineChartSelectionContext.Provider, {
116
+ value: selectionValue,
117
+ children: /*#__PURE__*/ jsx(LineChartZoomContext.Provider, {
118
+ value: zoomContextValue,
119
+ children: /*#__PURE__*/ jsx(TestIdProvider, {
120
+ value: testId,
121
+ children: /*#__PURE__*/ jsx("div", {
122
+ ...props,
123
+ ref: setRootRef,
124
+ "data-slot": "line-chart",
125
+ "data-testid": testId,
126
+ className: cn(lineChartRootClasses, className),
127
+ children: children
128
+ })
129
+ })
130
+ })
131
+ })
132
+ })
133
+ });
134
+ }
135
+ LineChart.displayName = 'LineChart';
136
+ export { LineChart };
@@ -0,0 +1,12 @@
1
+ import { type FC, type HTMLAttributes, type ReactNode, type Ref } from 'react';
2
+ export interface LineChartBodyProps extends HTMLAttributes<HTMLDivElement> {
3
+ ref?: Ref<HTMLDivElement>;
4
+ /** Recharts subcomponents — `<XAxis>`, `<YAxis>`, `<CartesianGrid>`, `<Line>`, `<Tooltip>`, `<Brush>`. */
5
+ children?: ReactNode;
6
+ /**
7
+ * Body height passed to recharts' `<ResponsiveContainer>`. Defaults to the
8
+ * Figma single-line plot height (`LINE_CARD_HEIGHT - LINE_HEADER_HEIGHT`).
9
+ */
10
+ height?: number;
11
+ }
12
+ export declare const LineChartBody: FC<LineChartBodyProps>;
@@ -0,0 +1,66 @@
1
+ import { jsx } from "react/jsx-runtime";
2
+ import { useCallback, useContext } from "react";
3
+ import { LineChart, ResponsiveContainer } from "recharts";
4
+ import { cn } from "../../../utils/cn.js";
5
+ import { useTestId } from "../../../utils/testId.js";
6
+ import { lineChartBodyClasses, lineChartBodyZoomEnabledClasses } from "./classes.js";
7
+ import { LINE_CARD_HEIGHT, LINE_DEFAULT_BODY_MARGIN, LINE_HEADER_HEIGHT } from "./constants.js";
8
+ import { LineChartDataContext, LineChartZoomContext } from "./LineChartContext.js";
9
+ const DEFAULT_BODY_HEIGHT = LINE_CARD_HEIGHT - LINE_HEADER_HEIGHT;
10
+ const toTooltipIndex = (value)=>{
11
+ if ('number' == typeof value) return Number.isFinite(value) ? value : null;
12
+ if ('string' == typeof value) {
13
+ const parsed = Number(value);
14
+ return Number.isFinite(parsed) ? parsed : null;
15
+ }
16
+ return null;
17
+ };
18
+ const LineChartBody = ({ height = DEFAULT_BODY_HEIGHT, className, ref, children, ...props })=>{
19
+ const testId = useTestId('body');
20
+ const dataCtx = useContext(LineChartDataContext);
21
+ const zoomCtx = useContext(LineChartZoomContext);
22
+ const isZoomEnabled = zoomCtx?.enabled ?? false;
23
+ const isZoomDragging = zoomCtx?.drag != null;
24
+ const handleMouseDown = useCallback((state, event)=>{
25
+ if (!zoomCtx?.enabled) return;
26
+ const index = toTooltipIndex(state.activeTooltipIndex);
27
+ if (null === index) return;
28
+ event.preventDefault();
29
+ zoomCtx.startDrag(index, event.clientX, event.clientY);
30
+ }, [
31
+ zoomCtx
32
+ ]);
33
+ const handleMouseMove = useCallback((state, event)=>{
34
+ if (!zoomCtx?.drag) return;
35
+ const next = toTooltipIndex(state.activeTooltipIndex);
36
+ if (null === next) return;
37
+ zoomCtx.updateDrag(next, event.clientX, event.clientY);
38
+ }, [
39
+ zoomCtx
40
+ ]);
41
+ return /*#__PURE__*/ jsx("div", {
42
+ ...props,
43
+ ref: ref,
44
+ "data-slot": "line-chart-body",
45
+ "data-testid": testId,
46
+ "aria-hidden": "true",
47
+ "data-zoom-active": isZoomDragging ? 'true' : void 0,
48
+ className: cn(lineChartBodyClasses, isZoomEnabled && lineChartBodyZoomEnabledClasses, className),
49
+ children: /*#__PURE__*/ jsx(ResponsiveContainer, {
50
+ width: "100%",
51
+ height: height,
52
+ children: /*#__PURE__*/ jsx(LineChart, {
53
+ data: dataCtx?.data ?? [],
54
+ margin: LINE_DEFAULT_BODY_MARGIN,
55
+ accessibilityLayer: false,
56
+ syncId: dataCtx?.syncId,
57
+ syncMethod: dataCtx?.syncMethod,
58
+ onMouseDown: handleMouseDown,
59
+ onMouseMove: handleMouseMove,
60
+ children: children
61
+ })
62
+ })
63
+ });
64
+ };
65
+ LineChartBody.displayName = 'LineChartBody';
66
+ export { LineChartBody };
@@ -0,0 +1,151 @@
1
+ import { type RefObject } from 'react';
2
+ import type { SyncMethod } from 'recharts/types/synchronisation/types';
3
+ import type { ChartColor } from '../types';
4
+ /**
5
+ * A single point on the X axis. Extra keys are series values.
6
+ *
7
+ * The loose default form is `Record<string, …>` — pass a concrete interface
8
+ * (e.g. `interface MyDatum { timestamp: number; requests: number }`) to gain
9
+ * compile-time safety on `xKey` and `series[].key`. See `LineChartProps<T>`.
10
+ */
11
+ export type LineChartDatum = Record<string, number | string | null | undefined>;
12
+ /**
13
+ * Series schema. `K` is the literal-string union of valid keys; defaults to
14
+ * `string` so untyped callers keep the loose form. When `LineChartProps<T>`
15
+ * is parameterised with a concrete `T`, `K` collapses to `Extract<keyof T,
16
+ * string>` and a typo in `key` becomes a compile error rather than a
17
+ * dev-mode `console.warn`.
18
+ */
19
+ export interface LineChartSeries<K extends string = string> {
20
+ /**
21
+ * Stable identity. Used as the lookup key on each `LineChartDatum`, the join key
22
+ * for legend/line/tooltip sync, and the React reconciliation key. Must be unique
23
+ * within `series`.
24
+ */
25
+ key: K;
26
+ /** Visible label rendered by the legend and the tooltip rows. */
27
+ label: string;
28
+ /**
29
+ * Series colour. Either a built-in palette token (`'brand'`, `'red'`, …) or
30
+ * any CSS colour string (`'var(--color-violet-500)'`, `'#8b5cf6'`,
31
+ * `'oklch(…)'`). Drives both the line stroke and the legend/tooltip dot — a
32
+ * single value keeps the two surfaces in sync. Defaults to `'slate'`.
33
+ */
34
+ color?: ChartColor | (string & {});
35
+ /** Visual line style. Defaults to `'solid'`. */
36
+ variant?: 'solid' | 'dashed';
37
+ }
38
+ export interface LineChartZoomRange {
39
+ /** Inclusive index into `data`. */
40
+ fromIndex: number;
41
+ /** Inclusive index into `data`. */
42
+ toIndex: number;
43
+ /** The `xKey` value at `fromIndex`. */
44
+ from: number | string;
45
+ /** The `xKey` value at `toIndex`. */
46
+ to: number | string;
47
+ }
48
+ /**
49
+ * Legend's internal row vs column layout. Pair with the wrapping layout the
50
+ * consumer chooses: `'horizontal'` for top/bottom JSX-order placement,
51
+ * `'vertical'` when wrapping body+legend in an `<HStack>` for left/right.
52
+ */
53
+ export type LineChartLegendOrientation = 'horizontal' | 'vertical';
54
+ /** Static chart shape — recomputes only when data/series/filter changes. */
55
+ export interface LineChartDataContextValue {
56
+ data: LineChartDatum[];
57
+ series: LineChartSeries[];
58
+ seriesByKey: Map<string, LineChartSeries>;
59
+ xKey: string;
60
+ hiddenSet: ReadonlySet<string>;
61
+ setActiveKey: (key: string | null) => void;
62
+ emitZoom: (range: LineChartZoomRange | null) => void;
63
+ /**
64
+ * Pair of charts that share a `syncId` get their tooltip cursor + brush
65
+ * synchronised by recharts' own redux middleware. `LineChartBody` forwards
66
+ * both values to `<RechartsLineChart>`; the chart itself does not read them.
67
+ */
68
+ syncId: string | number | undefined;
69
+ syncMethod: SyncMethod | undefined;
70
+ }
71
+ /**
72
+ * Active *series* — set by legend hover/focus. Drives line dimming and the
73
+ * legend item's `aria-current`/`data-active`. Cross-chart sync of the *cursor
74
+ * X* (tooltip + brush) is handled by recharts' built-in `syncId` mechanism on
75
+ * `<LineChart>` — only the series highlight needs custom controlled state, so
76
+ * the index has no equivalent context.
77
+ */
78
+ export interface LineChartActiveContextValue {
79
+ activeKey: string | null;
80
+ }
81
+ /** Set of `series.key` values that should be hidden from the plot and tooltip. */
82
+ export interface LineChartSelectionContextValue {
83
+ hiddenSet: ReadonlySet<string>;
84
+ }
85
+ /** In-progress zoom selection. Indices are inclusive into `data`. */
86
+ export interface LineChartZoomDragState {
87
+ startIndex: number;
88
+ endIndex: number;
89
+ /** Viewport coords of the latest pointer position — drives the floating popover. */
90
+ clientX: number;
91
+ clientY: number;
92
+ }
93
+ /**
94
+ * Released-but-unconfirmed zoom selection. The drag has ended, the gray
95
+ * selection rectangle stays, and the popover surfaces a "Zoom in" button for
96
+ * the user to confirm or dismiss. Position is locked at the cursor release.
97
+ */
98
+ export interface LineChartZoomPendingState {
99
+ range: LineChartZoomRange;
100
+ clientX: number;
101
+ clientY: number;
102
+ }
103
+ /**
104
+ * Zoom-drag state lives in its own context so the body re-renders on every
105
+ * mousemove frame without dragging the whole tree (static contexts like
106
+ * `LineChartDataContext` stay quiet). `enabled` flips when `LineChartZoomBrush`
107
+ * is mounted — the body uses it to decide whether to capture mousedown.
108
+ *
109
+ * The flow is two-phase: `drag` while the mouse button is held, then `pending`
110
+ * once it releases. `pending` is what the Figma confirm popover renders against
111
+ * — committing fires `onZoomChange`, dismissing just clears the state.
112
+ */
113
+ export interface LineChartZoomContextValue {
114
+ enabled: boolean;
115
+ drag: LineChartZoomDragState | null;
116
+ pending: LineChartZoomPendingState | null;
117
+ /**
118
+ * Ref to the owning chart root. Scopes the pending-state Enter/Escape
119
+ * handler so it only reacts to keystrokes from within *this* chart, even
120
+ * when several charts share the page (e.g. cross-chart hover sync).
121
+ */
122
+ rootRef: RefObject<HTMLDivElement | null>;
123
+ /** Called by `LineChartZoomBrush` on mount to opt the chart into zoom mode. */
124
+ registerEnabled: () => () => void;
125
+ startDrag: (index: number, clientX: number, clientY: number) => void;
126
+ updateDrag: (index: number, clientX: number, clientY: number) => void;
127
+ /** Releases the drag — moves it into `pending` for the user to confirm. */
128
+ endDrag: () => void;
129
+ /** Discards the in-progress drag without emitting. */
130
+ cancelDrag: () => void;
131
+ /** Commits the pending selection as a zoom range and clears it. */
132
+ confirmZoom: () => void;
133
+ /** Dismisses the pending selection without emitting. */
134
+ cancelPending: () => void;
135
+ }
136
+ /** Per-legend-row context — published by `LineChartLegendItem` to its children. */
137
+ export interface LineChartItemContextValue {
138
+ seriesKey: string;
139
+ selected: boolean;
140
+ interactive: boolean;
141
+ active: boolean;
142
+ color: ChartColor | string | undefined;
143
+ label: string | undefined;
144
+ }
145
+ export declare const EMPTY_HIDDEN_SET: ReadonlySet<string>;
146
+ export declare const isHoverSyncTarget: (target: EventTarget | null | undefined) => boolean;
147
+ export declare const LineChartDataContext: import("react").Context<LineChartDataContextValue | null>;
148
+ export declare const LineChartActiveContext: import("react").Context<LineChartActiveContextValue>;
149
+ export declare const LineChartSelectionContext: import("react").Context<LineChartSelectionContextValue>;
150
+ export declare const LineChartZoomContext: import("react").Context<LineChartZoomContextValue | null>;
151
+ export declare const LineChartItemContext: import("react").Context<LineChartItemContextValue | null>;
@@ -0,0 +1,16 @@
1
+ import { createContext } from "react";
2
+ import { makeIsHoverSyncTarget } from "../lib/hoverSync.js";
3
+ const EMPTY_HIDDEN_SET = new Set();
4
+ const isHoverSyncTarget = makeIsHoverSyncTarget([
5
+ 'line-chart-legend-item'
6
+ ]);
7
+ const LineChartDataContext = createContext(null);
8
+ const LineChartActiveContext = createContext({
9
+ activeKey: null
10
+ });
11
+ const LineChartSelectionContext = createContext({
12
+ hiddenSet: EMPTY_HIDDEN_SET
13
+ });
14
+ const LineChartZoomContext = createContext(null);
15
+ const LineChartItemContext = createContext(null);
16
+ export { EMPTY_HIDDEN_SET, LineChartActiveContext, LineChartDataContext, LineChartItemContext, LineChartSelectionContext, LineChartZoomContext, isHoverSyncTarget };
@@ -0,0 +1,15 @@
1
+ import type { FC, HTMLAttributes, ReactNode, Ref } from 'react';
2
+ import { type TestableProps } from '../../../utils/testId';
3
+ export interface LineChartEmptyProps extends HTMLAttributes<HTMLDivElement>, TestableProps {
4
+ ref?: Ref<HTMLDivElement>;
5
+ /** Body height override. Defaults to the standard plot height. */
6
+ height?: number;
7
+ /**
8
+ * Empty-state message. Pass the copy you want to render (`"No data"`, a
9
+ * localised string, or richer JSX). Omit (or pass `null`) to render only
10
+ * the dashed grid frame — the idiom for loading skeletons. There is no
11
+ * default text.
12
+ */
13
+ children?: ReactNode;
14
+ }
15
+ export declare const LineChartEmpty: FC<LineChartEmptyProps>;