@motion-proto/live-tokens 0.96.0 → 0.98.2

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 (206) hide show
  1. package/.claude/skills/live-tokens-check-compliance/SKILL.md +5 -0
  2. package/.claude/skills/live-tokens-create-component/SKILL.md +4 -3
  3. package/.claude/skills/live-tokens-create-component/references/contract-tests.md +71 -11
  4. package/CHANGELOG.md +309 -0
  5. package/README.md +2 -2
  6. package/bin/check-component.mjs +8 -0
  7. package/bin/check-page.mjs +6 -0
  8. package/bin/cli.mjs +36 -6
  9. package/bin/contractRunner.mjs +142 -17
  10. package/bin/lib/findings.mjs +20 -4
  11. package/bin/rules/a11y.mjs +53 -0
  12. package/bin/set-colors.mjs +1 -0
  13. package/bin/setup-claude.mjs +2 -2
  14. package/dist-plugin/{chunk-A4TBP4MM.js → chunk-SLICH4IH.js} +2 -2
  15. package/dist-plugin/index.cjs +148 -3
  16. package/dist-plugin/index.js +250 -105
  17. package/dist-plugin/setColors/index.cjs +7 -1
  18. package/dist-plugin/setColors/index.d.cts +9 -4
  19. package/dist-plugin/setColors/index.d.ts +9 -4
  20. package/dist-plugin/setColors/index.js +8 -2
  21. package/dist-plugin/setGeometry/index.d.cts +1 -1
  22. package/dist-plugin/setGeometry/index.d.ts +1 -1
  23. package/dist-plugin/setType/index.d.cts +1 -1
  24. package/dist-plugin/setType/index.d.ts +1 -1
  25. package/dist-plugin/{themeTypes-B8_Idrp4.d.cts → themeTypes-BaTQUyac.d.cts} +10 -1
  26. package/dist-plugin/{themeTypes-B8_Idrp4.d.ts → themeTypes-BaTQUyac.d.ts} +10 -1
  27. package/package.json +49 -2
  28. package/src/demo/LabeledSelect.svelte +1 -1
  29. package/src/editor/bootstrap.ts +3 -1
  30. package/src/editor/component-editor/BadgeEditor.svelte +13 -0
  31. package/src/editor/component-editor/ButtonEditor.svelte +33 -2
  32. package/src/editor/component-editor/CalloutEditor.svelte +13 -0
  33. package/src/editor/component-editor/CardEditor.svelte +12 -2
  34. package/src/editor/component-editor/CodeSnippetEditor.svelte +11 -1
  35. package/src/editor/component-editor/CollapsibleSectionEditor.svelte +18 -1
  36. package/src/editor/component-editor/CornerBadgeEditor.svelte +13 -0
  37. package/src/editor/component-editor/DialogEditor.svelte +15 -0
  38. package/src/editor/component-editor/IconButtonEditor.svelte +29 -1
  39. package/src/editor/component-editor/ImageEditor.svelte +20 -9
  40. package/src/editor/component-editor/ImageLightboxEditor.svelte +44 -0
  41. package/src/editor/component-editor/InlineEditActionsEditor.svelte +13 -1
  42. package/src/editor/component-editor/InputEditor.svelte +23 -0
  43. package/src/editor/component-editor/MenuSelectEditor.svelte +27 -1
  44. package/src/editor/component-editor/NotificationEditor.svelte +15 -0
  45. package/src/editor/component-editor/PanelEditor.svelte +1 -1
  46. package/src/editor/component-editor/ProgressBarEditor.svelte +13 -0
  47. package/src/editor/component-editor/RadioButtonEditor.svelte +20 -1
  48. package/src/editor/component-editor/SectionDividerEditor.svelte +41 -13
  49. package/src/editor/component-editor/SegmentedControlEditor.svelte +29 -1
  50. package/src/editor/component-editor/SideNavigationEditor.svelte +40 -1
  51. package/src/editor/component-editor/SlidePagerEditor.svelte +20 -0
  52. package/src/editor/component-editor/SliderEditor.svelte +33 -0
  53. package/src/editor/component-editor/TabBarEditor.svelte +23 -2
  54. package/src/editor/component-editor/TableEditor.svelte +14 -0
  55. package/src/editor/component-editor/ToggleEditor.svelte +17 -0
  56. package/src/editor/component-editor/TooltipEditor.svelte +11 -2
  57. package/src/editor/component-editor/VideoFrameEditor.svelte +8 -0
  58. package/src/editor/component-editor/VideoLightboxEditor.svelte +10 -0
  59. package/src/editor/component-editor/registration.ts +2 -1
  60. package/src/editor/component-editor/registry.ts +69 -27
  61. package/src/editor/component-editor/scaffolding/DemoHeader.svelte +2 -0
  62. package/src/editor/component-editor/scaffolding/StateBlock.svelte +19 -8
  63. package/src/editor/component-editor/scaffolding/TokenLayout.svelte +3 -0
  64. package/src/editor/component-editor/scaffolding/VariantGroup.svelte +70 -10
  65. package/src/editor/component-editor/scaffolding/editorContext.ts +7 -0
  66. package/src/editor/core/a11y/a11yReport.ts +101 -0
  67. package/src/editor/core/a11y/a11yReportTypes.ts +69 -0
  68. package/src/editor/core/a11y/contrastFailures.ts +22 -0
  69. package/src/editor/core/components/contrastPairRegistry.ts +18 -0
  70. package/src/editor/core/palettes/contrast.ts +44 -0
  71. package/src/editor/core/palettes/contrastPairs.ts +79 -0
  72. package/src/editor/core/palettes/resolveColor.ts +77 -0
  73. package/src/editor/core/store/editorPersistence.ts +9 -1
  74. package/src/editor/core/store/editorRenderer.ts +2 -0
  75. package/src/editor/core/store/editorStore.ts +29 -0
  76. package/src/editor/core/store/editorTypes.ts +9 -0
  77. package/src/editor/core/store/editorViewStore.ts +2 -2
  78. package/src/editor/core/store/unsavedEdits.ts +10 -0
  79. package/src/editor/core/themes/buildColors.ts +16 -5
  80. package/src/editor/core/themes/liveStateStream.ts +7 -1
  81. package/src/editor/core/themes/parsers/gradient.ts +5 -2
  82. package/src/editor/core/themes/slices/customColors.ts +226 -0
  83. package/src/editor/core/themes/themeTypes.ts +10 -0
  84. package/src/editor/docs/chapters.ts +1 -0
  85. package/src/editor/docs/content/accessibility.md +362 -0
  86. package/src/editor/docs/content/editing-tokens.md +56 -1
  87. package/src/editor/docs/content.generated.ts +2 -1
  88. package/src/editor/pages/ComponentEditorPage.svelte +10 -1
  89. package/src/editor/pages/EditorShell.svelte +97 -10
  90. package/src/editor/skill-atlas/skillSources.generated.ts +3 -3
  91. package/src/editor/skill-atlas/trees/check-compliance.ts +3 -3
  92. package/src/editor/skill-atlas/trees/create-component.ts +12 -12
  93. package/src/editor/ui/CustomColorReplaceStep.svelte +118 -0
  94. package/src/editor/ui/EditorViewSwitcher.svelte +15 -2
  95. package/src/editor/ui/GradientEditor.svelte +9 -1
  96. package/src/editor/ui/ThemePanel.svelte +4 -4
  97. package/src/editor/ui/UIContrastReadout.svelte +186 -0
  98. package/src/editor/ui/UIInfoPopover.svelte +16 -2
  99. package/src/editor/ui/UIPaletteSelector.svelte +347 -15
  100. package/src/editor/ui/UITokenSelector.svelte +33 -14
  101. package/src/editor/ui/VariablesTab.svelte +3 -0
  102. package/src/editor/ui/a11y/A11yComponentIssues.svelte +103 -0
  103. package/src/editor/ui/a11y/A11yFindingRow.svelte +57 -0
  104. package/src/editor/ui/a11y/A11yIssueRow.svelte +121 -0
  105. package/src/editor/ui/a11y/A11yOverview.svelte +242 -0
  106. package/src/editor/ui/a11y/A11yPanel.svelte +128 -0
  107. package/src/editor/ui/a11y/A11yPropertyMark.svelte +84 -0
  108. package/src/editor/ui/a11y/A11yRailMark.svelte +34 -0
  109. package/src/editor/ui/a11y/AccessibilityTab.svelte +334 -0
  110. package/src/editor/ui/a11y/a11yView.ts +218 -0
  111. package/src/editor/ui/anchorToTrigger.ts +63 -0
  112. package/src/editor/ui/contrastReadout.ts +45 -0
  113. package/src/editor/ui/sections/CustomColorsSection.svelte +254 -0
  114. package/src/live-tokens/data/themes/autumn.json +20 -20
  115. package/src/live-tokens/data/themes/halloween.json +20 -20
  116. package/src/live-tokens/data/themes/midnight-study.json +20 -20
  117. package/src/live-tokens/data/themes/ocean.json +20 -20
  118. package/src/live-tokens/data/themes/royal-velvet.json +20 -20
  119. package/src/live-tokens/data/themes/sketchy.json +20 -20
  120. package/src/live-tokens/data/themes/spring-meadow.json +20 -20
  121. package/src/live-tokens/data/themes/sunset.json +20 -20
  122. package/src/system/components/Badge.svelte +3 -3
  123. package/src/system/components/Button.svelte +9 -3
  124. package/src/system/components/CodeSnippet.svelte +8 -1
  125. package/src/system/components/CornerBadge.svelte +3 -3
  126. package/src/system/components/Dialog.svelte +43 -14
  127. package/src/system/components/IconButton.svelte +1 -1
  128. package/src/system/components/Image.svelte +7 -0
  129. package/src/system/components/ImageLightbox.svelte +26 -26
  130. package/src/system/components/Input.svelte +8 -1
  131. package/src/system/components/MenuSelect.svelte +30 -2
  132. package/src/system/components/Notification.svelte +1 -1
  133. package/src/system/components/ProgressBar.svelte +6 -0
  134. package/src/system/components/RadioButton.svelte +36 -3
  135. package/src/system/components/SegmentedControl.svelte +36 -2
  136. package/src/system/components/SlidePager.svelte +2 -2
  137. package/src/system/components/Slider.svelte +13 -9
  138. package/src/system/components/TabBar.svelte +33 -3
  139. package/src/system/components/Toggle.svelte +2 -2
  140. package/src/system/components/VideoFrame.svelte +1 -1
  141. package/src/system/components/VideoLightbox.svelte +2 -2
  142. package/src/system/internal/focusTrap.ts +35 -0
  143. package/src/testing-js/__aria__/badge.yml +40 -0
  144. package/src/testing-js/__aria__/button.yml +88 -0
  145. package/src/testing-js/__aria__/callout.yml +12 -0
  146. package/src/testing-js/__aria__/card.yml +8 -0
  147. package/src/testing-js/__aria__/codesnippet.yml +21 -0
  148. package/src/testing-js/__aria__/collapsiblesection.yml +23 -0
  149. package/src/testing-js/__aria__/cornerbadge.yml +24 -0
  150. package/src/testing-js/__aria__/dialog.yml +42 -0
  151. package/src/testing-js/__aria__/iconbutton.yml +57 -0
  152. package/src/testing-js/__aria__/image.yml +10 -0
  153. package/src/testing-js/__aria__/imagelightbox.yml +50 -0
  154. package/src/testing-js/__aria__/inlineeditactions.yml +16 -0
  155. package/src/testing-js/__aria__/input.yml +61 -0
  156. package/src/testing-js/__aria__/menuselect.yml +30 -0
  157. package/src/testing-js/__aria__/notification.yml +30 -0
  158. package/src/testing-js/__aria__/panel.yml +2 -0
  159. package/src/testing-js/__aria__/progressbar.yml +2 -0
  160. package/src/testing-js/__aria__/radiobutton.yml +20 -0
  161. package/src/testing-js/__aria__/sectiondivider.yml +9 -0
  162. package/src/testing-js/__aria__/segmentedcontrol.yml +35 -0
  163. package/src/testing-js/__aria__/sidenavigation.yml +304 -0
  164. package/src/testing-js/__aria__/slidepager.yml +72 -0
  165. package/src/testing-js/__aria__/slider.yml +28 -0
  166. package/src/testing-js/__aria__/tabbar.yml +35 -0
  167. package/src/testing-js/__aria__/table.yml +144 -0
  168. package/src/testing-js/__aria__/toggle.yml +12 -0
  169. package/src/testing-js/__aria__/tooltip.yml +2 -0
  170. package/src/testing-js/__aria__/videoframe.yml +6 -0
  171. package/src/testing-js/__aria__/videolightbox.yml +12 -0
  172. package/src/testing-js/{chunk-WIZ6W7UT.js → chunk-3WCLMOM7.js} +2 -2
  173. package/src/testing-js/{chunk-SHBYZUPD.js → chunk-5HNZHIHG.js} +211 -14
  174. package/src/testing-js/chunk-5HNZHIHG.js.map +1 -0
  175. package/src/testing-js/{chunk-NB3NZRBM.js → chunk-7CM5D7PF.js} +5 -1
  176. package/src/testing-js/chunk-7CM5D7PF.js.map +1 -0
  177. package/src/testing-js/chunk-EWSGE27V.js +168 -0
  178. package/src/testing-js/chunk-EWSGE27V.js.map +1 -0
  179. package/src/testing-js/{chunk-GKO27NGN.js → chunk-R54I7YL6.js} +2 -2
  180. package/src/testing-js/{chunk-X6KHEVIG.js → chunk-RWH46IU5.js} +97 -29
  181. package/src/testing-js/chunk-RWH46IU5.js.map +1 -0
  182. package/src/testing-js/chunk-SHLPDNAQ.js +658 -0
  183. package/src/testing-js/chunk-SHLPDNAQ.js.map +1 -0
  184. package/src/testing-js/{chunk-3UKGXCDL.js → chunk-YVVR3GJZ.js} +1 -1
  185. package/src/testing-js/chunk-YVVR3GJZ.js.map +1 -0
  186. package/src/testing-js/component-a11y.contract.js +283 -0
  187. package/src/testing-js/component-a11y.contract.js.map +1 -0
  188. package/src/testing-js/component-alias.contract.js +2 -2
  189. package/src/testing-js/component-behavior.contract.js +2 -2
  190. package/src/testing-js/component-editor.contract.js +6 -5
  191. package/src/testing-js/component-editor.contract.js.map +1 -1
  192. package/src/testing-js/component-render.contract.js +10 -6
  193. package/src/testing-js/component-render.contract.js.map +1 -1
  194. package/src/testing-js/index.d.ts +44 -16
  195. package/src/testing-js/index.js +9 -9
  196. package/src/testing-js/page-compliance.contract.js +163 -18
  197. package/src/testing-js/page-compliance.contract.js.map +1 -1
  198. package/src/testing-js/vitest.js +3 -3
  199. package/template/package.json +9 -0
  200. package/src/editor/ui/keepInViewport.ts +0 -84
  201. package/src/testing-js/chunk-3UKGXCDL.js.map +0 -1
  202. package/src/testing-js/chunk-NB3NZRBM.js.map +0 -1
  203. package/src/testing-js/chunk-SHBYZUPD.js.map +0 -1
  204. package/src/testing-js/chunk-X6KHEVIG.js.map +0 -1
  205. /package/src/testing-js/{chunk-WIZ6W7UT.js.map → chunk-3WCLMOM7.js.map} +0 -0
  206. /package/src/testing-js/{chunk-GKO27NGN.js.map → chunk-R54I7YL6.js.map} +0 -0
