@setsquare/ui 0.1.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 (312) hide show
  1. package/CHANGELOG.md +70 -0
  2. package/LICENSE +202 -0
  3. package/NOTICE +49 -0
  4. package/README.md +313 -0
  5. package/dist/index.d.ts +129 -0
  6. package/dist/index.d.ts.map +1 -0
  7. package/dist/index.js +78 -0
  8. package/dist/index.js.map +1 -0
  9. package/dist/lib/cn.d.ts +4 -0
  10. package/dist/lib/cn.d.ts.map +1 -0
  11. package/dist/lib/cn.js +59 -0
  12. package/dist/lib/cn.js.map +1 -0
  13. package/dist/lib/tokens.d.ts +5 -0
  14. package/dist/lib/tokens.d.ts.map +1 -0
  15. package/dist/lib/tokens.js +22 -0
  16. package/dist/lib/tokens.js.map +1 -0
  17. package/dist/lib/use-element-width.d.ts +4 -0
  18. package/dist/lib/use-element-width.d.ts.map +1 -0
  19. package/dist/lib/use-element-width.js +17 -0
  20. package/dist/lib/use-element-width.js.map +1 -0
  21. package/dist/lint/index.d.ts +41 -0
  22. package/dist/lint/index.d.ts.map +1 -0
  23. package/dist/lint/index.js +648 -0
  24. package/dist/lint/index.js.map +1 -0
  25. package/dist/shell/app-header.d.ts +13 -0
  26. package/dist/shell/app-header.d.ts.map +1 -0
  27. package/dist/shell/app-header.js +11 -0
  28. package/dist/shell/app-header.js.map +1 -0
  29. package/dist/shell/dashboard-shell.d.ts +67 -0
  30. package/dist/shell/dashboard-shell.d.ts.map +1 -0
  31. package/dist/shell/dashboard-shell.js +168 -0
  32. package/dist/shell/dashboard-shell.js.map +1 -0
  33. package/dist/shell/page-header.d.ts +19 -0
  34. package/dist/shell/page-header.d.ts.map +1 -0
  35. package/dist/shell/page-header.js +11 -0
  36. package/dist/shell/page-header.js.map +1 -0
  37. package/dist/shell/right-panel.d.ts +25 -0
  38. package/dist/shell/right-panel.d.ts.map +1 -0
  39. package/dist/shell/right-panel.js +37 -0
  40. package/dist/shell/right-panel.js.map +1 -0
  41. package/dist/shell/sidebar.d.ts +68 -0
  42. package/dist/shell/sidebar.d.ts.map +1 -0
  43. package/dist/shell/sidebar.js +68 -0
  44. package/dist/shell/sidebar.js.map +1 -0
  45. package/dist/shell/site-footer.d.ts +28 -0
  46. package/dist/shell/site-footer.d.ts.map +1 -0
  47. package/dist/shell/site-footer.js +15 -0
  48. package/dist/shell/site-footer.js.map +1 -0
  49. package/dist/shell/site-header-padding.d.ts +7 -0
  50. package/dist/shell/site-header-padding.d.ts.map +1 -0
  51. package/dist/shell/site-header-padding.js +27 -0
  52. package/dist/shell/site-header-padding.js.map +1 -0
  53. package/dist/shell/site-header.d.ts +23 -0
  54. package/dist/shell/site-header.d.ts.map +1 -0
  55. package/dist/shell/site-header.js +13 -0
  56. package/dist/shell/site-header.js.map +1 -0
  57. package/dist/shell/site-menu.d.ts +27 -0
  58. package/dist/shell/site-menu.d.ts.map +1 -0
  59. package/dist/shell/site-menu.js +56 -0
  60. package/dist/shell/site-menu.js.map +1 -0
  61. package/dist/shell/site-nav-link.d.ts +24 -0
  62. package/dist/shell/site-nav-link.d.ts.map +1 -0
  63. package/dist/shell/site-nav-link.js +35 -0
  64. package/dist/shell/site-nav-link.js.map +1 -0
  65. package/dist/shell/site-nav.d.ts +12 -0
  66. package/dist/shell/site-nav.d.ts.map +1 -0
  67. package/dist/shell/site-nav.js +9 -0
  68. package/dist/shell/site-nav.js.map +1 -0
  69. package/dist/shell/site-path.d.ts +8 -0
  70. package/dist/shell/site-path.d.ts.map +1 -0
  71. package/dist/shell/site-path.js +11 -0
  72. package/dist/shell/site-path.js.map +1 -0
  73. package/dist/shell/site-shell.d.ts +25 -0
  74. package/dist/shell/site-shell.d.ts.map +1 -0
  75. package/dist/shell/site-shell.js +17 -0
  76. package/dist/shell/site-shell.js.map +1 -0
  77. package/dist/styles/styles.css +10 -0
  78. package/dist/styles/theme.css +579 -0
  79. package/dist/styles/tokens.css +295 -0
  80. package/dist/testing/index.d.ts +321 -0
  81. package/dist/testing/index.d.ts.map +1 -0
  82. package/dist/testing/index.js +1175 -0
  83. package/dist/testing/index.js.map +1 -0
  84. package/dist/tokens.json +982 -0
  85. package/dist/ui/alert.d.ts +35 -0
  86. package/dist/ui/alert.d.ts.map +1 -0
  87. package/dist/ui/alert.js +65 -0
  88. package/dist/ui/alert.js.map +1 -0
  89. package/dist/ui/avatar.d.ts +16 -0
  90. package/dist/ui/avatar.d.ts.map +1 -0
  91. package/dist/ui/avatar.js +13 -0
  92. package/dist/ui/avatar.js.map +1 -0
  93. package/dist/ui/badge.d.ts +13 -0
  94. package/dist/ui/badge.d.ts.map +1 -0
  95. package/dist/ui/badge.js +24 -0
  96. package/dist/ui/badge.js.map +1 -0
  97. package/dist/ui/breadcrumbs.d.ts +13 -0
  98. package/dist/ui/breadcrumbs.d.ts.map +1 -0
  99. package/dist/ui/breadcrumbs.js +12 -0
  100. package/dist/ui/breadcrumbs.js.map +1 -0
  101. package/dist/ui/button-styles.d.ts +24 -0
  102. package/dist/ui/button-styles.d.ts.map +1 -0
  103. package/dist/ui/button-styles.js +50 -0
  104. package/dist/ui/button-styles.js.map +1 -0
  105. package/dist/ui/button.d.ts +27 -0
  106. package/dist/ui/button.d.ts.map +1 -0
  107. package/dist/ui/button.js +30 -0
  108. package/dist/ui/button.js.map +1 -0
  109. package/dist/ui/calendar.d.ts +19 -0
  110. package/dist/ui/calendar.d.ts.map +1 -0
  111. package/dist/ui/calendar.js +52 -0
  112. package/dist/ui/calendar.js.map +1 -0
  113. package/dist/ui/card.d.ts +30 -0
  114. package/dist/ui/card.d.ts.map +1 -0
  115. package/dist/ui/card.js +18 -0
  116. package/dist/ui/card.js.map +1 -0
  117. package/dist/ui/checkbox.d.ts +36 -0
  118. package/dist/ui/checkbox.d.ts.map +1 -0
  119. package/dist/ui/checkbox.js +38 -0
  120. package/dist/ui/checkbox.js.map +1 -0
  121. package/dist/ui/code-block.d.ts +20 -0
  122. package/dist/ui/code-block.d.ts.map +1 -0
  123. package/dist/ui/code-block.js +22 -0
  124. package/dist/ui/code-block.js.map +1 -0
  125. package/dist/ui/combo-box.d.ts +17 -0
  126. package/dist/ui/combo-box.d.ts.map +1 -0
  127. package/dist/ui/combo-box.js +14 -0
  128. package/dist/ui/combo-box.js.map +1 -0
  129. package/dist/ui/copy-button.d.ts +14 -0
  130. package/dist/ui/copy-button.d.ts.map +1 -0
  131. package/dist/ui/copy-button.js +36 -0
  132. package/dist/ui/copy-button.js.map +1 -0
  133. package/dist/ui/date-field.d.ts +38 -0
  134. package/dist/ui/date-field.d.ts.map +1 -0
  135. package/dist/ui/date-field.js +78 -0
  136. package/dist/ui/date-field.js.map +1 -0
  137. package/dist/ui/dialog.d.ts +41 -0
  138. package/dist/ui/dialog.d.ts.map +1 -0
  139. package/dist/ui/dialog.js +69 -0
  140. package/dist/ui/dialog.js.map +1 -0
  141. package/dist/ui/disclosure.d.ts +18 -0
  142. package/dist/ui/disclosure.d.ts.map +1 -0
  143. package/dist/ui/disclosure.js +15 -0
  144. package/dist/ui/disclosure.js.map +1 -0
  145. package/dist/ui/empty-state.d.ts +17 -0
  146. package/dist/ui/empty-state.d.ts.map +1 -0
  147. package/dist/ui/empty-state.js +9 -0
  148. package/dist/ui/empty-state.js.map +1 -0
  149. package/dist/ui/error-state.d.ts +45 -0
  150. package/dist/ui/error-state.d.ts.map +1 -0
  151. package/dist/ui/error-state.js +88 -0
  152. package/dist/ui/error-state.js.map +1 -0
  153. package/dist/ui/field.d.ts +46 -0
  154. package/dist/ui/field.d.ts.map +1 -0
  155. package/dist/ui/field.js +79 -0
  156. package/dist/ui/field.js.map +1 -0
  157. package/dist/ui/file-upload.d.ts +54 -0
  158. package/dist/ui/file-upload.d.ts.map +1 -0
  159. package/dist/ui/file-upload.js +170 -0
  160. package/dist/ui/file-upload.js.map +1 -0
  161. package/dist/ui/form.d.ts +56 -0
  162. package/dist/ui/form.d.ts.map +1 -0
  163. package/dist/ui/form.js +137 -0
  164. package/dist/ui/form.js.map +1 -0
  165. package/dist/ui/grid-list.d.ts +24 -0
  166. package/dist/ui/grid-list.d.ts.map +1 -0
  167. package/dist/ui/grid-list.js +21 -0
  168. package/dist/ui/grid-list.js.map +1 -0
  169. package/dist/ui/hero.d.ts +36 -0
  170. package/dist/ui/hero.d.ts.map +1 -0
  171. package/dist/ui/hero.js +19 -0
  172. package/dist/ui/hero.js.map +1 -0
  173. package/dist/ui/icon-button.d.ts +18 -0
  174. package/dist/ui/icon-button.d.ts.map +1 -0
  175. package/dist/ui/icon-button.js +13 -0
  176. package/dist/ui/icon-button.js.map +1 -0
  177. package/dist/ui/icon.d.ts +20 -0
  178. package/dist/ui/icon.d.ts.map +1 -0
  179. package/dist/ui/icon.js +26 -0
  180. package/dist/ui/icon.js.map +1 -0
  181. package/dist/ui/kbd.d.ts +7 -0
  182. package/dist/ui/kbd.d.ts.map +1 -0
  183. package/dist/ui/kbd.js +7 -0
  184. package/dist/ui/kbd.js.map +1 -0
  185. package/dist/ui/link-card.d.ts +23 -0
  186. package/dist/ui/link-card.d.ts.map +1 -0
  187. package/dist/ui/link-card.js +19 -0
  188. package/dist/ui/link-card.js.map +1 -0
  189. package/dist/ui/list-box.d.ts +17 -0
  190. package/dist/ui/list-box.d.ts.map +1 -0
  191. package/dist/ui/list-box.js +18 -0
  192. package/dist/ui/list-box.js.map +1 -0
  193. package/dist/ui/menu.d.ts +31 -0
  194. package/dist/ui/menu.d.ts.map +1 -0
  195. package/dist/ui/menu.js +40 -0
  196. package/dist/ui/menu.js.map +1 -0
  197. package/dist/ui/number-field.d.ts +19 -0
  198. package/dist/ui/number-field.d.ts.map +1 -0
  199. package/dist/ui/number-field.js +19 -0
  200. package/dist/ui/number-field.js.map +1 -0
  201. package/dist/ui/prose.d.ts +12 -0
  202. package/dist/ui/prose.d.ts.map +1 -0
  203. package/dist/ui/prose.js +11 -0
  204. package/dist/ui/prose.js.map +1 -0
  205. package/dist/ui/radio-group.d.ts +20 -0
  206. package/dist/ui/radio-group.d.ts.map +1 -0
  207. package/dist/ui/radio-group.js +16 -0
  208. package/dist/ui/radio-group.js.map +1 -0
  209. package/dist/ui/scroll-region.d.ts +18 -0
  210. package/dist/ui/scroll-region.d.ts.map +1 -0
  211. package/dist/ui/scroll-region.js +29 -0
  212. package/dist/ui/scroll-region.js.map +1 -0
  213. package/dist/ui/search-field.d.ts +12 -0
  214. package/dist/ui/search-field.d.ts.map +1 -0
  215. package/dist/ui/search-field.js +12 -0
  216. package/dist/ui/search-field.js.map +1 -0
  217. package/dist/ui/search.d.ts +43 -0
  218. package/dist/ui/search.d.ts.map +1 -0
  219. package/dist/ui/search.js +45 -0
  220. package/dist/ui/search.js.map +1 -0
  221. package/dist/ui/section.d.ts +50 -0
  222. package/dist/ui/section.d.ts.map +1 -0
  223. package/dist/ui/section.js +25 -0
  224. package/dist/ui/section.js.map +1 -0
  225. package/dist/ui/segmented-control.d.ts +18 -0
  226. package/dist/ui/segmented-control.d.ts.map +1 -0
  227. package/dist/ui/segmented-control.js +17 -0
  228. package/dist/ui/segmented-control.js.map +1 -0
  229. package/dist/ui/select.d.ts +18 -0
  230. package/dist/ui/select.d.ts.map +1 -0
  231. package/dist/ui/select.js +13 -0
  232. package/dist/ui/select.js.map +1 -0
  233. package/dist/ui/selection-bar.d.ts +28 -0
  234. package/dist/ui/selection-bar.d.ts.map +1 -0
  235. package/dist/ui/selection-bar.js +35 -0
  236. package/dist/ui/selection-bar.js.map +1 -0
  237. package/dist/ui/sheet.d.ts +21 -0
  238. package/dist/ui/sheet.d.ts.map +1 -0
  239. package/dist/ui/sheet.js +16 -0
  240. package/dist/ui/sheet.js.map +1 -0
  241. package/dist/ui/skeleton.d.ts +31 -0
  242. package/dist/ui/skeleton.d.ts.map +1 -0
  243. package/dist/ui/skeleton.js +38 -0
  244. package/dist/ui/skeleton.js.map +1 -0
  245. package/dist/ui/slider.d.ts +31 -0
  246. package/dist/ui/slider.d.ts.map +1 -0
  247. package/dist/ui/slider.js +33 -0
  248. package/dist/ui/slider.js.map +1 -0
  249. package/dist/ui/spinner.d.ts +27 -0
  250. package/dist/ui/spinner.d.ts.map +1 -0
  251. package/dist/ui/spinner.js +21 -0
  252. package/dist/ui/spinner.js.map +1 -0
  253. package/dist/ui/split.d.ts +14 -0
  254. package/dist/ui/split.d.ts.map +1 -0
  255. package/dist/ui/split.js +11 -0
  256. package/dist/ui/split.js.map +1 -0
  257. package/dist/ui/stat-list.d.ts +25 -0
  258. package/dist/ui/stat-list.d.ts.map +1 -0
  259. package/dist/ui/stat-list.js +14 -0
  260. package/dist/ui/stat-list.js.map +1 -0
  261. package/dist/ui/steps.d.ts +23 -0
  262. package/dist/ui/steps.d.ts.map +1 -0
  263. package/dist/ui/steps.js +16 -0
  264. package/dist/ui/steps.js.map +1 -0
  265. package/dist/ui/switch.d.ts +13 -0
  266. package/dist/ui/switch.d.ts.map +1 -0
  267. package/dist/ui/switch.js +12 -0
  268. package/dist/ui/switch.js.map +1 -0
  269. package/dist/ui/table.d.ts +25 -0
  270. package/dist/ui/table.d.ts.map +1 -0
  271. package/dist/ui/table.js +29 -0
  272. package/dist/ui/table.js.map +1 -0
  273. package/dist/ui/tag.d.ts +14 -0
  274. package/dist/ui/tag.d.ts.map +1 -0
  275. package/dist/ui/tag.js +11 -0
  276. package/dist/ui/tag.js.map +1 -0
  277. package/dist/ui/text-field.d.ts +27 -0
  278. package/dist/ui/text-field.d.ts.map +1 -0
  279. package/dist/ui/text-field.js +17 -0
  280. package/dist/ui/text-field.js.map +1 -0
  281. package/dist/ui/text-link.d.ts +17 -0
  282. package/dist/ui/text-link.d.ts.map +1 -0
  283. package/dist/ui/text-link.js +15 -0
  284. package/dist/ui/text-link.js.map +1 -0
  285. package/dist/ui/theme-switcher.d.ts +26 -0
  286. package/dist/ui/theme-switcher.d.ts.map +1 -0
  287. package/dist/ui/theme-switcher.js +32 -0
  288. package/dist/ui/theme-switcher.js.map +1 -0
  289. package/dist/ui/theme.d.ts +54 -0
  290. package/dist/ui/theme.d.ts.map +1 -0
  291. package/dist/ui/theme.js +135 -0
  292. package/dist/ui/theme.js.map +1 -0
  293. package/dist/ui/toast.d.ts +34 -0
  294. package/dist/ui/toast.d.ts.map +1 -0
  295. package/dist/ui/toast.js +69 -0
  296. package/dist/ui/toast.js.map +1 -0
  297. package/dist/ui/tooltip.d.ts +10 -0
  298. package/dist/ui/tooltip.d.ts.map +1 -0
  299. package/dist/ui/tooltip.js +10 -0
  300. package/dist/ui/tooltip.js.map +1 -0
  301. package/package.json +123 -0
  302. package/templates/next/error.tsx +32 -0
  303. package/templates/next/loading.tsx +19 -0
  304. package/templates/next/not-found.tsx +18 -0
  305. package/templates/next/page-transition.tsx +33 -0
  306. package/templates/next/portal-layout.tsx +70 -0
  307. package/templates/next/prefetch-on-intent.ts +31 -0
  308. package/templates/next/root-layout.tsx +16 -0
  309. package/templates/next/site-layout.tsx +58 -0
  310. package/templates/next/site-nav.ts +16 -0
  311. package/templates/next/site-not-found.tsx +21 -0
  312. package/templates/next/site-router.tsx +17 -0
