@astryxdesign/lab 0.7.7-canary.0d1ddcd → 0.7.7-canary.0eb44a2

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/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@astryxdesign/lab",
3
- "version": "0.7.7-canary.0d1ddcd",
3
+ "version": "0.7.7-canary.0eb44a2",
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.7-canary.0d1ddcd",
52
+ "@astryxdesign/core": "0.7.7-canary.0eb44a2",
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.7-canary.0d1ddcd",
63
- "@astryxdesign/cli": "0.7.7-canary.0d1ddcd",
64
- "@astryxdesign/interaction-harness": "0.7.7-canary.0d1ddcd",
62
+ "@astryxdesign/a11y-spec": "0.7.7-canary.0eb44a2",
63
+ "@astryxdesign/cli": "0.7.7-canary.0eb44a2",
64
+ "@astryxdesign/interaction-harness": "0.7.7-canary.0eb44a2",
65
65
  "@babel/cli": "^7.29.7",
66
66
  "@babel/core": "^7.29.7",
67
67
  "@babel/preset-react": "^7.29.7",
@@ -443,38 +443,74 @@ test('long popover content scrolls from the keyboard: Tab reaches its named grou
443
443
  top: Math.round(element.scrollTop),
444
444
  max: element.scrollHeight - element.clientHeight,
445
445
  }));
446
- // Keyboard scrolling is smooth, so each press is followed until the region
447
- // settles; the key is pressed until a press no longer moves it.
448
- const settle = async () => {
449
- let last = -1;
450
- for (let frame = 0; frame < 40; frame += 1) {
451
- const {top} = await scroll();
452
- if (top === last) {
453
- return top;
454
- }
455
- last = top;
456
- await page.waitForTimeout(50);
457
- }
458
- return last;
446
+ // Keyboard scrolling is smooth, and a busy browser can start it frames after
447
+ // the press, so each press is followed to the region's `scrollend`. A press
448
+ // that starts no scroll within 60 frames of its keydown is one that cannot
449
+ // move the region.
450
+ const press = async (key: string) => {
451
+ await region.evaluate(element => {
452
+ (window as unknown as {scrolled?: Promise<boolean>}).scrolled =
453
+ new Promise<boolean>(resolve => {
454
+ const listening = new AbortController();
455
+ const end = (scrolled: boolean) => {
456
+ listening.abort();
457
+ resolve(scrolled);
458
+ };
459
+ let started = false;
460
+ element.addEventListener(
461
+ 'scroll',
462
+ () => {
463
+ started = true;
464
+ },
465
+ {signal: listening.signal},
466
+ );
467
+ element.addEventListener('scrollend', () => end(true), {
468
+ signal: listening.signal,
469
+ });
470
+ // The frames count from the key's own keydown, so a slow runner
471
+ // between this setup and the press does not use them up.
472
+ window.addEventListener(
473
+ 'keydown',
474
+ () => {
475
+ let frames = 0;
476
+ const wait = () => {
477
+ if (started || listening.signal.aborted) {
478
+ return;
479
+ }
480
+ frames += 1;
481
+ if (frames > 60) {
482
+ end(false);
483
+ return;
484
+ }
485
+ requestAnimationFrame(wait);
486
+ };
487
+ requestAnimationFrame(wait);
488
+ },
489
+ {capture: true, once: true, signal: listening.signal},
490
+ );
491
+ });
492
+ });
493
+ await page.keyboard.press(key);
494
+ return page.evaluate(
495
+ () => (window as unknown as {scrolled?: Promise<boolean>}).scrolled,
496
+ );
459
497
  };
460
- const pressUntilStill = async (key: string) => {
461
- let top = await settle();
498
+ // The key is pressed until the region reaches its end or a press no longer
499
+ // moves it.
500
+ const pressUntilEnd = async (key: string) => {
462
501
  for (let presses = 0; presses < 200; presses += 1) {
463
- await page.keyboard.press(key);
464
- const next = await settle();
465
- if (next === top) {
502
+ const {top, max} = await scroll();
503
+ if (top >= max - 1 || !(await press(key))) {
466
504
  break;
467
505
  }
468
- top = next;
469
506
  }
470
507
  return scroll();
471
508
  };
472
509
  const atStart = await scroll();
473
- const afterPageDown = await pressUntilStill('PageDown');
474
- await page.keyboard.press('Home');
475
- await settle();
510
+ const afterPageDown = await pressUntilEnd('PageDown');
511
+ await press('Home');
476
512
  const afterHome = await scroll();
477
- const afterArrowDown = await pressUntilStill('ArrowDown');
513
+ const afterArrowDown = await pressUntilEnd('ArrowDown');
478
514
  // The surface itself stays inside the viewport.
479
515
  const surface = await dialog.boundingBox();
480
516
  const viewportHeight = page.viewportSize()?.height ?? 0;