@lo-tek/interfaces 0.0.0 → 0.37.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 +3254 -0
  2. package/LICENSE +21 -0
  3. package/README.md +128 -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 +35 -0
  161. package/dist/components/default-texts.d.ts.map +1 -0
  162. package/dist/components/default-texts.js +35 -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 +431 -0
  175. package/dist/components/frame/dialog/lt-dialog.js.map +1 -0
  176. package/dist/components/frame/error-summary/error-summary.d.ts +40 -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 +32 -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 +82 -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 +302 -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 +580 -0
  191. package/dist/components/frame/field/lt-field.js.map +1 -0
  192. package/dist/components/frame/popover/lt-popover.d.ts +132 -0
  193. package/dist/components/frame/popover/lt-popover.d.ts.map +1 -0
  194. package/dist/components/frame/popover/lt-popover.js +490 -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 +573 -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 +361 -0
  209. package/dist/components/frame/suggestion/lt-suggestion.d.ts.map +1 -0
  210. package/dist/components/frame/suggestion/lt-suggestion.js +1152 -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 +404 -0
  217. package/dist/components/frame/tabs/lt-tabs.d.ts.map +1 -0
  218. package/dist/components/frame/tabs/lt-tabs.js +1201 -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 +135 -0
  225. package/dist/components/host-element.d.ts.map +1 -0
  226. package/dist/components/host-element.js +366 -0
  227. package/dist/components/host-element.js.map +1 -0
  228. package/dist/components/standalone/connection-status/connection-status.d.ts +28 -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 +22 -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 +81 -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 +216 -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 +137 -0
  245. package/dist/diagnostics/core.d.ts.map +1 -0
  246. package/dist/diagnostics/core.js +72 -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 +492 -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 +1320 -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 +410 -0
  316. package/dist/vocabulary/elements.js.map +1 -0
  317. package/dist/vocabulary/types.d.ts +175 -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 +62 -0
  326. package/manifest/files.json +373 -0
  327. package/manifest/manifest.json +4965 -0
  328. package/manifest/manifest.schema.json +513 -0
  329. package/package.json +398 -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 +34 -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 +510 -0
  407. package/src/components/frame/error-summary/error-summary.css +47 -0
  408. package/src/components/frame/error-summary/error-summary.ts +56 -0
  409. package/src/components/frame/error-summary/lt-error-summary.ts +344 -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 +753 -0
  413. package/src/components/frame/popover/lt-popover.ts +555 -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 +681 -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 +1358 -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 +1319 -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 +400 -0
  426. package/src/components/standalone/connection-status/connection-status.css +41 -0
  427. package/src/components/standalone/connection-status/connection-status.ts +41 -0
  428. package/src/components/standalone/connection-status/lt-connection-status.ts +242 -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 +210 -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 +1322 -0
  453. package/src/vocabulary/elements.ts +412 -0
  454. package/src/vocabulary/types.ts +178 -0
  455. package/src/wasi-host.ts +155 -0
  456. package/web-types.json +800 -0
package/LICENSE ADDED
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2026 August Søberg-Klyver
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
package/README.md CHANGED
@@ -1,3 +1,130 @@
1
1
  # @lo-tek/interfaces
2
2
 
