@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.
- package/CHANGELOG.md +85 -0
- package/LICENSE +21 -0
- package/README.md +101 -0
- package/dist/cli.d.ts +31 -0
- package/dist/cli.d.ts.map +1 -0
- package/dist/cli.js +261 -0
- package/dist/cli.js.map +1 -0
- package/dist/components/css/accordion/accordion.d.ts +37 -0
- package/dist/components/css/accordion/accordion.d.ts.map +1 -0
- package/dist/components/css/accordion/accordion.js +31 -0
- package/dist/components/css/accordion/accordion.js.map +1 -0
- package/dist/components/css/alert/alert.d.ts +35 -0
- package/dist/components/css/alert/alert.d.ts.map +1 -0
- package/dist/components/css/alert/alert.js +29 -0
- package/dist/components/css/alert/alert.js.map +1 -0
- package/dist/components/css/avatar/avatar.d.ts +40 -0
- package/dist/components/css/avatar/avatar.d.ts.map +1 -0
- package/dist/components/css/avatar/avatar.js +30 -0
- package/dist/components/css/avatar/avatar.js.map +1 -0
- package/dist/components/css/badge/badge.d.ts +24 -0
- package/dist/components/css/badge/badge.d.ts.map +1 -0
- package/dist/components/css/badge/badge.js +24 -0
- package/dist/components/css/badge/badge.js.map +1 -0
- package/dist/components/css/breadcrumbs/breadcrumbs.d.ts +25 -0
- package/dist/components/css/breadcrumbs/breadcrumbs.d.ts.map +1 -0
- package/dist/components/css/breadcrumbs/breadcrumbs.js +23 -0
- package/dist/components/css/breadcrumbs/breadcrumbs.js.map +1 -0
- package/dist/components/css/button/button.d.ts +26 -0
- package/dist/components/css/button/button.d.ts.map +1 -0
- package/dist/components/css/button/button.js +25 -0
- package/dist/components/css/button/button.js.map +1 -0
- package/dist/components/css/card/card.d.ts +36 -0
- package/dist/components/css/card/card.d.ts.map +1 -0
- package/dist/components/css/card/card.js +28 -0
- package/dist/components/css/card/card.js.map +1 -0
- package/dist/components/css/checkbox/checkbox.d.ts +32 -0
- package/dist/components/css/checkbox/checkbox.d.ts.map +1 -0
- package/dist/components/css/checkbox/checkbox.js +27 -0
- package/dist/components/css/checkbox/checkbox.js.map +1 -0
- package/dist/components/css/dialog/dialog.d.ts +30 -0
- package/dist/components/css/dialog/dialog.d.ts.map +1 -0
- package/dist/components/css/dialog/dialog.js +28 -0
- package/dist/components/css/dialog/dialog.js.map +1 -0
- package/dist/components/css/divider/divider.d.ts +28 -0
- package/dist/components/css/divider/divider.d.ts.map +1 -0
- package/dist/components/css/divider/divider.js +22 -0
- package/dist/components/css/divider/divider.js.map +1 -0
- package/dist/components/css/error-text/error-text.d.ts +24 -0
- package/dist/components/css/error-text/error-text.d.ts.map +1 -0
- package/dist/components/css/error-text/error-text.js +18 -0
- package/dist/components/css/error-text/error-text.js.map +1 -0
- package/dist/components/css/fieldset/fieldset.d.ts +55 -0
- package/dist/components/css/fieldset/fieldset.d.ts.map +1 -0
- package/dist/components/css/fieldset/fieldset.js +39 -0
- package/dist/components/css/fieldset/fieldset.js.map +1 -0
- package/dist/components/css/file-upload/file-upload.d.ts +41 -0
- package/dist/components/css/file-upload/file-upload.d.ts.map +1 -0
- package/dist/components/css/file-upload/file-upload.js +32 -0
- package/dist/components/css/file-upload/file-upload.js.map +1 -0
- package/dist/components/css/heading/heading.d.ts +29 -0
- package/dist/components/css/heading/heading.d.ts.map +1 -0
- package/dist/components/css/heading/heading.js +23 -0
- package/dist/components/css/heading/heading.js.map +1 -0
- package/dist/components/css/help-text/help-text.d.ts +24 -0
- package/dist/components/css/help-text/help-text.d.ts.map +1 -0
- package/dist/components/css/help-text/help-text.js +23 -0
- package/dist/components/css/help-text/help-text.js.map +1 -0
- package/dist/components/css/input/input.d.ts +39 -0
- package/dist/components/css/input/input.d.ts.map +1 -0
- package/dist/components/css/input/input.js +44 -0
- package/dist/components/css/input/input.js.map +1 -0
- package/dist/components/css/label/label.d.ts +33 -0
- package/dist/components/css/label/label.d.ts.map +1 -0
- package/dist/components/css/label/label.js +23 -0
- package/dist/components/css/label/label.js.map +1 -0
- package/dist/components/css/link/link.d.ts +21 -0
- package/dist/components/css/link/link.d.ts.map +1 -0
- package/dist/components/css/link/link.js +14 -0
- package/dist/components/css/link/link.js.map +1 -0
- package/dist/components/css/list/list.d.ts +29 -0
- package/dist/components/css/list/list.d.ts.map +1 -0
- package/dist/components/css/list/list.js +23 -0
- package/dist/components/css/list/list.js.map +1 -0
- package/dist/components/css/pagination/pagination.d.ts +27 -0
- package/dist/components/css/pagination/pagination.d.ts.map +1 -0
- package/dist/components/css/pagination/pagination.js +25 -0
- package/dist/components/css/pagination/pagination.js.map +1 -0
- package/dist/components/css/paragraph/paragraph.d.ts +36 -0
- package/dist/components/css/paragraph/paragraph.d.ts.map +1 -0
- package/dist/components/css/paragraph/paragraph.js +26 -0
- package/dist/components/css/paragraph/paragraph.js.map +1 -0
- package/dist/components/css/radio/radio.d.ts +32 -0
- package/dist/components/css/radio/radio.d.ts.map +1 -0
- package/dist/components/css/radio/radio.js +27 -0
- package/dist/components/css/radio/radio.js.map +1 -0
- package/dist/components/css/search/search.d.ts +33 -0
- package/dist/components/css/search/search.d.ts.map +1 -0
- package/dist/components/css/search/search.js +31 -0
- package/dist/components/css/search/search.js.map +1 -0
- package/dist/components/css/select/select.d.ts +23 -0
- package/dist/components/css/select/select.d.ts.map +1 -0
- package/dist/components/css/select/select.js +18 -0
- package/dist/components/css/select/select.js.map +1 -0
- package/dist/components/css/shared.d.ts +26 -0
- package/dist/components/css/shared.d.ts.map +1 -0
- package/dist/components/css/shared.js +34 -0
- package/dist/components/css/shared.js.map +1 -0
- package/dist/components/css/skeleton/skeleton.d.ts +29 -0
- package/dist/components/css/skeleton/skeleton.d.ts.map +1 -0
- package/dist/components/css/skeleton/skeleton.js +23 -0
- package/dist/components/css/skeleton/skeleton.js.map +1 -0
- package/dist/components/css/skip-link/skip-link.d.ts +18 -0
- package/dist/components/css/skip-link/skip-link.d.ts.map +1 -0
- package/dist/components/css/skip-link/skip-link.js +16 -0
- package/dist/components/css/skip-link/skip-link.js.map +1 -0
- package/dist/components/css/spinner/spinner.d.ts +33 -0
- package/dist/components/css/spinner/spinner.d.ts.map +1 -0
- package/dist/components/css/spinner/spinner.js +25 -0
- package/dist/components/css/spinner/spinner.js.map +1 -0
- package/dist/components/css/sr-only/sr-only.d.ts +17 -0
- package/dist/components/css/sr-only/sr-only.d.ts.map +1 -0
- package/dist/components/css/sr-only/sr-only.js +14 -0
- package/dist/components/css/sr-only/sr-only.js.map +1 -0
- package/dist/components/css/switch/switch.d.ts +33 -0
- package/dist/components/css/switch/switch.d.ts.map +1 -0
- package/dist/components/css/switch/switch.js +29 -0
- package/dist/components/css/switch/switch.js.map +1 -0
- package/dist/components/css/table/table.d.ts +36 -0
- package/dist/components/css/table/table.d.ts.map +1 -0
- package/dist/components/css/table/table.js +28 -0
- package/dist/components/css/table/table.js.map +1 -0
- package/dist/components/css/tag/tag.d.ts +35 -0
- package/dist/components/css/tag/tag.d.ts.map +1 -0
- package/dist/components/css/tag/tag.js +27 -0
- package/dist/components/css/tag/tag.js.map +1 -0
- package/dist/components/css/textarea/textarea.d.ts +23 -0
- package/dist/components/css/textarea/textarea.d.ts.map +1 -0
- package/dist/components/css/textarea/textarea.js +18 -0
- package/dist/components/css/textarea/textarea.js.map +1 -0
- package/dist/components/css/toggle-group/toggle-group.d.ts +31 -0
- package/dist/components/css/toggle-group/toggle-group.d.ts.map +1 -0
- package/dist/components/css/toggle-group/toggle-group.js +29 -0
- package/dist/components/css/toggle-group/toggle-group.js.map +1 -0
- package/dist/components/css/tooltip/tooltip.d.ts +30 -0
- package/dist/components/css/tooltip/tooltip.d.ts.map +1 -0
- package/dist/components/css/tooltip/tooltip.js +28 -0
- package/dist/components/css/tooltip/tooltip.js.map +1 -0
- package/dist/components/frittstaende/calendar/fs-calendar.d.ts +52 -0
- package/dist/components/frittstaende/calendar/fs-calendar.d.ts.map +1 -0
- package/dist/components/frittstaende/calendar/fs-calendar.js +462 -0
- package/dist/components/frittstaende/calendar/fs-calendar.js.map +1 -0
- package/dist/components/frittstaende/date-field/fs-date-field.d.ts +110 -0
- package/dist/components/frittstaende/date-field/fs-date-field.d.ts.map +1 -0
- package/dist/components/frittstaende/date-field/fs-date-field.js +264 -0
- package/dist/components/frittstaende/date-field/fs-date-field.js.map +1 -0
- package/dist/components/frittstaende/suggestion/fs-suggestion.d.ts +133 -0
- package/dist/components/frittstaende/suggestion/fs-suggestion.d.ts.map +1 -0
- package/dist/components/frittstaende/suggestion/fs-suggestion.js +280 -0
- package/dist/components/frittstaende/suggestion/fs-suggestion.js.map +1 -0
- package/dist/components/frittstaende/toast/fs-toast.d.ts +67 -0
- package/dist/components/frittstaende/toast/fs-toast.d.ts.map +1 -0
- package/dist/components/frittstaende/toast/fs-toast.js +108 -0
- package/dist/components/frittstaende/toast/fs-toast.js.map +1 -0
- package/dist/components/ramme/error-summary/fs-error-summary.d.ts +70 -0
- package/dist/components/ramme/error-summary/fs-error-summary.d.ts.map +1 -0
- package/dist/components/ramme/error-summary/fs-error-summary.js +155 -0
- package/dist/components/ramme/error-summary/fs-error-summary.js.map +1 -0
- package/dist/components/ramme/field/field-core.d.ts +70 -0
- package/dist/components/ramme/field/field-core.d.ts.map +1 -0
- package/dist/components/ramme/field/field-core.js +60 -0
- package/dist/components/ramme/field/field-core.js.map +1 -0
- package/dist/components/ramme/field/fs-field.d.ts +49 -0
- package/dist/components/ramme/field/fs-field.d.ts.map +1 -0
- package/dist/components/ramme/field/fs-field.js +118 -0
- package/dist/components/ramme/field/fs-field.js.map +1 -0
- package/dist/components/ramme/popover/fs-popover.d.ts +68 -0
- package/dist/components/ramme/popover/fs-popover.d.ts.map +1 -0
- package/dist/components/ramme/popover/fs-popover.js +167 -0
- package/dist/components/ramme/popover/fs-popover.js.map +1 -0
- package/dist/components/ramme/tabs/fs-tabs.d.ts +61 -0
- package/dist/components/ramme/tabs/fs-tabs.d.ts.map +1 -0
- package/dist/components/ramme/tabs/fs-tabs.js +156 -0
- package/dist/components/ramme/tabs/fs-tabs.js.map +1 -0
- package/dist/dom.d.ts +33 -0
- package/dist/dom.d.ts.map +1 -0
- package/dist/dom.js +77 -0
- package/dist/dom.js.map +1 -0
- package/dist/fs.d.ts +199 -0
- package/dist/fs.d.ts.map +1 -0
- package/dist/fs.js +128 -0
- package/dist/fs.js.map +1 -0
- package/dist/index.d.ts +84 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +48 -0
- package/dist/index.js.map +1 -0
- package/dist/jsx/react.d.ts +127 -0
- package/dist/jsx/react.d.ts.map +1 -0
- package/dist/jsx/react.js +2 -0
- package/dist/jsx/react.js.map +1 -0
- package/dist/react.d.ts +207 -0
- package/dist/react.d.ts.map +1 -0
- package/dist/react.js +109 -0
- package/dist/react.js.map +1 -0
- package/dist/tailwind/preset.d.ts +120 -0
- package/dist/tailwind/preset.d.ts.map +1 -0
- package/dist/tailwind/preset.js +107 -0
- package/dist/tailwind/preset.js.map +1 -0
- package/dist/takeover.d.ts +79 -0
- package/dist/takeover.d.ts.map +1 -0
- package/dist/takeover.js +119 -0
- package/dist/takeover.js.map +1 -0
- package/dist/tokens/color.d.ts +85 -0
- package/dist/tokens/color.d.ts.map +1 -0
- package/dist/tokens/color.js +212 -0
- package/dist/tokens/color.js.map +1 -0
- package/dist/tokens/theme.d.ts +52 -0
- package/dist/tokens/theme.d.ts.map +1 -0
- package/dist/tokens/theme.js +197 -0
- package/dist/tokens/theme.js.map +1 -0
- package/dist/tokens/tokens.d.ts +210 -0
- package/dist/tokens/tokens.d.ts.map +1 -0
- package/dist/tokens/tokens.js +238 -0
- package/dist/tokens/tokens.js.map +1 -0
- package/package.json +334 -0
- package/src/components/css/accordion/accordion.css +74 -0
- package/src/components/css/accordion/accordion.ts +50 -0
- package/src/components/css/alert/alert.css +50 -0
- package/src/components/css/alert/alert.ts +48 -0
- package/src/components/css/avatar/avatar.css +64 -0
- package/src/components/css/avatar/avatar.ts +57 -0
- package/src/components/css/badge/badge.css +42 -0
- package/src/components/css/badge/badge.ts +43 -0
- package/src/components/css/breadcrumbs/breadcrumbs.css +50 -0
- package/src/components/css/breadcrumbs/breadcrumbs.ts +29 -0
- package/src/components/css/button/button.css +101 -0
- package/src/components/css/button/button.ts +44 -0
- package/src/components/css/card/card.css +48 -0
- package/src/components/css/card/card.ts +50 -0
- package/src/components/css/checkbox/checkbox.css +96 -0
- package/src/components/css/checkbox/checkbox.ts +50 -0
- package/src/components/css/dialog/dialog.css +50 -0
- package/src/components/css/dialog/dialog.ts +36 -0
- package/src/components/css/divider/divider.css +18 -0
- package/src/components/css/divider/divider.ts +41 -0
- package/src/components/css/error-text/error-text.css +21 -0
- package/src/components/css/error-text/error-text.ts +37 -0
- package/src/components/css/fieldset/fieldset.css +57 -0
- package/src/components/css/fieldset/fieldset.ts +87 -0
- package/src/components/css/file-upload/file-upload.css +92 -0
- package/src/components/css/file-upload/file-upload.ts +65 -0
- package/src/components/css/heading/heading.css +33 -0
- package/src/components/css/heading/heading.ts +42 -0
- package/src/components/css/help-text/help-text.css +24 -0
- package/src/components/css/help-text/help-text.ts +42 -0
- package/src/components/css/input/input.css +131 -0
- package/src/components/css/input/input.ts +76 -0
- package/src/components/css/label/label.css +34 -0
- package/src/components/css/label/label.ts +51 -0
- package/src/components/css/link/link.css +36 -0
- package/src/components/css/link/link.ts +29 -0
- package/src/components/css/list/list.css +40 -0
- package/src/components/css/list/list.ts +42 -0
- package/src/components/css/pagination/pagination.css +77 -0
- package/src/components/css/pagination/pagination.ts +33 -0
- package/src/components/css/paragraph/paragraph.css +31 -0
- package/src/components/css/paragraph/paragraph.ts +53 -0
- package/src/components/css/radio/radio.css +76 -0
- package/src/components/css/radio/radio.ts +50 -0
- package/src/components/css/search/search.css +49 -0
- package/src/components/css/search/search.ts +52 -0
- package/src/components/css/select/select.css +95 -0
- package/src/components/css/select/select.ts +40 -0
- package/src/components/css/shared.ts +40 -0
- package/src/components/css/skeleton/skeleton.css +49 -0
- package/src/components/css/skeleton/skeleton.ts +43 -0
- package/src/components/css/skip-link/skip-link.css +36 -0
- package/src/components/css/skip-link/skip-link.ts +22 -0
- package/src/components/css/spinner/spinner.css +48 -0
- package/src/components/css/spinner/spinner.ts +48 -0
- package/src/components/css/sr-only/sr-only.css +16 -0
- package/src/components/css/sr-only/sr-only.ts +18 -0
- package/src/components/css/switch/switch.css +101 -0
- package/src/components/css/switch/switch.ts +46 -0
- package/src/components/css/table/table.css +63 -0
- package/src/components/css/table/table.ts +50 -0
- package/src/components/css/tag/tag.css +58 -0
- package/src/components/css/tag/tag.ts +49 -0
- package/src/components/css/textarea/textarea.css +71 -0
- package/src/components/css/textarea/textarea.ts +40 -0
- package/src/components/css/toggle-group/toggle-group.css +82 -0
- package/src/components/css/toggle-group/toggle-group.ts +37 -0
- package/src/components/css/tooltip/tooltip.css +47 -0
- package/src/components/css/tooltip/tooltip.ts +36 -0
- package/src/components/frittstaende/calendar/fs-calendar.ts +525 -0
- package/src/components/frittstaende/date-field/date-field.css +54 -0
- package/src/components/frittstaende/date-field/fs-date-field.ts +309 -0
- package/src/components/frittstaende/suggestion/fs-suggestion.ts +333 -0
- package/src/components/frittstaende/suggestion/suggestion.css +63 -0
- package/src/components/frittstaende/toast/fs-toast.ts +146 -0
- package/src/components/frittstaende/toast/toast.css +71 -0
- package/src/components/ramme/error-summary/error-summary.css +45 -0
- package/src/components/ramme/error-summary/fs-error-summary.ts +197 -0
- package/src/components/ramme/field/field-core.ts +132 -0
- package/src/components/ramme/field/field.css +6 -0
- package/src/components/ramme/field/fs-field.ts +154 -0
- package/src/components/ramme/popover/fs-popover.ts +205 -0
- package/src/components/ramme/popover/popover.css +34 -0
- package/src/components/ramme/tabs/fs-tabs.ts +182 -0
- package/src/components/ramme/tabs/tabs.css +68 -0
- package/src/tailwind/tailwind.css +134 -0
- package/src/tokens/color.ts +267 -0
- package/src/tokens/theme.ts +350 -0
- package/src/tokens/tokens.css +214 -0
- 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
|
+
}
|