@astryxdesign/lab 0.7.8-canary.ea33daf → 0.7.8-canary.eb985e5
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/dist/Chart/Chart.d.ts.map +1 -1
- package/dist/Chart/Chart.js +8 -7
- package/dist/Sankey/SankeyChart.d.ts.map +1 -1
- package/dist/Sankey/SankeyChart.js +4 -9
- package/package.json +5 -5
- package/src/Chart/Chart.test.tsx +31 -0
- package/src/Chart/Chart.tsx +8 -7
- package/src/Sankey/SankeyChart.test.tsx +31 -0
- package/src/Sankey/SankeyChart.tsx +4 -15
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"Chart.d.ts","sourceRoot":"","sources":["../../src/Chart/Chart.tsx"],"names":[],"mappings":"AAEA;;;;;;;;;;;GAWG;AAEH,OAAO,EAEL,KAAK,SAAS,EAMf,MAAM,OAAO,CAAC;AAMf,OAAO,KAAK,EAAC,WAAW,EAAa,MAAM,SAAS,CAAC;AAErD;;;;;GAKG;AACH,MAAM,MAAM,SAAS,GAAG,MAAM,GAAG,MAAM,GAAG,MAAM,CAAC;AAEjD,MAAM,WAAW,UAAU;IACzB,0DAA0D;IAC1D,IAAI,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,EAAE,CAAC;IAChC;;;OAGG;IACH,IAAI,EAAE,MAAM,CAAC;IACb;;;OAGG;IACH,KAAK,EAAE,MAAM,EAAE,CAAC;IAChB,qEAAqE;IACrE,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,+BAA+B;IAC/B,MAAM,CAAC,EAAE,OAAO,CAAC,WAAW,CAAC,CAAC;IAC9B;;;;;OAKG;IACH,SAAS,CAAC,EAAE,SAAS,CAAC;IACtB;;;;OAIG;IACH,OAAO,CAAC,EAAE,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;IAC3B;;;;;OAKG;IACH,OAAO,CAAC,EAAE,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;IAC3B;;;;OAIG;IACH,WAAW,CAAC,EAAE,OAAO,CAAC;IACtB;;;;;OAKG;IACH,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,6CAA6C;IAC7C,QAAQ,EAAE,SAAS,CAAC;CACrB;AAgBD;;;;;;;;;;;GAWG;AACH,wBAAgB,KAAK,CAAC,EACpB,IAAI,EACJ,IAAI,EACJ,KAAK,EACL,MAAY,EACZ,MAAM,EAAE,cAAc,EACtB,SAAkB,EAClB,OAAO,EAAE,WAAW,EACpB,OAAO,EAAE,WAAW,EACpB,WAAmB,EACnB,KAAK,EACL,QAAQ,GACT,EAAE,UAAU,+
|
|
1
|
+
{"version":3,"file":"Chart.d.ts","sourceRoot":"","sources":["../../src/Chart/Chart.tsx"],"names":[],"mappings":"AAEA;;;;;;;;;;;GAWG;AAEH,OAAO,EAEL,KAAK,SAAS,EAMf,MAAM,OAAO,CAAC;AAMf,OAAO,KAAK,EAAC,WAAW,EAAa,MAAM,SAAS,CAAC;AAErD;;;;;GAKG;AACH,MAAM,MAAM,SAAS,GAAG,MAAM,GAAG,MAAM,GAAG,MAAM,CAAC;AAEjD,MAAM,WAAW,UAAU;IACzB,0DAA0D;IAC1D,IAAI,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,EAAE,CAAC;IAChC;;;OAGG;IACH,IAAI,EAAE,MAAM,CAAC;IACb;;;OAGG;IACH,KAAK,EAAE,MAAM,EAAE,CAAC;IAChB,qEAAqE;IACrE,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,+BAA+B;IAC/B,MAAM,CAAC,EAAE,OAAO,CAAC,WAAW,CAAC,CAAC;IAC9B;;;;;OAKG;IACH,SAAS,CAAC,EAAE,SAAS,CAAC;IACtB;;;;OAIG;IACH,OAAO,CAAC,EAAE,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;IAC3B;;;;;OAKG;IACH,OAAO,CAAC,EAAE,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;IAC3B;;;;OAIG;IACH,WAAW,CAAC,EAAE,OAAO,CAAC;IACtB;;;;;OAKG;IACH,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,6CAA6C;IAC7C,QAAQ,EAAE,SAAS,CAAC;CACrB;AAgBD;;;;;;;;;;;GAWG;AACH,wBAAgB,KAAK,CAAC,EACpB,IAAI,EACJ,IAAI,EACJ,KAAK,EACL,MAAY,EACZ,MAAM,EAAE,cAAc,EACtB,SAAkB,EAClB,OAAO,EAAE,WAAW,EACpB,OAAO,EAAE,WAAW,EACpB,WAAmB,EACnB,KAAK,EACL,QAAQ,GACT,EAAE,UAAU,+BAgPZ"}
|
package/dist/Chart/Chart.js
CHANGED
|
@@ -73,18 +73,19 @@ export function Chart({
|
|
|
73
73
|
const containerRef = useRef(null);
|
|
74
74
|
const svgRef = useRef(null);
|
|
75
75
|
const [containerWidth, setContainerWidth] = useState(0);
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
return;
|
|
79
|
-
}
|
|
76
|
+
const attachContainer = useCallback(container => {
|
|
77
|
+
containerRef.current = container;
|
|
80
78
|
const observer = new ResizeObserver(entries => {
|
|
81
79
|
const entry = entries[0];
|
|
82
80
|
if (entry) {
|
|
83
81
|
setContainerWidth(entry.contentRect.width);
|
|
84
82
|
}
|
|
85
83
|
});
|
|
86
|
-
observer.observe(
|
|
87
|
-
return () =>
|
|
84
|
+
observer.observe(container);
|
|
85
|
+
return () => {
|
|
86
|
+
observer.disconnect();
|
|
87
|
+
containerRef.current = null;
|
|
88
|
+
};
|
|
88
89
|
}, []);
|
|
89
90
|
|
|
90
91
|
// Block scroll/zoom on the container when interactive.
|
|
@@ -236,7 +237,7 @@ export function Chart({
|
|
|
236
237
|
const accessibleLabel = label ?? `Chart of ${yKeys.join(', ')} by ${xKey}`;
|
|
237
238
|
const showDataTable = data.length > 0 && data.length * Math.max(yKeys.length, 1) <= MAX_TABLE_POINTS;
|
|
238
239
|
return /*#__PURE__*/_jsxs("div", {
|
|
239
|
-
ref:
|
|
240
|
+
ref: attachContainer,
|
|
240
241
|
style: containerStyle,
|
|
241
242
|
children: [containerWidth > 0 && /*#__PURE__*/_jsxs("svg", {
|
|
242
243
|
ref: svgRef,
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"SankeyChart.d.ts","sourceRoot":"","sources":["../../src/Sankey/SankeyChart.tsx"],"names":[],"mappings":"AAEA;;;;;;;;;;;GAWG;AAEH,OAAO,
|
|
1
|
+
{"version":3,"file":"SankeyChart.d.ts","sourceRoot":"","sources":["../../src/Sankey/SankeyChart.tsx"],"names":[],"mappings":"AAEA;;;;;;;;;;;GAWG;AAEH,OAAO,EAAC,KAAK,SAAS,EAAiC,MAAM,OAAO,CAAC;AAIrE,OAAO,KAAK,EAAC,eAAe,EAAE,eAAe,EAAE,YAAY,EAAC,MAAM,SAAS,CAAC;AAE5E,MAAM,WAAW,gBAAgB;IAC/B,uBAAuB;IACvB,KAAK,EAAE,eAAe,EAAE,CAAC;IACzB,uBAAuB;IACvB,KAAK,EAAE,eAAe,EAAE,CAAC;IACzB;;;;;;;OAOG;IACH,OAAO,CAAC,EAAE,YAAY,EAAE,CAAC;IACzB,wCAAwC;IACxC,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,yCAAyC;IACzC,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,uDAAuD;IACvD,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB;;;;OAIG;IACH,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB;;;OAGG;IACH,cAAc,CAAC,EAAE,MAAM,CAAC;IACxB;;;;;;OAMG;IACH,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,qBAAqB;IACrB,QAAQ,EAAE,SAAS,CAAC;CACrB;AAsDD;;;;;;;;;;;;;;;;;;;;;GAqBG;AACH,wBAAgB,WAAW,CAAC,EAC1B,KAAK,EACL,KAAK,EACL,OAAO,EACP,MAAY,EACZ,SAAc,EACd,OAAY,EACZ,SAAS,EACT,cAAoB,EACpB,KAAsB,EACtB,QAAQ,GACT,EAAE,gBAAgB,+BAiHlB;yBA5He,WAAW"}
|
|
@@ -13,7 +13,7 @@
|
|
|
13
13
|
* small graphs are mirrored in a visually hidden From/To/Value table.
|
|
14
14
|
*/
|
|
15
15
|
|
|
16
|
-
import {
|
|
16
|
+
import { useCallback, useMemo, useState } from 'react';
|
|
17
17
|
import { VisuallyHidden } from '@astryxdesign/core/VisuallyHidden';
|
|
18
18
|
import { SankeyProvider } from "./SankeyContext.js";
|
|
19
19
|
import { computeLayout } from "./layout.js";
|
|
@@ -100,18 +100,13 @@ export function SankeyChart({
|
|
|
100
100
|
label = 'Sankey chart',
|
|
101
101
|
children
|
|
102
102
|
}) {
|
|
103
|
-
const containerRef = useRef(null);
|
|
104
103
|
const [containerWidth, setContainerWidth] = useState(0);
|
|
105
|
-
|
|
106
|
-
const el = containerRef.current;
|
|
107
|
-
if (!el) {
|
|
108
|
-
return;
|
|
109
|
-
}
|
|
104
|
+
const observeContainerWidth = useCallback(container => {
|
|
110
105
|
const ro = new ResizeObserver(entries => {
|
|
111
106
|
const w = entries[0]?.contentRect.width ?? 0;
|
|
112
107
|
setContainerWidth(w);
|
|
113
108
|
});
|
|
114
|
-
ro.observe(
|
|
109
|
+
ro.observe(container);
|
|
115
110
|
return () => ro.disconnect();
|
|
116
111
|
}, []);
|
|
117
112
|
const colCount = useMemo(() => resolveColumnCount(columns, nodes, links), [columns, nodes, links]);
|
|
@@ -149,7 +144,7 @@ export function SankeyChart({
|
|
|
149
144
|
const nodeLabelById = useMemo(() => new Map(nodes.map(n => [n.id, n.label || n.id])), [nodes]);
|
|
150
145
|
const showDataTable = links.length > 0 && links.length <= MAX_TABLE_LINKS;
|
|
151
146
|
return /*#__PURE__*/_jsxs("div", {
|
|
152
|
-
ref:
|
|
147
|
+
ref: observeContainerWidth,
|
|
153
148
|
style: {
|
|
154
149
|
width: '100%'
|
|
155
150
|
},
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@astryxdesign/lab",
|
|
3
|
-
"version": "0.7.8-canary.
|
|
3
|
+
"version": "0.7.8-canary.eb985e5",
|
|
4
4
|
"description": "Experimental Astryx components — published to npm only under the @canary dist-tag for early testing; never released as a stable (latest) version.",
|
|
5
5
|
"author": "Meta Open Source",
|
|
6
6
|
"license": "MIT",
|
|
@@ -49,7 +49,7 @@
|
|
|
49
49
|
},
|
|
50
50
|
"peerDependencies": {
|
|
51
51
|
"@stylexjs/stylex": ">=0.10.0",
|
|
52
|
-
"@astryxdesign/core": "0.7.8-canary.
|
|
52
|
+
"@astryxdesign/core": "0.7.8-canary.eb985e5",
|
|
53
53
|
"react": ">=19.0.0",
|
|
54
54
|
"react-dom": ">=19.0.0"
|
|
55
55
|
},
|
|
@@ -59,9 +59,9 @@
|
|
|
59
59
|
"d3-shape": "^3.2.0"
|
|
60
60
|
},
|
|
61
61
|
"devDependencies": {
|
|
62
|
-
"@astryxdesign/a11y-spec": "0.7.8-canary.
|
|
63
|
-
"@astryxdesign/cli": "0.7.8-canary.
|
|
64
|
-
"@astryxdesign/interaction-harness": "0.7.8-canary.
|
|
62
|
+
"@astryxdesign/a11y-spec": "0.7.8-canary.eb985e5",
|
|
63
|
+
"@astryxdesign/cli": "0.7.8-canary.eb985e5",
|
|
64
|
+
"@astryxdesign/interaction-harness": "0.7.8-canary.eb985e5",
|
|
65
65
|
"@babel/cli": "^7.29.7",
|
|
66
66
|
"@babel/core": "^7.29.7",
|
|
67
67
|
"@babel/preset-react": "^7.29.7",
|
package/src/Chart/Chart.test.tsx
CHANGED
|
@@ -171,6 +171,37 @@ describe('Chart measurement gate', () => {
|
|
|
171
171
|
});
|
|
172
172
|
});
|
|
173
173
|
|
|
174
|
+
describe('Chart container observation', () => {
|
|
175
|
+
it('observes its container while mounted and stops on unmount', () => {
|
|
176
|
+
const observed = new Set<Element>();
|
|
177
|
+
vi.stubGlobal(
|
|
178
|
+
'ResizeObserver',
|
|
179
|
+
class {
|
|
180
|
+
observe(element: Element) {
|
|
181
|
+
observed.add(element);
|
|
182
|
+
}
|
|
183
|
+
unobserve(element: Element) {
|
|
184
|
+
observed.delete(element);
|
|
185
|
+
}
|
|
186
|
+
disconnect() {
|
|
187
|
+
observed.clear();
|
|
188
|
+
}
|
|
189
|
+
},
|
|
190
|
+
);
|
|
191
|
+
const {container, unmount} = render(
|
|
192
|
+
<Chart data={data} xKey="month" yKeys={['revenue']}>
|
|
193
|
+
<g />
|
|
194
|
+
</Chart>,
|
|
195
|
+
);
|
|
196
|
+
const chartContainer = container.firstElementChild;
|
|
197
|
+
expect(chartContainer).not.toBeNull();
|
|
198
|
+
expect(observed.has(chartContainer!)).toBe(true);
|
|
199
|
+
|
|
200
|
+
unmount();
|
|
201
|
+
expect(observed.size).toBe(0);
|
|
202
|
+
});
|
|
203
|
+
});
|
|
204
|
+
|
|
174
205
|
describe('useChart', () => {
|
|
175
206
|
it('throws a clear error when used outside <Chart>', () => {
|
|
176
207
|
// React reports the uncaught render error via console.error; keep the
|
package/src/Chart/Chart.tsx
CHANGED
|
@@ -134,18 +134,19 @@ export function Chart({
|
|
|
134
134
|
const svgRef = useRef<SVGSVGElement>(null);
|
|
135
135
|
const [containerWidth, setContainerWidth] = useState(0);
|
|
136
136
|
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
return;
|
|
140
|
-
}
|
|
137
|
+
const attachContainer = useCallback((container: HTMLDivElement) => {
|
|
138
|
+
containerRef.current = container;
|
|
141
139
|
const observer = new ResizeObserver(entries => {
|
|
142
140
|
const entry = entries[0];
|
|
143
141
|
if (entry) {
|
|
144
142
|
setContainerWidth(entry.contentRect.width);
|
|
145
143
|
}
|
|
146
144
|
});
|
|
147
|
-
observer.observe(
|
|
148
|
-
return () =>
|
|
145
|
+
observer.observe(container);
|
|
146
|
+
return () => {
|
|
147
|
+
observer.disconnect();
|
|
148
|
+
containerRef.current = null;
|
|
149
|
+
};
|
|
149
150
|
}, []);
|
|
150
151
|
|
|
151
152
|
// Block scroll/zoom on the container when interactive.
|
|
@@ -320,7 +321,7 @@ export function Chart({
|
|
|
320
321
|
data.length * Math.max(yKeys.length, 1) <= MAX_TABLE_POINTS;
|
|
321
322
|
|
|
322
323
|
return (
|
|
323
|
-
<div ref={
|
|
324
|
+
<div ref={attachContainer} style={containerStyle}>
|
|
324
325
|
{containerWidth > 0 && (
|
|
325
326
|
<svg
|
|
326
327
|
ref={svgRef}
|
|
@@ -76,6 +76,37 @@ describe('SankeyChart scroll container', () => {
|
|
|
76
76
|
});
|
|
77
77
|
});
|
|
78
78
|
|
|
79
|
+
describe('SankeyChart container observation', () => {
|
|
80
|
+
it('observes its container while mounted and stops on unmount', () => {
|
|
81
|
+
const observed = new Set<Element>();
|
|
82
|
+
vi.stubGlobal(
|
|
83
|
+
'ResizeObserver',
|
|
84
|
+
class {
|
|
85
|
+
observe(element: Element) {
|
|
86
|
+
observed.add(element);
|
|
87
|
+
}
|
|
88
|
+
unobserve(element: Element) {
|
|
89
|
+
observed.delete(element);
|
|
90
|
+
}
|
|
91
|
+
disconnect() {
|
|
92
|
+
observed.clear();
|
|
93
|
+
}
|
|
94
|
+
},
|
|
95
|
+
);
|
|
96
|
+
const {container, unmount} = render(
|
|
97
|
+
<SankeyChart nodes={nodes} links={links}>
|
|
98
|
+
<SankeyNode />
|
|
99
|
+
</SankeyChart>,
|
|
100
|
+
);
|
|
101
|
+
const chartContainer = container.firstElementChild;
|
|
102
|
+
expect(chartContainer).not.toBeNull();
|
|
103
|
+
expect(observed.has(chartContainer!)).toBe(true);
|
|
104
|
+
|
|
105
|
+
unmount();
|
|
106
|
+
expect(observed.size).toBe(0);
|
|
107
|
+
});
|
|
108
|
+
});
|
|
109
|
+
|
|
79
110
|
describe('SankeyChart accessible name', () => {
|
|
80
111
|
it('names the svg when the chart does not scroll', () => {
|
|
81
112
|
render(
|
|
@@ -13,13 +13,7 @@
|
|
|
13
13
|
* small graphs are mirrored in a visually hidden From/To/Value table.
|
|
14
14
|
*/
|
|
15
15
|
|
|
16
|
-
import {
|
|
17
|
-
type ReactNode,
|
|
18
|
-
useMemo,
|
|
19
|
-
useRef,
|
|
20
|
-
useState,
|
|
21
|
-
useLayoutEffect,
|
|
22
|
-
} from 'react';
|
|
16
|
+
import {type ReactNode, useCallback, useMemo, useState} from 'react';
|
|
23
17
|
import {VisuallyHidden} from '@astryxdesign/core/VisuallyHidden';
|
|
24
18
|
import {SankeyProvider} from './SankeyContext';
|
|
25
19
|
import {computeLayout} from './layout';
|
|
@@ -154,19 +148,14 @@ export function SankeyChart({
|
|
|
154
148
|
label = 'Sankey chart',
|
|
155
149
|
children,
|
|
156
150
|
}: SankeyChartProps) {
|
|
157
|
-
const containerRef = useRef<HTMLDivElement>(null);
|
|
158
151
|
const [containerWidth, setContainerWidth] = useState(0);
|
|
159
152
|
|
|
160
|
-
|
|
161
|
-
const el = containerRef.current;
|
|
162
|
-
if (!el) {
|
|
163
|
-
return;
|
|
164
|
-
}
|
|
153
|
+
const observeContainerWidth = useCallback((container: HTMLDivElement) => {
|
|
165
154
|
const ro = new ResizeObserver(entries => {
|
|
166
155
|
const w = entries[0]?.contentRect.width ?? 0;
|
|
167
156
|
setContainerWidth(w);
|
|
168
157
|
});
|
|
169
|
-
ro.observe(
|
|
158
|
+
ro.observe(container);
|
|
170
159
|
return () => ro.disconnect();
|
|
171
160
|
}, []);
|
|
172
161
|
|
|
@@ -225,7 +214,7 @@ export function SankeyChart({
|
|
|
225
214
|
const showDataTable = links.length > 0 && links.length <= MAX_TABLE_LINKS;
|
|
226
215
|
|
|
227
216
|
return (
|
|
228
|
-
<div ref={
|
|
217
|
+
<div ref={observeContainerWidth} style={{width: '100%'}}>
|
|
229
218
|
{ctx && (
|
|
230
219
|
<div
|
|
231
220
|
role={needsScroll ? 'group' : undefined}
|