@@ -123,7 +123,7 @@ var STOP_RE = new RegExp(String.raw`^(.*?)\s+(${NUM})%$`);
123
123
  var CIRCLE_RADIUS_RE = new RegExp(String.raw`^circle\s+(${NUM})px$`, "i");
124
124
  var ELLIPSE_RE = new RegExp(String.raw`^ellipse\s+(${NUM})px\s+(${NUM})px$`, "i");
125
125
  var VAR_RE = /^var\((--[a-z0-9-]+)\)$/i;
126
- function splitTopLevel(s) {
126
+ function splitTopLevel(s, isSeparator = (c) => c === ",") {
127
127
  const parts = [];
128
128
  let depth = 0;
129
129
  let start = 0;
@@ -131,7 +131,7 @@ function splitTopLevel(s) {
131
131
  const c = s[i];
132
132
  if (c === "(") depth++;
133
133
  else if (c === ")") depth--;
134
- else if (c === "," && depth === 0) {
134
+ else if (depth === 0 && isSeparator(c)) {
135
135
  parts.push(s.slice(start, i));
136
136
  start = i + 1;
137
137
  }
@@ -5619,6 +5619,107 @@ function formatReport({ propertiesBefore, propertiesAfter, bytesSaved }) {
5619
5619
  return `live-tokens: the production CSS declares ${propertiesAfter.toLocaleString("en-US")} of ${propertiesBefore.toLocaleString("en-US")} custom properties and is ${kB} kB ${bytesSaved >= 0 ? "smaller" : "larger"}.`;
5620
5620
  }
5621
5621
 
5622
+ // vite-plugin/a11y/a11yRunServer.ts
5623
+ var import_node_child_process = require("child_process");
5624
+ var import_node_fs = __toESM(require("fs"), 1);
5625
+ var import_node_path2 = __toESM(require("path"), 1);
5626
+ var A11Y_RUN_ARGS = ["check-component", "--tests", "--a11y", "--no-fix", "--json", "--open-theme"];
5627
+ var A11Y_REPORT_PATH = import_node_path2.default.join("test-results", "live-tokens", "a11y-report.json");
5628
+ var STDERR_TAIL = 2e3;
5629
+ var CONTRAST_ROLES = /* @__PURE__ */ new Set(["text", "non-text"]);
5630
+ function spawnCli(cliPath) {
5631
+ return (args, cwd) => {
5632
+ const child = (0, import_node_child_process.spawn)(process.execPath, [cliPath, ...args], { cwd, stdio: ["ignore", "pipe", "pipe"] });
5633
+ const done = new Promise((resolve) => {
5634
+ let stdout = "";
5635
+ let stderr = "";
5636
+ child.stdout.on("data", (chunk) => stdout += chunk);
5637
+ child.stderr.on("data", (chunk) => stderr += chunk);
5638
+ child.on("error", (error) => resolve({ code: null, stdout, stderr: `${stderr}${error.message}` }));
5639
+ child.on("close", (code) => resolve({ code, stdout, stderr }));
5640
+ });
5641
+ return { done, stop: () => child.kill("SIGINT") };
5642
+ };
5643
+ }
5644
+ function isContrastFailure(value) {
5645
+ const v = value;
5646
+ return !!v && typeof v === "object" && typeof v.component === "string" && typeof v.variable === "string" && v.variable.startsWith("--") && Array.isArray(v.backdrop) && v.backdrop.every((layer) => typeof layer === "string") && typeof v.role === "string" && CONTRAST_ROLES.has(v.role) && typeof v.ratio === "number" && typeof v.floor === "number" && (v.context === void 0 || typeof v.context === "string");
5647
+ }
5648
+ function readContrast(body) {
5649
+ const contrast = body?.contrast;
5650
+ return Array.isArray(contrast) && contrast.every(isContrastFailure) ? contrast : null;
5651
+ }
5652
+ function parseCliReport(stdout) {
5653
+ try {
5654
+ const parsed = JSON.parse(stdout);
5655
+ return parsed && Array.isArray(parsed.findings) ? parsed : null;
5656
+ } catch {
5657
+ return null;
5658
+ }
5659
+ }
5660
+ function a11yRunServer({ root, reportFile, runCli, broadcast }) {
5661
+ let running = null;
5662
+ function current() {
5663
+ if (running) return running.report;
5664
+ if (!import_node_fs.default.existsSync(reportFile)) return null;
5665
+ return JSON.parse(import_node_fs.default.readFileSync(reportFile, "utf-8"));
5666
+ }
5667
+ function settle(started, outcome) {
5668
+ const finishedAt = (/* @__PURE__ */ new Date()).toISOString();
5669
+ const cli = parseCliReport(outcome.stdout);
5670
+ if (!cli) {
5671
+ const stderr = outcome.stderr.trim().slice(-STDERR_TAIL);
5672
+ return {
5673
+ ...started,
5674
+ state: "failed",
5675
+ finishedAt,
5676
+ error: `check-component exited with code ${outcome.code} and printed no report.${stderr ? `
5677
+ ${stderr}` : ""}`
5678
+ };
5679
+ }
5680
+ return {
5681
+ ...started,
5682
+ state: "finished",
5683
+ finishedAt,
5684
+ ...cli.theme ? { theme: cli.theme } : {},
5685
+ findings: cli.findings.filter((f) => f.details?.engineRule !== "color-contrast")
5686
+ };
5687
+ }
5688
+ function start(body) {
5689
+ if (running) {
5690
+ return { status: 409, body: { error: "An accessibility run is already going.", code: "A11Y_RUN_IN_PROGRESS" } };
5691
+ }
5692
+ const contrast = readContrast(body);
5693
+ if (!contrast) {
5694
+ return {
5695
+ status: 400,
5696
+ body: { error: "Body must be { contrast: [...] } with one entry per failing pair", code: "INVALID_BODY" }
5697
+ };
5698
+ }
5699
+ const report = { state: "running", startedAt: (/* @__PURE__ */ new Date()).toISOString(), contrast };
5700
+ const run = runCli(A11Y_RUN_ARGS, root);
5701
+ running = { report, stop: run.stop };
5702
+ broadcast(report);
5703
+ void run.done.then((outcome) => {
5704
+ const settled = settle(report, outcome);
5705
+ import_node_fs.default.mkdirSync(import_node_path2.default.dirname(reportFile), { recursive: true });
5706
+ import_node_fs.default.writeFileSync(reportFile, `${JSON.stringify(settled, null, 2)}
5707
+ `);
5708
+ running = null;
5709
+ broadcast(settled);
5710
+ });
5711
+ return { status: 202, body: report };
5712
+ }
5713
+ return {
5714
+ start,
5715
+ report: () => ({ status: 200, body: { report: current() } }),
5716
+ stop: () => running?.stop()
5717
+ };
5718
+ }
5719
+
5720
+ // src/editor/core/a11y/a11yReportTypes.ts
5721
+ var A11Y_EVENT = "a11y";
5722
+
5622
5723
  // vite-plugin/themeFileApi.ts
5623
5724
  var import_node_url2 = require("url");
5624
5725
  var import_meta2 = {};
@@ -5679,6 +5780,7 @@ function themeFileApi(opts) {
5679
5780
  const ISOLATED_DATA_DIR = testDataDir();
5680
5781
  const GENERATED_CSS_PATH = ISOLATED_DATA_DIR ? import_path5.default.join(ISOLATED_DATA_DIR, "tokens.generated.css") : opts.tokensGeneratedCssPath ? import_path5.default.resolve(opts.tokensGeneratedCssPath) : import_path5.default.join(dataDirs.dataDir, "tokens.generated.css");
5681
5782
  const FONTS_CSS_PATH = ISOLATED_DATA_DIR ? import_path5.default.join(ISOLATED_DATA_DIR, "fonts.css") : opts.fontsCssPath ? import_path5.default.resolve(opts.fontsCssPath) : import_path5.default.join(import_path5.default.dirname(CSS_PATH), "fonts.css");
5783
+ const A11Y_REPORT_FILE = ISOLATED_DATA_DIR ? import_path5.default.join(ISOLATED_DATA_DIR, import_path5.default.basename(A11Y_REPORT_PATH)) : import_path5.default.join(process.cwd(), A11Y_REPORT_PATH);
5682
5784
  const API_BASE = opts.apiBase ?? "/api/live-tokens";
5683
5785
  const consumerComponentDirs = opts.componentsSrcDir ? [import_path5.default.resolve(opts.componentsSrcDir)] : [import_path5.default.resolve("src/components"), import_path5.default.resolve("src/system/components")];
5684
5786
  const packageComponentsDir = import_path5.default.resolve(
@@ -5688,6 +5790,7 @@ function themeFileApi(opts) {
5688
5790
  "system",
5689
5791
  "components"
5690
5792
  );
5793
+ const PACKAGE_CLI_PATH = import_path5.default.resolve(import_path5.default.dirname((0, import_node_url2.fileURLToPath)(import_meta2.url)), "..", "bin", "cli.mjs");
5691
5794
  const packageDataDir = testPackageDataDir() ?? import_path5.default.resolve(
5692
5795
  import_path5.default.dirname((0, import_node_url2.fileURLToPath)(import_meta2.url)),
5693
5796
  "..",
@@ -6359,6 +6462,8 @@ ${lines.join("\n")}
6359
6462
  const SKETCH_STYLE_BY_NAME_REGEX = new RegExp(`^${escapedBase}/sketch-styles/([a-z0-9\\-_]+)$`);
6360
6463
  const PRODUCTION_ROUTE = `${API_BASE}/production`;
6361
6464
  const EVENTS_ROUTE = `${API_BASE}/events`;
6465
+ const A11Y_RUN_ROUTE = `${API_BASE}/a11y/run`;
6466
+ const A11Y_REPORT_ROUTE = `${API_BASE}/a11y/report`;
6362
6467
  async function handleListColorsAndType(_ctx) {
6363
6468
  const files = colorsAndTypeResource.listNames().map((fileName) => {
6364
6469
  const data = colorsAndTypeResource.readJson(fileName);
@@ -6785,7 +6890,38 @@ data: ${JSON.stringify(state)}
6785
6890
 
6786
6891
  `);
6787
6892
  });
6788
- req.on("close", unsubscribe);
6893
+ eventClients.add(res);
6894
+ req.on("close", () => {
6895
+ unsubscribe();
6896
+ eventClients.delete(res);
6897
+ });
6898
+ }
6899
+ const eventClients = /* @__PURE__ */ new Set();
6900
+ const a11yRuns = a11yRunServer({
6901
+ root: process.cwd(),
6902
+ reportFile: A11Y_REPORT_FILE,
6903
+ runCli: spawnCli(PACKAGE_CLI_PATH),
6904
+ broadcast: (report) => {
6905
+ const frame = `event: ${A11Y_EVENT}
6906
+ data: ${JSON.stringify(report)}
6907
+
6908
+ `;
6909
+ for (const client of eventClients) client.write(frame);
6910
+ }
6911
+ });
6912
+ async function handleStartA11yRun({ req, res }) {
6913
+ let body;
6914
+ try {
6915
+ body = JSON.parse(await readBody(req));
6916
+ } catch {
6917
+ body = void 0;
6918
+ }
6919
+ const answer = a11yRuns.start(body);
6920
+ jsonResponse(res, answer.status, answer.body);
6921
+ }
6922
+ async function handleGetA11yReport({ res }) {
6923
+ const answer = a11yRuns.report();
6924
+ jsonResponse(res, answer.status, answer.body);
6789
6925
  }
6790
6926
  async function handleExportTheme({ params, res }) {
6791
6927
  const [fileName] = params;
@@ -7058,6 +7194,14 @@ data: ${JSON.stringify(state)}
7058
7194
  { method: "DELETE", pattern: SKETCH_STYLE_BY_NAME_REGEX, handler: handleSketchStyleByName },
7059
7195
  { method: "POST", pattern: SKETCH_STYLE_BY_NAME_REGEX, handler: methodNotAllowed },
7060
7196
  { method: "GET", pattern: EVENTS_ROUTE, handler: handleEvents },
7197
+ { method: "POST", pattern: A11Y_RUN_ROUTE, handler: handleStartA11yRun },
7198
+ { method: "GET", pattern: A11Y_RUN_ROUTE, handler: methodNotAllowed },
7199
+ { method: "PUT", pattern: A11Y_RUN_ROUTE, handler: methodNotAllowed },
7200
+ { method: "DELETE", pattern: A11Y_RUN_ROUTE, handler: methodNotAllowed },
7201
+ { method: "GET", pattern: A11Y_REPORT_ROUTE, handler: handleGetA11yReport },
7202
+ { method: "PUT", pattern: A11Y_REPORT_ROUTE, handler: methodNotAllowed },
7203
+ { method: "POST", pattern: A11Y_REPORT_ROUTE, handler: methodNotAllowed },
7204
+ { method: "DELETE", pattern: A11Y_REPORT_ROUTE, handler: methodNotAllowed },
7061
7205
  { method: "PUT", pattern: PRODUCTION_ROUTE, handler: handleAdoptTheme },
7062
7206
  { method: "GET", pattern: PRODUCTION_ROUTE, handler: methodNotAllowed },
7063
7207
  { method: "POST", pattern: PRODUCTION_ROUTE, handler: methodNotAllowed },
@@ -7136,6 +7280,7 @@ data: ${JSON.stringify(state)}
7136
7280
  const handled = await dispatch(req, res, routes);
7137
7281
  if (!handled) next();
7138
7282
  });
7283
+ server.httpServer?.once("close", () => a11yRuns.stop());
7139
7284
  },
7140
7285
  handleHotUpdate(ctx) {
7141
7286
  if (legacyLayout) return;