@motion-proto/live-tokens 0.98.2 → 0.99.0

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.
Files changed (69) hide show
  1. package/CHANGELOG.md +67 -0
  2. package/bin/contractRunner.mjs +2 -2
  3. package/bin/rules/a11y.mjs +1 -1
  4. package/dist-plugin/index.cjs +71 -15
  5. package/dist-plugin/index.js +71 -15
  6. package/package.json +1 -1
  7. package/src/editor/bootstrap.ts +3 -1
  8. package/src/editor/component-editor/SectionDividerEditor.svelte +9 -10
  9. package/src/editor/core/a11y/a11yReport.ts +85 -22
  10. package/src/editor/core/a11y/a11yReportTypes.ts +11 -3
  11. package/src/editor/core/a11y/contrastFixes.ts +41 -0
  12. package/src/editor/core/palettes/contrastPairs.ts +4 -1
  13. package/src/editor/docs/content/accessibility.md +67 -18
  14. package/src/editor/docs/content/editing-tokens.md +4 -0
  15. package/src/editor/docs/content.generated.ts +2 -2
  16. package/src/editor/pages/ComponentEditorPage.svelte +4 -3
  17. package/src/editor/pages/EditorShell.svelte +10 -8
  18. package/src/editor/styles/ui-editor.css +2 -0
  19. package/src/editor/ui/a11y/A11yByEye.svelte +264 -0
  20. package/src/editor/ui/a11y/A11yComponentIssues.svelte +34 -16
  21. package/src/editor/ui/a11y/A11yFindingRow.svelte +66 -4
  22. package/src/editor/ui/a11y/A11yIssueRow.svelte +55 -24
  23. package/src/editor/ui/a11y/A11yOverview.svelte +72 -68
  24. package/src/editor/ui/a11y/A11yPanel.svelte +29 -4
  25. package/src/editor/ui/a11y/A11yPropertyMark.svelte +8 -8
  26. package/src/editor/ui/a11y/A11yRailMark.svelte +11 -4
  27. package/src/editor/ui/a11y/AccessibilityTab.svelte +22 -35
  28. package/src/editor/ui/a11y/a11yView.ts +50 -11
  29. package/src/live-tokens/data/colors-and-type/halloween.json +1 -1
  30. package/src/live-tokens/data/themes/autumn.json +16 -16
  31. package/src/live-tokens/data/themes/halloween.json +17 -17
  32. package/src/live-tokens/data/themes/midnight-study.json +16 -16
  33. package/src/live-tokens/data/themes/ocean.json +16 -16
  34. package/src/live-tokens/data/themes/royal-velvet.json +16 -16
  35. package/src/live-tokens/data/themes/sketchy.json +16 -16
  36. package/src/live-tokens/data/themes/spring-meadow.json +16 -16
  37. package/src/live-tokens/data/themes/sunset.json +16 -16
  38. package/src/system/components/Button.svelte +3 -3
  39. package/src/system/components/InlineEditActions.svelte +1 -1
  40. package/src/system/components/Input.svelte +1 -1
  41. package/src/system/components/MenuSelect.svelte +1 -1
  42. package/src/system/components/ProgressBar.svelte +1 -1
  43. package/src/system/components/SlidePager.svelte +1 -1
  44. package/src/system/components/Slider.svelte +6 -6
  45. package/src/system/components/TabBar.svelte +1 -1
  46. package/src/system/components/Toggle.svelte +1 -1
  47. package/src/testing-js/{chunk-RWH46IU5.js → chunk-7QXUJRSO.js} +2 -2
  48. package/src/testing-js/chunk-GZKUYLDW.js +193 -0
  49. package/src/testing-js/chunk-GZKUYLDW.js.map +1 -0
  50. package/src/testing-js/{chunk-SHLPDNAQ.js → chunk-RTZQLW3F.js} +172 -181
  51. package/src/testing-js/chunk-RTZQLW3F.js.map +1 -0
  52. package/src/testing-js/{chunk-5HNZHIHG.js → chunk-RWOT2XDB.js} +2 -2
  53. package/src/testing-js/{chunk-5HNZHIHG.js.map → chunk-RWOT2XDB.js.map} +1 -1
  54. package/src/testing-js/{chunk-R54I7YL6.js → chunk-THWGMSRH.js} +2 -2
  55. package/src/testing-js/component-a11y.contract.js +53 -23
  56. package/src/testing-js/component-a11y.contract.js.map +1 -1
  57. package/src/testing-js/component-behavior.contract.js +1 -1
  58. package/src/testing-js/component-editor.contract.js +3 -3
  59. package/src/testing-js/component-render.contract.js +3 -3
  60. package/src/testing-js/index.js +4 -4
  61. package/src/testing-js/index.js.map +1 -1
  62. package/src/testing-js/page-compliance.contract.js +3 -3
  63. package/src/testing-js/vitest.js +2 -2
  64. package/template/_gitignore +3 -0
  65. package/src/testing-js/chunk-EWSGE27V.js +0 -168
  66. package/src/testing-js/chunk-EWSGE27V.js.map +0 -1
  67. package/src/testing-js/chunk-SHLPDNAQ.js.map +0 -1
  68. /package/src/testing-js/{chunk-RWH46IU5.js.map → chunk-7QXUJRSO.js.map} +0 -0
  69. /package/src/testing-js/{chunk-R54I7YL6.js.map → chunk-THWGMSRH.js.map} +0 -0
@@ -197,10 +197,11 @@ var NON_TEXT_URL = "https://www.w3.org/WAI/WCAG22/Understanding/non-text-contras
197
197
  var FOCUS_ATTR = "data-lt-focus-probe";
198
198
  var NO_TRANSITION_ID = "lt-focus-probe-no-transition";
199
199
  var FORCE = ["focus", "focus-visible"];