@@ -0,0 +1,295 @@
1
+ /* @setsquare/ui tokens — generated from tokens/tokens.json by scripts/build-css.mjs. Do not edit. */
2
+ /* <html data-conformance="aa|aaa" class="dark?"> picks one of four themes. */
3
+ :root {
4
+ --space-1: 4px;
5
+ --space-2: 8px;
6
+ --space-3: 12px;
7
+ --space-4: 16px;
8
+ --space-5: 20px;
9
+ --space-6: 24px;
10
+ --space-8: 32px;
11
+ --space-10: 40px;
12
+ --space-12: 48px;
13
+ --space-16: 64px;
14
+ --radius-sm: 4px;
15
+ --radius-md: 6px;
16
+ --radius-lg: 8px;
17
+ --radius-xl: 12px;
18
+ --radius-full: 9999px;
19
+ --target-min-aa: 24px;
20
+ --target-min-aaa: 44px;
21
+ --target-floor: 24px;
22
+ --control-height-aa: 36px;
23
+ --control-height-aaa: 36px;
24
+ --control-height-sm-aa: 28px;
25
+ --control-height-sm-aaa: 28px;
26
+ --control-height-lg-aa: 44px;
27
+ --control-height-lg-aaa: 44px;
28
+ --control-pad-x-aa: 12px;
29
+ --control-pad-x-aaa: 12px;
30
+ --control-gap-aa: 8px;
31
+ --control-gap-aaa: 12px;
32
+ --nav-item-height-aa: 36px;
33
+ --nav-item-height-aaa: 36px;
34
+ --nav-item-gap-aa: 2px;
35
+ --nav-item-gap-aaa: 4px;
36
+ --choice-size-aa: 20px;
37
+ --choice-size-aaa: 20px;
38
+ --field-gap-aa: 20px;
39
+ --field-gap-aaa: 28px;
40
+ --toast-timeout-aa: 8000ms;
41
+ --toast-timeout-aaa: 0ms;
42
+ --focus-width-aa: 2px;
43
+ --focus-width-aaa: 3px;
44
+ --focus-offset: 2px;
45
+ --paragraph-gap-aa: 1em;
46
+ --paragraph-gap-aaa: 1.5lh;
47
+ --measure-aa: 75ch;
48
+ --measure-aaa: 64ch;
49
+ --motion-distance-aa: 8px;
50
+ --motion-distance-aaa: 0px;
51
+ --header-height-aa: 56px;
52
+ --header-height-aaa: 56px;
53
+ --sidebar-width-aa: 256px;
54
+ --sidebar-width-aaa: 256px;
55
+ --sidebar-width-collapsed-aa: 56px;
56
+ --sidebar-width-collapsed-aaa: 72px;
57
+ --rail-width-aa: 72px;
58
+ --rail-width-aaa: 88px;
59
+ --subnav-width-aa: 224px;
60
+ --subnav-width-aaa: 240px;
61
+ --panel-width-aa: 320px;
62
+ --panel-width-aaa: 360px;
63
+ --gutter: 24px;
64
+ --content-max: 1440px;
65
+ --site-max: 1180px;
66
+ --site-max-narrow: 768px;
67
+ --site-gutter: clamp(20px, calc(3.2 * var(--site-vw, 1vw)), 44px);
68
+ --section-y: clamp(56px, calc(7 * var(--site-vw, 1vw)), 112px);
69
+ --section-y-tight: clamp(40px, calc(5 * var(--site-vw, 1vw)), 80px);
70
+ --bp-md: 768px;
71
+ --bp-lg: 1024px;
72
+ --bp-xl: 1280px;
73
+ --duration-fast: 120ms;
74
+ --duration-exit: 150ms;
75
+ --duration-enter: 210ms;
76
+ --duration-panel: 200ms;
77
+ --duration-loading-delay: 400ms;
78
+ --duration-spin: 900ms;
79
+ --ease-standard: cubic-bezier(0.2, 0, 0, 1);
80
+ --z-header: 30;
81
+ --z-sidebar: 40;
82
+ --z-sheet: 50;
83
+ --z-popover: 60;
84
+ --font-sans: "Atkinson Hyperlegible Next", ui-sans-serif, system-ui, -apple-system, "Segoe UI", sans-serif;
85
+ --font-mono: "Atkinson Hyperlegible Mono", ui-monospace, "SF Mono", Menlo, monospace;
86
+ --target-min: var(--target-min-aa);
87
+ --control-height: var(--control-height-aa);
88
+ --control-height-sm: var(--control-height-sm-aa);
89
+ --control-height-lg: var(--control-height-lg-aa);
90
+ --control-pad-x: var(--control-pad-x-aa);
91
+ --control-gap: var(--control-gap-aa);
92
+ --nav-item-height: var(--nav-item-height-aa);
93
+ --nav-item-gap: var(--nav-item-gap-aa);
94
+ --choice-size: var(--choice-size-aa);
95
+ --field-gap: var(--field-gap-aa);
96
+ --toast-timeout: var(--toast-timeout-aa);
97
+ --focus-width: var(--focus-width-aa);
98
+ --paragraph-gap: var(--paragraph-gap-aa);
99
+ --measure: var(--measure-aa);
100
+ --motion-distance: var(--motion-distance-aa);
101
+ --header-height: var(--header-height-aa);
102
+ --sidebar-width: var(--sidebar-width-aa);
103
+ --sidebar-width-collapsed: var(--sidebar-width-collapsed-aa);
104
+ --rail-width: var(--rail-width-aa);
105
+ --subnav-width: var(--subnav-width-aa);
106
+ --panel-width: var(--panel-width-aa);
107
+ }
108
+ :root[data-conformance="aaa"] {
109
+ --target-min: var(--target-min-aaa);
110
+ --control-height: var(--control-height-aaa);
111
+ --control-height-sm: var(--control-height-sm-aaa);
112
+ --control-height-lg: var(--control-height-lg-aaa);
113
+ --control-pad-x: var(--control-pad-x-aaa);
114
+ --control-gap: var(--control-gap-aaa);
115
+ --nav-item-height: var(--nav-item-height-aaa);
116
+ --nav-item-gap: var(--nav-item-gap-aaa);
117
+ --choice-size: var(--choice-size-aaa);
118
+ --field-gap: var(--field-gap-aaa);
119
+ --toast-timeout: var(--toast-timeout-aaa);
120
+ --focus-width: var(--focus-width-aaa);
121
+ --paragraph-gap: var(--paragraph-gap-aaa);
122
+ --measure: var(--measure-aaa);
123
+ --motion-distance: var(--motion-distance-aaa);
124
+ --header-height: var(--header-height-aaa);
125
+ --sidebar-width: var(--sidebar-width-aaa);
126
+ --sidebar-width-collapsed: var(--sidebar-width-collapsed-aaa);
127
+ --rail-width: var(--rail-width-aaa);
128
+ --subnav-width: var(--subnav-width-aaa);
129
+ --panel-width: var(--panel-width-aaa);
130
+ }
131
+ @media (prefers-reduced-motion: reduce) { :root { --motion-distance: 0px; } }
132
+
133
+ /* Light · AA */
134
+ :root {
135
+ --brand: #2f47c9;
136
+ --brand-subtle: #eceffc;
137
+ --background: #ffffff;
138
+ --foreground: #161a1f;
139
+ --card: #ffffff;
140
+ --card-foreground: var(--foreground);
141
+ --popover: #ffffff;
142
+ --popover-foreground: var(--foreground);
143
+ --muted: #f2f4f6;
144
+ --muted-foreground: #59626d;
145
+ --secondary: #eceff3;
146
+ --secondary-foreground: var(--foreground);
147
+ --accent: #e7ebf0;
148
+ --accent-foreground: var(--foreground);
149
+ --primary: var(--brand);
150
+ --primary-foreground: #ffffff;
151
+ --border: #e0e4e9;
152
+ --input: #7a838e;
153
+ --ring: var(--brand);
154
+ --destructive: #bf2a2a;
155
+ --destructive-foreground: #ffffff;
156
+ --destructive-subtle: #fdecec;
157
+ --success: #0a6f61;
158
+ --success-subtle: #e2f4f0;
159
+ --warning: #8a4f00;
160
+ --warning-subtle: #fdf0da;
161
+ --overlay: #0c0e1166;
162
+ --sidebar: #f6f7f9;
163
+ --sidebar-foreground: var(--foreground);
164
+ --sidebar-primary: var(--brand);
165
+ --sidebar-primary-foreground: var(--primary-foreground);
166
+ --sidebar-accent: #e8ebf0;
167
+ --sidebar-accent-foreground: var(--foreground);
168
+ --sidebar-border: var(--border);
169
+ --sidebar-ring: var(--ring);
170
+ --shadow-sm: 0 1px 2px #161a1f0f, 0 1px 3px #161a1f14;
171
+ --shadow-lg: 0 4px 8px #161a1f14, 0 16px 32px -4px #161a1f29;
172
+ }
173
+
174
+ /* Dark · AA */
175
+ :root.dark {
176
+ --brand: #8fa3ff;
177
+ --brand-subtle: #1b2246;
178
+ --background: #0e1116;
179
+ --foreground: #e7eaee;
180
+ --card: #151a21;
181
+ --card-foreground: var(--foreground);
182
+ --popover: #1a2029;
183
+ --popover-foreground: var(--foreground);
184
+ --muted: #1b212a;
185
+ --muted-foreground: #9ba5b1;
186
+ --secondary: #202731;
187
+ --secondary-foreground: var(--foreground);
188
+ --accent: #232b36;
189
+ --accent-foreground: var(--foreground);
190
+ --primary: var(--brand);
191
+ --primary-foreground: #0e1116;
192
+ --border: #28303a;
193
+ --input: #6b7582;
194
+ --ring: var(--brand);
195
+ --destructive: #f47a70;
196
+ --destructive-foreground: #0e1116;
197
+ --destructive-subtle: #3a1616;
198
+ --success: #4fd3b8;
199
+ --success-subtle: #0f2c27;
200
+ --warning: #f0b45c;
201
+ --warning-subtle: #2f230f;
202
+ --overlay: #000000a6;
203
+ --sidebar: #11151b;
204
+ --sidebar-foreground: var(--foreground);
205
+ --sidebar-primary: var(--brand);
206
+ --sidebar-primary-foreground: var(--primary-foreground);
207
+ --sidebar-accent: #1f2630;
208
+ --sidebar-accent-foreground: var(--foreground);
209
+ --sidebar-border: var(--border);
210
+ --sidebar-ring: var(--ring);
211
+ --shadow-sm: 0 1px 3px #000000a6;
212
+ --shadow-lg: 0 16px 32px -4px #000000cc;
213
+ }
214
+
215
+ /* Light · AAA */
216
+ :root[data-conformance="aaa"] {
217
+ --brand: #22369f;
218
+ --brand-subtle: #e6eafb;
219
+ --background: #ffffff;
220
+ --foreground: #0c0e11;
221
+ --card: #ffffff;
222
+ --card-foreground: var(--foreground);
223
+ --popover: #ffffff;
224
+ --popover-foreground: var(--foreground);
225
+ --muted: #f1f3f5;
226
+ --muted-foreground: #3c444e;
227
+ --secondary: #e9ecf0;
228
+ --secondary-foreground: var(--foreground);
229
+ --accent: #e3e7ec;
230
+ --accent-foreground: var(--foreground);
231
+ --primary: var(--brand);
232
+ --primary-foreground: #ffffff;
233
+ --border: #7f8792;
234
+ --input: #5d6570;
235
+ --ring: var(--brand);
236
+ --destructive: #8c1818;
237
+ --destructive-foreground: #ffffff;
238
+ --destructive-subtle: #fbe7e7;
239
+ --success: #06544a;
240
+ --success-subtle: #ddf1ec;
241
+ --warning: #663a00;
242
+ --warning-subtle: #fcecd2;
243
+ --overlay: #0c0e1180;
244
+ --sidebar: #f4f6f8;
245
+ --sidebar-foreground: var(--foreground);
246
+ --sidebar-primary: var(--brand);
247
+ --sidebar-primary-foreground: var(--primary-foreground);
248
+ --sidebar-accent: #e3e7ec;
249
+ --sidebar-accent-foreground: var(--foreground);
250
+ --sidebar-border: var(--border);
251
+ --sidebar-ring: var(--ring);
252
+ --shadow-sm: none;
253
+ --shadow-lg: 0 4px 8px #0c0e1129, 0 16px 32px -4px #0c0e1140;
254
+ }
255
+
256
+ /* Dark · AAA */
257
+ :root[data-conformance="aaa"].dark {
258
+ --brand: #b0beff;
259
+ --brand-subtle: #1a2148;
260
+ --background: #07090c;
261
+ --foreground: #f5f7f9;
262
+ --card: #0e1217;
263
+ --card-foreground: var(--foreground);
264
+ --popover: #12171e;
265
+ --popover-foreground: var(--foreground);
266
+ --muted: #151a21;
267
+ --muted-foreground: #c5ccd4;
268
+ --secondary: #1a2029;
269
+ --secondary-foreground: var(--foreground);
270
+ --accent: #1f2630;
271
+ --accent-foreground: var(--foreground);
272
+ --primary: var(--brand);
273
+ --primary-foreground: #07090c;
274
+ --border: #6c7580;
275
+ --input: #8c96a3;
276
+ --ring: var(--brand);
277
+ --destructive: #ffa39b;
278
+ --destructive-foreground: #07090c;
279
+ --destructive-subtle: #3a1313;
280
+ --success: #86e6d0;
281
+ --success-subtle: #0d2a25;
282
+ --warning: #f8cd8c;
283
+ --warning-subtle: #2c200c;
284
+ --overlay: #000000b3;
285
+ --sidebar: #0b0e12;
286
+ --sidebar-foreground: var(--foreground);
287
+ --sidebar-primary: var(--brand);
288
+ --sidebar-primary-foreground: var(--primary-foreground);
289
+ --sidebar-accent: #1b222b;
290
+ --sidebar-accent-foreground: var(--foreground);
291
+ --sidebar-border: var(--border);
292
+ --sidebar-ring: var(--ring);
293
+ --shadow-sm: none;
294
+ --shadow-lg: 0 16px 32px -4px #000000e6;
295
+ }
@@ -0,0 +1,321 @@
1
+ /**
2
+ * @setsquare/ui/testing — checks on a rendered page, for use in Playwright (or anything with a
3
+ * `page.evaluate`). They look at what the browser actually laid out, so they find what the lint rules cannot:
4
+ * a wrapper without `relative`, a third-party widget, CSS from elsewhere.
5
+ *
6
+ * - Positioning: `findUncontainedPositioning`, `findHiddenOverflowScrolls`, `expectPositioningContained`.
7
+ * - Targets: `findSmallTargets`, `findOverlappingTargets`, `expectTargetsSized` — the target is the element a
8
+ * pointer hits (Layer 1), measured as laid out, not the paint inside it.
9
+ * - Focus: `findInvisibleFocus`, `expectFocusVisible` — every control a keyboard reaches must change on screen
10
+ * when it takes focus. These take screenshots, so they need a Playwright page.
11
+ * - Links: `findUndistinguishedLinks`, `expectLinksDistinguished` — a link in running text must be findable
12
+ * without colour (WCAG's F73 and G183), or with `{ underline: true }`, underlined.
13
+ * - Cursors: `findCursorMismatches`, `expectCursorsMatch` — one cursor rule on every target: the pointer on
14
+ * what is pressed, the I-beam on text entry, not-allowed when disabled. These hover, so they need a page
15
+ * with a mouse.
16
+ * - Reflow: `findPageOverflow`, `expectPageReflows` — at the width the page is laid out at, nothing makes it
17
+ * scroll sideways or runs off its edge, apart from content in a scroller of its own.
18
+ * - Text spacing: `findClippedText`, `expectTextUnclipped` — with WCAG 1.4.12's four spacing metrics applied,
19
+ * no text is cut off by its box or spills out of one.
20
+ * - Motion: `findEndlessAnimations`, `expectAnimationsPausable` — nothing moves for more than five seconds
21
+ * unless a visible control on the page pauses it.
22
+ *
23
+ * The DOM scans are self-contained functions: `page.evaluate(findSmallTargets)` runs them in the page.
24
+ * Nothing here imports Playwright.
25
+ */
26
+ export interface UncontainedElement {
27
+ /** The absolutely positioned element, described as `tag#id.class "name"`. */
28
+ element: string;
29
+ /** What it is: React Aria's hidden input, sr-only text, something focusable, or something else. */
30
+ kind: 'hidden-input' | 'sr-only' | 'focusable' | 'other';
31
+ /** Its nearest scroll container. */
32
+ scroller: string;
33
+ /** The positioned ancestor it is laid out against — outside the scroller, which is the bug. */
34
+ containingBlock: string;
35
+ }
36
+ /**
37
+ * Every `position: absolute` element whose containing block lies outside its nearest scroll container
38
+ * (`overflow: auto | scroll`). Such an element does not scroll with the content it belongs to, and scrolling
39
+ * it into view scrolls an ancestor instead. Returns [] when the page is clean.
40
+ */
41
+ export declare function findUncontainedPositioning(root?: ParentNode): UncontainedElement[];
42
+ export interface HiddenOverflowScroll {
43
+ /** What was focused or brought into view. */
44
+ trigger: string;
45
+ /** The overflow:hidden element that scrolled — people cannot scroll it back. */
46
+ scrolled: string;
47
+ x: number;
48
+ y: number;
49
+ }
50
+ /**
51
+ * Focus every focusable element, and bring every absolutely positioned element into view the way a screen
52
+ * reader's cursor or find-in-page would (so not a decorative, aria-hidden one with no text), with each scroll
53
+ * container scrolled first to its start and then to its
54
+ * end. Reports every time an `overflow: hidden` element scrolled as a result: content that moved with no way
55
+ * to scroll it back, which is the blank space at the bottom of the page. Restores scroll positions and focus.
56
+ */
57
+ export declare function findHiddenOverflowScrolls(root?: ParentNode): HiddenOverflowScroll[];
58
+ /** Anything with Playwright's `page.evaluate`. */
59
+ export interface Evaluates {
60
+ evaluate<R, A>(fn: (arg: A) => R | Promise<R>, arg: A): Promise<R>;
61
+ }
62
+ export interface PositioningReport {
63
+ uncontained: UncontainedElement[];
64
+ hiddenOverflowScrolls: HiddenOverflowScroll[];
65
+ }
66
+ /** Runs both scans in the page. */
67
+ export declare function checkPositioning(page: Evaluates): Promise<PositioningReport>;
68
+ /**
69
+ * Throws, listing every finding, unless the page is clean. Use it after the page reaches the state you want to
70
+ * check — open the panel, show the errors — since only what is rendered can be checked.
71
+ *
72
+ * ```ts
73
+ * import { expectPositioningContained } from '@setsquare/ui/testing';
74
+ * test('settings', async ({ page }) => { await page.goto('/settings'); await expectPositioningContained(page); });
75
+ * ```
76
+ */
77
+ export declare function expectPositioningContained(page: Evaluates): Promise<void>;
78
+ export interface TargetFinding {
79
+ /** The target, described as `tag#id.class "name"`. */
80
+ element: string;
81
+ width: number;
82
+ height: number;
83
+ }
84
+ export interface SmallTargetOptions {
85
+ /** Minimum size in CSS px. Default: the page's --target-min (24px at AA, 44px at AAA). */
86
+ min?: number;
87
+ /** Targets to leave out, such as ones covered by the Equivalent exception. */
88
+ ignore?: string;
89
+ }
90
+ /**
91
+ * Every pointer target smaller than the minimum in either axis. A target is an interactive element as laid
92
+ * out — for a visually hidden input (React Aria's checkbox, radio, switch, slider), the control around it that
93
+ * a pointer actually hits. Disabled, hidden and aria-hidden elements are skipped, and so are inline elements
94
+ * (display: inline), which is how this approximates the Inline exception for links in a sentence.
95
+ * Returns [] when every target is big enough.
96
+ */
97
+ export declare function findSmallTargets(options?: SmallTargetOptions, root?: ParentNode): TargetFinding[];
98
+ export interface OverlapFinding {
99
+ a: string;
100
+ b: string;
101
+ /** Overlapping area in CSS px². WCAG leaves it out of both targets' size. */
102
+ area: number;
103
+ }
104
+ /**
105
+ * Pairs of targets whose boxes overlap on screen, where neither contains the other. WCAG's definition of
106
+ * target leaves the overlapping area out of the measurement, so an overlap can take a target below its
107
+ * minimum even when its box is big enough. Three-layer controls keep the target in the layout, so they don't
108
+ * overlap by construction; this finds targets made bigger with an overlay or a negative margin. Only what is
109
+ * on screen is compared (something scrolled or translated out of view overlaps nothing), and only within one
110
+ * layer: a toast or popover over the page is left to the focus-obscured checks.
111
+ */
112
+ export declare function findOverlappingTargets(root?: ParentNode): OverlapFinding[];
113
+ /** Throws, listing every finding, unless every target meets the minimum and no two targets overlap. */
114
+ export declare function expectTargetsSized(page: Evaluates, options?: SmallTargetOptions): Promise<void>;
115
+ /** What `findInvisibleFocus` needs from a page: Playwright's `Page` has all of it. */
116
+ export interface ScreenshotPage extends Evaluates {
117
+ keyboard: {
118
+ press(key: string): Promise<void>;
119
+ };
120
+ screenshot(options: {
121
+ clip: {
122
+ x: number;
123
+ y: number;
124
+ width: number;
125
+ height: number;
126
+ };
127
+ animations?: 'disabled' | 'allow';
128
+ caret?: 'hide' | 'initial';
129
+ }): Promise<Uint8Array>;
130
+ }
131
+ export interface InvisibleFocus {
132
+ element: string;
133
+ /**
134
+ * `unchanged`: the pixels around it were the same focused and not. `offscreen`: it could not be seen at all.
135
+ * `trapped`: focus could not be moved off it (the only control in a modal), so there was nothing to compare
136
+ * against — not a failure, but not checked either.
137
+ */
138
+ reason: 'unchanged' | 'offscreen' | 'trapped';
139
+ }
140
+ export interface FocusVisibleOptions {
141
+ /** CSS px of surrounding page to include, for rings drawn outside the control. Default 8. */
142
+ pad?: number;
143
+ /**
144
+ * Elements not to check, such as a demo that paints its focus ring all the time, or parts checked on another
145
+ * page. Focus can still move to them while the others are checked.
146
+ */
147
+ ignore?: string;
148
+ }
149
+ /**
150
+ * Focuses every control a keyboard can reach, one at a time, and compares a screenshot of it (and `pad` px
151
+ * around it) with focus on it and with focus somewhere else. An element whose pixels do not change has no
152
+ * visible focus indicator, which fails WCAG 2.4.7. "Somewhere else" is another control far from this one —
153
+ * not the page body, because a modal dialog or menu would pull focus straight back. Tooltips are hidden, and
154
+ * transitions, animations and the text caret are turned off, so only the indicator can make the difference.
155
+ * This is the check that finds a ring styled on an element that never receives focus.
156
+ */
157
+ export declare function findInvisibleFocus(page: ScreenshotPage, options?: FocusVisibleOptions): Promise<InvisibleFocus[]>;
158
+ /** Throws, listing every control whose focus cannot be seen, unless there are none. `trapped` ones are skipped. */
159
+ export declare function expectFocusVisible(page: ScreenshotPage, options?: FocusVisibleOptions): Promise<void>;
160
+ export interface LinkFinding {
161
+ /** The link, described as `tag "text"`. */
162
+ element: string;
163
+ /** Contrast ratio between the link's colour and the text around it, to two decimals. */
164
+ contrast: number;
165
+ /**
166
+ * `colour-only`: nothing but colour tells it from the text around it, and at under 3:1 (G183's threshold)
167
+ * — WCAG's F73 failure. `no-underline`: only with `{ underline: true }`, a link that WCAG accepts (bold,
168
+ * italic or 3:1) but that has no underline.
169
+ */
170
+ reason: 'colour-only' | 'no-underline';
171
+ }
172
+ export interface LinkOptions {
173
+ /**
174
+ * Require an underline on every link in running text, which is this package's rule (brand colour is under
175
+ * 3:1 against body text in every theme). Default false: accept anything WCAG does — an underline or border,
176
+ * bold, italic, or colour at 3:1 or more against the text around it.
177
+ */
178
+ underline?: boolean;
179
+ /** Links to leave out. */
180
+ ignore?: string;
181
+ }
182
+ /**
183
+ * Every link in running text that people who can't tell the colours apart could not find. A link counts as
184
+ * in running text when it is laid out inline and the block around it has words of its own — so navigation,
185
+ * lists of links and link buttons are left alone, as WCAG's F73 leaves them. A link passes on an underline or
186
+ * bottom border the text around it doesn't have, a heavier weight (600+ against 200 lighter), italics the
187
+ * text around it doesn't have, or a colour at least 3:1 against that text (G183). Returns [] when every link
188
+ * is distinguished.
189
+ */
190
+ export declare function findUndistinguishedLinks(options?: LinkOptions, root?: ParentNode): LinkFinding[];
191
+ /** Throws, listing every finding, unless every link in running text can be told apart without colour. */
192
+ export declare function expectLinksDistinguished(page: Evaluates, options?: LinkOptions): Promise<void>;
193
+ /** What `findCursorMismatches` needs from a page: Playwright's `Page` has all of it. */
194
+ export interface HoverPage extends Evaluates {
195
+ mouse: {
196
+ move(x: number, y: number): Promise<void>;
197
+ };
198
+ }
199
+ /**
200
+ * What each kind of target shows. `press`: anything pressed — buttons, links, checkboxes, options, menu
201
+ * items, selectable rows, sortable column headers. `text`: text entry — inputs, textareas, date segments.
202
+ * `drag`: a slider thumb. `disabled`, `pending` (a button waiting on its action), `readonly` (a checkbox that
203
+ * can't change), and `current` (the current page in breadcrumbs, disabled because it is where you are).
204
+ */
205
+ export type CursorKind = 'press' | 'text' | 'drag' | 'disabled' | 'pending' | 'readonly' | 'current';
206
+ export interface CursorOptions {
207
+ /**
208
+ * The cursors each kind may show. Defaults: press `pointer`; text `text` or `auto` (which is the I-beam
209
+ * over editable text); drag `grab`; disabled `not-allowed`; pending `wait` or `progress`; readonly and
210
+ * current `default`. `false` leaves a kind unchecked — `{ press: ['default'] }` checks a product that keeps
211
+ * the arrow on buttons, as Tailwind's own reset does.
212
+ */
213
+ expect?: Partial<Record<CursorKind, string[] | false>>;
214
+ /** Targets to leave out. */
215
+ ignore?: string;
216
+ }
217
+ export interface CursorFinding {
218
+ element: string;
219
+ kind: CursorKind;
220
+ expected: string[];
221
+ /** Each cursor that was not expected, and where it showed: the centre or an edge of the target. */
222
+ actual: {
223
+ cursor: string;
224
+ at: 'centre' | 'edge';
225
+ }[];
226
+ }
227
+ /**
228
+ * Hovers every target and reads the cursor at its centre and just inside each corner — the whole of Layer 1,
229
+ * not only the paint — so a child that resets the cursor, or a target whose edge still shows the arrow, is
230
+ * found. Hovering first means states that only appear on hover (React Aria's data-hovered) count. Points
231
+ * covered by another target (a checkbox in a row) are that target's, and are checked on its own turn. A
232
+ * visually hidden input stands for its label (a checkbox, radio or switch) or, for a range input, the thumb
233
+ * around it; one with neither (a drop zone's hidden button) has no pointer target and is skipped. No WCAG
234
+ * criterion covers the cursor: this checks that one rule is applied everywhere.
235
+ */
236
+ export declare function findCursorMismatches(page: HoverPage, options?: CursorOptions): Promise<CursorFinding[]>;
237
+ /** Throws, listing every target whose cursor breaks the rule, unless there are none. */
238
+ export declare function expectCursorsMatch(page: HoverPage, options?: CursorOptions): Promise<void>;
239
+ export interface PageOverflow {
240
+ /** The element that reaches past the page's right edge, described as `tag#id.class "name"`. */
241
+ element: string;
242
+ /**
243
+ * `scrolls`: the page scrolls sideways because of it. `clipped`: an `overflow: hidden` or `clip` box that
244
+ * runs to the edge of the page cuts it off, so part of it can't be seen or scrolled to.
245
+ */
246
+ reason: 'scrolls' | 'clipped';
247
+ /** How far past the right edge it reaches, in CSS px. */
248
+ by: number;
249
+ }
250
+ export interface PageOverflowOptions {
251
+ /** Elements to leave out. */
252
+ ignore?: string;
253
+ }
254
+ /**
255
+ * Everything that reaches past the right edge of the page at the width it is laid out at: set the viewport
256
+ * to 320px to check WCAG 1.4.10's reflow width. Content inside its own scroll container (a `ScrollRegion`,
257
+ * a code block, a data table) is left alone as long as the scroller itself fits, since it scrolls on its own
258
+ * and the page doesn't; so is content an ancestor clips inside the page, which is that component's business.
259
+ * `clipped` is only reported for something with words or media in it, so a decorative glow bleeding off the
260
+ * edge isn't. Fixed-position elements are left out. Only the outermost culprit is reported. Returns [] when
261
+ * the page fits.
262
+ */
263
+ export declare function findPageOverflow(options?: PageOverflowOptions, root?: ParentNode): PageOverflow[];
264
+ /** Throws, listing every finding, unless the page fits its width. Set the viewport first: 320px for reflow. */
265
+ export declare function expectPageReflows(page: Evaluates, options?: PageOverflowOptions): Promise<void>;
266
+ export interface ClippedText {
267
+ /** The box the text no longer fits, described as `tag#id.class "name"`. */
268
+ element: string;
269
+ /**
270
+ * `clipped`: the box is `overflow: hidden` or `clip` (or truncates with an ellipsis), so the text is cut
271
+ * off. `overflows`: the box has a set size and shows its overflow, so the text spills over what follows.
272
+ */
273
+ reason: 'clipped' | 'overflows';
274
+ /** How much further the content runs past the box than it did before the spacing was applied, in CSS px. */
275
+ x: number;
276
+ y: number;
277
+ }
278
+ export interface TextSpacingOptions {
279
+ /** Elements to leave out. */
280
+ ignore?: string;
281
+ }
282
+ /**
283
+ * Applies WCAG 1.4.12's four text-spacing metrics to the whole page — line height 1.5, paragraph spacing
284
+ * 2em, letter spacing 0.12em, word spacing 0.16em, the way a user's stylesheet or bookmarklet would — and
285
+ * reports every box whose content now runs out of it further than it did before. Measuring the difference
286
+ * leaves alone anything that was already clipped on purpose (visually hidden text, a decorative bleed).
287
+ * Scroll containers are left out too, since their content can still be scrolled to, and so is text that
288
+ * spills from a box inside a scroller that scrolls that way (code in a code block). Only the innermost box
289
+ * is reported. Takes the spacing off again before returning. Returns [] when everything still fits.
290
+ */
291
+ export declare function findClippedText(options?: TextSpacingOptions, root?: ParentNode): ClippedText[];
292
+ /** Throws, listing every finding, unless all the text still fits with WCAG 1.4.12's spacing applied. */
293
+ export declare function expectTextUnclipped(page: Evaluates, options?: TextSpacingOptions): Promise<void>;
294
+ export interface EndlessAnimation {
295
+ /** What moves, described as `tag#id.class "name"`, with a pseudo-element when it is one. */
296
+ element: string;
297
+ /** The CSS animation's name, `transition: <property>`, `script` for a Web Animation, or `video`. */
298
+ animation: string;
299
+ /** How long it runs, in ms: `Infinity` for one that repeats forever. */
300
+ duration: number;
301
+ }
302
+ export interface AnimationOptions {
303
+ /** The longest anything may move without a pause control, in ms. Default 5000, WCAG 2.2.2's five seconds. */
304
+ max?: number;
305
+ /** Elements to leave out, such as a loading indicator. */
306
+ ignore?: string;
307
+ }
308
+ /**
309
+ * Everything moving on the page that runs longer than `max` (or forever) with no visible control to pause
310
+ * it. It reads `document.getAnimations()` — CSS animations, CSS transitions and Web Animations that are
311
+ * running now — and every `<video>` that is playing without its own `controls`. Something counts as paused
312
+ * by a control when it sits inside an element whose `id` a visible button on the page names in
313
+ * `data-pauses`; `aria-controls` doesn't count, since a menu button names its panel that way. It can't see
314
+ * motion drawn by `requestAnimationFrame`, SVG (SMIL)
315
+ * animation, animated images or canvas, and it only sees what is running when it is called, so call it once
316
+ * the page has settled and again in each state that starts something. Returns [] when nothing qualifies.
317
+ */
318
+ export declare function findEndlessAnimations(options?: AnimationOptions, root?: ParentNode): EndlessAnimation[];
319
+ /** Throws, listing every finding, unless everything that moves for longer than `max` can be paused. */
320
+ export declare function expectAnimationsPausable(page: Evaluates, options?: AnimationOptions): Promise<void>;
321
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/testing/index.ts"],"names":[],"mappings":"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"}