@lo-tek/interfaces 0.0.0 → 0.38.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 (456) hide show
  1. package/CHANGELOG.md +3389 -0
  2. package/LICENSE +21 -0
  3. package/README.md +129 -1
  4. package/agent/astro.md +400 -0
  5. package/agent/bundles.md +429 -0
  6. package/agent/datastar.md +409 -0
  7. package/agent/html.md +388 -0
  8. package/agent/react.md +440 -0
  9. package/agent/templates.md +472 -0
  10. package/core/lotek-core.wasm +0 -0
  11. package/core/lotek.wasm +0 -0
  12. package/dist/cli.d.ts +12 -0
  13. package/dist/cli.d.ts.map +1 -0
  14. package/dist/cli.js +14 -0
  15. package/dist/cli.js.map +1 -0
  16. package/dist/components/css/accordion/accordion.d.ts +37 -0
  17. package/dist/components/css/accordion/accordion.d.ts.map +1 -0
  18. package/dist/components/css/accordion/accordion.js +31 -0
  19. package/dist/components/css/accordion/accordion.js.map +1 -0
  20. package/dist/components/css/alert/alert.d.ts +35 -0
  21. package/dist/components/css/alert/alert.d.ts.map +1 -0
  22. package/dist/components/css/alert/alert.js +29 -0
  23. package/dist/components/css/alert/alert.js.map +1 -0
  24. package/dist/components/css/avatar/avatar.d.ts +40 -0
  25. package/dist/components/css/avatar/avatar.d.ts.map +1 -0
  26. package/dist/components/css/avatar/avatar.js +30 -0
  27. package/dist/components/css/avatar/avatar.js.map +1 -0
  28. package/dist/components/css/badge/badge.d.ts +24 -0
  29. package/dist/components/css/badge/badge.d.ts.map +1 -0
  30. package/dist/components/css/badge/badge.js +24 -0
  31. package/dist/components/css/badge/badge.js.map +1 -0
  32. package/dist/components/css/breadcrumbs/breadcrumbs.d.ts +26 -0
  33. package/dist/components/css/breadcrumbs/breadcrumbs.d.ts.map +1 -0
  34. package/dist/components/css/breadcrumbs/breadcrumbs.js +24 -0
  35. package/dist/components/css/breadcrumbs/breadcrumbs.js.map +1 -0
  36. package/dist/components/css/button/button.d.ts +26 -0
  37. package/dist/components/css/button/button.d.ts.map +1 -0
  38. package/dist/components/css/button/button.js +25 -0
  39. package/dist/components/css/button/button.js.map +1 -0
  40. package/dist/components/css/card/card.d.ts +36 -0
  41. package/dist/components/css/card/card.d.ts.map +1 -0
  42. package/dist/components/css/card/card.js +28 -0
  43. package/dist/components/css/card/card.js.map +1 -0
  44. package/dist/components/css/checkbox/checkbox.d.ts +32 -0
  45. package/dist/components/css/checkbox/checkbox.d.ts.map +1 -0
  46. package/dist/components/css/checkbox/checkbox.js +27 -0
  47. package/dist/components/css/checkbox/checkbox.js.map +1 -0
  48. package/dist/components/css/divider/divider.d.ts +29 -0
  49. package/dist/components/css/divider/divider.d.ts.map +1 -0
  50. package/dist/components/css/divider/divider.js +23 -0
  51. package/dist/components/css/divider/divider.js.map +1 -0
  52. package/dist/components/css/error-text/error-text.d.ts +24 -0
  53. package/dist/components/css/error-text/error-text.d.ts.map +1 -0
  54. package/dist/components/css/error-text/error-text.js +18 -0
  55. package/dist/components/css/error-text/error-text.js.map +1 -0
  56. package/dist/components/css/fieldset/fieldset.d.ts +55 -0
  57. package/dist/components/css/fieldset/fieldset.d.ts.map +1 -0
  58. package/dist/components/css/fieldset/fieldset.js +39 -0
  59. package/dist/components/css/fieldset/fieldset.js.map +1 -0
  60. package/dist/components/css/file-upload/file-upload.d.ts +41 -0
  61. package/dist/components/css/file-upload/file-upload.d.ts.map +1 -0
  62. package/dist/components/css/file-upload/file-upload.js +32 -0
  63. package/dist/components/css/file-upload/file-upload.js.map +1 -0
  64. package/dist/components/css/heading/heading.d.ts +29 -0
  65. package/dist/components/css/heading/heading.d.ts.map +1 -0
  66. package/dist/components/css/heading/heading.js +23 -0
  67. package/dist/components/css/heading/heading.js.map +1 -0
  68. package/dist/components/css/help-text/help-text.d.ts +24 -0
  69. package/dist/components/css/help-text/help-text.d.ts.map +1 -0
  70. package/dist/components/css/help-text/help-text.js +23 -0
  71. package/dist/components/css/help-text/help-text.js.map +1 -0
  72. package/dist/components/css/icon/icon.d.ts +34 -0
  73. package/dist/components/css/icon/icon.d.ts.map +1 -0
  74. package/dist/components/css/icon/icon.js +25 -0
  75. package/dist/components/css/icon/icon.js.map +1 -0
  76. package/dist/components/css/input/input.d.ts +40 -0
  77. package/dist/components/css/input/input.d.ts.map +1 -0
  78. package/dist/components/css/input/input.js +45 -0
  79. package/dist/components/css/input/input.js.map +1 -0
  80. package/dist/components/css/label/label.d.ts +33 -0
  81. package/dist/components/css/label/label.d.ts.map +1 -0
  82. package/dist/components/css/label/label.js +23 -0
  83. package/dist/components/css/label/label.js.map +1 -0
  84. package/dist/components/css/link/link.d.ts +28 -0
  85. package/dist/components/css/link/link.d.ts.map +1 -0
  86. package/dist/components/css/link/link.js +20 -0
  87. package/dist/components/css/link/link.js.map +1 -0
  88. package/dist/components/css/list/list.d.ts +31 -0
  89. package/dist/components/css/list/list.d.ts.map +1 -0
  90. package/dist/components/css/list/list.js +25 -0
  91. package/dist/components/css/list/list.js.map +1 -0
  92. package/dist/components/css/pagination/pagination.d.ts +27 -0
  93. package/dist/components/css/pagination/pagination.d.ts.map +1 -0
  94. package/dist/components/css/pagination/pagination.js +25 -0
  95. package/dist/components/css/pagination/pagination.js.map +1 -0
  96. package/dist/components/css/paragraph/paragraph.d.ts +36 -0
  97. package/dist/components/css/paragraph/paragraph.d.ts.map +1 -0
  98. package/dist/components/css/paragraph/paragraph.js +26 -0
  99. package/dist/components/css/paragraph/paragraph.js.map +1 -0
  100. package/dist/components/css/progress/progress.d.ts +53 -0
  101. package/dist/components/css/progress/progress.d.ts.map +1 -0
  102. package/dist/components/css/progress/progress.js +38 -0
  103. package/dist/components/css/progress/progress.js.map +1 -0
  104. package/dist/components/css/radio/radio.d.ts +32 -0
  105. package/dist/components/css/radio/radio.d.ts.map +1 -0
  106. package/dist/components/css/radio/radio.js +27 -0
  107. package/dist/components/css/radio/radio.js.map +1 -0
  108. package/dist/components/css/search/search.d.ts +34 -0
  109. package/dist/components/css/search/search.d.ts.map +1 -0
  110. package/dist/components/css/search/search.js +32 -0
  111. package/dist/components/css/search/search.js.map +1 -0
  112. package/dist/components/css/select/select.d.ts +40 -0
  113. package/dist/components/css/select/select.d.ts.map +1 -0
  114. package/dist/components/css/select/select.js +31 -0
  115. package/dist/components/css/select/select.js.map +1 -0
  116. package/dist/components/css/shared.d.ts +90 -0
  117. package/dist/components/css/shared.d.ts.map +1 -0
  118. package/dist/components/css/shared.js +167 -0
  119. package/dist/components/css/shared.js.map +1 -0
  120. package/dist/components/css/skeleton/skeleton.d.ts +29 -0
  121. package/dist/components/css/skeleton/skeleton.d.ts.map +1 -0
  122. package/dist/components/css/skeleton/skeleton.js +23 -0
  123. package/dist/components/css/skeleton/skeleton.js.map +1 -0
  124. package/dist/components/css/skip-link/skip-link.d.ts +18 -0
  125. package/dist/components/css/skip-link/skip-link.d.ts.map +1 -0
  126. package/dist/components/css/skip-link/skip-link.js +16 -0
  127. package/dist/components/css/skip-link/skip-link.js.map +1 -0
  128. package/dist/components/css/spinner/spinner.d.ts +33 -0
  129. package/dist/components/css/spinner/spinner.d.ts.map +1 -0
  130. package/dist/components/css/spinner/spinner.js +25 -0
  131. package/dist/components/css/spinner/spinner.js.map +1 -0
  132. package/dist/components/css/sr-only/sr-only.d.ts +17 -0
  133. package/dist/components/css/sr-only/sr-only.d.ts.map +1 -0
  134. package/dist/components/css/sr-only/sr-only.js +15 -0
  135. package/dist/components/css/sr-only/sr-only.js.map +1 -0
  136. package/dist/components/css/switch/switch.d.ts +37 -0
  137. package/dist/components/css/switch/switch.d.ts.map +1 -0
  138. package/dist/components/css/switch/switch.js +29 -0
  139. package/dist/components/css/switch/switch.js.map +1 -0
  140. package/dist/components/css/table/table.d.ts +76 -0
  141. package/dist/components/css/table/table.d.ts.map +1 -0
  142. package/dist/components/css/table/table.js +59 -0
  143. package/dist/components/css/table/table.js.map +1 -0
  144. package/dist/components/css/tag/tag.d.ts +35 -0
  145. package/dist/components/css/tag/tag.d.ts.map +1 -0
  146. package/dist/components/css/tag/tag.js +27 -0
  147. package/dist/components/css/tag/tag.js.map +1 -0
  148. package/dist/components/css/textarea/textarea.d.ts +23 -0
  149. package/dist/components/css/textarea/textarea.d.ts.map +1 -0
  150. package/dist/components/css/textarea/textarea.js +18 -0
  151. package/dist/components/css/textarea/textarea.js.map +1 -0
  152. package/dist/components/css/toggle-group/toggle-group.d.ts +31 -0
  153. package/dist/components/css/toggle-group/toggle-group.d.ts.map +1 -0
  154. package/dist/components/css/toggle-group/toggle-group.js +29 -0
  155. package/dist/components/css/toggle-group/toggle-group.js.map +1 -0
  156. package/dist/components/css/tooltip/tooltip.d.ts +31 -0
  157. package/dist/components/css/tooltip/tooltip.d.ts.map +1 -0
  158. package/dist/components/css/tooltip/tooltip.js +29 -0
  159. package/dist/components/css/tooltip/tooltip.js.map +1 -0
  160. package/dist/components/default-texts.d.ts +41 -0
  161. package/dist/components/default-texts.d.ts.map +1 -0
  162. package/dist/components/default-texts.js +41 -0
  163. package/dist/components/default-texts.js.map +1 -0
  164. package/dist/components/events.d.ts +77 -0
  165. package/dist/components/events.d.ts.map +1 -0
  166. package/dist/components/events.js +3 -0
  167. package/dist/components/events.js.map +1 -0
  168. package/dist/components/frame/dialog/dialog.d.ts +122 -0
  169. package/dist/components/frame/dialog/dialog.d.ts.map +1 -0
  170. package/dist/components/frame/dialog/dialog.js +112 -0
  171. package/dist/components/frame/dialog/dialog.js.map +1 -0
  172. package/dist/components/frame/dialog/lt-dialog.d.ts +104 -0
  173. package/dist/components/frame/dialog/lt-dialog.d.ts.map +1 -0
  174. package/dist/components/frame/dialog/lt-dialog.js +434 -0
  175. package/dist/components/frame/dialog/lt-dialog.js.map +1 -0
  176. package/dist/components/frame/error-summary/error-summary.d.ts +53 -0
  177. package/dist/components/frame/error-summary/error-summary.d.ts.map +1 -0
  178. package/dist/components/frame/error-summary/error-summary.js +54 -0
  179. package/dist/components/frame/error-summary/error-summary.js.map +1 -0
  180. package/dist/components/frame/error-summary/lt-error-summary.d.ts +93 -0
  181. package/dist/components/frame/error-summary/lt-error-summary.d.ts.map +1 -0
  182. package/dist/components/frame/error-summary/lt-error-summary.js +408 -0
  183. package/dist/components/frame/error-summary/lt-error-summary.js.map +1 -0
  184. package/dist/components/frame/field/field-core.d.ts +92 -0
  185. package/dist/components/frame/field/field-core.d.ts.map +1 -0
  186. package/dist/components/frame/field/field-core.js +63 -0
  187. package/dist/components/frame/field/field-core.js.map +1 -0
  188. package/dist/components/frame/field/lt-field.d.ts +173 -0
  189. package/dist/components/frame/field/lt-field.d.ts.map +1 -0
  190. package/dist/components/frame/field/lt-field.js +600 -0
  191. package/dist/components/frame/field/lt-field.js.map +1 -0
  192. package/dist/components/frame/popover/lt-popover.d.ts +136 -0
  193. package/dist/components/frame/popover/lt-popover.d.ts.map +1 -0
  194. package/dist/components/frame/popover/lt-popover.js +520 -0
  195. package/dist/components/frame/popover/lt-popover.js.map +1 -0
  196. package/dist/components/frame/popover/popover.d.ts +49 -0
  197. package/dist/components/frame/popover/popover.d.ts.map +1 -0
  198. package/dist/components/frame/popover/popover.js +64 -0
  199. package/dist/components/frame/popover/popover.js.map +1 -0
  200. package/dist/components/frame/session-timeout/lt-session-timeout.d.ts +198 -0
  201. package/dist/components/frame/session-timeout/lt-session-timeout.d.ts.map +1 -0
  202. package/dist/components/frame/session-timeout/lt-session-timeout.js +610 -0
  203. package/dist/components/frame/session-timeout/lt-session-timeout.js.map +1 -0
  204. package/dist/components/frame/session-timeout/session-timeout.d.ts +113 -0
  205. package/dist/components/frame/session-timeout/session-timeout.d.ts.map +1 -0
  206. package/dist/components/frame/session-timeout/session-timeout.js +101 -0
  207. package/dist/components/frame/session-timeout/session-timeout.js.map +1 -0
  208. package/dist/components/frame/suggestion/lt-suggestion.d.ts +367 -0
  209. package/dist/components/frame/suggestion/lt-suggestion.d.ts.map +1 -0
  210. package/dist/components/frame/suggestion/lt-suggestion.js +1171 -0
  211. package/dist/components/frame/suggestion/lt-suggestion.js.map +1 -0
  212. package/dist/components/frame/suggestion/suggestion.d.ts +143 -0
  213. package/dist/components/frame/suggestion/suggestion.d.ts.map +1 -0
  214. package/dist/components/frame/suggestion/suggestion.js +127 -0
  215. package/dist/components/frame/suggestion/suggestion.js.map +1 -0
  216. package/dist/components/frame/tabs/lt-tabs.d.ts +426 -0
  217. package/dist/components/frame/tabs/lt-tabs.d.ts.map +1 -0
  218. package/dist/components/frame/tabs/lt-tabs.js +1265 -0
  219. package/dist/components/frame/tabs/lt-tabs.js.map +1 -0
  220. package/dist/components/frame/tabs/tabs.d.ts +112 -0
  221. package/dist/components/frame/tabs/tabs.d.ts.map +1 -0
  222. package/dist/components/frame/tabs/tabs.js +107 -0
  223. package/dist/components/frame/tabs/tabs.js.map +1 -0
  224. package/dist/components/host-element.d.ts +184 -0
  225. package/dist/components/host-element.d.ts.map +1 -0
  226. package/dist/components/host-element.js +440 -0
  227. package/dist/components/host-element.js.map +1 -0
  228. package/dist/components/standalone/connection-status/connection-status.d.ts +32 -0
  229. package/dist/components/standalone/connection-status/connection-status.d.ts.map +1 -0
  230. package/dist/components/standalone/connection-status/connection-status.js +26 -0
  231. package/dist/components/standalone/connection-status/connection-status.js.map +1 -0
  232. package/dist/components/standalone/connection-status/lt-connection-status.d.ts +86 -0
  233. package/dist/components/standalone/connection-status/lt-connection-status.d.ts.map +1 -0
  234. package/dist/components/standalone/connection-status/lt-connection-status.js +240 -0
  235. package/dist/components/standalone/connection-status/lt-connection-status.js.map +1 -0
  236. package/dist/components/standalone/toast/lt-toast.d.ts +109 -0
  237. package/dist/components/standalone/toast/lt-toast.d.ts.map +1 -0
  238. package/dist/components/standalone/toast/lt-toast.js +256 -0
  239. package/dist/components/standalone/toast/lt-toast.js.map +1 -0
  240. package/dist/components/standalone/toast/toast.d.ts +52 -0
  241. package/dist/components/standalone/toast/toast.d.ts.map +1 -0
  242. package/dist/components/standalone/toast/toast.js +42 -0
  243. package/dist/components/standalone/toast/toast.js.map +1 -0
  244. package/dist/diagnostics/core.d.ts +171 -0
  245. package/dist/diagnostics/core.d.ts.map +1 -0
  246. package/dist/diagnostics/core.js +84 -0
  247. package/dist/diagnostics/core.js.map +1 -0
  248. package/dist/diagnostics/default-core.d.ts +10 -0
  249. package/dist/diagnostics/default-core.d.ts.map +1 -0
  250. package/dist/diagnostics/default-core.js +72 -0
  251. package/dist/diagnostics/default-core.js.map +1 -0
  252. package/dist/diagnostics/index.d.ts +84 -0
  253. package/dist/diagnostics/index.d.ts.map +1 -0
  254. package/dist/diagnostics/index.js +106 -0
  255. package/dist/diagnostics/index.js.map +1 -0
  256. package/dist/dom.d.ts +55 -0
  257. package/dist/dom.d.ts.map +1 -0
  258. package/dist/dom.js +162 -0
  259. package/dist/dom.js.map +1 -0
  260. package/dist/index.d.ts +97 -0
  261. package/dist/index.d.ts.map +1 -0
  262. package/dist/index.js +58 -0
  263. package/dist/index.js.map +1 -0
  264. package/dist/jsx/react.d.ts +180 -0
  265. package/dist/jsx/react.d.ts.map +1 -0
  266. package/dist/jsx/react.js +2 -0
  267. package/dist/jsx/react.js.map +1 -0
  268. package/dist/lotek.css +3617 -0
  269. package/dist/lt.d.ts +325 -0
  270. package/dist/lt.d.ts.map +1 -0
  271. package/dist/lt.js +183 -0
  272. package/dist/lt.js.map +1 -0
  273. package/dist/react.d.ts +494 -0
  274. package/dist/react.d.ts.map +1 -0
  275. package/dist/react.js +296 -0
  276. package/dist/react.js.map +1 -0
  277. package/dist/register.d.ts +17 -0
  278. package/dist/register.d.ts.map +1 -0
  279. package/dist/register.js +35 -0
  280. package/dist/register.js.map +1 -0
  281. package/dist/tokens/color.d.ts +43 -0
  282. package/dist/tokens/color.d.ts.map +1 -0
  283. package/dist/tokens/color.js +123 -0
  284. package/dist/tokens/color.js.map +1 -0
  285. package/dist/tokens/contract.d.ts +18 -0
  286. package/dist/tokens/contract.d.ts.map +1 -0
  287. package/dist/tokens/contract.js +18 -0
  288. package/dist/tokens/contract.js.map +1 -0
  289. package/dist/tokens/matrix-cells.d.ts +30 -0
  290. package/dist/tokens/matrix-cells.d.ts.map +1 -0
  291. package/dist/tokens/matrix-cells.js +273 -0
  292. package/dist/tokens/matrix-cells.js.map +1 -0
  293. package/dist/tokens/matrix.d.ts +18 -0
  294. package/dist/tokens/matrix.d.ts.map +1 -0
  295. package/dist/tokens/matrix.js +21 -0
  296. package/dist/tokens/matrix.js.map +1 -0
  297. package/dist/tokens/theme-check.d.ts +42 -0
  298. package/dist/tokens/theme-check.d.ts.map +1 -0
  299. package/dist/tokens/theme-check.js +10 -0
  300. package/dist/tokens/theme-check.js.map +1 -0
  301. package/dist/tokens/theme.d.ts +94 -0
  302. package/dist/tokens/theme.d.ts.map +1 -0
  303. package/dist/tokens/theme.js +14 -0
  304. package/dist/tokens/theme.js.map +1 -0
  305. package/dist/tokens/tokens.d.ts +122 -0
  306. package/dist/tokens/tokens.d.ts.map +1 -0
  307. package/dist/tokens/tokens.js +158 -0
  308. package/dist/tokens/tokens.js.map +1 -0
  309. package/dist/vocabulary/classes.d.ts +3 -0
  310. package/dist/vocabulary/classes.d.ts.map +1 -0
  311. package/dist/vocabulary/classes.js +1354 -0
  312. package/dist/vocabulary/classes.js.map +1 -0
  313. package/dist/vocabulary/elements.d.ts +3 -0
  314. package/dist/vocabulary/elements.d.ts.map +1 -0
  315. package/dist/vocabulary/elements.js +490 -0
  316. package/dist/vocabulary/elements.js.map +1 -0
  317. package/dist/vocabulary/types.d.ts +229 -0
  318. package/dist/vocabulary/types.d.ts.map +1 -0
  319. package/dist/vocabulary/types.js +11 -0
  320. package/dist/vocabulary/types.js.map +1 -0
  321. package/dist/wasi-host.d.ts +24 -0
  322. package/dist/wasi-host.d.ts.map +1 -0
  323. package/dist/wasi-host.js +140 -0
  324. package/dist/wasi-host.js.map +1 -0
  325. package/live-templates.xml +63 -0
  326. package/manifest/files.json +373 -0
  327. package/manifest/manifest.json +5090 -0
  328. package/manifest/manifest.schema.json +586 -0
  329. package/package.json +399 -5
  330. package/src/cli.ts +21 -0
  331. package/src/components/css/accordion/accordion.css +102 -0
  332. package/src/components/css/accordion/accordion.ts +50 -0
  333. package/src/components/css/alert/alert.css +53 -0
  334. package/src/components/css/alert/alert.ts +48 -0
  335. package/src/components/css/avatar/avatar.css +96 -0
  336. package/src/components/css/avatar/avatar.ts +57 -0
  337. package/src/components/css/badge/badge.css +42 -0
  338. package/src/components/css/badge/badge.ts +43 -0
  339. package/src/components/css/breadcrumbs/breadcrumbs.css +62 -0
  340. package/src/components/css/breadcrumbs/breadcrumbs.ts +30 -0
  341. package/src/components/css/button/button.css +128 -0
  342. package/src/components/css/button/button.ts +44 -0
  343. package/src/components/css/card/card.css +65 -0
  344. package/src/components/css/card/card.ts +50 -0
  345. package/src/components/css/checkbox/checkbox.css +114 -0
  346. package/src/components/css/checkbox/checkbox.ts +50 -0
  347. package/src/components/css/divider/divider.css +38 -0
  348. package/src/components/css/divider/divider.ts +42 -0
  349. package/src/components/css/error-text/error-text.css +21 -0
  350. package/src/components/css/error-text/error-text.ts +37 -0
  351. package/src/components/css/fieldset/fieldset.css +72 -0
  352. package/src/components/css/fieldset/fieldset.ts +87 -0
  353. package/src/components/css/file-upload/file-upload.css +102 -0
  354. package/src/components/css/file-upload/file-upload.ts +65 -0
  355. package/src/components/css/heading/heading.css +33 -0
  356. package/src/components/css/heading/heading.ts +42 -0
  357. package/src/components/css/help-text/help-text.css +24 -0
  358. package/src/components/css/help-text/help-text.ts +42 -0
  359. package/src/components/css/icon/icon.css +20 -0
  360. package/src/components/css/icon/icon.ts +44 -0
  361. package/src/components/css/input/input.css +145 -0
  362. package/src/components/css/input/input.ts +77 -0
  363. package/src/components/css/label/label.css +42 -0
  364. package/src/components/css/label/label.ts +51 -0
  365. package/src/components/css/link/link.css +38 -0
  366. package/src/components/css/link/link.ts +38 -0
  367. package/src/components/css/list/list.css +53 -0
  368. package/src/components/css/list/list.ts +44 -0
  369. package/src/components/css/pagination/pagination.css +95 -0
  370. package/src/components/css/pagination/pagination.ts +33 -0
  371. package/src/components/css/paragraph/paragraph.css +31 -0
  372. package/src/components/css/paragraph/paragraph.ts +53 -0
  373. package/src/components/css/progress/progress.css +161 -0
  374. package/src/components/css/progress/progress.ts +78 -0
  375. package/src/components/css/radio/radio.css +94 -0
  376. package/src/components/css/radio/radio.ts +50 -0
  377. package/src/components/css/search/search.css +50 -0
  378. package/src/components/css/search/search.ts +56 -0
  379. package/src/components/css/select/select.css +321 -0
  380. package/src/components/css/select/select.ts +63 -0
  381. package/src/components/css/shared.ts +199 -0
  382. package/src/components/css/skeleton/skeleton.css +62 -0
  383. package/src/components/css/skeleton/skeleton.ts +43 -0
  384. package/src/components/css/skip-link/skip-link.css +41 -0
  385. package/src/components/css/skip-link/skip-link.ts +22 -0
  386. package/src/components/css/spinner/spinner.css +48 -0
  387. package/src/components/css/spinner/spinner.ts +48 -0
  388. package/src/components/css/sr-only/sr-only.css +16 -0
  389. package/src/components/css/sr-only/sr-only.ts +21 -0
  390. package/src/components/css/switch/switch.css +105 -0
  391. package/src/components/css/switch/switch.ts +50 -0
  392. package/src/components/css/table/table.css +159 -0
  393. package/src/components/css/table/table.ts +107 -0
  394. package/src/components/css/tag/tag.css +58 -0
  395. package/src/components/css/tag/tag.ts +49 -0
  396. package/src/components/css/textarea/textarea.css +83 -0
  397. package/src/components/css/textarea/textarea.ts +40 -0
  398. package/src/components/css/toggle-group/toggle-group.css +92 -0
  399. package/src/components/css/toggle-group/toggle-group.ts +37 -0
  400. package/src/components/css/tooltip/tooltip.css +89 -0
  401. package/src/components/css/tooltip/tooltip.ts +37 -0
  402. package/src/components/default-texts.ts +41 -0
  403. package/src/components/events.ts +68 -0
  404. package/src/components/frame/dialog/dialog.css +306 -0
  405. package/src/components/frame/dialog/dialog.ts +166 -0
  406. package/src/components/frame/dialog/lt-dialog.ts +513 -0
  407. package/src/components/frame/error-summary/error-summary.css +47 -0
  408. package/src/components/frame/error-summary/error-summary.ts +90 -0
  409. package/src/components/frame/error-summary/lt-error-summary.ts +458 -0
  410. package/src/components/frame/field/field-core.ts +152 -0
  411. package/src/components/frame/field/field.css +17 -0
  412. package/src/components/frame/field/lt-field.ts +790 -0
  413. package/src/components/frame/popover/lt-popover.ts +586 -0
  414. package/src/components/frame/popover/popover.css +50 -0
  415. package/src/components/frame/popover/popover.ts +102 -0
  416. package/src/components/frame/session-timeout/lt-session-timeout.ts +715 -0
  417. package/src/components/frame/session-timeout/session-timeout.css +50 -0
  418. package/src/components/frame/session-timeout/session-timeout.ts +156 -0
  419. package/src/components/frame/suggestion/lt-suggestion.ts +1379 -0
  420. package/src/components/frame/suggestion/suggestion.css +132 -0
  421. package/src/components/frame/suggestion/suggestion.ts +172 -0
  422. package/src/components/frame/tabs/lt-tabs.ts +1395 -0
  423. package/src/components/frame/tabs/tabs.css +128 -0
  424. package/src/components/frame/tabs/tabs.ts +188 -0
  425. package/src/components/host-element.ts +493 -0
  426. package/src/components/standalone/connection-status/connection-status.css +41 -0
  427. package/src/components/standalone/connection-status/connection-status.ts +47 -0
  428. package/src/components/standalone/connection-status/lt-connection-status.ts +268 -0
  429. package/src/components/standalone/toast/lt-toast.ts +300 -0
  430. package/src/components/standalone/toast/toast.css +78 -0
  431. package/src/components/standalone/toast/toast.ts +70 -0
  432. package/src/diagnostics/core.ts +227 -0
  433. package/src/diagnostics/default-core.ts +81 -0
  434. package/src/diagnostics/index.ts +150 -0
  435. package/src/dom.ts +185 -0
  436. package/src/index.ts +218 -0
  437. package/src/jsx/react.ts +212 -0
  438. package/src/lt.ts +192 -0
  439. package/src/react.ts +411 -0
  440. package/src/register.ts +43 -0
  441. package/src/tailwind/tailwind.css +169 -0
  442. package/src/tokens/boundary.css +104 -0
  443. package/src/tokens/color-contract.json +231 -0
  444. package/src/tokens/color.ts +150 -0
  445. package/src/tokens/contract.ts +24 -0
  446. package/src/tokens/matrix-cells.ts +375 -0
  447. package/src/tokens/matrix.ts +32 -0
  448. package/src/tokens/theme-check.ts +51 -0
  449. package/src/tokens/theme.ts +104 -0
  450. package/src/tokens/tokens.css +569 -0
  451. package/src/tokens/tokens.ts +223 -0
  452. package/src/vocabulary/classes.ts +1356 -0
  453. package/src/vocabulary/elements.ts +492 -0
  454. package/src/vocabulary/types.ts +228 -0
  455. package/src/wasi-host.ts +155 -0
  456. package/web-types.json +800 -0
