@astryxdesign/lab 0.7.3-canary.fba04ed → 0.7.4-canary.31e54e4
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/ListInput/ListInput.d.ts +1 -1
- package/dist/ListInput/ListInput.d.ts.map +1 -1
- package/dist/ListInput/ListInput.js +161 -129
- package/dist/lab.css +6 -3
- package/package.json +4 -4
- package/src/CircularProgress/__tests__/CircularProgress.a11y.chromium.spec.ts +114 -0
- package/src/CircularProgress/__tests__/CircularProgress.a11y.known-failures.ts +12 -0
- package/src/CircularProgress/__tests__/CircularProgress.a11y.renders.tsx +41 -0
- package/src/CircularProgress/__tests__/CircularProgress.a11y.states.ts +106 -0
- package/src/CircularProgress/__tests__/CircularProgress.a11y.test.tsx +108 -0
- package/src/ListInput/ListInput.doc.mjs +7 -7
- package/src/ListInput/ListInput.test.tsx +183 -3
- package/src/ListInput/ListInput.tsx +231 -166
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* @file ListInput.tsx
|
|
3
|
-
* @input React, StyleX, Astryx field/list/button/icon/layer/empty-state primitives, compact size context, browser scroll geometry, programmatic theme tokens, and shared Lab reorder styles
|
|
3
|
+
* @input React, StyleX, Astryx field/list/button/icon/layer/empty-state primitives, the container-reveal hook, compact size context, browser scroll geometry, programmatic theme tokens, and shared Lab reorder styles
|
|
4
4
|
* @output Exports ListInput and its controlled data, column, renderer, and change types
|
|
5
5
|
* @position Lab experiment (RFC facebook/astryx#4531) for editing compact repeated records
|
|
6
6
|
*
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"ListInput.d.ts","sourceRoot":"","sources":["../../src/ListInput/ListInput.tsx"],"names":[],"mappings":"AAIA;;;;;;;;;;;GAWG;AAEH,OAAO,EAOL,KAAK,GAAG,EACR,KAAK,SAAS,EAEf,MAAM,OAAO,CAAC;AAGf,OAAO,KAAK,EAAC,SAAS,EAAC,MAAM,oBAAoB,CAAC;AAGlD,OAAO,EAAQ,KAAK,WAAW,EAAC,MAAM,0BAA0B,CAAC;
|
|
1
|
+
{"version":3,"file":"ListInput.d.ts","sourceRoot":"","sources":["../../src/ListInput/ListInput.tsx"],"names":[],"mappings":"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"}
|
|
@@ -4,7 +4,7 @@
|
|
|
4
4
|
|
|
5
5
|
/**
|
|
6
6
|
* @file ListInput.tsx
|
|
7
|
-
* @input React, StyleX, Astryx field/list/button/icon/layer/empty-state primitives, compact size context, browser scroll geometry, programmatic theme tokens, and shared Lab reorder styles
|
|
7
|
+
* @input React, StyleX, Astryx field/list/button/icon/layer/empty-state primitives, the container-reveal hook, compact size context, browser scroll geometry, programmatic theme tokens, and shared Lab reorder styles
|
|
8
8
|
* @output Exports ListInput and its controlled data, column, renderer, and change types
|
|
9
9
|
* @position Lab experiment (RFC facebook/astryx#4531) for editing compact repeated records
|
|
10
10
|
*
|
|
@@ -22,7 +22,7 @@ import { EmptyState } from '@astryxdesign/core/EmptyState';
|
|
|
22
22
|
import { Field } from '@astryxdesign/core/Field';
|
|
23
23
|
import { FieldStatus } from '@astryxdesign/core/FieldStatus';
|
|
24
24
|
import { Icon } from '@astryxdesign/core/Icon';
|
|
25
|
-
import { useAnnounce, useMediaQuery } from '@astryxdesign/core/hooks';
|
|
25
|
+
import { useAnnounce, useContainerReveal, useMediaQuery } from '@astryxdesign/core/hooks';
|
|
26
26
|
import { IconButton } from '@astryxdesign/core/IconButton';
|
|
27
27
|
import { useTranslator } from '@astryxdesign/core/i18n';
|
|
28
28
|
import { useLayer } from '@astryxdesign/core/Layer';
|
|
@@ -31,7 +31,7 @@ import { useTheme } from '@astryxdesign/core/theme';
|
|
|
31
31
|
import { VisuallyHidden } from '@astryxdesign/core/VisuallyHidden';
|
|
32
32
|
import '@astryxdesign/core/theme/tokens.stylex';
|
|
33
33
|
import { colorVars, fontWeightVars, sizeVars, spacingVars, typeScaleVars } from '@astryxdesign/core/theme/tokens.stylex';
|
|
34
|
-
import { mergeProps, themeProps } from '@astryxdesign/core/utils';
|
|
34
|
+
import { focusOutlineStyles, mergeProps, themeProps } from '@astryxdesign/core/utils';
|
|
35
35
|
import { reorderStyles } from "../reorderStyles.js";
|
|
36
36
|
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
37
37
|
const styles = {
|
|
@@ -54,18 +54,10 @@ const styles = {
|
|
|
54
54
|
kumcoG: "x1mkdm3x",
|
|
55
55
|
$$css: true
|
|
56
56
|
},
|
|
57
|
-
rowWithReorder: {
|
|
58
|
-
kumcoG: "x1ni329g",
|
|
59
|
-
$$css: true
|
|
60
|
-
},
|
|
61
57
|
rowWithRemove: {
|
|
62
58
|
kumcoG: "x1ni329g",
|
|
63
59
|
$$css: true
|
|
64
60
|
},
|
|
65
|
-
rowWithBothControls: {
|
|
66
|
-
kumcoG: "x1nra26t",
|
|
67
|
-
$$css: true
|
|
68
|
-
},
|
|
69
61
|
fields: {
|
|
70
62
|
k1xSpc: "xrvj5dj x12gktpv",
|
|
71
63
|
kGNEyG: "xpqajaz",
|
|
@@ -81,25 +73,22 @@ const styles = {
|
|
|
81
73
|
kBCFzs: "x1rlpkp8",
|
|
82
74
|
$$css: true
|
|
83
75
|
},
|
|
84
|
-
contentBeforeBothControls: {
|
|
85
|
-
kBCFzs: "xez1zrf",
|
|
86
|
-
$$css: true
|
|
87
|
-
},
|
|
88
76
|
itemStatus: {
|
|
89
77
|
kbNqZ1: "x7sv70a x1nh3qrq",
|
|
90
78
|
keoZOQ: "xcsaf9d xc47mtf",
|
|
91
79
|
k7Eaqz: "xeuugli",
|
|
92
80
|
$$css: true
|
|
93
81
|
},
|
|
94
|
-
|
|
95
|
-
k1xSpc: "
|
|
82
|
+
reorderGrip: {
|
|
83
|
+
k1xSpc: "x78zum5",
|
|
96
84
|
kGNEyG: "x6s0dn4",
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
85
|
+
kjj79g: "xl56j7k",
|
|
86
|
+
kzqmXN: "x1f0dxl5",
|
|
87
|
+
kmVPX3: "x1717udv",
|
|
88
|
+
kogj98: "x1ghz6dp",
|
|
89
|
+
ksu8eU: "xng3xce",
|
|
90
|
+
kWkggS: "xjbqb8w",
|
|
91
|
+
kMwMTN: "xtbr613 x100q762",
|
|
103
92
|
$$css: true
|
|
104
93
|
}
|
|
105
94
|
};
|
|
@@ -128,40 +117,44 @@ const dynamicStyles = {
|
|
|
128
117
|
"--x-viewTransitionName": name != null ? name : undefined
|
|
129
118
|
}]
|
|
130
119
|
};
|
|
120
|
+
|
|
121
|
+
// The six-dot grip drawn at its own size, so the narrow reorder target needs no
|
|
122
|
+
// square icon box around it.
|
|
131
123
|
function GripVerticalIcon(props) {
|
|
132
124
|
return /*#__PURE__*/_jsxs("svg", {
|
|
133
|
-
viewBox: "0 0
|
|
125
|
+
viewBox: "0 0 6 10",
|
|
134
126
|
fill: "none",
|
|
127
|
+
"aria-hidden": "true",
|
|
135
128
|
...props,
|
|
136
129
|
children: [/*#__PURE__*/_jsx("circle", {
|
|
137
|
-
cx: "
|
|
138
|
-
cy: "
|
|
139
|
-
r: "1
|
|
130
|
+
cx: "1",
|
|
131
|
+
cy: "1",
|
|
132
|
+
r: "1",
|
|
140
133
|
fill: "currentColor"
|
|
141
134
|
}), /*#__PURE__*/_jsx("circle", {
|
|
142
|
-
cx: "
|
|
143
|
-
cy: "
|
|
144
|
-
r: "1
|
|
135
|
+
cx: "5",
|
|
136
|
+
cy: "1",
|
|
137
|
+
r: "1",
|
|
145
138
|
fill: "currentColor"
|
|
146
139
|
}), /*#__PURE__*/_jsx("circle", {
|
|
147
|
-
cx: "
|
|
148
|
-
cy: "
|
|
149
|
-
r: "1
|
|
140
|
+
cx: "1",
|
|
141
|
+
cy: "5",
|
|
142
|
+
r: "1",
|
|
150
143
|
fill: "currentColor"
|
|
151
144
|
}), /*#__PURE__*/_jsx("circle", {
|
|
152
|
-
cx: "
|
|
153
|
-
cy: "
|
|
154
|
-
r: "1
|
|
145
|
+
cx: "5",
|
|
146
|
+
cy: "5",
|
|
147
|
+
r: "1",
|
|
155
148
|
fill: "currentColor"
|
|
156
149
|
}), /*#__PURE__*/_jsx("circle", {
|
|
157
|
-
cx: "
|
|
158
|
-
cy: "
|
|
159
|
-
r: "1
|
|
150
|
+
cx: "1",
|
|
151
|
+
cy: "9",
|
|
152
|
+
r: "1",
|
|
160
153
|
fill: "currentColor"
|
|
161
154
|
}), /*#__PURE__*/_jsx("circle", {
|
|
162
|
-
cx: "
|
|
163
|
-
cy: "
|
|
164
|
-
r: "1
|
|
155
|
+
cx: "5",
|
|
156
|
+
cy: "9",
|
|
157
|
+
r: "1",
|
|
165
158
|
fill: "currentColor"
|
|
166
159
|
})]
|
|
167
160
|
});
|
|
@@ -187,7 +180,9 @@ function joinIDs(...ids) {
|
|
|
187
180
|
const resolved = ids.filter(Boolean);
|
|
188
181
|
return resolved.length > 0 ? resolved.join(' ') : undefined;
|
|
189
182
|
}
|
|
190
|
-
|
|
183
|
+
|
|
184
|
+
// The reorder grip shares the first field's cell but is not a field.
|
|
185
|
+
const focusableFieldSelector = '[data-list-input-cell] input, [data-list-input-cell] select, [data-list-input-cell] textarea, [data-list-input-cell] button:not([data-list-input-reorder]), [data-list-input-cell] [tabindex]:not([tabindex="-1"]):not([data-list-input-reorder])';
|
|
191
186
|
function getScrollableAncestors(element) {
|
|
192
187
|
const scrollRoots = [];
|
|
193
188
|
let current = element.parentElement;
|
|
@@ -411,6 +406,12 @@ export function ListInput({
|
|
|
411
406
|
} = useLayer({
|
|
412
407
|
mode: 'fixed'
|
|
413
408
|
});
|
|
409
|
+
// Each record row reveals its row actions (Remove and, when reorderable, the
|
|
410
|
+
// grip) on hover or keyboard focus; touch keeps them visible.
|
|
411
|
+
const {
|
|
412
|
+
getContainerProps,
|
|
413
|
+
getContentRevealProps
|
|
414
|
+
} = useContainerReveal();
|
|
414
415
|
const setReorderState = nextState => {
|
|
415
416
|
reorderStateRef.current = nextState;
|
|
416
417
|
setReorderStateState(nextState);
|
|
@@ -424,7 +425,7 @@ export function ListInput({
|
|
|
424
425
|
}
|
|
425
426
|
return moveItem(reorderState.originalValue, reorderState.fromIndex, reorderState.toIndex);
|
|
426
427
|
}, [reorderState, value]);
|
|
427
|
-
const
|
|
428
|
+
const showReorderHandle = isReorderable;
|
|
428
429
|
const showRemoveColumn = true;
|
|
429
430
|
const fieldGridTemplate = useMemo(() => columns.map(column => resolveColumnTrack(column.width)).join(' '), [columns]);
|
|
430
431
|
const pointerPlacement = useMemo(() => {
|
|
@@ -446,6 +447,7 @@ export function ListInput({
|
|
|
446
447
|
};
|
|
447
448
|
}, [getItemKey, reorderState]);
|
|
448
449
|
const previewCloneKey = reorderState?.mode === 'pointer' ? String(reorderState.itemKey) : null;
|
|
450
|
+
const isPointerReorderActive = previewCloneKey != null;
|
|
449
451
|
useEffect(() => {
|
|
450
452
|
if (process.env.NODE_ENV === 'production') {
|
|
451
453
|
return;
|
|
@@ -1008,8 +1010,8 @@ export function ListInput({
|
|
|
1008
1010
|
}));
|
|
1009
1011
|
}
|
|
1010
1012
|
};
|
|
1011
|
-
const rowLayoutStyle =
|
|
1012
|
-
const contentGridStyle =
|
|
1013
|
+
const rowLayoutStyle = showRemoveColumn ? styles.rowWithRemove : styles.rowFieldsOnly;
|
|
1014
|
+
const contentGridStyle = showRemoveColumn ? styles.contentBeforeOneControl : styles.contentOnly;
|
|
1013
1015
|
const dragPreviewPosition = reorderState?.mode === 'pointer' && reorderState.pointerClientX != null && reorderState.pointerClientY != null && reorderState.pointerOffsetX != null && reorderState.pointerOffsetY != null && reorderState.previewWidth != null ? {
|
|
1014
1016
|
x: reorderState.pointerClientX - reorderState.pointerOffsetX,
|
|
1015
1017
|
y: reorderState.pointerClientY - reorderState.pointerOffsetY,
|
|
@@ -1078,6 +1080,91 @@ export function ListInput({
|
|
|
1078
1080
|
const isPointerReorderSource = isActiveReorder && reorderState?.mode === 'pointer';
|
|
1079
1081
|
const itemStatus = getItemStatus?.(item, index);
|
|
1080
1082
|
const itemStatusID = itemStatus?.message ? `${groupID}-item-${index}-status` : undefined;
|
|
1083
|
+
const reorderHandle = showReorderHandle ? /*#__PURE__*/_jsx("div", {
|
|
1084
|
+
...{
|
|
1085
|
+
className: "x10l6tqk x13vifvy x1ey2m1c x1eu7cjg x78zum5 x1qjc9v5 x1djylfy"
|
|
1086
|
+
},
|
|
1087
|
+
children: /*#__PURE__*/_jsx("div", {
|
|
1088
|
+
...mergeProps(getContentRevealProps({
|
|
1089
|
+
isLayoutPreserved: true,
|
|
1090
|
+
// The grip owns an active reorder, so it stays
|
|
1091
|
+
// visible however the pointer moves.
|
|
1092
|
+
forceVisibility: isActiveReorder ? 'shown' : undefined
|
|
1093
|
+
}), // A flex row, so the grip stretches to the field's height.
|
|
1094
|
+
{
|
|
1095
|
+
className: "x78zum5"
|
|
1096
|
+
}),
|
|
1097
|
+
children: /*#__PURE__*/_jsx("button", {
|
|
1098
|
+
type: "button",
|
|
1099
|
+
"aria-label": t('@astryx.listInput.reorderItem', {
|
|
1100
|
+
itemName,
|
|
1101
|
+
position: index + 1
|
|
1102
|
+
}),
|
|
1103
|
+
disabled: isDisabled || isLoading,
|
|
1104
|
+
"aria-describedby": reorderInstructionsID,
|
|
1105
|
+
"aria-pressed": isActiveReorder || undefined,
|
|
1106
|
+
"data-list-input-reorder": "",
|
|
1107
|
+
...stylex.props(focusOutlineStyles.focusVisible, styles.reorderGrip, reorderStyles.handle, isActiveReorder && reorderStyles.handleActive),
|
|
1108
|
+
onKeyDown: event => handleReorderKeyDown(event, item, index),
|
|
1109
|
+
onBlur: () => {
|
|
1110
|
+
const activeState = reorderStateRef.current;
|
|
1111
|
+
if (activeState?.mode === 'keyboard' && String(activeState.itemKey) === itemKeyString) {
|
|
1112
|
+
cancelReorder();
|
|
1113
|
+
}
|
|
1114
|
+
},
|
|
1115
|
+
onPointerDown: event => {
|
|
1116
|
+
if (event.button !== 0 || isDisabled || isLoading) {
|
|
1117
|
+
return;
|
|
1118
|
+
}
|
|
1119
|
+
const sourceRow = rowRefs.current.get(itemKeyString);
|
|
1120
|
+
if (sourceRow == null) {
|
|
1121
|
+
return;
|
|
1122
|
+
}
|
|
1123
|
+
const bounds = sourceRow.getBoundingClientRect();
|
|
1124
|
+
event.currentTarget.setPointerCapture?.(event.pointerId);
|
|
1125
|
+
startReorder(item, index, 'pointer', event.pointerId, {
|
|
1126
|
+
pointerStartX: event.clientX,
|
|
1127
|
+
pointerStartY: event.clientY,
|
|
1128
|
+
pointerOffsetX: event.clientX - bounds.left,
|
|
1129
|
+
pointerOffsetY: event.clientY - bounds.top,
|
|
1130
|
+
pointerClientX: event.clientX,
|
|
1131
|
+
pointerClientY: event.clientY,
|
|
1132
|
+
previewWidth: bounds.width
|
|
1133
|
+
});
|
|
1134
|
+
},
|
|
1135
|
+
onPointerMove: handlePointerMove,
|
|
1136
|
+
onPointerUp: event => {
|
|
1137
|
+
const activeState = reorderStateRef.current;
|
|
1138
|
+
if (activeState?.mode === 'pointer' && activeState.pointerId === event.pointerId) {
|
|
1139
|
+
commitReorder();
|
|
1140
|
+
if (event.currentTarget.hasPointerCapture?.(event.pointerId)) {
|
|
1141
|
+
event.currentTarget.releasePointerCapture?.(event.pointerId);
|
|
1142
|
+
}
|
|
1143
|
+
}
|
|
1144
|
+
},
|
|
1145
|
+
onPointerCancel: event => {
|
|
1146
|
+
const activeState = reorderStateRef.current;
|
|
1147
|
+
if (activeState?.mode === 'pointer' && activeState.pointerId === event.pointerId) {
|
|
1148
|
+
cancelReorder();
|
|
1149
|
+
if (event.currentTarget.hasPointerCapture?.(event.pointerId)) {
|
|
1150
|
+
event.currentTarget.releasePointerCapture?.(event.pointerId);
|
|
1151
|
+
}
|
|
1152
|
+
}
|
|
1153
|
+
},
|
|
1154
|
+
onLostPointerCapture: event => {
|
|
1155
|
+
const activeState = reorderStateRef.current;
|
|
1156
|
+
if (activeState?.mode === 'pointer' && activeState.pointerId === event.pointerId) {
|
|
1157
|
+
cancelReorder();
|
|
1158
|
+
}
|
|
1159
|
+
},
|
|
1160
|
+
children: /*#__PURE__*/_jsx(GripVerticalIcon, {
|
|
1161
|
+
...{
|
|
1162
|
+
className: "x1lliihq x2lah0s x1wu31ai x14r7d11"
|
|
1163
|
+
}
|
|
1164
|
+
})
|
|
1165
|
+
})
|
|
1166
|
+
})
|
|
1167
|
+
}) : null;
|
|
1081
1168
|
return /*#__PURE__*/_jsx("li", {
|
|
1082
1169
|
"data-list-input-motion-key": `item:${itemKeyString}`,
|
|
1083
1170
|
"data-list-input-drop-target": dropPosition ?? undefined,
|
|
@@ -1096,7 +1183,11 @@ export function ListInput({
|
|
|
1096
1183
|
}
|
|
1097
1184
|
},
|
|
1098
1185
|
"data-list-input-row": itemKeyString,
|
|
1099
|
-
...
|
|
1186
|
+
...mergeProps(getContainerProps({
|
|
1187
|
+
// A pointer drag owns the list: rows the pointer
|
|
1188
|
+
// crosses stay quiet instead of lighting their grips.
|
|
1189
|
+
forceState: isPointerReorderActive && !isActiveReorder ? 'inactive' : undefined
|
|
1190
|
+
}), stylex.props(styles.row, rowLayoutStyle, dynamicStyles.rowTransition(transitionName(groupID, itemKey)), isPointerReorderSource && reorderStyles.source)),
|
|
1100
1191
|
children: [/*#__PURE__*/_jsx("div", {
|
|
1101
1192
|
...stylex.props(styles.fields, dynamicStyles.fields(fieldGridTemplate)),
|
|
1102
1193
|
children: columns.map((column, columnIndex) => {
|
|
@@ -1139,18 +1230,28 @@ export function ListInput({
|
|
|
1139
1230
|
}
|
|
1140
1231
|
}[!!isRepeatedLabel << 0],
|
|
1141
1232
|
children: column.header
|
|
1142
|
-
}), /*#__PURE__*/
|
|
1233
|
+
}), /*#__PURE__*/_jsxs("div", {
|
|
1143
1234
|
...{
|
|
1144
|
-
|
|
1145
|
-
|
|
1146
|
-
|
|
1235
|
+
0: {
|
|
1236
|
+
className: "xeuugli"
|
|
1237
|
+
},
|
|
1238
|
+
1: {
|
|
1239
|
+
className: "xeuugli x1n2onr6"
|
|
1240
|
+
}
|
|
1241
|
+
}[!!(columnIndex === 0 && showReorderHandle) << 0],
|
|
1242
|
+
children: [columnIndex === 0 ? reorderHandle : null, content]
|
|
1147
1243
|
})]
|
|
1148
1244
|
}, column.key);
|
|
1149
1245
|
})
|
|
1150
1246
|
}), showRemoveColumn ? /*#__PURE__*/_jsx("div", {
|
|
1151
|
-
...
|
|
1247
|
+
...mergeProps(
|
|
1248
|
+
// Opacity only: Remove keeps its column, so the
|
|
1249
|
+
// fields never shift when it appears.
|
|
1250
|
+
getContentRevealProps({
|
|
1251
|
+
isLayoutPreserved: true
|
|
1252
|
+
}), {
|
|
1152
1253
|
className: "x78zum5 x6s0dn4 x7fd4wk xl56j7k x1uogy3y xm5moh1 x4qyour x15daork x1y9m8ji"
|
|
1153
|
-
},
|
|
1254
|
+
}),
|
|
1154
1255
|
children: /*#__PURE__*/_jsx(IconButton, {
|
|
1155
1256
|
label: t('@astryx.listInput.removeItem', {
|
|
1156
1257
|
itemName,
|
|
@@ -1172,79 +1273,6 @@ export function ListInput({
|
|
|
1172
1273
|
"data-list-input-remove": "",
|
|
1173
1274
|
onClick: () => handleRemove(item)
|
|
1174
1275
|
})
|
|
1175
|
-
}) : null, showReorderColumn ? /*#__PURE__*/_jsx("div", {
|
|
1176
|
-
...{
|
|
1177
|
-
className: "x78zum5 x6s0dn4 x7fd4wk xl56j7k x1uogy3y xm5moh1 x1b1z6u9 x15daork x1y9m8ji"
|
|
1178
|
-
},
|
|
1179
|
-
children: /*#__PURE__*/_jsx(IconButton, {
|
|
1180
|
-
label: t('@astryx.listInput.reorderItem', {
|
|
1181
|
-
itemName,
|
|
1182
|
-
position: index + 1
|
|
1183
|
-
}),
|
|
1184
|
-
icon: /*#__PURE__*/_jsx(Icon, {
|
|
1185
|
-
icon: GripVerticalIcon,
|
|
1186
|
-
size: "sm"
|
|
1187
|
-
}),
|
|
1188
|
-
variant: "ghost",
|
|
1189
|
-
size: "md",
|
|
1190
|
-
isDisabled: isDisabled || isLoading,
|
|
1191
|
-
"aria-describedby": reorderInstructionsID,
|
|
1192
|
-
"aria-pressed": isActiveReorder || undefined,
|
|
1193
|
-
"data-list-input-reorder": "",
|
|
1194
|
-
xstyle: [reorderStyles.handle, isActiveReorder && reorderStyles.handleActive],
|
|
1195
|
-
onKeyDown: event => handleReorderKeyDown(event, item, index),
|
|
1196
|
-
onBlur: () => {
|
|
1197
|
-
const activeState = reorderStateRef.current;
|
|
1198
|
-
if (activeState?.mode === 'keyboard' && String(activeState.itemKey) === itemKeyString) {
|
|
1199
|
-
cancelReorder();
|
|
1200
|
-
}
|
|
1201
|
-
},
|
|
1202
|
-
onPointerDown: event => {
|
|
1203
|
-
if (event.button !== 0 || isDisabled || isLoading) {
|
|
1204
|
-
return;
|
|
1205
|
-
}
|
|
1206
|
-
const sourceRow = rowRefs.current.get(itemKeyString);
|
|
1207
|
-
if (sourceRow == null) {
|
|
1208
|
-
return;
|
|
1209
|
-
}
|
|
1210
|
-
const bounds = sourceRow.getBoundingClientRect();
|
|
1211
|
-
event.currentTarget.setPointerCapture?.(event.pointerId);
|
|
1212
|
-
startReorder(item, index, 'pointer', event.pointerId, {
|
|
1213
|
-
pointerStartX: event.clientX,
|
|
1214
|
-
pointerStartY: event.clientY,
|
|
1215
|
-
pointerOffsetX: event.clientX - bounds.left,
|
|
1216
|
-
pointerOffsetY: event.clientY - bounds.top,
|
|
1217
|
-
pointerClientX: event.clientX,
|
|
1218
|
-
pointerClientY: event.clientY,
|
|
1219
|
-
previewWidth: bounds.width
|
|
1220
|
-
});
|
|
1221
|
-
},
|
|
1222
|
-
onPointerMove: handlePointerMove,
|
|
1223
|
-
onPointerUp: event => {
|
|
1224
|
-
const activeState = reorderStateRef.current;
|
|
1225
|
-
if (activeState?.mode === 'pointer' && activeState.pointerId === event.pointerId) {
|
|
1226
|
-
commitReorder();
|
|
1227
|
-
if (event.currentTarget.hasPointerCapture?.(event.pointerId)) {
|
|
1228
|
-
event.currentTarget.releasePointerCapture?.(event.pointerId);
|
|
1229
|
-
}
|
|
1230
|
-
}
|
|
1231
|
-
},
|
|
1232
|
-
onPointerCancel: event => {
|
|
1233
|
-
const activeState = reorderStateRef.current;
|
|
1234
|
-
if (activeState?.mode === 'pointer' && activeState.pointerId === event.pointerId) {
|
|
1235
|
-
cancelReorder();
|
|
1236
|
-
if (event.currentTarget.hasPointerCapture?.(event.pointerId)) {
|
|
1237
|
-
event.currentTarget.releasePointerCapture?.(event.pointerId);
|
|
1238
|
-
}
|
|
1239
|
-
}
|
|
1240
|
-
},
|
|
1241
|
-
onLostPointerCapture: event => {
|
|
1242
|
-
const activeState = reorderStateRef.current;
|
|
1243
|
-
if (activeState?.mode === 'pointer' && activeState.pointerId === event.pointerId) {
|
|
1244
|
-
cancelReorder();
|
|
1245
|
-
}
|
|
1246
|
-
}
|
|
1247
|
-
})
|
|
1248
1276
|
}) : null, itemStatus?.message ? /*#__PURE__*/_jsx(FieldStatus, {
|
|
1249
1277
|
id: itemStatusID,
|
|
1250
1278
|
type: itemStatus.type,
|
|
@@ -1259,10 +1287,14 @@ export function ListInput({
|
|
|
1259
1287
|
}), /*#__PURE__*/_jsx("div", {
|
|
1260
1288
|
ref: addActionRef,
|
|
1261
1289
|
"data-list-input-motion-key": "action:add",
|
|
1262
|
-
...
|
|
1290
|
+
...{
|
|
1291
|
+
className: "xrvj5dj x6s0dn4 x1lfs0n9 xtbrsbv x1ni329g"
|
|
1292
|
+
},
|
|
1263
1293
|
children: /*#__PURE__*/_jsx("div", {
|
|
1264
1294
|
"data-list-input-add-content": "",
|
|
1265
|
-
...
|
|
1295
|
+
...{
|
|
1296
|
+
className: "xeuugli x1rlpkp8"
|
|
1297
|
+
},
|
|
1266
1298
|
children: /*#__PURE__*/_jsx(Button, {
|
|
1267
1299
|
ref: addButtonRef,
|
|
1268
1300
|
label: t('@astryx.listInput.addItem', {
|
|
@@ -1280,7 +1312,7 @@ export function ListInput({
|
|
|
1280
1312
|
onClick: handleAdd
|
|
1281
1313
|
})
|
|
1282
1314
|
})
|
|
1283
|
-
}),
|
|
1315
|
+
}), showReorderHandle ? /*#__PURE__*/_jsx(VisuallyHidden, {
|
|
1284
1316
|
as: "div",
|
|
1285
1317
|
id: reorderInstructionsID,
|
|
1286
1318
|
children: t('@astryx.listInput.reorderInstructions')
|
package/dist/lab.css
CHANGED
|
@@ -115,7 +115,6 @@
|
|
|
115
115
|
.x4h4c4w:not(#\#):not(#\#){grid-column:-2 / -1}
|
|
116
116
|
.x1osaytk:not(#\#):not(#\#){grid-column:1 / -1}
|
|
117
117
|
.x1rlpkp8:not(#\#):not(#\#){grid-column:1 / -2}
|
|
118
|
-
.xez1zrf:not(#\#):not(#\#){grid-column:1 / -3}
|
|
119
118
|
.xgkxs2y:not(#\#):not(#\#){grid-column:1}
|
|
120
119
|
.x17d9j0x:not(#\#):not(#\#){grid-column:2 / -1}
|
|
121
120
|
.x1npkx4u:not(#\#):not(#\#){grid-column:2}
|
|
@@ -165,7 +164,6 @@
|
|
|
165
164
|
@container list-input (max-width: 640px){.x6pnyrg.x6pnyrg:not(#\#):not(#\#){gap:var(--spacing-8)}}
|
|
166
165
|
@container list-input (max-width: 640px){.x1v2w52t.x1v2w52t:not(#\#):not(#\#){grid-column:1}}
|
|
167
166
|
@container list-input (max-width: 640px){.x4qyour.x4qyour:not(#\#):not(#\#){grid-column:2}}
|
|
168
|
-
@container list-input (max-width: 640px){.x1b1z6u9.x1b1z6u9:not(#\#):not(#\#){grid-column:3}}
|
|
169
167
|
@container list-input (max-width: 640px){.x1y9m8ji.x1y9m8ji:not(#\#):not(#\#){grid-row:1}}
|
|
170
168
|
@container list-input (max-width: 640px){.x1nh3qrq.x1nh3qrq:not(#\#):not(#\#){grid-row:auto}}
|
|
171
169
|
@container (max-width: 40rem){.xf3ta42.xf3ta42:not(#\#):not(#\#){overscroll-behavior:auto}}
|
|
@@ -177,6 +175,7 @@
|
|
|
177
175
|
.xuk3077:not(#\#):not(#\#):not(#\#){align-items:flex-end}
|
|
178
176
|
.x1cy8zhl:not(#\#):not(#\#):not(#\#){align-items:flex-start}
|
|
179
177
|
.x7a106z:not(#\#):not(#\#):not(#\#){align-items:start}
|
|
178
|
+
.x1qjc9v5:not(#\#):not(#\#):not(#\#){align-items:stretch}
|
|
180
179
|
.x7fd4wk:not(#\#):not(#\#):not(#\#){align-self:end}
|
|
181
180
|
.xqcrz7y:not(#\#):not(#\#):not(#\#){align-self:flex-start}
|
|
182
181
|
.x1y8v6su:not(#\#):not(#\#):not(#\#){align-self:start}
|
|
@@ -203,6 +202,7 @@
|
|
|
203
202
|
.x128ha8g:not(#\#):not(#\#):not(#\#){animation-timing-function:var(--ease-standard)}
|
|
204
203
|
.xjyslct:not(#\#):not(#\#):not(#\#){appearance:none}
|
|
205
204
|
.x1plog1:not(#\#):not(#\#):not(#\#){aspect-ratio:1}
|
|
205
|
+
.x14r7d11:not(#\#):not(#\#):not(#\#){aspect-ratio:3 / 5}
|
|
206
206
|
.x11fneen:not(#\#):not(#\#):not(#\#){aspect-ratio:auto}
|
|
207
207
|
.x1ta4xzc:not(#\#):not(#\#):not(#\#){background-clip:text}
|
|
208
208
|
.x2kq1z0:not(#\#):not(#\#):not(#\#){background-color:#0a0a0a}
|
|
@@ -423,7 +423,6 @@
|
|
|
423
423
|
.x1dl91lv:not(#\#):not(#\#):not(#\#){grid-template-columns:96px 52px minmax(0,1fr)}
|
|
424
424
|
.x37c5m6:not(#\#):not(#\#):not(#\#){grid-template-columns:minmax(0,1fr) auto minmax(0,1fr)}
|
|
425
425
|
.xcjjqqt:not(#\#):not(#\#):not(#\#){grid-template-columns:minmax(0,1fr) minmax(0,1fr)}
|
|
426
|
-
.x1nra26t:not(#\#):not(#\#):not(#\#){grid-template-columns:minmax(0,1fr) var(--size-element-md) var(--size-element-md)}
|
|
427
426
|
.x1ni329g:not(#\#):not(#\#):not(#\#){grid-template-columns:minmax(0,1fr) var(--size-element-md)}
|
|
428
427
|
.x1mkdm3x:not(#\#):not(#\#):not(#\#){grid-template-columns:minmax(0,1fr)}
|
|
429
428
|
.x1gj6vdr:not(#\#):not(#\#):not(#\#){grid-template-columns:repeat(7,minmax(0,1fr))}
|
|
@@ -437,6 +436,7 @@
|
|
|
437
436
|
.x1eiw8i6:not(#\#):not(#\#):not(#\#){grid-template-rows:56px auto auto}
|
|
438
437
|
.x1clt5hq:not(#\#):not(#\#):not(#\#){grid-template-rows:subgrid}
|
|
439
438
|
.x1xxtoay:not(#\#):not(#\#):not(#\#){grid-template-rows:var(--x-gridTemplateRows)}
|
|
439
|
+
.x1eu7cjg:not(#\#):not(#\#):not(#\#){inset-inline-end:100%}
|
|
440
440
|
.x1itk590:not(#\#):not(#\#):not(#\#){inset-inline-end:calc(var(--spacing-0-5) + var(--border-width))}
|
|
441
441
|
.x1mcfs9z:not(#\#):not(#\#):not(#\#){inset-inline-end:var(--spacing-3)}
|
|
442
442
|
.x1o0tod:not(#\#):not(#\#):not(#\#){inset-inline-start:0}
|
|
@@ -584,6 +584,7 @@
|
|
|
584
584
|
.x173emx3:is([dir="rtl"] *):not(#\#):not(#\#):not(#\#){transform-origin:right bottom}
|
|
585
585
|
.x135w3n3:focus-visible:not(#\#):not(#\#):not(#\#){z-index:1}
|
|
586
586
|
.x16iypot:focus-visible:not(#\#):not(#\#):not(#\#){z-index:2}
|
|
587
|
+
.x100q762:disabled:not(#\#):not(#\#):not(#\#){color:var(--color-icon-disabled)}
|
|
587
588
|
.xuqm82a:active:not(#\#):not(#\#):not(#\#){background-image:none}
|
|
588
589
|
@media (prefers-reduced-motion: reduce){.xdn7m2a.xdn7m2a:not(#\#):not(#\#):not(#\#){animation-duration:1ms}}
|
|
589
590
|
@media (prefers-reduced-motion: reduce){.xnh0sag.xnh0sag:not(#\#):not(#\#):not(#\#){animation-duration:3s}}
|
|
@@ -731,6 +732,8 @@
|
|
|
731
732
|
.x1lout4y:not(#\#):not(#\#):not(#\#):not(#\#){width:var(--astryx-chat-typing-indicator-dots-column-width,auto)}
|
|
732
733
|
.x1oai4fc:not(#\#):not(#\#):not(#\#):not(#\#){width:var(--icon-size)}
|
|
733
734
|
.xw7hby4:not(#\#):not(#\#):not(#\#):not(#\#){width:var(--spacing-0-5)}
|
|
735
|
+
.x1wu31ai:not(#\#):not(#\#):not(#\#):not(#\#){width:var(--spacing-1-5)}
|
|
736
|
+
.x1f0dxl5:not(#\#):not(#\#):not(#\#):not(#\#){width:var(--spacing-2)}
|
|
734
737
|
.x1uyokj7:not(#\#):not(#\#):not(#\#):not(#\#){width:var(--x-inlineSize)}
|
|
735
738
|
.x5lhr3w:not(#\#):not(#\#):not(#\#):not(#\#){width:var(--x-width)}
|
|
736
739
|
.x14l7nz5:first-child:not(#\#):not(#\#):not(#\#):not(#\#){margin-top:0}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@astryxdesign/lab",
|
|
3
|
-
"version": "0.7.
|
|
3
|
+
"version": "0.7.4-canary.31e54e4",
|
|
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.
|
|
52
|
+
"@astryxdesign/core": "0.7.4-canary.31e54e4",
|
|
53
53
|
"react": ">=19.0.0",
|
|
54
54
|
"react-dom": ">=19.0.0"
|
|
55
55
|
},
|
|
@@ -59,8 +59,8 @@
|
|
|
59
59
|
"d3-shape": "^3.2.0"
|
|
60
60
|
},
|
|
61
61
|
"devDependencies": {
|
|
62
|
-
"@astryxdesign/a11y-spec": "0.7.
|
|
63
|
-
"@astryxdesign/cli": "0.7.
|
|
62
|
+
"@astryxdesign/a11y-spec": "0.7.4-canary.31e54e4",
|
|
63
|
+
"@astryxdesign/cli": "0.7.4-canary.31e54e4",
|
|
64
64
|
"@babel/cli": "^7.29.7",
|
|
65
65
|
"@babel/core": "^7.29.7",
|
|
66
66
|
"@babel/preset-react": "^7.29.7",
|
|
@@ -0,0 +1,114 @@
|
|
|
1
|
+
// Copyright (c) Meta Platforms, Inc. and affiliates.
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* @file CircularProgress.a11y.chromium.spec.ts
|
|
5
|
+
* @input Built CircularProgress stories and PROGRESSBAR_PATTERN in real Chromium
|
|
6
|
+
* @output Browser evidence for every progressbar expectation across the binding's states, reconciled against the exact known failures
|
|
7
|
+
* @position Chromium lane of the CircularProgress binding
|
|
8
|
+
*/
|
|
9
|
+
|
|
10
|
+
import {
|
|
11
|
+
expect,
|
|
12
|
+
test,
|
|
13
|
+
type CDPSession,
|
|
14
|
+
type Locator,
|
|
15
|
+
type Page,
|
|
16
|
+
} from '@playwright/test';
|
|
17
|
+
import {
|
|
18
|
+
PROGRESSBAR_PATTERN,
|
|
19
|
+
blockingResults,
|
|
20
|
+
checkAccessibilitySpec,
|
|
21
|
+
formatFailures,
|
|
22
|
+
neverExercised,
|
|
23
|
+
summarize,
|
|
24
|
+
unmatchedKnownFailures,
|
|
25
|
+
type BindingResult,
|
|
26
|
+
} from '@astryxdesign/a11y-spec';
|
|
27
|
+
import {
|
|
28
|
+
createChromiumHarness,
|
|
29
|
+
holdMotionStill,
|
|
30
|
+
} from '@astryxdesign/a11y-spec/chromium';
|
|
31
|
+
import {
|
|
32
|
+
DEFAULT_STORYBOOK_DIR,
|
|
33
|
+
serveStorybook,
|
|
34
|
+
type StaticServer,
|
|
35
|
+
} from '@astryxdesign/a11y-spec/storybook';
|
|
36
|
+
import {CIRCULAR_PROGRESS_KNOWN_FAILURES} from './CircularProgress.a11y.known-failures';
|
|
37
|
+
import {
|
|
38
|
+
CIRCULAR_PROGRESS_BINDING_STATES,
|
|
39
|
+
type CircularProgressBindingState,
|
|
40
|
+
} from './CircularProgress.a11y.states';
|
|
41
|
+
|
|
42
|
+
let storybook: StaticServer;
|
|
43
|
+
|
|
44
|
+
test.beforeAll(async () => {
|
|
45
|
+
storybook = await serveStorybook(
|
|
46
|
+
process.env.ASTRYX_STORYBOOK_DIR ?? DEFAULT_STORYBOOK_DIR,
|
|
47
|
+
);
|
|
48
|
+
});
|
|
49
|
+
|
|
50
|
+
test.afterAll(async () => {
|
|
51
|
+
await storybook?.close();
|
|
52
|
+
});
|
|
53
|
+
|
|
54
|
+
function storyUrl(storyId: string): string {
|
|
55
|
+
return `${storybook.origin}/iframe.html?id=${storyId}&viewMode=story`;
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
async function mountState(
|
|
59
|
+
page: Page,
|
|
60
|
+
state: CircularProgressBindingState,
|
|
61
|
+
): Promise<{subject: Locator; related: Record<string, Locator>}> {
|
|
62
|
+
await page.goto(storyUrl(state.storyId), {waitUntil: 'load'});
|
|
63
|
+
await holdMotionStill(page);
|
|
64
|
+
const subject = page
|
|
65
|
+
.locator('#storybook-root')
|
|
66
|
+
.getByRole('progressbar', {name: state.facts.name});
|
|
67
|
+
await subject.waitFor({state: 'attached'});
|
|
68
|
+
return {subject, related: {}};
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
async function runState(
|
|
72
|
+
page: Page,
|
|
73
|
+
cdp: CDPSession,
|
|
74
|
+
state: CircularProgressBindingState,
|
|
75
|
+
): Promise<BindingResult> {
|
|
76
|
+
return checkAccessibilitySpec({
|
|
77
|
+
spec: PROGRESSBAR_PATTERN,
|
|
78
|
+
binding: 'CircularProgress',
|
|
79
|
+
state: state.id,
|
|
80
|
+
facts: state.facts,
|
|
81
|
+
knownFailures: CIRCULAR_PROGRESS_KNOWN_FAILURES,
|
|
82
|
+
mount: async () => {
|
|
83
|
+
const {subject, related} = await mountState(page, state);
|
|
84
|
+
return createChromiumHarness({page, cdp, subject, related});
|
|
85
|
+
},
|
|
86
|
+
});
|
|
87
|
+
}
|
|
88
|
+
|
|
89
|
+
test('every progressbar expectation is exercised by a CircularProgress state', async ({
|
|
90
|
+
page,
|
|
91
|
+
}) => {
|
|
92
|
+
const cdp = await page.context().newCDPSession(page);
|
|
93
|
+
const results: BindingResult[] = [];
|
|
94
|
+
for (const state of CIRCULAR_PROGRESS_BINDING_STATES) {
|
|
95
|
+
results.push(await runState(page, cdp, state));
|
|
96
|
+
}
|
|
97
|
+
expect(neverExercised(results)).toEqual([]);
|
|
98
|
+
expect(
|
|
99
|
+
unmatchedKnownFailures(CIRCULAR_PROGRESS_KNOWN_FAILURES, results),
|
|
100
|
+
).toEqual([]);
|
|
101
|
+
});
|
|
102
|
+
|
|
103
|
+
for (const state of CIRCULAR_PROGRESS_BINDING_STATES) {
|
|
104
|
+
test(`CircularProgress [${state.id}] — ${state.summary}`, async ({page}) => {
|
|
105
|
+
const cdp = await page.context().newCDPSession(page);
|
|
106
|
+
const result = await runState(page, cdp, state);
|
|
107
|
+
const report = summarize(PROGRESSBAR_PATTERN, [result]);
|
|
108
|
+
// Required rows block (AST-020 FR9); advisory rows and exact known
|
|
109
|
+
// failures report.
|
|
110
|
+
expect(formatFailures(blockingResults([result]))).toBe('');
|
|
111
|
+
expect(report.unrunLayers).toEqual([]);
|
|
112
|
+
expect(report.counts.unexpectedPass).toBe(0);
|
|
113
|
+
});
|
|
114
|
+
}
|