3
- Placeholder that reserves the name. The first real release is 0.37.0.
3
+ A framework-agnostic design system for the web: tokens, CSS components and web components. Everything is built on things the browser already understands, so the same components work in plain HTML, React, Astro and [Datastar](https://data-star.dev).
4
+
5
+ > LO-TEK is pre-1.0. A minor version can contain breaking changes, and they are listed under "Breaking" (in versions up to 0.36.0, "Brytende") in the [changelog](https://github.com/MarkusAugust/lo-tek/blob/master/interfaces/CHANGELOG.md).
6
+
7
+ The full documentation, with component pages, tokens, patterns and examples for four environments, is at **[lo-tek.sobernetics.no](https://lo-tek.sobernetics.no/)**.
8
+
9
+ **Coding agents** find the rules at [lo-tek.sobernetics.no/llms.txt](https://lo-tek.sobernetics.no/llms.txt), with one rulebook per environment, described under [Coding agents](https://lo-tek.sobernetics.no/coding-agents/). The same rulebooks ship in the package, in `node_modules/@lo-tek/interfaces/agent/`.
10
+
11
+ ## Installation
12
+
13
+ ```bash
14
+ npm install @lo-tek/interfaces
15
+ ```
16
+
17
+ The package has no dependencies. The web components are plain `HTMLElement` classes, and nothing is registered on import alone, so you only pay for what you actually call.
18
+
19
+ ## CSS components
20
+
21
+ A class and a few `data-*` attributes, no JavaScript. `tokens.css` defines the variables everything else builds on, so it has to be loaded. It comes first out of habit; the order makes no difference.
22
+
23
+ With a build step you import only the stylesheets you use, so a page with only buttons does not load CSS for a dialog:
24
+
25
+ ```js
26
+ import "@lo-tek/interfaces/tokens.css"
27
+ import "@lo-tek/interfaces/button.css"
28
+ ```
29
+
30
+ Without a build step you link the combined file, which has everything in it:
31
+
32
+ ```html
33
+ <link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/@lo-tek/interfaces/dist/lotek.css" />
34
+ ```
35
+
36
+ The markup is the same whichever of the two you chose:
37
+
38
+ ```html
39
+ <button class="lt-button">Submit application</button>
40
+ <button class="lt-button" data-variant="secondary">Save draft</button>
41
+ ```
42
+
43
+ ## The attributes as functions
44
+
45
+ `lt` gives the same classes and attributes with completion and type checking in the editor. Each component takes one object of options and returns the attributes:
46
+
47
+ ```js
48
+ import { lt } from "@lo-tek/interfaces"
49
+
50
+ lt.button({ variant: "secondary" })
51
+ // { class: "lt-button", "data-variant": "secondary" }
52
+ ```
53
+
54
+ In React you import from `@lo-tek/interfaces/react`, which gives `className` and `htmlFor` instead of the HTML names:
55
+
56
+ ```jsx
57
+ import { lt } from "@lo-tek/interfaces/react"
58
+
59
+ <button {...lt.button({ variant: "secondary" })}>Save draft</button>
60
+ ```
61
+
62
+ ## Web components
63
+
64
+ Nothing is registered on import alone. You call `defineLt*` yourself, so you decide when the element exists:
65
+
66
+ ```js
67
+ import { defineLtToast } from "@lo-tek/interfaces/toast"
68
+ import "@lo-tek/interfaces/tokens.css"
69
+ import "@lo-tek/interfaces/toast.css"
70
+
71
+ defineLtToast()
72
+ ```
73
+
74
+ ```html
75
+ <lt-toast class="lt-toast" role="status" aria-live="polite" aria-atomic="false"
76
+ aria-label="Notifications" data-ignore-morph></lt-toast>
77
+ ```
78
+
79
+ Every `defineLt*` also takes a tag name of your choice, such as `defineLtToast("app-toast")`, and repeated calls are harmless, also alongside `defineLt()`. The stylesheets are still written for the `lt-*` names: an `<lt-field>` registered as `<my-field>` still wires the label to the field, but the `display` rule on the element name does not follow, `<lt-tabs>` and `<lt-suggestion>` do not hide their content before registration, and `<lt-dialog>` no longer positions a dialog that is open before it is modal. The four that set their class themselves, `<lt-toast>`, `<lt-session-timeout>`, `<lt-connection-status>` and `<lt-error-summary>`, look the same under another name.
80
+
81
+ ## The server writes the markup
82
+
83
+ LO-TEK is built for apps where the HTML comes from the server, whether that is TanStack Start, React Server Components or Datastar. No web component creates nodes in markup the server has sent, because the surrounding framework would tear them out again on the next update.
84
+
85
+ The builder functions in `lt` give the markup, the components give the behaviour, and the two do not overlap:
86
+
87
+ ```js
88
+ import { lt } from "@lo-tek/interfaces"
89
+
90
+ lt.errorSummary({ count: 2, id: "errors" })
91
+ // { host: { class: "lt-error-summary", role: "alert", tabindex: "-1", id: "errors" },
92
+ // title: { class: "lt-error-summary__title" } }
93
+ ```
94
+
95
+ `id` is required in `lt.field()`, `lt.suggestion()`, `lt.tabs()` and `lt.popover()`, and `titleId` in `lt.dialog()`. `lt.tabs()` and `lt.suggestion()` also take `keys`, one key from the data per tab or option, and `lt.tabs()` requires `label`, the name of the tab list. The reason is hydration: if the function creates the id itself, the server and the browser each create their own, and the wiring between the parts is broken until React has corrected it. In React it comes from `useId()`. In `lt.errorSummary()` it is optional, since it only names the box so that something else can point to it.
96
+
97
+ The full reasoning, with the tests behind it, is on [Markup and behaviour](https://lo-tek.sobernetics.no/markup-and-behaviour/).
98
+
99
+ ## Your own colour theme
100
+
101
+ The CLI creates a complete theme from your brand colours, with the contrast requirements computed in OKLCH:
102
+
103
+ ```bash
104
+ npx @lo-tek/interfaces theme --accent=#7c3aed --danger=#b3261e \
105
+ --success=#2b6940 --warning=#8a5a00 --neutral=#1a1a1a --out=theme.css
106
+ ```
107
+
108
+ If customising through CSS is not enough, `takeover` copies the source code of one component into your project, with the imports rewritten:
109
+
110
+ ```bash
111
+ npx @lo-tek/interfaces takeover button --out=src/ui
112
+ ```
113
+
114
+ `npx @lo-tek/interfaces --help` shows the rest.
115
+
116
+ ## Customising
117
+
118
+ The components are in `@layer lotek`, so your own rules win without `!important`. If you embed a component in a page you do not control, `data-lt-boundary` on the root element gives LO-TEK its styles back where the host's unlayered CSS would otherwise take them; see Customising in the documentation. Shape and size are read from `--lt-*` variables with the token value as fallback:
119
+
120
+ ```css
121
+ .lt-button {
122
+ --lt-button-padding: var(--lt-spacing-3) var(--lt-spacing-6);
123
+ }
124
+ ```
125
+
126
+ Tailwind is optional. The theme is a plain CSS file, `@lo-tek/interfaces/tailwind.css`, so the package has no dependency on Tailwind and cannot conflict with your version.
127
+
128
+ ## Licence
129
+
130
+ MIT
package/agent/astro.md ADDED
@@ -0,0 +1,400 @@
1
+ # LO-TEK in Astro
2
+
3
+ The rulebook for LO-TEK in an Astro project.
4
+
5
+ An `.astro` file is HTML with frontmatter above it. The stylesheets are
6
+ imported there, and the builder functions are used directly in the template,
7
+ since Astro supports spreading like JSX. What is particular is that all of
8
+ this runs at build time: out comes plain HTML, and `lt` is gone once the page
9
+ is built. The only JavaScript the browser gets from the package is the
10
+ registration of the web components you use, in a `<script>`.
11
+
12
+ This is @lo-tek/interfaces 0.37.0. The file is generated by the package and
13
+ follows its version, so it can never say anything other than the code next to
14
+ it.
15
+
16
+ ## Short version
17
+
18
+ 1. **Import the stylesheets in the frontmatter**, `tokens.css` first. Without
19
+ them, the components look unstyled. The answer is then to add the import,
20
+ never to write your own CSS to make them look right.
21
+ 2. **Use only the classes and elements in the tables below.** `lt-modal`,
22
+ `lt-datepicker` and `data-variant="outlined"` exist in other design
23
+ systems, not in LO-TEK. If you are unsure whether something exists, it is
24
+ listed here or it does not exist.
25
+ 3. **No hard-coded colours or pixels.** `var(--lt-color-…)` and
26
+ `var(--lt-spacing-…)`.
27
+ 4. **`defineLt*()` belongs in a `<script>` in the template, never in the
28
+ frontmatter:** the frontmatter runs at build time, or on the server when a
29
+ page is rendered on demand, and `customElements` exists in neither. And a
30
+ boolean attribute is true as long as it is there.
31
+ 5. **Run the check on what you have written:**
32
+ `npx @lo-tek/interfaces check src/pages/*.astro`. It knows every class,
33
+ every element, every attribute and every allowed value, prints
34
+ `file:line:column: error: message`, or `warning:`, and exits with an error
35
+ code if it finds anything. It reads the file as text, so it does not see
36
+ what a spread such as `{...lt.button()}` writes; the check on the running
37
+ page below does. With the app running, also check every page you have
38
+ changed: `npx @lo-tek/interfaces check http://localhost:4321/page`. That
39
+ also requires every `for` and `aria-describedby` to point to an id that
40
+ exists, and every field to have a label. You are done when both answer "The
41
+ markup matches LO-TEK".
42
+
43
+ ## 1. The stylesheets
44
+
45
+ `tokens.css` defines all the variables, and all the other stylesheets build on
46
+ it. It must be loaded, and comes first out of habit: the order between it and
47
+ the others does not matter. The imports go in the frontmatter:
48
+
49
+ ```astro
50
+ ---
51
+ import "@lo-tek/interfaces/tokens.css"
52
+ import "@lo-tek/interfaces/button.css"
53
+ import "@lo-tek/interfaces/badge.css"
54
+ ---
55
+ ```
56
+
57
+ The name of each stylesheet is in the tables below. If you have a layout
58
+ component, `tokens.css` belongs there, once for the whole page.
59
+
60
+ ## 2. What exists
61
+
62
+ 35 CSS components and 9 web components, and this is the whole list. The
63
+ classes are `lt-` + kebab-case. Variants are always `data-*` attributes, never
64
+ classes of their own: `data-variant="secondary"`, not `lt-button--secondary`.
65
+ The default variant has no attribute.
66
+
67
+ ### CSS components (no JavaScript)
68
+
69
+ | Class | Stylesheet | Attributes |
70
+ | --- | --- | --- |
71
+ | `lt-accordion`<br>`lt-accordion__content` | `@lo-tek/interfaces/accordion.css` | `data-variant`: plain |
72
+ | `lt-alert`<br>`lt-alert__title` | `@lo-tek/interfaces/alert.css` | `data-color`: info, success, warning, danger |
73
+ | `lt-avatar`<br>`lt-avatar-stack` | `@lo-tek/interfaces/avatar.css` | `data-variant`: square<br>`data-size`: small, large |
74
+ | `lt-badge` | `@lo-tek/interfaces/badge.css` | `data-color`: success, warning, danger, neutral |
75
+ | `lt-breadcrumbs` | `@lo-tek/interfaces/breadcrumbs.css` | none |
76
+ | `lt-button` | `@lo-tek/interfaces/button.css` | `data-variant`: secondary, ghost, danger |
77
+ | `lt-card`<br>`lt-card__title` | `@lo-tek/interfaces/card.css` | `data-variant`: filled<br>`data-interactive` (flag) |
78
+ | `lt-checkbox`<br>`lt-checkbox-row` | `@lo-tek/interfaces/checkbox.css` | `data-state`: invalid, success |
79
+ | `lt-divider` | `@lo-tek/interfaces/divider.css` | `data-variant`: subtle, strong |
80
+ | `lt-error-text` | `@lo-tek/interfaces/error-text.css` | `data-variant`: warning |
81
+ | `lt-fieldset`<br>`lt-legend` | `@lo-tek/interfaces/fieldset.css` | `data-state`: invalid, success<br>`data-required`: symbol, text<br>`data-optional` (flag) |
82
+ | `lt-file-upload`<br>`lt-file-upload-list` | `@lo-tek/interfaces/file-upload.css` | `data-state`: invalid, success |
83
+ | `lt-heading` | `@lo-tek/interfaces/heading.css` | `data-size`: xs, s, m, xl, mega |
84
+ | `lt-help-text` | `@lo-tek/interfaces/help-text.css` | `data-variant`: strong, success, warning |
85
+ | `lt-icon` | `@lo-tek/interfaces/icon.css` | none |
86
+ | `lt-input` | `@lo-tek/interfaces/input.css` | `data-state`: invalid, success<br>`data-variant`: date, datetime-local, time |
87
+ | `lt-label` | `@lo-tek/interfaces/label.css` | `data-required`: symbol, text<br>`data-optional` (flag) |
88
+ | `lt-link` | `@lo-tek/interfaces/link.css` | none |
89
+ | `lt-list` | `@lo-tek/interfaces/list.css` | `data-variant`: plain, divided |
90
+ | `lt-pagination`<br>`lt-pagination__gap` | `@lo-tek/interfaces/pagination.css` | none |
91
+ | `lt-paragraph` | `@lo-tek/interfaces/paragraph.css` | `data-variant`: lead<br>`data-size`: small, large |
92
+ | `lt-progress` | `@lo-tek/interfaces/progress.css` | `data-color`: success, warning, danger |
93
+ | `lt-radio`<br>`lt-radio-row` | `@lo-tek/interfaces/radio.css` | `data-state`: invalid, success |
94
+ | `lt-search`<br>`lt-search-row` | `@lo-tek/interfaces/search.css` | `data-state`: invalid, success |
95
+ | `lt-select` | `@lo-tek/interfaces/select.css` | `data-state`: invalid, success<br>`data-picker`: styled |
96
+ | `lt-skeleton` | `@lo-tek/interfaces/skeleton.css` | `data-variant`: text, circle |
97
+ | `lt-skip-link` | `@lo-tek/interfaces/skip-link.css` | none |
98
+ | `lt-spinner` | `@lo-tek/interfaces/spinner.css` | `data-size`: small, large |
99
+ | `lt-sr-only` | `@lo-tek/interfaces/sr-only.css` | none |
100
+ | `lt-switch`<br>`lt-switch-row` | `@lo-tek/interfaces/switch.css` | none |
101
+ | `lt-table`<br>`lt-table__sort`<br>`lt-table-scroll` | `@lo-tek/interfaces/table.css` | `data-variant`: striped<br>`data-hoverable` (flag) |
102
+ | `lt-tag` | `@lo-tek/interfaces/tag.css` | `data-variant`: filled<br>`data-selectable` (flag) |
103
+ | `lt-textarea` | `@lo-tek/interfaces/textarea.css` | `data-state`: invalid, success |
104
+ | `lt-toggle-group`<br>`lt-toggle-group__option` | `@lo-tek/interfaces/toggle-group.css` | none |
105
+ | `lt-tooltip`<br>`lt-tooltip__bubble` | `@lo-tek/interfaces/tooltip.css` | none |
106
+
107
+ There is also `lt-theme-control`, a class on a radio button that lets the user
108
+ choose a theme. It is in `tokens.css`, and is described under Tokens.
109
+
110
+ ## 3. Tokens
111
+
112
+ One layer. A colour is a cell in a matrix of **family**, that is, what it
113
+ means, and **role**, that is, what it does, and the name is
114
+ `--lt-color-<family>-<role>`. Every family has every role, so
115
+ `--lt-color-danger-border` and `--lt-color-success-border` both exist. The
116
+ roles are the same whatever the family: `surface` is a tinted surface, `fill`
117
+ a filled one, `content` the text on top of `fill`, `border` a border, and
118
+ `text` the family's colour as text. Border and text each have a weaker and a
119
+ stronger step next to them.
120
+
121
+ ```
122
+ Families: `accent`, `visited`, `brand1`, `brand2`, `brand3`, `neutral`, `danger`, `warning`, `success`.
123
+
124
+ Roles: `surface`, `border-subtle`, `border`, `border-strong`, `fill`, `text`, `text-strong`, `text-subtle`, `content`.
125
+
126
+ Outside the matrix: `--lt-color-disabled-surface`, `--lt-color-disabled-text`, `--lt-color-neutral-canvas`, `--lt-color-neutral-raised`, `--lt-color-overlay`, `--lt-focus-ring`, `--lt-icon-calendar`, `--lt-icon-check`, `--lt-icon-clock`, `--lt-icon-dash`, `--lt-icon-search`, `--lt-shadow-overlay`.
127
+ ```
128
+
129
+ Spacing: `--lt-spacing-0-5`, `--lt-spacing-1`, `--lt-spacing-10`,
130
+ `--lt-spacing-12`, `--lt-spacing-16`, `--lt-spacing-2`, `--lt-spacing-3`,
131
+ `--lt-spacing-4`, `--lt-spacing-5`, `--lt-spacing-6`, `--lt-spacing-7`,
132
+ `--lt-spacing-8`, `--lt-spacing-px`.
133
+
134
+ Font: `--lt-font-size-l`, `--lt-font-size-m`, `--lt-font-size-mega`,
135
+ `--lt-font-size-reference`, `--lt-font-size-s`, `--lt-font-size-xl`,
136
+ `--lt-font-size-xs`, `--lt-font-size-xxl`, `--lt-font-size-xxs`,
137
+ `--lt-font-weight-bold`, `--lt-font-weight-medium`,
138
+ `--lt-font-weight-regular`, `--lt-font-weight-semibold`.
139
+
140
+ Line height: `--lt-line-height-article`, `--lt-line-height-compact`,
141
+ `--lt-line-height-default`, `--lt-line-height-heading`.
142
+
143
+ `disabled` and `neutral` are not the same. `disabled` is for controls that are
144
+ turned off, and is exempt from the contrast requirement in WCAG 1.4.3.
145
+ `neutral` is for subdued information the user actually has to read or press,
146
+ and holds 4.5:1. Never use the `disabled` colours to subdue something that is
147
+ meant to be read.
148
+
149
+ ### Light and dark
150
+
151
+ Without you doing anything, the colours follow the device's setting. A page
152
+ that wants to decide for itself sets `data-theme="light"` or
153
+ `data-theme="dark"` on `<html>`.
154
+
155
+ The attribute is a **theme boundary** and works on any element, not only on
156
+ the root. One theme can sit inside another, both ways.
157
+
158
+ This is what an embedded component should use. When you put LO-TEK into a page
159
+ you do not control, set the attribute on the component's own root element:
160
+
161
+ ```html
162
+ <div data-theme="light">
163
+ <button class="lt-button">Save</button>
164
+ </div>
165
+ ```
166
+
167
+ The component is then light whatever the device is set to, and the host is
168
+ left alone.
169
+
170
+ **The host's CSS stops at the boundary.** The host often has rules without a
171
+ layer, such as `button { background: none; border: none }` or a normalize, and
172
+ they beat `@layer lotek`. In that case, set `data-lt-boundary` on the same
173
+ root element:
174
+
175
+ ```html
176
+ <div data-lt-boundary data-theme="light">
177
+ <button class="lt-button">Save</button>
178
+ </div>
179
+ ```
180
+
181
+ Below the root element the browser then ignores the host's CSS without a
182
+ layer, unless a rule of the host's wins on specificity as described below, and
183
+ LO-TEK's layer applies again. The rule is in `lotek.css` and in
184
+ `@lo-tek/interfaces/boundary.css`. Fonts and other inherited properties still
185
+ come from the host, and the `--lt-*` variables work. Three things follow from
186
+ it:
187
+
188
+ - Your own CSS inside the boundary must be in a layer after `lotek`. CSS
189
+ without a layer disappears there in the same way as the host's.
190
+ - Elements without a LO-TEK class lose the host's CSS without a layer. A layer
191
+ the host has declared before `lotek`, such as Tailwind's Preflight in
192
+ `base`, still applies where LO-TEK sets nothing.
193
+ - The boundary has the specificity (0,2,0). A rule from the host with the same
194
+ specificity wins if it is loaded after the boundary, and one with more
195
+ always wins. So do `!important` and layers the host has declared after
196
+ `lotek`.
197
+
198
+ LO-TEK sets `color-scheme` only where someone has chosen a theme: on
199
+ `[data-theme="light"]`, on `[data-theme="dark"]` and on the options of the
200
+ theme picker below. Bare `:root` never gets it. The property controls the
201
+ browser's own surfaces, that is, scrollbars, dropdowns and calendar panels,
202
+ and it is inherited. A child can opt out with `color-scheme: normal`, but that
203
+ is a counter-rule the host never asked to have to write: with the value on the
204
+ root, it applied to the whole document, including where the package is only a
205
+ guest. If the whole page should follow the system, write
206
+ `color-scheme: light dark` on `<html>` yourself, in the same way as you set
207
+ the layer order yourself.
208
+
209
+ ### Letting the user choose a theme
210
+
211
+ `lt-theme-control` on a radio button makes `value` a theme choice. It is plain
212
+ CSS, without a line of JavaScript:
213
+
214
+ ```html
215
+ <fieldset class="lt-toggle-group">
216
+ <legend class="lt-sr-only">Theme</legend>
217
+ <label class="lt-toggle-group__option">
218
+ <input class="lt-theme-control" type="radio" name="theme"
219
+ value="auto" checked /> Follow the system
220
+ </label>
221
+ <label class="lt-toggle-group__option">
222
+ <input class="lt-theme-control" type="radio" name="theme"
223
+ value="light" /> Light
224
+ </label>
225
+ <label class="lt-toggle-group__option">
226
+ <input class="lt-theme-control" type="radio" name="theme"
227
+ value="dark" /> Dark
228
+ </label>
229
+ </fieldset>
230
+ ```
231
+
232
+ The choice controls two things. LO-TEK's colours come from the tokens, and the
233
+ browser's **own** surfaces from `color-scheme`: `light` gives `light`, `dark`
234
+ gives `dark`, and `auto` gives `light dark`. `light dark` is not a theme, but
235
+ the statement that the page works in both, so the browser can choose by the
236
+ system.
237
+
238
+ "Follow the system" has no theme block, and that is on purpose: a value
239
+ without a block matches nothing, and then the media query applies again.
240
+
241
+ Do not write `color-scheme` yourself when the picker is in use. Such a rule
242
+ outside a layer beats `@layer lotek` and locks the browser's surfaces to the
243
+ system while the user has chosen something else.
244
+
245
+ `light` and `dark` win over `data-theme` on `<html>`, so the server can send
246
+ the stored choice while a click still takes effect before the response is
247
+ back. `auto` does not: it means "no override from me", so if the server has
248
+ written `data-theme`, the server's value stands. For "follow the system" to
249
+ work at once, whatever stores the choice must also remove the attribute.
250
+
251
+ Two things it does not do. It **stores nothing**: submit the group in a form
252
+ and store the choice in a cookie the server reads, or in `localStorage`. And
253
+ it must be in the **same tree as `<html>`**, since `:has()` does not see out
254
+ of its own tree; a control inside a shadow root does not set the theme on the
255
+ page.
256
+
257
+ ## 4. Web components
258
+
259
+ Three rules apply to all of them:
260
+
261
+ 1. **`defineLt*()` runs once** in a `<script>` in the template. Astro bundles
262
+ `<script>` tags and runs them on the client. The import has no side effect
263
+ on its own; it is the `define` call that registers the element.
264
+ 2. **Boolean attributes are true as long as they are present.**
265
+ `hidden="false"`, `disabled="false"` and `open="false"` turn it *on*. To
266
+ turn any of them off, remove the attribute entirely.
267
+ 3. **You write the markup, the component adds the behaviour.** `<lt-field>`
268
+ does not create your label or your control. You write `for` on the label
269
+ and `id` on the control, or wrap the control in a `<label>`, so the field
270
+ has a name without JavaScript too. The component wires the help text and
271
+ the error text with `aria-describedby` and `aria-invalid`, and never writes
272
+ an id on the control: an id the server did not send makes an update from
273
+ the server replace the field, with the focus and what the user has typed.
274
+ The field is invalid when the error text is there without `hidden`.
275
+
276
+ | Element | Category | Stylesheet | Registration | Attributes | Events | Classes inside |
277
+ | --- | --- | --- | --- | --- | --- | --- |
278
+ | `<lt-field>` | frame | `@lo-tek/interfaces/field.css` | `defineLtField()` from `@lo-tek/interfaces/field` | `disabled` (flag)<br>`optional` (flag)<br>`described-by` (text) | none | none |
279
+ | `<lt-tabs>` | frame | `@lo-tek/interfaces/tabs.css` | `defineLtTabs()` from `@lo-tek/interfaces/tabs` | `server-controlled` (flag)<br>`activation`: manual, automatic | `tab-select` (index) | `lt-tabs__list`<br>`lt-tabs__panel` |
280
+ | `<lt-error-summary>` | frame | `@lo-tek/interfaces/error-summary.css` | `defineLtErrorSummary()` from `@lo-tek/interfaces/error-summary` | `data-autofocus`: false, true<br>`hidden` (flag) | none | `lt-error-summary`<br>`lt-error-summary__title` |
281
+ | `<lt-popover>` | frame | `@lo-tek/interfaces/popover.css` | `defineLtPopover()` from `@lo-tek/interfaces/popover` | `open` (flag)<br>`placement`: bottom-start, bottom-end, top-start, top-end<br>`server-controlled` (flag) | `popover-toggle` (open) | `lt-popover` |
282
+ | `<lt-suggestion>` | frame | `@lo-tek/interfaces/suggestion.css` | `defineLtSuggestion()` from `@lo-tek/interfaces/suggestion` | `prefiltered` (flag)<br>`count-none` (text)<br>`count-zero` (text)<br>`count-one` (text)<br>`count-two` (text)<br>`count-few` (text)<br>`count-many` (text)<br>`count-other` (text)<br>`server-controlled` (flag) | `suggestion-select` (value, label) | `lt-suggestion__list`<br>`lt-suggestion__option`<br>`lt-suggestion__value`<br>`lt-suggestion__empty` |
283
+ | `<lt-dialog>` | frame | `@lo-tek/interfaces/dialog.css` | `defineLtDialog()` from `@lo-tek/interfaces/dialog` | `open` (flag)<br>`server-controlled` (flag) | `dialog-toggle` (open, returnValue) | `lt-dialog` (`data-color`: brand, info, success, warning, danger)<br>`lt-dialog__body`<br>`lt-dialog__title`<br>`lt-dialog__footer`<br>`lt-dialog__header`<br>`lt-dialog__subtitle` |
284
+ | `<lt-toast>` | standalone | `@lo-tek/interfaces/toast.css` | `defineLtToast()` from `@lo-tek/interfaces/toast` | `duration` (number)<br>`label` (text)<br>`close-label` (text) | `toast-dismiss` | `lt-toast`<br>`lt-toast__message`<br>`lt-toast__close` |
285
+ | `<lt-session-timeout>` | frame | `@lo-tek/interfaces/session-timeout.css` | `defineLtSessionTimeout()` from `@lo-tek/interfaces/session-timeout` | `warn-at` (number)<br>`expires-at` (number)<br>`activity-interval` (number) | `session-warn`<br>`session-extend`<br>`session-logout`<br>`session-expired`<br>`session-activity` | `lt-session-timeout`<br>`lt-session-timeout__dialog`<br>`lt-session-timeout__title`<br>`lt-session-timeout__text`<br>`lt-session-timeout__count`<br>`lt-session-timeout__actions` |
286
+ | `<lt-connection-status>` | standalone | `@lo-tek/interfaces/connection-status.css` | `defineLtConnectionStatus()` from `@lo-tek/interfaces/connection-status` | `offline-text` (text)<br>`online-text` (text) | `connection-lost`<br>`connection-restored` | `lt-connection-status`<br>`lt-connection-status__bar` |
287
+
288
+ None of them uses shadow DOM. The content is in plain DOM, so `querySelector`,
289
+ `FormData` and ordinary CSS work straight into it.
290
+
291
+ ## 5. The builder functions in the template
292
+
293
+ ```astro
294
+ ---
295
+ import { lt } from "@lo-tek/interfaces"
296
+ import "@lo-tek/interfaces/tokens.css"
297
+ import "@lo-tek/interfaces/button.css"
298
+ import "@lo-tek/interfaces/badge.css"
299
+ ---
300
+
301
+ <button {...lt.button({ variant: "secondary" })}>Save draft</button>
302
+ <span {...lt.badge({ color: "success" })}>Approved</span>
303
+ ```
304
+
305
+ Runs at build time. Out comes plain HTML:
306
+
307
+ ```html
308
+ <button class="lt-button" data-variant="secondary">Save draft</button>
309
+ <span class="lt-badge" data-color="success">Approved</span>
310
+ ```
311
+
312
+ `lt` is imported from the main entry, which gives `class` and `for`. The 46
313
+ builder functions:
314
+
315
+ `lt.accordion()`, `lt.alert()`, `lt.avatar()`, `lt.badge()`,
316
+ `lt.breadcrumbs()`, `lt.button()`, `lt.card()`, `lt.checkbox()`,
317
+ `lt.connectionStatus()`, `lt.dialog()`, `lt.divider()`, `lt.errorSummary()`,
318
+ `lt.errorText()`, `lt.field()`, `lt.fieldset()`, `lt.fileUpload()`,
319
+ `lt.heading()`, `lt.helpText()`, `lt.icon()`, `lt.input()`, `lt.label()`,
320
+ `lt.legend()`, `lt.link()`, `lt.list()`, `lt.pagination()`, `lt.paragraph()`,
321
+ `lt.popover()`, `lt.progress()`, `lt.radio()`, `lt.search()`, `lt.select()`,
322
+ `lt.sessionTimeout()`, `lt.skeleton()`, `lt.skipLink()`, `lt.spinner()`,
323
+ `lt.srOnly()`, `lt.suggestion()`, `lt.switch()`, `lt.table()`,
324
+ `lt.tableSort()`, `lt.tabs()`, `lt.tag()`, `lt.textarea()`, `lt.toast()`,
325
+ `lt.toggleGroup()`, `lt.tooltip()`
326
+
327
+ ## 6. Fields without JavaScript
328
+
329
+ `lt.field()` works out the wiring between label, control, help text and error
330
+ text in the frontmatter, so that too becomes static HTML:
331
+
332
+ ```astro
333
+ ---
334
+ import { lt } from "@lo-tek/interfaces"
335
+ import "@lo-tek/interfaces/tokens.css"
336
+ import "@lo-tek/interfaces/field.css"
337
+
338
+ const email = lt.field({ id: "email", required: "symbol", help: true, error: true })
339
+ ---
340
+
341
+ <label {...email.label}>Email address</label>
342
+ <input {...lt.input({ type: "email" })} {...email.control} name="email" required />
343
+ <p {...lt.helpText()} {...email.help}>We will send the receipt here.</p>
344
+ <p {...lt.errorText()} {...email.error}>Enter a valid address.</p>
345
+ ```
346
+
347
+ No `<lt-field>`, no runtime.
348
+
349
+ ## 7. Web components in Astro
350
+
351
+ If the field should be able to become invalid while the user is in it, the
352
+ component has to be registered. It wires the error text to the field when it
353
+ shows:
354
+
355
+ ```astro
356
+ ---
357
+ import "@lo-tek/interfaces/tokens.css"
358
+ import "@lo-tek/interfaces/field.css"
359
+ ---
360
+
361
+ <lt-field>
362
+ <label class="lt-label" for="name" data-required="symbol">Full name</label>
363
+ <input class="lt-input" id="name" type="text" name="name" required />
364
+ <p class="lt-error-text" hidden>Enter your name.</p>
365
+ </lt-field>
366
+
367
+ <script>
368
+ import { defineLtField } from "@lo-tek/interfaces/field"
369
+ defineLtField()
370
+ </script>
371
+ ```
372
+
373
+ `customElements` exists only in the browser, so the registration cannot be in
374
+ the frontmatter. A `<script>` in the template is all it takes: the components
375
+ are ordinary web components, and need neither an Astro integration nor a
376
+ `client:` directive.
377
+
378
+ ## Known pitfalls
379
+
380
+ | Symptom | Cause |
381
+ | --- | --- |
382
+ | The styles are missing | `tokens.css` is not loaded. The order between it and the component's stylesheet does not matter |
383
+ | An `<lt-toast>` or `<lt-connection-status>` shows nothing, an `<lt-session-timeout>` never warns, or another component does nothing | The `define` function has not run. `<lt-toast>` and `<lt-connection-status>` create their content themselves and are empty without it, and `<lt-session-timeout>` does not count the time. The markup in the others comes from you and is there regardless, with two exceptions until they are registered. `<lt-tabs>` shows one panel: of those the server left without `hidden`, the one the URL points to, otherwise the first, and under `server-controlled` always the first. `<lt-suggestion>` hides the list |
384
+ | A component speaks English on a page in another language | The text in the markup comes from you, and is written with the app's own translation setup. The few default texts the package has are replaced with `label` and `close-label` on `<lt-toast>`, `offline-text` and `online-text` on `<lt-connection-status>`, `count-none`, `count-one` and `count-other` on `<lt-suggestion>`, and `--lt-label-required-text`, `--lt-label-optional-text` and `--lt-label-required-symbol` in CSS. Numbers and durations follow the nearest `lang`, usually the one on `<html>`. See https://lo-tek.sobernetics.no/translation/ |
385
+ | The error text never shows, and the field counts as valid | `hidden="false"` is set on the error text, and it hides it all the same. The attribute must be removed, not set to `false` |
386
+ | The component does nothing, and nothing says so | The registration is in the frontmatter, which never runs in the browser. It belongs in a `<script>` in the template |
387
+
388
+ ## When CSS is not enough
389
+
390
+ The components are customised with tokens and `--lt-` variables. If that is
391
+ not enough, `npx @lo-tek/interfaces takeover <component>` copies the source
392
+ code of one component into `src/lotek/<component>/`, so the code is yours to
393
+ change. The copy is TypeScript that imports from the package by name, so it
394
+ needs a build step. It is renamed from `lt-` to `app-`, and a
395
+ `lotek-manifest.json` next to it teaches the check the new names:
396
+ `npx @lo-tek/interfaces check --manifest=src/lotek/<component>/lotek-manifest.json <files>`.
397
+ A complete colour theme from your brand colours is made with
398
+ `npx @lo-tek/interfaces theme`.
399
+
400
+ All of this, with live examples: https://lo-tek.sobernetics.no/