@fristil/designsystem 0.2.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 (314) hide show
  1. package/CHANGELOG.md +85 -0
  2. package/LICENSE +21 -0
  3. package/README.md +101 -0
  4. package/dist/cli.d.ts +31 -0
  5. package/dist/cli.d.ts.map +1 -0
  6. package/dist/cli.js +261 -0
  7. package/dist/cli.js.map +1 -0
  8. package/dist/components/css/accordion/accordion.d.ts +37 -0
  9. package/dist/components/css/accordion/accordion.d.ts.map +1 -0
  10. package/dist/components/css/accordion/accordion.js +31 -0
  11. package/dist/components/css/accordion/accordion.js.map +1 -0
  12. package/dist/components/css/alert/alert.d.ts +35 -0
  13. package/dist/components/css/alert/alert.d.ts.map +1 -0
  14. package/dist/components/css/alert/alert.js +29 -0
  15. package/dist/components/css/alert/alert.js.map +1 -0
  16. package/dist/components/css/avatar/avatar.d.ts +40 -0
  17. package/dist/components/css/avatar/avatar.d.ts.map +1 -0
  18. package/dist/components/css/avatar/avatar.js +30 -0
  19. package/dist/components/css/avatar/avatar.js.map +1 -0
  20. package/dist/components/css/badge/badge.d.ts +24 -0
  21. package/dist/components/css/badge/badge.d.ts.map +1 -0
  22. package/dist/components/css/badge/badge.js +24 -0
  23. package/dist/components/css/badge/badge.js.map +1 -0
  24. package/dist/components/css/breadcrumbs/breadcrumbs.d.ts +25 -0
  25. package/dist/components/css/breadcrumbs/breadcrumbs.d.ts.map +1 -0
  26. package/dist/components/css/breadcrumbs/breadcrumbs.js +23 -0
  27. package/dist/components/css/breadcrumbs/breadcrumbs.js.map +1 -0
  28. package/dist/components/css/button/button.d.ts +26 -0
  29. package/dist/components/css/button/button.d.ts.map +1 -0
  30. package/dist/components/css/button/button.js +25 -0
  31. package/dist/components/css/button/button.js.map +1 -0
  32. package/dist/components/css/card/card.d.ts +36 -0
  33. package/dist/components/css/card/card.d.ts.map +1 -0
  34. package/dist/components/css/card/card.js +28 -0
  35. package/dist/components/css/card/card.js.map +1 -0
  36. package/dist/components/css/checkbox/checkbox.d.ts +32 -0
  37. package/dist/components/css/checkbox/checkbox.d.ts.map +1 -0
  38. package/dist/components/css/checkbox/checkbox.js +27 -0
  39. package/dist/components/css/checkbox/checkbox.js.map +1 -0
  40. package/dist/components/css/dialog/dialog.d.ts +30 -0
  41. package/dist/components/css/dialog/dialog.d.ts.map +1 -0
  42. package/dist/components/css/dialog/dialog.js +28 -0
  43. package/dist/components/css/dialog/dialog.js.map +1 -0
  44. package/dist/components/css/divider/divider.d.ts +28 -0
  45. package/dist/components/css/divider/divider.d.ts.map +1 -0
  46. package/dist/components/css/divider/divider.js +22 -0
  47. package/dist/components/css/divider/divider.js.map +1 -0
  48. package/dist/components/css/error-text/error-text.d.ts +24 -0
  49. package/dist/components/css/error-text/error-text.d.ts.map +1 -0
  50. package/dist/components/css/error-text/error-text.js +18 -0
  51. package/dist/components/css/error-text/error-text.js.map +1 -0
  52. package/dist/components/css/fieldset/fieldset.d.ts +55 -0
  53. package/dist/components/css/fieldset/fieldset.d.ts.map +1 -0
  54. package/dist/components/css/fieldset/fieldset.js +39 -0
  55. package/dist/components/css/fieldset/fieldset.js.map +1 -0
  56. package/dist/components/css/file-upload/file-upload.d.ts +41 -0
  57. package/dist/components/css/file-upload/file-upload.d.ts.map +1 -0
  58. package/dist/components/css/file-upload/file-upload.js +32 -0
  59. package/dist/components/css/file-upload/file-upload.js.map +1 -0
  60. package/dist/components/css/heading/heading.d.ts +29 -0
  61. package/dist/components/css/heading/heading.d.ts.map +1 -0
  62. package/dist/components/css/heading/heading.js +23 -0
  63. package/dist/components/css/heading/heading.js.map +1 -0
  64. package/dist/components/css/help-text/help-text.d.ts +24 -0
  65. package/dist/components/css/help-text/help-text.d.ts.map +1 -0
  66. package/dist/components/css/help-text/help-text.js +23 -0
  67. package/dist/components/css/help-text/help-text.js.map +1 -0
  68. package/dist/components/css/input/input.d.ts +39 -0
  69. package/dist/components/css/input/input.d.ts.map +1 -0
  70. package/dist/components/css/input/input.js +44 -0
  71. package/dist/components/css/input/input.js.map +1 -0
  72. package/dist/components/css/label/label.d.ts +33 -0
  73. package/dist/components/css/label/label.d.ts.map +1 -0
  74. package/dist/components/css/label/label.js +23 -0
  75. package/dist/components/css/label/label.js.map +1 -0
  76. package/dist/components/css/link/link.d.ts +21 -0
  77. package/dist/components/css/link/link.d.ts.map +1 -0
  78. package/dist/components/css/link/link.js +14 -0
  79. package/dist/components/css/link/link.js.map +1 -0
  80. package/dist/components/css/list/list.d.ts +29 -0
  81. package/dist/components/css/list/list.d.ts.map +1 -0
  82. package/dist/components/css/list/list.js +23 -0
  83. package/dist/components/css/list/list.js.map +1 -0
  84. package/dist/components/css/pagination/pagination.d.ts +27 -0
  85. package/dist/components/css/pagination/pagination.d.ts.map +1 -0
  86. package/dist/components/css/pagination/pagination.js +25 -0
  87. package/dist/components/css/pagination/pagination.js.map +1 -0
  88. package/dist/components/css/paragraph/paragraph.d.ts +36 -0
  89. package/dist/components/css/paragraph/paragraph.d.ts.map +1 -0
  90. package/dist/components/css/paragraph/paragraph.js +26 -0
  91. package/dist/components/css/paragraph/paragraph.js.map +1 -0
  92. package/dist/components/css/radio/radio.d.ts +32 -0
  93. package/dist/components/css/radio/radio.d.ts.map +1 -0
  94. package/dist/components/css/radio/radio.js +27 -0
  95. package/dist/components/css/radio/radio.js.map +1 -0
  96. package/dist/components/css/search/search.d.ts +33 -0
  97. package/dist/components/css/search/search.d.ts.map +1 -0
  98. package/dist/components/css/search/search.js +31 -0
  99. package/dist/components/css/search/search.js.map +1 -0
  100. package/dist/components/css/select/select.d.ts +23 -0
  101. package/dist/components/css/select/select.d.ts.map +1 -0
  102. package/dist/components/css/select/select.js +18 -0
  103. package/dist/components/css/select/select.js.map +1 -0
  104. package/dist/components/css/shared.d.ts +26 -0
  105. package/dist/components/css/shared.d.ts.map +1 -0
  106. package/dist/components/css/shared.js +34 -0
  107. package/dist/components/css/shared.js.map +1 -0
  108. package/dist/components/css/skeleton/skeleton.d.ts +29 -0
  109. package/dist/components/css/skeleton/skeleton.d.ts.map +1 -0
  110. package/dist/components/css/skeleton/skeleton.js +23 -0
  111. package/dist/components/css/skeleton/skeleton.js.map +1 -0
  112. package/dist/components/css/skip-link/skip-link.d.ts +18 -0
  113. package/dist/components/css/skip-link/skip-link.d.ts.map +1 -0
  114. package/dist/components/css/skip-link/skip-link.js +16 -0
  115. package/dist/components/css/skip-link/skip-link.js.map +1 -0
  116. package/dist/components/css/spinner/spinner.d.ts +33 -0
  117. package/dist/components/css/spinner/spinner.d.ts.map +1 -0
  118. package/dist/components/css/spinner/spinner.js +25 -0
  119. package/dist/components/css/spinner/spinner.js.map +1 -0
  120. package/dist/components/css/sr-only/sr-only.d.ts +17 -0
  121. package/dist/components/css/sr-only/sr-only.d.ts.map +1 -0
  122. package/dist/components/css/sr-only/sr-only.js +14 -0
  123. package/dist/components/css/sr-only/sr-only.js.map +1 -0
  124. package/dist/components/css/switch/switch.d.ts +33 -0
  125. package/dist/components/css/switch/switch.d.ts.map +1 -0
  126. package/dist/components/css/switch/switch.js +29 -0
  127. package/dist/components/css/switch/switch.js.map +1 -0
  128. package/dist/components/css/table/table.d.ts +36 -0
  129. package/dist/components/css/table/table.d.ts.map +1 -0
  130. package/dist/components/css/table/table.js +28 -0
  131. package/dist/components/css/table/table.js.map +1 -0
  132. package/dist/components/css/tag/tag.d.ts +35 -0
  133. package/dist/components/css/tag/tag.d.ts.map +1 -0
  134. package/dist/components/css/tag/tag.js +27 -0
  135. package/dist/components/css/tag/tag.js.map +1 -0
  136. package/dist/components/css/textarea/textarea.d.ts +23 -0
  137. package/dist/components/css/textarea/textarea.d.ts.map +1 -0
  138. package/dist/components/css/textarea/textarea.js +18 -0
  139. package/dist/components/css/textarea/textarea.js.map +1 -0
  140. package/dist/components/css/toggle-group/toggle-group.d.ts +31 -0
  141. package/dist/components/css/toggle-group/toggle-group.d.ts.map +1 -0
  142. package/dist/components/css/toggle-group/toggle-group.js +29 -0
  143. package/dist/components/css/toggle-group/toggle-group.js.map +1 -0
  144. package/dist/components/css/tooltip/tooltip.d.ts +30 -0
  145. package/dist/components/css/tooltip/tooltip.d.ts.map +1 -0
  146. package/dist/components/css/tooltip/tooltip.js +28 -0
  147. package/dist/components/css/tooltip/tooltip.js.map +1 -0
  148. package/dist/components/frittstaende/calendar/fs-calendar.d.ts +52 -0
  149. package/dist/components/frittstaende/calendar/fs-calendar.d.ts.map +1 -0
  150. package/dist/components/frittstaende/calendar/fs-calendar.js +462 -0
  151. package/dist/components/frittstaende/calendar/fs-calendar.js.map +1 -0
  152. package/dist/components/frittstaende/date-field/fs-date-field.d.ts +110 -0
  153. package/dist/components/frittstaende/date-field/fs-date-field.d.ts.map +1 -0
  154. package/dist/components/frittstaende/date-field/fs-date-field.js +264 -0
  155. package/dist/components/frittstaende/date-field/fs-date-field.js.map +1 -0
  156. package/dist/components/frittstaende/suggestion/fs-suggestion.d.ts +133 -0
  157. package/dist/components/frittstaende/suggestion/fs-suggestion.d.ts.map +1 -0
  158. package/dist/components/frittstaende/suggestion/fs-suggestion.js +280 -0
  159. package/dist/components/frittstaende/suggestion/fs-suggestion.js.map +1 -0
  160. package/dist/components/frittstaende/toast/fs-toast.d.ts +67 -0
  161. package/dist/components/frittstaende/toast/fs-toast.d.ts.map +1 -0
  162. package/dist/components/frittstaende/toast/fs-toast.js +108 -0
  163. package/dist/components/frittstaende/toast/fs-toast.js.map +1 -0
  164. package/dist/components/ramme/error-summary/fs-error-summary.d.ts +70 -0
  165. package/dist/components/ramme/error-summary/fs-error-summary.d.ts.map +1 -0
  166. package/dist/components/ramme/error-summary/fs-error-summary.js +155 -0
  167. package/dist/components/ramme/error-summary/fs-error-summary.js.map +1 -0
  168. package/dist/components/ramme/field/field-core.d.ts +70 -0
  169. package/dist/components/ramme/field/field-core.d.ts.map +1 -0
  170. package/dist/components/ramme/field/field-core.js +60 -0
  171. package/dist/components/ramme/field/field-core.js.map +1 -0
  172. package/dist/components/ramme/field/fs-field.d.ts +49 -0
  173. package/dist/components/ramme/field/fs-field.d.ts.map +1 -0
  174. package/dist/components/ramme/field/fs-field.js +118 -0
  175. package/dist/components/ramme/field/fs-field.js.map +1 -0
  176. package/dist/components/ramme/popover/fs-popover.d.ts +68 -0
  177. package/dist/components/ramme/popover/fs-popover.d.ts.map +1 -0
  178. package/dist/components/ramme/popover/fs-popover.js +167 -0
  179. package/dist/components/ramme/popover/fs-popover.js.map +1 -0
  180. package/dist/components/ramme/tabs/fs-tabs.d.ts +61 -0
  181. package/dist/components/ramme/tabs/fs-tabs.d.ts.map +1 -0
  182. package/dist/components/ramme/tabs/fs-tabs.js +156 -0
  183. package/dist/components/ramme/tabs/fs-tabs.js.map +1 -0
  184. package/dist/dom.d.ts +33 -0
  185. package/dist/dom.d.ts.map +1 -0
  186. package/dist/dom.js +77 -0
  187. package/dist/dom.js.map +1 -0
  188. package/dist/fs.d.ts +199 -0
  189. package/dist/fs.d.ts.map +1 -0
  190. package/dist/fs.js +128 -0
  191. package/dist/fs.js.map +1 -0
  192. package/dist/index.d.ts +84 -0
  193. package/dist/index.d.ts.map +1 -0
  194. package/dist/index.js +48 -0
  195. package/dist/index.js.map +1 -0
  196. package/dist/jsx/react.d.ts +127 -0
  197. package/dist/jsx/react.d.ts.map +1 -0
  198. package/dist/jsx/react.js +2 -0
  199. package/dist/jsx/react.js.map +1 -0
  200. package/dist/react.d.ts +207 -0
  201. package/dist/react.d.ts.map +1 -0
  202. package/dist/react.js +109 -0
  203. package/dist/react.js.map +1 -0
  204. package/dist/tailwind/preset.d.ts +120 -0
  205. package/dist/tailwind/preset.d.ts.map +1 -0
  206. package/dist/tailwind/preset.js +107 -0
  207. package/dist/tailwind/preset.js.map +1 -0
  208. package/dist/takeover.d.ts +79 -0
  209. package/dist/takeover.d.ts.map +1 -0
  210. package/dist/takeover.js +119 -0
  211. package/dist/takeover.js.map +1 -0
  212. package/dist/tokens/color.d.ts +85 -0
  213. package/dist/tokens/color.d.ts.map +1 -0
  214. package/dist/tokens/color.js +212 -0
  215. package/dist/tokens/color.js.map +1 -0
  216. package/dist/tokens/theme.d.ts +52 -0
  217. package/dist/tokens/theme.d.ts.map +1 -0
  218. package/dist/tokens/theme.js +197 -0
  219. package/dist/tokens/theme.js.map +1 -0
  220. package/dist/tokens/tokens.d.ts +210 -0
  221. package/dist/tokens/tokens.d.ts.map +1 -0
  222. package/dist/tokens/tokens.js +238 -0
  223. package/dist/tokens/tokens.js.map +1 -0
  224. package/package.json +334 -0
  225. package/src/components/css/accordion/accordion.css +74 -0
  226. package/src/components/css/accordion/accordion.ts +50 -0
  227. package/src/components/css/alert/alert.css +50 -0
  228. package/src/components/css/alert/alert.ts +48 -0
  229. package/src/components/css/avatar/avatar.css +64 -0
  230. package/src/components/css/avatar/avatar.ts +57 -0
  231. package/src/components/css/badge/badge.css +42 -0
  232. package/src/components/css/badge/badge.ts +43 -0
  233. package/src/components/css/breadcrumbs/breadcrumbs.css +50 -0
  234. package/src/components/css/breadcrumbs/breadcrumbs.ts +29 -0
  235. package/src/components/css/button/button.css +101 -0
  236. package/src/components/css/button/button.ts +44 -0
  237. package/src/components/css/card/card.css +48 -0
  238. package/src/components/css/card/card.ts +50 -0
  239. package/src/components/css/checkbox/checkbox.css +96 -0
  240. package/src/components/css/checkbox/checkbox.ts +50 -0
  241. package/src/components/css/dialog/dialog.css +50 -0
  242. package/src/components/css/dialog/dialog.ts +36 -0
  243. package/src/components/css/divider/divider.css +18 -0
  244. package/src/components/css/divider/divider.ts +41 -0
  245. package/src/components/css/error-text/error-text.css +21 -0
  246. package/src/components/css/error-text/error-text.ts +37 -0
  247. package/src/components/css/fieldset/fieldset.css +57 -0
  248. package/src/components/css/fieldset/fieldset.ts +87 -0
  249. package/src/components/css/file-upload/file-upload.css +92 -0
  250. package/src/components/css/file-upload/file-upload.ts +65 -0
  251. package/src/components/css/heading/heading.css +33 -0
  252. package/src/components/css/heading/heading.ts +42 -0
  253. package/src/components/css/help-text/help-text.css +24 -0
  254. package/src/components/css/help-text/help-text.ts +42 -0
  255. package/src/components/css/input/input.css +131 -0
  256. package/src/components/css/input/input.ts +76 -0
  257. package/src/components/css/label/label.css +34 -0
  258. package/src/components/css/label/label.ts +51 -0
  259. package/src/components/css/link/link.css +36 -0
  260. package/src/components/css/link/link.ts +29 -0
  261. package/src/components/css/list/list.css +40 -0
  262. package/src/components/css/list/list.ts +42 -0
  263. package/src/components/css/pagination/pagination.css +77 -0
  264. package/src/components/css/pagination/pagination.ts +33 -0
  265. package/src/components/css/paragraph/paragraph.css +31 -0
  266. package/src/components/css/paragraph/paragraph.ts +53 -0
  267. package/src/components/css/radio/radio.css +76 -0
  268. package/src/components/css/radio/radio.ts +50 -0
  269. package/src/components/css/search/search.css +49 -0
  270. package/src/components/css/search/search.ts +52 -0
  271. package/src/components/css/select/select.css +95 -0
  272. package/src/components/css/select/select.ts +40 -0
  273. package/src/components/css/shared.ts +40 -0
  274. package/src/components/css/skeleton/skeleton.css +49 -0
  275. package/src/components/css/skeleton/skeleton.ts +43 -0
  276. package/src/components/css/skip-link/skip-link.css +36 -0
  277. package/src/components/css/skip-link/skip-link.ts +22 -0
  278. package/src/components/css/spinner/spinner.css +48 -0
  279. package/src/components/css/spinner/spinner.ts +48 -0
  280. package/src/components/css/sr-only/sr-only.css +16 -0
  281. package/src/components/css/sr-only/sr-only.ts +18 -0
  282. package/src/components/css/switch/switch.css +101 -0
  283. package/src/components/css/switch/switch.ts +46 -0
  284. package/src/components/css/table/table.css +63 -0
  285. package/src/components/css/table/table.ts +50 -0
  286. package/src/components/css/tag/tag.css +58 -0
  287. package/src/components/css/tag/tag.ts +49 -0
  288. package/src/components/css/textarea/textarea.css +71 -0
  289. package/src/components/css/textarea/textarea.ts +40 -0
  290. package/src/components/css/toggle-group/toggle-group.css +82 -0
  291. package/src/components/css/toggle-group/toggle-group.ts +37 -0
  292. package/src/components/css/tooltip/tooltip.css +47 -0
  293. package/src/components/css/tooltip/tooltip.ts +36 -0
  294. package/src/components/frittstaende/calendar/fs-calendar.ts +525 -0
  295. package/src/components/frittstaende/date-field/date-field.css +54 -0
  296. package/src/components/frittstaende/date-field/fs-date-field.ts +309 -0
  297. package/src/components/frittstaende/suggestion/fs-suggestion.ts +333 -0
  298. package/src/components/frittstaende/suggestion/suggestion.css +63 -0
  299. package/src/components/frittstaende/toast/fs-toast.ts +146 -0
  300. package/src/components/frittstaende/toast/toast.css +71 -0
  301. package/src/components/ramme/error-summary/error-summary.css +45 -0
  302. package/src/components/ramme/error-summary/fs-error-summary.ts +197 -0
  303. package/src/components/ramme/field/field-core.ts +132 -0
  304. package/src/components/ramme/field/field.css +6 -0
  305. package/src/components/ramme/field/fs-field.ts +154 -0
  306. package/src/components/ramme/popover/fs-popover.ts +205 -0
  307. package/src/components/ramme/popover/popover.css +34 -0
  308. package/src/components/ramme/tabs/fs-tabs.ts +182 -0
  309. package/src/components/ramme/tabs/tabs.css +68 -0
  310. package/src/tailwind/tailwind.css +134 -0
  311. package/src/tokens/color.ts +267 -0
  312. package/src/tokens/theme.ts +350 -0
  313. package/src/tokens/tokens.css +214 -0
  314. package/src/tokens/tokens.ts +293 -0