200
+ var SIBLING_FOCUS_ATTR = "data-lt-focus-sibling";
200
201
  function inPage(request) {
201
202
  const scopes = [...document.querySelectorAll("scope" in request && request.scope || ":not(*)")];
202
203
  const excluded = (el) => "exclude" in request && request.exclude.some((selector) => el.closest(selector));
203
- const inScope = (el) => scopes.some((scope) => scope.contains(el)) && !excluded(el);
204
+ const inScope2 = (el) => scopes.some((scope) => scope.contains(el)) && !excluded(el);
204
205
  const canvas = document.createElement("canvas");
205
206
  canvas.width = canvas.height = 1;
206
207
  const ctx = canvas.getContext("2d", { willReadFrequently: true });
@@ -252,7 +253,8 @@ function inPage(request) {
252
253
  let first = -1;
253
254
  for (let e = from; e; e = e.parentElement, level++) {
254
255
  const box = e.getBoundingClientRect();
255
- const contains = box.left <= ring.left + 0.5 && box.top <= ring.top + 0.5 && box.right >= ring.right - 0.5 && box.bottom >= ring.bottom - 0.5;
256
+ const isScope = scopes.includes(e);
257
+ const contains = isScope || box.left <= ring.left + 0.5 && box.top <= ring.top + 0.5 && box.right >= ring.right - 0.5 && box.bottom >= ring.bottom - 0.5;
256
258
  if (!contains) continue;
257
259
  if (first < 0) first = level;
258
260
  const style = getComputedStyle(e);
@@ -260,6 +262,12 @@ function inPage(request) {
260
262
  const a = alpha(style.backgroundColor);
261
263
  if (a > 0) layers.unshift(style.backgroundColor);
262
264
  if (a >= 1) break;
265
+ if (isScope) {
266
+ const page = getComputedStyle(document.documentElement).getPropertyValue("--page-bg").trim();
267
+ if (/gradient|url\(/.test(page)) return { color: null, first };
268
+ if (page) layers.unshift(page);
269
+ break;
270
+ }
263
271
  }
264
272
  return { color: paint(layers), first: Math.max(first, 0) };
265
273
  };
@@ -276,7 +284,7 @@ function inPage(request) {
276
284
  for (const sibling of target.parentElement?.children ?? []) {
277
285
  if (sibling !== target) list.push(sibling, ...sibling.querySelectorAll("*"));
278
286
  }
279
- return list.filter(inScope);
287
+ return list.filter(inScope2);
280
288
  };
281
289
  const signature = (el) => {
282
290
  const s = getComputedStyle(el);
@@ -316,8 +324,9 @@ function inPage(request) {
316
324
  style.id = request.styleId;
317
325
  style.textContent = "*, *::before, *::after { transition: none !important; }";
318
326
  document.head.append(style);
327
+ for (const el of document.querySelectorAll(`[${request.marker}]`)) el.removeAttribute(request.marker);
319
328
  const focusable = 'a[href], area[href], button, input:not([type="hidden"]), select, textarea, summary, iframe, [tabindex], [contenteditable]:not([contenteditable="false"])';
320
- const found = scopes.flatMap((scope) => [scope, ...scope.querySelectorAll(focusable)]).filter((el, i, all) => all.indexOf(el) === i && el.matches(focusable) && inScope(el)).filter((el) => el.tabIndex >= 0 && !el.matches(":disabled") && el.checkVisibility({ visibilityProperty: true }));
329
+ const found = scopes.flatMap((scope) => [scope, ...scope.querySelectorAll(focusable)]).filter((el, i, all) => all.indexOf(el) === i && el.matches(focusable) && inScope2(el)).filter((el) => el.tabIndex >= 0 && !el.matches(":disabled") && el.checkVisibility({ visibilityProperty: true }));
321
330
  found.forEach((el, i) => el.setAttribute(request.attr, String(i)));
322
331
  return found.length;
323
332
  }
@@ -332,6 +341,7 @@ function inPage(request) {
332
341
  if (request.before[i] === void 0 || request.before[i] === signature(el)) continue;
333
342
  const found = indicatorOf(el, request.before[i]);
334
343
  if (!found) continue;
344
+ if (el !== target && !target.contains(el)) target.setAttribute(request.marker, "");
335
345
  if (found.channel === "browser") return { kind: "browser" };
336
346
  const ring = inflate(el.getBoundingClientRect(), Math.max(found.extent, 0));
337
347
  const behind = backdrop(found.channel === "border" ? el.parentElement : el, found.extent < 0 ? el.getBoundingClientRect() : ring);
@@ -363,7 +373,7 @@ function inPage(request) {
363
373
  return controls.length > 0 && controls.every((c) => c.matches(":disabled") || c.getAttribute("aria-disabled") === "true");
364
374
  };
365
375
  for (const part of request.parts) {
366
- const elements = scopes.flatMap((scope) => [scope, ...scope.querySelectorAll(part.selector)]).filter((el, i, all) => all.indexOf(el) === i && el.matches(part.selector) && inScope(el)).filter((el) => !part.when || el.matches(part.when)).filter((el) => el.checkVisibility({ visibilityProperty: true }) && el.getBoundingClientRect().width > 0 && !inactive(el));
376
+ const elements = scopes.flatMap((scope) => [scope, ...scope.querySelectorAll(part.selector)]).filter((el, i, all) => all.indexOf(el) === i && el.matches(part.selector) && inScope2(el)).filter((el) => !part.when || el.matches(part.when)).filter((el) => el.checkVisibility({ visibilityProperty: true }) && el.getBoundingClientRect().width > 0 && !inactive(el));
367
377
  for (const el of elements) {
368
378
  const style = getComputedStyle(el);
369
379
  const behind = backdrop(el.parentElement, el.getBoundingClientRect());
@@ -409,7 +419,7 @@ function ratioText(ratio) {
409
419
  }
410
420
  async function scanFocusIndicators(page, scope, exclude) {
411
421
  const cdp = await cdpSession(page);
412
- const count = await run(page, { kind: "focusables", scope, exclude, attr: FOCUS_ATTR, styleId: NO_TRANSITION_ID });
422
+ const count = await run(page, { kind: "focusables", scope, exclude, attr: FOCUS_ATTR, styleId: NO_TRANSITION_ID, marker: SIBLING_FOCUS_ATTR });
413
423
  const checked = [];
414
424
  try {
415
425
  const { root } = await cdp.send("DOM.getDocument", { depth: 0 });
@@ -419,7 +429,7 @@ async function scanFocusIndicators(page, scope, exclude) {
419
429
  await cdp.send("CSS.forcePseudoState", { nodeId, forcedPseudoClasses: FORCE });
420
430
  let outcome;
421
431
  try {
422
- outcome = await run(page, { kind: "measure", attr: FOCUS_ATTR, index, scope, exclude, before });
432
+ outcome = await run(page, { kind: "measure", attr: FOCUS_ATTR, index, scope, exclude, before, marker: SIBLING_FOCUS_ATTR });
423
433
  } finally {
424
434
  await cdp.send("CSS.forcePseudoState", { nodeId, forcedPseudoClasses: [] });
425
435
  }
@@ -463,196 +473,177 @@ async function scanBoundaries(page, scope, exclude, parts, root) {
463
473
  });
464
474
  }
465
475
 
466
- // src/testing/support/textSpacingAndMotion.ts
467
- var TEXT_SPACING_URL = "https://www.w3.org/WAI/WCAG22/Understanding/text-spacing.html";
468
- var MOTION_MS = 200;
469
- var MOTION_URL = "https://www.w3.org/WAI/WCAG22/Techniques/css/C39";
470
- var TEXT_SPACING_RULE = "text-spacing";
471
- var REDUCED_MOTION_RULE = "prefers-reduced-motion";
472
- var SPACING_ATTR = "data-lt-spacing-probe";
473
- var MOTION_ATTR = "data-lt-motion-probe";
474
- var STILL_ID = "lt-spacing-probe-still";
475
- var TOLERANCE = 1;
476
- function textSpacingCss(scope) {
477
- const every = scope ? `${scope}, ${scope} *` : "*";
478
- const paragraphs = scope ? `${scope} p` : "p";
479
- return `
480
- ${every} { line-height: 1.5 !important; letter-spacing: 0.12em !important; word-spacing: 0.16em !important; }
481
- ${paragraphs} { margin-bottom: 2em !important; }
482
- `;
483
- }
484
- async function newUnderTextSpacing(page, observe, key, scope) {
485
- const before = await observe();
486
- const style = await page.addStyleTag({ content: textSpacingCss(scope) });
487
- let after;
476
+ // src/testing/support/a11y.ts
477
+ import { test } from "@playwright/test";
478
+ var A11Y_ANNOTATION = "a11y";
479
+ var AXE_TAGS = ["wcag2a", "wcag2aa", "wcag21aa", "wcag22aa"];
480
+ var SCOPE_ATTR = "data-lt-a11y-scope";
481
+ var EXCLUDE_ATTR = "data-lt-a11y-exclude";
482
+ var HTML_LIMIT = 300;
483
+ var EngineMissing = class extends Error {
484
+ };
485
+ async function importEngine(packageName, load) {
488
486
  try {
489
- after = await observe();
490
- } finally {
491
- await style.evaluate((node) => node.remove());
487
+ return await load();
488
+ } catch (error) {
489
+ if (error.code === "ERR_MODULE_NOT_FOUND") throw new EngineMissing(`${packageName} is not installed`);
490
+ throw error;
492
491
  }
493
- const known = /* @__PURE__ */ new Map();
494
- for (const failure of before) known.set(key(failure), (known.get(key(failure)) ?? 0) + 1);
495
- return after.filter((failure) => {
496
- const left = known.get(key(failure)) ?? 0;
497
- if (left > 0) known.set(key(failure), left - 1);
498
- return left === 0;
499
- });
500
492
  }
501
- function tagInScope(page, scope, exclude, own, attr) {
502
- return page.evaluate(({ scope: scope2, exclude: exclude2, own: own2, attr: attr2 }) => {
503
- const found = [...document.querySelectorAll(scope2)].flatMap((root) => [root, ...root.querySelectorAll("*")]).filter((el, i, all) => all.indexOf(el) === i && el.closest(own2) && !exclude2.some((selector) => el.closest(selector)));
504
- found.forEach((el, i) => el.setAttribute(attr2, String(i)));
505
- return found.length;
506
- }, { scope, exclude, own: own.join(", "), attr });
507
- }
508
- function untag(page, attr, styleId) {
509
- return page.evaluate(({ attr: attr2, styleId: styleId2 }) => {
510
- if (styleId2) document.getElementById(styleId2)?.remove();
511
- for (const el of document.querySelectorAll(`[${attr2}]`)) el.removeAttribute(attr2);
512
- }, { attr, styleId });
513
- }
514
- function observeOverflow(page) {
515
- return page.evaluate(({ attr, tolerance }) => [...document.querySelectorAll(`[${attr}]`)].flatMap((el) => {
516
- const style = getComputedStyle(el);
517
- if (style.display === "none" || style.display === "contents") return [];
518
- if (el.clientWidth === 0 && el.clientHeight === 0) return [];
519
- if (!el.textContent?.trim()) return [];
520
- const index = el.getAttribute(attr);
521
- const tag = el.tagName.toLowerCase();
522
- const found = [];
523
- const axes = [
524
- ["x", el.scrollWidth, el.clientWidth, style.overflowX],
525
- ["y", el.scrollHeight, el.clientHeight, style.overflowY]
526
- ];
527
- for (const [axis, content, box, overflow] of axes) {
528
- if (overflow === "auto" || overflow === "scroll" || content <= box + tolerance) continue;
529
- found.push({ index, axis, tag, content, box, overflow });
530
- }
531
- return found;
532
- }), { attr: SPACING_ATTR, tolerance: TOLERANCE });
533
- }
534
- function groupBy(items, key) {
535
- const groups = /* @__PURE__ */ new Map();
536
- for (const item of items) groups.set(key(item), [...groups.get(key(item)) ?? [], item]);
537
- return groups;
538
- }
539
- async function scanTextSpacing(page, scope, exclude, own) {
540
- await page.evaluate(({ id, scope: scope2 }) => {
541
- const style = document.createElement("style");
542
- style.id = id;
543
- style.textContent = `${scope2} *, ${scope2} *::before, ${scope2} *::after { transition: none !important; }`;
544
- document.head.append(style);
545
- }, { id: STILL_ID, scope });
493
+ var axeModules = null;
494
+ async function importAxe() {
495
+ await importEngine("axe-core", () => import("axe-core"));
496
+ const { AxeBuilder } = await importEngine("@axe-core/playwright", () => import("@axe-core/playwright"));
497
+ return { AxeBuilder };
498
+ }
499
+ var loadAxe = () => axeModules ??= importAxe();
500
+ var alfaModules = null;
501
+ async function importAlfa() {
502
+ const { Audit, Outcome } = await importEngine("@siteimprove/alfa-act", () => import("@siteimprove/alfa-act"));
503
+ const { Rules } = await importEngine("@siteimprove/alfa-rules", () => import("@siteimprove/alfa-rules"));
504
+ const { Node } = await importEngine("@siteimprove/alfa-dom", () => import("@siteimprove/alfa-dom"));
505
+ const { Native: DomNative } = await importEngine("@siteimprove/alfa-dom", () => import("@siteimprove/alfa-dom/native"));
506
+ const { Device } = await importEngine("@siteimprove/alfa-device", () => import("@siteimprove/alfa-device"));
507
+ const { Native: DeviceNative } = await importEngine("@siteimprove/alfa-device", () => import("@siteimprove/alfa-device/native"));
508
+ const { Page: AlfaPage } = await importEngine("@siteimprove/alfa-web", () => import("@siteimprove/alfa-web"));
509
+ const http = await importEngine("@siteimprove/alfa-http", () => import("@siteimprove/alfa-http"));
510
+ const { URL } = await importEngine("@siteimprove/alfa-url", () => import("@siteimprove/alfa-url"));
511
+ return {
512
+ Audit,
513
+ Outcome,
514
+ R65: Rules.get("R65").getUnsafe(),
515
+ Node,
516
+ DomNative,
517
+ Device,
518
+ DeviceNative,
519
+ AlfaPage,
520
+ http,
521
+ URL
522
+ };
523
+ }
524
+ var loadAlfa = () => alfaModules ??= importAlfa();
525
+ async function missingEngine(engines) {
546
526
  try {
547
- if (await tagInScope(page, scope, exclude, own, SPACING_ATTR) === 0) return [];
548
- const found = await newUnderTextSpacing(page, () => observeOverflow(page), (o) => `${o.index}|${o.axis}`, scope);
549
- if (found.length === 0) return [];
550
- const byElement = groupBy(found, (o) => o.index);
551
- const described = await describeTagged(page, scope, exclude, SPACING_ATTR, [...byElement.keys()]);
552
- return [...byElement.values()].map((overflows, i) => ({
553
- rule: "a11y-text-spacing",
554
- engineRule: TEXT_SPACING_RULE,
555
- impact: null,
556
- target: described[i].target,
557
- html: described[i].html,
558
- help: `Under the text spacing override, ${overflows.map((o) => `<${o.tag}> holds ${o.content}px of content in ${o.box}px of ${o.axis === "x" ? "width" : "height"}, and its overflow-${o.axis} is ${o.overflow}`).join("; ")}`,
559
- helpUrl: TEXT_SPACING_URL
560
- }));
561
- } finally {
562
- await untag(page, SPACING_ATTR, STILL_ID);
527
+ for (const name of engines) await (name === "axe" ? loadAxe() : loadAlfa());
528
+ return null;
529
+ } catch (error) {
530
+ if (error instanceof EngineMissing) return error.message;
531
+ throw error;
563
532
  }
564
533
  }
565
- function observeMotion(page) {
566
- return page.evaluate(({ attr, limit }) => {
567
- const ms = (time) => parseFloat(time) * (time.trim().endsWith("ms") ? 1 : 1e3) || 0;
568
- const list = (value) => value.split(/,(?![^(]*\))/).map((part) => part.trim());
569
- const at = (values, i) => values[i % values.length];
570
- const found = [];
571
- const tagged = [...document.querySelectorAll(`[${attr}]`)].filter((el) => el.checkVisibility());
572
- for (const el of tagged) {
573
- const index = el.getAttribute(attr);
574
- for (const pseudo of ["", "::before", "::after"]) {
575
- const style = getComputedStyle(el, pseudo || null);
576
- if (pseudo && (style.content === "none" || style.content === "normal" || style.display === "none")) continue;
577
- const durations = list(style.animationDuration);
578
- const counts = list(style.animationIterationCount);
579
- const delays = list(style.animationDelay);
580
- list(style.animationName).forEach((name, i) => {
581
- if (name === "none") return;
582
- const count = at(counts, i);
583
- const end = ms(at(delays, i)) + (count === "infinite" ? Infinity : ms(at(durations, i)) * parseFloat(count));
584
- if (end > limit) found.push({ index, pseudo, kind: "animation", name: name.replace(/^svelte-[a-z0-9]+-/, ""), end });
585
- });
586
- const transitionDurations = list(style.transitionDuration);
587
- const transitionDelays = list(style.transitionDelay);
588
- list(style.transitionProperty).forEach((name, i) => {
589
- const end = ms(at(transitionDurations, i)) + ms(at(transitionDelays, i));
590
- if (name !== "none" && end > limit) found.push({ index, pseudo, kind: "transition", name, end });
591
- });
592
- }
593
- }
594
- for (const animation of document.getAnimations()) {
595
- if (animation instanceof CSSAnimation || animation instanceof CSSTransition || animation.playState !== "running") continue;
596
- const effect = animation.effect;
597
- if (!(effect instanceof KeyframeEffect) || !effect.target?.hasAttribute(attr)) continue;
598
- const end = Number(effect.getComputedTiming().endTime ?? 0);
599
- if (end > limit) {
600
- found.push({ index: effect.target.getAttribute(attr), pseudo: effect.pseudoElement ?? "", kind: "script", name: animation.id, end });
601
- }
602
- }
603
- return found;
604
- }, { attr: MOTION_ATTR, limit: MOTION_MS });
534
+ function axeResults(rule, results, withReasons) {
535
+ return results.flatMap(
536
+ (result) => result.nodes.map((node) => {
537
+ const reasons = withReasons ? [...new Set([...node.any, ...node.all, ...node.none].map((check) => check.message).filter(Boolean))] : [];
538
+ return {
539
+ rule,
540
+ engineRule: result.id,
541
+ impact: node.impact ?? result.impact ?? null,
542
+ target: node.target.map((part) => Array.isArray(part) ? part.join(" >>> ") : String(part)).join(" | "),
543
+ html: node.html.slice(0, HTML_LIMIT),
544
+ help: [result.help, ...reasons].join(". "),
545
+ helpUrl: result.helpUrl
546
+ };
547
+ })
548
+ );
605
549
  }
606
- var capitalize = (text) => text.charAt(0).toUpperCase() + text.slice(1);
607
- function describeMotion({ kind, name, end }) {
608
- const what = kind === "animation" ? `the animation ${name}` : kind === "transition" ? `a transition of ${name}` : `a script animation${name ? ` ${name}` : ""}`;
609
- return `${what} ${Number.isFinite(end) ? `lasts ${Math.round(end)} ms` : "runs without end"}`;
550
+ async function scanAxe(page, scope, exclude, rule, only) {
551
+ const { AxeBuilder } = await loadAxe();
552
+ let builder = new AxeBuilder({ page }).include(scope);
553
+ builder = only ? builder.withRules(only) : builder.withTags(AXE_TAGS);
554
+ for (const selector of exclude) builder = builder.exclude(selector);
555
+ if (rule === "a11y-page") builder = builder.disableRules(["color-contrast"]);
556
+ const result = await builder.analyze();
557
+ return [
558
+ ...axeResults(rule, result.violations, false),
559
+ ...axeResults("a11y-review", result.incomplete, true)
560
+ ];
610
561
  }
611
- async function scanReducedMotion(page, scope, exclude, own) {
612
- try {
613
- if (await tagInScope(page, scope, exclude, own, MOTION_ATTR) === 0) return [];
614
- if ((await observeMotion(page)).length === 0) return [];
615
- let reduced;
616
- await page.emulateMedia({ reducedMotion: "reduce" });
617
- try {
618
- await page.evaluate(() => new Promise((resolve) => requestAnimationFrame(() => requestAnimationFrame(() => resolve()))));
619
- reduced = await observeMotion(page);
620
- } finally {
621
- await page.emulateMedia({ reducedMotion: null });
562
+ function pruneToScope(node) {
563
+ if (node.type === "element" && node.attributes?.some((a) => a.name === SCOPE_ATTR)) return true;
564
+ if (!node.children) return false;
565
+ if (node.type === "element" && node.name === "head") return true;
566
+ node.children = node.children.filter((child) => child.type === "type" || pruneToScope(child));
567
+ return node.type === "document" || node.children.some((child) => child.type === "element");
568
+ }
569
+ var FOCUS_HELP = {
570
+ failed: "Focusing the element changes nothing visible",
571
+ cantTell: "Focusing the element changes no style on it, its descendants, or its ancestors"
572
+ };
573
+ async function scanFocusVisible(page, scope, exclude) {
574
+ const alfa = await loadAlfa();
575
+ await page.evaluate(({ scope: scope2, exclude: exclude2, scopeAttr, excludeAttr }) => {
576
+ for (const element of document.querySelectorAll(scope2)) element.setAttribute(scopeAttr, "");
577
+ for (const selector of exclude2) {
578
+ for (const element of document.querySelectorAll(selector)) element.setAttribute(excludeAttr, "");
622
579
  }
623
- if (reduced.length === 0) return [];
624
- const byTarget = groupBy(reduced, (m) => `${m.index}
625
- ${m.pseudo}`);
626
- const groups = [...byTarget.values()];
627
- const described = await describeTagged(page, scope, exclude, MOTION_ATTR, groups.map((motions) => motions[0].index));
628
- return groups.map((motions, i) => ({
629
- result: {
630
- rule: "a11y-reduced-motion",
631
- engineRule: REDUCED_MOTION_RULE,
632
- impact: null,
633
- target: `${described[i].target}${motions[0].pseudo}`,
634
- html: described[i].html,
635
- help: capitalize(`${motions.map(describeMotion).join("; ")} under prefers-reduced-motion: reduce`),
636
- helpUrl: MOTION_URL
637
- },
638
- trace: { selector: described[i].target }
639
- }));
580
+ }, { scope, exclude, scopeAttr: SCOPE_ATTR, excludeAttr: EXCLUDE_ATTR });
581
+ let json;
582
+ try {
583
+ const handle = await page.evaluateHandle(() => document);
584
+ json = await handle.evaluate(alfa.DomNative.fromNode);
585
+ await handle.dispose();
640
586
  } finally {
641
- await untag(page, MOTION_ATTR);
587
+ await page.evaluate((attrs) => {
588
+ for (const attr of attrs) for (const element of document.querySelectorAll(`[${attr}]`)) element.removeAttribute(attr);
589
+ }, [SCOPE_ATTR, EXCLUDE_ATTR]);
642
590
  }
591
+ pruneToScope(json);
592
+ const fromWindow = alfa.DeviceNative.fromWindow;
593
+ const device = alfa.Device.from(await page.evaluate(fromWindow));
594
+ const url = alfa.URL.parse(page.url()).getUnsafe();
595
+ const { Request, Response, Headers, Header } = alfa.http;
596
+ const alfaPage = alfa.AlfaPage.of(
597
+ Request.of("GET", url),
598
+ Response.of(url, 200, Headers.of([Header.of("Content-Type", "text/html")])),
599
+ alfa.Node.from(json, device),
600
+ device
601
+ );
602
+ const results = [];
603
+ for (const outcome of await alfa.Audit.of(alfaPage, [alfa.R65]).evaluate()) {
604
+ const kind = alfa.Outcome.isFailed(outcome) ? "failed" : alfa.Outcome.isCantTell(outcome) ? "cantTell" : null;
605
+ if (!kind) continue;
606
+ const target = outcome.target;
607
+ if (!inScope(target)) continue;
608
+ if (kind === "cantTell" && target.attribute?.(SIBLING_FOCUS_ATTR).isSome()) continue;
609
+ results.push({
610
+ rule: "a11y-focus-visible",
611
+ engineRule: "SIA-R65",
612
+ impact: null,
613
+ target: elementLabel(target),
614
+ html: target.toString().replace(/\s+/g, " ").slice(0, HTML_LIMIT),
615
+ help: FOCUS_HELP[kind],
616
+ helpUrl: alfa.R65.uri
617
+ });
618
+ }
619
+ return results;
620
+ }
621
+ function inScope(target) {
622
+ for (const node of target.inclusiveAncestors()) {
623
+ if (typeof node.attribute !== "function") continue;
624
+ if (node.attribute(EXCLUDE_ATTR).isSome()) return false;
625
+ if (node.attribute(SCOPE_ATTR).isSome()) return true;
626
+ }
627
+ return false;
628
+ }
629
+ function elementLabel(target) {
630
+ const id = target.id.isSome() ? `#${target.id.get()}` : "";
631
+ return `${target.name}${id}${[...target.classes].map((name) => `.${name}`).join("")}`;
632
+ }
633
+ function recordA11y(results) {
634
+ if (results.length === 0) return;
635
+ test.info().annotations.push({ type: A11Y_ANNOTATION, description: JSON.stringify(results) });
643
636
  }
644
637
 
645
638
  export {
646
639
  TRACE_AXES,
647
640
  traceProperties,
641
+ describeTagged,
648
642
  scanFocusIndicators,
649
643
  scanBoundaries,
650
- TEXT_SPACING_URL,
651
- MOTION_MS,
652
- MOTION_URL,
653
- TEXT_SPACING_RULE,
654
- newUnderTextSpacing,
655
- scanTextSpacing,
656
- scanReducedMotion
644
+ missingEngine,
645
+ scanAxe,
646
+ scanFocusVisible,
647
+ recordA11y
657
648
  };
658
- //# sourceMappingURL=chunk-SHLPDNAQ.js.map
649
+ //# sourceMappingURL=chunk-RTZQLW3F.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../testing/support/traceProperties.ts","../testing/support/nonTextContrast.ts","../testing/support/a11y.ts"],"sourcesContent":["import type { CDPSession, Page } from '@playwright/test';\n\n/** The CSS properties a result's verdict reads, per element. A name ending in\n * `*` matches every property that starts with the rest; `*` alone matches\n * every property. */\nexport interface TraceAxes {\n target: string[];\n pseudoElements: string[];\n ancestors: string[];\n /** Pseudo-classes forced on the target while its styles are read. The\n * target then keeps only the declarations the force brings in or changes. */\n force?: string[];\n}\n\nconst BOX_SIZE = ['width', 'height', 'min-*', 'inline-size', 'block-size', 'padding*'];\nconst FOCUS = ['focus', 'focus-visible'];\n// Every border property but the radii, which carry no colour or width.\nconst BORDER_PAINT = ['border-block*', 'border-inline*', ...['', '-top', '-right', '-bottom', '-left']\n .flatMap((side) => [`border${side}`, `border${side}-color`, `border${side}-width`, `border${side}-style`])];\n\n// What sets how long a motion lasts; easing and fill shape it without lengthening it.\nconst MOTION = ['animation', 'animation-name', 'animation-duration', 'animation-delay', 'animation-iteration-count',\n 'transition', 'transition-property', 'transition-duration', 'transition-delay'];\n\n/** Decision 2 of docs/plans/a11y-property-marks.md, keyed by engine rule. An\n * engine rule absent here traces nothing. */\nexport const TRACE_AXES: Readonly<Record<string, TraceAxes>> = {\n 'color-contrast': {\n target: ['color', 'background*', 'opacity', 'text-shadow'],\n pseudoElements: ['*'],\n ancestors: ['background*', 'opacity'],\n },\n 'SIA-R65': {\n target: ['outline*', 'box-shadow', 'border*', 'background*', 'color', 'text-decoration*'],\n pseudoElements: [],\n ancestors: [],\n force: FOCUS,\n },\n 'target-size': { target: BOX_SIZE, pseudoElements: BOX_SIZE, ancestors: [] },\n 'focus-indicator-contrast': {\n target: ['outline*', 'box-shadow', ...BORDER_PAINT, 'background*', 'color'],\n pseudoElements: [],\n ancestors: ['background*'],\n force: FOCUS,\n },\n 'control-boundary-contrast': {\n target: [...BORDER_PAINT, 'outline', 'outline-color', 'outline-width', 'outline-style', 'background*'],\n pseudoElements: [],\n ancestors: ['background*'],\n },\n // Every element's line height is 1.5 under the override, so the theme's own cannot cause the overflow.\n 'text-spacing': {\n target: ['height', 'max-height', 'width', 'max-width', 'padding*', 'overflow*', 'white-space'],\n pseudoElements: [],\n ancestors: [],\n },\n // A pseudo-element that does not display does not move, so its display gates the motion, as Button's shimmer does.\n 'prefers-reduced-motion': { target: MOTION, pseudoElements: [...MOTION, 'display'], ancestors: [] },\n};\n\ninterface Declaration {\n name: string;\n value: string;\n text?: string;\n important?: boolean;\n}\n\ninterface Style {\n cssProperties: Declaration[];\n}\n\ninterface RuleMatch {\n rule: {\n origin: string;\n style: Style & { range?: unknown };\n styleSheetId?: string;\n selectorList: { text: string };\n };\n}\n\ninterface ElementStyles {\n inlineStyle?: Style;\n matchedCSSRules?: RuleMatch[];\n}\n\nconst sessions = new WeakMap<Page, Promise<CDPSession>>();\n\n/** One DevTools session per page, with `DOM` and `CSS` enabled. */\nexport function cdpSession(page: Page): Promise<CDPSession> {\n let session = sessions.get(page);\n if (!session) {\n session = (async () => {\n const cdp = await page.context().newCDPSession(page);\n await cdp.send('DOM.enable');\n await cdp.send('CSS.enable');\n return cdp;\n })();\n sessions.set(page, session);\n }\n return session;\n}\n\nfunction onAxis(property: string, axis: string[]): boolean {\n return axis.some((name) => (name.endsWith('*') ? property.startsWith(name.slice(0, -1)) : property === name));\n}\n\n/** Authored declarations only: Chromium also lists each shorthand's longhands\n * without text, which would repeat every reference. */\nfunction authored(style: Style | undefined): Declaration[] {\n return (style?.cssProperties ?? []).filter((declaration) => declaration.text);\n}\n\nfunction regularRules(styles: ElementStyles): RuleMatch['rule'][] {\n return (styles.matchedCSSRules ?? []).filter(({ rule }) => rule.origin === 'regular').map(({ rule }) => rule);\n}\n\nfunction declarations(styles: ElementStyles): Declaration[] {\n return [authored(styles.inlineStyle), ...regularRules(styles).map((rule) => authored(rule.style))].flat();\n}\n\n/** One element's declarations from lowest to highest precedence: its rules\n * in cascade order, then its inline style. */\nfunction cascadeOrder(styles: ElementStyles): Declaration[] {\n return [...regularRules(styles).flatMap((rule) => authored(rule.style)), ...authored(styles.inlineStyle)];\n}\n\n/** The declaration of `name` that wins among `ordered`, or none. */\nfunction winning(ordered: Declaration[], name: string): Declaration | undefined {\n const all = ordered.filter((d) => d.name === name);\n // Chromium flags `important` on standard properties and leaves it in a custom property's value.\n return all.filter((d) => d.important || /!\\s*important\\s*$/i.test(d.value)).at(-1) ?? all.at(-1);\n}\n\nfunction ruleKey(rule: RuleMatch['rule']): string {\n return JSON.stringify([rule.styleSheetId, rule.selectorList.text, rule.style.range]);\n}\n\ntype Longhands = (names: string[]) => Promise<Map<string, string[]>>;\n\n/** The longhands each property sets, read from the page's CSSOM, so that\n * `outline` and `outline-color` count as the same property. */\nfunction longhandsIn(page: Page): Longhands {\n return async (names) => new Map(await page.evaluate((names) => names.map((name): [string, string[]] => {\n if (name.startsWith('--')) return [name, [name]];\n const style = document.createElement('div').style;\n style.setProperty(name, 'initial');\n return [name, style.length ? Array.from({ length: style.length }, (_, i) => style.item(i)) : [name]];\n }), names));\n}\n\n/**\n * The target's declarations under `forced` that the force brings in or\n * changes: every declaration of a rule that matches only under the force,\n * and every declaration of a later rule, or of the inline style, that sets a\n * property one of those rules sets. Rules that match in every state drop, so\n * a field's resting border and surface never name a focus finding.\n */\nasync function forcedDeclarations(plain: ElementStyles, forced: ElementStyles, longhands: Longhands): Promise<Declaration[]> {\n const before = new Set(regularRules(plain).map(ruleKey));\n const cascade = [\n ...regularRules(forced).map((rule) => ({ forcedOnly: !before.has(ruleKey(rule)), declarations: authored(rule.style) })),\n { forcedOnly: false, declarations: authored(forced.inlineStyle) },\n ];\n const expanded = await longhands([...new Set(cascade.flatMap((entry) => entry.declarations.map((d) => d.name)))]);\n const changed = new Set<string>();\n const kept: Declaration[] = [];\n for (const { forcedOnly, declarations } of cascade) {\n for (const d of declarations) {\n const sets = expanded.get(d.name) ?? [d.name];\n if (forcedOnly) sets.forEach((name) => changed.add(name));\n if (forcedOnly || sets.some((name) => changed.has(name))) kept.push(d);\n }\n }\n return kept;\n}\n\nfunction references(value: string): string[] {\n return [...value.matchAll(/var\\(\\s*(--[\\w-]+)/g)].map((match) => match[1]);\n}\n\n/** How many ancestors separate each element `selector` matches from the\n * nearest element `scope` matches, in document order, or -1 outside it. */\nfunction scopeDepths(page: Page, selector: string, scope: string): Promise<number[]> {\n return page.evaluate(({ selector, scope }) => [...document.querySelectorAll(selector)].map((element) => {\n let depth = 0;\n for (let node: Element | null = element; node; node = node.parentElement, depth++) {\n if (node.matches(scope)) return depth;\n }\n return -1;\n }), { selector, scope });\n}\n\nasync function matchedStyles(cdp: CDPSession, nodeId: number, force: string[] = [], forceNodeId = nodeId) {\n const forcePseudoState = (forcedPseudoClasses: string[]) => cdp.send('CSS.forcePseudoState', { nodeId: forceNodeId, forcedPseudoClasses });\n if (force.length === 0) return cdp.send('CSS.getMatchedStylesForNode', { nodeId });\n await forcePseudoState(force);\n return cdp.send('CSS.getMatchedStylesForNode', { nodeId }).finally(() => forcePseudoState([]));\n}\n\ninterface TraceNode {\n nodeId: number;\n depth: number;\n forceNodeId?: number;\n ancestorsFrom: number;\n}\n\nasync function traceNode(\n cdp: CDPSession,\n node: TraceNode,\n axes: TraceAxes,\n known: ReadonlySet<string>,\n longhands: Longhands,\n): Promise<string[]> {\n const matched = await matchedStyles(cdp, node.nodeId, axes.force, node.forceNodeId);\n const own = axes.force\n ? await forcedDeclarations(await matchedStyles(cdp, node.nodeId), matched, longhands)\n : declarations(matched);\n const pseudo = (matched.pseudoElements ?? []).flatMap(({ matches }) => declarations({ matchedCSSRules: matches }));\n const chain = (matched.inherited ?? []).slice(0, node.depth);\n\n // A reference resolves on the element whose declaration holds it: level 0\n // is the target, level n its nth ancestor, and PSEUDO its pseudo-elements.\n // Only the winning declaration of a private property counts there, so a\n // selected tab traces its selected binding and leaves the default one out.\n const PSEUDO = -1;\n const levels = [cascadeOrder(matched), ...chain.map(cascadeOrder)];\n const pseudoCustom = pseudo.filter((d) => d.name.startsWith('--'));\n const from = Math.max(node.ancestorsFrom - 1, 0);\n const pending: { name: string; level: number }[] = [\n ...own.filter((d) => onAxis(d.name, axes.target)).map((d) => ({ d, level: 0 })),\n ...pseudo.filter((d) => onAxis(d.name, axes.pseudoElements)).map((d) => ({ d, level: PSEUDO })),\n ...chain.slice(from).flatMap((entry, i) => declarations(entry)\n .filter((d) => onAxis(d.name, axes.ancestors))\n .map((d) => ({ d, level: from + i + 1 }))),\n ].flatMap(({ d, level }) => references(d.value).map((name) => ({ name, level })));\n\n const resolve = (name: string, level: number): { declarations: Declaration[]; level: number } => {\n if (level === PSEUDO) {\n const own = pseudoCustom.filter((d) => d.name === name);\n if (own.length > 0) return { declarations: own, level: PSEUDO };\n }\n for (let at = Math.max(level, 0); at < levels.length; at++) {\n const won = winning(levels[at], name);\n if (won) return { declarations: [won], level: at };\n }\n return { declarations: [], level };\n };\n\n const found = new Set<string>();\n const followed = new Set<string>();\n for (let next = pending.pop(); next !== undefined; next = pending.pop()) {\n const { name, level } = next;\n const key = `${name}@${level}`;\n if (known.has(name)) found.add(name);\n else if (!followed.has(key)) {\n followed.add(key);\n const resolved = resolve(name, level);\n for (const d of resolved.declarations) pending.push(...references(d.value).map((ref) => ({ name: ref, level: resolved.level })));\n }\n }\n return [...found];\n}\n\n/** The element a trace reads, inside `scope`. `forceOn`, when set, names the\n * element `axes.force` applies to, for a focus style drawn on another\n * element. `ancestorsFrom` is the nearest ancestor whose `axes.ancestors`\n * declarations count, 1 being the parent and the default. */\nexport interface TraceTarget {\n selector: string;\n scope: string;\n forceOn?: string;\n ancestorsFrom?: number;\n}\n\n/**\n * The component properties `axes` reads on the element `target.selector`\n * names inside `target.scope` (decisions 1 to 3): each matched declaration on\n * an axis, narrowed under `axes.force` to the ones the force brings in or\n * changes, its `var()` references followed through the winning declaration\n * of each private custom property on the target or an in-scope ancestor,\n * kept where a name is in `known`. Sorted and unique.\n */\nexport async function traceProperties(\n page: Page,\n target: TraceTarget,\n axes: TraceAxes,\n known: ReadonlySet<string>,\n): Promise<string[]> {\n let depths: number[];\n let forceDepths: number[] = [];\n try {\n depths = await scopeDepths(page, target.selector, target.scope);\n if (target.forceOn) forceDepths = await scopeDepths(page, target.forceOn, target.scope);\n } catch {\n // An Alfa label or an axe frame path need not parse as one selector.\n return [];\n }\n const cdp = await cdpSession(page);\n const { root } = await cdp.send('DOM.getDocument', { depth: 0 });\n const query = async (selector: string) => (await cdp.send('DOM.querySelectorAll', { nodeId: root.nodeId, selector })).nodeIds;\n const nodeIds = await query(target.selector);\n const forceNodeId = target.forceOn\n ? (await query(target.forceOn)).find((_, index) => forceDepths[index] >= 0)\n : undefined;\n if (target.forceOn && forceNodeId === undefined) return [];\n const longhands = longhandsIn(page);\n const found = new Set<string>();\n for (const [index, nodeId] of nodeIds.entries()) {\n if (depths[index] < 0) continue;\n const node = { nodeId, depth: depths[index], forceNodeId, ancestorsFrom: target.ancestorsFrom ?? 1 };\n for (const name of await traceNode(cdp, node, axes, known, longhands)) found.add(name);\n }\n return [...found].sort();\n}\n","import type { Page } from '@playwright/test';\nimport type { A11yResult } from './a11y';\nimport { cdpSession } from './traceProperties';\n\nexport const FOCUS_INDICATOR_RULE = 'focus-indicator-contrast';\nexport const BOUNDARY_RULE = 'control-boundary-contrast';\n\nconst NON_TEXT_URL = 'https://www.w3.org/WAI/WCAG22/Understanding/non-text-contrast.html';\nconst FOCUS_ATTR = 'data-lt-focus-probe';\nconst NO_TRANSITION_ID = 'lt-focus-probe-no-transition';\nconst FORCE = ['focus', 'focus-visible'];\n/** Marks a focusable whose focus ring the probe found on a sibling, which\n * SIA-R65 cannot see. `scanFocusVisible` reads it. */\nexport const SIBLING_FOCUS_ATTR = 'data-lt-focus-sibling';\n\n/** Where the trace reads a result's properties: `selector` names the element\n * that paints the colour, `forceOn` the element focus is forced on, and\n * `ancestorsFrom` the nearest ancestor (1 is the parent, 0 the element\n * itself) whose surface lies behind the measured edge. */\nexport interface TraceRequest {\n selector: string;\n forceOn?: string;\n ancestorsFrom?: number;\n}\n\nexport interface CheckedResult {\n result: A11yResult;\n trace: TraceRequest;\n}\n\n/** A part whose border, outline or surface draws a control's visible edge.\n * `when` narrows it to the elements that also match, such as a state class. */\nexport interface BoundaryPart {\n selector: string;\n label: string;\n when?: string;\n}\n\ntype Snapshot = string[];\n\ntype FocusOutcome =\n | { kind: 'none' | 'browser' | 'pass' }\n | {\n kind: 'fail' | 'review';\n channel: string;\n ratio?: number;\n target: string;\n indicator: string;\n html: string;\n ancestorsFrom: number;\n };\n\ntype BoundaryOutcome = {\n kind: 'fail' | 'review';\n label: string;\n target: string;\n html: string;\n edge: { channel: 'border' | 'outline'; ratio: number } | null;\n surface: number | null;\n ancestorsFrom: number;\n};\n\ntype PageRequest =\n | { kind: 'focusables'; scope: string; exclude: string[]; attr: string; styleId: string; marker: string }\n | { kind: 'snapshot'; attr: string; index: number; scope: string; exclude: string[] }\n | { kind: 'measure'; attr: string; index: number; scope: string; exclude: string[]; before: Snapshot; marker: string }\n | { kind: 'cleanup'; attr: string; styleId: string }\n | { kind: 'boundaries'; scope: string; exclude: string[]; parts: BoundaryPart[]; root: string }\n | { kind: 'describe'; scope: string; exclude: string[]; attr: string; values: string[] };\n\n/**\n * Runs in the page, so it carries every helper it needs. Colours resolve and\n * composite on a 1px canvas, which reads any CSS colour syntax the computed\n * style returns and blends alpha the way the page paints it.\n */\nfunction inPage(request: PageRequest): unknown {\n const scopes = [...document.querySelectorAll<HTMLElement>(('scope' in request && request.scope) || ':not(*)')];\n const excluded = (el: Element) => 'exclude' in request && request.exclude.some((selector) => el.closest(selector));\n const inScope = (el: Element) => scopes.some((scope) => scope.contains(el)) && !excluded(el);\n\n const canvas = document.createElement('canvas');\n canvas.width = canvas.height = 1;\n const ctx = canvas.getContext('2d', { willReadFrequently: true })!;\n const paint = (layers: string[]): number[] => {\n ctx.clearRect(0, 0, 1, 1);\n for (const layer of ['#fff', ...layers]) {\n ctx.fillStyle = 'transparent';\n ctx.fillStyle = layer;\n ctx.fillRect(0, 0, 1, 1);\n }\n return [...ctx.getImageData(0, 0, 1, 1).data.slice(0, 3)];\n };\n const alpha = (color: string): number => {\n ctx.clearRect(0, 0, 1, 1);\n ctx.fillStyle = 'transparent';\n ctx.fillStyle = color;\n ctx.fillRect(0, 0, 1, 1);\n return ctx.getImageData(0, 0, 1, 1).data[3] / 255;\n };\n const rgb = (channels: number[]) => `rgb(${channels.join(' ')})`;\n const luminance = (channels: number[]) => {\n const [r, g, b] = channels.map((c) => {\n const s = c / 255;\n return s <= 0.04045 ? s / 12.92 : ((s + 0.055) / 1.055) ** 2.4;\n });\n return 0.2126 * r + 0.7152 * g + 0.0722 * b;\n };\n const contrast = (a: number[], b: number[]) => {\n const [hi, lo] = [luminance(a), luminance(b)].sort((x, y) => y - x);\n return (hi + 0.05) / (lo + 0.05);\n };\n\n const selectorFor = (el: Element): string => {\n const count = (selector: string) => scopes.reduce((n, scope) => n + (scope.matches(selector) ? 1 : 0) + scope.querySelectorAll(selector).length, 0);\n const own = (e: Element) => e.tagName.toLowerCase()\n + [...e.classList].filter((name) => !name.startsWith('svelte-') && /^[\\w-]+$/.test(name)).map((name) => `.${name}`).join('');\n const path: string[] = [];\n for (let e: Element | null = el; e; e = e.parentElement) {\n const step = own(e);\n path.unshift(step);\n if (count(path.join(' > ')) === 1) break;\n const same = [...(e.parentElement?.children ?? [])].filter((c) => c.tagName === e!.tagName);\n if (same.length > 1) path[0] = `${step}:nth-of-type(${same.indexOf(e) + 1})`;\n if (count(path.join(' > ')) === 1 || scopes.includes(e as HTMLElement)) break;\n }\n return path.join(' > ');\n };\n\n /** The surfaces behind `ring`, from the nearest box that contains it up to\n * the first opaque one, composited over white. A gradient or image among\n * them leaves the colour unknown. Past a scope lie the editor's own\n * surfaces, so the walk ends there on `--page-bg`, which a real page puts\n * behind the component. A part that fills its preview edge to edge spills\n * its ring past the scope. */\n const backdrop = (from: Element, ring: DOMRect) => {\n const layers: string[] = [];\n let level = 0;\n let first = -1;\n for (let e: Element | null = from; e; e = e.parentElement, level++) {\n const box = e.getBoundingClientRect();\n const isScope = scopes.includes(e as HTMLElement);\n const contains = isScope || (box.left <= ring.left + 0.5 && box.top <= ring.top + 0.5\n && box.right >= ring.right - 0.5 && box.bottom >= ring.bottom - 0.5);\n if (!contains) continue;\n if (first < 0) first = level;\n const style = getComputedStyle(e);\n if (style.backgroundImage !== 'none') return { color: null, first };\n const a = alpha(style.backgroundColor);\n if (a > 0) layers.unshift(style.backgroundColor);\n if (a >= 1) break;\n if (isScope) {\n const page = getComputedStyle(document.documentElement).getPropertyValue('--page-bg').trim();\n if (/gradient|url\\(/.test(page)) return { color: null, first };\n if (page) layers.unshift(page);\n break;\n }\n }\n return { color: paint(layers), first: Math.max(first, 0) };\n };\n const inflate = (box: DOMRect, by: number) => new DOMRect(box.x - by, box.y - by, box.width + 2 * by, box.height + 2 * by);\n const px = (value: string) => parseFloat(value) || 0;\n const html = (el: Element) => el.outerHTML.replace(/\\s+/g, ' ').slice(0, 300);\n\n const SIDES = ['Top', 'Right', 'Bottom', 'Left'] as const;\n const visibleSide = (style: CSSStyleDeclaration, side: string) => {\n const s = style as unknown as Record<string, string>;\n return !['none', 'hidden'].includes(s[`border${side}Style`]) && px(s[`border${side}Width`]) >= 0.99\n ? s[`border${side}Color`] : null;\n };\n\n const candidates = (target: Element): Element[] => {\n const list = [target, ...target.querySelectorAll('*')];\n for (const sibling of target.parentElement?.children ?? []) {\n if (sibling !== target) list.push(sibling, ...sibling.querySelectorAll('*'));\n }\n return list.filter(inScope);\n };\n const signature = (el: Element) => {\n const s = getComputedStyle(el);\n return JSON.stringify([\n [s.outlineStyle, s.outlineWidth, s.outlineColor, s.outlineOffset],\n s.boxShadow,\n SIDES.map((side) => visibleSide(s, side)),\n ]);\n };\n\n /** The colour focus brings in on `el`, by decision 8's order: an outline,\n * else the first outer box shadow, else a border. A channel focus leaves\n * alone, or paints fully transparent, is no indicator. */\n const indicatorOf = (el: Element, before: string) => {\n const [outlineBefore, shadowBefore, bordersBefore] = JSON.parse(before);\n const s = getComputedStyle(el);\n const outline = [s.outlineStyle, s.outlineWidth, s.outlineColor, s.outlineOffset];\n if (JSON.stringify(outline) !== JSON.stringify(outlineBefore) && s.outlineStyle !== 'none' && px(s.outlineWidth) > 0) {\n if (s.outlineStyle === 'auto') return { channel: 'browser', color: '', extent: 0 };\n if (alpha(s.outlineColor) > 0) return { channel: 'outline', color: s.outlineColor, extent: px(s.outlineOffset) + px(s.outlineWidth) };\n }\n if (s.boxShadow !== shadowBefore && s.boxShadow !== 'none') {\n const shadows = s.boxShadow.split(/,(?![^(]*\\))/).map((part) => part.trim());\n for (const shadow of shadows) {\n if (/\\binset\\b/.test(shadow)) continue;\n const color = /^(?:[a-z-]+\\([^)]*\\)|#[\\da-f]+|[a-z]+)/i.exec(shadow)?.[0] ?? '';\n if (!color || alpha(color) === 0) continue;\n const [x = 0, y = 0, blur = 0, spread = 0] = (shadow.slice(color.length).match(/-?[\\d.]+px/g) ?? []).map(px);\n return { channel: 'shadow', color, extent: Math.max(Math.abs(x), Math.abs(y)) + blur + spread };\n }\n }\n const borders = SIDES.map((side) => visibleSide(s, side));\n for (const [i, color] of borders.entries()) {\n if (color && color !== bordersBefore[i] && alpha(color) > 0) return { channel: 'border', color, extent: 0 };\n }\n return null;\n };\n\n switch (request.kind) {\n case 'focusables': {\n // A focus transition would leave the computed colour at its start.\n const style = document.createElement('style');\n style.id = request.styleId;\n style.textContent = '*, *::before, *::after { transition: none !important; }';\n document.head.append(style);\n for (const el of document.querySelectorAll(`[${request.marker}]`)) el.removeAttribute(request.marker);\n const focusable = 'a[href], area[href], button, input:not([type=\"hidden\"]), select, textarea, summary, iframe, [tabindex], [contenteditable]:not([contenteditable=\"false\"])';\n const found = scopes.flatMap((scope) => [scope, ...scope.querySelectorAll(focusable)])\n .filter((el, i, all) => all.indexOf(el) === i && el.matches(focusable) && inScope(el))\n .filter((el) => (el as HTMLElement).tabIndex >= 0 && !el.matches(':disabled') && el.checkVisibility({ visibilityProperty: true }));\n found.forEach((el, i) => el.setAttribute(request.attr, String(i)));\n return found.length;\n }\n case 'snapshot': {\n const target = document.querySelector(`[${request.attr}=\"${request.index}\"]`)!;\n return candidates(target).map(signature);\n }\n case 'measure': {\n const target = document.querySelector(`[${request.attr}=\"${request.index}\"]`)!;\n const list = candidates(target);\n for (const [i, el] of list.entries()) {\n if (request.before[i] === undefined || request.before[i] === signature(el)) continue;\n const found = indicatorOf(el, request.before[i]);\n if (!found) continue;\n if (el !== target && !target.contains(el)) target.setAttribute(request.marker, '');\n if (found.channel === 'browser') return { kind: 'browser' };\n const ring = inflate(el.getBoundingClientRect(), Math.max(found.extent, 0));\n const behind = backdrop(found.channel === 'border' ? el.parentElement! : el, found.extent < 0 ? el.getBoundingClientRect() : ring);\n const offset = found.channel === 'border' ? 1 : 0;\n const common = {\n channel: found.channel,\n target: selectorFor(target),\n indicator: selectorFor(el),\n html: html(target),\n ancestorsFrom: behind.first + offset,\n };\n if (!behind.color) return { kind: 'review', ...common };\n const ratio = contrast(paint([rgb(behind.color), found.color]), behind.color);\n return ratio < 3 ? { kind: 'fail', ratio, ...common } : { kind: 'pass' };\n }\n return { kind: 'none' };\n }\n case 'cleanup': {\n document.getElementById(request.styleId)?.remove();\n for (const el of document.querySelectorAll(`[${request.attr}]`)) el.removeAttribute(request.attr);\n return null;\n }\n case 'boundaries': {\n const outcomes: BoundaryOutcome[] = [];\n const control = 'button, input, select, textarea, [aria-disabled]';\n const inactive = (el: Element) => {\n const root = el.closest(request.root) ?? el;\n const controls = [root, ...root.querySelectorAll(control)].filter((c) => c.matches(control));\n return controls.length > 0 && controls.every((c) => c.matches(':disabled') || c.getAttribute('aria-disabled') === 'true');\n };\n for (const part of request.parts) {\n const elements = scopes.flatMap((scope) => [scope, ...scope.querySelectorAll(part.selector)])\n .filter((el, i, all) => all.indexOf(el) === i && el.matches(part.selector) && inScope(el))\n .filter((el) => !part.when || el.matches(part.when))\n .filter((el) => el.checkVisibility({ visibilityProperty: true }) && el.getBoundingClientRect().width > 0 && !inactive(el));\n for (const el of elements) {\n const style = getComputedStyle(el);\n const behind = backdrop(el.parentElement!, el.getBoundingClientRect());\n const common = { label: part.label, target: selectorFor(el), html: html(el), ancestorsFrom: behind.first + 1 };\n if (!behind.color) {\n outcomes.push({ kind: 'review', edge: null, surface: null, ...common });\n continue;\n }\n const surfaceColor = paint([rgb(behind.color), style.backgroundColor]);\n const surface = style.backgroundImage === 'none' ? contrast(surfaceColor, behind.color) : null;\n // A state indicator may draw one side, as TabBar's underline does, or\n // an inset outline, as SegmentedControl's selected option does.\n const edges: { channel: 'border' | 'outline'; color: string; under: number[] }[] = [];\n const borderUnder = style.backgroundClip === 'border-box' ? surfaceColor : behind.color;\n for (const side of SIDES) {\n const color = visibleSide(style, side);\n if (color) edges.push({ channel: 'border', color, under: borderUnder });\n }\n if (!['none', 'auto'].includes(style.outlineStyle) && px(style.outlineWidth) >= 0.99) {\n edges.push({ channel: 'outline', color: style.outlineColor, under: px(style.outlineOffset) < 0 ? surfaceColor : behind.color });\n }\n const edge = edges\n .map(({ channel, color, under }) => ({ channel, ratio: contrast(paint([rgb(under), color]), behind.color) }))\n .reduce<BoundaryOutcome['edge']>((best, next) => (best && best.ratio >= next.ratio ? best : next), null);\n if ((edge?.ratio ?? 0) >= 3 || (surface ?? 0) >= 3) continue;\n outcomes.push({ kind: surface === null ? 'review' : 'fail', edge, surface, ...common });\n }\n }\n return outcomes;\n }\n case 'describe': {\n return request.values.map((value) => {\n const el = document.querySelector(`[${request.attr}=\"${value}\"]`)!;\n return { target: selectorFor(el), html: html(el) };\n });\n }\n }\n}\n\nfunction run<T>(page: Page, request: PageRequest): Promise<T> {\n return page.evaluate(inPage, request) as Promise<T>;\n}\n\n/** The selector and markup a result names for each element in `scope` whose\n * `attr` holds one of `values`, in that order. The selector is unique in\n * `scope`, which the trace needs. */\nexport function describeTagged(\n page: Page,\n scope: string,\n exclude: string[],\n attr: string,\n values: string[],\n): Promise<{ target: string; html: string }[]> {\n return run(page, { kind: 'describe', scope, exclude, attr, values });\n}\n\n/** Below 3:1 fails; WCAG does not round, so neither does the reading. */\nfunction ratioText(ratio: number): string {\n return `${Math.floor(ratio * 100) / 100}:1`;\n}\n\n/**\n * Decision 8: focus forced on each focusable element in `scope`, the colour\n * it brings in measured against the surfaces behind it. The indicator is the\n * first of the element, its descendants and its siblings whose outline, box\n * shadow or border focus changes, so a ring drawn on a sibling, as Slider\n * draws it, counts. Chromium's own `auto` ring pairs a dark and a light band,\n * one of which contrasts with any backdrop, so it passes. An element focus\n * leaves unchanged is SIA-R65's finding and adds none here. A ring found on\n * a sibling marks the focused element with `SIBLING_FOCUS_ATTR` until the\n * next scan, which settles SIA-R65's \"can't tell\" on it.\n */\nexport async function scanFocusIndicators(page: Page, scope: string, exclude: string[]): Promise<CheckedResult[]> {\n const cdp = await cdpSession(page);\n const count = await run<number>(page, { kind: 'focusables', scope, exclude, attr: FOCUS_ATTR, styleId: NO_TRANSITION_ID, marker: SIBLING_FOCUS_ATTR });\n const checked: CheckedResult[] = [];\n try {\n const { root } = await cdp.send('DOM.getDocument', { depth: 0 });\n for (let index = 0; index < count; index++) {\n const { nodeId } = await cdp.send('DOM.querySelector', { nodeId: root.nodeId, selector: `[${FOCUS_ATTR}=\"${index}\"]` });\n const before = await run<Snapshot>(page, { kind: 'snapshot', attr: FOCUS_ATTR, index, scope, exclude });\n await cdp.send('CSS.forcePseudoState', { nodeId, forcedPseudoClasses: FORCE });\n let outcome: FocusOutcome;\n try {\n outcome = await run<FocusOutcome>(page, { kind: 'measure', attr: FOCUS_ATTR, index, scope, exclude, before, marker: SIBLING_FOCUS_ATTR });\n } finally {\n await cdp.send('CSS.forcePseudoState', { nodeId, forcedPseudoClasses: [] });\n }\n if (outcome.kind !== 'fail' && outcome.kind !== 'review') continue;\n const where = outcome.indicator === outcome.target ? '' : ` on ${outcome.indicator}`;\n checked.push({\n result: {\n rule: outcome.kind === 'fail' ? 'a11y-component' : 'a11y-review',\n engineRule: FOCUS_INDICATOR_RULE,\n impact: null,\n target: outcome.target,\n html: outcome.html,\n help: outcome.kind === 'fail'\n ? `Focus ${outcome.channel}${where} ${ratioText(outcome.ratio!)} against the backdrop, needs 3:1`\n : `Focus ${outcome.channel}${where} sits over a gradient or image. Check by eye that it contrasts 3:1 with the backdrop`,\n helpUrl: NON_TEXT_URL,\n },\n trace: { selector: outcome.indicator, forceOn: outcome.target, ancestorsFrom: outcome.ancestorsFrom },\n });\n }\n } finally {\n await run(page, { kind: 'cleanup', attr: FOCUS_ATTR, styleId: NO_TRANSITION_ID });\n }\n return checked;\n}\n\n/**\n * Decision 9: each visible element of each boundary part in `scope` passes\n * when its best border side or outline, 1px or wider, or its surface\n * contrasts 3:1 with the surfaces behind it. A part of a control whose every\n * form control is disabled is inactive, which SC 1.4.11 exempts. `root` names\n * the component's root part, the extent of the control.\n */\nexport async function scanBoundaries(\n page: Page,\n scope: string,\n exclude: string[],\n parts: BoundaryPart[],\n root: string,\n): Promise<CheckedResult[]> {\n if (parts.length === 0) return [];\n const outcomes = await run<BoundaryOutcome[]>(page, { kind: 'boundaries', scope, exclude, parts, root });\n return outcomes.map((outcome) => {\n const edge = outcome.edge === null ? 'no border' : `${outcome.edge.channel} ${ratioText(outcome.edge.ratio)}`;\n return {\n result: {\n rule: outcome.kind === 'fail' ? 'a11y-component' : 'a11y-review',\n engineRule: BOUNDARY_RULE,\n impact: null,\n target: outcome.target,\n html: outcome.html,\n help: outcome.kind === 'fail'\n ? `${outcome.label} ${edge} and surface ${ratioText(outcome.surface!)} against the backdrop, needs 3:1`\n : `${outcome.label} sits on or carries a gradient or image. Check by eye that its edge contrasts 3:1 with the backdrop`,\n helpUrl: NON_TEXT_URL,\n },\n trace: { selector: outcome.target, ancestorsFrom: outcome.ancestorsFrom },\n };\n });\n}\n","import { test, type Page } from '@playwright/test';\nimport { SIBLING_FOCUS_ATTR } from './nonTextContrast';\n\nexport type A11yRule =\n | 'a11y-component'\n | 'a11y-page'\n | 'a11y-review'\n | 'a11y-focus-visible'\n | 'a11y-text-spacing'\n | 'a11y-reduced-motion'\n | 'a11y-keyboard';\n\n/** One element one engine flagged. `line` is the page file line, which only\n * the page suite can resolve; a component finding anchors on its runtime.\n * `view` names the variants, states, and themes the element failed in.\n * `variables` names the component properties the result traced to. */\nexport interface A11yResult {\n rule: A11yRule;\n engineRule: string;\n impact: string | null;\n target: string;\n html: string;\n help: string;\n helpUrl: string;\n line?: number;\n view?: string;\n variables?: string[];\n}\n\nconst A11Y_ANNOTATION = 'a11y';\n\nexport type A11yEngine = 'axe' | 'alfa';\n\nconst AXE_TAGS = ['wcag2a', 'wcag2aa', 'wcag21aa', 'wcag22aa'];\nconst SCOPE_ATTR = 'data-lt-a11y-scope';\nconst EXCLUDE_ATTR = 'data-lt-a11y-exclude';\nconst HTML_LIMIT = 300;\n\nclass EngineMissing extends Error {}\n\nexport async function importEngine<T>(packageName: string, load: () => Promise<T>): Promise<T> {\n try {\n return await load();\n } catch (error) {\n if ((error as { code?: string }).code === 'ERR_MODULE_NOT_FOUND') throw new EngineMissing(`${packageName} is not installed`);\n throw error;\n }\n}\n\nlet axeModules: ReturnType<typeof importAxe> | null = null;\nasync function importAxe() {\n await importEngine('axe-core', () => import('axe-core'));\n const { AxeBuilder } = await importEngine('@axe-core/playwright', () => import('@axe-core/playwright'));\n return { AxeBuilder };\n}\nconst loadAxe = () => (axeModules ??= importAxe());\n\nlet alfaModules: ReturnType<typeof importAlfa> | null = null;\nasync function importAlfa() {\n const { Audit, Outcome } = await importEngine('@siteimprove/alfa-act', () => import('@siteimprove/alfa-act'));\n const { Rules } = await importEngine('@siteimprove/alfa-rules', () => import('@siteimprove/alfa-rules'));\n const { Node } = await importEngine('@siteimprove/alfa-dom', () => import('@siteimprove/alfa-dom'));\n const { Native: DomNative } = await importEngine('@siteimprove/alfa-dom', () => import('@siteimprove/alfa-dom/native'));\n const { Device } = await importEngine('@siteimprove/alfa-device', () => import('@siteimprove/alfa-device'));\n const { Native: DeviceNative } = await importEngine('@siteimprove/alfa-device', () => import('@siteimprove/alfa-device/native'));\n const { Page: AlfaPage } = await importEngine('@siteimprove/alfa-web', () => import('@siteimprove/alfa-web'));\n const http = await importEngine('@siteimprove/alfa-http', () => import('@siteimprove/alfa-http'));\n const { URL } = await importEngine('@siteimprove/alfa-url', () => import('@siteimprove/alfa-url'));\n return {\n Audit, Outcome, R65: Rules.get('R65').getUnsafe(), Node, DomNative, Device, DeviceNative, AlfaPage, http, URL,\n };\n}\nconst loadAlfa = () => (alfaModules ??= importAlfa());\n\n/** The reason to annotate a test `inapplicable` with when one of `engines`\n * cannot load, or null when all of them load. */\nexport async function missingEngine(engines: A11yEngine[]): Promise<string | null> {\n try {\n for (const name of engines) await (name === 'axe' ? loadAxe() : loadAlfa());\n return null;\n } catch (error) {\n if (error instanceof EngineMissing) return error.message;\n throw error;\n }\n}\n\ninterface AxeNode {\n target: unknown[];\n html: string;\n impact?: string | null;\n any: { message: string }[];\n all: { message: string }[];\n none: { message: string }[];\n}\n\ninterface AxeRuleResult {\n id: string;\n impact?: string | null;\n help: string;\n helpUrl: string;\n nodes: AxeNode[];\n}\n\nfunction axeResults(rule: A11yRule, results: AxeRuleResult[], withReasons: boolean): A11yResult[] {\n return results.flatMap((result) =>\n result.nodes.map((node) => {\n const reasons = withReasons\n ? [...new Set([...node.any, ...node.all, ...node.none].map((check) => check.message).filter(Boolean))]\n : [];\n return {\n rule,\n engineRule: result.id,\n impact: node.impact ?? result.impact ?? null,\n target: node.target.map((part) => (Array.isArray(part) ? part.join(' >>> ') : String(part))).join(' | '),\n html: node.html.slice(0, HTML_LIMIT),\n help: [result.help, ...reasons].join('. '),\n helpUrl: result.helpUrl,\n };\n }),\n );\n}\n\n/** axe over `scope` (a selector), minus `exclude`. Violations report under\n * `rule`, and the results axe cannot decide under `a11y-review`. A page scan\n * leaves contrast to `page-contrast` (decision 8). `only` narrows the scan\n * from the WCAG tags to the axe rules it names. */\nexport async function scanAxe(\n page: Page,\n scope: string,\n exclude: string[],\n rule: 'a11y-component' | 'a11y-page',\n only?: string[],\n): Promise<A11yResult[]> {\n const { AxeBuilder } = await loadAxe();\n let builder = new AxeBuilder({ page }).include(scope);\n builder = only ? builder.withRules(only) : builder.withTags(AXE_TAGS);\n for (const selector of exclude) builder = builder.exclude(selector);\n if (rule === 'a11y-page') builder = builder.disableRules(['color-contrast']);\n const result = await builder.analyze();\n return [\n ...axeResults(rule, result.violations as AxeRuleResult[], false),\n ...axeResults('a11y-review', result.incomplete as AxeRuleResult[], true),\n ];\n}\n\ninterface SerialNode {\n type: string;\n name?: string;\n attributes?: { name: string }[];\n children?: SerialNode[];\n}\n\n/** Keeps the head, every scope's ancestor chain, and each scope's subtree\n * whole. The style sheets travel on the document node, so the cascade stays\n * intact, and SIA-R65 skips the editor's own controls: 0.3 to 0.8 s a scan\n * against 2.5 s for the whole document, with the same outcomes. */\nfunction pruneToScope(node: SerialNode): boolean {\n if (node.type === 'element' && node.attributes?.some((a) => a.name === SCOPE_ATTR)) return true;\n if (!node.children) return false;\n if (node.type === 'element' && node.name === 'head') return true;\n node.children = node.children.filter((child) => child.type === 'type' || pruneToScope(child));\n return node.type === 'document' || node.children.some((child) => child.type === 'element');\n}\n\nconst FOCUS_HELP = {\n failed: 'Focusing the element changes nothing visible',\n cantTell: 'Focusing the element changes no style on it, its descendants, or its ancestors',\n};\n\n/** Alfa's SIA-R65 over `scope` (a selector), minus `exclude`. A cantTell\n * outcome means Alfa found no focus style at all, so it reports beside a\n * failure under `a11y-focus-visible`, unless `scanFocusIndicators` found the\n * element's ring on a sibling, where Alfa does not look. */\nexport async function scanFocusVisible(page: Page, scope: string, exclude: string[]): Promise<A11yResult[]> {\n const alfa = await loadAlfa();\n await page.evaluate(({ scope, exclude, scopeAttr, excludeAttr }) => {\n for (const element of document.querySelectorAll(scope)) element.setAttribute(scopeAttr, '');\n for (const selector of exclude) {\n for (const element of document.querySelectorAll(selector)) element.setAttribute(excludeAttr, '');\n }\n }, { scope, exclude, scopeAttr: SCOPE_ATTR, excludeAttr: EXCLUDE_ATTR });\n let json: SerialNode;\n try {\n const handle = await page.evaluateHandle(() => document);\n json = (await handle.evaluate(alfa.DomNative.fromNode as (node: Document) => Promise<unknown>)) as SerialNode;\n await handle.dispose();\n } finally {\n await page.evaluate((attrs) => {\n for (const attr of attrs) for (const element of document.querySelectorAll(`[${attr}]`)) element.removeAttribute(attr);\n }, [SCOPE_ATTR, EXCLUDE_ATTR]);\n }\n pruneToScope(json);\n\n const fromWindow = alfa.DeviceNative.fromWindow as () => ReturnType<typeof alfa.DeviceNative.fromWindow>;\n const device = alfa.Device.from(await page.evaluate(fromWindow));\n const url = alfa.URL.parse(page.url()).getUnsafe();\n const { Request, Response, Headers, Header } = alfa.http;\n const alfaPage = alfa.AlfaPage.of(\n Request.of('GET', url),\n Response.of(url, 200, Headers.of([Header.of('Content-Type', 'text/html')])),\n alfa.Node.from(json as Parameters<typeof alfa.Node.from>[0], device) as Parameters<typeof alfa.AlfaPage.of>[2],\n device,\n );\n\n const results: A11yResult[] = [];\n for (const outcome of await alfa.Audit.of(alfaPage, [alfa.R65]).evaluate()) {\n const kind = alfa.Outcome.isFailed(outcome) ? 'failed' : alfa.Outcome.isCantTell(outcome) ? 'cantTell' : null;\n if (!kind) continue;\n const target = outcome.target as unknown as AlfaElement;\n if (!inScope(target)) continue;\n if (kind === 'cantTell' && target.attribute?.(SIBLING_FOCUS_ATTR).isSome()) continue;\n results.push({\n rule: 'a11y-focus-visible',\n engineRule: 'SIA-R65',\n impact: null,\n target: elementLabel(target),\n html: target.toString().replace(/\\s+/g, ' ').slice(0, HTML_LIMIT),\n help: FOCUS_HELP[kind],\n helpUrl: alfa.R65.uri,\n });\n }\n return results;\n}\n\ninterface AlfaElement {\n name: string;\n classes: Iterable<string>;\n id: { isSome(): boolean; get(): string };\n attribute?: (name: string) => { isSome(): boolean };\n inclusiveAncestors(): Iterable<AlfaElement>;\n toString(): string;\n}\n\nfunction inScope(target: AlfaElement): boolean {\n for (const node of target.inclusiveAncestors()) {\n if (typeof node.attribute !== 'function') continue;\n if (node.attribute(EXCLUDE_ATTR).isSome()) return false;\n if (node.attribute(SCOPE_ATTR).isSome()) return true;\n }\n return false;\n}\n\nfunction elementLabel(target: AlfaElement): string {\n const id = target.id.isSome() ? `#${target.id.get()}` : '';\n return `${target.name}${id}${[...target.classes].map((name) => `.${name}`).join('')}`;\n}\n\n/** Records `results` on the running test as the annotation the runner turns\n * into findings (decision 3). The test itself passes. */\nexport function recordA11y(results: A11yResult[]): void {\n if (results.length === 0) return;\n test.info().annotations.push({ type: A11Y_ANNOTATION, description: JSON.stringify(results) });\n}\n"],"mappings":"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","names":["names","declarations","selector","scope","own","inScope","scope","exclude"]}