@astryxdesign/lab 0.7.8-canary.f50bc74 → 0.7.8-canary.f60d2bb
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/Comments/CommentActions.d.ts +2 -2
- package/dist/Comments/CommentActions.d.ts.map +1 -1
- package/dist/Comments/CommentActions.js +9 -23
- 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/Chat/__tests__/ChatTypingIndicator.a11y.chromium.spec.ts +1 -1
- package/src/CircularProgress/__tests__/CircularProgress.a11y.chromium.spec.ts +1 -1
- package/src/CircularProgress/__tests__/CircularProgressMotion.a11y.chromium.spec.ts +1 -1
- package/src/Comments/CommentActions.tsx +7 -29
- package/src/Comments/Comments.test.tsx +32 -0
- package/src/Sankey/SankeyChart.test.tsx +31 -0
- package/src/Sankey/SankeyChart.tsx +4 -15
- package/src/Schedule/__tests__/ScheduleEventPopover.a11y.chromium.spec.ts +1 -1
- package/src/Schedule/__tests__/ScheduleMonthChip.a11y.chromium.spec.ts +1 -1
- package/src/Schedule/__tests__/ScheduleMonthEventPopover.a11y.chromium.spec.ts +1 -1
- package/src/Schedule/__tests__/ScheduleMonthOverflow.a11y.chromium.spec.ts +1 -1
- package/src/Schedule/__tests__/ScheduleTimeDirection.a11y.chromium.spec.ts +1 -1
- package/src/Schedule/__tests__/ScheduleTimeGridGeometry.a11y.chromium.spec.ts +1 -1
- package/src/Schedule/__tests__/ScheduleTimeGridInitialPosition.a11y.chromium.spec.ts +1 -1
- package/src/Schedule/__tests__/ScheduleTimeGridLongSpan.a11y.chromium.spec.ts +1 -1
- package/src/Schedule/__tests__/ScheduleTimeGridMidnight.a11y.chromium.spec.ts +1 -1
- package/src/Schedule/__tests__/ScheduleTimeGridOverlap.a11y.chromium.spec.ts +1 -1
- package/src/Schedule/__tests__/ScheduleTimeGridSkippedMidnight.a11y.chromium.spec.ts +1 -1
- package/src/SelectableCardGroup/__tests__/SelectableCardGroupRadio.a11y.chromium.spec.ts +1 -1
- package/src/__tests__/ReorderGripPinchZoom.a11y.chromium.spec.ts +6 -1
|
@@ -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,7 +1,7 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* @file CommentActions.tsx
|
|
3
|
-
* @input Uses React, React DOM flushSync, StyleX,
|
|
4
|
-
* ToggleButton, OverflowList, DropdownMenu, Popover, Text
|
|
3
|
+
* @input Uses React, React DOM flushSync, StyleX, useClipboard, IconButton,
|
|
4
|
+
* Button, Tooltip, ToggleButton, OverflowList, DropdownMenu, Popover, Text
|
|
5
5
|
* @output Exports CommentActions (a comment's header actions), ReactionSummary
|
|
6
6
|
* (its reaction toggles), and the action-lookup helpers rows use for focus
|
|
7
7
|
* hand-offs
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"CommentActions.d.ts","sourceRoot":"","sources":["../../src/Comments/CommentActions.tsx"],"names":[],"mappings":"AAIA;;;;;;;;GAQG;AAEH,OAAO,
|
|
1
|
+
{"version":3,"file":"CommentActions.d.ts","sourceRoot":"","sources":["../../src/Comments/CommentActions.tsx"],"names":[],"mappings":"AAIA;;;;;;;;GAQG;AAEH,OAAO,EAAgC,KAAK,SAAS,EAAC,MAAM,OAAO,CAAC;AAIpE,OAAO,EAEL,KAAK,kBAAkB,EACxB,MAAM,iCAAiC,CAAC;AAczC,OAAO,EAAkB,KAAK,UAAU,EAAC,MAAM,SAAS,CAAC;AACzD,OAAO,KAAK,EAAkB,qBAAqB,EAAC,MAAM,SAAS,CAAC;AAmBpE,MAAM,MAAM,eAAe,GAAG,SAAS,GAAG,QAAQ,GAAG,OAAO,GAAG,OAAO,GAAG,MAAM,CAAC;AAEhF,oEAAoE;AACpE,MAAM,MAAM,aAAa,GAAG;IAAC,IAAI,EAAE,SAAS,GAAG,QAAQ,CAAC;IAAC,OAAO,EAAE,MAAM,IAAI,CAAA;CAAC,CAAC;AAE9E;;sBAEsB;AACtB,wBAAgB,oBAAoB,CAClC,IAAI,EAAE,WAAW,GAAG,IAAI,EACxB,MAAM,EAAE,eAAe,GACtB,WAAW,GAAG,IAAI,CAMpB;AAED,wBAAgB,sBAAsB,CACpC,IAAI,EAAE,WAAW,GAAG,IAAI,GACvB,WAAW,GAAG,IAAI,CAIpB;AAiCD,kFAAkF;AAClF,wBAAgB,eAAe,CAAC,EAC9B,QAAQ,EACR,OAAO,EACP,MAAM,EACN,OAAO,GACR,EAAE;IACD,QAAQ,EAAE,OAAO,CAAC;IAClB,OAAO,EAAE,UAAU,CAAC;IACpB,MAAM,EAAE,OAAO,CAAC;IAChB,OAAO,EAAE,CAAC,OAAO,EAAE,UAAU,EAAE,GAAG,EAAE,MAAM,KAAK,IAAI,CAAC;CACrD,sCA0CA;AAkDD;;;;;GAKG;AACH,wBAAgB,cAAc,CAAC,EAC7B,iBAAiB,EACjB,WAAW,EACX,QAAQ,EACR,QAAQ,EACR,OAAO,EACP,MAAM,EACN,SAAS,EACT,SAAS,EACT,YAAY,EACZ,OAAO,EACP,OAAO,EACP,OAAO,EACP,aAAa,GACd,EAAE;IACD,iBAAiB,CAAC,EAAE,SAAS,CAAC;IAC9B,WAAW,EAAE,OAAO,CAAC;IACrB,QAAQ,EAAE,OAAO,CAAC;IAClB,QAAQ,EAAE,OAAO,CAAC;IAClB,OAAO,EAAE,UAAU,CAAC;IACpB,MAAM,EAAE,OAAO,CAAC;IAChB,sDAAsD;IACtD,SAAS,EAAE,SAAS,kBAAkB,EAAE,CAAC;IACzC,SAAS,EAAE,MAAM,CAAC;IAClB,sEAAsE;IACtE,YAAY,EAAE,CAAC,MAAM,EAAE,OAAO,KAAK,IAAI,CAAC;IACxC,OAAO,EAAE,CACP,OAAO,EAAE,UAAU,EACnB,GAAG,EAAE,MAAM,EACX,MAAM,CAAC,EAAE,qBAAqB,KAC3B,IAAI,CAAC;IACV,OAAO,EAAE,MAAM,IAAI,CAAC;IACpB,OAAO,EAAE,SAAS,qBAAqB,EAAE,CAAC;IAC1C,aAAa,CAAC,EAAE,aAAa,CAAC;CAC/B,+BAuQA"}
|
|
@@ -4,18 +4,19 @@
|
|
|
4
4
|
|
|
5
5
|
/**
|
|
6
6
|
* @file CommentActions.tsx
|
|
7
|
-
* @input Uses React, React DOM flushSync, StyleX,
|
|
8
|
-
* ToggleButton, OverflowList, DropdownMenu, Popover, Text
|
|
7
|
+
* @input Uses React, React DOM flushSync, StyleX, useClipboard, IconButton,
|
|
8
|
+
* Button, Tooltip, ToggleButton, OverflowList, DropdownMenu, Popover, Text
|
|
9
9
|
* @output Exports CommentActions (a comment's header actions), ReactionSummary
|
|
10
10
|
* (its reaction toggles), and the action-lookup helpers rows use for focus
|
|
11
11
|
* hand-offs
|
|
12
12
|
* @position Internal parts of a comment row in the Comments family
|
|
13
13
|
*/
|
|
14
|
-
import { useCallback,
|
|
14
|
+
import { useCallback, useRef, useState } from 'react';
|
|
15
15
|
import { flushSync } from 'react-dom';
|
|
16
16
|
import * as stylex from '@stylexjs/stylex';
|
|
17
17
|
import { Button } from '@astryxdesign/core/Button';
|
|
18
18
|
import { DropdownMenu } from '@astryxdesign/core/DropdownMenu';
|
|
19
|
+
import { useClipboard } from '@astryxdesign/core/hooks';
|
|
19
20
|
import { Icon } from '@astryxdesign/core/Icon';
|
|
20
21
|
import { IconButton } from '@astryxdesign/core/IconButton';
|
|
21
22
|
import { HStack, VStack } from '@astryxdesign/core/Layout';
|
|
@@ -31,7 +32,6 @@ import { reactionDescription } from "./i18n.js";
|
|
|
31
32
|
import { CommentIcon } from "./icons.js";
|
|
32
33
|
import { commentAnchorId } from "./utils.js";
|
|
33
34
|
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
34
|
-
const LINK_COPIED_RESET_MS = 2_000;
|
|
35
35
|
const MORE_MENU_MIN_WIDTH = `calc(${spacingVars['--spacing-8']} * 5)`;
|
|
36
36
|
const styles = {
|
|
37
37
|
actionsList: {
|
|
@@ -218,7 +218,10 @@ export function CommentActions({
|
|
|
218
218
|
resolveAction
|
|
219
219
|
}) {
|
|
220
220
|
const t = useTranslator();
|
|
221
|
-
const
|
|
221
|
+
const {
|
|
222
|
+
copy: copyToClipboard,
|
|
223
|
+
isCopied: isLinkCopied
|
|
224
|
+
} = useClipboard();
|
|
222
225
|
const [isLinkTooltipOpen, setIsLinkTooltipOpen] = useState(false);
|
|
223
226
|
const [isPickerOpen, setIsPickerOpen] = useState(false);
|
|
224
227
|
const [collapsed, setCollapsed] = useState(NO_COLLAPSED_ACTIONS);
|
|
@@ -236,24 +239,7 @@ export function CommentActions({
|
|
|
236
239
|
}) : /*#__PURE__*/_jsx(CommentIcon, {
|
|
237
240
|
name: "copyLink"
|
|
238
241
|
});
|
|
239
|
-
const copyCommentLink =
|
|
240
|
-
if (navigator.clipboard == null) {
|
|
241
|
-
return;
|
|
242
|
-
}
|
|
243
|
-
try {
|
|
244
|
-
await navigator.clipboard.writeText(new URL(href, window.location.href).href);
|
|
245
|
-
setIsLinkCopied(true);
|
|
246
|
-
} catch {
|
|
247
|
-
setIsLinkCopied(false);
|
|
248
|
-
}
|
|
249
|
-
};
|
|
250
|
-
useEffect(() => {
|
|
251
|
-
if (!isLinkCopied) {
|
|
252
|
-
return;
|
|
253
|
-
}
|
|
254
|
-
const timer = window.setTimeout(() => setIsLinkCopied(false), LINK_COPIED_RESET_MS);
|
|
255
|
-
return () => window.clearTimeout(timer);
|
|
256
|
-
}, [isLinkCopied]);
|
|
242
|
+
const copyCommentLink = () => copyToClipboard(new URL(href, window.location.href).href);
|
|
257
243
|
const changePicker = isOpen => {
|
|
258
244
|
setIsPickerOpen(isOpen);
|
|
259
245
|
onOpenChange(isOpen);
|
|
@@ -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.f60d2bb",
|
|
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.f60d2bb",
|
|
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.f60d2bb",
|
|
63
|
+
"@astryxdesign/cli": "0.7.8-canary.f60d2bb",
|
|
64
|
+
"@astryxdesign/interaction-harness": "0.7.8-canary.f60d2bb",
|
|
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}
|
|
@@ -19,7 +19,7 @@
|
|
|
19
19
|
|
|
20
20
|
import fs from 'node:fs';
|
|
21
21
|
import path from 'node:path';
|
|
22
|
-
import {expect, test, type Page} from '@playwright
|
|
22
|
+
import {expect, test, type Page} from '@astryxdesign/a11y-spec/playwright';
|
|
23
23
|
import {
|
|
24
24
|
DEFAULT_STORYBOOK_DIR,
|
|
25
25
|
serveStorybook,
|
|
@@ -4,15 +4,15 @@
|
|
|
4
4
|
|
|
5
5
|
/**
|
|
6
6
|
* @file CommentActions.tsx
|
|
7
|
-
* @input Uses React, React DOM flushSync, StyleX,
|
|
8
|
-
* ToggleButton, OverflowList, DropdownMenu, Popover, Text
|
|
7
|
+
* @input Uses React, React DOM flushSync, StyleX, useClipboard, IconButton,
|
|
8
|
+
* Button, Tooltip, ToggleButton, OverflowList, DropdownMenu, Popover, Text
|
|
9
9
|
* @output Exports CommentActions (a comment's header actions), ReactionSummary
|
|
10
10
|
* (its reaction toggles), and the action-lookup helpers rows use for focus
|
|
11
11
|
* hand-offs
|
|
12
12
|
* @position Internal parts of a comment row in the Comments family
|
|
13
13
|
*/
|
|
14
14
|
|
|
15
|
-
import {useCallback,
|
|
15
|
+
import {useCallback, useRef, useState, type ReactNode} from 'react';
|
|
16
16
|
import {flushSync} from 'react-dom';
|
|
17
17
|
import * as stylex from '@stylexjs/stylex';
|
|
18
18
|
import {Button} from '@astryxdesign/core/Button';
|
|
@@ -20,6 +20,7 @@ import {
|
|
|
20
20
|
DropdownMenu,
|
|
21
21
|
type DropdownMenuOption,
|
|
22
22
|
} from '@astryxdesign/core/DropdownMenu';
|
|
23
|
+
import {useClipboard} from '@astryxdesign/core/hooks';
|
|
23
24
|
import {Icon} from '@astryxdesign/core/Icon';
|
|
24
25
|
import {IconButton} from '@astryxdesign/core/IconButton';
|
|
25
26
|
import {HStack, VStack} from '@astryxdesign/core/Layout';
|
|
@@ -35,7 +36,6 @@ import {CommentIcon} from './icons';
|
|
|
35
36
|
import {commentAnchorId, type AnyComment} from './utils';
|
|
36
37
|
import type {CommentReaction, CommentReactionOption} from './types';
|
|
37
38
|
|
|
38
|
-
const LINK_COPIED_RESET_MS = 2_000;
|
|
39
39
|
const MORE_MENU_MIN_WIDTH = `calc(${spacingVars['--spacing-8']} * 5)`;
|
|
40
40
|
|
|
41
41
|
const styles = stylex.create({
|
|
@@ -256,7 +256,7 @@ export function CommentActions({
|
|
|
256
256
|
resolveAction?: ResolveAction;
|
|
257
257
|
}) {
|
|
258
258
|
const t = useTranslator();
|
|
259
|
-
const
|
|
259
|
+
const {copy: copyToClipboard, isCopied: isLinkCopied} = useClipboard();
|
|
260
260
|
const [isLinkTooltipOpen, setIsLinkTooltipOpen] = useState(false);
|
|
261
261
|
const [isPickerOpen, setIsPickerOpen] = useState(false);
|
|
262
262
|
const [collapsed, setCollapsed] = useState(NO_COLLAPSED_ACTIONS);
|
|
@@ -276,30 +276,8 @@ export function CommentActions({
|
|
|
276
276
|
<CommentIcon name="copyLink" />
|
|
277
277
|
);
|
|
278
278
|
|
|
279
|
-
const copyCommentLink =
|
|
280
|
-
|
|
281
|
-
return;
|
|
282
|
-
}
|
|
283
|
-
try {
|
|
284
|
-
await navigator.clipboard.writeText(
|
|
285
|
-
new URL(href, window.location.href).href,
|
|
286
|
-
);
|
|
287
|
-
setIsLinkCopied(true);
|
|
288
|
-
} catch {
|
|
289
|
-
setIsLinkCopied(false);
|
|
290
|
-
}
|
|
291
|
-
};
|
|
292
|
-
|
|
293
|
-
useEffect(() => {
|
|
294
|
-
if (!isLinkCopied) {
|
|
295
|
-
return;
|
|
296
|
-
}
|
|
297
|
-
const timer = window.setTimeout(
|
|
298
|
-
() => setIsLinkCopied(false),
|
|
299
|
-
LINK_COPIED_RESET_MS,
|
|
300
|
-
);
|
|
301
|
-
return () => window.clearTimeout(timer);
|
|
302
|
-
}, [isLinkCopied]);
|
|
279
|
+
const copyCommentLink = () =>
|
|
280
|
+
copyToClipboard(new URL(href, window.location.href).href);
|
|
303
281
|
|
|
304
282
|
const changePicker = (isOpen: boolean) => {
|
|
305
283
|
setIsPickerOpen(isOpen);
|
|
@@ -957,6 +957,38 @@ describe('Comments threads', () => {
|
|
|
957
957
|
).toBeTruthy();
|
|
958
958
|
});
|
|
959
959
|
|
|
960
|
+
it('keeps the copied label for the full time after a second copy', async () => {
|
|
961
|
+
vi.useFakeTimers({toFake: ['setTimeout', 'clearTimeout']});
|
|
962
|
+
const wait = (ms: number) => act(() => vi.advanceTimersByTimeAsync(ms));
|
|
963
|
+
const copyButton = (name: string) => screen.getByRole('button', {name});
|
|
964
|
+
try {
|
|
965
|
+
render(
|
|
966
|
+
<Sized>
|
|
967
|
+
<Comments
|
|
968
|
+
comments={[{...COMMENTS[0], replies: []}]}
|
|
969
|
+
currentUser={OTHER}
|
|
970
|
+
/>
|
|
971
|
+
</Sized>,
|
|
972
|
+
);
|
|
973
|
+
await click(copyButton('Copy comment link'));
|
|
974
|
+
await wait(0);
|
|
975
|
+
expect(copyButton('Comment link copied')).toBeTruthy();
|
|
976
|
+
|
|
977
|
+
await wait(1500);
|
|
978
|
+
await click(copyButton('Comment link copied'));
|
|
979
|
+
await wait(0);
|
|
980
|
+
// 2.5 s after the first copy and 1 s after the second one.
|
|
981
|
+
await wait(1000);
|
|
982
|
+
expect(writeText).toHaveBeenCalledTimes(2);
|
|
983
|
+
expect(copyButton('Comment link copied')).toBeTruthy();
|
|
984
|
+
|
|
985
|
+
await wait(1000);
|
|
986
|
+
expect(copyButton('Copy comment link')).toBeTruthy();
|
|
987
|
+
} finally {
|
|
988
|
+
vi.useRealTimers();
|
|
989
|
+
}
|
|
990
|
+
});
|
|
991
|
+
|
|
960
992
|
it('collapses header actions into the more menu when space runs low', async () => {
|
|
961
993
|
overflowControl.collapsed = new Set(['reply', 'link']);
|
|
962
994
|
const onSubmit = vi.fn();
|
|
@@ -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}
|
|
@@ -15,7 +15,7 @@
|
|
|
15
15
|
* focus ring, or produce a touch tap.
|
|
16
16
|
*/
|
|
17
17
|
|
|
18
|
-
import {expect, test, type Page} from '@playwright
|
|
18
|
+
import {expect, test, type Page} from '@astryxdesign/a11y-spec/playwright';
|
|
19
19
|
import pixelmatch from 'pixelmatch';
|
|
20
20
|
// @ts-expect-error -- pngjs ships no declarations; runtime support is pinned.
|
|
21
21
|
import {PNG} from 'pngjs';
|
|
@@ -11,7 +11,7 @@
|
|
|
11
11
|
* layout, so it cannot tell whether a time fits beside a title.
|
|
12
12
|
*/
|
|
13
13
|
|
|
14
|
-
import {expect, test, type Page} from '@playwright
|
|
14
|
+
import {expect, test, type Page} from '@astryxdesign/a11y-spec/playwright';
|
|
15
15
|
import {
|
|
16
16
|
finishEvidence,
|
|
17
17
|
openStory,
|
|
@@ -13,7 +13,7 @@
|
|
|
13
13
|
* cannot show a native popover, return focus through it, or lay out chips.
|
|
14
14
|
*/
|
|
15
15
|
|
|
16
|
-
import {expect, test, type Page} from '@playwright
|
|
16
|
+
import {expect, test, type Page} from '@astryxdesign/a11y-spec/playwright';
|
|
17
17
|
import {
|
|
18
18
|
finishEvidence,
|
|
19
19
|
openStory,
|
|
@@ -16,7 +16,7 @@
|
|
|
16
16
|
* through it, or paint a focus ring.
|
|
17
17
|
*/
|
|
18
18
|
|
|
19
|
-
import {expect, test, type Page} from '@playwright
|
|
19
|
+
import {expect, test, type Page} from '@astryxdesign/a11y-spec/playwright';
|
|
20
20
|
import pixelmatch from 'pixelmatch';
|
|
21
21
|
// @ts-expect-error -- pngjs ships no declarations; runtime support is pinned.
|
|
22
22
|
import {PNG} from 'pngjs';
|
|
@@ -11,7 +11,7 @@
|
|
|
11
11
|
* ownership are checkable only here.
|
|
12
12
|
*/
|
|
13
13
|
|
|
14
|
-
import {expect, test} from '@playwright
|
|
14
|
+
import {expect, test} from '@astryxdesign/a11y-spec/playwright';
|
|
15
15
|
import pixelmatch from 'pixelmatch';
|
|
16
16
|
// @ts-expect-error -- pngjs ships no declarations; runtime support is pinned.
|
|
17
17
|
import {PNG} from 'pngjs';
|
|
@@ -11,7 +11,7 @@
|
|
|
11
11
|
* no layout, so it cannot measure where a span paints or how wide a block is.
|
|
12
12
|
*/
|
|
13
13
|
|
|
14
|
-
import {expect, test, type Page} from '@playwright
|
|
14
|
+
import {expect, test, type Page} from '@astryxdesign/a11y-spec/playwright';
|
|
15
15
|
import {
|
|
16
16
|
finishEvidence,
|
|
17
17
|
NARROW,
|
|
@@ -10,7 +10,7 @@
|
|
|
10
10
|
* jsdom has no native radio-group keyboard, so only a real engine shows it.
|
|
11
11
|
*/
|
|
12
12
|
|
|
13
|
-
import {expect, test, type Page} from '@playwright
|
|
13
|
+
import {expect, test, type Page} from '@astryxdesign/a11y-spec/playwright';
|
|
14
14
|
import {
|
|
15
15
|
DEFAULT_STORYBOOK_DIR,
|
|
16
16
|
serveStorybook,
|
|
@@ -13,7 +13,12 @@
|
|
|
13
13
|
* (packages/lab/src/reorderStyles.ts)
|
|
14
14
|
*/
|
|
15
15
|
|
|
16
|
-
import {
|
|
16
|
+
import {
|
|
17
|
+
expect,
|
|
18
|
+
test,
|
|
19
|
+
type CDPSession,
|
|
20
|
+
type Page,
|
|
21
|
+
} from '@astryxdesign/a11y-spec/playwright';
|
|
17
22
|
import {
|
|
18
23
|
DEFAULT_STORYBOOK_DIR,
|
|
19
24
|
serveStorybook,
|