@@ -0,0 +1,96 @@
1
+ @layer fristil {
2
+ .fs-checkbox {
3
+ /* Designsystemet kan ikke regne med at konsumenten har en CSS-reset. */
4
+ box-sizing: border-box;
5
+
6
+ appearance: none;
7
+ flex: none;
8
+ display: inline-block;
9
+ inline-size: var(--fs-checkbox-size, var(--size-5));
10
+ block-size: var(--fs-checkbox-size, var(--size-5));
11
+ margin: 0;
12
+ background-color: var(--semantic-page-background);
13
+ background-position: center;
14
+ background-repeat: no-repeat;
15
+ background-size: 80%;
16
+ border: 1px solid var(--semantic-field-border);
17
+ border-radius: var(--fs-checkbox-radius, var(--size-1));
18
+ cursor: pointer;
19
+ }
20
+
21
+ .fs-checkbox:hover:not(:disabled) {
22
+ border-color: var(--semantic-field-border-hover);
23
+ }
24
+
25
+ .fs-checkbox:focus-visible {
26
+ outline: 2px solid var(--semantic-interactive-main);
27
+ outline-offset: 2px;
28
+ }
29
+
30
+ .fs-checkbox:checked,
31
+ .fs-checkbox:indeterminate {
32
+ background-color: var(--semantic-interactive-main);
33
+ border-color: var(--semantic-interactive-main);
34
+ }
35
+
36
+ /* Haken er et token og ikke et bilde i denne fila, fordi en data-URL ikke
37
+ kan lese en CSS-variabel. Streken er malt inn i bildet, og må derfor snu
38
+ med temaet der de andre fargene snur. */
39
+ .fs-checkbox:checked {
40
+ background-image: var(--semantic-icon-check);
41
+ }
42
+
43
+ .fs-checkbox:indeterminate {
44
+ background-image: var(--semantic-icon-dash);
45
+ }
46
+
47
+ .fs-checkbox:disabled {
48
+ background-color: var(--semantic-disabled-background);
49
+ border-color: var(--semantic-disabled-background);
50
+ cursor: not-allowed;
51
+ }
52
+
53
+ .fs-checkbox:disabled:checked,
54
+ .fs-checkbox:disabled:indeterminate {
55
+ background-color: var(--semantic-disabled-foreground);
56
+ border-color: var(--semantic-disabled-foreground);
57
+ }
58
+
59
+ .fs-checkbox[data-state="invalid"] {
60
+ border-color: var(--semantic-danger-foreground);
61
+ }
62
+
63
+ .fs-checkbox[data-state="invalid"]:focus-visible {
64
+ outline-color: var(--semantic-danger-foreground);
65
+ }
66
+
67
+ .fs-checkbox[data-state="success"] {
68
+ border-color: var(--semantic-success-foreground);
69
+ }
70
+
71
+ /* Boksen og teksten på én linje, med teksten på plass ved flere linjer. */
72
+ .fs-checkbox-row {
73
+ display: flex;
74
+ align-items: flex-start;
75
+ gap: var(--size-2);
76
+ line-height: 1.5;
77
+ }
78
+
79
+ /*
80
+ * Høykontrast: la nettleseren tegne boksen selv.
81
+ *
82
+ * Målt i modusen: gradienter og box-shadow fjernes, egne farger overstyres,
83
+ * og bare systemfarger, rammer, masker og data-URL-bilder overlever. Haken
84
+ * vår er hvit og malt inn i bildet, så den ville blitt usynlig mot den
85
+ * påtvungne flaten. Nettleserens egen avkryssingsboks er riktig i alle
86
+ * temaer brukeren kan velge, og koster oss ingenting å falle tilbake på.
87
+ */
88
+ @media (forced-colors: active) {
89
+ .fs-checkbox,
90
+ .fs-checkbox:checked,
91
+ .fs-checkbox:indeterminate {
92
+ appearance: auto;
93
+ background-image: none;
94
+ }
95
+ }
96
+ }
@@ -0,0 +1,50 @@
1
+ import {
2
+ attributes,
3
+ type FieldState,
4
+ fieldStates,
5
+ isFieldState,
6
+ type NonDefaultFieldState,
7
+ } from "../shared.js"
8
+
9
+ export const CHECKBOX_CLASS = "fs-checkbox" as const
10
+ /** Raden som holder boksen og teksten ved siden av hverandre. */
11
+ export const CHECKBOX_ROW_CLASS = "fs-checkbox-row" as const
12
+
13
+ export type CheckboxOptions = {
14
+ /** Valideringstilstand. Standard: `default`. */
15
+ state?: FieldState
16
+ }
17
+
18
+ export type CheckboxAttributes = {
19
+ class: typeof CHECKBOX_CLASS
20
+ type: "checkbox"
21
+ "data-state"?: NonDefaultFieldState
22
+ "aria-invalid"?: "true"
23
+ }
24
+
25
+ /**
26
+ * Attributtene for en avkryssingsboks.
27
+ *
28
+ * `type` settes her, slik at boksen ikke kan bli et tekstfelt med en boks sin
29
+ * stil. Delvis avkrysset settes med `element.indeterminate = true` i
30
+ * JavaScript, ikke som et attributt, fordi HTML ikke har noe slikt attributt.
31
+ *
32
+ * ```ts
33
+ * <input {...checkbox({ state: "invalid" })} />
34
+ * ```
35
+ */
36
+ export const checkbox = Object.assign(
37
+ ({ state = "default" }: CheckboxOptions = {}): CheckboxAttributes =>
38
+ attributes({
39
+ class: CHECKBOX_CLASS,
40
+ type: "checkbox" as const,
41
+ "data-state": state === "default" ? undefined : state,
42
+ "aria-invalid": state === "invalid" ? ("true" as const) : undefined,
43
+ }),
44
+ {
45
+ /** Klassen på raden rundt boksen og teksten. */
46
+ row: CHECKBOX_ROW_CLASS,
47
+ states: fieldStates,
48
+ isState: isFieldState,
49
+ },
50
+ )
@@ -0,0 +1,50 @@
1
+ @layer fristil {
2
+ .fs-dialog {
3
+ box-sizing: border-box;
4
+ /*
5
+ * `100%` og ikke bare `100vw`: en ekte dialog i topplaget måler seg mot
6
+ * vindusruten, men står den i en smalere boks, som i dokumentasjonen,
7
+ * stakk den utenfor. `min()` tar den minste av de tre.
8
+ */
9
+ inline-size: var(
10
+ --fs-dialog-width,
11
+ min(32rem, 100%, calc(100vw - var(--size-8)))
12
+ );
13
+ max-block-size: calc(100vh - var(--size-16));
14
+ padding: var(--fs-dialog-padding, var(--size-5));
15
+ font-family: inherit;
16
+ font-size: var(--font-size-m);
17
+ line-height: 1.5;
18
+ color: var(--semantic-page-foreground);
19
+ background: var(--semantic-page-background);
20
+ border: 1px solid var(--semantic-divider-30);
21
+ border-radius: var(--fs-dialog-radius, var(--size-2));
22
+ box-shadow: var(--semantic-shadow-overlay);
23
+ }
24
+
25
+ /* Flaten bak dialogen. Den finnes bare når dialogen er åpnet med
26
+ showModal(); et vanlig show() gir ingen ::backdrop. */
27
+ .fs-dialog::backdrop {
28
+ background: var(--semantic-overlay-backdrop);
29
+ }
30
+
31
+ .fs-dialog__title {
32
+ margin: 0 0 var(--size-2);
33
+ font-size: var(--font-size-l);
34
+ font-weight: 600;
35
+ line-height: 1.4;
36
+ }
37
+
38
+ .fs-dialog__body {
39
+ margin: 0;
40
+ overflow-y: auto;
41
+ }
42
+
43
+ .fs-dialog__footer {
44
+ display: flex;
45
+ flex-wrap: wrap;
46
+ justify-content: flex-end;
47
+ gap: var(--size-2);
48
+ margin-block-start: var(--size-5);
49
+ }
50
+ }
@@ -0,0 +1,36 @@
1
+ import { attributes } from "../shared.js"
2
+
3
+ export const DIALOG_CLASS = "fs-dialog" as const
4
+ export const DIALOG_TITLE_CLASS = "fs-dialog__title" as const
5
+ export const DIALOG_BODY_CLASS = "fs-dialog__body" as const
6
+ export const DIALOG_FOOTER_CLASS = "fs-dialog__footer" as const
7
+
8
+ export type DialogAttributes = {
9
+ class: typeof DIALOG_CLASS
10
+ }
11
+
12
+ /**
13
+ * Attributtene for en dialog.
14
+ *
15
+ * Klassen hører på et `<dialog>`. Åpne den med `showModal()`, ikke ved å
16
+ * sette `open`: bare den første flytter fokus inn, holder fokus inne i
17
+ * dialogen, lukker på Escape og gjør resten av siden utilgjengelig. Et
18
+ * `<dialog open>` i markupen er en boks på siden, ikke en dialog.
19
+ *
20
+ * ```ts
21
+ * <dialog {...dialog()} aria-labelledby="tittel">
22
+ * <h2 {...{ class: dialog.title }} id="tittel">Slette søknaden?</h2>
23
+ * </dialog>
24
+ * ```
25
+ */
26
+ export const dialog = Object.assign(
27
+ (): DialogAttributes => attributes({ class: DIALOG_CLASS }),
28
+ {
29
+ /** Klassen på overskriften i dialogen. */
30
+ title: DIALOG_TITLE_CLASS,
31
+ /** Klassen på innholdet, som ruller når dialogen blir for høy. */
32
+ body: DIALOG_BODY_CLASS,
33
+ /** Klassen på raden med knapper nederst. */
34
+ footer: DIALOG_FOOTER_CLASS,
35
+ },
36
+ )
@@ -0,0 +1,18 @@
1
+ @layer fristil {
2
+ .fs-divider {
3
+ /* <hr> har både ramme og høyde fra nettleseren. Begge må bort før
4
+ fargen under er den eneste som vises. */
5
+ border: 0;
6
+ block-size: 1px;
7
+ margin-block: var(--fs-divider-space, var(--size-4));
8
+ background: var(--semantic-divider-30);
9
+ }
10
+
11
+ .fs-divider[data-variant="strong"] {
12
+ background: var(--semantic-divider-100);
13
+ }
14
+
15
+ .fs-divider[data-variant="subtle"] {
16
+ background: var(--semantic-neutral-background);
17
+ }
18
+ }
@@ -0,0 +1,41 @@
1
+ import { attributes, createGuard } from "../shared.js"
2
+
3
+ export const DIVIDER_CLASS = "fs-divider" as const
4
+
5
+ export const dividerVariants = ["default", "subtle", "strong"] as const
6
+
7
+ export type DividerVariant = (typeof dividerVariants)[number]
8
+ export type NonDefaultDividerVariant = Exclude<DividerVariant, "default">
9
+
10
+ export type DividerOptions = {
11
+ /** Hvor tydelig streken er. Standard: `default`. */
12
+ variant?: DividerVariant
13
+ }
14
+
15
+ export type DividerAttributes = {
16
+ class: typeof DIVIDER_CLASS
17
+ "data-variant"?: NonDefaultDividerVariant
18
+ }
19
+
20
+ /**
21
+ * Attributtene for en skillelinje.
22
+ *
23
+ * Klassen hører på et `<hr>`. Skiller streken to deler av innholdet, er den
24
+ * en opplysning skjermlesere skal få. Er den bare pynt mellom to bokser som
25
+ * allerede er atskilt, sett `aria-hidden="true"` på den.
26
+ *
27
+ * ```ts
28
+ * <hr {...divider({ variant: "subtle" })} />
29
+ * ```
30
+ */
31
+ export const divider = Object.assign(
32
+ ({ variant = "default" }: DividerOptions = {}): DividerAttributes =>
33
+ attributes({
34
+ class: DIVIDER_CLASS,
35
+ "data-variant": variant === "default" ? undefined : variant,
36
+ }),
37
+ {
38
+ variants: dividerVariants,
39
+ isVariant: createGuard(dividerVariants),
40
+ },
41
+ )
@@ -0,0 +1,21 @@
1
+ @layer fristil {
2
+ .fs-error-text {
3
+ display: block;
4
+ /* Hele margin settes, ikke bare toppen: uten dette arver <p>
5
+ nettleserens 1em i bunn hos konsumenter uten reset. */
6
+ margin: var(--size-1) 0 0;
7
+ font-family: inherit;
8
+ font-size: var(--font-size-xs);
9
+ font-weight: 500;
10
+ line-height: 1.4;
11
+ color: var(--semantic-danger-foreground);
12
+ }
13
+
14
+ .fs-error-text[hidden] {
15
+ display: none;
16
+ }
17
+
18
+ .fs-error-text[data-variant="warning"] {
19
+ color: var(--semantic-warning-foreground);
20
+ }
21
+ }
@@ -0,0 +1,37 @@
1
+ import { attributes, createGuard } from "../shared.js"
2
+
3
+ export const ERROR_TEXT_CLASS = "fs-error-text" as const
4
+
5
+ export const errorTextVariants = ["error", "warning"] as const
6
+
7
+ export type ErrorTextVariant = (typeof errorTextVariants)[number]
8
+ export type NonDefaultErrorTextVariant = Exclude<ErrorTextVariant, "error">
9
+
10
+ export type ErrorTextOptions = {
11
+ /** Om feilen stopper innsending eller bare advarer. Standard: `error`. */
12
+ variant?: ErrorTextVariant
13
+ }
14
+
15
+ export type ErrorTextAttributes = {
16
+ class: typeof ERROR_TEXT_CLASS
17
+ "data-variant"?: NonDefaultErrorTextVariant
18
+ }
19
+
20
+ /**
21
+ * Attributtene for en feilmelding under et felt.
22
+ *
23
+ * ```ts
24
+ * <p {...errorText({ variant: "warning" })}>…</p>
25
+ * ```
26
+ */
27
+ export const errorText = Object.assign(
28
+ ({ variant = "error" }: ErrorTextOptions = {}): ErrorTextAttributes =>
29
+ attributes({
30
+ class: ERROR_TEXT_CLASS,
31
+ "data-variant": variant === "error" ? undefined : variant,
32
+ }),
33
+ {
34
+ variants: errorTextVariants,
35
+ isVariant: createGuard(errorTextVariants),
36
+ },
37
+ )
@@ -0,0 +1,57 @@
1
+ @import "../label/label.css";
2
+
3
+ @layer fristil {
4
+ .fs-fieldset {
5
+ box-sizing: border-box;
6
+ display: flex;
7
+ flex-direction: column;
8
+ gap: var(--fs-fieldset-gap, var(--size-2));
9
+ margin: 0;
10
+ padding: 0;
11
+ /* Nettleserens egen ramme og innrykk på <fieldset> hører til et utseende
12
+ fra 1996, og kan ikke slås av med mindre begge nullstilles her. */
13
+ border: 0;
14
+ min-inline-size: 0;
15
+ }
16
+
17
+ .fs-legend {
18
+ padding: 0;
19
+ margin-block-end: var(--size-1);
20
+ font-family: inherit;
21
+ font-size: var(--font-size-m);
22
+ font-weight: 600;
23
+ line-height: 1.5;
24
+ color: var(--semantic-page-foreground);
25
+ }
26
+
27
+ /* Samme markering som på en ledetekst. Reglene står her og ikke i
28
+ label.css, fordi <legend> er et annet element med egne standardverdier. */
29
+ .fs-legend[data-required]::after {
30
+ content: " *";
31
+ color: var(--semantic-danger-foreground);
32
+ font-weight: 700;
33
+ }
34
+
35
+ .fs-legend[data-required="text"]::after {
36
+ content: " (påkrevd)";
37
+ color: var(--semantic-danger-foreground);
38
+ font-weight: 400;
39
+ font-size: var(--font-size-xs);
40
+ }
41
+
42
+ .fs-legend[data-optional]::after {
43
+ content: " (valgfri)";
44
+ color: var(--semantic-disabled-foreground);
45
+ font-weight: 400;
46
+ font-size: var(--font-size-xs);
47
+ }
48
+
49
+ .fs-fieldset[data-state="invalid"] .fs-legend {
50
+ color: var(--semantic-danger-foreground);
51
+ }
52
+
53
+ .fs-fieldset:disabled .fs-legend,
54
+ .fs-legend[aria-disabled="true"] {
55
+ color: var(--semantic-muted-foreground);
56
+ }
57
+ }
@@ -0,0 +1,87 @@
1
+ import {
2
+ attributes,
3
+ createGuard,
4
+ type FieldState,
5
+ fieldStates,
6
+ isFieldState,
7
+ type NonDefaultFieldState,
8
+ type RequiredMarker,
9
+ requiredMarkers,
10
+ } from "../shared.js"
11
+
12
+ export const FIELDSET_CLASS = "fs-fieldset" as const
13
+ export const LEGEND_CLASS = "fs-legend" as const
14
+
15
+ export type FieldsetOptions = {
16
+ /** Valideringstilstand for hele gruppen. Standard: `default`. */
17
+ state?: FieldState
18
+ /** Slår av alle kontrollene i gruppen. */
19
+ disabled?: boolean
20
+ }
21
+
22
+ export type FieldsetAttributes = {
23
+ class: typeof FIELDSET_CLASS
24
+ "data-state"?: NonDefaultFieldState
25
+ disabled?: true
26
+ }
27
+
28
+ export type LegendOptions = {
29
+ /** Marker gruppen som påkrevd, med stjerne eller med ordet «(påkrevd)». */
30
+ required?: RequiredMarker
31
+ /** Marker gruppen som valgfri. Velg én av `required` og `optional`. */
32
+ optional?: boolean
33
+ /** Demper teksten når gruppen er slått av. */
34
+ disabled?: boolean
35
+ }
36
+
37
+ export type LegendAttributes = {
38
+ class: typeof LEGEND_CLASS
39
+ "data-required"?: RequiredMarker
40
+ "data-optional"?: ""
41
+ "aria-disabled"?: "true"
42
+ }
43
+
44
+ /**
45
+ * Attributtene for en gruppe med kontroller som hører sammen.
46
+ *
47
+ * `<fieldset>` med `<legend>` er den ene måten å gi et sett radioknapper eller
48
+ * avkryssingsbokser en felles ledetekst som skjermlesere faktisk leser opp
49
+ * før hvert valg.
50
+ *
51
+ * ```ts
52
+ * <fieldset {...fieldset({ state: "invalid" })}>
53
+ * <legend {...legend({ required: "symbol" })}>Leveringsmåte</legend>
54
+ * </fieldset>
55
+ * ```
56
+ */
57
+ export const fieldset = Object.assign(
58
+ ({ state = "default", disabled }: FieldsetOptions = {}): FieldsetAttributes =>
59
+ attributes({
60
+ class: FIELDSET_CLASS,
61
+ "data-state": state === "default" ? undefined : state,
62
+ disabled: disabled ? (true as const) : undefined,
63
+ }),
64
+ {
65
+ states: fieldStates,
66
+ isState: isFieldState,
67
+ },
68
+ )
69
+
70
+ /**
71
+ * Attributtene for ledeteksten på en gruppe.
72
+ *
73
+ * Samme markering som `label()`, men på et `<legend>`.
74
+ */
75
+ export const legend = Object.assign(
76
+ ({ required, optional, disabled }: LegendOptions = {}): LegendAttributes =>
77
+ attributes({
78
+ class: LEGEND_CLASS,
79
+ "data-required": required,
80
+ "data-optional": optional && !required ? ("" as const) : undefined,
81
+ "aria-disabled": disabled ? ("true" as const) : undefined,
82
+ }),
83
+ {
84
+ markers: requiredMarkers,
85
+ isMarker: createGuard(requiredMarkers),
86
+ },
87
+ )
@@ -0,0 +1,92 @@
1
+ @layer fristil {
2
+ .fs-file-upload {
3
+ box-sizing: border-box;
4
+ display: block;
5
+ inline-size: 100%;
6
+ padding: var(--fs-file-upload-padding, var(--size-2));
7
+ font-family: inherit;
8
+ font-size: var(--font-size-m);
9
+ line-height: 1.5;
10
+ color: var(--semantic-page-foreground);
11
+ background: var(--semantic-page-background);
12
+ border: 1px dashed var(--semantic-field-border);
13
+ border-radius: var(--fs-file-upload-radius, var(--size-1));
14
+ cursor: pointer;
15
+ }
16
+
17
+ /* Knappen inne i feltet er nettleserens egen, og kan bare styles gjennom
18
+ denne pseudoklassen. Teksten på den kommer fra nettleseren og språket i
19
+ operativsystemet, så den kan ikke oversettes herfra. */
20
+ .fs-file-upload::file-selector-button {
21
+ margin-inline-end: var(--size-3);
22
+ padding: var(--size-2) var(--size-4);
23
+ font-family: inherit;
24
+ font-size: var(--font-size-m);
25
+ line-height: 1.5;
26
+ color: var(--semantic-interactive-main);
27
+ background: transparent;
28
+ border: 1px solid var(--semantic-interactive-main);
29
+ border-radius: var(--fs-file-upload-radius, var(--size-1));
30
+ cursor: pointer;
31
+ }
32
+
33
+ .fs-file-upload::file-selector-button:hover {
34
+ background: var(--semantic-interactive-background);
35
+ }
36
+
37
+ .fs-file-upload:hover {
38
+ border-color: var(--semantic-field-border-hover);
39
+ }
40
+
41
+ .fs-file-upload:focus-visible {
42
+ outline: 2px solid var(--semantic-interactive-main);
43
+ outline-offset: 2px;
44
+ }
45
+
46
+ .fs-file-upload:disabled {
47
+ background: var(--semantic-disabled-background);
48
+ color: var(--semantic-disabled-foreground);
49
+ border-color: var(--semantic-disabled-background);
50
+ cursor: not-allowed;
51
+ }
52
+
53
+ .fs-file-upload[data-state="invalid"] {
54
+ border-color: var(--semantic-danger-foreground);
55
+ background: var(--semantic-danger-background);
56
+ }
57
+
58
+ .fs-file-upload[data-state="success"] {
59
+ border-color: var(--semantic-success-foreground);
60
+ }
61
+
62
+ /* Lista over filene som er valgt. Den skriver du selv, siden bare du vet
63
+ hva som skal skje når en fil fjernes. */
64
+ .fs-file-upload-list {
65
+ display: flex;
66
+ flex-direction: column;
67
+ gap: var(--size-2);
68
+ margin: var(--size-2) 0 0;
69
+ padding: 0;
70
+ list-style: none;
71
+ }
72
+
73
+ .fs-file-upload-list li {
74
+ display: flex;
75
+ flex-wrap: wrap;
76
+ align-items: center;
77
+ justify-content: space-between;
78
+ gap: var(--size-2);
79
+ padding: var(--size-2) var(--size-3);
80
+ background: var(--semantic-neutral-background);
81
+ border-radius: var(--fs-file-upload-radius, var(--size-1));
82
+ /* Filnavn har sjelden mellomrom å brekke i, og knappeteksten gjentar
83
+ navnet. Uten dette presser raden seg bredere enn skjermen på mobil. */
84
+ overflow-wrap: anywhere;
85
+ }
86
+
87
+ /* Et flex-element kan som standard ikke bli smalere enn innholdet sitt.
88
+ Uten dette brekker ikke filnavnet, uansett hva vi sier over. */
89
+ .fs-file-upload-list li > * {
90
+ min-inline-size: 0;
91
+ }
92
+ }
@@ -0,0 +1,65 @@
1
+ import {
2
+ attributes,
3
+ type FieldState,
4
+ fieldStates,
5
+ isFieldState,
6
+ type NonDefaultFieldState,
7
+ } from "../shared.js"
8
+
9
+ export const FILE_UPLOAD_CLASS = "fs-file-upload" as const
10
+ /** Lista over filene som er valgt. */
11
+ export const FILE_UPLOAD_LIST_CLASS = "fs-file-upload-list" as const
12
+
13
+ export type FileUploadOptions = {
14
+ /** Valideringstilstand. Standard: `default`. */
15
+ state?: FieldState
16
+ /** Tillat flere filer. */
17
+ multiple?: boolean
18
+ /** Filtypene feltet tar imot, som `.pdf,image/*`. */
19
+ accept?: string
20
+ }
21
+
22
+ export type FileUploadAttributes = {
23
+ class: typeof FILE_UPLOAD_CLASS
24
+ type: "file"
25
+ multiple?: true
26
+ accept?: string
27
+ "data-state"?: NonDefaultFieldState
28
+ "aria-invalid"?: "true"
29
+ }
30
+
31
+ /**
32
+ * Attributtene for et filopplastingsfelt.
33
+ *
34
+ * Feltet er et vanlig `<input type="file">`. Knappen inni er nettleserens
35
+ * egen, og teksten på den kommer fra operativsystemets språk. Den kan ikke
36
+ * oversettes, så ledeteksten over feltet må si hva som skal lastes opp.
37
+ *
38
+ * `accept` er en hjelp i filvelgeren, ikke en sperre. Brukeren kan velge
39
+ * «alle filer», så typen må sjekkes på serveren uansett.
40
+ *
41
+ * ```ts
42
+ * <input {...fileUpload({ multiple: true, accept: ".pdf" })} />
43
+ * ```
44
+ */
45
+ export const fileUpload = Object.assign(
46
+ ({
47
+ state = "default",
48
+ multiple,
49
+ accept,
50
+ }: FileUploadOptions = {}): FileUploadAttributes =>
51
+ attributes({
52
+ class: FILE_UPLOAD_CLASS,
53
+ type: "file" as const,
54
+ multiple: multiple ? (true as const) : undefined,
55
+ accept,
56
+ "data-state": state === "default" ? undefined : state,
57
+ "aria-invalid": state === "invalid" ? ("true" as const) : undefined,
58
+ }),
59
+ {
60
+ /** Klassen på lista over valgte filer. */
61
+ list: FILE_UPLOAD_LIST_CLASS,
62
+ states: fieldStates,
63
+ isState: isFieldState,
64
+ },
65
+ )
@@ -0,0 +1,33 @@
1
+ @layer fristil {
2
+ .fs-heading {
3
+ margin: 0;
4
+ font-family: inherit;
5
+ font-weight: 700;
6
+ line-height: 1.2;
7
+ color: var(--semantic-page-foreground);
8
+ text-wrap: balance;
9
+ font-size: var(--font-size-xl);
10
+ }
11
+
12
+ .fs-heading[data-size="mega"] {
13
+ font-size: var(--font-size-mega);
14
+ }
15
+
16
+ .fs-heading[data-size="xl"] {
17
+ font-size: var(--font-size-xxl);
18
+ }
19
+
20
+ .fs-heading[data-size="m"] {
21
+ font-size: var(--font-size-l);
22
+ }
23
+
24
+ .fs-heading[data-size="s"] {
25
+ font-size: var(--font-size-m);
26
+ }
27
+
28
+ .fs-heading[data-size="xs"] {
29
+ font-size: var(--font-size-s);
30
+ text-transform: uppercase;
31
+ letter-spacing: 0.06em;
32
+ }
33
+ }