@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
package/CHANGELOG.md ADDED
@@ -0,0 +1,3389 @@
1
+ # Changes in @lo-tek/interfaces
2
+
3
+ Version numbers follow [semantic versioning](https://semver.org/). The
4
+ public API is larger than the functions the package exports, so these count
5
+ as breaking changes and require a new major version:
6
+
7
+ - a class name, a `data-*` attribute or an allowed value that disappears or
8
+ changes meaning,
9
+ - any other attribute a builder function writes, `aria-*` included, that
10
+ disappears or changes meaning. What the builder functions write ends up in
11
+ the consumer's markup, where it can be styled and tested against. What a
12
+ web component sets in the browser is not API in the same way: it is
13
+ behaviour, and is fixed as behaviour,
14
+ - a `part` name in a component with shadow DOM,
15
+ - a token name or an `--lt-*` variable,
16
+ - a function or a type in `lt`,
17
+ - an entry in `exports` in `package.json`.
18
+
19
+ New components, new optional attributes, new attributes a builder function
20
+ adds, and fixes that do not change markup come in a new minor version.
21
+ Before 1.0 a minor version can also contain breaking changes, and they are
22
+ listed under a heading of their own, "Breaking". Versions up to and
23
+ including 0.36.0 were written in Norwegian, and list them under "Brytende".
24
+
25
+ ## Unreleased
26
+
27
+ ## 0.38.0 (2026-10-31)
28
+
29
+ ### Breaking
30
+
31
+ - **One rule, `without-name`, replaces `icon-without-name`,
32
+ `control-without-label`, `tab-list-without-name` and
33
+ `field-without-label`.** A `<!-- lotek-ignore-next -->` naming one of the
34
+ four names now has to name `without-name`. The rule is an error, also for
35
+ a field, which was a warning.
36
+
37
+ ### Added
38
+
39
+ - **`lotek check` reports every element a screen reader gets no name for**
40
+ (`without-name`): the roles WAI-ARIA 1.2 says must have one, on LO-TEK's
41
+ classes and elements and on every button and link, and what LO-TEK demands
42
+ beyond that, from `name` on an element, a part or a class in the manifest:
43
+ a tab list, a fieldset, a toggle group, a dialog in `<lt-dialog>` without a
44
+ heading, an error summary without a heading with an id. The name is
45
+ computed as the browsers compute it (AccName 1.2), by the same model the
46
+ accessibility check compares with Chromium and Firefox, and a `<title>` in
47
+ an svg counts (SVG-AAM). Where a binding, a template or another part of
48
+ the page could give the name, the rule says nothing.
49
+ - **`lotek check` warns about LO-TEK's own English texts on a page in
50
+ another language** (`untranslated-text`): `<lt-toast>`,
51
+ `<lt-connection-status>` and the counts in `<lt-suggestion>` without the
52
+ attribute that replaces the text, and, when the style sheets are given,
53
+ " (required)" and " (optional)" on a label or legend without the CSS
54
+ variable. The language is the nearest `lang`. The manifest has
55
+ `textLanguage`, `texts` on the elements and classes, and `name`, which
56
+ `Manifest` in LO-TEK for Kotlin reads as `textLanguage`, `texts` and
57
+ `named`.
58
+
59
+ ### Changed
60
+
61
+ - **`lt.errorSummary()` writes the heading's id and the box's
62
+ `aria-labelledby`.** `titleId` is new, and defaults to the box's `id` with
63
+ `-title`, so `lt.errorSummary({ id: "errors" })` names the box after
64
+ `<h2 id="errors-title">`. As with every option of a builder function,
65
+ `lt.setAttributes()` with a set that has no `aria-labelledby` removes one
66
+ the element had. An empty `titleId` counts as none, and one with whitespace
67
+ throws, in TypeScript and in Kotlin; so does an `id` with whitespace,
68
+ which `lt.errorSummary({ id })` accepted before, since the default
69
+ `titleId` is made from it.
70
+ - **`lt.connectionStatus()` writes `role="status"` and `aria-live="polite"`**
71
+ on the host, the live region; `lt.setAttributes()` sets them over a role
72
+ the element had.
73
+
74
+ ### Fixed
75
+
76
+ - **`<lt-field>` keeps an `aria-invalid` the server writes, and `<lt-tabs>`
77
+ an `aria-selected`, when the value is the one the component had
78
+ written.** The components told the server's word from their own by the
79
+ value, and a morph leaves an attribute whose value is already right, so
80
+ the server's `aria-invalid="true"` was taken for the component's own and
81
+ removed. They now mark what they write that differs from the server, in
82
+ `data-lt-written`, which a morph from the server removes; markup that is
83
+ already right, as React renders it, gets no mark. Found by the new model
84
+ tests, which try every order of server updates and user actions.
85
+ - **`<lt-tabs>` keeps the user's tab when the server inserts a tab before
86
+ it.** Datastar and idiomorph match links without ids by position, and the
87
+ link the user pressed became the inserted tab. The component now finds
88
+ the user's tab by the panel it points to when a morph has moved or
89
+ dropped the link, and still forgets the selection when the links are
90
+ replaced.
91
+ - **`<lt-popover>` puts focus back on the button whatever closes the panel
92
+ with focus in it**: `hide()`, `toggle()`, a click on the button in Safari,
93
+ which gives a clicked button no focus, and the server taking `open`.
94
+ Escape alone did it before, and otherwise the focus was lost to the page.
95
+ A patch that only takes `open` for a moment, while the component puts it
96
+ back, no longer closes and reopens the panel, which took the focus from a
97
+ button in it.
98
+ - **`show()` on a `<lt-popover>` the server opened is remembered**, as
99
+ `open = true` is: the next patch without `open` closed the panel, since
100
+ `show()` returned before the setter that remembers it. `hide()` the same.
101
+ - **`<lt-suggestion>` filters an open list an update changed under
102
+ `server-controlled` too.** The attribute is about whether the list is open
103
+ and what is highlighted, but the repair returned before the filter, so the
104
+ list showed every option the server sent whatever the user had typed, and
105
+ an emptied list kept its empty message hidden.
106
+ - **`<lt-suggestion>` announces a count only for a list that opens.**
107
+ Focusing an empty field over a list with nothing to show announced "No
108
+ matches" for a list that stayed closed. An update that removed
109
+ `prefiltered` counted the options before the morph had replaced them, and
110
+ an update that also locked the field announced the count for a list it
111
+ closed.
112
+ - **`<lt-dialog>` names the dialog after its heading again when an update
113
+ removes `aria-label`.** The component did not watch `aria-label`, and the
114
+ dialog was left without a name until something else changed.
115
+ - **`<lt-dialog>` no longer reports a close for a dialog that never
116
+ opened.** `dialog-toggle` with `open: false` came when the component
117
+ closed a `<dialog open>` it had never shown.
118
+ - **`<lt-session-timeout>` keeps the warning's role and name through an
119
+ update.** A morph of the open warning removed `role="alertdialog"` and
120
+ `aria-labelledby`, which the component had written, and a screen reader
121
+ had a modal dialog without a name until the warning closed.
122
+ - **`<lt-session-timeout>` goes on with a warning the renderer replaced
123
+ while it showed**, as `innerHTML` does: focus goes back to where the user
124
+ was, not to the page, and `session-warn` is not sent a second time.
125
+ - **`<lt-error-summary>` has a name when it takes focus.** The box moves
126
+ focus to itself when a submission fails, and had no name, so a screen
127
+ reader said only "alert". The template writes the heading's `id` and the
128
+ box's `aria-labelledby`, as it writes `for` and `id` on a field, and the
129
+ recipes on the page do. When the heading has an id and the box no name,
130
+ the component points `aria-labelledby` at it, and follows a heading a
131
+ patch has replaced; when the heading has no id, it says so in the console.
132
+ It never writes an id itself: Datastar and idiomorph replace an element
133
+ whose id the server did not send, so the heading would have got a new one
134
+ on every patch. A blank `aria-label` or `aria-labelledby` counts as
135
+ missing.
136
+ - **`<lt-error-summary>` takes focus after an update, not in the middle of
137
+ it.** It moved focus as a morph removed `hidden`, before the morph had
138
+ updated the content, and idiomorph with `ignoreActiveValue` then left the
139
+ content of the focused box as it was: the box showed the previous errors.
140
+ A script that moves focus elsewhere in the same turn keeps it there.
141
+ - **`<lt-error-summary>` lets go of focus when it is hidden**, also from a
142
+ link inside it. In Firefox and WebKit the hidden box kept focus, so the
143
+ next errors never reached it.
144
+ - **`<lt-connection-status>` is announced in Firefox.** The component made
145
+ the bar a live region as it inserted it, and Firefox then sent no
146
+ live-region text through the accessibility API, so "No connection" was
147
+ never read out. The host is now the live region from the moment it is
148
+ connected, with `role="status"` and `aria-live="polite"` when it has
149
+ neither, and the bar is content inside it. A role the server wrote keeps
150
+ its own politeness. A morph that takes both off gets them back.
151
+
152
+ The name, and the announcement in Firefox, were found by
153
+ `check-accessibility-tree.ts`, which reads what a screen reader is given
154
+ through AT-SPI in Chromium and Firefox, against an accessibility contract per
155
+ component; the contracts are shown on the component pages, under
156
+ "Accessibility". The focus fixes were found by
157
+ `lt-error-summary.model.browser.test.ts`, which sends every version of the box
158
+ by Datastar, idiomorph and `outerHTML` in every order and checks the
159
+ accessibility tree the core computes after each step, and by the code review
160
+ of the pull request.
161
+
162
+ ## 0.37.0 (2026-10-26)
163
+
164
+ ### Breaking
165
+
166
+ - **Fristil is now LO-TEK, and everything is in English.** The package, the
167
+ prefix, the API, the command line, the check, the default texts, the
168
+ documentation and its addresses all have new names. Nothing else about the
169
+ architecture changes: the same markup, written with the new prefix, behaves
170
+ as before. The old packages stay where they are. `@fristil/designsystem` is
171
+ deprecated on npm with a pointer to `@lo-tek/interfaces`, and the last
172
+ version of each old Maven artifact carries a relocation to the new one, so
173
+ Maven and Gradle follow it and warn. Nothing is deleted. **How to update:**
174
+ install `@lo-tek/interfaces`, then replace the names in the tables below.
175
+
176
+ | Before | Now |
177
+ |---|---|
178
+ | `@fristil/designsystem` | `@lo-tek/interfaces` |
179
+ | `fristil.sobernetics.no` | `lo-tek.sobernetics.no` (every old address redirects) |
180
+ | `github.com/MarkusAugust/fristil` | `github.com/MarkusAugust/lo-tek` |
181
+ | `fs-button`, `<fs-field>`, every `fs-` class and element | `lt-button`, `<lt-field>`, `lt-` |
182
+ | `--fs-…`, every token and component variable | `--lt-…` |
183
+ | `@layer fristil` | `@layer lotek` (`@layer theme, base, lotek, components, utilities;`) |
184
+ | `fristil-tema` (the theme layer) | `lotek-theme` |
185
+ | `data-fs-boundary` | `data-lt-boundary` |
186
+ | `fs` (the builder object) | `lt` |
187
+ | `defineFs()`, `defineFsField()` and the others | `defineLt()`, `defineLtField()` |
188
+ | `FS_FIELD_TAG`, `FS_FIELD_PARTS` and the others | `LT_FIELD_TAG`, `LT_FIELD_PARTS` |
189
+ | `FsField` and the other classes, `FsEventMap` | `LtField`, `LtEventMap` |
190
+ | `dist/fristil.css` | `dist/lotek.css` (`@lo-tek/interfaces/lotek.css`) |
191
+ | exports `./tema`, `./farge`, `./kontrakt`, `./matrise`, `./tema-sjekk` | `./theme`, `./color`, `./contract`, `./matrix`, `./theme-check` |
192
+ | exports `./fargekontrakt.json`, `./kjerne.wasm` | `./color-contract.json`, `./core.wasm` |
193
+ | source folders `ramme/`, `frittstaende/` (in `lotek takeover`) | `frame/`, `standalone/` |
194
+ | the binary `fristil` | `lotek` |
195
+ | `fristil.tema.json` | `lotek.theme.json` |
196
+ | env `FRISTIL_PACKAGE` | `LOTEK_PACKAGE` |
197
+ | the comment `fristil-ignore-next` | `lotek-ignore-next` |
198
+ | Kotlin `no.fristil`, `Fs`, `Fristil`, `Tag.fs(…)` | `no.lotek`, `Lt`, `Lotek`, `Tag.lt(…)` |
199
+ | Maven `io.github.markusaugust:fristil`, `fristil-kotlinx-html`, `fristil-kommandolinje`, `fristil-gradle-plugin` | `lo-tek-interfaces`, `lo-tek-kotlinx-html`, `lo-tek-cli`, `lo-tek-gradle-plugin` |
200
+ | Gradle plugin `io.github.markusaugust.fristil`, tasks `fristilSjekk`, `fristilTema`, `fristilManifest` | `io.github.markusaugust.lo-tek`, `lotekCheck`, `lotekTheme`, `lotekManifest` |
201
+ | WebJar `webjars/fristil/` | `webjars/lo-tek/` |
202
+ | VS Code `Fristil.fristil-vscode` | `lo-tek.interfaces` ("LO-TEK for VS Code") |
203
+ | IntelliJ `no.fristil` | `no.lotek` ("LO-TEK Interfaces") |
204
+ | rulebook `agent/maler.md` | `agent/templates.md` |
205
+
206
+ - **The command line has English verbs, flags and recipe keys.** There are
207
+ no Norwegian aliases.
208
+
209
+ | Before | Now |
210
+ |---|---|
211
+ | `sjekk`, `sjekk-tema`, `overta`, `tema` | `check`, `check-theme`, `takeover`, `theme` |
212
+ | `--rendret`, `--ut`, `--rammeverk`, `--overskriv=ja`, `--hjelp` | `--rendered`, `--out`, `--framework`, `--overwrite=yes`, `--help` |
213
+ | `--aksent`, `--fare`, `--suksess`, `--advarsel`, `--noytral`, `--besokt`, `--merke1..3` | `--accent`, `--danger`, `--success`, `--warning`, `--neutral`, `--visited`, `--brand1..3` |
214
+ | `--skrift`, `--knapp-hjorner`, `--felt-hjorner`, `--flate-hjorner`, `--knapp-ramme`, `--knapp-vekt` | `--font`, `--button-radius`, `--field-radius`, `--surface-radius`, `--button-border`, `--button-weight` |
215
+ | recipe keys `aksent` … `merke3`, `typografi`, `form` | `accent` … `brand3`, `typography`, `shape` |
216
+
217
+ - **The check's rule ids are English.** A filter or a suppression on an id
218
+ must use the new one.
219
+
220
+ | Before | Now |
221
+ |---|---|
222
+ | `boolsk-med-verdi` | `boolean-with-value` |
223
+ | `deaktivert-med-href` | `disabled-with-href` |
224
+ | `del-flere-ganger` | `part-repeated` |
225
+ | `fane-uten-lenke` | `tab-without-link` |
226
+ | `fanelenke-uten-panel` | `tab-link-without-panel` |
227
+ | `fanerad-uten-navn` | `tab-list-without-name` |
228
+ | `feilmelding-motsier` | `error-text-contradicts` |
229
+ | `felt-uten-kontroll` | `field-without-control` |
230
+ | `felt-uten-ledetekst` | `field-without-label` |
231
+ | `id-fra-komponenten` | `id-from-component` |
232
+ | `ikke-tall` | `not-a-number` |
233
+ | `ikon-uten-navn` | `icon-without-name` |
234
+ | `kontroll-uten-kobling` | `control-without-wiring` |
235
+ | `panel-uten-id` | `panel-without-id` |
236
+ | `tekst-i-ledetekst` | `text-in-label` |
237
+ | `tidsavbrudd-uten-dialog` | `timeout-without-dialog` |
238
+ | `ugyldig-klasseverdi` | `invalid-class-value` |
239
+ | `ugyldig-verdi` | `invalid-value` |
240
+ | `ukjent-attributt` | `unknown-attribute` |
241
+ | `ukjent-element` | `unknown-element` |
242
+ | `ukjent-klasse` | `unknown-class` |
243
+ | `ustylet-klasse` | `unstyled-class` |
244
+ | `ustylet-verdi` | `unstyled-value` |
245
+ | `utgatt-attributt` | `removed-attribute` |
246
+ | `verdi-uten-felt` | `value-without-field` |
247
+ | `duplikat-id` | `duplicate-id` |
248
+ | `id-finnes-ikke` | `id-not-found` |
249
+ | `for-peker-feil` | `for-points-nowhere` |
250
+ | `oppsummering-peker-feil` | `summary-points-nowhere` |
251
+ | `kontroll-uten-ledetekst` | `control-without-label` |
252
+ | `tekst-ikke-koblet` | `text-not-wired` |
253
+
254
+ Every message from the check, the components' console warnings and the
255
+ errors the builder functions throw are in English too.
256
+
257
+ - **The default texts are English.** Each can still be replaced, as before.
258
+
259
+ | Before | Now |
260
+ |---|---|
261
+ | «Varsler» | "Notifications" |
262
+ | «Lukk melding» | "Close message" |
263
+ | «Ingen forbindelse. Det du skriver blir ikke lagret.» | "No connection. What you type is not being saved." |
264
+ | «Forbindelsen er tilbake.» | "Connection restored." |
265
+ | «Ingen treff», «Ett treff», «{n} treff» | "No matches", "One match", "{n} matches" |
266
+ | « (påkrevd)», « (valgfri)» | " (required)", " (optional)" |
267
+
268
+ **How to update:** a Norwegian page that relied on the defaults sets them
269
+ as the translation page shows.
270
+
271
+ - **The documentation is in English, at new addresses.** Every old address
272
+ redirects to its new one, and `/components/…` is unchanged.
273
+
274
+ | Before | Now |
275
+ |---|---|
276
+ | `/introduksjon/`, `/kom-i-gang/`, `/rammeverk/` | `/introduction/`, `/getting-started/`, `/frameworks/` |
277
+ | `/markup-og-oppforsel/`, `/tilpasning/`, `/tilgjengelighet/` | `/markup-and-behaviour/`, `/customising/`, `/accessibility/` |
278
+ | `/oversettelse/`, `/eget-tema/`, `/typesikker-bruk/` | `/translation/`, `/your-own-theme/`, `/type-safe-use/` |
279
+ | `/editoren/`, `/kommandolinjen/`, `/kodeagenter/` | `/the-editor/`, `/command-line/`, `/coding-agents/` |
280
+ | `/lisens/`, `/veikart/`, `/versjonslogg/` | `/licence/`, `/roadmap/`, `/changelog/` |
281
+ | `/monster/skjema/`, `liste`, `sideskjelett`, `bekreftelse`, `dato`, `tema` | `/patterns/form/`, `list`, `page-skeleton`, `confirmation`, `date`, `theme` |
282
+
283
+ ## 0.36.0 (2026-10-25)
284
+
285
+ ### Brytende
286
+
287
+ - **Forslagslista står i det øverste laget.** Den var `position: absolute` i
288
+ `<fs-suggestion>`, og en forelder med `overflow`, som kroppen i en dialog,
289
+ klippet den. Nå er lista `popover="manual"`, og komponenten åpner og lukker
290
+ vinduet etter `hidden`, som fortsatt er det som sier om lista er åpen.
291
+ Komponenten legger den rett under feltet, like bred som det.
292
+ `--fs-suggestion-layer` er tatt ut, siden det øverste laget ligger over alt
293
+ uten `z-index`. **Slik oppdaterer du:** ta bort `--fs-suggestion-layer` fra
294
+ egen CSS. `fs.suggestion()` skriver `popover` selv; skriver du markupen for
295
+ hånd, gjør komponenten det.
296
+ - **En rettelse fra `diagnoseMarkup` er en liste av endringer.** `Fix` har
297
+ `edits`, hver med `start`, `end` og `text`, i tekstens rekkefølge og uten
298
+ overlapp, i stedet for ett `start`, `end` og `text`. Det samme i Kotlin,
299
+ `Fix(title, edits, preferred)` med `Edit`. Grunnen er «Gi feltet id
300
+ «epost»», som skriver `id` på feltet og `for` på ledeteksten under ett.
301
+ **Slik oppdaterer du:** bruk `fix.edits` bakfra, så posisjonene i de
302
+ første holder. Språkserveren og editorene gjør det alt.
303
+ - **Fanene i `<fs-tabs>` er lenker til panelene, ikke knapper.** Raden er en
304
+ `<ul class="fs-tabs__list">` med `<li><a href="#panel">`, og hvert
305
+ `.fs-tabs__panel` har den id-en lenken peker på. Uten JavaScript er raden
306
+ en innholdsfortegnelse, og panelene står etter hverandre under den. Med
307
+ JavaScript skriver komponenten rollene, `aria-selected`, `aria-controls` fra
308
+ `href`, tabbestoppene og `hidden="until-found"` på panelene som ikke er
309
+ valgt, så søk i siden og en lenke til noe inni et panel velger fanen.
310
+ Lenkene har ingen id, og komponenten skriver aldri en, så en oppdatering fra
311
+ serveren kjenner dem igjen og valget står. Hvert valg skrives i adressen,
312
+ som `#sak-vedlegg`, uten ny historikkoppføring, og adressen velger fane når
313
+ siden lastes. En `role="tab"` på noe som ikke er en lenke til et panel, er
314
+ ikke lenger en fane, og komponenten sier fra i konsollen. **Slik oppdaterer
315
+ du:** bytt `<div class="fs-tabs__list">` med knapper til en `<ul>` med
316
+ lenker, gi hvert panel en id og la lenken peke på den.
317
+ - **`fs.tabs()` og `Fs.tabs` tar `keys` i stedet for `count`, og `selected`
318
+ er borte.** Nøklene kommer fra dataene, én per fane, og gir panelene
319
+ `${id}-${nøkkel}` og overskriftene `${id}-${nøkkel}-heading`. En nøkkel som
320
+ er tom, har mellomrom eller står to ganger, kaster, likt i TypeScript og
321
+ Kotlin. Den første fanen er utgangspunktet; et annet valg kommer fra
322
+ adressen, fra `hidden="until-found"` på de andre panelene, eller fra appen
323
+ gjennom `selected` og `select()` på elementet. **Slik oppdaterer du:**
324
+ `fs.tabs({ id, count: 3, selected: 1, label })` blir
325
+ `fs.tabs({ id, keys: ["soknaden", "vedlegg", "meldinger"], label })`.
326
+ - **`fs.tabs()` og `Fs.tabs` skriver bare lenker, id-er og klasser.** `list`
327
+ har klassen og `aria-label`, `tabs` har `href`, `panels` har `id` og
328
+ klassen, og det nye `headings` har `id` til overskriften i hvert panel.
329
+ Ingen roller, `aria-*`, `tabindex` eller `hidden`: uten JavaScript skal
330
+ raden være en liste med lenker, og en `<section>` med navn ville blitt et
331
+ landemerke. Komponenten
332
+ skriver resten når den registreres. **Slik oppdaterer du:** spre
333
+ `faner.tabs[i]` på en `<a>` i en `<li>`, og `faner.headings[i]` på
334
+ overskriften i panelet.
335
+ - **En tom `label` kaster i `fs.tabs()`, i React-inngangen og i `Fs.tabs`.**
336
+ Raden må ha et navn som sier hva fanene velger mellom; uten det sier
337
+ skjermleseren bare «faneliste». `label` sjekkes før `keys`, med samme
338
+ melding i TypeScript og Kotlin. **Slik oppdaterer du:** gi raden et navn,
339
+ som `label: "Deler av saken"`.
340
+ - **`fs.tabs()` i `@fristil/designsystem/react` gir hele tilstanden.** Den tar
341
+ `selected` (standard 0) og skriver rollene, `aria-selected`, `aria-controls`,
342
+ `tabIndex`, `hidden` og `aria-labelledby` fra panelet til lenken, som får id
343
+ `${id}-${nøkkel}-tab`. `item` gir `role="presentation"` til hvert `<li>`.
344
+ Da har komponenten ingenting å skrive når den registreres, og React
345
+ hydrerer uten avvik. `hidden` er boolsk, fordi React 19 skriver
346
+ `hidden="until-found"` som `hidden=""`; søk i siden åpner derfor ikke et
347
+ skjult panel i en React-app. Har markupen `aria-selected` fra serveren,
348
+ gjelder den når siden lastes, og adressen velger ingen fane. **Slik
349
+ oppdaterer du:** importer `fs` fra `@fristil/designsystem/react` og spre
350
+ `faner.item` på `<li>`.
351
+ - **`fs.suggestion()` og `Fs.suggestion` tar `keys` i stedet for `count`.**
352
+ Alternativene får id fra nøkkelen, `${id}-option-${nøkkel}`, ikke fra
353
+ plassen i lista, så en oppdatering fra serveren kjenner dem igjen. Antall
354
+ nøkler avgjør om tommeldingen har `hidden`, som `count` gjorde. Nøklene
355
+ sjekkes som i `fs.tabs()`. **Slik oppdaterer du:**
356
+ `fs.suggestion({ id, count: kommuner.length })` blir
357
+ `fs.suggestion({ id, keys: kommuner.map((k) => k.nr) })`.
358
+
359
+ ### Nytt
360
+
361
+ - **Forslagslista har et navn**, fra ledeteksten. `fs.suggestion()` gir
362
+ ledeteksten id `${id}-label` og lista `aria-labelledby` mot den. Kommer
363
+ markupen uten, gjør komponenten det samme, og står ledeteksten rundt
364
+ feltet, får lista teksten som `aria-label`, uten å skrive id på ledeteksten.
365
+ - **`fs.suggestion({ pending: true })` skriver `aria-busy="true"` på lista**,
366
+ og stilarket skjuler «Ingen treff» mens det står.
367
+ - **Ti regler i kjernen om det malen må skrive selv**, for at komponentene
368
+ skal virke uten JavaScript og overleve en oppdatering fra serveren, i
369
+ `fristil sjekk`, språkserveren, VS Code og IntelliJ: `kontroll-uten-kobling`
370
+ (ledeteksten har verken `for` mot feltet eller står rundt det, med rettelsen
371
+ «Gi feltet id «navn»» fra feltets `name`), `panel-uten-id` i
372
+ `<fs-popover>`, `fanelenke-uten-panel`, `fane-uten-lenke` (`role="tab"` på
373
+ noe som ikke er en lenke), `fanerad-uten-navn` (med rettelse),
374
+ `tekst-i-ledetekst` (hjelpetekst eller feilmelding inni `<label>`),
375
+ `verdi-uten-felt` (`data-value` uten `.fs-suggestion__value`, og omvendt),
376
+ `feilmelding-motsier` (`hidden` på feilmeldingen ved siden av
377
+ `aria-invalid="true"`), `utgatt-attributt` (`invalid`, `required-marker` og
378
+ `control-id` på `<fs-field>`, med rettelse og beskjed om hva som gjelder i
379
+ stedet) og `id-fra-komponenten` (en id komponenten lagde selv, kopiert inn
380
+ fra DevTools; bare i markupmodus). Reglene tier der malen avgjør markupen,
381
+ også ved en bundet id som `:id`, `th:id` eller `asp-for`. Hver bygde side
382
+ i dokumentasjonen gir null funn, også hver forhåndsvisning lest som markup,
383
+ og en vaktpost i bygget krever det.
384
+ - **Manifestet sier hvilke deler som må ha id fra serveren**, `stableId` på
385
+ delen, og hvilke attributter som er tatt ut av et element, `removed` med
386
+ beskjeden. Begge er tillegg; `schemaVersion` er fortsatt 1.
387
+ - **`fs.progress({ valueText })`** skriver `aria-valuetext`, som skjermleseren
388
+ leser i stedet for prosenten: «Steg 3 av 7» sier mer, og `max` leses sjelden
389
+ opp.
390
+ - **Snippetene har id-en som tabbestopp**, og `for` og `href` følger med. Og
391
+ `live-templates.xml` i pakken har de samme oppskriftene som live templates
392
+ for IntelliJ, med id-en som variabel.
393
+
394
+ ### Rettet
395
+
396
+ - **Hvert alternativ i forslagslista har `aria-selected` fra starten.**
397
+ Komponenten skrev det først når lista ble lukket, så alternativene serveren
398
+ sendte, sto uten fram til da, mens resten av lista hadde det.
399
+ - **`<fs-popover>` skriver aldri id på panelet.** Den lagde en når malen ikke
400
+ hadde skrevet en, og Datastar og idiomorph byttet da ut panelet ved neste
401
+ oppdatering, med fokus og det brukeren gjorde i det. Nå beholdes panelet.
402
+ Uten id kan knappen ikke kobles til panelet med `aria-controls`, og
403
+ komponenten sier fra i konsollen. Byttes panelet ut mens det står åpent
404
+ fordi id-en fra serveren endret seg, sier komponenten også fra, som
405
+ `<fs-field>` gjør. Oppskriften har id på panelet og merker ingen forskjell.
406
+ - **`server-controlled` satt etter et klikk lot ikke serveren flytte fanen
407
+ med bare `hidden`.** `aria-selected` komponenten selv hadde skrevet, ble
408
+ regnet som serverens ord. Nå gjør komponenten det samme som når serveren
409
+ svarer på et klikk, og attributtet kan også fjernes igjen mens siden lever.
410
+ - **Søk i siden velger fanen også i faner i faner.** Komponenten venter til
411
+ nettleseren er ferdig med å avdekke treffet før den skriver raden; før
412
+ stoppet Chromium og WebKit før det ytre panelet.
413
+ - **Serverens `aria-selected` vinner over adressen når siden lastes.** En
414
+ React-app rendrer på serveren uten å se fragmentet, og valgte komponenten
415
+ fra adressen før React hydrerte, meldte React avvik. Peker adressen på en
416
+ annen fane i raden, rettes den til den valgte.
417
+ - **`hidden` skrives tilbake i formen serveren brukte**, `hidden=""` eller
418
+ `hidden="until-found"`, og i én form per rad.
419
+ - **Før registrering viser `tabs.css` panelet adressen peker på**, eller
420
+ panelet med det inni, i stedet for alltid det første, så innholdet ikke
421
+ hopper når komponenten registreres. Serverens `hidden` går foran, og under
422
+ `server-controlled` vises det første. Regelen står bak
423
+ `@media (scripting: enabled)`: uten JavaScript vises alle panelene.
424
+
425
+ ## 0.35.0 (2026-10-22)
426
+
427
+ ### Brytende
428
+
429
+ - **`<fs-field>` og `<fs-suggestion>` skriver aldri id på feltet.** Datastar
430
+ og idiomorph kjenner igjen et element på id, og et felt med en id serveren
431
+ ikke sendte, ble byttet ut ved neste oppdatering, med fokus og det brukeren
432
+ hadde skrevet. Nå er det malen som skriver `for` på ledeteksten og `id` på
433
+ feltet, som HTML uansett krever for at feltet skal ha et navn før skriptet
434
+ har kjørt, eller som legger ledeteksten rundt feltet. Komponenten skriver
435
+ `for` fra feltets id når ledeteksten ikke står rundt feltet. Et felt uten id
436
+ med ledeteksten ved siden av gir en advarsel i konsollen. Hjelpeteksten,
437
+ feilmeldingen, lista og alternativene får fortsatt id av komponenten når de
438
+ mangler: byttes de ut, kobler komponenten dem på nytt, og det markerte
439
+ alternativet gjenfinnes på teksten. **Slik oppdaterer du:** skriv `for` og
440
+ `id` i malen, eller legg `<label>` rundt feltet.
441
+ - **`invalid`, `required-marker` og `control-id` er tatt ut av `<fs-field>`.**
442
+ Feltet er ugyldig når feilmeldingen synes, altså har tekst og står uten
443
+ `hidden` og uten `display: none` (som `data-show` i Datastar setter), eller
444
+ når serveren har skrevet `aria-invalid` på feltet. Komponenten rører aldri
445
+ `hidden` på feilmeldingen; før skjulte den en feilmelding serveren hadde
446
+ rendret synlig, fordi verten manglet `invalid`. Påkrevd-merket står som
447
+ `data-required` på ledeteksten, og vises da også uten JavaScript.
448
+ `control-id` fikk komponenten til å skrive en id serveren ikke sendte.
449
+ **Slik oppdaterer du:** `<fs-field invalid>` blir en synlig `.fs-error-text`
450
+ (i Datastar `data-attr:hidden="!$ugyldig"` på feilmeldingen framfor
451
+ `data-attr:invalid` på verten), `required-marker="x"` blir
452
+ `data-required="x"` på `<label>`, og `control-id` blir `id` på feltet.
453
+ Egenskapene `invalid`, `requiredMarker` og `controlId` er borte, og
454
+ React-typene i `react-jsx` er oppdatert.
455
+ - **`<fs-suggestion>` viser alltid teksten i feltet.** Før skrev den
456
+ `data-value` inn i det synlige feltet, så brukeren som valgte Bergen, så
457
+ «4601», og skjemaet sendte koden under feltets `name`. Nå får et skjult
458
+ `.fs-suggestion__value` koden når serveren har skrevet det, og
459
+ `suggestion-select` har både `value` og `label`. Tilbakestilles skjemaet,
460
+ følger koden teksten: serverens når teksten er serverens, ellers det
461
+ valgte, ellers alternativet med den teksten, ellers ingen. **Slik
462
+ oppdaterer du:**
463
+ skal skjemaet sende koden, legg inn `<input class="fs-suggestion__value"
464
+ type="hidden" name="…">`, eller les `evt.detail.value`.
465
+ - **`.fs-suggestion__field` er borte, og statuselementet har verken
466
+ `aria-live` eller `data-ignore-morph`.** Feltet, lista, tommeldingen og
467
+ statuselementet står rett i `<fs-suggestion>`, som selv gir lista plassen
468
+ under feltet. `role="status"` gir `aria-live="polite"` av seg selv, og
469
+ tømmer en oppdatering statuselementet, skriver komponenten antallet på
470
+ nytt (ikke under `prefiltered`, der det nye antallet kommer rett etter),
471
+ så Datastars `data-ignore-morph` trengs ikke, og det samme gjelder med
472
+ htmx. Tommeldingen trenger ikke `hidden`: stilarket skjuler den sammen
473
+ med lista. `fs.suggestion()` gir ikke lenger `field`. **Slik oppdaterer
474
+ du:** ta bort `<div class="fs-suggestion__field">` og `{...forslag.field}`
475
+ rundt feltet, og `aria-live`, `data-ignore-morph` og `hidden` på de to
476
+ elementene.
477
+
478
+ ### Lagt til
479
+
480
+ - **`<fs-tabs>` og `<fs-popover>` sier fra når en patch byttet ut
481
+ elementene fordi serveren ikke skrev id.** Datastar og idiomorph morfer
482
+ ikke et element med id inn i et uten: det gamle fjernes og serverens
483
+ settes inn. Lager komponenten id-ene selv, som den gjør for bar markup,
484
+ byttes fanene og panelet ut ved neste patch som sender området på nytt, og
485
+ fanevalget og fokus er borte. Nå kommer det én advarsel i konsollen i det
486
+ øyeblikket det skjer, med beskjed om å skrive id i malen. Sider som aldri
487
+ patcher, eller patcher smalt, får ingen advarsel. Reprodusert mot Datastar
488
+ v1.0.4 i `fs-tabs-morph.browser.test.ts`, som kjører den ekte bundlen.
489
+ - **`<fs-field>` og `<fs-suggestion>` sier fra når en oppdatering byttet ut
490
+ feltet fordi id-en fra serveren endret seg** mellom to rendringer, som når
491
+ malen lager id-en av et tilfeldig tall eller en teller, og det brukeren
492
+ hadde skrevet, gikk tapt.
493
+ - **`<fs-field>` og `<fs-suggestion>` sier fra når `for` på ledeteksten
494
+ pekte på en annen id enn feltets.** Komponenten skriver den om, men uten
495
+ JavaScript hadde feltet da ingen ledetekst.
496
+ - **`fs.suggestion()` gir det skjulte feltet for koden som `value`**, og
497
+ `.fs-suggestion__value` er en ny del i manifestet og i begge editorene.
498
+ Komponenten sender `input` og `change` på feltet når den skriver eller
499
+ tømmer koden, så `data-bind` i Datastar ser den; de bobler ikke, så en
500
+ `data-on:input` på verten utløses ikke av dem.
501
+ - **`<fs-suggestion>` går til første og siste alternativ med PgUp og PgDn.**
502
+ Home og End røres ikke; de flytter markøren i teksten.
503
+ - **`idOrFallback` sier også at en ny id per rendring bytter ut
504
+ elementene** ved neste patch.
505
+
506
+ ### Rettet
507
+
508
+ - **`<fs-suggestion>` mistet markeringen når serveren sendte lista på
509
+ nytt.** Alternativene får id av komponenten, og en oppdatering bytter dem
510
+ ut med nye id-er. Markeringen gjenfinnes nå på teksten.
511
+ - **`<fs-suggestion>` valgte bare på `mousedown`.** Hjelpemidler som
512
+ aktiverer et element, sender `click`, og den valgte da ingenting. Nå skjer
513
+ valget på `click`, og `mousedown` holder bare fokus i feltet.
514
+ - **`<fs-suggestion>` åpnet lista og endret verdien i et felt med
515
+ `readonly`.** Nå åpner et felt med `readonly` eller `disabled` ikke lista.
516
+ - **Et alternativ med `aria-disabled="true"` kunne velges.** Nå vises det,
517
+ men hoppes over av piltastene og kan ikke velges med mus.
518
+ - **Enter under en IME-komposisjon valgte det markerte alternativet.** Nå
519
+ hører tastene til komposisjonen.
520
+ - **`<fs-popover>` lukket vinduet etter en patch fra en mal uten
521
+ `popover`.** Morfingen tok `open` på verten og `popover` på panelet i
522
+ samme omgang. Komponenten lukket panelet, gjenåpnet det i neste mikrotask,
523
+ og først etterpå kom `toggle` med «closed» fra lukkingen, som en egen
524
+ oppgave. Den ble tatt som brukerens lukking. Nå gjelder `toggle` bare når
525
+ den stemmer med panelets faktiske tilstand.
526
+
527
+ ### Endret
528
+
529
+ - **«Markup og oppførsel» sier hvilke id-er som overlever en oppdatering.**
530
+ Felt og forslagsfelt får `for` og `id` fra malen, fanene og
531
+ sprettoppvinduet trenger id fra serveren når hele området sendes på nytt,
532
+ og id-er i en løkke lages av en nøkkel i dataene, aldri av indeksen eller en
533
+ teller. Regelbøkene i `agent/` og sidene for felt, forslagsfelt og faner
534
+ sier det samme. Før sto det at `outer` morfer og at malen ikke trenger gjøre
535
+ noe, og det holdt bare for markup fra byggefunksjonene.
536
+
537
+ ## 0.34.0 (2026-10-18)
538
+
539
+ ### Brytende
540
+
541
+ - **`hidden` på `<fs-error-summary>` er et flagg i JSX-typene.** `hidden`
542
+ kom fra `HTMLAttributes` som `boolean`, så `hidden={false}` kompilerte,
543
+ mens React 18 skriver det som `hidden="false"` på en web component, som er
544
+ sant: boksen ble aldri vist. Typen er nå `true | undefined`, som `open` på
545
+ `<fs-dialog>`, slik regelboka for React sier om hvert boolske attributt på
546
+ en web component. `fs.errorSummary().host` sendte alt `true` eller
547
+ ingenting.
548
+ Det er brytende for den som skrev `hidden={!harFeil}` eller
549
+ `hidden={false}`: det kompilerte, og i React 19 virket det, siden React 19
550
+ setter egenskapen `hidden` i stedet for attributtet. Skriv
551
+ `hidden={harFeil ? undefined : true}`, eller bruk
552
+ `fs.errorSummary({ count }).host`, som sender det riktig.
553
+ - **`fristil sjekk` meldte grønt for en tom fil og en tom side.** Bare tom
554
+ standard inn ga feilkode. En tom fil, og en adresse som svarte 200 med tom
555
+ HTML, ga «Markupen stemmer» og 0, så en CI-linje mot en side som rendret
556
+ tomt ble grønn. Nå gir en adresse med tom side feilkode, og det gjør også
557
+ filer som alle er tomme. Én tom fil blant flere, som en tom partial i et
558
+ glob, er fortsatt ikke en feil.
559
+ En CI-linje som var grønn mot en tom side, blir rød med denne versjonen.
560
+
561
+ ### Lagt til
562
+
563
+ - **`setAttributes` og typen `ReactSet` fra `/react`.** `fs.setAttributes`
564
+ derfra er den samme funksjonen, for sett med `className`, `htmlFor` og
565
+ `tabIndex` som tall. Hovedinngangen eksporterer `rememberManaged`, som
566
+ `/react` bruker for å gi et omdøpt sett de samme forvaltede navnene; den
567
+ er ikke ment for apper.
568
+ - **Regelen `del-flere-ganger` i `fristil sjekk`, editoren og
569
+ `diagnoseMarkup`.** En del med det nye feltet `unique` i manifestet som
570
+ står mer enn én gang, gir en advarsel: et `<fs-field>` med to kontroller,
571
+ to hjelpetekster i ett felt, en `fs-table` med to `<caption>`. `unique`
572
+ står på delene der en til er en feil og ikke vanlig innhold, og leses av
573
+ `Part` i Kotlin og `Part` i TypeScript. Regelen leser `parts` på
574
+ elementene og klassene i manifestet, så en ny del med `unique` sjekkes
575
+ uten en egen regel. Et treff inni en nøstet vert av samme slag hører til
576
+ den, det som står i en `<template>` teller ikke, og står det malsyntaks i
577
+ verten, sier regelen ingenting.
578
+ - **`tbody` i `fs-table` kan stå flere ganger** i manifestet, som HTML
579
+ tillater.
580
+ - **`Fristil.manifest.builders` i Kotlin-pakken.** Hver byggefunksjon med
581
+ valgene (`name`, `required`, `type` som `values`, `flag`, `text`,
582
+ `number` eller `textList`, og `description`) og formen på svaret
583
+ (`attributes`, `text`, `values`, `list` eller `group`). Tabellen
584
+ generatoren bak `Fs` bruker er fortsatt utelatt. TypeScript-typen
585
+ `Manifest` har fått `builders` med samme form.
586
+ - **`Fristil.buildTheme(oppskrift)` og `Fristil.inspectTheme(css)` i
587
+ Kotlin-pakken.** Temaet kunne før bare bygges med `fristil tema` og
588
+ Gradle-oppgaven `fristilTema`. Oppskriften er JSON-teksten `fristil tema`
589
+ leser, med norske eller engelske nøkler, og svarene `Theme` og
590
+ `ThemeReport` har de samme feltene som `CoreTheme` og `CoreThemeReport`
591
+ i TypeScript. Fargekontrakten ligger nå i jar-en, som manifestet.
592
+ - **Manifestet har en `tokens`-seksjon.** Avstandsskalaen, brekkpunktene
593
+ og containerbreddene fra `tokens.ts`, fargefamiliene, rollene og lagene
594
+ med hva hver er til, hvert `--fs-color-*`-navn, og komponentvariablene
595
+ per komponent med standardverdien stilarket faller tilbake på. Fargene
596
+ står som akser og navn, ikke som verdier, siden et tema kan ha andre
597
+ verdier enn Fristils egne. `ManifestTokens` i Kotlin leser det samme.
598
+ `schemaVersion` er fortsatt 1, og `tokens` i Kotlin er `null` i et manifest
599
+ fra før denne versjonen. Beskrivelsene av familiene, rollene og
600
+ lagene eksporteres også fra `@fristil/designsystem/tokens`, som
601
+ `FAMILY_DESCRIPTIONS`, `ROLE_DESCRIPTIONS` og `LAYER_DESCRIPTIONS`.
602
+ - **Manifestet sier hva hver klasse tar som innhold, og hvilke deler den
603
+ består av.** Hver klasse i `classes` har `content`, med samme ord som
604
+ delene til elementene: `text`, `free`, `parts` eller `none`. Klassene med
605
+ en fast struktur, som `fs-table`, `fs-list` og `fs-toggle-group`, har
606
+ `parts` med `selector`, `description`, `content`, `multiple` og
607
+ `optional`, og en klasse som bare er en del av en annen komponents
608
+ markup, som `fs-card__title`, peker på forelderen med `partOf`.
609
+ `schemaVersion` er fortsatt 1. I Kotlin har `ManifestClass` fått
610
+ `content`, `partOf` og `parts`, og `content` er `null` i et manifest fra
611
+ før denne versjonen, så IntelliJ kan lese manifestet til en eldre pakke.
612
+
613
+ ### Endret
614
+
615
+ - **Pakken sender med kildene kartene peker på.** `dist` har kildekart og
616
+ deklarasjonskart, og de for `fs`, `/react`, `/register`, `/dom`,
617
+ `/diagnostics` og kommandolinja pekte på fjorten filer i `src` som ikke var
618
+ med i tarballen, så «gå til definisjon» og et stakkspor derfra landet i en
619
+ fil som ikke fantes. `src/*.ts`, `src/diagnostics`, `src/jsx` og
620
+ `src/vocabulary` følger nå med, som `src/components` alt gjorde, og
621
+ byggesteget krever at hvert medsendt kart peker på en fil i pakken.
622
+ - **Regelboka for maler sier at Kotlin-pakken ligger på Maven Central.**
623
+ `agent/maler.md` sa at `io.github.markusaugust:fristil` og Gradle-pluginen
624
+ måtte bygges fra kildekoden. Begge ligger på Central fra 0.33.0, med samme
625
+ versjon som npm-pakken, men ikke hver npm-versjon går dit. Regelboka ber
626
+ derfor agenten bruke den nyeste versjonen som finnes på Central, og aldri
627
+ skrive en den ikke har sett der.
628
+
629
+ ### Rettet
630
+
631
+ - **`<fs-error-summary>` tar fokus også i React.** React gir fokus tilbake
632
+ til elementet som hadde det før en commit, og boksen flyttet fokus inne i
633
+ den samme commiten. Fokus endte derfor på innsendingsknappen i Chromium og
634
+ Firefox, og på feltet i alle tre motorene når skjemaet ble sendt med Enter,
635
+ både når boksen ble satt inn og når `hidden` ble tatt bort. Boksen tar nå
636
+ fokus én gang til etter commiten, hvis det gikk tilbake dit det var. Har et skript flyttet fokus
637
+ til noe annet, står det. En React-app som viser boksen mens brukeren står
638
+ i et felt, for eksempel ved `blur`, merker at fokus nå flyttes dit, slik
639
+ det alltid har gjort uten React.
640
+ - **Et merke, en etikett, en knapp eller en lenke i et kort strekkes ikke
641
+ lenger til hele bredden.** `.fs-card` er en flekskolonne, så
642
+ `<span class="fs-badge">Innvilget</span>` ble et bånd tvers over kortet,
643
+ slik eksempelet på komponentsiden viste. Avsnitt, lister og bilder
644
+ strekkes som før.
645
+ - **`fristil lsp` leter ikke over arbeidsområdet for en fil utenfor det.**
646
+ Letingen etter manifestet stoppet ved rota av arbeidsområdet fila lå
647
+ under, men for en fil utenfor det, som en kladdefil, og for hver fil når
648
+ editoren ikke ga noe arbeidsområde, som Neovim uten treff på
649
+ `root_markers`, fantes ingen rot å stoppe ved, så den gikk helt til rota
650
+ av filsystemet og tok en pakke i hjemmemappa som prosjektets. Nå letes det
651
+ ikke fra en slik fil: den sjekkes mot manifestet ved rota av
652
+ arbeidsområdet, om det har et, ellers mot pakkens, slik Editoren-siden og
653
+ IntelliJ-pluginen alt sa.
654
+ - **Tagnavnene er typet fra `/register` og `/react-jsx` alene.** Typesikker
655
+ bruk-siden sa at hendelsestypene følger med hver inngang til
656
+ web-komponentene, men `HTMLElementTagNameMap` ble bare utvidet i
657
+ komponentfilene, og `/register` og `/react-jsx` tar dem ikke med i typene.
658
+ Da var `document.querySelector("fs-dialog")` et `Element`, og lytteren på
659
+ det fikk `Event` uten `detail`, så mønsteret på siden var en typefeil. Kartet
660
+ over tagnavnene står nå i `events.ts`, som hver inngang alt tar med, så
661
+ `querySelector("fs-dialog")` gir `FsDialog | null` fra alle tretten
662
+ inngangene, også hver komponentinngang for de andre komponentene. Bygget
663
+ kompilerer en fil per inngang, med bare den importen, så det ikke kan gli
664
+ tilbake.
665
+ - **`fs.setAttributes` fra `/react` skriver `class` og `for`, og rydder.**
666
+ Funksjonen var hovedinngangens, mens settene fra `/react` har `className`
667
+ og `htmlFor`, så den skrev attributtene `classname` og `htmlfor`, og fant
668
+ ikke byggefunksjonen bak det omdøpte settet: `aria-invalid` ble stående
669
+ etter at feltet var rettet, uten advarsel. Nå oversettes navnene tilbake
670
+ før de settes, `tabIndex` blir `tabindex`, og settet rydder det samme som
671
+ fra hovedinngangen.
672
+ - **`engines` slipper ikke lenger inn Node 21 og 22.0–22.2.** Kjernen lastes
673
+ med `process.getBuiltinModule`, som kom i Node 20.16 og 22.3, men
674
+ `>=20.16` tok med versjonene mellom, og der sa feilmeldingen at Node 22.1
675
+ var eldre enn 20.16. Kravet er nå `^20.16.0 || >=22.3.0`, og meldingen
676
+ nevner begge grensene. Oppføringen under 0.32.0 som sier «20.16 eller
677
+ nyere», gjelder med dette unntaket.
678
+ - **Regelboka for React og Kodeagenter-siden sa at `react-jsx` stopper en
679
+ variant som ikke finnes.** `react-jsx` typer attributtene på
680
+ web-komponentene, og ingen av dem har en variant. Det er
681
+ `fs.button({ variant })` som gjør en ukjent variant til en kompileringsfeil,
682
+ med eller uten `react-jsx`, og en håndskrevet `className` eller
683
+ `data-variant` ser ingen av dem, og heller ikke `fristil sjekk`, som leser
684
+ `class`, ikke `className`. Begge tekstene sier nå hva som fanger hva, og
685
+ at det håndskrevne skal erstattes av byggefunksjonene.
686
+ - **`defineFs*` kaster ikke når klassen alt er registrert under et eget
687
+ navn.** `defineFsToast("app-toast")` fulgt av `defineFs()` ga
688
+ NotSupportedError på `fs-toast`, siden en konstruktør bare kan stå i
689
+ registeret én gang, og `<fs-session-timeout>` og `<fs-connection-status>`
690
+ ble aldri registrert. Nå registreres en underklasse under det andre navnet,
691
+ så begge navnene virker og flere kall er ufarlige, slik dokumentasjonen
692
+ sier. `tagName` er dessuten typet som `string`. Før var typen standardnavnet,
693
+ så TypeScript avviste `defineFsToast("app-toast")` før det kom så langt.
694
+ - **`<fs-toast>` flytter fokus riktig også i en skyggerot.** Komponenten
695
+ leste `document.activeElement`, som peker på skyggeverten når regionen
696
+ står i en skyggerot, slik hver forhåndsvisning i dokumentasjonen gjør. Da
697
+ så det ut som om ingen melding hadde fokus: lukket brukeren meldingen med
698
+ Enter, falt fokus til `body` i stedet for til meldingen ved siden av eller
699
+ dit det kom fra, og det samme skjedde ved `clear()`. Fokus leses nå fra
700
+ komponentens egen rot. `<fs-session-timeout>` husker hvor fokus sto før
701
+ varselet enten feltet står i siden eller i samme skyggerot som
702
+ komponenten, så det får fokus tilbake også når nettleseren ikke setter det
703
+ dit selv.
704
+ - **README sier hva et eget tagnavn gir.** Den lovet at du bestemmer «hva
705
+ det skal hete», men stilarkene til `<fs-field>`, `<fs-tabs>`,
706
+ `<fs-popover>`, `<fs-dialog>` og `<fs-suggestion>` er skrevet for
707
+ `fs-*`-navnene, så en komponent under et annet navn mistet `display`-regelen
708
+ på verten, og `<fs-dialog>` også plasseringen av en dialog som står åpen
709
+ før den er modal. README sier nå at oppførselen følger med navnet, men
710
+ ikke stilen, og hvilke fire komponenter som setter klassen sin selv.
711
+ - **`popover-toggle` er beskrevet slik den sendes.** Beskrivelsen i
712
+ `events.ts` og `web-types.json` sa «Panelet åpnet eller lukket seg», men
713
+ hendelsen kommer bare når brukeren åpner eller lukker panelet, og fra
714
+ `show()`, `hide()` og `toggle()`. Settes `open` som egenskap eller
715
+ attributt, som React 19 og Datastars `data-attr:open` gjør, kommer ingen
716
+ hendelse, ellers hadde Datastar-oppskriften fått sitt eget signal i retur.
717
+ Popover-siden skiller nå `meny.open = false` fra `hide()`.
718
+ - **Regelboka for maler lovet at `<fs-tabs>` husker fanevalget etter enhver
719
+ patch.** Den nevnte `innerHTML`, htmx og Turbo, men valget er knyttet til
720
+ selve knappen og overlever bare en morfing som beholder elementene, som
721
+ Datastars `outer`, htmx med idiomorph og Turbo 8 med morfing. Bytter
722
+ patchen ut nodene, følger komponenten markupen. Regelboka sier nå hvilke
723
+ patcher som beholder valget, og at serveren ellers må skrive det selv
724
+ eller bruke `server-controlled`.
725
+ - **Regelbøkene sa at markupen i en `ramme`-komponent står der uansett.**
726
+ «Kom i gang» og «Rammeverk» ble rettet i 0.33.0, men ikke teksten i
727
+ generatoren, så alle seks regelbøkene manglet unntaket: Tabs viser bare det
728
+ første panelet og Suggestion skjuler lista til de er registrert.
729
+ - **React-oppskriften på Dialog-siden og mønsteret «Bekreft en handling»
730
+ tømmer `returnValue` før `showModal()`.** «Ren HTML»- og Astro-fanene
731
+ fikk tømmingen i 0.33.0, men React-fanen, mønstersiden og demoen åpnet
732
+ dialogen med den gamle verdien stående. Ble dialogen åpnet igjen etter en
733
+ «Slett» og lukket uten knapp, fikk `close`-lytteren «slett» på nytt og
734
+ slettet igjen.
735
+ - **`fristil sjekk-tema` og `inspectTheme` hoppet over en nøstet blokk som
736
+ begynner med et element og et kolon.** `html:not([data-theme="light"]) { … }`
737
+ eller `body:has(…) { … }` inni en `@media`, et `@layer` eller en annen
738
+ blokk ble lest som deklarasjonen `html`, og den slukte alt fram til neste
739
+ semikolon, blokkene etter den med. Et tema med et brudd der fikk «Temaet
740
+ holder hvert løfte». Nå leses blokka som en regel, slik nettleseren gjør.
741
+ - **`fristil sjekk-tema` og `inspectTheme` leste
742
+ `@media not (prefers-color-scheme: dark)` som mørkt tema.** Blokka gjelder
743
+ i lyst tema, og Fristils egne lyse verdier ga brudd. `not` snur nå
744
+ mediespørringen, også skrevet med en medietype, som `not all and (…)` eller
745
+ `not screen and (…)`, og blokka kontrolleres bare som lys. Med en annen
746
+ medietype, som `not print and (…)`, gjelder blokka skjermen i både lyst og
747
+ mørkt tema, og den kontrolleres som en blokk uten betingelse.
748
+ - **`fristil sjekk-tema` og `inspectTheme` meldte systemfargene som feil.**
749
+ `--fs-color-disabled-surface`, `--fs-color-disabled-text` og
750
+ `--fs-color-overlay` er ingen celle, men ble lest som familien `disabled`
751
+ med roller som manglet, og som et token systemet ikke har. En overstyring
752
+ skrevet på hver temagrense, slik dokumentasjonen ber om, ga feilkode, og
753
+ det gjorde Fristils egen `tokens.css` også, med tolv problemer. Nå hopper
754
+ sjekken over dem: de lover ingen kontrast.
755
+ - **Et tema uten farger fra `fristil tema` ga feilkode i `fristil sjekk-tema`.**
756
+ Et tema med bare skrift og form fikk «Fant ingen --fs-color-*-verdier»,
757
+ og `inspectTheme` meldte det som et problem, enda dokumentasjonen sier at
758
+ et tema laget med `tema` holder kravene. Nå svarer sjekken at det ikke er
759
+ noen kontrast å kontrollere, uten feilkode. En fil uten noen
760
+ `--fs-*`-verdier gir fortsatt feilkode.
761
+ - **En `fs-progress` med `value` viste ikke fyllet i høykontrastmodus.**
762
+ Den fylte delen leste `currentColor`, og modusen tvang bakgrunnen på
763
+ pseudoelementet tilbake til `Canvas`, så stolpen så tom ut uansett hvor
764
+ langt den hadde kommet. Fyllet tegnes nå i `Highlight` rett på
765
+ `::-webkit-progress-value` og `::-moz-progress-bar`.
766
+ - **Klassen på et avsnitt i `fs-card` og `fs-alert` vinner over
767
+ komponenten.** `.fs-card p` og `.fs-alert p` slo klassene på avsnittet på
768
+ spesifisitet. I et kort virket ikke `--fs-paragraph-line-height`, en
769
+ `fs-card__title` som var en `<p>` fikk artikkelens linjehøyde, og
770
+ `fs-help-text` og `fs-error-text` mistet marginen i toppen, også i en
771
+ melding. Reglene teller nå bare elementet, så et avsnitt uten klasse ser
772
+ ut som før.
773
+ - **En besøkt `fs-link` skifter farge under musa.** `:hover` sto før
774
+ `:visited` med samme spesifisitet, så besøktfargen vant og hover-fargen
775
+ kom aldri. Rekkefølgen er snudd.
776
+ - **Ringen rundt `fs-avatar` vises over bildet.** Den var en `box-shadow`
777
+ innover, og en slik skygge males under innholdet, så et bilde dekket den
778
+ helt og ringen fantes bare med initialer. Den er nå en `outline` innover,
779
+ også i `fs-avatar-stack`, der skyggen utenfor fortsatt skiller bildene, og
780
+ hver avatar i stabelen males for seg, så ringen til den bak ikke skinner
781
+ gjennom bildet til den foran.
782
+ En slik `outline` slår nettleserens egen fokusmarkering, så en
783
+ `fs-avatar` som er en knapp får `--fs-focus-ring` på `:focus-visible`, og
784
+ i en stabel løftes den med fokus over naboene så fokusringen vises hel.
785
+ - **`--fs-skeleton-radius` virker på `data-variant="text"`.** Tekstlinjene
786
+ hadde en fast radius og leste ikke variabelen. Standarden der er
787
+ fortsatt `var(--fs-spacing-0-5)`, og tabellen på siden sier det.
788
+ - **Et langt valg i `fs-select` med `data-picker="styled"` ble ikke
789
+ klippet.** Regelen som klipper det, treffer `<selectedcontent>`, og
790
+ kommentaren sa at nettleseren lager elementet selv. Det gjør den ikke, så
791
+ med markupen på siden ble et langt valg brutt over flere linjer, og feltet
792
+ ble høyere. Komponentsiden sier nå at
793
+ `<button><selectedcontent></selectedcontent></button>` må stå først i
794
+ `<select>`-en for at valget skal klippes.
795
+ - **Siden om `fs-textarea` sa at `rows` virker som før.** Minstehøyden er
796
+ litt under tre rader, så `rows="1"` og `rows="2"` gir det samme feltet.
797
+ Siden sier nå hvor grensen går, og at `--fs-textarea-min-height: 0` lar
798
+ `rows` bestemme alene.
799
+ - **`fristil tema oppskrift.json --ut tema.css` skrev ingen fil.** Uten
800
+ likhetstegn ble `--ut` og `tema.css` lest som to filnavn etter
801
+ oppskriften og ignorert. Temaet gikk til utdata, og kjøringen avsluttet
802
+ med 0. På samme måte forsvant `--aksent #f00` bak fargen i fila. Nå stopper
803
+ `tema` og ber om likhetstegn, slik `overta` og `agent` gjør, og mer enn én
804
+ oppskriftsfil gir også feilkode. `overta` og `agent` stopper dessuten på et
805
+ ukjent flagg med likhetstegn, som `--utt=src/ui` eller `--rammverk=react`,
806
+ i stedet for å bruke standarden.
807
+ - **`fristil tema` leser oppskriften som `JSON.parse`.** Sto en nøkkel to
808
+ ganger, vant den første, mens `JSON.parse` lar den siste vinne. Tall som
809
+ `0700` og `1.` og et rått kontrolltegn i en streng ble godtatt, og en fil
810
+ med svært dyp nesting stoppet den kjørbare fila med «stack overflow». Nå
811
+ vinner den siste verdien, slike tall og strenger gir «er ikke gyldig
812
+ JSON», og det gjør også mer enn 128 objekter og lister inni hverandre.
813
+ - **Tall i temaet og manifestet skrives som `String(tall)` i JavaScript.**
814
+ `1e-7` ble `0.0000001` og `1e21` ble `1000000000000000000000`, og et
815
+ uendelig tall ble `inf`. Nå får de eksponent, som `1e-7` og `1e+21`, og
816
+ `Infinity` heter `Infinity`. I manifestet blir et uendelig tall `null`,
817
+ som i `JSON.stringify`. Vanlige tall skrives som før.
818
+ - **Meldingen for `aria-controls` som peker på en id som ikke finnes, slutter
819
+ ikke lenger med et mellomrom.** Det sto igjen etter «styrer.», i
820
+ `fristil sjekk`, i editoren og som to mellomrom før regelnavnet i
821
+ `assertFristil`.
822
+ - **En BOM først i en fil eller side gir ikke lenger en kolonne for mye.**
823
+ `fristil sjekk` talte U+FEFF som et tegn på linje 1, så kolonnen var én
824
+ mer enn editoren viser. For en adresse svarte `npx` riktig, fordi Node
825
+ fjerner BOM-en, mens den kjørbare fila og `java -jar` ga én kolonne mer.
826
+ Nå fjernes den for filer, standard inn og adresser i alle verter.
827
+ - **Språkserveren og `fristil sjekk` regner `\r` som linjeskift.** Bare
828
+ `\n` delte linjer, så et dokument med `\r`-linjeskift ble én lang linje,
829
+ og en editor som sender bufferen slik den er, som Neovim med
830
+ `fileformat=mac`, fikk funnene og hurtigrettelsene på feil sted. Nå er
831
+ `\n`, `\r\n` og `\r` alene linjeskift, som LSP krever. Linje og kolonne i
832
+ `diagnosePage`, `assertFristil` og `fristil sjekk` følger samme regel.
833
+ Hurtigrettelsen «Sett inn en ledetekst» gir også `<label>` sin egen linje
834
+ med samme innrykk når linjeskiftene er `\r`.
835
+ - **Eksempelet på siden om Kotlin viste feil regelnavn.** Funnet for en
836
+ `for` som peker på en id som ikke finnes, sto med `[for-peker-feil]`, men
837
+ regelen heter `id-finnes-ikke`. `for-peker-feil` gjelder en `for` som
838
+ peker på et element som ikke kan ha ledetekst. Den som kopierte navnet
839
+ til `<!-- fristil-ignore-next … -->`, fikk funnet likevel.
840
+ - **Oppskriften for å bytte skilletegn i `fs-breadcrumbs` tok ikke med
841
+ alternativteksten.** Siden viste `content: "›"`, og en regel utenfor laget
842
+ slår stilarket, så den som fulgte rådet fikk tilbake feilen 0.33.0 rettet:
843
+ skjermleseren sa «›» mellom hvert steg. Snutten har nå `content: "›" / ""`
844
+ bak samme `@supports` som stilarket, og siden sier hvorfor. En test kjører
845
+ snutten fra siden mot stilarket.
846
+ - **Oppskriften for å bytte pila i `fs-accordion` lot rotasjonen stå.** Siden
847
+ sa at `content` og `border` var nok, men pseudoelementet har fast størrelse
848
+ og `transform`, og vinkelen byttes når panelet er åpent, så et «+» sto på
849
+ skrå og ble et «×» i åpen tilstand. Et synlig tegn uten alternativ tekst
850
+ ble dessuten en del av navnet på knappen, det skjermleseren sier når
851
+ `<summary>` får fokus. Snutten nullstiller nå begge og gir tegnet tom
852
+ alternativ tekst.
853
+ - **JSDoc-eksempelet for `alert` spredte `alert.title`.** `alert.title` er
854
+ klassenavnet, en streng, og `<p {...alert.title}>` gir tegnene som
855
+ attributter og ikke klassen. Eksempelet skriver `class={alert.title}`,
856
+ som accordion og card.
857
+ - **Fieldset-siden sa at en `<legend>` lenger ned ikke kobles til gruppen.**
858
+ Nettleserne bruker den første `<legend>`-en som navn og tegnet ledetekst
859
+ uansett hvor den står. Regelen om at den skal stå først gjelder fortsatt,
860
+ men begrunnelsen er at HTML krever det, og at markupen ellers er ugyldig.
861
+ - **Select-siden sa at listen tegnes i siden fra Chromium 148.** Det eneste
862
+ stilarket spør om, er `@supports (appearance: base-select)`, og den slår
863
+ til i eldre Chromium også; 148 er versjonen Fristil er testet i. Tabellen
864
+ sier nå hva som avgjør, og hvilke versjoner som er testet.
865
+ - **Skip Link-siden begrunnet `tabindex="-1"` med at neste Tab fortsatte i
866
+ menyen.** Nettleseren fortsetter fra målet etter hoppet også uten
867
+ attributtet. Det som mangler uten det, er fokuset og skjermleserens
868
+ opplesning, og det sier siden og mønstersiden «Sideskjelett» nå. Error
869
+ Summary-siden og JSDoc-en til `fs-error-summary` sa det samme om en vanlig
870
+ ankerlenke, at neste tastetrykk fortsatte i oppsummeringen, og sier nå at
871
+ nettleseren bare gir fokus til et mål som kan få det. Siden og
872
+ stilarket sa også at fokus satt fra kode aldri regnes som synlig fokus.
873
+ Det gjelder bare etter et museklikk, og det er det tilfellet `:focus` er
874
+ valgt for.
875
+ - **Lagringseksempelet på Switch-siden rullet ikke tilbake ved et feilsvar,
876
+ og tok fokuset fra bryteren.** `fetch` avviser bare ved nettverksfeil, så
877
+ et 500-svar ble meldt som «Varsler er på.» med bryteren stående i ny
878
+ stilling. Eksemplet slo dessuten av bryteren mens den lagret, og
879
+ `disabled` tar fokuset fra en bryter som har det uten å gi det tilbake, så
880
+ et nytt mellomromstrykk gjorde ingenting. «Ren HTML» og React sjekker nå
881
+ `svar.ok` og sperrer et nytt trykk uten `disabled`, Datastar-fanen og
882
+ eksemplet med `fs.setAttributes` slår ikke lenger av bryteren, og
883
+ JSDoc-en til `disabled` i `switchControl` advarer mot bruken. Det korte
884
+ eksemplet på Connection Status-siden og i JSDoc-en til
885
+ `FsConnectionStatus` sjekker også `svar.ok`. En test kjører «Ren
886
+ HTML»-eksemplet fra siden mot en server som svarer 500.
887
+ - **`fs-list` beholder punktene og tallene sammen med Tailwinds Preflight.**
888
+ Standardvarianten sa ingenting om `list-style` og lente seg på nettleseren,
889
+ mens Preflight setter `list-style: none` på hver `<ul>` og `<ol>`. Med
890
+ oppsettet Tailwind-siden anbefaler, `@import "tailwindcss"` og `base` før
891
+ `fristil`, mistet lista punktene og nummereringen, og det gjorde lista i
892
+ `fs-error-summary` også. Klassen setter nå `list-style-type: revert`, som
893
+ går tilbake til nettleserens eget stilark, så listene ser ut som uten
894
+ Tailwind. Variantene `plain` og `divided` er fortsatt uten punkter. Vil du
895
+ ha et annet punkt på alle `.fs-list`, sett det selv, i CSS uten lag eller
896
+ i et lag etter `fristil`: en `list-style` på `ul` i et lag foran, som
897
+ `base`, når ikke lenger fram til klassen. Testen bygger oppsettet med
898
+ Tailwinds egen `preflight.css`, ikke en håndskrevet utgave med bare
899
+ knappereglene.
900
+ - **Lagrekkefølgen for Tailwind tar med `fristil-tema`.** Et generert tema
901
+ erklærer `@layer fristil, fristil-tema;`, og en `@layer`-setning flytter
902
+ ikke lag som alt er erklært. Med den anbefalte linja
903
+ `@layer theme, base, fristil, components, utilities;` havnet temaet derfor
904
+ sist, etter `utilities`, og slo Tailwind-klassene og `@layer base` på de
905
+ samme elementene, enda Tilpasning- og Eget tema-sidene sa at din egen CSS
906
+ fortsatt vinner. Linja i dokumentasjonen og i kommentaren i `tailwind.css`
907
+ er nå `@layer theme, base, fristil, fristil-tema, components, utilities;`,
908
+ og Eget tema-siden sier at laget må stå der når Tailwind brukes, og at
909
+ linja må stå i `<head>` når temaet lastes som en `<link>` før den
910
+ bundlede CSS-en, for da har temaet alt erklært lagene sine. Temaet
911
+ `fristil tema` skriver, er uendret.
912
+ - **Tailwind-siden og Design tokens-siden sa at skalaen følger med når du
913
+ setter `--fs-spacing-1`.** `p-4` er `calc(var(--fs-spacing-1) * 4)`, men
914
+ `--fs-spacing-4` og de andre trinnene er egne verdier, så eksempelet
915
+ `--fs-spacing-1: 0.3rem` ga `p-4` 1,2rem mens komponentene sto på 1rem.
916
+ Sidene og kommentaren i `tailwind.css` sier nå at trinnene må skrives om
917
+ hver for seg, og eksempelet gjør det. Tabellen over skalaen oppgir også
918
+ `px` som Tailwind-motstykket til `--fs-spacing-px`, der det sto «ingen».
919
+
920
+ ## 0.33.0 (2026-10-12)
921
+
922
+ ### Brytende
923
+
924
+ - **Kjernen bærer ingen data.** `fristil-kjerne.wasm` hadde manifestet og
925
+ fargekontrakten bygget inn. Nå gir verten dem. For `diagnoseMarkup`, `diagnosePage`,
926
+ `buildTheme` og `fristil` fra npm er ingenting endret: pakken gir
927
+ kjernen sitt eget manifest og sin egen fargekontrakt. Den som laster
928
+ kjernen selv, merker det:
929
+ - `loadCore()` gir en kjerne uten noe. Kall `loadManifest()` før
930
+ sjekken og `loadContract()` før temaet, ellers kaster de med en
931
+ forklaring. `resetManifest()` er fjernet, siden det ikke finnes noe
932
+ innebygd å gå tilbake til. `version().manifest` er `null` før et
933
+ manifest er gitt.
934
+ - En vert i et annet språk kaller `load_manifest_raw` og den nye
935
+ `load_contract_raw` først. `diagnose_markup_raw`, `diagnose_page_raw`
936
+ og `inspect_theme_raw` svarer nå 0, eller 1 med `{"error": …}`, som
937
+ `build_theme_raw` og `diagnose_styled_raw` alt gjorde.
938
+ `reset_manifest` er fjernet.
939
+ - Kommandolinja leser manifestet, fargekontrakten, regelbøkene og
940
+ komponentene fra `@fristil/designsystem`: fra mappa
941
+ `FRISTIL_PACKAGE` peker på, eller fra `node_modules` i arbeidsmappa
942
+ eller over den. npm-pakken og `fristil.jar` setter variabelen selv.
943
+ `fristil.wasm` i wasmtime og den kjørbare fila fra `cargo install`
944
+ trenger den, eller pakken installert, og stopper med en forklaring
945
+ uten. `fristil agent` og `fristil overta` svarer dermed for versjonen
946
+ prosjektet har installert.
947
+
948
+ Modulen er 93 kB mindre.
949
+ - **En temagrense har nå en flate.** Et element med `data-theme="light"`
950
+ eller `data-theme="dark"` får temaets bakgrunn og tekstfarge. Før fikk det
951
+ mørke tokens, men beholdt sidens hvite bakgrunn, så brødteksten i en mørk
952
+ seksjon på en lys side ble 1,23:1. Regelen har spesifisitet null i
953
+ `@layer fristil`, så en komponent med `data-theme` på seg, og din egen stil
954
+ uten lag eller i et senere lag, beholder sin egen bakgrunn. Stil i et lag
955
+ foran `fristil` taper. `<html>` og `fs-toast` får ingenting. En innebygd
956
+ komponent med `data-theme` på rotelementet står nå på temaets flate i
957
+ stedet for å være gjennomsiktig over verten.
958
+ - **`--fs-focus-ring`, `--fs-color-disabled-surface` og
959
+ `--fs-color-disabled-text` følger en temagrense.** De sto bare på `:root`,
960
+ der en `var()` regnes ut én gang for hele siden, så en mørk seksjon på en
961
+ lys side fikk den lyse fokusringen, 2,4:1 mot flaten. De deklareres nå i
962
+ hver temablokk. Har du overstyrt en av dem på `:root`, gjelder ikke
963
+ overstyringen lenger inne i et `data-theme`. Skriv den også på
964
+ `[data-theme="light"]` og `[data-theme="dark"]`.
965
+ - **`fristil sjekk-tema` kontrollerer en blokk som ikke er bundet til lyst
966
+ tema, som en bar `:root`, i mørkt tema også.** Fristils mørke blokk
967
+ overstyrer bare tokenene den selv har, så en verdi som ingen mørk blokk
968
+ tar, står også når systemet er i mørkt. Sjekken så den bare som lys:
969
+ `--fs-color-neutral-text: #0d4e8c` på `:root` ga «holder hvert løfte», men
970
+ har 2,22:1 i mørkt. Funnene merkes «i mørkt tema, ingen mørk blokk
971
+ overstyrer». En blokk med `color-scheme: light`, en selektor med `light`
972
+ som eget ord og `@media print` gjelder bare lyst og kontrolleres som før. Et tema som før var grønt kan nå gi funn, og da var
973
+ det brutt i mørkt hele tiden.
974
+ - **`fristil sjekk` melder nye funn.**
975
+ - Et flagg med en tekstmal i verdien, som `data-optional="{{ .Optional }}"`
976
+ eller `open="<%= open %>"`. Malen skriver verdien som tekst, og et boolsk
977
+ attributt er på uansett verdi, også «false» og en tom streng. Regelen er
978
+ `boolsk-med-verdi`. Astro, Svelte, JSX, Razor og JTE tar selv bort et
979
+ usant boolsk attributt, og meldes ikke. Står attributtet alt i en
980
+ betingelse i malen, som `{{ if .Open }} open="{{ .Open }}" {{ end }}`,
981
+ meldes det heller ikke.
982
+ - En `fs-link` eller `fs-button` med både `aria-disabled="true"` og `href`.
983
+ Stilen slår av musa, men Enter følger lenken. Regelen er ny:
984
+ `deaktivert-med-href`.
985
+ - **`fs.link({ disabled: true })` gir `role="link"` og `tabindex="0"`.** En
986
+ deaktivert lenke skal skrives uten `href`, ellers følger Enter den, og uten
987
+ `href` er en `<a>` ingen lenke for skjermleseren og står ikke i
988
+ tabrekkefølgen. De to gir begge tilbake, og `disabled: false` fjerner dem.
989
+ `fs.link()` forvalter dermed `role` og `tabindex`: setter du en av dem
990
+ selv på en lenke, som `role="menuitem"` i en meny, fjerner
991
+ `fs.setAttributes(lenke, fs.link())` den. Sett den etter. Komponentsidene
992
+ for Link og Button viste en deaktivert lenke med `href`, og det gjorde også
993
+ rådet i byggefunksjonen. Har du fulgt det, ta bort `href` mens lenken er
994
+ av.
995
+ - **`hidden` skjuler nå alle komponentene.** Forfatterstil slår nettleserens
996
+ `[hidden] { display: none }`, så `<div class="fs-alert" hidden>` og 41 andre
997
+ klasser, åtte av elementene og barn uten klasse, som `option` i en stylet
998
+ `fs-select`, et ledd i `fs-breadcrumbs` og en rad i fillista, sto
999
+ synlige. En regel i `@layer fristil` med `!important` skjuler dem nå,
1000
+ slik nettleseren selv gjør. Den kan ikke overstyres med en regel uten
1001
+ `!important`, og heller ikke med `!important` uten lag. `hidden="until-found"`
1002
+ får stå.
1003
+ - **`.fs-tooltip__bubble` er `display: none` når den er skjult**, ikke
1004
+ `visibility: hidden`. En skjult boble tok plass og ga sidelengs rulling ved
1005
+ høyre kant. Teksten er fortsatt knappens beskrivelse gjennom
1006
+ `aria-describedby`.
1007
+
1008
+ ### Lagt til
1009
+
1010
+ - **`.fs-icon` og `fs.icon()`, for et ikon fra appens eget sett.** Klassen
1011
+ går på en `<svg>` og gjør den like stor som teksten rundt. `fs.icon()` gir
1012
+ `aria-hidden="true"`, og `fs.icon({ label })` gir `role="img"` og
1013
+ `aria-label` for et ikon som betyr noe alene. Fristil sender ingen ikoner.
1014
+ Stilarket er `@fristil/designsystem/icon.css`.
1015
+ - **Regelen `ikon-uten-navn`.** En `<button>` eller `<a href>` med bare et
1016
+ ikon i seg og ikke noe navn er en feil i `fristil sjekk`, i editorene og
1017
+ i `diagnoseMarkup`. Navnet kan komme fra tekst, også med `fs-sr-only`, fra
1018
+ `aria-label`, `aria-labelledby` eller `title`, eller fra `alt` på et bilde.
1019
+ Det som er skjult med `aria-hidden="true"` eller `hidden`, teller ikke.
1020
+ Står det noe på knappen eller et barn som ikke er vanlig HTML, som
1021
+ `:aria-label`, `v-bind`, `x-text` eller `{...props}`, kan navnet komme
1022
+ derfra, og regelen tier.
1023
+ - **Typen `Manifest` fra `@fristil/designsystem/diagnostics`**, formen på
1024
+ `manifest.json` slik skjemaet beskriver den, for den som leser manifestet
1025
+ selv. Kotlin-pakken har det samme som `Fristil.manifest`, og leser et
1026
+ prosjekts eget manifest med `Manifest.parse`: elementene med attributter,
1027
+ deler og hendelser, og klassene med attributtene og de lovlige verdiene.
1028
+ - **Delene og beskrivelsene står i manifestet.** Hvert element har nå
1029
+ `description` og `parts`: delene web-komponenten finner i markupen, med
1030
+ selektoren den leter med, hva delen skal inneholde, og om den kan stå
1031
+ flere ganger eller mangle. `<fs-field>` har ledetekst, kontroll,
1032
+ hjelpetekst og feilmelding, og `<fs-dialog>` har dialogen, tittelen og
1033
+ kroppen. Hvert attributt på et element og hvert valg i en
1034
+ byggefunksjon har `description`, og et attributt på en klasse har
1035
+ beskrivelsen til valget med samme navn. Et verktøy eller et
1036
+ annet språk kan dermed lese hva hvert element leter etter, uten å lese
1037
+ kildekoden.
1038
+ Feltene er nye og valgfrie i skjemaet, så `schemaVersion` er fortsatt 1.
1039
+ Fragmentet fra `fristil overta` gir klassene nye navn også i selektorene
1040
+ og beskrivelsene, så kopien beskrives med sine egne klasser.
1041
+ Selektorene eksporteres også, fra hovedinngangen og fra inngangen til
1042
+ hver av de sju web-komponentene som finner deler, som `FS_FIELD_PARTS`
1043
+ fra `@fristil/designsystem/field`.
1044
+ - **`@fristil/designsystem/fargekontrakt.json`** i `exports`, så en side
1045
+ som laster kjernen i nettleseren kan gi den fargekontrakten med
1046
+ `loadContract()`, som den gir manifestet fra `./manifest.json`.
1047
+ - **Hendelsene har typer i `addEventListener`.** `HTMLElementEventMap` og
1048
+ `DocumentEventMap` utvides med hver hendelse web-komponentene sender,
1049
+ med `detail` slik komponenten sender den: `dialog-toggle` gir
1050
+ `event.detail.open` som `boolean` og `returnValue` som `string`. Typene
1051
+ følger med hver inngang til web-komponentene, `/register`, `/react` og
1052
+ `/react-jsx` medregnet, så `as CustomEvent<…>` trengs ikke lenger. Typen
1053
+ står også som `FsEventMap` i hovedinngangen. Den genereres fra den samme metadataen
1054
+ som manifestet og `web-types.json`, og har ingen avhengighet av React.
1055
+ - **`"./package.json"` i `exports`.** Et verktøy som leser pakkens versjon
1056
+ med `require.resolve("@fristil/designsystem/package.json")` eller
1057
+ `import … with { type: "json" }`, fikk `ERR_PACKAGE_PATH_NOT_EXPORTED`.
1058
+ Nå finner de den.
1059
+ - **`--fs-progress-border`** styrer kanten rundt sporet i `fs-progress`.
1060
+ - **`fs.popover()` skriver `type="button"` på knappen.** En knapp uten `type`
1061
+ sender skjemaet den står i.
1062
+ - **`session-activity` og `activity-interval` på `fs-session-timeout`.**
1063
+ Klokka nullstilles av aktivitet i nettleseren, men serverøkten visste
1064
+ ikke om den. En bruker som skrev i et langt skjema uten et eneste kall til
1065
+ serveren, fikk aldri varselet, og innsendingen feilet fordi serverøkten
1066
+ var ute. Hendelsen kommer i starten av hvert intervall med aktivitet og på
1067
+ slutten hvis brukeren har gjort noe siden, høyst én gang per
1068
+ `activity-interval` sekunder (standard 60, minst 1), og aldri mens
1069
+ varselet står eller etter at økten er ute. `fs.sessionTimeout()` tar
1070
+ `activityInterval`. Komponentsiden viser også hvordan flere faner holder
1071
+ klokkene i takt.
1072
+ - **`--fs-accordion-padding-inline`** gir overskriften og innholdet i
1073
+ `fs-accordion` samme luft til sidene. Før gjaldt `--fs-accordion-padding`
1074
+ bare overskriften.
1075
+ - **Hendelsene står i manifestet, i `web-types.json` og i regelbøkene.**
1076
+ Elementene som sender hendelser, har nå `events` i manifestet, med feltene
1077
+ i `detail` og typen deres, som `dialog-toggle` med `open` og `returnValue`.
1078
+ `web-types.json` har dem som `js.events`, og regelbøkene har en kolonne for
1079
+ dem. Før sto de bare på komponentsidene, og noen ikke der heller.
1080
+
1081
+ - **`manifest` i `Fristil.diagnoseMarkup` og `Fristil.diagnosePage` i
1082
+ Kotlin.** Teksten i et `manifest.json`, som det `fristilManifest`
1083
+ skriver, gir sjekk mot komponentene prosjektet har overtatt. Uten valget
1084
+ gjelder manifestet i pakken, som før. Et manifest kjernen ikke kan lese,
1085
+ kaster `IllegalArgumentException` med grunnen.
1086
+
1087
+ ### Endret
1088
+
1089
+ - **Pil opp og ned bytter ikke lenger fane i en vannrett `fs-tabs`.** De
1090
+ stjal siderullingen og avvek fra WAI-ARIA. De virker når raden har
1091
+ `aria-orientation="vertical"`.
1092
+
1093
+ ### Rettet
1094
+
1095
+ - **`fs.setAttributes` virker på en `<svg>`.** Klassen ble satt med
1096
+ `className`, som er skrivebeskyttet på et svg-element, og kallet kastet
1097
+ «Cannot set property className». Den settes nå med `setAttribute`.
1098
+ - **`<fs-field>` kobler bare sine egne deler.** Sto et felt inni et annet,
1099
+ som et søkefelt i et sprettoppvindu inni feltet, fant det ytre feltet det
1100
+ innerste feltets kontroll først og skrev `for`, `id` og
1101
+ `aria-describedby` på den. Nå ser hvert felt bare kontrollen, ledeteksten,
1102
+ hjelpeteksten og feilmeldingen som hører til det selv, slik de andre
1103
+ komponentene alt avgrenset delene sine. Et felt med mer enn én kontroll
1104
+ gir en advarsel i konsollen, siden bare den første får koblingen.
1105
+ - **En overskrift i kroppen til `<fs-dialog>` blir ikke lenger tittel.**
1106
+ Uten `aria-labelledby` og `aria-label` tok komponenten den første
1107
+ overskriften i dialogen, også en som sto i `fs-dialog__body`, og ga den
1108
+ klassen `fs-dialog__title` og stilen som følger med. Nå er tittelen den
1109
+ første overskriften utenfor kroppen, og en dialog som står uten navn,
1110
+ gir en advarsel i konsollen i stedet for å låne innholdets overskrift.
1111
+ - **En ubestemt `fs-progress` var en tom ramme i høykontrastmodus.** Stripen
1112
+ som sveiper over, er en gradient, og modusen fjerner gradienter. Den
1113
+ tegnes nå i `Highlight` på `Canvas` med `forced-color-adjust: none`, så
1114
+ brukerens systemfarger fortsatt gjelder.
1115
+ - **Kotlin skriver tall i attributter slik JavaScript gjør.** `jsNumber` ga
1116
+ `1000000000000000000000` for `1e+21`, `0.0000001` for `1e-7` og den
1117
+ eksakte binærverdien for heltall over 2^53, som `123456789012345683968`
1118
+ for `123456789012345680000`, og byggefunksjonene i
1119
+ Kotlin kunne dermed skrive et annet attributt enn `fs` i TypeScript. Nå
1120
+ brukes de færreste sifrene som gir det samme tallet tilbake, og
1121
+ JavaScripts regler for når eksponent brukes. Etterprøvd mot JavaScript på
1122
+ 224 614 tall uten avvik, hver toerpotens medregnet.
1123
+ - **`fristilManifest` skriver bare `build/fristil/manifest.json` når
1124
+ `manifests` har fragmenter**, og sletter fila når det siste fragmentet er
1125
+ fjernet. Språkserveren foretrekker den fila framfor pakken i
1126
+ `node_modules`, så en kopi uten fragmenter ble stående med versjonen fra
1127
+ da den ble skrevet, også etter at pakken var oppgradert.
1128
+ - **Fokusringen på det valgte alternativet i `fs-toggle-group` var 1,23:1.**
1129
+ Ringen står oppå den valgte flaten, og har nå `accent-content` som farge
1130
+ der.
1131
+ - **Sporet i `fs-progress` var 1,12:1 mot siden.** Stolpen har nå en kant i
1132
+ `neutral-border`, så det synes hvor langt den går. Kanten er tegnet innover
1133
+ og tar ikke av høyden.
1134
+ - **`fs-dialog` meldte forrige knapps verdi når dialogen ble lukket uten
1135
+ knapp.** Escape og `close()` uten argument lar `returnValue` stå fra forrige
1136
+ lukking. En dialog serveren åpnet på nytt og så lukket, sendte derfor
1137
+ `dialog-toggle` med for eksempel `returnValue: "slett"` fra gangen før, og en
1138
+ app som skiller «Avbryt» fra «Slett» på verdien kunne slette noe brukeren
1139
+ aldri ba om. Komponenten tømmer nå verdien hver gang den åpner dialogen.
1140
+ Skriver noe `open` på verten etter at brukeren har trykket en knapp, men før
1141
+ `close` er kommet, åpner komponenten heller ikke dialogen igjen. Før gjorde
1142
+ den det, og verdien ble borte for en lytter på `close`.
1143
+ - **`fs-dialog` åpnet seg ikke igjen etter at verten var flyttet.** En morfer
1144
+ som flytter verten kobler den fra og til, og komponenten tok den gamle
1145
+ `returnValue` for en lukking brukeren gjorde før skriptet kom, og fjernet
1146
+ `open` serveren nettopp hadde satt. Den sjekken gjøres nå bare første gang
1147
+ en dialog sees, også når den flyttes inn i en ny vert.
1148
+ - **`fs-dialog` meldte `open: true` for en dialog som var åpen hele tiden.**
1149
+ En morfer som flytter verten eller dialogen, tar dialogen ut av topplaget,
1150
+ og komponenten åpner den igjen. `dialog-toggle` kommer nå bare når
1151
+ tilstanden faktisk endrer seg.
1152
+ - **`data-color="neutral"` på `fs-dialog` ga mer luft enn ingen farge.**
1153
+ Verdien er standardverdien og skal se ut som ingen verdi, men reglene for
1154
+ luften traff bare en dialog uten attributtet. Nå gjelder de alt som ikke er
1155
+ en av de fem fargene, også en tom verdi fra en mal.
1156
+ - **Knappen i `fs-popover` sendte skjemaet den sto i.** Komponenten setter nå
1157
+ `type="button"` på en `<button>` uten `type`, eller med en tom eller ukjent
1158
+ verdi, også etter en patch som river det bort. En knapp som sier
1159
+ `type="submit"` selv, får stå. Eksemplene på komponentsiden og snippeten i editoren har det med.
1160
+ - **Escape i `fs-popover` tok for mye.**
1161
+ - Et trykk i et annet felt flyttet fokus fra feltet til knappen. Nå lukkes
1162
+ vinduet, og fokus blir stående.
1163
+ - Et trykk i en modal dialog åpnet oppå vinduet lukket vinduet også. Nå
1164
+ lukker det bare dialogen.
1165
+ - Et trykk noe annet alt hadde brukt, som en forslagsliste i vinduet som
1166
+ lukket seg, lukket vinduet også. Nå står vinduet.
1167
+ - Med to vinduer inni hverandre lukkes nå det innerste først.
1168
+ - **`fristil sjekk --css` fulgte ikke `@import` fra en pakke.**
1169
+ `@import "@fristil/designsystem/fristil.css"` er et navn i pakkens
1170
+ `exports`, og fila ligger i `dist/`. Sjekken lette etter den som en fil i
1171
+ `node_modules` under arbeidsmappa, fant ingenting og meldte hver klasse som
1172
+ ustylet. Nå slår den opp i `exports`, også mønstre som `./*` og en pakke
1173
+ importert ved navn alene, i nærmeste `node_modules` over stilarket. En
1174
+ relativ sti slås aldri opp som en pakke.
1175
+ - **`fristil sjekk-tema` leste `dark` inne i `:not()`.**
1176
+ `.kort:not([data-theme="dark"])` ble kontrollert som et mørkt tema.
1177
+ `:root:not([data-theme="dark"])` gjelder også i systemets mørke modus, og
1178
+ kontrolleres nå mot begge temaer.
1179
+ - **`fristil sjekk` meldte Bootstraps `fs-1` til `fs-6` som ukjente
1180
+ klasser.** En klasse som er `fs-` og bare sifre, er ikke Fristils.
1181
+ - **`fristil sjekk` kjente ikke `writingsuggestions`, `autocorrect` og
1182
+ `headingoffset`.** De er globale attributter i HTML.
1183
+ - **`fs-suggestion` nådde ikke et felt React styrer.** Valget ble satt rett på
1184
+ noden, React så ingen endring, `onChange` kom aldri, og ved neste rendring
1185
+ skrev React den gamle teksten tilbake. Komponenten bruker nå setteren fra
1186
+ elementets prototype.
1187
+ - **`fs-session-timeout` kunne hoppe over en opplesning.** Et tikk som kom
1188
+ sent, kunne gå fra 61 til 59 sekunder, og «1 minutt» ble aldri lest opp.
1189
+ Opplesningen kommer nå når en terskel krysses.
1190
+ - **`fs-toast` mistet fokus.** Ble den siste meldingen lukket, eller ble alle
1191
+ fjernet med `clear()`, mens en melding hadde fokus, falt fokus til `body`.
1192
+ Det går nå tilbake dit det kom fra. `label` skrev også over en
1193
+ `aria-label` forfatteren hadde satt, og når `label` ble fjernet, sto det
1194
+ gamle navnet igjen.
1195
+ - **`fs-tabs` og `fs-error-summary` holdt fast faner og lenker en morfing
1196
+ hadde byttet ut.** Begge har nå én lytter på verten.
1197
+ - **Dokumentasjonen lovet for mye.** «Kom i gang» og «Rammeverk» sa at
1198
+ markupen i en `ramme`-komponent vises uansett, men Tabs og Suggestion
1199
+ skjuler innhold til de er registrert. Datastar-oppskriften for Error
1200
+ Summary flyttet ikke fokus ved andre feilede innsending, og skjema-mønsteret
1201
+ skrev oppsummeringen med `role="alert"` på nytt ved hvert tastetrykk, så
1202
+ skjermleseren ble avbrutt. Toast og Connection Status sier nå at de er
1203
+ inerte mens en modal dialog står åpen.
1204
+ - **Avslått vant ikke over en tilstand.** Et ugyldig eller vellykket felt
1205
+ som var slått av, så rødt eller grønt ut, ikke avslått. Det gjaldt input,
1206
+ select, textarea, filopplasting, avkryssingsboks og radioknapp.
1207
+ - **Gjeldende side i `fs-pagination` ble uleselig under musa i høykontrast.**
1208
+ Hover-regelen slo høykontrastregelen, og bakgrunn og tekst fikk samme farge.
1209
+ - **Skilletegnet i `fs-breadcrumbs` ble lest opp.** Generert innhold leses
1210
+ opp, så skjermleseren sa «skråstrek» mellom hvert steg. Det har nå en tom
1211
+ alternativ tekst der nettleseren støtter det.
1212
+ - **Boblen i `fs-tooltip` forsvant før musa nådde den.** Gapet mellom knappen
1213
+ og boblen har nå en usynlig bro i knappens bredde mens boblen vises. Flytter
1214
+ du boblen under knappen, må broen også flyttes; snutten på komponentsiden
1215
+ har det med. Komponentsiden sier at boblen ikke kan
1216
+ lukkes med Escape, som WCAG 1.4.13 krever, og når Popover passer bedre.
1217
+ - **Pila i `fs-accordion` pekte sidelengs i høyre-til-venstre**, og pila i
1218
+ `fs-select` sto 6 piksler fra kanten der i stedet for 12.
1219
+ - **En overskrift i `summary` i `fs-accordion` fikk nettleserens marg og
1220
+ størrelse.** Dokumentasjonen viser `<summary><h3>`, og raden ble høyere og
1221
+ teksten større enn uten overskrift.
1222
+ - **Flaggene på klassene manglet i editoren og i regelbøkene.**
1223
+ `data-interactive` på `fs-card`, `data-selectable` på `fs-tag`,
1224
+ `data-hoverable` på `fs-table` og `data-optional` på `fs-label` og
1225
+ `fs-legend` sto i manifestet, men ikke i forklaringen i VS Code eller i
1226
+ tabellene en kodeagent leser. Klasseattributtene til web components, som
1227
+ `data-color` på `.fs-dialog`, sto heller ikke i regelbøkene.
1228
+ - **`fristil sjekk` ga feil på `<fs-error-summary data-autofocus="true">`.**
1229
+ Komponenten flytter fokus for alt annet enn `"false"`, og `"true"` er nå
1230
+ lovlig.
1231
+ - **Editoren sa at `required-marker="text"` skriver «må fylles ut».** Den
1232
+ skriver «(påkrevd)».
1233
+ - **Regelbøkene kalte `data-variant="outline"` oppfunnet.** Det er
1234
+ standardvarianten til `fs-card` og `fs-tag`. Eksempelet er nå `outlined`.
1235
+ `fs-theme-control` sto ikke i lista som kalles «hele lista».
1236
+ - **Språkserveren fant bare pakken ved rota av arbeidsområdet.** I et
1237
+ monorepo ble en side i `apps/web` sjekket mot det innebygde manifestet,
1238
+ enda `apps/web/node_modules` hadde pakken. Den leter nå fra mappa til fila
1239
+ og oppover, men ikke over rota av arbeidsområdet.
1240
+ - **Dokumentasjonen sa at feilmeldingene bare finnes i VS Code.** Pluginen
1241
+ for IntelliJ har dem, i filer og i HTML i en merket streng, og regelbøkene
1242
+ nevner nå den og Fristil for Kotlin.
1243
+ Kotlin-siden sa at hver tråd får sin egen instans av kjernen. Det er en
1244
+ pool.
1245
+
1246
+ ## 0.32.1 (2026-10-09)
1247
+
1248
+ ### Rettet
1249
+
1250
+ - **`fs-divider` var usynlig i flex og grid.** Nettleseren gir `<hr>`
1251
+ auto-marger til sidene, og i en flex-kolonne vinner de over
1252
+ `align-items: stretch`. Streken har ikke noe innhold å være bred av, så den
1253
+ ble 0 piksler bred og forsvant. Det gjaldt også eksempelet på
1254
+ komponentsiden og demosiden for sideskjelettet. Klassen nullstiller nå
1255
+ margene til sidene og strekker seg selv, så streken fyller bredden også i en
1256
+ flex- eller grid-forelder som sentrerer barna eller legger dem til start.
1257
+ Har du gjort streken smalere selv, står den nå til start; sett
1258
+ `margin-inline: auto` for å sentrere den.
1259
+
1260
+ ### Endret
1261
+
1262
+ - **`fs-divider` med `data-variant="subtle"` er litt tydeligere.** Den brukte
1263
+ `--fs-color-neutral-surface`, som lå så nær lerretet at streken nesten
1264
+ forsvant. Nå bruker den `--fs-color-neutral-raised`, som ligger mellom
1265
+ flatefargen og `border-subtle` i både lyst og mørkt tema.
1266
+
1267
+ ## 0.32.0 (2026-10-08)
1268
+
1269
+ ### Brytende
1270
+
1271
+ - **Sjekken er Rust-kjernen.** `diagnoseMarkup` og `diagnosePage` i
1272
+ `@fristil/designsystem/diagnostics` kjører nå den samme
1273
+ WebAssembly-modulen som VS Code, IntelliJ og Fristil for Kotlin, i stedet for
1274
+ en egen utgave i TypeScript. Svarene er de samme: begge utgavene ble kjørt
1275
+ side om side på over 4000 sider uten ett avvik før TypeScript-utgaven ble
1276
+ slettet. Modulen følger pakken og lastes første gang en av funksjonene
1277
+ kalles, i Node, Bun og Deno.
1278
+
1279
+ Disse forsvinner fra `@fristil/designsystem/diagnostics`:
1280
+
1281
+ | Borte | I stedet |
1282
+ | --- | --- |
1283
+ | `diagnose(text, elements, classes)` | `diagnoseMarkup(text)`. Et eget ordforråd gis som manifest med `loadCore(modul).loadManifest(json)`. |
1284
+ | `checkReferences(text)` | `diagnosePage(text)`, som gir koblingsfunnene sammen med resten. Regelnavnet i `rule` skiller dem. |
1285
+ | `pageSource(text)` | Ingen. `diagnosePage` leser siden slik den gjorde. |
1286
+ | `elements`, `classes` | `@fristil/designsystem/manifest.json`, med elementene, klassene og de lovlige verdiene. |
1287
+ | `closest`, `tagEnd`, `withoutHidden` | Ingen. De var hjelpere for sjekken. |
1288
+ | typene `Attribute`, `Element`, `Elements`, `ClassAttribute`, `ClassInfo`, `Classes` | Skjemaet i `@fristil/designsystem/manifest.json` (`manifest.schema.json`). |
1289
+
1290
+ `diagnosePage(text, elementer, klasser)` tar ikke lenger egne lister.
1291
+
1292
+ Ingenting endres i `fs`, i komponentene eller i CSS-en.
1293
+
1294
+ - **Temaet er Rust-kjernen.** `buildTheme` i `@fristil/designsystem/tema` og
1295
+ `inspectTheme` og `checkTheme` i `@fristil/designsystem/tema-sjekk` kjører
1296
+ den samme WebAssembly-modulen som sjekken. Svarene er de samme: de to
1297
+ utgavene ble kjørt side om side på over 6000 oppskrifter og temaer, med
1298
+ ugyldige farger, farlige verdier og ødelagt CSS, uten ett avvik, heller ikke
1299
+ i kontrastforholdene. `buildTheme` laster modulen fra pakken i Node, Bun og
1300
+ Deno. I nettleseren lastes den med `loadCore` fra
1301
+ `@fristil/designsystem/diagnostics`, og modulen er
1302
+ `@fristil/designsystem/kjerne.wasm`.
1303
+
1304
+ Fargekontrakten er data, i `src/tokens/fargekontrakt.json`, og regningen
1305
+ finnes bare i kjernen. Disse forsvinner:
1306
+
1307
+ | Borte | I stedet |
1308
+ | --- | --- |
1309
+ | `buildMatrix(merker, utseende)` fra `matrise` | `buildTheme(merker)`, som gir `light`, `dark` og `violations`. Fristils egne farger er `lightCells` og `darkCells` i `matrise`. |
1310
+ | `buildFamily`, `promisesFor`, `checkPromises` og typen `Violation` fra `kontrakt` | `buildTheme` for et tema, `inspectTheme` for å kontrollere ett. `Violation` står i `tema`. |
1311
+ | `parseBlocks` og typen `ParsedBlock` fra `tema-sjekk` | `inspectTheme`, som leser blokkene. |
1312
+ | typene `Matrix` og `RoleCss` fra `matrise` | `MatrixToken` gir hvert navn. |
1313
+
1314
+ `ROLES`, `NEUTRAL_LAYERS`, `REQUIREMENT`, `FAMILIES`, `FRISTIL_BRANDS`,
1315
+ `roleToCss` og `tokenName` er der som før, og `@fristil/designsystem/farge`
1316
+ er uendret.
1317
+
1318
+ - **Pakken krever Node 20.16 eller nyere** (`engines` i `package.json`), eller
1319
+ Bun eller Deno. Kjernen lastes med `process.getBuiltinModule`, som kom i
1320
+ Node 20.16 og 22.3. En eldre Node får beskjed om at versjonen er for
1321
+ gammel. Node 18 og 20 har ikke lenger støtte fra Node-prosjektet.
1322
+ - **`fristil overta` gir kopien nytt navn.** `fs-button` blir `app-button` i
1323
+ klassene, taggene, `customElements.define` og selektorene, så kopien er
1324
+ din og kan stå ved siden av originalen. Variablene fra temaet, `--fs-*`,
1325
+ beholder navnet. Bytt til det nye navnet i markupen der kopien skal brukes.
1326
+ Kopier du har tatt fra før, røres ikke.
1327
+
1328
+ ### Nytt
1329
+
1330
+ - **Kommandolinja uten Node.** Den samme kommandolinja kjører som
1331
+ `java -jar fristil.jar` (Java 17 eller nyere), i wasmtime som
1332
+ `fristil.wasm`, og som en kjørbar fil med
1333
+ `cargo install --git https://github.com/MarkusAugust/fristil fristil`.
1334
+ Jar-en og modulen ligger ved hver utgivelse på GitHub, med attestasjon av
1335
+ hvilken commit de ble bygd av, og svarer det samme som `npx`, byte for
1336
+ byte.
1337
+ - **`fristil overta` skriver et fragment av manifestet** ved siden av kopien,
1338
+ `fristil-manifest.json`, og `fristil sjekk --manifest=<fil>` sjekker
1339
+ markupen for kopien mot det. Bare kopiens egne navn sjekkes, ikke resten av
1340
+ prosjektets klasser.
1341
+ - **Sjekken ser stilarkene.** `fristil sjekk --css=<fil>`, og `css` som valg
1342
+ til `diagnoseMarkup` og `diagnosePage`, sier fra om en klasse ingen av
1343
+ stilarkene styler (`ustylet-klasse`) og om en verdi uten regel
1344
+ (`ustylet-verdi`). Stilarkene leses av en CSS-leser i kjernen, med
1345
+ nesting, `:is()`, `:where()`, `@layer` og `@import`. Pakkens egen kontroll
1346
+ av at CSS-en og manifestet sier det samme, bruker den også.
1347
+ - **`diagnoseRendered(page)`** sjekker siden slik nettleseren har rendret
1348
+ den, med Playwright: DOM-en etter at web-komponentene og skriptene har
1349
+ kjørt, og stilarkene den faktisk lastet, også fra et CDN.
1350
+ - **`fristil lsp`, språkserveren.** Funnene og hurtigrettelsene i hver editor
1351
+ som snakker LSP: Neovim, Helix, VS Code og andre, med UTF-16-posisjoner.
1352
+ Den sjekker mot manifestet i `build/fristil/` eller i `node_modules`, med
1353
+ det innebygde som reserve, og leser det på nytt når det endres. Den
1354
+ startes med `npx`, `java -jar`, wasmtime eller den kjørbare fila.
1355
+ - **`fristil manifest`** skriver manifestet sjekken bruker, med fragmentene
1356
+ lagt til, for en editor eller et annet verktøy.
1357
+ - **Gradle-pluginen `io.github.markusaugust.fristil`**, med `fristilSjekk`
1358
+ (kjøres av `check`), `fristilTema` og `fristilManifest`, som skriver
1359
+ `build/fristil/manifest.json`. Den kjører den samme kommandolinja i
1360
+ Gradle-prosessen.
1361
+
1362
+ - **Kommandolinja er skrevet i Rust.** `npx @fristil/designsystem` kjører den
1363
+ som en WASI-modul med Node sin egen `node:wasi`, og den samme koden kan
1364
+ bygges som en kjørbar fil. Kommandoene, flaggene, meldingene og feilkodene
1365
+ er de samme: alle 130 kjøringene i pakkens egen test av kommandolinja svarer
1366
+ likt, byte for byte. Én melding er ny: er en oppskrift til `fristil tema`
1367
+ ikke gyldig JSON, er forklaringen kjernens egen og ikke Nodes.
1368
+
1369
+ - **Funnene har regelnavn, linje og kolonne.** `rule` er navnet på regelen,
1370
+ som `ukjent-klasse`, og `line` og `column` er der funnet begynner, fra 1.
1371
+ - **Et funn kan undertrykkes med en kommentar** over taggen:
1372
+ `<!-- fristil-ignore-next ukjent-klasse -->`. Uten regelnavn gjelder den
1373
+ alle reglene for den neste taggen. Det virker i `fristil sjekk`, i
1374
+ editorene og i testene.
1375
+ - **`loadCore(modul)`** i `@fristil/designsystem/diagnostics` laster kjernen
1376
+ fra en modul du har selv, som i nettleseren eller i en utvidelse som pakker
1377
+ den med seg. Den gir også `loadManifest(json)`, `resetManifest()` og
1378
+ `version()`.
1379
+ - **`@fristil/designsystem/manifest.json`** beskriver hele ordforrådet og
1380
+ hver byggefunksjon som data, med skjema. Det er det Fristil for Kotlin
1381
+ genereres fra, og det kjernen sjekker mot.
1382
+ - **`data-color` på `fs-dialog` sjekkes.** Sjekken kjente ikke fargene
1383
+ `fs.dialog({ color })` gir, fordi ordlista bare leste byggefunksjoner som
1384
+ svarer med ett sett. `data-color="red"` sa derfor ingenting. Nå meldes en
1385
+ ukjent farge, med de fem lovlige og `neutral` som standard.
1386
+ - **Flaggene på klassene står i manifestet:** `data-optional` på `fs-label`
1387
+ og `fs-legend`, `data-interactive` på `fs-card`, `data-selectable` på
1388
+ `fs-tag` og `data-hoverable` på `fs-table`. Sjekken sier fra om
1389
+ `data-optional="false"`, som slår flagget på, slik den gjør for boolske
1390
+ attributter på elementene.
1391
+ - **Kommentarer i malspråkene hoppes over.** Markup i `{{-- --}}` i Blade,
1392
+ `@* *@` i Razor, `{{/* */}}` i Go, `{# #}` i Jinja, Twig og Nunjucks, og
1393
+ `<%-- --%>` i JSP ble sjekket som om den ble rendret, og en tagg i en
1394
+ kommentar ga funn.
1395
+ - **`fristil sjekk-tema` og `inspectTheme` leser CSS med en ekte
1396
+ tokenizer**, den fra Servo som Firefox bruker. En klamme eller et semikolon
1397
+ i en streng, i `url(…)` eller i en kommentar delte en blokk eller en
1398
+ deklarasjon, og en farge kunne forsvinne fra kontrollen uten et ord. En
1399
+ blokk som ikke er lukket, leses nå til fila slutter, slik nettleseren gjør,
1400
+ i stedet for å hoppes over, og meldingen om klammene står fortsatt.
1401
+ - **En stor side med mange funn sjekkes raskere.** Linja og kolonnen til hvert
1402
+ funn ble regnet fra starten av teksten. 6000 funn på en side med 3000 linjer
1403
+ tok en kvart sekund, og tar nå 25 millisekunder.
1404
+
1405
+ - **Hver side i dokumentasjonen finnes som Markdown.** `/components/button/`
1406
+ har sin på `/components/button.md`, og hver side lenker til sin med
1407
+ `<link rel="alternate" type="text/markdown">`. Lenkene i `/llms.txt` går dit.
1408
+ Filene lages av de bygde sidene, så «Ren HTML»-fanen med `<link>`-ene,
1409
+ importlinjene og versjonsnummeret står der slik siden viser dem, og fanene
1410
+ står etter hverandre.
1411
+
1412
+ ## 0.31.0 (2026-10-06)
1413
+
1414
+ ### Nytt
1415
+
1416
+ - **`fristil sjekk` sjekker hele sider.** En adresse, som
1417
+ `fristil sjekk http://localhost:8080/skjema`, hentes og sjekkes som en hel
1418
+ side, og `--rendret` gjør det samme for filer og standard inn. På en hel side
1419
+ kreves det i tillegg at hver id i `for`, `aria-describedby`,
1420
+ `aria-labelledby` og `aria-controls` finnes, at `for` peker på et felt, at
1421
+ ingen id står to ganger, at hvert felt med en `fs-`-klasse har en
1422
+ ledetekst, at hver synlige hjelpetekst og feilmelding som ikke er et
1423
+ statusfelt er koblet, og at hver
1424
+ lenke i `<fs-error-summary>` går til en id som finnes. En adresse som svarer
1425
+ med noe annet enn HTML, gir feilkode. Bar markup inni `<fs-field>` gir ingen
1426
+ funn. En mal sjekkes som før uten flagget, siden en id der kan stå i en
1427
+ annen fil.
1428
+ - **`diagnosePage(html)` og `checkReferences(html)`** i
1429
+ `@fristil/designsystem/diagnostics` gir den samme sjekken til tester skrevet
1430
+ i JavaScript. **`pageSource(html)`** gir siden slik sjekken leser den, uten
1431
+ kommentarer, innholdet i `<script>`, `<style>`, `<textarea>` og
1432
+ `<template>`, og markup i attributtverdier, med posisjonene uendret.
1433
+
1434
+ ## 0.30.0 (2026-10-05)
1435
+
1436
+ ### Nytt
1437
+
1438
+ - **Kolonner som kan sorteres i `.fs-table`.** `.fs-table__sort` er knappen
1439
+ i overskriften, og `aria-sort` på `<th>` er tilstanden. Pila tegnes fra
1440
+ `aria-sort`, med begge pilene dempet når kolonnen ikke er sortert, og
1441
+ knappen fyller cellen, så overskriftsraden har samme høyde og innrykk som
1442
+ uten knapp. `fs.tableSort({ direction })` gir `header` og `button`, og
1443
+ `tableSortDirections` er de lovlige retningene. Sorteringen er appens.
1444
+
1445
+ ## 0.29.0 (2026-10-05)
1446
+
1447
+ ### Brytende
1448
+
1449
+ - **`<fs-session-timeout>` lager ikke lenger dialogen selv.** Den som
1450
+ rendrer skriver dialogen og teksten inne i elementet, på sitt eget språk,
1451
+ og komponenten tar tiden: den åpner og lukker dialogen, fyller inn tallet
1452
+ og leser opp nedtellingen. Før var tittelen, teksten og knappene norsk
1453
+ skrevet rett i koden, og kunne ikke oversettes. Komponenten finner delene
1454
+ på `<dialog>`, `.fs-session-timeout__count`, `[role=status]` og knappene i
1455
+ et `<form method="dialog">`, og setter `open` tilbake når en morfing tar
1456
+ det fra en dialog som står i topplaget, slik `<fs-dialog>` gjør. Uten det
1457
+ sto siden fast etter en patch fra Datastar uten `data-ignore-morph`. En
1458
+ knapp med `value="logout"` logger ut, og
1459
+ alt annet, Escape medregnet, forlenger. Hendelsene, `warn-at`,
1460
+ `expires-at`, `extend()` og `reset()` er de samme, men `session-logout`
1461
+ og `session-extend` fra en knapp kommer nå med `close`-hendelsen, altså
1462
+ litt etter klikket og ikke i det. Det du må gjøre: skriv
1463
+ dialogen inn i elementet, slik komponentsiden viser. Et tomt
1464
+ `<fs-session-timeout>` sier fra i konsollen i det varselet skulle kommet,
1465
+ og `fristil sjekk` melder det.
1466
+ - **`fs.sessionTimeout()` gir ett attributtsett per del,** som
1467
+ `fs.dialog()`: `host`, `dialog`, `title`, `text`, `count`, `live`,
1468
+ `actions`, `extend` og `logout`. `titleId` er påkrevd, siden en id som
1469
+ lages av seg selv ikke overlever hydrering.
1470
+ - **Komponenten ligger i `ramme/` og ikke i `frittstaende/`.** Navnene i
1471
+ `exports` er de samme, men stien til fila er ny. Det du må gjøre: lenker
1472
+ du rett til fila på en CDN, bytt `frittstaende/session-timeout` med
1473
+ `ramme/session-timeout` i adressen.
1474
+
1475
+ - **Skrifttokenene heter `--fs-font-size-*` og `--fs-font-weight-*`.** De
1476
+ fjorten navnene var de eneste uten `fs-`, og de står på `:root` i en side
1477
+ Fristil ikke alltid eier. Et annet designsystem på samme side deklarerte de
1478
+ samme navnene, og da avgjorde rekkefølgen på stilarkene hvilken verdi
1479
+ begge systemenes komponenter fikk. Ved 0.22.0 fikk de beholde navnene,
1480
+ siden de alt fulgte CSS-egenskapen de setter; det holder ikke når
1481
+ navnet deles med andre. Det gjelder de ni størrelsene, de fire vektene og
1482
+ `--font-family-base` fra temageneratoren, som nå heter
1483
+ `--fs-font-family-base`. Tailwind-klassene, som `text-fs-m`, heter det
1484
+ samme. Det finnes ingen aliaser, siden et alias fortsatt måtte stått på
1485
+ `:root` under det gamle navnet. Det du må gjøre: bytt `--font-size-` med
1486
+ `--fs-font-size-`, `--font-weight-` med `--fs-font-weight-` og
1487
+ `--font-family-base` med `--fs-font-family-base` i egen CSS, og lag
1488
+ temaet ditt på nytt med `fristil tema` hvis du har ett. Et tema laget med
1489
+ en eldre utgave setter skriften under de gamle navnene, og den delen av
1490
+ temaet virker ikke lenger uten at noe sier fra. Fargene virker som før.
1491
+
1492
+ ### Nytt
1493
+
1494
+ - **`data-fs-boundary` er en grense mot vertssiden.** Bygges en komponent
1495
+ inn i en side du ikke eier, slår vertens CSS uten lag `@layer fristil`, og
1496
+ en `button { background: none }` tar bakgrunnen fra `.fs-button`. Under
1497
+ et element med attributtet ser nettleseren bort fra CSS uten lag, så
1498
+ Fristils lag gjelder igjen, mens skrift og annet som arves fortsatt kommer
1499
+ fra verten og `--fs-*`-variablene virker. Regelen ligger i `fristil.css`,
1500
+ og som `@fristil/designsystem/boundary.css`. Den har spesifisiteten (0,2,0),
1501
+ og egen CSS inne i grensen må ligge i et lag. Se «Vertens CSS stopper ved
1502
+ grensen» under Tilpasning.
1503
+ - **`--fs-select-padding` og `--fs-select-width`.** Luften i nedtrekkslista
1504
+ kan settes som i feltet. I standardutseendet står plassen til pila fast,
1505
+ og `auto` gir et kompakt felt så bredt som innholdet.
1506
+ - **`--fs-input-width`,** av samme grunn.
1507
+ - **Boblen i `.fs-tooltip` har `box-sizing: border-box`,** så
1508
+ `--fs-tooltip-width` er hele boblen også i en side uten en CSS-reset.
1509
+
1510
+ - **`close-label` på `<fs-toast>`** er standard for hva lukkeknappen i hver
1511
+ melding heter for skjermleseren. `fs.toast({ closeLabel })` skriver det,
1512
+ og `closeLabel` i `show()` overstyrer det for én melding.
1513
+ - **Antall treff i `<fs-suggestion>` kan oversettes,** med `count-none`,
1514
+ `count-one` og `count-other`, og `count-zero`, `count-two`, `count-few` og
1515
+ `count-many` for språk som har dem. `{n}` står for antallet, og
1516
+ `Intl.PluralRules` velger form etter `lang` på siden. Uten attributtene er
1517
+ teksten norsk som før.
1518
+ - **Markeringen på `.fs-label` og `.fs-legend` leses fra variabler:**
1519
+ `--fs-label-required-symbol`, `--fs-label-required-text` og
1520
+ `--fs-label-optional-text`, med « *», « (påkrevd)» og « (valgfri)» som
1521
+ reserve.
1522
+ - **Opplesningen av nedtellingen følger sidens språk.** Varigheten skrives
1523
+ med `Intl` etter `lang`, så den er «1 minutt og 30 sekunder» på en norsk
1524
+ side og «1 minute and 30 seconds» på en engelsk.
1525
+ - **`@fristil/designsystem/default-texts`** har hver standardtekst pakken
1526
+ skriver inn i siden. En vaktpost i bygget feller en tekst som står rett i
1527
+ en komponent i stedet for der, en tekst i CSS som ikke leses fra en
1528
+ variabel, og en tekst som mangler i tabellen på siden om oversettelse.
1529
+
1530
+ ## 0.28.0 (2026-10-04)
1531
+
1532
+ ### Brytende
1533
+
1534
+ - **`.fs-toast` er nå klassen på regionen, og meldingen heter
1535
+ `.fs-toast__message`.** Regionen ble stylet med elementnavnet, så en
1536
+ `<fs-toast>` registrert under et annet navn mistet plasseringen i hjørnet.
1537
+ Komponenten setter klassen på seg selv, og `fs.toast().host` skriver den.
1538
+ Elementnavnet `fs-toast` har fortsatt de samme reglene, så en region uten
1539
+ klassen står der den sto.
1540
+ Det du må gjøre: har du egen CSS mot `.fs-toast`, eller en server som
1541
+ skriver meldinger rett inn i regionen, bytt til `.fs-toast__message`.
1542
+ `fs.toast().toast` heter `fs.toast().message`, og `TOAST_MESSAGE_CLASS` er
1543
+ ny ved siden av `TOAST_CLASS`. `--fs-toast-*`-variablene er de samme.
1544
+ - **Varianten `default` på hjelpeteksten heter `strong`.** Standardverdien
1545
+ er `muted`, og overalt ellers betyr `default` «gir ikke attributt». Det du
1546
+ må gjøre: bytt `data-variant="default"` med `data-variant="strong"`, og
1547
+ `fs.helpText({ variant: "default" })` med `"strong"`.
1548
+ - **`fs.suggestion()` leser ikke lenger `open` for tommeldingen.** Den
1549
+ skriver `hidden` på «Ingen treff» når det finnes treff, eller når `pending`
1550
+ er satt. At lista er lukket, tar stilarket seg av: `.fs-suggestion__empty`
1551
+ vises ikke etter en liste med `hidden`. Før måtte en app som filtrerer selv
1552
+ (`prefiltered`) sende `open`, en tilstand bare komponenten kjenner, så
1553
+ meldingen kunne aldri vises. Det du må gjøre: tommeldingen må stå etter
1554
+ lista, som søsken, og et asynkront søk sender `pending: true` mens svaret
1555
+ er underveis.
1556
+ - **Forslagslista åpnes ikke når den er tom og feltet er tomt.** Fokus åpnet
1557
+ en liste uten alternativer, med `aria-expanded="true"` over ingenting. Et
1558
+ felt som venter på sitt første søk viser dermed ikke «Ingen treff» før
1559
+ brukeren har skrevet noe.
1560
+
1561
+ - **`fs.setAttributes` rydder bare det byggefunksjonen selv forvalter.**
1562
+ Før hadde den én felles liste, og `fs.setAttributes(knapp, fs.button())`
1563
+ fjernet `disabled`, `hidden`, `open`, `aria-describedby`, `multiple` og
1564
+ `accept` fra elementet, selv om knappefunksjonen aldri har skrevet noen av
1565
+ dem. En deaktivert knapp ble aktiv, og et åpent `<details>` lukket seg. Nå
1566
+ fjernes et attributt bare når settet kommer fra en byggefunksjon som
1567
+ skriver det: `fs.switch()` kan ta bort `disabled`, `fs.button()` rører det
1568
+ ikke. Regelen går begge veier: har byggefunksjonen et valg for et
1569
+ attributt, eier den det. `fs.spinner()` har `label`, så et kall uten
1570
+ `label` fjerner `role` og `aria-label`, også når du skrev dem for hånd.
1571
+ Det gjorde den ikke før. `id` og `for` fjernes aldri. Det du må gjøre:
1572
+ send valgene på nytt i hvert kall, og skal to sett på samme element, send
1573
+ dem hver for seg, `fs.setAttributes(felt, fs.input(), kobling.control)`,
1574
+ ikke spredd sammen i ett objekt. Et spredd objekt settes riktig, men rydder
1575
+ bare `data-*`, og funksjonen sier fra i konsollen første gang.
1576
+
1577
+ ### Lagt til
1578
+
1579
+ - **`pending` i `fs.suggestion()`.** Holder «Ingen treff» skjult mens svaret
1580
+ på et søk er underveis.
1581
+ - **Regelboka for bundlere forklarer `fs.setAttributes()`.** Ingen av
1582
+ regelbøkene nevnte funksjonen, så en kodeagent som skrev markup uten
1583
+ spredning fikk ikke vite om den, eller om at to sett sendes hver for seg.
1584
+
1585
+ ### Rettet
1586
+
1587
+ - **En dialog styrt av React-tilstand lot seg ikke lukke i React 19.** React
1588
+ skriver `el.open = undefined` når en prop går fra `true` til borte, og
1589
+ setteren vekslet attributtet i stedet for å fjerne det. Dialogen åpnet seg
1590
+ igjen etter både knappen og Escape, og sprettoppvinduet ble stående åpent.
1591
+ Det samme gjaldt `invalid`, `disabled` og `optional` på `<fs-field>` og
1592
+ `prefiltered` på `<fs-suggestion>`.
1593
+ - **Fanene lot seg ikke bytte under `server-controlled`.** Klikket ble angret
1594
+ i neste mikrotask, fordi komponenten leste serverens gamle valg fra minnet.
1595
+ Klikket står nå til noen andre rører `aria-selected` eller `hidden`, og da
1596
+ bestemmer serveren som før.
1597
+ - **`optional` og `required-marker` på `<fs-field>` lot seg ikke slå av.**
1598
+ Komponenten leste sin egen `data-optional` og `data-required` tilbake fra
1599
+ ledeteksten. Markeringer serveren skrev der, står fortsatt.
1600
+ - **`<fs-field>` fjernet en `data-state="invalid"` malen hadde skrevet.** Den
1601
+ fjerner nå bare den den selv satte.
1602
+ - **Feiloppsummeringen tok fokus når en synlig liste ble tømt og fylt igjen.**
1603
+ Brukeren ble rykket ut av feltet han rettet. Fokus flyttes nå bare når
1604
+ boksen går fra skjult til synlig.
1605
+ - **`<fs-connection-status>` ble hengende etter å ha vært ute av dokumentet.**
1606
+ Kvitteringen sto for godt, og linja sa offline etter at nettet var tilbake.
1607
+ - **Økttidsvarselet sluttet å være modalt når elementet ble flyttet,** og
1608
+ opplesningen sa «2 minutter» med 1:30 igjen. Den sier nå «ett minutt og 30
1609
+ sekunder».
1610
+ - **`fs.setAttributes` rydder de boolske valgene.** `data-interactive` på
1611
+ kortet, `data-hoverable` på tabellen, `data-selectable` på etiketten,
1612
+ `data-autofocus` på feiloppsummeringen og `placement` på sprettoppvinduet
1613
+ ble stående etter at valget var tatt bort.
1614
+ - **`fristil tema --merke1`, `--merke2` og `--merke3` ble lest som
1615
+ filnavn.** Flaggleseren godtok ikke sifre.
1616
+ - **`fristil overta button --ut src/ui` ignorerte flagget** og skrev til
1617
+ standardmappa. Den stopper nå og ber om likhetstegn, slik `agent` gjør.
1618
+ - **Advarselen fra `fs.dialog()` uten id ba om `id`.** Valget heter
1619
+ `titleId`, og det står nå i meldingen.
1620
+ - **Eksempellinja i `fristil --hjelp`** hadde en linjefortsettelse som ble
1621
+ til fem mellomrom midt i kommandoen.
1622
+ - **En deaktivert knapp med variant så aktiv ut.** `secondary`, `ghost` og
1623
+ `danger` hadde samme bakgrunn, tekst og kant med og uten `disabled`, og
1624
+ fikk hoverfarge under musa. Regelen for deaktivert sto over variantene og
1625
+ tapte på rekkefølgen.
1626
+ - **Musa tok bort feilrammen og rammen på en valgt** avkryssingsboks, radio
1627
+ og bryter. Hover var løftet over tilstandene med `:not(:disabled)`.
1628
+ - **Hjelpeboblen sto en hel boblebredde til venstre i RTL.**
1629
+ - **Søkefeltet mistet forstørrelsesglasset** når det var ugyldig, gyldig
1630
+ eller deaktivert og `input.css` ble lastet etter `search.css`. Tilstandene
1631
+ setter nå `background-color` og ikke kortformen.
1632
+ - **«(valgfri)» hadde kontrast 4,37:1 i lyst tema.** Teksten brukte fargen
1633
+ for deaktivert tekst. Den bruker nå `--fs-color-neutral-text-subtle`.
1634
+ - **«(påkrevd)» kunne komme ut som «pÃ¥krevd».** Tegnet sto rått i
1635
+ stilarket, og en side uten `<meta charset>` fra en tjener som ikke sender
1636
+ tegnsettet, leste det feil. Det står nå som en escape.
1637
+ - **Markup med både `data-required` og `data-optional` viste «(valgfri)».**
1638
+ Byggefunksjonen velger påkrevd, og stilarket gjør nå det samme.
1639
+ - **Regelbøkene for kodeagenter sa tre ting som ikke stemte.** At
1640
+ registrering på en server gir «customElements is not defined» (den gjør
1641
+ ingenting, uten et ord), at siden «ser tom ut» uten registrering (det gjelder
1642
+ bare de tre frittstående), og at `tokens.css` må lastes før komponentens
1643
+ stilark (rekkefølgen betyr ikke noe). React-boka viser nå `fs.field()` med
1644
+ `useId()` for et felt, ikke `<fs-field>`, som gir hydreringsfeil med
1645
+ server-rendring. Formatet fra `fristil sjekk` står med alvoret,
1646
+ `fil:linje:kolonne: feil: melding`.
1647
+ - **Lenkene til dokumentasjonen peker på `fristil.sobernetics.no`.**
1648
+ `homepage` i pakken, regelbøkene, `web-types.json` og lenkene diagnostikken
1649
+ skriver ut brukte `fristil.netlify.app`.
1650
+ - **Byttet en patch ut et panel i `<fs-tabs>`, sto fanen og pekte på en id
1651
+ som ikke fantes.** Det nye panelet fikk verken id, rolle eller `hidden`.
1652
+ Det får nå den samme id-en fanen alt peker på. `<fs-suggestion>` gjør det
1653
+ samme for feltet og lista: et nytt felt får id-en ledetekstens `for` peker
1654
+ på.
1655
+ - **Fanene tok piltaster med Alt, Ctrl og Cmd.** Alt+venstrepil er «tilbake»
1656
+ i nettleseren, og ble stoppet.
1657
+ - **Escape i et sprettoppvindu inne i en modal dialog lukket begge.**
1658
+ Tastetrykket stopper nå i vinduet.
1659
+ - **Feiloppsummeringen meldte en prosentkodet lenke som brutt.**
1660
+ `href="#f%C3%B8dselsdato"` peker på `id="fødselsdato"`, og oppslaget
1661
+ dekoder nå fragmentet slik nettleseren gjør.
1662
+ - **Økttidsvarselet frøs når `warn-at` ble hevet mens dialogen sto.**
1663
+ - **Tilkoblingslinja viste den gamle teksten** når `offline-text` eller
1664
+ `online-text` ble byttet mens den sto.
1665
+ - **Skillelinja og skjelettet var usynlige i høykontrastmodus.** Begge var
1666
+ bare en bakgrunn. Linja bruker nå en systemfarge, og skjelettet får en
1667
+ kant.
1668
+ - **Et kort som er en `<button>` hadde nettleserens knappeskrift,** 13
1669
+ piksler. Kortet arver nå hele skriften.
1670
+ - **`<span aria-disabled="true">` i sidenavigeringen hadde ikke boksen til
1671
+ lenkene,** så rekka hoppet når «Neste» ble byttet inn på siste side.
1672
+
1673
+ ## 0.27.1 (2026-10-03)
1674
+
1675
+ ### Rettet
1676
+
1677
+ - **Størrelsen på `fristil.css` i regelbøkene.** Tre av dem sa «rundt 75 kB,
1678
+ under 10 kB komprimert» om en fil på 90 kB og 11 kB. Tallet var hardkodet i
1679
+ generatoren; det regnes nå ut av de samme `exports`-oppføringene fila
1680
+ bygges av. `bygg:css` skrev også KiB merket som kB, og telte
1681
+ UTF-16-kodeenheter framfor byte.
1682
+
1683
+ ## 0.27.0 (2026-10-02)
1684
+
1685
+ ### Lagt til
1686
+
1687
+ - **`fs.progress()` og `progress.css`.** En framdriftsstolpe på et ekte
1688
+ `<progress>`, så rollen og opplesningen av tallet kommer fra nettleseren.
1689
+ `data-color` gir `success`, `warning` og `danger`, og uten `value` blir
1690
+ stolpen ubestemt. `max` har standardverdien 100 og skrives alltid ut: HTMLs
1691
+ egen standard er `1`, og en `<progress value="40">` uten `max` viser en full
1692
+ stolpe uten at noe sier fra.
1693
+
1694
+ ## 0.26.1 (2026-10-02)
1695
+
1696
+ ### Rettet
1697
+
1698
+ - **Beskrivelsene i klassekatalogen stemmer med komponentsidene.** `classes.ts`
1699
+ og `web-types.json` leser frontmatteren fra hver komponentside, og fire av dem
1700
+ sa «én klasse» om en komponent med to. Hoverboksen i VS Code og
1701
+ JetBrains-IDE-ene siterte tallet videre.
1702
+
1703
+ ## 0.26.0 (2026-10-02)
1704
+
1705
+ ### Lagt til
1706
+
1707
+ - **`.fs-theme-control` lar brukeren velge tema uten JavaScript.** Klassen står
1708
+ på en radioknapp, og `value` sier hvilket tema den velger: `auto`, `light`
1709
+ eller `dark`. Selektoren er en ekstra linje på de to temablokkene i
1710
+ `tokens.css`, og den samme linja i temaer `buildTheme()` skriver. «Følg
1711
+ systemet» har ingen temablokk, siden en verdi uten blokk nettopp skal falle
1712
+ tilbake på mediespørringen. `light` og `dark` vinner over `data-theme` på
1713
+ `<html>`, slik at serveren kan sende et lagret valg mens et klikk slår
1714
+ igjennom før svaret er tilbake. `auto` gjør det ikke: har serveren skrevet
1715
+ `data-theme`, står serverens verdi, og det som lagrer valget må også fjerne
1716
+ attributtet.
1717
+ - **Hvert av de tre valgene setter `color-scheme` selv.** `light` gir `light`,
1718
+ `dark` gir `dark`, og `auto` gir `light dark` så lenge `<html>` ikke bærer
1719
+ `data-theme="light"` eller `data-theme="dark"`. Det siste er ikke et tema, men beskjeden til nettleseren om at siden
1720
+ fungerer i begge, så den kan tegne sine egne flater etter systemet.
1721
+
1722
+ Bruker du velgeren, skal du ikke skrive `color-scheme` på `<html>` selv: en
1723
+ regel utenfor et lag slår `@layer fristil`, og nettleserens egne flater blir
1724
+ låst til systemet mens brukeren har valgt noe annet. For den som ikke bruker
1725
+ velgeren, er ingenting endret, og bar `:root` har fortsatt ingen
1726
+ `color-scheme`.
1727
+
1728
+ Overstyrer du et token per tema, må dine egne `[data-theme]`-blokker ha
1729
+ velgerens selektor ved siden av. CSS kan ikke skrive et attributt, så
1730
+ velgeren setter ingen `data-theme`.
1731
+
1732
+ ## 0.25.0 (2026-10-01)
1733
+
1734
+ ### Rettet
1735
+
1736
+ - **Språkvask i regelbøkene og dokumentasjonen.** Et «de» som skulle vært
1737
+ «dem», og en forklaring og et eksempel som var lånt fra en konkret
1738
+ feilrapport framfor å stå på egne bein. Teksten beskriver nå mekanismen:
1739
+ en innebygd komponent i en vertsside.
1740
+
1741
+ ## 0.24.0 (2026-10-01)
1742
+
1743
+ ### Lagt til
1744
+
1745
+ - **JetBrains-IDE-ene foreslår nå `fs-`-klassene.** `web-types.json` hadde
1746
+ bare de ni web-komponentene, så du fikk forslag på `<fs-field>` men
1747
+ ingenting på `fs-button`, enda klassene er den eneste delen en
1748
+ CSS-komponent har. Nå står alle 72 under `contributions.css.classes`, med
1749
+ komponentnavn og lenke til dokumentasjonssiden.
1750
+
1751
+ VS Code-utvidelsen har hatt dette hele tiden, i kode framfor i data, så
1752
+ dette retter en skjevhet mellom de to editorene. Lista bygges av
1753
+ `classesData()`, den samme funksjonen som skriver `classes.ts`, så editoren
1754
+ kan ikke foreslå en klasse diagnostikken avviser.
1755
+
1756
+ ## 0.23.0 (2026-10-01)
1757
+
1758
+ ### Brytende
1759
+
1760
+ - **`data-theme="light"` deklarerer nå alle de lyse tokenene, ikke bare
1761
+ `color-scheme`.** Før sto blokken med én linje mens `[data-theme="dark"]`
1762
+ hadde alle 90, så lyst tema virket bare på `<html>`: et barn kan ikke
1763
+ overstyre en variabel det arver uten å deklarere den på nytt. Nå er
1764
+ attributtet en temagrense begge veier, på et hvilket som helst element, og
1765
+ et tema kan ligge inne i et annet.
1766
+
1767
+ **Overstyrer du en farge per tema, må du legge til en `[data-theme="light"]`-
1768
+ blokk.** En deklarasjon på elementet selv vinner over en verdi det arver,
1769
+ uansett hvilket lag arven kom fra, så uten blokken står Fristils egen farge
1770
+ inne i en lys temagrense mens din gjelder ellers på siden. Oppskriften i
1771
+ «Tilpasning» viser alle fire blokkene.
1772
+
1773
+ - **Temageneratoren skriver nå også `[data-theme="light"]`.** `buildTheme()`
1774
+ skrev `:root`, mediespørringen og `[data-theme="dark"]`, men ikke den lyse
1775
+ blokken, så et generert tema hadde nøyaktig den samme asymmetrien: inne i en
1776
+ lys temagrense sto Fristils egen farge, mens temaets farge gjaldt ellers på
1777
+ siden. Har du et generert tema, må fila skrives om igjen med
1778
+ `fristil tema` for å få blokken.
1779
+
1780
+ - **`color-scheme` settes ikke lenger på `:root`.** Den står bare på
1781
+ `[data-theme="light"]` og `[data-theme="dark"]`, altså der noen har valgt et
1782
+ tema. Egenskapen arves nedover, så en verdi på roten gjaldt hele dokumentet,
1783
+ også der pakken bare er en gjest: en komponent som lastet `fristil.css` inn
1784
+ i en vertsside ga hele verten mørke rullefelt og skjemakontroller i mørk
1785
+ modus, langt utenfor komponenten selv.
1786
+
1787
+ **Vil du at nettleserens flater skal følge systemet på hele siden, skriver
1788
+ du `color-scheme: light dark` på `<html>` selv.** Det er den samme avtalen
1789
+ som for lagrekkefølgen.
1790
+
1791
+ ### Rettet
1792
+
1793
+ - **Regelbøkene for kodeagenter og dokumentasjonen sa ulike ord om det samme.**
1794
+ Regelbøkene under `agent/` skrev «byggerne» og «egendefinert element» der
1795
+ dokumentasjonen skrev «byggefunksjon» og «web component». En agent som får
1796
+ begge i konteksten møtte to navn på én ting. `sjekk-ordbruk.ts` vokter nå
1797
+ begge ordene, og leser også `README.md` i pakken, som den ikke gjorde før.
1798
+
1799
+ ## 0.22.0 (2026-09-29)
1800
+
1801
+ ### Brytende
1802
+
1803
+ - **Fargene er en matrise, ikke to lag.** En farge er et punkt i en matrise av
1804
+ **familie** (`accent`, `visited`, `brand1-3`, `neutral`, `danger`, `warning`,
1805
+ `success`) og **rolle** (`surface`, `border-subtle`, `border`,
1806
+ `border-strong`, `fill`, `content`, `text-subtle`, `text`, `text-strong`).
1807
+ Navnet er `--fs-color-<familie>-<rolle>`.
1808
+
1809
+ `--palette-*` og `--semantic-*` er borte. Det samme er `--size-*`, som nå
1810
+ heter `--fs-spacing-*`. Hvert fargenavn, hver avstand, hver linjeavstand,
1811
+ hvert ikon, skyggen og fokusringen heter nå `--fs-<slag>-<navn>`, som hos
1812
+ Tailwind, daisyUI og Digdir, og slaget i navnet er det som lar Tailwind-temaet
1813
+ bli generert framfor skrevet av for hånd. De tretten `--font-size-*` og
1814
+ `--font-weight-*` beholder navnene sine, siden de alt følger CSS-egenskapen
1815
+ de setter.
1816
+
1817
+ - **Kontrasten er garantert av konstruksjonen.** Kuløren er konsumentens,
1818
+ lysheten er rollens. Lyshetene er regnet fram mot et sveip rundt hele
1819
+ fargesirkelen på den høyeste metningen sRGB kan vise, så løftene holder
1820
+ uansett merkefarge. Justeringspasset som flyttet fargen din etterpå er borte,
1821
+ og det samme er metningstaket `maxChroma`: uten et pass å mate finnes det
1822
+ ingenting å dempe for.
1823
+
1824
+ - **Generatoren er 352 linjer mot 744.** `buildScale`, `buildNeutralScale`,
1825
+ `adjustForContrast`, `SCALE_STEPS`, `NEUTRAL_STEPS`, `MAX_CHROMA`,
1826
+ `CHROMA_FLOOR`, `CHROMA_CEILING` og typen `AdjustResult` er fjernet fra
1827
+ `@fristil/designsystem/farge`, som nå bare har fargeregningen. Fra
1828
+ `@fristil/designsystem/tema` er typen `ThemeAdjustment` og feltet
1829
+ `Theme.adjustments` borte.
1830
+ En familie du utelater arver Fristils egen framfor å felle kjøringen, så
1831
+ `fristil tema --aksent=#7c3aed` er nok. Flagget het `--interaktiv`, og heter
1832
+ nå `--aksent`, som familien. To navn på den samme fargen var nettopp det
1833
+ matrisen skulle bli kvitt.
1834
+
1835
+ - **To nye roller og ett nytt lag kom av migreringen.** `border-strong`, fordi koden brukte
1836
+ tre kantnivåer og matrisen hadde to: en feltramme som endrer seg ved hover,
1837
+ og en tabellstrek som er tydeligere enn en radskiller. `text-strong`, fordi
1838
+ brødtekst satt til `text` ble `#4a4d51` der den før var `#1a1a1a`, altså
1839
+ 8,5:1 mot hvitt der den hadde 17,4:1. Kravet holdt, lesbarheten ikke.
1840
+ Brødteksten står nå på `text-strong`, `#27292b`, som er 14,6:1. Og `raised`,
1841
+ som er et lag den nøytrale familien har ved siden av rollene, siden tekst må
1842
+ holde mot et kort som ligger over et kort.
1843
+
1844
+ ### Lagt til
1845
+
1846
+ - **`fristil sjekk-tema <fil…>`** kontrollerer et tema noen har skrevet selv,
1847
+ og sier hvilken celle som ryker og hvorfor. Den teller verdiene konsumenten
1848
+ selv skrev: både filtallet og løftetallet er de samme for én linje som for et
1849
+ helt tema, siden standardverdiene fyller hullene.
1850
+
1851
+ - **Tre nye inngangspunkter:** `./kontrakt` med rollene og løftene, `./matrise`
1852
+ som bygger et tokensett av merkefarger, og `./tema-sjekk`.
1853
+
1854
+ ### Rettet
1855
+
1856
+ - **Gjeldende side i pagineringen forsvant under musa.**
1857
+ `.fs-pagination a:hover` slo `[aria-current="page"]` på spesifisitet, så
1858
+ sidetallet brukeren sto på fikk en lys flate mens teksten ble stående i
1859
+ `accent-content`: 1,09:1 i lyst tema og 1,25:1 i mørkt. Gjeldende side er nå
1860
+ unntatt fra regelen og har sin egen hover. Feilen har vært der siden
1861
+ pagineringen kom, og ingen test så den, fordi `:hover` ikke kan leses av
1862
+ `getComputedStyle`.
1863
+
1864
+ `hover.browser.test.ts` fører nå musa over tolv av de fjorten hover-reglene
1865
+ som bytter bakgrunn, i begge temaer, og krever 4,5:1. De to siste ligger bak
1866
+ et pseudoelement og bak en `@supports` Firefox ikke har, og kontrolleres på
1867
+ tokenparet. Lista er bundet til stilarkene, så en ny slik regel uten et
1868
+ tilfelle feller testen, og hvert tilfelle påstår at flaten under musa er en
1869
+ annen enn flaten uten.
1870
+
1871
+ - **Siste steg i brødsmulestien ble blått under musa.** Samme årsak:
1872
+ `:hover` slo `[aria-current="page"]`. Gjeldende steg er ikke et sted å gå,
1873
+ og står nå urørt.
1874
+
1875
+ - **Tre steder i dokumentasjonen sto «byggefunksjon» der ordet var et verb,**
1876
+ som «generatoren byggefunksjon skalaene». Setningene ga ingen mening.
1877
+
1878
+ - **«Tilpasning» sa «fire veier» over en tabell med tre rader.**
1879
+
1880
+ - **«Eget tema» sa at skriften settes i `@layer fristil`.** Den står i
1881
+ `fristil-tema`.
1882
+
1883
+ ## 0.21.0 (2026-09-28)
1884
+
1885
+ ### Lagt til
1886
+
1887
+ - **Folketelling over attributter bare morferen leser.** `fs.browser.test.ts`
1888
+ kaller hver byggefunksjon og krever at `data-ignore-morph` kommer ut fra
1889
+ nøyaktig `connectionStatus`, `sessionTimeout`, `suggestion` og `toast`, og at
1890
+ `data-preserve-attr` ikke kommer ut fra noen. Vakten feller både et nytt
1891
+ sted attributtet dukker opp og et sted det forsvinner fra, siden begge
1892
+ endrer hva malen må skrive. Hjelperen i `morfing.browser.test.ts` hopper
1893
+ over attributter som står i en fredningsliste, slik den ekte løkka gjør. Står
1894
+ et navn der, fjerner løkka ingenting for nettopp det attributtet, og testen
1895
+ etterprøver ingenting. Noen av fixturene bygges av byggefunksjonene, og der
1896
+ feller folketellingen. Andre er skrevet for hånd, som en Go-mal ville gjort,
1897
+ og der feller en ny påstand i hjelperen om at lista er tom.
1898
+
1899
+ ### Rettet
1900
+
1901
+ - **`<fs-field>` leter ikke lenger etter `data-role` på hjelpetekst og
1902
+ feilmelding.** Komponenten leste `[data-role='help']` og
1903
+ `[data-role='error']` ved siden av klassene `fs-help-text` og
1904
+ `fs-error-text`. Kroken sto bare i en `querySelector` i kilden, uten tester
1905
+ og uten omtale noe sted, så ingen kunne bygge på den med vilje. `data-role`
1906
+ er uprefikset og eies i praksis av andre, og en app som brukte det til noe
1907
+ annet inne i et felt fikk sitt eget avsnitt adoptert som feilmelding, uten at
1908
+ noe sa fra. Komponentsiden sier nå hva komponenten faktisk krever, og en test
1909
+ holder fjerningen på plass.
1910
+
1911
+ Fjerningen er ingen brytende endring etter reglene øverst. Ingen
1912
+ byggefunksjon skrev attributtet og ingen komponent satte det, så ingenting i
1913
+ konsumentens markup endrer betydning: den virker som før, den blir bare ikke
1914
+ koblet.
1915
+
1916
+ - **Dokumentasjonen påsto mer enn den kunne vise.** «Holder markupen der,
1917
+ holder den overalt» var en påstand om alle morfere, mens vi kjører løkka til
1918
+ én. Kravet står nå slik det er: det en komponent har satt, skal overleve at
1919
+ attributter blir fjernet fra et element som består. Og `data-preserve-attr`
1920
+ og `data-ignore-morph` er beskrevet som morferens egne attributtnavn, siden
1921
+ et `data-*`-attributt bare betyr noe for koden som leser det.
1922
+
1923
+ - **«To komponenter eier sitt eget innhold» var tre.** `<fs-toast>` sto ikke i
1924
+ lista i «Markup og oppførsel», og at `fs.suggestion()` setter
1925
+ `data-ignore-morph` på statusområdet sto bare på komponentsiden, ikke der
1926
+ regelen forklares.
1927
+
1928
+ - **`overta` sa ingenting om tilgjengelighetsansvaret.** Siden om tilpasning
1929
+ sier nå at en overtatt og endret komponent ikke dekkes av en
1930
+ tilgjengelighetserklæring som viser til designsystemet.
1931
+
1932
+ ## 0.20.0 (2026-09-28)
1933
+
1934
+ ### Lagt til
1935
+
1936
+ - **`fristil agent` og regelbøkene i `agent/`.** Seks regelbøker skrevet for
1937
+ kodeagenter som Claude Code og GitHub Copilot, én per miljø: `html`, `maler`,
1938
+ `bundles`, `react`, `astro` og `datastar`. Hver er komplett for sitt miljø og
1939
+ nevner ingen andre, siden en agent som leser om `className` i et prosjekt med
1940
+ Go-maler er en agent som skriver `className` i en Go-mal. Vue, Svelte, Solid
1941
+ og Lit deler `bundles`, og `--rammeverk=svelte` peker dit.
1942
+
1943
+ Hver fil har de fire feilene en agent gjør oftest øverst: glemt stilark,
1944
+ oppfunne komponenter og varianter, hardkodede farger og bommet registrering.
1945
+ Så følger alle komponentene med klasse, element, attributter og lovlige
1946
+ verdier, tokenlagene, de tre reglene for web components, og sjekken som
1947
+ retteløkke. Kommandoen leser miljøet av `package.json`, og `--rammeverk=<navn>`
1948
+ overstyrer.
1949
+
1950
+ Kommandoen skriver aldri en fil. `AGENTS.md`, `CLAUDE.md` og
1951
+ `.github/copilot-instructions.md` er konsumentens egne, og et verktøy som
1952
+ skriver i dem må gjette stier, flette med innhold det ikke har skrevet, og
1953
+ holde en kopi i takt med pakken. Regelboka blir derfor stående i pakken, på
1954
+ `node_modules/@fristil/designsystem/agent/<navn>.md`, og følger versjonen.
1955
+ Mappa er med i tarballen.
1956
+
1957
+ De samme filene ligger også på dokumentasjonssiden, på `/llms.txt` og
1958
+ `/agent/<navn>.md`. Den viktigste agenten har ingen `node_modules`: blir noen
1959
+ bedt om å lage et skjema med Fristil i en tom mappe, skrives markupen før
1960
+ `npm install` har kjørt.
1961
+
1962
+ Filene genereres av `scripts/generate-agent.ts`, og `scripts/sjekk-agent.ts`
1963
+ feller hvis de er utdaterte, hvis en komponent mangler i en av dem, hvis et
1964
+ markupeksempel ikke tåler `diagnoseMarkup`, hvis en importsti ikke finnes i
1965
+ `exports`, hvis et tokennavn ikke finnes, eller hvis en `html`-blokk
1966
+ importerer et pakkenavn der nettleseren trenger en URL.
1967
+
1968
+ ### Rettet
1969
+
1970
+ - **Versjonen i dokumentasjonens CDN-adresser kom fra 74 hardkodede steder.**
1971
+ `prepare-version` skrev dem om ved hver utgivelse, men et omskrivingssteg må
1972
+ finne den gamle versjonen for å bytte den, så en adresse som hadde glidd ble
1973
+ stående og pekte på en eldre pakke enn teksten rundt beskrev. Kilden har nå
1974
+ plassholderen `@fristil/designsystem@VERSJON`, og `remark-versjon.mjs` setter
1975
+ inn versjonen fra `package.json` når siden bygges. Omskrivingssteget er
1976
+ fjernet, og fire vaktposter passer på: tre på at kilden bruker plassholderen,
1977
+ og `sjekk-bygget-versjon.ts` på at den faktisk ble byttet ut i det bygde
1978
+ resultatet.
1979
+
1980
+ - **To kodeeksempler i dokumentasjonen importerte et pakkenavn i nettleseren.**
1981
+ Datastar-sporet på [Rammeverk](https://fristil.sobernetics.no/rammeverk/) og
1982
+ dialogen på
1983
+ [Bekreft en handling](https://fristil.sobernetics.no/monster/bekreftelse/) hadde
1984
+ `import … from "@fristil/designsystem/field"` i en `<script type="module">`.
1985
+ Ingen av sidene har et byggesteg, og en nettleser slår ikke opp et pakkenavn
1986
+ uten byggesteg eller importmap, så koden feilet stille for den som limte den
1987
+ inn. Begge bruker nå hele URL-en.
1988
+
1989
+ Regelen fantes i `sjekk-oppskrifter.ts`, men den leser bare komponentsidene
1990
+ og velger regel ut fra navnet på fanen, så de to sto med feilen i flere
1991
+ runder. `sjekk-nettleserimport.ts` dekker nå alle sidene uavhengig av fane:
1992
+ en `html`-blokk er markup for nettleseren uansett hvor den står.
1993
+
1994
+ ## 0.19.0 (2026-09-28)
1995
+
1996
+ ### Lagt til
1997
+
1998
+ - **`maxChroma` i temageneratoren, og `--maks-metning` på kommandolinja.**
1999
+ Taket på metningen i de kulørte skalaene har stått fast på 0,16 i OKLCH. De
2000
+ fleste merkefarger ligger under det, men neon gjør ikke: `#39ff14` ligger på
2001
+ 0,286 og mistet 44 prosent mot taket, `#ff2d6f` på 0,240 og mistet 33. Taket
2002
+ kan nå settes, i `buildTheme({ maxChroma })`, med `--maks-metning` på
2003
+ kommandolinja, eller som `maksMetning` i en oppskriftsfil. Standarden er den
2004
+ samme som før, så et tema som ikke oppgir noe kommer ut likt.
2005
+
2006
+ Kontrastkravet berøres ikke. Taket styrer metning, mens kontrasten kommer av
2007
+ de faste lyshetene i skalaen og av passet som måler hvert par etterpå og
2008
+ flytter lysheten. Mer metning gir flere slike justeringer, ikke en svakere
2009
+ garanti, og et merke med hevet tak kjøres nå gjennom hele listen av par i
2010
+ `theme.browser.test.ts`. Den nøytrale skalaen har sitt eget, mye lavere tak,
2011
+ og er uendret.
2012
+
2013
+ Oppskriftsfila sier nå fra om en ukjent toppnøkkel, slik dokumentasjonen
2014
+ alltid har lovet. En fil som har stått med en skrivefeil og virket, stopper
2015
+ derfor nå. `$schema` er fortsatt lovlig: editorer skriver den inn av seg selv,
2016
+ og den sier ingenting om temaet. En fil som er gyldig JSON, men ikke et
2017
+ objekt, får også en forklaring framfor et stakkspor fra Node.
2018
+
2019
+ `buildTheme` avviser et tak utenfor 0,01 til 0,33. Et negativt tak speilet
2020
+ fargen og gjorde knallgrønt til magenta, `NaN` ga en feilmelding om en
2021
+ heksadesimal farge som aldri var oppgitt, og 0 ga et helt grått tema, alle
2022
+ tre i stillhet.
2023
+
2024
+ ## 0.18.0 (2026-09-27)
2025
+
2026
+ ### Lagt til
2027
+
2028
+ - **`fristil sjekk <fil…>` og `@fristil/designsystem/diagnostics`.** Sjekken
2029
+ editorutvidelsen kjører mens du skriver, elementer som ikke finnes,
2030
+ attributter elementet ikke har, verdier utenfor lista, klasser som
2031
+ `fs-buton` og `<fs-field>` uten kontroll, ligger nå i pakken.
2032
+ Kommandolinjen leser filer eller standard inn og skriver hvert funn som
2033
+ `fil:linje:kolonne: melding`, med feilkode ved funn. `diagnoseMarkup(html)`
2034
+ er den samme sjekken som funksjon, for en test i appen som kjører den over
2035
+ HTML-en serveren faktisk sender, der det ikke finnes noen malfil å sjekke.
2036
+ Editorutvidelsen importerer nå diagnostikken fra pakken, og listene den
2037
+ sjekker mot genereres inn i pakken som `elements.ts` og `classes.ts`.
2038
+ - **`<fs-popover>`, `<fs-suggestion>` og `<fs-dialog>` kobler fra bar
2039
+ struktur,** som fanene og feiloppsummeringen. En knapp og et panel med
2040
+ klassen `fs-popover` er nok: komponenten setter `popover="manual"`, lager
2041
+ id-en og skriver `aria-controls` på knappen, ellers den første knappen
2042
+ utenfor panelet som ikke peker på noe annet. En `<label>`, et `<input>`,
2043
+ en `.fs-suggestion__list` med `<li>` og et statuselement er nok for
2044
+ forslagsfeltet: komponenten setter rollene, lager id-ene, skriver `for`
2045
+ og `aria-controls`, og holder lista lukket til brukeren rører feltet.
2046
+ Dialogen får klassen, og navnet sitt fra den første overskriften når den
2047
+ ikke alt har et fra `aria-labelledby` eller `aria-label`, med en id
2048
+ komponenten lager om den mangler; peker `aria-labelledby` på en overskrift,
2049
+ er det den som får tittelklassen. Bare det som mangler skrives,
2050
+ `suggestion.css` holder en bar liste skjult til komponenten er
2051
+ registrert, og advarslene sier hva som faktisk mangler.
2052
+ `derivedParts` og `uniqueId` i `/host-element` er hjelperne bak.
2053
+ - **`<fs-tabs>` og `<fs-error-summary>` kobler fra bar struktur.** En
2054
+ `.fs-tabs__list` med knapper og ett `.fs-tabs__panel` per knapp er nok:
2055
+ komponenten setter rollene, lager id-ene, kobler `aria-controls` og
2056
+ `aria-labelledby`, og skjuler panelene som ikke er valgt. Valget leses fra
2057
+ `aria-selected`, ellers fra hvilket panel som ikke er `hidden`.
2058
+ Feiloppsummeringen får klassen, `role="alert"` og `tabindex="-1"`, og
2059
+ overskriften klassen sin. Det serveren har skrevet står, og det
2060
+ komponenten fylte inn settes tilbake etter en patch, med de samme id-ene.
2061
+ `tabs.css` viser bare det første synlige panelet til komponenten er
2062
+ registrert, så innholdet ikke hopper. Kotlin-malen i spilldemoen skrev sju
2063
+ attributter per fane for hånd. `fs.tabs()` og `fs.errorSummary()` er som
2064
+ før, for markup som lages med JavaScript.
2065
+
2066
+ To ting endrer seg for markup som alt fantes. Under `server-controlled`
2067
+ setter fanene fortsatt ikke brukerens valg tilbake, men skriver nå ut det
2068
+ markupen sier: `aria-selected`, tabbestoppet og `hidden` i takt, så en
2069
+ patch som bare rørte panelene flytter også markeringen. Det komponenten
2070
+ selv skrev teller ikke som markupens svar. Og advarselen om manglende
2071
+ `tabindex` på feiloppsummeringen er borte, siden komponenten setter den.
2072
+ - **`@fristil/designsystem/register`: `defineFs()` registrerer alle ni
2073
+ web-komponentene i ett kall,** også fra `dist/register.js` på en CDN.
2074
+ Spilldemoen sto med sju `defineFs*`-kall i en `useEffect`, altså etter
2075
+ første tegning, og den første meldingen fra hendelsesstrømmen kom i gapet:
2076
+ «reportSuccess is not a function». Dokumentasjonen sier nå: registrer ved
2077
+ import, aldri i en effekt.
2078
+ - **De frittstående komponentene har funksjoner som venter på
2079
+ registreringen:** `showToast(element, tekst, valg)`,
2080
+ `reportFailure(element)`, `reportSuccess(element)`,
2081
+ `extendSession(element)` og `resetSession(element)`. De venter på
2082
+ `customElements.whenDefined` for elementets tagnavn og kaller så metoden,
2083
+ så et kall som kommer for tidlig blir gjort i stedet for å feile. Et
2084
+ element ingen registrerer gir en advarsel i konsollen etter tre sekunder.
2085
+ `whenUpgraded(element)` i `/host-element` er hjelperen bak dem.
2086
+ - **`@fristil/designsystem/fristil.css`: alle stilarkene i én fil.** For den
2087
+ som lenker fra CDN eller `node_modules` uten byggesteg. De enkelte stilarkene
2088
+ henter delene sine med `@import`, som nettleseren først ser når fila er
2089
+ lastet, og på mobilnett sto feltene uten ramme til den andre runden kom;
2090
+ spilldemoen forhåndslastet fem filer for hånd for å komme rundt det. Fila
2091
+ bygges av CSS-oppføringene i `exports`, med `tokens.css` først, uten
2092
+ `@import` og uten kommentarer. Et byggesteg bruker de enkelte stilarkene som
2093
+ før. Tailwind-temaet er ikke med, siden det ikke er et stilark for en side.
2094
+ - **Dialogen kan ha en farget topp.** `fs.dialog({ color })` gir `data-color`
2095
+ på dialogen og en ny `header`-del som pakker overskriften, med en valgfri
2096
+ `subtitle` under. Fargene er varslerens, `info`, `success`, `warning` og
2097
+ `danger`, og `brand` for merkefargen. Med toppen i markupen flyttes luften
2098
+ fra dialogen til delene, så båndet går helt ut i kantene; uten den står
2099
+ dialogen som før. To dialoger i spilldemoen skrev om padding på tre
2100
+ klasser for å få til dette, og det brakk ved en oppgradering.
2101
+ `fs.dialog.colors` og `fs.dialog.isColor` lister og sjekker verdiene.
2102
+
2103
+ ## 0.17.0 (2026-09-27)
2104
+
2105
+ ### Brytende
2106
+
2107
+ - **`idEllerReserve` heter `idOrFallback`.** Hjelperen i `@fristil/designsystem/shared`
2108
+ var den siste eksporterte identifikatoren på norsk, og identifikatorer i
2109
+ pakken skal være engelske. Ingen alias: pakken har ingen konsumenter ennå,
2110
+ og en brytende endring gjøres én gang. Parameteren `oppgittId` i
2111
+ byggefunksjonene heter `givenId`; den er intern.
2112
+
2113
+ ## 0.16.0 (2026-09-27)
2114
+
2115
+ ### Lagt til
2116
+
2117
+ - **`reset()` på `<fs-session-timeout>`** nullstiller klokka uten å sende
2118
+ `session-extend`, for en app som alt har forlenget økten selv, som når en
2119
+ autolagring gikk gjennom.
2120
+ - **`--fs-toast-layer`** styrer `z-index` på varselregionen, med `60` som
2121
+ reserve.
2122
+ - **`isToastColor`** eksporteres ved siden av `toastColors`.
2123
+ - **`fs.popover()` tar `placement`.** `fs.popover.isPlacement` sjekker en
2124
+ verdi, også i `/react`, og `popoverPlacements` fra hovedinngangen lister
2125
+ dem, med typen `PopoverPlacement`. Før måtte attributtet skrives for hånd
2126
+ uten typesjekk.
2127
+ - **`--fs-suggestion-layer`** styrer `z-index` på forslagslista, med `30`
2128
+ som reserve.
2129
+
2130
+ ### Rettet
2131
+
2132
+ - **Escape i `<fs-session-timeout>` forlenger, og dialogen kommer ikke
2133
+ tilbake.** Komponenten lyttet ikke på `close`, så neste tikk så en lukket
2134
+ dialog etter varselgrensen og åpnet den igjen, ett sekund etter Escape,
2135
+ hver gang, med en ny `session-warn`. Escape regnes nå som «jeg er her» og
2136
+ gjør det samme som knappen.
2137
+ - **Skjermleseren får vite hvor lenge det er igjen i det varselet åpnes.**
2138
+ Tallet i avsnittet er `aria-hidden`, og live-området ble fylt først ved
2139
+ neste terskel, så med standardverdiene hørte skjermleseren «Vi logger deg
2140
+ ut om for å beskytte opplysningene dine», og første tall kom tre minutter
2141
+ senere.
2142
+ - **`<fs-session-timeout>` står stille etter utløpet og etter «Logg ut nå»**
2143
+ til `extend()` eller `reset()` kalles. Før startet syklusen på nytt av seg
2144
+ selv, med ny dialog og ny `session-expired` hvert `expires-at`-sekund, og
2145
+ en app som brukte mer enn ett sekund på utloggingen fikk dialogen tilbake.
2146
+ - **`warn-at` og `expires-at` sjekkes.** Et tall som ikke er et tall, eller
2147
+ et varsel som ikke kommer før utløpet, gir beskjed i konsollen framfor
2148
+ stillhet. `warnAt` og `expiresAt` har fått settere, rulling i en boks
2149
+ teller som aktivitet, og hver forekomst har sin egen overskrift-id.
2150
+ - **Pausen i `<fs-toast>` holder til både musa og fokus har forlatt
2151
+ meldingen.** Den var to uavhengige par, og musa som gikk ut startet klokka
2152
+ igjen mens fokus sto i meldingen, som så forsvant under brukeren.
2153
+ - **`dismiss()` flytter fokus til meldingen ved siden av** når meldingen som
2154
+ lukkes hadde fokus. Før falt fokus til `body`, og neste Tab startet øverst
2155
+ på siden.
2156
+ - **Varselregionen er `aria-atomic="false"`**, både fra `fs.toast()` og fra
2157
+ komponenten. `status` er atomisk som standard, og hele stabelen ble lest
2158
+ opp på nytt for hver ny melding.
2159
+ - **Regionen heter «Varsler» begge steder.** Komponenten sa «Meldinger» når
2160
+ attributtet manglet, `fs.toast()` sa «Varsler». Et tomt `duration` gir
2161
+ standardverdien framfor null, og en ukjent `color` gir ingen kant.
2162
+ - **`<fs-connection-status>` melder `connection-lost` én gang per utfall.**
2163
+ Nettlesere fyrer gjerne flere `offline` på rad, og hver ga en ny hendelse
2164
+ og en ny opplesning av den samme linja. Linja settes nå inn tom og fylles
2165
+ i neste tegning, slik at live-området finnes før innholdet kommer.
2166
+ `offlineText` og `onlineText` har fått settere.
2167
+ - **`<fs-suggestion>` lukker lista når fokus forlater komponenten.** Tab
2168
+ gikk videre til neste felt, og lista ble stående over det med
2169
+ `aria-expanded="true"` på et felt som ikke lenger hadde fokus. Lytteren på
2170
+ `document` er borte: et trykk i lista holder fokus i feltet, fokus på noe
2171
+ inne i komponenten lar lista stå, og alt utenfor lukker den. Dermed virker
2172
+ feltet også inne i en skyggerot, der klikket i
2173
+ feltet før ble regnet som et klikk utenfor og lukket lista i samme klikk
2174
+ som åpnet den.
2175
+ - **«Ingen treff» følger lista.** Meldingen er søsken til lista og ble
2176
+ stående synlig under et lukket felt etter Escape. `fs.suggestion()` skriver
2177
+ den også skjult på et lukket felt uten alternativer, som er det anbefalte
2178
+ oppsettet for asynkront søk; før sto meldingen der alt ved sidelasting.
2179
+ - **Markeringen ryddes i det alternativet filtreres bort**, også med
2180
+ `server-controlled`. Før pekte `aria-activedescendant` på et skjult
2181
+ alternativ, og skjermleseren leste det opp.
2182
+ - **Alternativene kjennes igjen på `role="option"`**, ikke på klassen. En mal
2183
+ med egen styling fikk verken filtrering eller piltaster, uten et ord.
2184
+ - **`<fs-suggestion>` sier fra når `[role="status"]` mangler.** Antall treff
2185
+ leses opp der, og uten elementet sto komponenten stille.
2186
+ - **`fs.suggestion()` skriver `aria-selected` og `aria-activedescendant`
2187
+ under samme vilkår**, altså bare når lista er åpen. Før fikk en lukket
2188
+ liste det ene uten det andre.
2189
+ - **Det markerte alternativet vises i høykontrastmodus**, med systemfargene.
2190
+ - **`<fs-popover>` står på riktig side i `dir="rtl"`.** Posisjonen er
2191
+ fysisk, men stilarket brukte den som `inset-inline-start`, som er høyre
2192
+ kant i en side som leses fra høyre. `start` og `end` i `placement` følger
2193
+ nå leseretningen.
2194
+ - **`top-start` og `top-end` klemmes inn i vinduet.** Et panel ved toppen av
2195
+ siden lå helt utenfor skjermen, uten å kunne rulles fram. Er det ikke
2196
+ plass på den siden plasseringen ber om, legges panelet på den andre.
2197
+ - **Verten følger med når nettleseren selv lukker et `popover="auto"`.**
2198
+ Håndskrevet markup med bare `popover` er `auto`, og etter en lett
2199
+ avvisning sto verten med `open` og knappen med `aria-expanded="true"`
2200
+ over et lukket panel. Komponenten lytter nå på `toggle`.
2201
+ - **Klikk utenfor et sprettoppvindu i en skyggerot** leser
2202
+ `composedPath()`, så et klikk i panelet ikke regnes som utenfor.
2203
+ - **`<fs-dialog server-controlled>` lukker når patchen tar `open` fra en
2204
+ modal dialog.** Reparasjonen var slått av, men ingen kalte `close()`, og
2205
+ dialogen sto igjen i topplaget med `display: none` mens resten av siden
2206
+ var inert.
2207
+ - **`<fs-tabs>` hopper over deaktiverte faner.** Piltastene, Home og End
2208
+ valgte en fane med `disabled`, `focus()` på en deaktivert knapp gjør
2209
+ ingenting, og raden sto uten en eneste fane som kunne få fokus.
2210
+ Tastaturbrukeren var låst ute. `select()` avviser dem også.
2211
+ - **Faner i faner er hver sin rad.** Komponenten fant faner og paneler i hele
2212
+ undertreet, så et klikk på en indre fane skjulte det ytre panelet den sto i.
2213
+ - **Panelet finnes gjennom `aria-controls`.** Koblingen står i markupen og
2214
+ leses derfra, med rekkefølgen som reserve bare for markup uten
2215
+ `aria-controls`. Panelene kan dermed stå i en annen rekkefølge enn fanene,
2216
+ og utenfor verten. Peker `aria-controls` på en id som ikke finnes, sier
2217
+ komponenten fra i konsollen. Peker to faner på det samme panelet, vises
2218
+ det når en av dem er valgt.
2219
+ - **Tabbestoppet flyttes når en patch deaktiverer fanen brukeren valgte**,
2220
+ til den neste fanen som kan få fokus. Valget står. Har brukeren ikke valgt
2221
+ noe, er markupen serverens, og komponenten rører den ikke.
2222
+ - **Venstre og høyre pil bytter retning i `dir="rtl"`.**
2223
+ - **`selected` på `<fs-tabs>` kan settes.** Getteren sto uten setter, og
2224
+ `faner.selected = 1`, som dokumentasjonen viste, kastet.
2225
+ - **`fs.tabs()` med negativt `count` gir en tom rad** framfor å kaste.
2226
+ - **`<fs-error-summary>` prøver igjen når fokus ikke landet.** Sto boksen i et
2227
+ skjult panel eller en lukket dialog i det den kom, feilet `focus()` i
2228
+ stillhet mens flagget «har flyttet fokus» ble satt, og boksen fikk aldri
2229
+ fokus da forelderen ble synlig og lista byttet ut. Gjenforsøket skjer bare
2230
+ når ingen står i et felt, så live-validering som patcher lista ikke river
2231
+ fokus ut av feltet brukeren retter i.
2232
+ - **En lenke til en `<label>` uten kontroll følger `for`** dit den peker,
2233
+ som til en gruppe.
2234
+ - **`<fs-error-summary>` sier fra når `tabindex` mangler.** Uten det gjør
2235
+ `focus()` ingenting, og hele grunnen til komponenten forsvant i stillhet.
2236
+ - **En lenke til en `<label>` som omslutter kontrollen** sender fokus til
2237
+ kontrollen, ikke til ledeteksten.
2238
+ - **Rullingen til feltet følger sidens `scroll-behavior`** framfor å tvinge
2239
+ `smooth`, så `prefers-reduced-motion` gjelder av seg selv.
2240
+ - **`<fs-field>` eier bare det den selv skrev.** Komponenten leser
2241
+ `aria-invalid`, `aria-describedby` og `disabled` fra kontrollen, fordi
2242
+ serveren kan ha skrevet feltet med `fs.field()`. Skillet mellom serverens
2243
+ ord og komponentens eget ekko fantes bare for `aria-invalid`, og de to
2244
+ andre hadde samme feil: `aria-describedby` pekte fortsatt på feilmeldingen
2245
+ etter at feltet var gyldig, og på en hjelpetekst en patch hadde fjernet, og
2246
+ `felt.disabled = false` slo ikke av et `disabled` komponenten selv hadde
2247
+ satt. Minnet er nå nøklet på kontrollen og overlever at feltet flyttes,
2248
+ slik React gjør ved en omstrukturering, og at kontrollen forsvinner og
2249
+ kommer tilbake i en patch. Id-er serveren selv la i `aria-describedby` blir
2250
+ med videre.
2251
+ - **Ingen `aria-disabled` på kontrollen.** Komponenten skrev det ved siden av
2252
+ `disabled`, og strøk samtidig et `aria-disabled` konsumenten selv hadde
2253
+ skrevet. `computeFieldAttributes` er kontrakten, og den skriver det bare på
2254
+ ledeteksten; et ekte `disabled` er alt synlig for hjelpemidlene.
2255
+ - **Serverens `aria-invalid` står ordrett når det er serveren som sier feltet
2256
+ er ugyldig.** `false` er gyldig og vanlig i håndskrevet HTML, og ble strøket
2257
+ ved hver patch. `grammar` og `spelling` betyr ugyldig, men ble lest som
2258
+ «ikke true» og strøket på samme måte. Tom streng leses som `false`, slik
2259
+ ARIA sier.
2260
+ - **`requiredMarker` som egenskap betyr det samme som attributtet.** Setteren
2261
+ skriver `"none"` bokstavelig, siden `required-marker="none"` overstyrer en
2262
+ `data-required` serveren skrev på ledeteksten. Før fjernet setteren
2263
+ attributtet, og markeringen kom tilbake fra ledeteksten. Getteren leser nå
2264
+ markupen, ledeteksten medregnet, framfor bare sitt eget attributt.
2265
+
2266
+ ## 0.15.0 (2026-09-26)
2267
+
2268
+ - **`web-types.json` følger med pakken.** Det er JetBrains sitt format for
2269
+ fullføring og forklaring i HTML, med de ni `<fs-*>`-elementene og
2270
+ attributtene deres. IDE-en finner den selv fra `node_modules`, gjennom
2271
+ feltet `web-types` i `package.json`. Etterprøvd i IntelliJ IDEA Ultimate 2026.2:
2272
+ fullføring av elementene, attributtene og verdiene, og forklaring med
2273
+ lenke. Fila genereres fra `editor/metadata.ts` i repoet, der
2274
+ VS Code-utvidelsen også lages.
2275
+ - `observedAttributes` på komponentklassene er nå skrivebeskyttede tupler
2276
+ (`as const`) i stedet for `string[]`. Verdiene er de samme. En klasse som
2277
+ arver fra en komponent og skriver over `observedAttributes` med `string[]`
2278
+ får en typefeil, og må bruke `as const` den også.
2279
+
2280
+ ## 0.14.0 (2026-09-24)
2281
+
2282
+ ### Brytende
2283
+
2284
+ - **Verten heter `host` i alle byggefunksjonene.** Den delen serveren skriver,
2285
+ og komponenten fester seg på, het tre ting: `host` i `fs.dialog()` og
2286
+ `fs.popover()`, `region` i `fs.toast()` og `container` i `fs.errorSummary()`.
2287
+ Tre ord for den samme tingen, og to av dem sa ikke hva den var. De heter nå
2288
+ `host`, som er ordet arkitekturen bruker om den ellers.
2289
+
2290
+ `fs.connectionStatus()` og `fs.sessionTimeout()` er urørt. De har bare én
2291
+ del, og returnerer attributtene flatt, slik `fs.button()` gjør. Nøkkelen
2292
+ finnes der verten selv bærer attributter. `fs.field()`, `fs.tabs()` og
2293
+ `fs.suggestion()` har mange deler og ingen `host`, fordi verten deres
2294
+ ikke har noe å bære.
2295
+
2296
+ ```diff
2297
+ - <fs-toast {...varsler.region} />
2298
+ + <fs-toast {...varsler.host} />
2299
+ - <fs-error-summary {...feil.container}>
2300
+ + <fs-error-summary {...feil.host}>
2301
+ ```
2302
+
2303
+ ### Lagt til
2304
+
2305
+ - **`setAttributes` tar `null`.** `document.querySelector()` gir
2306
+ `Element | null`, så hvert eneste kallsted i en `strict`-app måtte skrive en
2307
+ vakt eller et utropstegn rundt et oppslag som nesten alltid treffer. Den gjør
2308
+ nå ingenting på `null`, som `element?.classList`. Parameteren er utvidet, så
2309
+ ingen kallsteder brytes.
2310
+
2311
+ ### Rettet
2312
+
2313
+ - **Panelet i `<fs-popover>` nullstiller lista.** Panelet er ofte en `<ul>`
2314
+ med handlinger, og `.fs-popover` hadde ingen `list-style`. Markupen i
2315
+ dokumentasjonen skrev `data-variant="plain"` for å bøte på det, men det
2316
+ attributtet finnes bare på `.fs-list` og traff ingen regel, så panelet sto
2317
+ med nettleserens kuler. Nullstillingen hører i pakken og ikke
2318
+ hos konsumenten.
2319
+
2320
+ - **`ref` virker på de egendefinerte elementene i JSX.** Typene bygget på
2321
+ `HTMLAttributes`, som ikke har `ref`; den ligger i `RefAttributes`. Derfor
2322
+ var `<fs-toast ref={kø} />` en typefeil, altså nøyaktig mønsteret
2323
+ dokumentasjonen anbefaler for å kalle `.show()` og `.hide()` fra React. Alle
2324
+ vertene bygger nå på en felles `Host`-type som har begge.
2325
+
2326
+ - **`warn-at` og `expires-at` godtar det byggefunksjonen sender.** De sto som
2327
+ `number` i JSX-typene, mens `fs.sessionTimeout()` sender strenger, slik
2328
+ HTML-attributter er. Det er den samme feilen som `tabIndex: "0"`, motsatt
2329
+ vei, og den viste seg bare i en ekte React-app.
2330
+
2331
+ - **`fs.connectionStatus()` og `fs.sessionTimeout()` reklamerte med en død
2332
+ klasse.** Begge sender ut `fs-connection-status` og `fs-session-timeout`,
2333
+ men stilarkene stylet bare elementnavnet, så klassen gjorde ingenting. Nå
2334
+ treffer regelen begge, og en konsument som setter klassen på noe annet enn
2335
+ elementet får den samme oppførselen.
2336
+
2337
+ ## 0.13.0 (2026-09-24)
2338
+
2339
+ ### Brytende
2340
+
2341
+ - **`.fs-dialog` er en kolonne når `.fs-dialog__body` er et direkte barn.**
2342
+ Det er rettelsen under, men den endrer hvordan innholdet legger seg for
2343
+ markup som alt finnes, og det er den strukturen dokumentasjonen viser. Marger
2344
+ mellom avsnitt slutter å falle sammen, og tekst og knapper som står rett i
2345
+ dialogen ved siden av kroppen blir egne rader i full bredde. En dialog uten
2346
+ `.fs-dialog__body` er urørt.
2347
+
2348
+ - **`display` kan ikke lenger settes alene på `.fs-dialog`.** En `<dialog>`
2349
+ uten `open` skjules av nettleserens eget stilark, og lagene sorterer bare
2350
+ innenfor ett opphav, så en hvilken som helst forfatterregel med `display`
2351
+ slår den skjulingen. Setter du din egen, må du ta med
2352
+ `dialog.fs-dialog:not([open]):not(:is(:popover-open)) { display: none }`,
2353
+ minst like spesifikk som din egen regel. Det står på komponentsiden og på
2354
+ siden om tilpasning. Dette er det eneste unntaket fra løftet om at en enkel
2355
+ selektor slår hva som helst i pakken.
2356
+
2357
+ ### Rettet
2358
+
2359
+ - **Dialogen hopper heller ikke sidelengs.** 0.12.1 ga den plassen til en
2360
+ modal før den var det, og det loddrette hoppet var borte. Et vannrett kom i
2361
+ stedet: nettleserens eget stilark setter `max-width: calc(100% - 6px - 2em)`
2362
+ på `dialog:modal`, og det hadde vi ikke. På en skjerm som er 390 piksler
2363
+ bred gikk dialogen derfor fra 358 til 352 piksler i det `showModal()` kjørte,
2364
+ og flyttet seg tre piksler mot høyre.
2365
+
2366
+ `.fs-dialog[open]:not(:modal)` inne i `<fs-dialog>` bruker nå `inset: 0` med
2367
+ `margin: auto`, det samme maksmålet på bredden og `overflow: auto`, altså de
2368
+ samme verdiene spesifikasjonen gir en modal, i logisk form. Maksmålet på
2369
+ høyden står med vilje bare på `.fs-dialog`, siden det er det strengeste av
2370
+ de to og dermed gjelder i begge tilstandene. Testen leser boksen før og
2371
+ etter `showModal()`, med to slags innhold, og krever at den står stille.
2372
+
2373
+ - **`.fs-dialog__body` ruller nå faktisk.** Klassen har hatt `overflow-y: auto`
2374
+ siden komponenten kom, uten at den kunne gjøre noe: dialogen var en blokk, så
2375
+ kroppens høyde var innholdsbestemt og ble aldri klippet. Det som rullet var
2376
+ dialogen selv, og bare når den var modal, så overskriften og knapperaden
2377
+ forsvant ut av syne sammen med teksten. `.fs-dialog:has(> .fs-dialog__body)`
2378
+ er nå en kolonne, og da krymper kroppen og ruller mens tittelen og knappene
2379
+ blir stående. Det er også det dokumentasjonen har sagt hele tiden.
2380
+
2381
+ Regelen tar samtidig tilbake det den tok: en `<dialog>` uten `open` er skjult
2382
+ av nettleserens eget stilark, og en forfatterregel med `display` slår den
2383
+ uansett lag og spesifisitet. `dialog.fs-dialog:not([open]):not(:popover-open)`
2384
+ setter `display: none` igjen, ellers ville en lukket dialog stått som et kort
2385
+ oppå innholdet rundt, fra sidelasting og etter hver lukking. Unntaket for
2386
+ popover står der spesifikasjonens eget stilark har det, siden en popover
2387
+ aldri setter `open`.
2388
+
2389
+ **Det gjør `display` til den ene egenskapen en konsument ikke kan sette fritt
2390
+ på `.fs-dialog`.** Gjør du det, må du ta den skjulte tilstanden tilbake selv.
2391
+ Det står nå på komponentsiden.
2392
+
2393
+ Vilkåret i selektoren er en del av oppførselen, og står nå i tabellen over
2394
+ klassene. Kolonnen virker bare når kroppen er et direkte barn, og den endrer
2395
+ samtidig hvordan alt annet legger seg: marger mellom avsnitt slutter å falle
2396
+ sammen, og tekst og knapper som står rett i dialogen blir egne rader i full
2397
+ bredde. En dialog uten kropp er derfor urørt.
2398
+
2399
+ ## 0.12.1 (2026-09-24)
2400
+
2401
+ ### Rettet
2402
+
2403
+ - **Dialogen hopper ikke lenger på plass.** En dialog serveren vil vise sendes
2404
+ med `open`, ellers finnes ikke innholdet uten JavaScript, og nettleseren
2405
+ legger den da i den vanlige flyten. Først når komponenten kaller
2406
+ `showModal()` flyttes den til topplaget og midtstilles, og mellom de to
2407
+ øyeblikkene hopper den. På en treg forbindelse er hoppet godt synlig:
2408
+ testet i Chromium sto dialogen på topp 0 og landet på topp 128, og det ble
2409
+ meldt fra en telefon.
2410
+
2411
+ `.fs-dialog[open]:not(:modal)` inne i `<fs-dialog>` plasseres nå som en
2412
+ modal allerede før den er det, med flaten bak malt av en skygge, siden
2413
+ `::backdrop` bare finnes i topplaget. Laget kan settes med
2414
+ `--fs-dialog-layer`, som er 40 i utgangspunktet.
2415
+
2416
+ Regelen gjelder bare inne i verten. En `.fs-dialog` som brukes uten
2417
+ komponenten, og med vilje ikke er modal, står der den står.
2418
+
2419
+ ## 0.12.0 (2026-09-24)
2420
+
2421
+ ### Brytende
2422
+
2423
+ - **`ThemeInput` er en union.** Merkefargene kan utelates, men da skal ingen av
2424
+ dem stå: enten alle fire, eller ingen. Vilkåret står i typen og ikke bare som
2425
+ en feilmelding i kjøretid, så `buildTheme({ interactive, danger })` er en
2426
+ typefeil. En konsument som leste `input.interactive` fra en variabel av typen
2427
+ `ThemeInput`, må nå skille de to tilfellene. Meldingen i kjøretid står ved
2428
+ siden av, for oppskriften kan komme fra en JSON-fil eller et skript uten
2429
+ typer.
2430
+
2431
+ ### Lagt til
2432
+
2433
+ - **Temageneratoren kan også sette skrift og form.** Den bygget fargene, og
2434
+ bare dem, og to systemer med den samme paletten ser fortsatt ulike ut når
2435
+ skriften og hjørnene er ulike. `buildTheme()` tar nå to valgfrie blokker,
2436
+ `typography` og `shape`. Seks av verdiene finnes også som flagg: `--skrift`,
2437
+ `--knapp-hjorner`, `--felt-hjorner`, `--flate-hjorner`, `--knapp-ramme` og
2438
+ `--knapp-vekt`. Vektene og linjeavstandene settes fra fil. Utelates begge
2439
+ blokkene, er temaet nøyaktig det det var før.
2440
+
2441
+ Hjørnene er delt i tre framfor ett felles tall, fordi ett tall er feil:
2442
+ et annet norsk designsystem har helt runde knapper mens feltene har nesten
2443
+ rette hjørner, og med én verdi blir feltene kapsler. `buttonRadius` treffer knapp,
2444
+ paginering og hopplenke, `fieldRadius` felt, tekstområde og nedtrekksliste,
2445
+ og `surfaceRadius` de elleve flatene, meldingen og hjelpeboblen medregnet.
2446
+ Avkryssingsboksen, merket, etiketten, valggruppa, avataren og skjelettet
2447
+ står utenfor, fordi hjørnet der ikke er et stilvalg, men selve formen.
2448
+
2449
+ Skriften skrives som en ekte regel på `:root` og ikke bare som et token.
2450
+ Fristil arver skrift med vilje, så et token alene ville ikke endret én
2451
+ eneste bokstav.
2452
+
2453
+ - **Den genererte fila ligger i sitt eget lag,** `fristil-tema`, erklært etter
2454
+ `fristil` med `@layer fristil, fristil-tema;`. Den lå i `@layer fristil`
2455
+ først, og da avgjorde rekkefølgen stilarkene ble lastet i. Den rekkefølgen
2456
+ har konsumenten ikke alltid i hånda: både Astro og TanStack Start legger sin
2457
+ bundlede CSS inn rett før `</head>`, altså etter en `<link>` appen selv har
2458
+ skrevet, og temaet tapte da mot pakkens egne verdier. Begge lagene ligger
2459
+ fortsatt foran usortert CSS, så konsumentens egne regler vinner som før.
2460
+
2461
+ - **Et tema kan la fargene stå.** Merkefargene er nå valgfrie, og utelates
2462
+ alle fire, lages et tema som bare setter skrift og form. Det er ikke en
2463
+ kuriositet: bruker organisasjonen allerede Fristils palett, er det nettopp
2464
+ skriften og hjørnene som skiller, og å kjøre fargene gjennom generatoren
2465
+ ville flyttet dem bort fra der de skal være. `#1362ae` kommer ut som
2466
+ `#1e6ab7`, siden skalaene regnes om i OKLCH fra merkefargen. Enten alle fire
2467
+ fargene, eller ingen: to farger kaster, siden resten av temaet da ville blitt
2468
+ bygget av standardfarger uten at noen ba om det. Se «Brytende» over for hva
2469
+ det gjorde med typen.
2470
+
2471
+ - **Verdier i et tema kan ikke bryte ut av regelen de skrives inn i.**
2472
+ Oppskriften er en JSON-fil som kan komme fra et annet repo eller fra et
2473
+ byggesteg, og `«4px; } html { display: none } :root { --x: 1` lukket både
2474
+ erklæringen og `:root`-blokka, og fikk en vilkårlig regel inn i
2475
+ `@layer fristil`. Tre veier til var åpne, og alle er etterprøvd i nettleser:
2476
+ `1px (` åpnet en parentes som slukte resten av stilarket, `Arial\` lot
2477
+ baksnabelen spise semikolonet, og `Arial</style><script>…` kjørte et skript i
2478
+ en side der CSS-en står inline. Verdier med `;`, `{`, `}`, `<`, `>`, `\`,
2479
+ `/*` eller styretegn avvises nå, parenteser og anførselstegn må gå opp, og
2480
+ meldingen navngir nøkkelen i oppskriften framfor variabelen vi skriver.
2481
+
2482
+ - **Et ukjent flagg eller en ukjent nøkkel stopper kjøringen** framfor å bli
2483
+ ignorert. `--knapp-hjørner` med ø er den naturlige norske stavemåten, mens
2484
+ flagget heter `hjorner`, og temaet kom før ut uten hjørnet og uten et ord.
2485
+ Det samme gjaldt en skrivefeil inne i oppskriftsfila, altså den som kan
2486
+ komme fra et annet repo.
2487
+
2488
+ - **Vekt og linjeavstand er tokens.** `--font-weight-regular`,
2489
+ `--font-weight-medium`, `--font-weight-semibold`, `--font-weight-bold`,
2490
+ `--semantic-line-height-default`, `--semantic-line-height-heading`,
2491
+ `--semantic-line-height-article` og `--semantic-line-height-compact`.
2492
+ Verdiene er nøyaktig dem komponentene hadde skrevet ut fra før, så
2493
+ ingenting ser annerledes ut.
2494
+
2495
+ - **Trettisju stilark leser nå vekt og linjeavstand fra tokenene** framfor å
2496
+ skrive tallet. Verdiene er de samme, så ingenting ser annerledes ut, men uten
2497
+ dette ville `typography.weights` og `typography.lineHeights` i et tema truffet
2498
+ tre komponenter og ikke resten. Knappen, overskriften og avsnittet leser dem
2499
+ gjennom sin egen komponentvariabel, de andre leser tokenet direkte: en egen
2500
+ variabel per komponent er verdt det der man vil kunne skille dem, og støy der
2501
+ man ikke vil.
2502
+
2503
+ - **Seks nye komponentvariabler** der form sto skrevet ut i stilarket:
2504
+ `--fs-button-border-width`, `--fs-button-font-weight`,
2505
+ `--fs-button-line-height`, `--fs-heading-font-weight`,
2506
+ `--fs-heading-line-height` og `--fs-paragraph-line-height`. Regelen er at
2507
+ form og størrelse leses fra en komponentvariabel med tokenverdien som
2508
+ reserve, og disse tre komponentene brøt den.
2509
+
2510
+ ## 0.11.0 (2026-09-23)
2511
+
2512
+ ### Brytende
2513
+
2514
+ - **`server-filtered` heter `prefiltered`.** Navnet var misvisende på to
2515
+ måter. Det handler ikke om servere: en React-app som rendrer bare treffene
2516
+ har filtrert like fullt, uten at noen server er involvert. Og det handler
2517
+ ikke om hvem som filtrerte, men om hva de filtrerte på. Ingen konsumenter
2518
+ ennå, så navnet er byttet framfor å dokumenteres rundt.
2519
+
2520
+ - **`id` er påkrevd i `fs.field()`, og i de andre byggerne som tar en.** Den var valgfri, og funksjonen laget en
2521
+ når den manglet. Det var en felle: id-en er tilfeldig, så to kjøringer gir
2522
+ to ulike, og rendres det samme feltet på en server og så i nettleseren,
2523
+ peker `for` og `aria-describedby` på noe annet enn det som står der. React
2524
+ melder avvik ved hydreringen, og advarselen sier selv at avviket ikke blir
2525
+ rettet opp. Det er sett i en ekte app.
2526
+
2527
+ Å kaste når `document` ikke finnes ble vurdert og forkastet: det er å slutte
2528
+ fra miljøet til hva utvikleren mente. `document === undefined` betyr bare
2529
+ «dette er ikke en nettleser», og en Astro-side rendres på serveren og
2530
+ hydrerer ingenting, så der er en laget id helt i orden.
2531
+
2532
+ Typen alene er heller ikke nok, for en konsument uten TypeScript ser ingen
2533
+ type, og ren HTML med `<script type="module">` er en førsteklasses måte å
2534
+ bruke Fristil på. Utelates id-en likevel, lager byggeren en og sier fra i
2535
+ konsollen, én gang, med navnet på byggeren i meldingen. Uten den reserven
2536
+ fikk en JavaScript-konsument `aria-describedby="undefined-help"` og verken
2537
+ `for` eller `id`, altså verre enn den ustabile id-en kravet skulle bli
2538
+ kvitt.
2539
+
2540
+ Reserven gjelder `fs.field()`, `fs.suggestion()`, `fs.tabs()`,
2541
+ `fs.popover()` og `fs.dialog()`. Forslagsfeltet er grunnen til at den ikke
2542
+ kunne bo i feltet alene: uten id ble `list.id` og `options[n].id` til
2543
+ `undefined-list` og `undefined-option-0`, mens meldingen sa «fs.field()» og
2544
+ sendte utvikleren til feil sted.
2545
+
2546
+ Den tomme strengen teller som ingen id. `fs.field({ id: "" })` ga `for=""`
2547
+ og `help.id="-help"`, altså det samme problemet uten at noe sa fra.
2548
+
2549
+ I React kommer id-en fra `useId()`. Ellers er feltets eget navn som regel
2550
+ det opplagte valget. Vet du sikkert at markupen rendres én gang, kall
2551
+ `createFieldId()` selv. Den er nå også eksportert fra
2552
+ `@fristil/designsystem/react`, siden det er inngangen React-dokumentasjonen
2553
+ ber deg bruke.
2554
+
2555
+ `<fs-field>` er upåvirket når komponenten er det eneste som kobler feltet:
2556
+ den lager id-er i nettleseren, etter at HTML-en står der. Bruker du React
2557
+ med server-rendring, skal du bruke `fs.field()`, så koblingen står ferdig i
2558
+ markupen serveren sendte.
2559
+
2560
+ - **`createFieldId` eksporteres også fra `@fristil/designsystem/react`.** Den
2561
+ lå bare i hovedinngangen og i `./field-core`, mens dokumentasjonen peker på
2562
+ den i en seksjon som ber leseren importere fra `/react`.
2563
+
2564
+ ### Rettet
2565
+
2566
+ - **Forslagsfeltet sluttet å melde antall treff når noen andre filtrerte.**
2567
+ `filter()` returnerte med en gang, så en app med attributtet mistet
2568
+ opplesningen i `[role="status"]`. Det sto ikke noe sted, og den som ikke
2569
+ ser skjermen merket det.
2570
+
2571
+ Beskjeden kommer nå av at lista har endret seg, og ikke av tastetrykket.
2572
+ Med `prefiltered` rendrer appen lista, og mellom tastetrykket og det nye
2573
+ svaret kan det gå et halvt sekund over nettverket. Bare en endring i
2574
+ antallet leses opp; det første antallet er utgangspunktet og ikke en nyhet.
2575
+
2576
+ Tommeldingen er derimot en del av det lista viser, og den eier du med
2577
+ `prefiltered`. `fs.suggestion({ count })` skriver `hidden` på den når du
2578
+ har treff, så rendrer du feltet for hvert søk, er det gjort. Komponenten
2579
+ kan ikke se forskjell på «søket ga ingenting» og «svaret er ikke kommet
2580
+ ennå», og meldte derfor «Ingen treff» ved fokus på et tomt felt og i hvert
2581
+ opphold i et asynkront søk.
2582
+
2583
+ - **`prefiltered` kunne ikke settes fra React.** Getteren hadde ingen setter,
2584
+ og React 19 skriver egenskapen framfor attributtet når et egendefinert
2585
+ element har en med det navnet. Skrivingen kastet «Cannot set property»,
2586
+ attributtet landet aldri, og komponenten skjulte det React nettopp hadde
2587
+ rendret. Det gamle navnet `server-filtered` kunne ikke være et
2588
+ egenskapsnavn, så feilen kom med omdøpingen.
2589
+
2590
+ - **`prefiltered` gjorde ingenting før neste tastetrykk.** Attributtet sto i
2591
+ `observedAttributes`, men tilbakekallet svarte bare på `server-controlled`.
2592
+ Slås det av mens siden lever, filtrerer komponenten nå med en gang.
2593
+
2594
+ ### Lagt til
2595
+
2596
+ - **`sjekk-dokumentasjon.ts` avviser et eksempel som kaller `fs.field()` uten
2597
+ `id`.** Ingenting annet i rekka leser kodeblokkene i dokumentasjonen, så et
2598
+ utdatert eksempel kunne stått grønt gjennom hele `bun run sjekk`. Den leser
2599
+ koden: i mdx kodegjerdene, i Astro frontmatteret og skriptene. I brødtekst
2600
+ teller bare et kall som har en argumentliste, siden `fs.field()` uten
2601
+ argumenter er navnet på en funksjon og står slik i dusinvis av setninger.
2602
+ Det skillet måtte til: `fs.suggestion({ count: treff.length })` sto i en
2603
+ setning under et eksempel og slapp gjennom.
2604
+
2605
+ ## 0.10.0 (2026-09-23)
2606
+
2607
+ ### Brytende
2608
+
2609
+ - **`data-preserve-attr` er borte fra hele pakken.** `fs.tabs()`,
2610
+ `fs.popover()`, `fs.suggestion()` og `fs.dialog()` skriver det ikke lenger,
2611
+ og typene deres har ikke feltet. Skriver du markupen for hånd, kan du slette
2612
+ attributtet.
2613
+
2614
+ Lista krevde at malen skrev av navnene på hvert attributt komponenten kom
2615
+ til å røre, ni strenger fordelt på fire komponenter, uten at noen
2616
+ kompilator så på dem. Endret Fristil hva en komponent satte, gikk malen
2617
+ stille i stykker. Komponentene setter nå tilbake det brukeren gjorde, og
2618
+ ingen mal trenger å kjenne attributtene.
2619
+
2620
+ ### Lagt til
2621
+
2622
+ - **`server-controlled` på verten gir serveren tilstanden tilbake.** Det
2623
+ fredningen ga, og som reparasjonen måtte erstatte, er at den som skrev
2624
+ markupen kunne bestemme hvem som eier tilstanden. «Gå videre til steg 2» er
2625
+ en ekte ting en server vil kunne gjøre. Står attributtet der, reparerer
2626
+ komponenten ingenting, og hver patch bestemmer. Ett attributt å huske i
2627
+ stedet for ni, og standardvalget er det som er riktig nesten alltid. Gjelder
2628
+ `<fs-tabs>`, `<fs-popover>`, `<fs-suggestion>` og `<fs-dialog>`, og er
2629
+ deklarert for JSX på alle fire.
2630
+
2631
+ - **`setAttr`, `setFlag`, `setText`, `addClass`, `SERVER_CONTROLLED` og
2632
+ `isServerControlled` er nye eksporter** fra
2633
+ `@fristil/designsystem/host-element`. De fire første skriver bare når noe
2634
+ faktisk endrer seg, og er de eneste lovlige veiene til et attributt, et
2635
+ boolsk flagg, tekst og en klasse i en komponent som observerer sine egne. En
2636
+ overtatt komponent bruker dem.
2637
+
2638
+ - **`scripts/sjekk-skriving.ts` håndhever den regelen.** Den kjører som del av
2639
+ `build`, både i pakken og i rota, og leser kilden, fordi regelen ikke lar seg
2640
+ etterprøve ved å kjøre noe: bryter en komponent den, kaller observatøren seg
2641
+ selv, mikrooppgavekøen tømmes aldri, og en testkjøring **henger** framfor å
2642
+ feile. Ingen stakksporing, ingen påstand, bare en kjøring som må drepes for
2643
+ hånd.
2644
+
2645
+ Den ser etter seks skrivemåter, ikke bare `setAttribute`: `el.hidden = x`,
2646
+ `el.tabIndex = n`, `el.htmlFor = s`, `el.textContent = s`,
2647
+ `classList.add()` og `el.style.cssText = s`. Alle gir en mutasjonspost når
2648
+ ingenting endrer seg, og fem av dem var i bruk. Verten er ikke et unntak:
2649
+ komponentene observerer seg selv, så `this.classList.add()` henger en
2650
+ kjøring like godt som en skriving på et barn.
2651
+
2652
+ - **`sjekk:server` kjøres nå også fra rota.** Den sto bare i pakkens egen
2653
+ `build`, så den kjørte ved publisering og ikke i CI, mens `CLAUDE.md` sa at
2654
+ den var en vaktpost.
2655
+
2656
+ - **`stabilitet.browser.test.ts`** teller mutasjoner i hver av de fem
2657
+ komponentene etter at brukeren har gjort noe, og krever null. Den fanger en
2658
+ komponent som skriver litt for mye.
2659
+
2660
+ ### Endret
2661
+
2662
+ - **Komponentene setter tilbake det brukeren gjorde.** `<fs-tabs>` setter
2663
+ fanevalget tilbake, `<fs-popover>` at vinduet er åpent og hvor det står,
2664
+ `<fs-suggestion>` om lista er utvidet og hva som er markert, og
2665
+ `<fs-dialog>` `open` på selve `<dialog>` når den fortsatt står i topplaget.
2666
+ Alle fire observerer nå de attributtene de selv setter, og hver skriving
2667
+ sammenligner først.
2668
+
2669
+ Sprettoppvinduet reparerer én vei: har noen bedt om at vinduet er åpent,
2670
+ blir det stående, men sender serveren `open`, åpnes det, for det er noe
2671
+ serveren faktisk sa. En app lukker det med egenskapen, altså
2672
+ `meny.open = false`, `hide()` eller `toggle()`; et attributt fjernet utenfra
2673
+ er ikke til å skille fra en morfing, og der er `server-controlled` svaret.
2674
+ Dialogen skiller på samme måte mellom `open` på verten, som er serverens
2675
+ beskjed, og `open` på `<dialog>`, som nettleseren setter.
2676
+
2677
+ Komponentene husker identiteter og ikke posisjoner. `<fs-tabs>` husker selve
2678
+ knappen brukeren valgte: en indeks er ingen identitet, og en id virker ikke
2679
+ i håndskrevet markup, som ofte ikke har noen. En attributtmorfing beholder
2680
+ nodene, så referansen overlever den. `<fs-suggestion>` husker både id-en og
2681
+ teksten på det markerte alternativet, siden id-ene fra `fs.suggestion()` er
2682
+ posisjonelle og en ny liste gjenbruker dem. Er det borte, glemmer
2683
+ komponenten det framfor å gjette, og fanene rydder opp etter seg slik at
2684
+ raden fortsatt svarer.
2685
+
2686
+ ## 0.9.0 (2026-09-23)
2687
+
2688
+ ### Brytende
2689
+
2690
+ - **`FIELD_PRESERVED_ATTRIBUTES` er fjernet.** Lista fantes for at en mal
2691
+ skulle kunne skrive av navnene på alt `<fs-field>` setter, inn i
2692
+ `data-preserve-attr`, slik at en morfing lot dem stå. Den er ikke lenger
2693
+ nødvendig: komponenten ser at attributtene er borte, og setter dem
2694
+ tilbake. Bruker du den i dag, kan du ta bort både lista og
2695
+ `data-preserve-attr` på feltet.
2696
+
2697
+ ### Rettet
2698
+
2699
+ - **Sprettoppvinduet åpnet seg igjen når en patch både fjernet `open` og
2700
+ overlot tilstanden.** En morfing setter ett attributt om gangen, og `open`
2701
+ kommer før `server-controlled` i dokumentrekkefølgen, så komponenten
2702
+ reparerte mens serveren var midt i å si at den overtar. Reparasjonen venter
2703
+ nå til hele patchen har landet, og sjekker vilkåret på nytt der.
2704
+
2705
+ - **Forslagsfeltet satte ikke tilbake `aria-activedescendant` alene.** Rev en
2706
+ patch bare pekeren, mens markeringen sto igjen, så ingenting galt ut i
2707
+ markupen, men skjermleseren hadde mistet lesepunktet sitt. Begge sidene av
2708
+ koblingen sjekkes nå.
2709
+
2710
+ - **En fanerad sluttet å svare når en patch fjernet den valgte fanen.**
2711
+ `<fs-tabs>` glemte valget, men lot markupen stå i utakt: ingen fane markert,
2712
+ alle paneler skjult, og et klikk gjorde ingenting, fordi `select(0)`
2713
+ sammenlignet mot en `selected` som svarer 0 også når ingenting er markert.
2714
+ Komponenten velger nå den første fanen i det tilfellet, og melder fra med
2715
+ `tab-select`, siden det er komponentens eget valg og ikke brukerens. Sendte
2716
+ serveren med vilje en rad uten markering, blir den overkjørt, men bare når
2717
+ brukeren hadde valgt noe fra før.
2718
+
2719
+ - **Et felt kunne ikke bli gyldig igjen.** `<fs-field>` leser `aria-invalid`
2720
+ fra kontrollen, fordi serveren kan ha skrevet feltet med `fs.field()` og da
2721
+ står svaret allerede der. Uten et skille mellom serverens attributt og
2722
+ komponentens eget leste den tilbake sitt eget svar fra forrige runde, så
2723
+ `felt.invalid = false` fjernet flagget på verten mens den røde rammen og
2724
+ feilmeldingen ble stående.
2725
+
2726
+ Komponenten noterer nå verdien den selv skrev, og hvilken kontroll den ble
2727
+ skrevet på. Står det noe annet der neste gang, har noen andre rørt
2728
+ attributtet, og det er serverens ord som gjelder. Avlesningen er dermed
2729
+ alltid utledet av en endring som faktisk har skjedd, så det samme
2730
+ dokumentet gir alltid det samme svaret. Skrev serveren `aria-invalid` selv,
2731
+ står det derfor: `felt.invalid = false` fjerner flagget på verten, men
2732
+ stryker ikke det serveren sa. Bruk den ene av de to kildene, ikke begge.
2733
+
2734
+ ### Endret
2735
+
2736
+ - **`<fs-field>` kobler også en ledetekst som står utenfor elementet.** En
2737
+ `<label for>` som peker på kontrollen navngir feltet like godt som en inni,
2738
+ og komponenten skriver nå `fs-label`, `data-required` og `aria-disabled` på
2739
+ den. Bytter en patch ut kontrollen med en uten id, husker komponenten
2740
+ id-en, så ledetekstens `for` fortsetter å peke på et element som finnes.
2741
+ Én forskjell er verdt å vite: en ledetekst utenfor ligger ikke i det
2742
+ komponenten observerer, så river en patch klassen av den, kommer den ikke
2743
+ tilbake før neste gang feltet synkroniserer.
2744
+
2745
+ - **`<fs-field>` reparerer sin egen kobling.** Bevaringslista var en kontrakt
2746
+ vi ikke kunne kontrollere: en Go- eller Kotlin-mal måtte skrive av ni
2747
+ attributtnavn fra dokumentasjonen, og endret Fristil hva komponenten satte,
2748
+ gikk malen stille i stykker. Komponenten observerer nå de attributtene den
2749
+ selv utleder, og setter dem tilbake i det en patch river dem bort. Id-ene
2750
+ den har laget huskes, så en skjermleser midt i en opplesning ikke følger en
2751
+ peker som skifter under den.
2752
+
2753
+ Skillet er mellom det komponenten har **regnet ut** og det brukeren har
2754
+ **gjort**. Det første kan regnes ut på nytt, og repareres. Det andre, som
2755
+ `open` på et sprettoppvindu eller hvilken fane som er valgt, finnes det
2756
+ ingen kilde til, og en reparasjon ville dessuten kjempet mot en server som
2757
+ med vilje endret noe. Det fredes fortsatt med `data-preserve-attr`, skrevet
2758
+ av byggefunksjonen.
2759
+
2760
+ ### Lagt til
2761
+
2762
+ - **Komponentene sier fra når markupen de fikk ikke henger sammen.** Alle
2763
+ disse ga før stillhet, og feilen viste seg først når noen leste siden med
2764
+ skjermleser:
2765
+
2766
+ - `<fs-field>` uten en kontroll, og uten en ledetekst. Feltet regnes som
2767
+ navngitt av en `<label>` inni, en `<label for>` utenfor, eller
2768
+ `aria-label` og `aria-labelledby` på kontrollen, som i et søkefelt med
2769
+ bare et ikon;
2770
+ - `<fs-tabs>` uten noe med `role="tab"`, og med færre paneler enn faner;
2771
+ - `<fs-dialog>` uten en `<dialog>` som direkte barn;
2772
+ - `<fs-suggestion>` uten en combobox, og uten en listboks;
2773
+ - `<fs-popover>` uten et panel, uten en id på panelet, og uten en knapp som
2774
+ peker på det;
2775
+ - `<fs-error-summary>` med punkter som ikke lenker til feltene, og med en
2776
+ lenke som peker på en id som ikke finnes. Den siste meldes når boksen
2777
+ synkroniserer, ikke først når noen klikker: en lenke som ikke fører noe
2778
+ sted er like ødelagt om ingen prøver den.
2779
+
2780
+ Advarselen kommer én gang per element og melding, og først når siden har
2781
+ falt til ro. Det siste er grunnen til at den kan stoles på: HTML som
2782
+ strømmer fra en server leveres i pakker, og et brudd mellom ledeteksten og
2783
+ feltet er helt vanlig, så komponenten ser ofte halvferdig markup i det den
2784
+ kobles til.
2785
+
2786
+ - **`warnAboutMarkup` er en ny eksport** fra `@fristil/designsystem/host-element`.
2787
+ En overtatt komponent bruker den, så den må være tilgjengelig.
2788
+
2789
+ - **En vaktpost på at hver komponent kan overtas.** `sjekk-cli.ts` kjører
2790
+ `overta` på hver komponent verktøyet selv lister opp, og krever at ingen
2791
+ fil i kopien peker ut av mappa, og at hver `@fristil/…`-henvisning står i
2792
+ `exports`. Faren har stått skrevet ned lenge: en komponent som henter noe
2793
+ fra en ny mappe uten et inngangspunkt gir en kopi som peker i løse lufta,
2794
+ og feilen viser seg først når konsumenten bygger. Nå sier den fra her.
2795
+
2796
+ ## 0.8.3 (2026-09-23)
2797
+
2798
+ ### Rettet
2799
+
2800
+ - **`<fs-dialog>` åpnet igjen en dialog brukeren nettopp hadde lukket.**
2801
+ Serveren skriver `open` begge steder, så innholdet finnes uten JavaScript,
2802
+ og `<form method="dialog">` lukker boksen uten JavaScript også. Skjer det
2803
+ før komponenten har fått kjøre, finnes det ingen lytter, og første
2804
+ synkronisering så en vert som sa «åpen» og en lukket dialog. Da spratt
2805
+ dialogen opp igjen. På mobil skjedde det hver gang, fordi vinduet der er
2806
+ langt nok til å rekke et trykk.
2807
+
2808
+ `returnValue` skiller de to tilfellene: nettleseren setter den til verdien
2809
+ på knappen som lukket dialogen, så en dialog som aldri har vært åpnet har
2810
+ den tom. En mal som bare skriver `open` på verten åpnes derfor som før.
2811
+ Funnet i spilldemoen, på 375 piksler.
2812
+
2813
+ Det holder bare når knappen har en `value`. Lukkes dialogen med en knapp
2814
+ uten verdi, etterlater nettleseren ingenting å se etter. Det står nå på
2815
+ dialogsiden, og eksemplene der har alltid hatt en.
2816
+
2817
+ ## 0.8.2 (2026-09-23)
2818
+
2819
+ ### Rettet
2820
+
2821
+ - **`<fs-field>` mistet koblingen mellom ledetekst og felt ved første
2822
+ patch.** Bytter en morfing ut selve kontrollen, finnes det ingen node å
2823
+ frede, og den nye kommer uten id. Ledeteksten står igjen med sin `for`.
2824
+ Komponenten fant da ingen id, fant opp en ny, skrev den bare på
2825
+ kontrollen, og `for` pekte etter det på et element som ikke fantes. Feltet
2826
+ var altså uten ledetekst for en skjermleser, og det holdt seg til siden
2827
+ ble lastet på nytt.
2828
+
2829
+ Id-en leses nå også fra ledetekstens `for`, og `for` skrives hver gang, ikke
2830
+ bare når den mangler: de to er den samme opplysningen og kan ikke få si
2831
+ hver sin ting. Funnet i spilldemoen, i appen som sender HTML-biter fra en
2832
+ Kotlin-server.
2833
+
2834
+ ## 0.8.1 (2026-09-23)
2835
+
2836
+ ### Endret
2837
+
2838
+ - **`fs.dialog({ open: true })` skriver `open` på `<dialog>` også.** Det sto
2839
+ bare på verten, og da var innholdet borte for den som ikke har
2840
+ JavaScript: en `<dialog>` uten `open` er skjult. Nå vises det, plassert
2841
+ over innholdet under seg slik nettleserens egen stil gjør det, og
2842
+ komponenten gjør den om til en ekte modal med `showModal()` når den får
2843
+ kjøre. I React var det dessuten det eneste som stemte: komponenten setter
2844
+ `open` før React hydrerer, og sto det ikke i serverens HTML, meldte React
2845
+ avvik ved hvert eneste oppslag. Funnet i demoappen i TanStack Start.
2846
+
2847
+ `<fs-dialog>` tar attributtet bort med `removeAttribute` framfor `close()`
2848
+ før den kaller `showModal()`. `close()` sender en ekte `close`-hendelse, og
2849
+ den ville nå kommet ved hver eneste lasting av en åpen dialog. En app som
2850
+ lytter på `close` rett på `<dialog>` fikk altså en lukking før brukeren
2851
+ hadde sett dialogen. `dialog-toggle` så den ikke, siden komponenten
2852
+ stopper på `:modal`.
2853
+
2854
+ Komponenten ser nå på `:modal` og ikke på `open` når den lukker.
2855
+ Byggefunksjonen sender `open` på `<dialog>`, så i React er det React som
2856
+ eier attributtet, og React oppdaterer barn før forelder: lukker appen
2857
+ dialogen, er attributtet borte før komponenten får vite det. `close()` gjør
2858
+ ingenting uten attributtet, så dialogen ble stående i topplaget, usynlig,
2859
+ med resten av siden inert.
2860
+
2861
+ Styrer du dialogen selv fra nettleseren, skal du ikke sende `open` inn i
2862
+ `fs.dialog()`. `showModal()` kaster `InvalidStateError` på en dialog som alt
2863
+ står åpen, så en app som gjorde begge deler virket før og kaster nå. Det
2864
+ står i typen, i JSDoc-en og på siden.
2865
+
2866
+ Har du JavaScript, ser du dessuten dialogen et øyeblikk som en boks der den
2867
+ står i flyten, før komponenten flytter den til midten som en modal. Før var
2868
+ det ingenting å se før modalen kom.
2869
+
2870
+ ### Rettet
2871
+
2872
+ - **`fs.field()` sa ikke fra om at en id som lages av seg selv er
2873
+ tilfeldig.** Rendres feltet både på serveren og i nettleseren, blir det to
2874
+ ulike, og `for` og `aria-describedby` peker på noe annet enn det som står
2875
+ der. React melder avvik ved hydreringen. Det står nå i typen, på feltsiden
2876
+ og i React-fanen, med `useId()` som svaret.
2877
+
2878
+ ## 0.8.0 (2026-09-23)
2879
+
2880
+ ### Brytende
2881
+
2882
+ - **Boolske attributter på en vert er `true`, ikke `""`.** `fs.dialog().host`
2883
+ og `fs.popover().host` sendte ut `open: ""`. React 19 setter egenskaper
2884
+ framfor attributter på egendefinerte elementer, og `el.open = ""` er usant,
2885
+ så setteren i komponenten fjernet attributtet igjen: dialogen og panelet
2886
+ åpnet seg ikke, og om det skjedde kom an på om elementet var oppgradert
2887
+ ennå. `data-*` er noe annet og beholder den tomme strengen, for dem sender
2888
+ React videre som attributter i begge versjoner. `Flag` i `jsx/react.ts` er
2889
+ dermed `true | undefined` igjen, slik dokumentasjonen har sagt hele tiden.
2890
+
2891
+ - **Avslaget på fokus i feiloppsummeringen heter `data-autofocus="false"`.**
2892
+ Det het `autofocus="false"`. `autofocus` er en boolsk egenskap på
2893
+ `HTMLElement`, så React 19 satte `el.autofocus = "false"`, som er sant,
2894
+ mens attributtet aldri kom i markupen. Avslaget virket altså ikke i React
2895
+ 19, og feilen var taus. Samme feilklasse som `open` over.
2896
+
2897
+ - **`ReactAttributes<T>` gir `number` for `tabIndex`.** Typen er eksportert,
2898
+ altså offentlig API, og den sa før `string`. Rettelsen under er grunnen:
2899
+ verdien var feil, og typen beskrev feilen. Kode som tok imot den gamle
2900
+ typen som en streng, for eksempel `const t: string = fs.tabs(...).tabs[0]
2901
+ .tabIndex`, kompilerer ikke lenger. Selve attributtet i DOM-en er uendret.
2902
+
2903
+ ### Rettet
2904
+
2905
+ - **`tabIndex` kom ut som en streng fra React-inngangen.** `NAVN` døpte om
2906
+ `tabindex`, men lot verdien stå. I HTML er den en streng, i React er
2907
+ `tabIndex` et tall, så `fs.tabs()` ga `tabIndex: "0"` og TypeScript avviste
2908
+ den i enhver React-app. Den virket i nettleseren, siden React gjør om
2909
+ verdien selv, så feilen viste seg bare som en typefeil hos konsumenten.
2910
+ Funnet i en ekte React-app, ikke her.
2911
+
2912
+ - **`fs.fieldset` lovet en tilstand som ikke fantes.** `states` har alltid
2913
+ oppgitt `success`, men `fieldset.css` hadde bare en regel for `invalid`.
2914
+ Attributtet ble skrevet, og ingenting skjedde.
2915
+
2916
+ - **JSX-deklarasjonene godtok ikke det byggerne sender ut.** Et boolsk
2917
+ attributt er `""` fra byggeren, mens `Flag` i `jsx/react.ts` bare tillot
2918
+ `true` og `undefined`. `<fs-popover {...fs.popover({ open: true }).host}>`
2919
+ type-sjekket derfor ikke, altså to deler av det samme API-et som var
2920
+ uenige om det samme attributtet.
2921
+
2922
+ ### Lagt til
2923
+
2924
+ - **En vaktpost på at hver lovlig verdi finnes i CSS-en.** `pakke-css.browser.test.ts`
2925
+ går gjennom listene byggerne reklamerer med, `variants`, `colors`, `sizes`,
2926
+ `states`, `pickers`, `markers` og `types`, kaller byggeren med hver av dem,
2927
+ og rendrer elementet to ganger, med og uten attributtet. Noe i den beregnede
2928
+ stilen må være forskjellig, pseudoelementene medregnet. Et tekstsøk ville
2929
+ passert på en tom regel og på en som blir overstyrt lenger nede.
2930
+ Farger regelen et barn framfor elementet selv, som feltsettet gjør med
2931
+ `.fs-legend`, kreves det i stedet at en regel som gjelder her erklærer noe.
2932
+ Uten det ville en tom blokk passert, og det var nettopp en tom blokk som
2933
+ slapp gjennom første utgave av prøven.
2934
+
2935
+ Verdier som ikke sender ut noe attributt hoppes over: standardverdien, og
2936
+ verdier som ikke er ment å se annerledes ut. To egne prøver passer på at
2937
+ hoppelista ikke blir en bakdør. Den ene krever at opsjonsnavnet er et
2938
+ byggefunksjonen kjenner, siden feil navn ellers tar en hel liste ut av
2939
+ prøven i stillhet. Den andre krever at hver liste en byggefunksjon har,
2940
+ står i tabellen.
2941
+
2942
+ Hvilke regler som gjelder hentes fra CSSOM, ikke fra teksten: en regel i en
2943
+ `@supports` motoren ikke har, eller i en `@media` som ikke slår til, gjør
2944
+ ingenting. Den stylede nedtrekkslista står i begge, og skal ikke endre noe
2945
+ i Firefox.
2946
+
2947
+ `dom.browser.test.ts` sjekket at en verdi kan settes og fjernes, ikke at
2948
+ den betyr noe. Fieldset-feilen over hadde ligget der siden komponenten kom.
2949
+
2950
+ - **En vaktpost på at ingen byggefunksjon sender ut et navn React staver
2951
+ annerledes.** `react.browser.test.ts` kalte før ti byggefunksjoner for hånd
2952
+ og så bare etter `class` og `for`. Den går nå gjennom hver byggefunksjon i
2953
+ `/react`, med hver lovlige verdi funksjonen selv oppgir, og avviser hvert
2954
+ navn i Reacts egen tabell, også `readonly`, `maxlength` og `colspan`, som
2955
+ ingen byggefunksjon sender ut ennå. Den krever også at hver byggefunksjon i
2956
+ `fs` finnes i `/react`.
2957
+
2958
+ - **En vaktpost på at byggerne passer i JSX-deklarasjonene.**
2959
+ `src/jsx/typer.browser.test.ts` tilordner det byggerne sender ut til
2960
+ `JSX.IntrinsicElements`, og det er `typecheck:tests` som er prøven. Begge
2961
+ deler er offentlig API, og de kan gå fra hverandre uten at noe sier fra.
2962
+
2963
+ ## 0.7.0 (2026-09-22)
2964
+
2965
+ ### Brytende
2966
+
2967
+ - **`fs.dialog()` tar nå et valgobjekt og gir ett attributtsett per element.**
2968
+ Den ga før `{ class: "fs-dialog" }` til selve `<dialog>`. Nå heter kallet
2969
+ `fs.dialog({ titleId, open })` og gir `host`, `dialog`, `title`, `body` og
2970
+ `footer`, på samme form som `fs.popover()`. Klassenavnene ligger fortsatt på
2971
+ funksjonen: `fs.dialog.title` og de andre.
2972
+
2973
+ - **Dialogen har flyttet fra `css/` til `ramme/`,** siden den nå har en
2974
+ komponent. `@fristil/designsystem/dialog` peker derfor på `<fs-dialog>` og
2975
+ ikke lenger på byggefunksjonen; den hentes fra hovedinngangen, som for de
2976
+ andre sammensatte komponentene. `@fristil/designsystem/dialog.css` er
2977
+ uendret.
2978
+
2979
+ ### Lagt til
2980
+
2981
+ - **`<fs-dialog>` lar en server åpne en dialog.** Å åpne en `<dialog>` er et
2982
+ kall og ikke et attributt: bare `showModal()` flytter fokus inn, holder
2983
+ fokus inne i dialogen, lukker på Escape og gjør resten av siden
2984
+ utilgjengelig. `<dialog open>` er bare en boks på siden. En app som skriver
2985
+ HTML på serveren, i Datastar, htmx, en Go-mal eller en Razor-visning, kunne
2986
+ derfor ikke åpne en dialog i det hele tatt uten å skrive sitt eget skript
2987
+ ved siden av. Nå sier serveren `open` på `<fs-dialog>`, og komponenten gjør
2988
+ kallet.
2989
+
2990
+ Lukker brukeren dialogen, fjernes `open` fra verten igjen, så markupen sier
2991
+ det samme som skjermen. De to `open`-ene er ikke det samme: det på verten er
2992
+ serverens beskjed og er ikke fredet, for ellers kunne serveren aldri åpnet
2993
+ dialogen igjen etter første lukking. Det nettleseren setter på selve
2994
+ `<dialog>` når `showModal()` kalles, er derimot fredet, ellers river
2995
+ morfingen det bort og lukker dialogen i samme øyeblikk som den åpnet den.
2996
+ `morfing.browser.test.ts` kjører hele runden.
2997
+
2998
+ Komponenten melder fra med hendelsen `dialog-toggle`, som bærer `open` og
2999
+ `returnValue`, altså hvilken knapp som lukket dialogen. Den er `composed`,
3000
+ så den kommer ut av en skyggerot.
3001
+
3002
+ Komponenten gjør ingenting når den står løsrevet fra siden. En morfer
3003
+ bygger serverens utgave i et løsrevet tre før den sammenlignes, og et
3004
+ egendefinert element tas i bruk der også; uten den sperren kastet
3005
+ `showModal()` ved hver patch som rørte dialogen.
3006
+
3007
+ ### Rettet
3008
+
3009
+ - **`color-scheme` i `tokens.css`.** Uten den tegner nettleseren sine egne
3010
+ flater lyst uansett hva tokenene sier: nedtrekkslista til en `<select>`,
3011
+ rullefelt og kalenderpanelet i et datofelt. En side i mørkt tema fikk da en
3012
+ hvit liste midt i seg. `:root` sier nå `light dark`, så systemvalget
3013
+ avgjør, og `data-theme` setter den til `light` eller `dark` slik at
3014
+ nettleserens flater følger med når appen tvinger fram et tema.
3015
+
3016
+ Dette ble funnet i en demoapp, ikke i enhetstestene. Det er bare
3017
+ nettleserens eget utseende som røper det.
3018
+
3019
+ - **`<fs-field>` sier selv at det er en blokk.** Et egendefinert element er
3020
+ `display: inline` til noen sier noe annet, og feltet var det eneste som
3021
+ pakker inn andre elementer uten å si det. Barna er blokker, så det så
3022
+ riktig ut helt til noen ga elementet en avstand eller la det i et rutenett.
3023
+ `<fs-suggestion>` har alltid sagt det samme om seg selv.
3024
+
3025
+ ## 0.6.1 (2026-09-22)
3026
+
3027
+ ### Lagt til
3028
+
3029
+ - **`--semantic-focus-ring` samler fokusringen på ett sted.** Den sto skrevet
3030
+ ut med bredde og farge i tjue regler fordelt på atten stilark. Selektorene
3031
+ er forskjellige i hver komponent, og `outline-offset` skal være ulik, så det
3032
+ som faktisk gjentok seg var verdien. Nå skriver hver komponent
3033
+ `outline: var(--semantic-focus-ring)`, og en konsument som vil ha en annen
3034
+ fokusring endrer ett token framfor atten filer.
3035
+
3036
+ De tre stedene som med vilje har en annen farge, feiloppsummeringen og
3037
+ hopplenken, skriver `outline-color` etter kortformen og arver bredden. Da
3038
+ følger også de med hvis bredden endres.
3039
+
3040
+ En ny vaktpost i `pakke-css.browser.test.ts` avviser en `outline` med
3041
+ `solid` skrevet ut i et komponentstilark.
3042
+
3043
+ ## 0.6.0 (2026-09-22)
3044
+
3045
+ ### Brytende
3046
+
3047
+ - **`fs.popover()` sender ikke lenger ut `slot="trigger"`.** Attributtet var
3048
+ et levn fra den gangen komponenten hadde shadow DOM. Uten en skyggerot gjør
3049
+ `slot` ingenting i HTML, så det var en merkelapp som så ut som noe annet enn
3050
+ det var, og dokumentasjonen ba leseren skrive noe nettleseren ignorerte.
3051
+
3052
+ `<fs-popover>` kjenner nå igjen delene på koblingen som må være der uansett:
3053
+ panelet er det som har `popover`, og knappen er den som peker på panelet med
3054
+ `aria-controls`. Begge deler skriver `fs.popover()` fra før, så markup laget
3055
+ med byggefunksjonen virker uendret, og et `slot`-attributt som blir stående
3056
+ fra en server som ikke er oppdatert, gjør ingen skade.
3057
+
3058
+ Skriver du markupen for hånd, må knappen ha `aria-controls` med panelets
3059
+ `id`, og panelet må ha `popover`. Det er de samme to tingene
3060
+ tilgjengeligheten krever.
3061
+
3062
+ Typen `PopoverAttributes` har mistet `slot` fra `trigger`.
3063
+
3064
+ ## 0.5.3 (2026-09-22)
3065
+
3066
+ ### Rettet
3067
+
3068
+ - **Pakken lar seg importere på en server.** `class X extends HTMLElement`
3069
+ blir evaluert i det modulen lastes, og `HTMLElement` finnes bare i
3070
+ nettleseren. Ni av inngangspunktene stoppet derfor med «HTMLElement is not
3071
+ defined» på en server uten DOM, hovedinngangen `@fristil/designsystem`
3072
+ inkludert. Det gjorde `import { fs } from "@fristil/designsystem"` umulig i
3073
+ en Node- eller Bun-server, altså nøyaktig den linja «Kom i gang» ber leseren
3074
+ skrive, i nettopp den situasjonen systemet er bygd for.
3075
+
3076
+ Web-komponentene arver nå fra `HostElement` i det nye inngangspunktet
3077
+ `@fristil/designsystem/host-element`, som faller tilbake på en tom klasse
3078
+ når `HTMLElement` ikke finnes. `defineFs*` gjør ingenting når det ikke
3079
+ finnes noen `customElements` å registrere i, så et kall fra en modul som
3080
+ kjøres begge steder er trygt.
3081
+
3082
+ Ingen nettlesertest kunne se dette, for der finnes `HTMLElement`. En ny
3083
+ vaktpost, `scripts/sjekk-server-import.ts`, kjører i Bun uten DOM og
3084
+ importerer hver JavaScript-oppføring i `exports` fra `dist`.
3085
+
3086
+ ## 0.5.2 (2026-09-22)
3087
+
3088
+ ### Lagt til
3089
+
3090
+ - **`<select>` kan tegne nedtrekkslista inne i siden.** `fs.select({ picker:
3091
+ "styled" })` gir `data-picker="styled"`, og da bruker feltet
3092
+ `appearance: base-select`: lista blir et vanlig element i siden i stedet for
3093
+ et vindu fra operativsystemet, og får Fristils farger, avstander og skygge.
3094
+ Elementet er fortsatt en helt vanlig `<select>`, så innsending, tastatur og
3095
+ skjermleser er uendret.
3096
+
3097
+ Det må slås på, og det er med vilje. Chromium 148 og WebKit 26.4 har
3098
+ `appearance: base-select`; Firefox 150 har det ikke og viser nettleserens
3099
+ egen liste som før. Begge deler er testet i hver sin motor. I
3100
+ høykontrastmodus faller alle tre tilbake til nettleserens egen liste, siden
3101
+ systemfargene er de eneste som er garantert lesbare der.
3102
+
3103
+ Nye variabler: `--fs-select-option-padding` og
3104
+ `--fs-select-viewport-margin`. `--fs-select-radius` gjelder nå også lista.
3105
+
3106
+ ### Rettet
3107
+
3108
+ - **`FIELD_PRESERVED_ATTRIBUTES` dekker nå hjelpeteksten og feilmeldingen.**
3109
+ Skriver malen ingen id-er, lager `<fs-field>` dem selv, og
3110
+ `aria-describedby` på kontrollen peker på dem. `id` sto ikke i noen liste,
3111
+ så en morfing fjernet den, og koblingen pekte på noe som ikke fantes: verken
3112
+ hjelpeteksten eller feilmeldingen ble lest opp. Lista har nå en `help`-nøkkel,
3113
+ `error` har fått `id` og ledeteksten har fått `for`.
3114
+
3115
+ - **`<fs-error-summary>` tar fokus hver gang boksen vises på nytt.** Den tok
3116
+ det bare første gang. Mønsteret i en Datastar-app er at serveren sender
3117
+ boksen skjult og bare slår `hidden` av og på, mens lista står med de samme
3118
+ lenkene, og da nullstilte ingenting flagget. Andre gang det samme skjemaet
3119
+ feilet, ble brukeren stående i feltet uten å få vite hvorfor innsendingen
3120
+ ikke gikk gjennom. Flagget nullstilles nå når boksen skjules.
3121
+
3122
+ - **`<fs-suggestion>` leser hvilket alternativ som er markert fra markupen.**
3123
+ Komponenten holdt en egen teller ved siden av `aria-selected`. Satte
3124
+ serveren markeringen selv med `fs.suggestion({ activeIndex })`, hoppet
3125
+ første piltast til toppen av lista i stedet for til alternativet etter, og
3126
+ markeringen serveren nettopp sendte var borte.
3127
+
3128
+ - **Pil opp åpner lista, og går til det siste alternativet.** Den markerte før
3129
+ et alternativ uten å åpne lista, så `aria-activedescendant` pekte inn i noe
3130
+ feltet samtidig meldte som lukket, og skjermleseren leste opp et alternativ
3131
+ som ikke sto på skjermen. Uten noe markert fra før gikk den dessuten til det
3132
+ nest siste, ikke det siste.
3133
+
3134
+ - **`fs.suggestion().empty` bevarer `hidden` gjennom en oppdatering.**
3135
+ Komponenten skjuler «Ingen treff» når noe passer, men elementet hadde ingen
3136
+ `data-preserve-attr`, så teksten dukket opp igjen ved hver patch, også midt
3137
+ i en liste med treff. Byggefunksjonen sender nå `hidden` når serveren har
3138
+ noe å velge mellom, og navnet står i lista.
3139
+
3140
+ Begge ble funnet av en ny vaktpost, `morfing.browser.test.ts`, som kjører
3141
+ Datastars egen attributtsynkronisering mot ekte markup etter at komponenten
3142
+ har gjort jobben sin. Den dekker felt, forslagsfelt, faner og
3143
+ sprettoppvindu.
3144
+
3145
+ - **`.fs-select` snur riktig i språk som skrives fra høyre mot venstre.**
3146
+ Feltet holdt av plass til pila si med en `padding` på fire verdier, altså
3147
+ over, høyre, under og venstre. De to fysiske sidene snur ikke med språket,
3148
+ så i RTL lå plassen på feil side og teksten la seg oppå pila. Plassen settes
3149
+ nå logisk, og pila, som er to gradienter og derfor ikke har noen logisk
3150
+ variant, speilvendes med `:dir(rtl)`. Nedtrekkslista var ikke dekket av
3151
+ retningstesten i det hele tatt, og er det nå. En ny vaktpost i
3152
+ `pakke-css.browser.test.ts` avviser fysiske kortformer med fire verdier i
3153
+ alle stilark.
3154
+
3155
+ - **`fs.setAttributes` fjerner nå `data-size` og `data-picker` igjen.** Den
3156
+ rydder bare i en lukket liste av attributtnavn, og de to sto utenfor. En
3157
+ avatar eller en overskrift som gikk tilbake til standardstørrelsen beholdt
3158
+ altså `data-size` fra forrige kall, og fikk aldri standardutseendet sitt
3159
+ igjen. En ny vaktpost kaller hver byggefunksjon med hver lovlige verdi den
3160
+ selv oppgir, regner et attributt som valgfritt når det ikke er med i kallet
3161
+ uten argumenter, og krever at hvert av dem lar seg fjerne.
3162
+
3163
+ ## 0.5.1 (2026-09-21)
3164
+
3165
+ ### Rettet
3166
+
3167
+ - **React-inngangen døper nå også om `autocomplete` til `autoComplete`.**
3168
+ `fs.suggestion()` sender det ut på kontrollen, og React advarte «Invalid DOM
3169
+ property `autocomplete`» i konsollen for hvert forslagsfelt. En ny vaktpost
3170
+ kaller hver byggefunksjon, teller opp hvert attributtnavn de sender ut, og
3171
+ krever at ingen av dem er et navn React staver annerledes uten at
3172
+ `react.ts` døper det om.
3173
+
3174
+ - **`<fs-session-timeout>` bygger dialogen sin først når den skal vises.** Den
3175
+ lagde den i `connectedCallback`, altså før React rakk å hydrere, og
3176
+ hydreringen feilet med «server rendered HTML didn't match the client». Nå
3177
+ gjør den det samme som `<fs-toast>` og `<fs-connection-status>`: ingenting
3178
+ står i DOM-en før det trengs.
3179
+
3180
+ ### Endret
3181
+
3182
+ - **`fs.toast()` er dokumentert.** Byggefunksjonen fantes, men sto ikke på
3183
+ komponentsiden. Den gir tre attributtsett, og det er `region` du sprer på
3184
+ `<fs-toast>`, ikke hele objektet.
3185
+
3186
+
3187
+ ## 0.5.0 (2026-09-21)
3188
+
3189
+ ### Brytende
3190
+
3191
+ - **Serveren skriver markupen, komponentene fester bare oppførsel.** Seks
3192
+ komponenter satte tidligere klasser, roller og tilgjengelighetskoblinger på
3193
+ elementer serveren hadde sendt. Det virker ikke i en app med server-rendret
3194
+ HTML: Datastars morfing fjerner hvert attributt som ikke står i HTML-en
3195
+ serveren nettopp sendte, og React kan kaste bort noder et egendefinert
3196
+ element har lagt inn i et tre React eier. Testet med ekte Datastar mistet et
3197
+ `<fs-field>` både `aria-describedby`, klassen på ledeteksten og den skjulte
3198
+ feilmeldingen etter én patch, og fikk dem ikke tilbake.
3199
+
3200
+ Markupen skrives nå av nye byggere i `fs`: `fs.errorSummary()`,
3201
+ `fs.popover()`, `fs.tabs()`, `fs.suggestion()` og `fs.toast()`. Byggerne
3202
+ setter også `data-preserve-attr` for de attributtene komponenten endrer
3203
+ underveis, så du slipper å vite om det. Se «Server først» i dokumentasjonen.
3204
+
3205
+ - **`<fs-calendar>` og `<fs-date-field>` er fjernet.** Nettleserens eget panel
3206
+ i `<input type="date">` gjør jobben, og `fs.field()` sammen med
3207
+ `fs.input({ type: "date" })` gir et komplett datofelt. Mønstersiden «Dato i
3208
+ et skjema» viser oppsettet, med de to forskjellene vi har testet mellom nettleserne.
3209
+ `exports`-oppføringene `./calendar`, `./date-field` og `./date-field.css` er
3210
+ borte, og det samme er `--fs-calendar-*`- og `--fs-date-field-*`-variablene
3211
+ og alle `part`-navnene i kalenderen.
3212
+
3213
+ - **`<fs-suggestion>` er flyttet fra `frittstående` til `ramme`.** Den lagde
3214
+ tidligere hele feltet selv, så det fantes verken ledetekst eller
3215
+ inndatafelt før skriptet hadde kjørt, og ingenting ble med i innsendingen.
3216
+ Nå skriver serveren feltet og lista med `fs.suggestion()`.
3217
+
3218
+ - **`<fs-tabs>` har ingen `selected`- eller `label`-attributter lenger.**
3219
+ Hvilken fane som er valgt står i markupen serveren sendte. `<fs-error-summary>`
3220
+ har ikke lenger `heading`: overskriften skrives av serveren.
3221
+
3222
+ - **Ingen komponent bruker shadow DOM.** `::part()` er dermed ikke lenger en
3223
+ del av det offentlige API-et.
3224
+
3225
+ - **`<fs-field>` leser tilstanden fra markupen, ikke fra egne attributter.**
3226
+ Skrev serveren feltet med `fs.field()`, står `aria-invalid` og
3227
+ `data-required` allerede på elementene. Komponenten regnet tidligere ut sitt
3228
+ eget svar fra attributtene på verten, fant ingenting der, og fjernet det
3229
+ serveren nettopp hadde skrevet. De to halvdelene av API-et kranglet altså
3230
+ med hverandre når de ble brukt sammen. Den setter heller ikke lenger
3231
+ `aria-hidden` på feilmeldingen: `hidden` tar den allerede ut av
3232
+ tilgjengelighetstreet, og attributtet ga hydreringsfeil i React.
3233
+
3234
+ ### Lagt til
3235
+
3236
+ - **`<fs-session-timeout>`** varsler før en innlogget økt går ut, med en
3237
+ nedtelling som leses opp ved terskler i stedet for hvert sekund, og fokus
3238
+ som går tilbake dit brukeren var.
3239
+
3240
+ - **`<fs-connection-status>`** sier fra når forbindelsen til serveren er
3241
+ borte. `navigator.onLine` sier bare at maskinen har et nettverk, så
3242
+ `reportFailure()` og `reportSuccess()` lar appen melde fra selv.
3243
+
3244
+ - **Siden «Server først»** forklarer hvorfor markupen kommer fra serveren, med
3245
+ testene bak, og hva det betyr i TanStack Start, React Server Components og
3246
+ Datastar.
3247
+
3248
+ - **Mønstersiden «Dato i et skjema»** viser hvordan du ber om en dato uten en
3249
+ datovelger fra oss, med de to forskjellene vi har testet mellom nettleserne:
3250
+ WebKit krever skilletegnene, og Chromium tar imot feil rekkefølge som
3251
+ gyldig.
3252
+
3253
+ - **`FIELD_PRESERVED_ATTRIBUTES`** er lista serveren skal skrive som
3254
+ `data-preserve-attr` når den ikke kan kalle `fs.field()` selv.
3255
+
3256
+ ### Rettet
3257
+
3258
+ - **`<fs-toast duration="0">` lot ikke meldingene bli stående.** Attributtet
3259
+ ble lest som «ugyldig» og falt tilbake til seks sekunder, så bare
3260
+ `show(…, { duration: 0 })` virket.
3261
+
3262
+ - **`<fs-error-summary>` fikk ikke fokus når serveren bare tok bort `hidden`.**
3263
+ Komponenten så etter endringer i barna, ikke i attributtene, så en
3264
+ oppsummering som nettopp ble synlig ble stående uten fokus.
3265
+
3266
+ - **`<fs-error-summary>` finner nå feltet i sin egen rot.** Oppslaget gikk mot
3267
+ `document`, som ikke ser inn i en skyggerot, så lenken ble en vanlig
3268
+ ankerlenke uten fokusflytting når skjemaet lå inne i en annen komponent.
3269
+
3270
+ - **`FIELD_PRESERVED_ATTRIBUTES` dekker alle tre elementene.** Den dekket bare
3271
+ kontrollen, men komponenten legger også `fs-label` og markeringene på
3272
+ ledeteksten og skjuler feilmeldingen. Serveren må derfor skrive én liste per
3273
+ element, og konstanten har nå `label`, `control` og `error`.
3274
+
3275
+ - **`<fs-popover>` lot seg ikke åpne etter at den var flyttet i DOM-en.**
3276
+ Referansen til knappen ble stående, så lytteren ble aldri festet på nytt.
3277
+
3278
+ - **`fs.popover({ open: true })` sier det nå på verten.** Før satte den bare
3279
+ `aria-expanded` på knappen, så markupen meldte at panelet var åpent mens
3280
+ komponenten mente det var lukket.
3281
+
3282
+ - **`<fs-suggestion>` mistet musevalg etter at serveren sendte en ny liste.**
3283
+ Alternativene fikk bare lytteren sin når selve feltet var nytt.
3284
+
3285
+ ### Endret
3286
+
3287
+ - **React-inngangen døper også om `tabindex` til `tabIndex`,** og dekker de nye
3288
+ sammensatte byggerne. `fs.errorSummary()`, `fs.popover()`, `fs.tabs()`,
3289
+ `fs.suggestion()` og `fs.toast()` finnes nå også i
3290
+ `@fristil/designsystem/react`, der hvert attributtsett er døpt om for seg.
3291
+ Pakken har fortsatt ingen avhengighet til React: dette er ren omdøping av
3292
+ tre objektnøkler.
3293
+
3294
+ - **`lit` er ikke lenger en avhengighet.** Etter omleggingen rendrer ingen
3295
+ komponent sitt eget innhold, så Lit ble brukt til nesten ingenting.
3296
+ Komponentene er vanlige `HTMLElement`-klasser, og pakken har nå ingen
3297
+ avhengigheter i det hele tatt.
3298
+
3299
+ ## 0.4.0 (2026-09-21)
3300
+
3301
+ ### Endret
3302
+
3303
+ - `lit` er en vanlig avhengighet, ikke en valgfri `peerDependency`. Du trenger
3304
+ bare `npm install @fristil/designsystem`, og ikke lenger vite at Lit finnes.
3305
+ Bygget ditt er upåvirket: ingenting registreres ved import alene, så Lit
3306
+ kommer først med når du kaller en `defineFs*`.
3307
+
3308
+ ## 0.3.0 (2026-09-21)
3309
+
3310
+ ### Rettet
3311
+
3312
+ - `sjekk-eksport.ts` leser svaret fra `npm pack --json` i begge formene npm
3313
+ bruker. npm 11 svarer med en liste, npm 12 med et objekt der pakkenavnet er
3314
+ nøkkelen, og arbeidsflyten som publiserer henter alltid nyeste npm. Utgivelsen
3315
+ stoppet derfor på «{} is not iterable», med en feil som pekte på vår egen kode
3316
+ framfor på npm. Skriptet sier nå fra med npm sin egen feilmelding når
3317
+ pakkingen feiler.
3318
+
3319
+ - `bin` peker på `dist/cli.js` uten `./` foran. npm rettet det selv ved
3320
+ publisering og advarte om at navnet var «invalid and removed», som leste som
3321
+ om kommandolinja forsvant. Den var med hele tiden.
3322
+
3323
+ ## 0.2.0 (2026-09-21)
3324
+
3325
+ ### Lagt til
3326
+
3327
+ - `fristil overta <komponent>` kopierer kildekoden til én komponent inn i
3328
+ prosjektet ditt, og skriver om henvisningene ut av mappa. Til bruk når
3329
+ tilpasning gjennom CSS ikke strekker til. Kopien er din, og oppdateringer av
3330
+ pakken rører den ikke.
3331
+
3332
+ - `fristil --hjelp` (og `--help`, `-h`, `help`) skriver ut hva kommandoen kan.
3333
+ Uten argumenter gjorde den før et forsøk på å lage et tema, og klaget over
3334
+ manglende farger uten å nevne at `overta` fantes.
3335
+
3336
+ - Pakken kan publiseres på npm. Den har lisens (MIT), en README som blir
3337
+ forsiden på npm, og feltene `repository`, `homepage`, `bugs` og `keywords`.
3338
+ `publishConfig` sier `public`, siden en pakke med navnerom ellers blir
3339
+ privat, og `prepublishOnly` bygger, så en publisering fra et rent klon ikke
3340
+ kan komme ut uten `dist`.
3341
+
3342
+ - `bun run sjekk:pakke` kjører [publint](https://publint.dev) mot pakken, som
3343
+ en del av bygget. Den leser `exports` slik nettlesere, byggverktøy og TypeScript
3344
+ faktisk gjør det.
3345
+
3346
+ ### Rettet
3347
+
3348
+ - `types` står først i hver oppføring i `exports`. Betingelsene leses i
3349
+ rekkefølge, og `import` sto først, så TypeScript fant typene bare fordi
3350
+ `.d.ts`-fila lå ved siden av `.js`-fila. Stiene er de samme som før.
3351
+
3352
+ - Kommandolinja svarer med en forklaring i stedet for et stakkspor fra Node
3353
+ når kommandoen er ukjent, eller når temafila mangler eller ikke er JSON.
3354
+
3355
+ - Lista over valgte filer i `file-upload` brekker nå til flere linjer på smal
3356
+ skjerm. Raden var bredere enn en telefon når filnavnet var langt, og knappen
3357
+ «Fjern <filnavn>» ble klippet av.
3358
+ - `<fs-error-summary>` oppdaterer overskriften når `heading` endrer seg. Den
3359
+ ble bare skrevet første gang, så en oppsummering som talte ned fra to feil
3360
+ til én ble stående på to.
3361
+
3362
+ ## 0.1.0 (2026-09-21)
3363
+
3364
+ Første versjon.
3365
+
3366
+ ### Lagt til
3367
+
3368
+ - **Tokens** for farge, størrelse, typografi, radius og skygge, med semantiske
3369
+ navn (`--semantic-*`) over en råskala. Lyst og mørkt tema, og en egen fil for
3370
+ Tailwind 4.
3371
+ - **34 CSS-komponenter** som bare trenger en klasse og `data-*`-attributter:
3372
+ accordion, alert, avatar, badge, breadcrumbs, button, card, checkbox, dialog,
3373
+ divider, error-text, fieldset, file-upload, heading, help-text, input, label,
3374
+ link, list, pagination, paragraph, radio, search, select, skeleton,
3375
+ skip-link, spinner, sr-only, switch, table, tag, textarea, toggle-group og
3376
+ tooltip.
3377
+ - **Fire rammekomponenter** som kobler sammen markupen du selv skriver:
3378
+ `<fs-field>`, `<fs-error-summary>`, `<fs-popover>` og `<fs-tabs>`.
3379
+ - **Fire frittstående komponenter** som eier markupen og interaksjonen:
3380
+ `<fs-calendar>`, `<fs-date-field>`, `<fs-suggestion>` og `<fs-toast>`.
3381
+ - **`fs`-API-et**: én funksjon per komponent som tar et valgobjekt og gir
3382
+ attributter tilbake, med lovlige verdier og vakt hengt på funksjonen. En egen
3383
+ inngang for React (`@fristil/designsystem/react`) med `className` og
3384
+ `htmlFor`, og JSX-deklarasjoner for de egendefinerte elementene.
3385
+ - **`fristil`-kommandoen** som bygger et tema fra egne farger, sjekker
3386
+ kontrasten mot WCAG og skriver ut CSS-en.
3387
+ - **Tilpasning utenfra**: all CSS ligger i `@layer fristil`, form og størrelse
3388
+ leses fra `--fs-*`-variabler med tokenverdien som reserve, og komponenten med
3389
+ shadow DOM eksponerer delene sine med `::part()`.