@astryxdesign/lab 0.7.6-canary.2d1900c → 0.7.6-canary.30c3fdf
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.
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"CodeEditor.d.ts","sourceRoot":"","sources":["../../src/CodeEditor/CodeEditor.tsx"],"names":[],"mappings":"AAyBA,OAAO,KAAK,EAAC,SAAS,EAAC,MAAM,oBAAoB,CAAC;AAkBlD,OAAO,KAAK,EAAC,SAAS,EAAC,MAAM,8BAA8B,CAAC;
|
|
1
|
+
{"version":3,"file":"CodeEditor.d.ts","sourceRoot":"","sources":["../../src/CodeEditor/CodeEditor.tsx"],"names":[],"mappings":"AAyBA,OAAO,KAAK,EAAC,SAAS,EAAC,MAAM,oBAAoB,CAAC;AAkBlD,OAAO,KAAK,EAAC,SAAS,EAAC,MAAM,8BAA8B,CAAC;AA2F5D,MAAM,WAAW,eAAgB,SAAQ,IAAI,CAC3C,SAAS,CAAC,cAAc,CAAC,EACzB,UAAU,CACX;IACC,wCAAwC;IACxC,GAAG,CAAC,EAAE,KAAK,CAAC,GAAG,CAAC,cAAc,CAAC,CAAC;IAChC,uBAAuB;IACvB,KAAK,EAAE,MAAM,CAAC;IACd,qBAAqB;IACrB,QAAQ,EAAE,CAAC,KAAK,EAAE,MAAM,KAAK,IAAI,CAAC;IAClC,sDAAsD;IACtD,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,sFAAsF;IACtF,KAAK,EAAE,MAAM,CAAC;IACd,wCAAwC;IACxC,cAAc,CAAC,EAAE,OAAO,CAAC;IACzB,qCAAqC;IACrC,UAAU,CAAC,EAAE,OAAO,CAAC;IACrB,6BAA6B;IAC7B,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,kCAAkC;IAClC,SAAS,CAAC,EAAE,MAAM,GAAG,MAAM,CAAC;IAC5B,+BAA+B;IAC/B,IAAI,CAAC,EAAE,IAAI,GAAG,IAAI,CAAC;IACnB,uBAAuB;IACvB,SAAS,CAAC,EAAE,CAAC,IAAI,EAAE,MAAM,EAAE,QAAQ,EAAE,MAAM,KAAK,SAAS,EAAE,CAAC;IAC5D;;;;;OAKG;IACH,UAAU,CAAC,EAAE,MAAM,CAAC;CACrB;AAsED;;;;;;;;;;;;;;;;;;;;;;;;;GAyBG;AACH,wBAAgB,UAAU,CAAC,EACzB,KAAK,EACL,QAAQ,EACR,QAAsB,EACtB,cAAsB,EACtB,UAAkB,EAClB,WAAW,EACX,SAAS,EACT,IAAW,EACX,SAAS,EAAE,eAAe,EAC1B,KAAK,EACL,UAAqE,EACrE,MAAM,EACN,SAAS,EACT,KAAK,EACL,GAAG,EACH,GAAG,KAAK,EACT,EAAE,eAAe,+BAsVjB;yBAvWe,UAAU"}
|
|
@@ -35,6 +35,9 @@ const styles = {
|
|
|
35
35
|
k1xSpc: "x78zum5",
|
|
36
36
|
kaIpWk: "xh6dtrn",
|
|
37
37
|
kWkggS: "xwmxj5m",
|
|
38
|
+
kMzoRj: "x1litavf",
|
|
39
|
+
ksu8eU: "x1y0btm7",
|
|
40
|
+
kVAM5u: "x14i3s5s",
|
|
38
41
|
kVQacm: "xb3r6kr",
|
|
39
42
|
$$css: true
|
|
40
43
|
},
|
|
@@ -51,6 +54,9 @@ const styles = {
|
|
|
51
54
|
k9WMMc: "xp4054r",
|
|
52
55
|
kfSwDN: "x87ps6o",
|
|
53
56
|
kMwMTN: "xnbbluu",
|
|
57
|
+
kWqL5O: "x1pcaw5z",
|
|
58
|
+
kSWEuD: "x32b0ac",
|
|
59
|
+
k26BEO: "xtgwc6q",
|
|
54
60
|
$$css: true
|
|
55
61
|
},
|
|
56
62
|
editor: {
|
package/dist/lab.css
CHANGED
|
@@ -650,6 +650,9 @@
|
|
|
650
650
|
.x1q0q8m5:not(#\#):not(#\#):not(#\#):not(#\#){border-bottom-style:solid}
|
|
651
651
|
.x1qhh985:not(#\#):not(#\#):not(#\#):not(#\#){border-bottom-width:0}
|
|
652
652
|
.x92x3c3:not(#\#):not(#\#):not(#\#):not(#\#){border-bottom-width:var(--border-width)}
|
|
653
|
+
.xtgwc6q:not(#\#):not(#\#):not(#\#):not(#\#){border-right-color:var(--color-border)}
|
|
654
|
+
.x32b0ac:not(#\#):not(#\#):not(#\#):not(#\#){border-right-style:solid}
|
|
655
|
+
.x1pcaw5z:not(#\#):not(#\#):not(#\#):not(#\#){border-right-width:var(--border-width)}
|
|
653
656
|
.x5mp61g:not(#\#):not(#\#):not(#\#):not(#\#){border-top-color:var(--color-border-orange)}
|
|
654
657
|
.x1pc3f07:not(#\#):not(#\#):not(#\#):not(#\#){border-top-color:var(--color-border)}
|
|
655
658
|
.x13fuv20:not(#\#):not(#\#):not(#\#):not(#\#){border-top-style:solid}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@astryxdesign/lab",
|
|
3
|
-
"version": "0.7.6-canary.
|
|
3
|
+
"version": "0.7.6-canary.30c3fdf",
|
|
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.6-canary.
|
|
52
|
+
"@astryxdesign/core": "0.7.6-canary.30c3fdf",
|
|
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.6-canary.
|
|
63
|
-
"@astryxdesign/cli": "0.7.6-canary.
|
|
64
|
-
"@astryxdesign/interaction-harness": "0.7.6-canary.
|
|
62
|
+
"@astryxdesign/a11y-spec": "0.7.6-canary.30c3fdf",
|
|
63
|
+
"@astryxdesign/cli": "0.7.6-canary.30c3fdf",
|
|
64
|
+
"@astryxdesign/interaction-harness": "0.7.6-canary.30c3fdf",
|
|
65
65
|
"@babel/cli": "^7.29.7",
|
|
66
66
|
"@babel/core": "^7.29.7",
|
|
67
67
|
"@babel/preset-react": "^7.29.7",
|
|
@@ -3,7 +3,8 @@
|
|
|
3
3
|
/**
|
|
4
4
|
* @file CircularProgressMotion.a11y.chromium.spec.ts
|
|
5
5
|
* @input Built CircularProgress stories in real Chromium (Web Animations
|
|
6
|
-
* seeking, CDP screencast, tracing)
|
|
6
|
+
* seeking, CDP screencast, tracing), the interaction harness's busy-window
|
|
7
|
+
* control and proof
|
|
7
8
|
* @output Browser evidence that a determinate value change keeps moving while
|
|
8
9
|
* a script holds the main thread and paints nothing per frame, that the
|
|
9
10
|
* ring at rest draws what the stroked circle drew, and that the arc stays
|
|
@@ -24,7 +25,14 @@ import {
|
|
|
24
25
|
serveStorybook,
|
|
25
26
|
type StaticServer,
|
|
26
27
|
} from '@astryxdesign/a11y-spec/storybook';
|
|
27
|
-
import {
|
|
28
|
+
import {
|
|
29
|
+
busyWindowProof,
|
|
30
|
+
CONTROL_RGB,
|
|
31
|
+
inPresentationOrder,
|
|
32
|
+
startBusyControl,
|
|
33
|
+
trackMarker,
|
|
34
|
+
type TrackedFrame,
|
|
35
|
+
} from '@astryxdesign/interaction-harness';
|
|
28
36
|
|
|
29
37
|
let storybook: StaticServer;
|
|
30
38
|
test.beforeAll(async () => {
|
|
@@ -152,35 +160,59 @@ async function colors(page: Page) {
|
|
|
152
160
|
|
|
153
161
|
/**
|
|
154
162
|
* For each degree clockwise from 12 o'clock, whether the ring's centerline is
|
|
155
|
-
* drawn in the fill color in the given screenshot
|
|
163
|
+
* drawn in the fill color in the given screenshot: PNGs of the ring box, or,
|
|
164
|
+
* with `frame`, PNGs of the whole viewport (`viewportWidth` CSS px wide) read
|
|
165
|
+
* at the ring box, the same pixels a crop to that box would hold.
|
|
156
166
|
*/
|
|
157
167
|
async function inkByDegree(
|
|
158
168
|
page: Page,
|
|
159
169
|
shots: string[],
|
|
160
170
|
palette: {fill: number[]; track: number[]},
|
|
171
|
+
frame?: {ring: Box; viewportWidth: number},
|
|
161
172
|
): Promise<boolean[][]> {
|
|
162
173
|
const scratch = await page.context().newPage();
|
|
163
174
|
try {
|
|
164
175
|
return await scratch.evaluate(
|
|
165
|
-
async ({items, fill, track, diameter, stroke}) => {
|
|
176
|
+
async ({items, fill, track, diameter, stroke, region}) => {
|
|
166
177
|
const out: boolean[][] = [];
|
|
167
178
|
for (const item of items) {
|
|
168
179
|
const bitmap = await createImageBitmap(
|
|
169
180
|
await (await fetch(`data:image/png;base64,${item}`)).blob(),
|
|
170
181
|
);
|
|
171
|
-
|
|
182
|
+
// The ring box in the shot's pixels: the whole shot, or the box's
|
|
183
|
+
// pixels in a viewport frame.
|
|
184
|
+
const frameScale =
|
|
185
|
+
region == null ? 1 : bitmap.width / region.viewportWidth;
|
|
186
|
+
const x0 =
|
|
187
|
+
region == null ? 0 : Math.round(region.ring.x * frameScale);
|
|
188
|
+
const y0 =
|
|
189
|
+
region == null ? 0 : Math.round(region.ring.y * frameScale);
|
|
190
|
+
const boxWidth =
|
|
191
|
+
region == null
|
|
192
|
+
? bitmap.width
|
|
193
|
+
: Math.round(region.ring.width * frameScale);
|
|
194
|
+
const boxHeight =
|
|
195
|
+
region == null
|
|
196
|
+
? bitmap.height
|
|
197
|
+
: Math.round(region.ring.height * frameScale);
|
|
198
|
+
const canvas = new OffscreenCanvas(boxWidth, boxHeight);
|
|
172
199
|
const context = canvas.getContext('2d');
|
|
173
200
|
if (context == null) {
|
|
174
201
|
throw new Error('no 2d context');
|
|
175
202
|
}
|
|
176
|
-
context.drawImage(
|
|
177
|
-
|
|
203
|
+
context.drawImage(
|
|
204
|
+
bitmap,
|
|
205
|
+
x0,
|
|
206
|
+
y0,
|
|
207
|
+
boxWidth,
|
|
208
|
+
boxHeight,
|
|
178
209
|
0,
|
|
179
210
|
0,
|
|
180
|
-
|
|
181
|
-
|
|
211
|
+
boxWidth,
|
|
212
|
+
boxHeight,
|
|
182
213
|
);
|
|
183
|
-
const
|
|
214
|
+
const {data, width} = context.getImageData(0, 0, boxWidth, boxHeight);
|
|
215
|
+
const scale = boxWidth / diameter;
|
|
184
216
|
const r = ((diameter - stroke) / 2) * scale;
|
|
185
217
|
const c = (diameter / 2) * scale;
|
|
186
218
|
const d = (a: number[], b: number[]) =>
|
|
@@ -200,7 +232,13 @@ async function inkByDegree(
|
|
|
200
232
|
}
|
|
201
233
|
return out;
|
|
202
234
|
},
|
|
203
|
-
{
|
|
235
|
+
{
|
|
236
|
+
items: shots,
|
|
237
|
+
...palette,
|
|
238
|
+
diameter: DIAMETER,
|
|
239
|
+
stroke: STROKE,
|
|
240
|
+
region: frame ?? null,
|
|
241
|
+
},
|
|
204
242
|
);
|
|
205
243
|
} finally {
|
|
206
244
|
await scratch.close();
|
|
@@ -263,6 +301,10 @@ test('a value change keeps moving while a script holds the main thread', async (
|
|
|
263
301
|
everyNthFrame: 1,
|
|
264
302
|
});
|
|
265
303
|
await page.waitForTimeout(300);
|
|
304
|
+
// The harness's busy-window control, through the block: a box the
|
|
305
|
+
// compositor moves along the top edge, clear of the ring, in the same
|
|
306
|
+
// screencast.
|
|
307
|
+
const control = await startBusyControl(page);
|
|
266
308
|
// A value change, one presented frame, then 700 ms of script.
|
|
267
309
|
const busy = await page.evaluate(
|
|
268
310
|
async ({storyId}) =>
|
|
@@ -298,6 +340,9 @@ test('a value change keeps moving while a script holds the main thread', async (
|
|
|
298
340
|
}),
|
|
299
341
|
{storyId: STORY},
|
|
300
342
|
);
|
|
343
|
+
// Gone once the block ends, so the page is still again when the
|
|
344
|
+
// screencast stops.
|
|
345
|
+
await control.remove();
|
|
301
346
|
await page.waitForTimeout(300);
|
|
302
347
|
await cdp.send('Page.stopScreencast');
|
|
303
348
|
await Promise.all(acks);
|
|
@@ -309,61 +354,54 @@ test('a value change keeps moving while a script holds the main thread', async (
|
|
|
309
354
|
// that shows the arc behind an earlier one still has its own later
|
|
310
355
|
// timestamp, so it stays in place.
|
|
311
356
|
const presented = inPresentationOrder(raw);
|
|
312
|
-
//
|
|
313
|
-
const
|
|
314
|
-
|
|
315
|
-
|
|
316
|
-
|
|
317
|
-
|
|
318
|
-
|
|
319
|
-
for (const item of items) {
|
|
320
|
-
const bitmap = await createImageBitmap(
|
|
321
|
-
await (await fetch(`data:image/png;base64,${item}`)).blob(),
|
|
322
|
-
);
|
|
323
|
-
const scale = bitmap.width / 240;
|
|
324
|
-
const canvas = new OffscreenCanvas(
|
|
325
|
-
Math.round(ring.width * scale),
|
|
326
|
-
Math.round(ring.height * scale),
|
|
327
|
-
);
|
|
328
|
-
const context = canvas.getContext('2d');
|
|
329
|
-
if (context == null) {
|
|
330
|
-
throw new Error('no 2d context');
|
|
331
|
-
}
|
|
332
|
-
context.drawImage(
|
|
333
|
-
bitmap,
|
|
334
|
-
Math.round(ring.x * scale),
|
|
335
|
-
Math.round(ring.y * scale),
|
|
336
|
-
canvas.width,
|
|
337
|
-
canvas.height,
|
|
338
|
-
0,
|
|
339
|
-
0,
|
|
340
|
-
canvas.width,
|
|
341
|
-
canvas.height,
|
|
342
|
-
);
|
|
343
|
-
const blob = await canvas.convertToBlob({type: 'image/png'});
|
|
344
|
-
const bytes = new Uint8Array(await blob.arrayBuffer());
|
|
345
|
-
let binary = '';
|
|
346
|
-
for (const byte of bytes) {
|
|
347
|
-
binary += String.fromCharCode(byte);
|
|
348
|
-
}
|
|
349
|
-
out.push(btoa(binary));
|
|
350
|
-
}
|
|
351
|
-
return out;
|
|
352
|
-
},
|
|
353
|
-
{items: presented.map(f => f.data), ring: box},
|
|
354
|
-
);
|
|
355
|
-
} finally {
|
|
356
|
-
await scratch.close();
|
|
357
|
-
}
|
|
358
|
-
const rows = await inkByDegree(page, crops, palette);
|
|
357
|
+
// How far the arc reaches in each frame, read at the ring.
|
|
358
|
+
const rows = await inkByDegree(
|
|
359
|
+
page,
|
|
360
|
+
presented.map(f => f.data),
|
|
361
|
+
palette,
|
|
362
|
+
{ring: box, viewportWidth: 240},
|
|
363
|
+
);
|
|
359
364
|
const frames = rows.map((row, i) => ({t: presented[i].t, ...span(row)}));
|
|
360
365
|
const inside = frames.filter(
|
|
361
366
|
f => f.t >= busy.from + 20 && f.t <= busy.to - 20,
|
|
362
367
|
);
|
|
363
|
-
// The
|
|
364
|
-
//
|
|
365
|
-
const
|
|
366
|
-
|
|
368
|
+
// The control, in the frames around the block (the proof reads it from the
|
|
369
|
+
// last frame before the block through the block's end).
|
|
370
|
+
const controlFrames = await trackMarker(
|
|
371
|
+
page,
|
|
372
|
+
presented
|
|
373
|
+
.filter(f => f.t >= busy.from - 250 && f.t <= busy.to)
|
|
374
|
+
.map(f => ({
|
|
375
|
+
t: f.t,
|
|
376
|
+
data: f.data,
|
|
377
|
+
format: 'png' as const,
|
|
378
|
+
viewportWidth: 240,
|
|
379
|
+
viewportHeight: 160,
|
|
380
|
+
})),
|
|
381
|
+
{rgb: CONTROL_RGB},
|
|
382
|
+
);
|
|
383
|
+
// The change runs through the block: the arc's reach shows a new degree on
|
|
384
|
+
// every frame the control moved on, and stalls no longer than the control,
|
|
385
|
+
// until it settles (the harness's busy proof: the screencast's capture rate
|
|
386
|
+
// thins both alike). It settles 3 degrees short of its end: on the change's
|
|
387
|
+
// own clock each 1-degree step of the reading takes 2 to 8 ms up to 324,
|
|
388
|
+
// then 12, 12 and 18 ms for 325, 326 and 327 before it rests at 328, so
|
|
389
|
+
// from 325 two frames can read the same degree while the arc still moves.
|
|
390
|
+
// It stays one piece the whole way, and lands at 90%.
|
|
391
|
+
const arc: TrackedFrame[] = frames.map(f => ({
|
|
392
|
+
t: f.t,
|
|
393
|
+
box: {x: f.last, y: 0, width: 1, height: 1},
|
|
394
|
+
pixels: 1,
|
|
395
|
+
}));
|
|
396
|
+
const proof = busyWindowProof(arc, busy, {
|
|
397
|
+
axis: 'x',
|
|
398
|
+
settledWithin: 3,
|
|
399
|
+
control: controlFrames,
|
|
400
|
+
});
|
|
401
|
+
test
|
|
402
|
+
.info()
|
|
403
|
+
.annotations.push({type: 'busy window', description: proof.summary});
|
|
404
|
+
expect(proof.verdict.failures, proof.summary).toEqual([]);
|
|
367
405
|
for (const frame of inside) {
|
|
368
406
|
expect(frame.pieces, `pieces at ${frame.t}`).toBe(1);
|
|
369
407
|
}
|
|
@@ -58,7 +58,9 @@ const styles = stylex.create({
|
|
|
58
58
|
display: 'flex',
|
|
59
59
|
borderRadius: radiusVars['--radius-element'],
|
|
60
60
|
backgroundColor: colorVars['--color-background-muted'],
|
|
61
|
-
|
|
61
|
+
borderWidth: borderVars['--border-width'],
|
|
62
|
+
borderStyle: 'solid',
|
|
63
|
+
borderColor: colorVars['--color-border'],
|
|
62
64
|
overflow: 'hidden',
|
|
63
65
|
},
|
|
64
66
|
rootFocused: {
|
|
@@ -73,7 +75,9 @@ const styles = stylex.create({
|
|
|
73
75
|
textAlign: 'end',
|
|
74
76
|
userSelect: 'none',
|
|
75
77
|
color: colorVars['--color-text-disabled'],
|
|
76
|
-
|
|
78
|
+
borderRightWidth: borderVars['--border-width'],
|
|
79
|
+
borderRightStyle: 'solid',
|
|
80
|
+
borderRightColor: colorVars['--color-border'],
|
|
77
81
|
},
|
|
78
82
|
gutterLine: {
|
|
79
83
|
fontFamily: typographyVars['--font-family-code'],
|