@@ -0,0 +1,70 @@
1
+ import { attributes } from "../../css/shared.js"
2
+ import { DEFAULT_TEXTS } from "../../default-texts.js"
3
+
4
+ /**
5
+ * The class on the host, that is, the region the messages are in.
6
+ *
7
+ * Until 0.28.0 this was the class on each message, and the region was styled
8
+ * by its element name. Registered under another name, with
9
+ * `defineLtToast("my-toast")`, it then lost its position.
10
+ */
11
+ export const TOAST_CLASS = "lt-toast" as const
12
+ export const TOAST_MESSAGE_CLASS = "lt-toast__message" as const
13
+ export const TOAST_CLOSE_CLASS = "lt-toast__close" as const
14
+
15
+ export type ToastOptions = {
16
+ /** Text that says what the region is. Becomes `aria-label`. */
17
+ label?: string
18
+ /**
19
+ * The screen reader name of the close button in each message. Default:
20
+ * "Close message". `closeLabel` in `show()` overrides it for one message.
21
+ */
22
+ closeLabel?: string
23
+ }
24
+
25
+ export type ToastAttributes = {
26
+ host: {
27
+ class: typeof TOAST_CLASS
28
+ role: "status"
29
+ "aria-live": "polite"
30
+ "aria-atomic": "false"
31
+ "aria-label": string
32
+ "close-label"?: string
33
+ "data-ignore-morph": ""
34
+ }
35
+ message: { class: typeof TOAST_MESSAGE_CLASS }
36
+ close: { class: typeof TOAST_CLOSE_CLASS }
37
+ }
38
+
39
+ /**
40
+ * The attributes for the toast region.
41
+ *
42
+ * The region is `role="status"` and not `role="alert"`. A message that comes
43
+ * because something went well should not interrupt what the screen reader is
44
+ * doing.
45
+ *
46
+ * `data-ignore-morph` is not optional. `<lt-toast>` creates and removes its
47
+ * message elements inside the region, and without the attribute the Datastar
48
+ * morph tears them away at the next patch, because the server's version of
49
+ * the region is empty. The attribute must be in the HTML the server sends:
50
+ * the component cannot set it on itself, since the morph reads it from the
51
+ * server's node.
52
+ */
53
+ export const toast = ({
54
+ label = DEFAULT_TEXTS.toastRegion,
55
+ closeLabel,
56
+ }: ToastOptions = {}): ToastAttributes => ({
57
+ host: attributes({
58
+ class: TOAST_CLASS,
59
+ role: "status" as const,
60
+ "aria-live": "polite" as const,
61
+ // `status` is atomic by default, and then the whole stack is announced
62
+ // again for every message that is added.
63
+ "aria-atomic": "false" as const,
64
+ "aria-label": label,
65
+ "close-label": closeLabel,
66
+ "data-ignore-morph": "" as const,
67
+ }),
68
+ message: attributes({ class: TOAST_MESSAGE_CLASS }),
69
+ close: attributes({ class: TOAST_CLOSE_CLASS }),
70
+ })
@@ -0,0 +1,227 @@
1
+ /**
2
+ * The core: LO-TEK's check and theme generator, written in Rust and built to
3
+ * a single WebAssembly module.
4
+ *
5
+ * The same module runs here, in VS Code, on the JVM (Chicory) and in
6
+ * IntelliJ, and gives the same answer everywhere. The module has no imports,
7
+ * so it needs no glue: the loader writes the text in as UTF-8 and reads the
8
+ * answer out as JSON, as every host language does.
9
+ *
10
+ * The core carries no data. The vocabulary and the colour contract are given
11
+ * to it with `loadManifest` and `loadContract`, from the files in the package.
12
+ *
13
+ * `diagnoseMarkup` and `diagnosePage` in `index.ts` load the module and the
14
+ * files from the package themselves. `loadCore` is for anyone who has the
15
+ * module some other way, such as an extension that bundles it, or a browser:
16
+ *
17
+ * ```ts
18
+ * const core = loadCore(await WebAssembly.compileStreaming(fetch(url)))
19
+ * core.loadManifest(await (await fetch(manifestUrl)).text())
20
+ * core.diagnosePage(html)
21
+ * ```
22
+ *
23
+ * Synchronous, because Node, Bun and VS Code allow it. In the browser the
24
+ * module must be compiled with `WebAssembly.compile` first, and the compiled
25
+ * module passed here.
26
+ */
27
+
28
+ export type Severity = "error" | "warning"
29
+
30
+ /** One edit in a fix: replace the text from `start` to `end` with `text`. */
31
+ export type Edit = {
32
+ start: number
33
+ end: number
34
+ text: string
35
+ }
36
+
37
+ /**
38
+ * A fix the editor can offer: one or more edits that belong together, such
39
+ * as `id` on the field and `for` on the label. They are in text order and do
40
+ * not overlap; apply them from the end, so the positions hold. `preferred`
41
+ * marks the safe one, such as `onlinetext` to `online-text`: the same
42
+ * letters, only written differently. A suggestion at a distance is a
43
+ * suggestion.
44
+ */
45
+ export type Fix = {
46
+ title: string
47
+ edits: Edit[]
48
+ preferred?: boolean
49
+ }
50
+
51
+ export type Finding = {
52
+ /** Where the finding starts, as an index into the text (UTF-16, like a `string`). */
53
+ start: number
54
+ end: number
55
+ /** The line the finding starts on, from 1. */
56
+ line: number
57
+ /** The column the finding starts at, from 1, in UTF-16 units. */
58
+ column: number
59
+ message: string
60
+ severity: Severity
61
+ /** The name of the rule, such as `unknown-class`. That is what `lotek-ignore-next` takes. */
62
+ rule: string
63
+ /** The component page, as a link in the message. */
64
+ link: string
65
+ fix?: Fix
66
+ }
67
+
68
+ export type CoreVersion = {
69
+ /** The version of the core. */
70
+ core: string
71
+ /** The version of `@lo-tek/interfaces` the manifest was written from, or `null` without a manifest. */
72
+ manifest: string | null
73
+ /** The manifest format the core understands. */
74
+ schemaVersion: number
75
+ }
76
+
77
+ /** A promise in the colour contract that does not hold. */
78
+ export type Violation = {
79
+ family: string
80
+ promise: string
81
+ ratio: number
82
+ required: number
83
+ }
84
+
85
+ /** The theme `buildTheme` returns: the tokens per appearance, the promises that break, and the CSS. */
86
+ export type CoreTheme = {
87
+ light: Record<string, string>
88
+ dark: Record<string, string>
89
+ /** Promises that do not hold. Empty when the theme is sound. */
90
+ violations: Violation[]
91
+ css: string
92
+ }
93
+
94
+ /** What `inspectTheme` found in a theme the consumer has written by hand. */
95
+ export type CoreThemeReport = {
96
+ problems: { selector: string; message: string }[]
97
+ /** Blocks that were actually read. */
98
+ blocks: number
99
+ /** Values the consumer wrote, and that were understood. */
100
+ declarations: number
101
+ /** Promises that were actually checked. */
102
+ promises: number
103
+ }
104
+
105
+ /** What `inspectStyles` found in a stylesheet. */
106
+ export type CoreStyles = {
107
+ /** Every class that appears in a selector. */
108
+ classes: string[]
109
+ /** Every class with an attribute, and the value when the selector requires one. */
110
+ attributes: { class: string; attribute: string; value?: string }[]
111
+ /** The URLs in `@import`. */
112
+ imports: string[]
113
+ }
114
+
115
+ export type Core = {
116
+ /** Checks a template or a fragment. Throws without a manifest. */
117
+ diagnoseMarkup(html: string): Finding[]
118
+ /** Checks a whole page, including the wiring. Throws without a manifest. */
119
+ diagnosePage(html: string): Finding[]
120
+ /** Gives the core the vocabulary. Throws with the core's explanation if it cannot be read. */
121
+ loadManifest(json: string): void
122
+ /** Gives the core the colour contract. Throws with the core's explanation if it cannot be read. */
123
+ loadContract(json: string): void
124
+ version(): CoreVersion
125
+ /** Builds a theme from the recipe. Throws without a colour contract, or when the recipe cannot be used. */
126
+ buildTheme(recipe: unknown): CoreTheme
127
+ /** Checks every promise in a theme written as CSS. Throws without a colour contract. */
128
+ inspectTheme(css: string): CoreThemeReport
129
+ /** The classes and attribute values a stylesheet styles, read with the core's CSS reader. */
130
+ inspectStyles(css: string): CoreStyles
131
+ /**
132
+ * The check with the stylesheets as well: a class none of them styles, and
133
+ * a value without a rule. `page` checks as `diagnosePage`, otherwise as
134
+ * `diagnoseMarkup`. Throws without a manifest.
135
+ */
136
+ diagnoseStyled(html: string, css: string[], page: boolean): Finding[]
137
+ }
138
+
139
+ type Exports = {
140
+ memory: WebAssembly.Memory
141
+ alloc(length: number): number
142
+ diagnose_markup_raw(pointer: number, length: number): number
143
+ diagnose_page_raw(pointer: number, length: number): number
144
+ load_manifest_raw(pointer: number, length: number): number
145
+ load_contract_raw(pointer: number, length: number): number
146
+ version_raw(): void
147
+ build_theme_raw(pointer: number, length: number): number
148
+ inspect_theme_raw(pointer: number, length: number): number
149
+ inspect_styles_raw(pointer: number, length: number): void
150
+ diagnose_styled_raw(pointer: number, length: number): number
151
+ accessibility_tree_raw(pointer: number, length: number): number
152
+ accessibility_facts_raw(): void
153
+ accessibility_roles_raw(): void
154
+ accessibility_states_raw(): void
155
+ result_ptr(): number
156
+ result_len(): number
157
+ }
158
+
159
+ /**
160
+ * @internal Not part of the package's API.
161
+ *
162
+ * An instance of the core and the helpers every call goes through: the text
163
+ * written into the module's memory, and the answer read back. Not part of
164
+ * the package: `index.ts` exports `loadCore`. The tests reach the core's
165
+ * other functions, such as the accessibility tree, through this.
166
+ */
167
+ export function instantiate(source: BufferSource | WebAssembly.Module) {
168
+ const module =
169
+ source instanceof WebAssembly.Module
170
+ ? source
171
+ : new WebAssembly.Module(source)
172
+ const e = new WebAssembly.Instance(module, {}).exports as unknown as Exports
173
+ const encoder = new TextEncoder()
174
+ const decoder = new TextDecoder()
175
+
176
+ /** Writes the text into the module's memory and returns the pointer and length. */
177
+ const write = (text: string): [number, number] => {
178
+ const bytes = encoder.encode(text)
179
+ const pointer = e.alloc(bytes.length)
180
+ // The memory can grow on every call, so the view is created after `alloc`.
181
+ new Uint8Array(e.memory.buffer, pointer, bytes.length).set(bytes)
182
+ return [pointer, bytes.length]
183
+ }
184
+ const read = <T>(): T =>
185
+ JSON.parse(
186
+ decoder.decode(
187
+ new Uint8Array(e.memory.buffer, e.result_ptr(), e.result_len()),
188
+ ),
189
+ ) as T
190
+ /** The answer from a call that can be rejected: the value, or the core's explanation as an error. */
191
+ const answer = <T>(status: number): T => {
192
+ if (status !== 0) throw new Error(read<{ error: string }>().error)
193
+ return read<T>()
194
+ }
195
+ return { e, write, read, answer }
196
+ }
197
+
198
+ /** Loads the core from the module's bytes or an already compiled module. */
199
+ export function loadCore(source: BufferSource | WebAssembly.Module): Core {
200
+ const { e, write, read, answer } = instantiate(source)
201
+
202
+ return {
203
+ diagnoseMarkup: (html) => answer(e.diagnose_markup_raw(...write(html))),
204
+ diagnosePage: (html) => answer(e.diagnose_page_raw(...write(html))),
205
+ loadManifest: (json) => {
206
+ answer(e.load_manifest_raw(...write(json)))
207
+ },
208
+ loadContract: (json) => {
209
+ answer(e.load_contract_raw(...write(json)))
210
+ },
211
+ version: () => {
212
+ e.version_raw()
213
+ return read()
214
+ },
215
+ buildTheme: (recipe) =>
216
+ answer(e.build_theme_raw(...write(JSON.stringify(recipe)))),
217
+ inspectTheme: (css) => answer(e.inspect_theme_raw(...write(css))),
218
+ inspectStyles: (css) => {
219
+ e.inspect_styles_raw(...write(css))
220
+ return read()
221
+ },
222
+ diagnoseStyled: (html, css, page) =>
223
+ answer(
224
+ e.diagnose_styled_raw(...write(JSON.stringify({ html, css, page }))),
225
+ ),
226
+ }
227
+ }
@@ -0,0 +1,81 @@
1
+ /**
2
+ * The core from the package itself, loaded the first time it is needed, with
3
+ * the package's manifest and colour contract, which sit next to the module.
4
+ *
5
+ * Both the check (`@lo-tek/interfaces/diagnostics`) and the theme
6
+ * (`@lo-tek/interfaces/theme` and `theme-check`) use the same instance.
7
+ */
8
+
9
+ import { type Core, loadCore } from "./core.js"
10
+
11
+ /** The files in the package, seen from both `src/diagnostics/` and `dist/diagnostics/`. */
12
+ const MODULE = new URL("../../core/lotek-core.wasm", import.meta.url)
13
+ const MANIFEST = new URL("../../manifest/manifest.json", import.meta.url)
14
+ const CONTRACT = new URL(
15
+ "../../src/tokens/color-contract.json",
16
+ import.meta.url,
17
+ )
18
+
19
+ let core: Core | undefined
20
+
21
+ /*
22
+ * Loaded the first time it is needed, not when the module is imported:
23
+ * anyone who only wants the types, or `loadCore`, should not pay for it.
24
+ *
25
+ * `node:fs` is fetched with `process.getBuiltinModule` instead of an import,
26
+ * so the file can be bundled for the browser without the bundler looking
27
+ * for `fs`.
28
+ */
29
+ export function defaultCore(): Core {
30
+ if (core) return core
31
+ const fs = globalThis.process?.getBuiltinModule?.("node:fs") as
32
+ | typeof import("node:fs")
33
+ | undefined
34
+ if (!fs) {
35
+ // `getBuiltinModule` arrived in Node 20.16 and 22.3, so Node 21 and 22.0
36
+ // to 22.2 are excluded even though they are newer than 20.16. `engines`
37
+ // in package.json says the same. A Node without it is still Node, and
38
+ // should be told that the version is wrong, with both limits, so Node
39
+ // 22.1 is not told it is older than 20.16.
40
+ const node = globalThis.process?.versions?.node
41
+ throw new Error(
42
+ node
43
+ ? `LO-TEK requires Node 20.16 or later in the 20 series, or Node 22.3 or later, and this is Node ${node}.`
44
+ : "LO-TEK reads the core from the package, which requires Node, Bun or Deno. In the browser, load lotek-core.wasm yourself, pass it to loadCore, and give the core manifest.json with loadManifest and color-contract.json with loadContract.",
45
+ )
46
+ }
47
+ let bytes: Uint8Array
48
+ try {
49
+ bytes = fs.readFileSync(MODULE)
50
+ } catch {
51
+ throw new Error(
52
+ `Could not find the core at ${MODULE.pathname}. In the repository it is built with "bun run core" in interfaces/, which requires Rust.`,
53
+ )
54
+ }
55
+ // The manifest is only needed by the check, and the colour contract only
56
+ // by the theme. Each is read the first time a call needs it.
57
+ const loaded = loadCore(bytes)
58
+ let manifest = false
59
+ let contract = false
60
+ const withManifest = () => {
61
+ if (!manifest) loaded.loadManifest(fs.readFileSync(MANIFEST, "utf8"))
62
+ manifest = true
63
+ return loaded
64
+ }
65
+ const withContract = () => {
66
+ if (!contract) loaded.loadContract(fs.readFileSync(CONTRACT, "utf8"))
67
+ contract = true
68
+ return loaded
69
+ }
70
+ core = {
71
+ ...loaded,
72
+ diagnoseMarkup: (html) => withManifest().diagnoseMarkup(html),
73
+ diagnosePage: (html) => withManifest().diagnosePage(html),
74
+ diagnoseStyled: (html, css, page) =>
75
+ withManifest().diagnoseStyled(html, css, page),
76
+ version: () => withManifest().version(),
77
+ buildTheme: (recipe) => withContract().buildTheme(recipe),
78
+ inspectTheme: (css) => withContract().inspectTheme(css),
79
+ }
80
+ return core
81
+ }
@@ -0,0 +1,150 @@
1
+ /**
2
+ * Checks markup against LO-TEK, outside the browser.
3
+ *
4
+ * `diagnoseMarkup(html)` is the same check the editor extensions run while
5
+ * you type, and that `lotek check` runs on the command line. It is here
6
+ * because markup produced without JavaScript, in a Go template, a Kotlin
7
+ * string or a Razor view, has no compiler looking at the attributes. A test
8
+ * in the app can then run it over the HTML the server actually sends:
9
+ *
10
+ * ```ts
11
+ * import { diagnosePage } from "@lo-tek/interfaces/diagnostics"
12
+ *
13
+ * expect(diagnosePage(html)).toEqual([])
14
+ * ```
15
+ *
16
+ * The check is the core, written in Rust and built to WebAssembly (see
17
+ * `core.ts`). The module ships with the package, and is loaded the first
18
+ * time one of the functions is called, in Node, Bun and Deno. In the
19
+ * browser, or where the module is bundled some other way, `loadCore` loads
20
+ * it.
21
+ */
22
+
23
+ import type { Finding } from "./core.js"
24
+
25
+ export type { Manifest } from "../vocabulary/types.js"
26
+
27
+ import { defaultCore } from "./default-core.js"
28
+
29
+ export {
30
+ type Core,
31
+ type CoreStyles,
32
+ type CoreTheme,
33
+ type CoreThemeReport,
34
+ type CoreVersion,
35
+ type Finding,
36
+ type Fix,
37
+ loadCore,
38
+ type Severity,
39
+ type Violation,
40
+ } from "./core.js"
41
+
42
+ /** Options for the check. */
43
+ export type DiagnoseOptions = {
44
+ /**
45
+ * The stylesheets the page loads, as text. With them the check also
46
+ * reports a class none of them styles, as when the component's stylesheet
47
+ * is not loaded, and a value without a rule, such as a variant added to a
48
+ * taken-over component without the CSS getting it.
49
+ */
50
+ css?: string[]
51
+ }
52
+
53
+ /** Every finding in the text: the vocabulary, for a template or a fragment of a page. */
54
+ export function diagnoseMarkup(
55
+ text: string,
56
+ options: DiagnoseOptions = {},
57
+ ): Finding[] {
58
+ return options.css
59
+ ? defaultCore().diagnoseStyled(text, options.css, false)
60
+ : defaultCore().diagnoseMarkup(text)
61
+ }
62
+
63
+ /**
64
+ * Every finding on a whole page: what `diagnoseMarkup` finds, and also that
65
+ * every `for`, `aria-describedby`, `aria-labelledby` and `aria-controls`
66
+ * points to an id that exists, that no id appears twice, and that every
67
+ * LO-TEK field and every help text and error text is wired.
68
+ *
69
+ * Use it on the HTML the server sends, not on a template: in a template split
70
+ * into pieces, the id can be in another file.
71
+ *
72
+ * ```ts
73
+ * const html = await (await fetch("http://localhost:8080/form")).text()
74
+ * expect(diagnosePage(html)).toEqual([])
75
+ * ```
76
+ */
77
+ export function diagnosePage(
78
+ text: string,
79
+ options: DiagnoseOptions = {},
80
+ ): Finding[] {
81
+ return options.css
82
+ ? defaultCore().diagnoseStyled(text, options.css, true)
83
+ : defaultCore().diagnosePage(text)
84
+ }
85
+
86
+ /** What `diagnoseRendered` needs from a page: `evaluate`, as in Playwright. */
87
+ export type RenderedPage = {
88
+ evaluate<T>(script: () => Promise<T>): Promise<T>
89
+ }
90
+
91
+ /**
92
+ * Reads the rendered page in the browser: the DOM as it stands now, and the
93
+ * text of every stylesheet, with what they import. A stylesheet from another
94
+ * origin, such as a CDN, cannot be read through the CSSOM without
95
+ * `crossorigin`, and is then fetched again with `fetch`.
96
+ *
97
+ * The function runs in the browser, and cannot use anything outside itself.
98
+ */
99
+ export const READ_RENDERED_PAGE = async (): Promise<{
100
+ html: string
101
+ css: string[]
102
+ }> => {
103
+ const sheets: CSSStyleSheet[] = [
104
+ ...document.styleSheets,
105
+ ...document.adoptedStyleSheets,
106
+ ]
107
+ const css: string[] = []
108
+ const read = async (sheet: CSSStyleSheet): Promise<void> => {
109
+ let rules: CSSRuleList
110
+ try {
111
+ rules = sheet.cssRules
112
+ } catch {
113
+ if (!sheet.href) return
114
+ const answer = await fetch(sheet.href)
115
+ if (!answer.ok)
116
+ throw new Error(
117
+ `The stylesheet ${sheet.href} could not be read, and answered ${answer.status} when it was fetched again.`,
118
+ )
119
+ css.push(await answer.text())
120
+ return
121
+ }
122
+ for (const rule of rules)
123
+ if (rule instanceof CSSImportRule && rule.styleSheet)
124
+ await read(rule.styleSheet)
125
+ css.push([...rules].map((rule) => rule.cssText).join("\n"))
126
+ }
127
+ for (const sheet of sheets) await read(sheet)
128
+ const doctype = document.doctype ? `<!DOCTYPE ${document.doctype.name}>` : ""
129
+ return { html: doctype + document.documentElement.outerHTML, css }
130
+ }
131
+
132
+ /**
133
+ * Checks the page as the browser has rendered it, with the stylesheets it
134
+ * has loaded: what `diagnosePage` finds, and what the stylesheets do not
135
+ * style. Markup the web components have added, and a class JavaScript has
136
+ * set, are included.
137
+ *
138
+ * ```ts
139
+ * import { diagnoseRendered } from "@lo-tek/interfaces/diagnostics"
140
+ *
141
+ * await page.goto("http://localhost:8080/form")
142
+ * expect(await diagnoseRendered(page)).toEqual([])
143
+ * ```
144
+ *
145
+ * `page` is a Playwright page, or anything with `evaluate`.
146
+ */
147
+ export async function diagnoseRendered(page: RenderedPage): Promise<Finding[]> {
148
+ const { html, css } = await page.evaluate(READ_RENDERED_PAGE)
149
+ return defaultCore().diagnoseStyled(html, css, true)
150
+ }