@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,42 @@
|
|
|
1
|
+
import { attributes, createGuard } from "../shared.js"
|
|
2
|
+
|
|
3
|
+
export const HEADING_CLASS = "fs-heading" as const
|
|
4
|
+
|
|
5
|
+
export const headingSizes = ["xs", "s", "m", "l", "xl", "mega"] as const
|
|
6
|
+
|
|
7
|
+
export type HeadingSize = (typeof headingSizes)[number]
|
|
8
|
+
export type NonDefaultHeadingSize = Exclude<HeadingSize, "l">
|
|
9
|
+
|
|
10
|
+
export type HeadingOptions = {
|
|
11
|
+
/** Visuell størrelse. Standard: `l`. */
|
|
12
|
+
size?: HeadingSize
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
export type HeadingAttributes = {
|
|
16
|
+
class: typeof HEADING_CLASS
|
|
17
|
+
"data-size"?: NonDefaultHeadingSize
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
/**
|
|
21
|
+
* Attributtene for en overskrift.
|
|
22
|
+
*
|
|
23
|
+
* Størrelsen og nivået er to forskjellige ting. Nivået er `<h1>` til `<h6>`
|
|
24
|
+
* og bestemmer strukturen skjermlesere navigerer etter; `size` bestemmer bare
|
|
25
|
+
* hvor stor teksten ser ut. En `<h2>` som skal se liten ut er riktig; en
|
|
26
|
+
* `<h4>` valgt fordi den var liten nok, hopper over et nivå i strukturen.
|
|
27
|
+
*
|
|
28
|
+
* ```ts
|
|
29
|
+
* <h2 {...heading({ size: "m" })}>Vedlegg</h2>
|
|
30
|
+
* ```
|
|
31
|
+
*/
|
|
32
|
+
export const heading = Object.assign(
|
|
33
|
+
({ size = "l" }: HeadingOptions = {}): HeadingAttributes =>
|
|
34
|
+
attributes({
|
|
35
|
+
class: HEADING_CLASS,
|
|
36
|
+
"data-size": size === "l" ? undefined : size,
|
|
37
|
+
}),
|
|
38
|
+
{
|
|
39
|
+
sizes: headingSizes,
|
|
40
|
+
isSize: createGuard(headingSizes),
|
|
41
|
+
},
|
|
42
|
+
)
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
@layer fristil {
|
|
2
|
+
.fs-help-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
|
+
line-height: 1.4;
|
|
10
|
+
color: var(--semantic-muted-foreground);
|
|
11
|
+
}
|
|
12
|
+
|
|
13
|
+
.fs-help-text[data-variant="default"] {
|
|
14
|
+
color: var(--semantic-page-foreground);
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
.fs-help-text[data-variant="success"] {
|
|
18
|
+
color: var(--semantic-success-foreground);
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
.fs-help-text[data-variant="warning"] {
|
|
22
|
+
color: var(--semantic-warning-foreground);
|
|
23
|
+
}
|
|
24
|
+
}
|
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
import { attributes, createGuard } from "../shared.js"
|
|
2
|
+
|
|
3
|
+
export const HELP_TEXT_CLASS = "fs-help-text" as const
|
|
4
|
+
|
|
5
|
+
export const helpTextVariants = [
|
|
6
|
+
"muted",
|
|
7
|
+
"default",
|
|
8
|
+
"success",
|
|
9
|
+
"warning",
|
|
10
|
+
] as const
|
|
11
|
+
|
|
12
|
+
export type HelpTextVariant = (typeof helpTextVariants)[number]
|
|
13
|
+
export type NonDefaultHelpTextVariant = Exclude<HelpTextVariant, "muted">
|
|
14
|
+
|
|
15
|
+
export type HelpTextOptions = {
|
|
16
|
+
/** Hvor mye teksten skal rope. Standard: `muted`. */
|
|
17
|
+
variant?: HelpTextVariant
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
export type HelpTextAttributes = {
|
|
21
|
+
class: typeof HELP_TEXT_CLASS
|
|
22
|
+
"data-variant"?: NonDefaultHelpTextVariant
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
/**
|
|
26
|
+
* Attributtene for hjelpetekst under et felt.
|
|
27
|
+
*
|
|
28
|
+
* ```ts
|
|
29
|
+
* <p {...helpText({ variant: "warning" })}>…</p>
|
|
30
|
+
* ```
|
|
31
|
+
*/
|
|
32
|
+
export const helpText = Object.assign(
|
|
33
|
+
({ variant = "muted" }: HelpTextOptions = {}): HelpTextAttributes =>
|
|
34
|
+
attributes({
|
|
35
|
+
class: HELP_TEXT_CLASS,
|
|
36
|
+
"data-variant": variant === "muted" ? undefined : variant,
|
|
37
|
+
}),
|
|
38
|
+
{
|
|
39
|
+
variants: helpTextVariants,
|
|
40
|
+
isVariant: createGuard(helpTextVariants),
|
|
41
|
+
},
|
|
42
|
+
)
|
|
@@ -0,0 +1,131 @@
|
|
|
1
|
+
@layer fristil {
|
|
2
|
+
.fs-input {
|
|
3
|
+
/* Designsystemet kan ikke regne med at konsumenten har en CSS-reset.
|
|
4
|
+
Uten border-box legges padding og ramme utenpå width, og feltet
|
|
5
|
+
blir bredere enn boksen det ligger i. */
|
|
6
|
+
box-sizing: border-box;
|
|
7
|
+
|
|
8
|
+
display: block;
|
|
9
|
+
width: 100%;
|
|
10
|
+
padding: var(--fs-input-padding, var(--size-2) var(--size-3));
|
|
11
|
+
font-family: inherit;
|
|
12
|
+
font-size: var(--font-size-m);
|
|
13
|
+
line-height: 1.5;
|
|
14
|
+
color: var(--semantic-page-foreground);
|
|
15
|
+
background: var(--semantic-page-background);
|
|
16
|
+
border: 1px solid var(--semantic-field-border);
|
|
17
|
+
border-radius: var(--fs-input-radius, var(--size-1));
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
.fs-input::placeholder {
|
|
21
|
+
color: var(--semantic-muted-foreground);
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
.fs-input:hover {
|
|
25
|
+
border-color: var(--semantic-field-border-hover);
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
.fs-input:focus-visible {
|
|
29
|
+
outline: 2px solid var(--semantic-interactive-main);
|
|
30
|
+
outline-offset: 2px;
|
|
31
|
+
border-color: var(--semantic-interactive-main);
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
.fs-input:disabled,
|
|
35
|
+
.fs-input[aria-disabled="true"] {
|
|
36
|
+
background: var(--semantic-disabled-background);
|
|
37
|
+
color: var(--semantic-disabled-foreground);
|
|
38
|
+
border-color: var(--semantic-disabled-background);
|
|
39
|
+
/* Ingen pointer-events: none her. Nettleseren blokkerer allerede et
|
|
40
|
+
deaktivert felt, og pointer-events ville bare hindret markøren i å
|
|
41
|
+
vises. Elementet blir da ikke truffet av musa i det hele tatt. */
|
|
42
|
+
cursor: not-allowed;
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
/* aria-disabled er bare en opplysning til skjermlesere; elementet virker
|
|
46
|
+
fortsatt. Her stopper pointer-events musa, på bekostning av markøren.
|
|
47
|
+
Skal feltet faktisk være av, bruk `disabled` eller `readonly`. */
|
|
48
|
+
.fs-input[aria-disabled="true"] {
|
|
49
|
+
pointer-events: none;
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
.fs-input[data-state="invalid"] {
|
|
53
|
+
border-color: var(--semantic-danger-foreground);
|
|
54
|
+
background: var(--semantic-danger-background);
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
.fs-input[data-state="invalid"]:focus-visible {
|
|
58
|
+
outline-color: var(--semantic-danger-foreground);
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
.fs-input[data-state="success"] {
|
|
62
|
+
border-color: var(--semantic-success-foreground);
|
|
63
|
+
background: var(--semantic-success-background);
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
.fs-input[data-state="success"]:focus-visible {
|
|
67
|
+
outline-color: var(--semantic-success-foreground);
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
.fs-input[data-variant="date"],
|
|
71
|
+
.fs-input[data-variant="time"],
|
|
72
|
+
.fs-input[data-variant="datetime-local"] {
|
|
73
|
+
position: relative;
|
|
74
|
+
min-height: calc(var(--size-4) * 2.5);
|
|
75
|
+
font-variant-numeric: tabular-nums;
|
|
76
|
+
letter-spacing: 0.01em;
|
|
77
|
+
padding-inline-end: calc(var(--size-6) + var(--size-2));
|
|
78
|
+
background-repeat: no-repeat;
|
|
79
|
+
background-position: right var(--size-2) center;
|
|
80
|
+
background-size: 0.95rem 0.95rem;
|
|
81
|
+
}
|
|
82
|
+
|
|
83
|
+
/* background-position har ingen logisk variant, så retningen må snus for
|
|
84
|
+
hånd. Alt annet her er logiske egenskaper, som snur av seg selv. */
|
|
85
|
+
.fs-input[data-variant="date"]:dir(rtl),
|
|
86
|
+
.fs-input[data-variant="time"]:dir(rtl),
|
|
87
|
+
.fs-input[data-variant="datetime-local"]:dir(rtl) {
|
|
88
|
+
background-position: left var(--size-2) center;
|
|
89
|
+
}
|
|
90
|
+
|
|
91
|
+
.fs-input[data-variant="date"],
|
|
92
|
+
.fs-input[data-variant="datetime-local"] {
|
|
93
|
+
background-image: var(--semantic-icon-calendar);
|
|
94
|
+
}
|
|
95
|
+
|
|
96
|
+
.fs-input[data-variant="time"] {
|
|
97
|
+
background-image: var(--semantic-icon-clock);
|
|
98
|
+
}
|
|
99
|
+
|
|
100
|
+
.fs-input[data-variant="date"]::-webkit-calendar-picker-indicator,
|
|
101
|
+
.fs-input[data-variant="time"]::-webkit-calendar-picker-indicator,
|
|
102
|
+
.fs-input[data-variant="datetime-local"]::-webkit-calendar-picker-indicator {
|
|
103
|
+
position: absolute;
|
|
104
|
+
inset-inline-end: var(--size-2);
|
|
105
|
+
top: 50%;
|
|
106
|
+
transform: translateY(-50%);
|
|
107
|
+
opacity: 0;
|
|
108
|
+
width: var(--size-6);
|
|
109
|
+
height: var(--size-6);
|
|
110
|
+
min-width: var(--size-6);
|
|
111
|
+
min-height: var(--size-6);
|
|
112
|
+
cursor: pointer;
|
|
113
|
+
}
|
|
114
|
+
|
|
115
|
+
/* Høykontrast: ikonet er malt inn i bildet med fast farge, og kan bli
|
|
116
|
+
usynlig i et mørkt tema. Nettleserens egen knapp er skjult bak vårt ikon,
|
|
117
|
+
og hentes fram igjen her. */
|
|
118
|
+
@media (forced-colors: active) {
|
|
119
|
+
.fs-input[data-variant="date"],
|
|
120
|
+
.fs-input[data-variant="time"],
|
|
121
|
+
.fs-input[data-variant="datetime-local"] {
|
|
122
|
+
background-image: none;
|
|
123
|
+
}
|
|
124
|
+
|
|
125
|
+
.fs-input[data-variant="date"]::-webkit-calendar-picker-indicator,
|
|
126
|
+
.fs-input[data-variant="time"]::-webkit-calendar-picker-indicator,
|
|
127
|
+
.fs-input[data-variant="datetime-local"]::-webkit-calendar-picker-indicator {
|
|
128
|
+
opacity: 1;
|
|
129
|
+
}
|
|
130
|
+
}
|
|
131
|
+
}
|
|
@@ -0,0 +1,76 @@
|
|
|
1
|
+
import {
|
|
2
|
+
attributes,
|
|
3
|
+
createGuard,
|
|
4
|
+
type FieldState,
|
|
5
|
+
fieldStates,
|
|
6
|
+
isFieldState,
|
|
7
|
+
type NonDefaultFieldState,
|
|
8
|
+
} from "../shared.js"
|
|
9
|
+
|
|
10
|
+
export const INPUT_CLASS = "fs-input" as const
|
|
11
|
+
|
|
12
|
+
export const inputTypes = [
|
|
13
|
+
"text",
|
|
14
|
+
"password",
|
|
15
|
+
"email",
|
|
16
|
+
"number",
|
|
17
|
+
"date",
|
|
18
|
+
"datetime-local",
|
|
19
|
+
"week",
|
|
20
|
+
"month",
|
|
21
|
+
"tel",
|
|
22
|
+
"url",
|
|
23
|
+
"search",
|
|
24
|
+
"time",
|
|
25
|
+
] as const
|
|
26
|
+
|
|
27
|
+
export type InputType = (typeof inputTypes)[number]
|
|
28
|
+
|
|
29
|
+
/** Typene som får et ikon i feltet, og som åpner nettleserens egen velger. */
|
|
30
|
+
const TYPER_MED_IKON = ["date", "time", "datetime-local"] as const
|
|
31
|
+
type TypeMedIkon = (typeof TYPER_MED_IKON)[number]
|
|
32
|
+
|
|
33
|
+
export type InputOptions = {
|
|
34
|
+
/** HTML-typen. Settes som `type`, og styrer ikonet. Standard: `text`. */
|
|
35
|
+
type?: InputType
|
|
36
|
+
/** Valideringstilstand. Standard: `default`. */
|
|
37
|
+
state?: FieldState
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
export type InputAttributes = {
|
|
41
|
+
class: typeof INPUT_CLASS
|
|
42
|
+
type: InputType
|
|
43
|
+
"data-variant"?: TypeMedIkon
|
|
44
|
+
"data-state"?: NonDefaultFieldState
|
|
45
|
+
"aria-invalid"?: "true"
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
/**
|
|
49
|
+
* Attributtene for et tekstfelt.
|
|
50
|
+
*
|
|
51
|
+
* `type` setter både HTML-typen og ikonvarianten, så de to kan ikke komme i
|
|
52
|
+
* utakt. Skriver du dem for hånd, er det lett å få et datofelt som ser ut
|
|
53
|
+
* som et datofelt, men der ingenting skjer når brukeren trykker på ikonet.
|
|
54
|
+
*
|
|
55
|
+
* ```ts
|
|
56
|
+
* <input {...input({ type: "date", state: "invalid" })} />
|
|
57
|
+
* ```
|
|
58
|
+
*/
|
|
59
|
+
export const input = Object.assign(
|
|
60
|
+
({ type = "text", state = "default" }: InputOptions = {}): InputAttributes =>
|
|
61
|
+
attributes({
|
|
62
|
+
class: INPUT_CLASS,
|
|
63
|
+
type,
|
|
64
|
+
"data-variant": (TYPER_MED_IKON as readonly string[]).includes(type)
|
|
65
|
+
? (type as TypeMedIkon)
|
|
66
|
+
: undefined,
|
|
67
|
+
"data-state": state === "default" ? undefined : state,
|
|
68
|
+
"aria-invalid": state === "invalid" ? ("true" as const) : undefined,
|
|
69
|
+
}),
|
|
70
|
+
{
|
|
71
|
+
types: inputTypes,
|
|
72
|
+
isType: createGuard(inputTypes),
|
|
73
|
+
states: fieldStates,
|
|
74
|
+
isState: isFieldState,
|
|
75
|
+
},
|
|
76
|
+
)
|
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
@layer fristil {
|
|
2
|
+
.fs-label {
|
|
3
|
+
display: block;
|
|
4
|
+
font-family: inherit;
|
|
5
|
+
font-size: var(--font-size-s);
|
|
6
|
+
font-weight: 600;
|
|
7
|
+
line-height: 1.5;
|
|
8
|
+
color: var(--semantic-page-foreground);
|
|
9
|
+
}
|
|
10
|
+
|
|
11
|
+
.fs-label[data-required]::after {
|
|
12
|
+
content: " *";
|
|
13
|
+
color: var(--semantic-danger-foreground);
|
|
14
|
+
font-weight: 700;
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
.fs-label[data-required="text"]::after {
|
|
18
|
+
content: " (påkrevd)";
|
|
19
|
+
color: var(--semantic-danger-foreground);
|
|
20
|
+
font-weight: 400;
|
|
21
|
+
font-size: var(--font-size-xs);
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
.fs-label[data-optional]::after {
|
|
25
|
+
content: " (valgfri)";
|
|
26
|
+
color: var(--semantic-disabled-foreground);
|
|
27
|
+
font-weight: 400;
|
|
28
|
+
font-size: var(--font-size-xs);
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
.fs-label[aria-disabled="true"] {
|
|
32
|
+
color: var(--semantic-muted-foreground);
|
|
33
|
+
}
|
|
34
|
+
}
|
|
@@ -0,0 +1,51 @@
|
|
|
1
|
+
import {
|
|
2
|
+
attributes,
|
|
3
|
+
createGuard,
|
|
4
|
+
type RequiredMarker,
|
|
5
|
+
requiredMarkers,
|
|
6
|
+
} from "../shared.js"
|
|
7
|
+
|
|
8
|
+
export const LABEL_CLASS = "fs-label" as const
|
|
9
|
+
|
|
10
|
+
export type { RequiredMarker }
|
|
11
|
+
export { requiredMarkers }
|
|
12
|
+
|
|
13
|
+
export type LabelOptions = {
|
|
14
|
+
/** Marker feltet som påkrevd, med stjerne eller med ordet «(påkrevd)». */
|
|
15
|
+
required?: RequiredMarker
|
|
16
|
+
/** Marker feltet som valgfritt. Velg én av `required` og `optional`. */
|
|
17
|
+
optional?: boolean
|
|
18
|
+
/** Demper teksten når kontrollen er slått av. */
|
|
19
|
+
disabled?: boolean
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
export type LabelAttributes = {
|
|
23
|
+
class: typeof LABEL_CLASS
|
|
24
|
+
"data-required"?: RequiredMarker
|
|
25
|
+
"data-optional"?: ""
|
|
26
|
+
"aria-disabled"?: "true"
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
/**
|
|
30
|
+
* Attributtene for en ledetekst.
|
|
31
|
+
*
|
|
32
|
+
* Markeringen er bare visuell, så sett `required` på selve feltet i tillegg,
|
|
33
|
+
* ellers får skjermleseren ikke vite at det må fylles ut.
|
|
34
|
+
*
|
|
35
|
+
* ```ts
|
|
36
|
+
* <label {...label({ required: "symbol" })} htmlFor="epost">E-postadresse</label>
|
|
37
|
+
* ```
|
|
38
|
+
*/
|
|
39
|
+
export const label = Object.assign(
|
|
40
|
+
({ required, optional, disabled }: LabelOptions = {}): LabelAttributes =>
|
|
41
|
+
attributes({
|
|
42
|
+
class: LABEL_CLASS,
|
|
43
|
+
"data-required": required,
|
|
44
|
+
"data-optional": optional && !required ? ("" as const) : undefined,
|
|
45
|
+
"aria-disabled": disabled ? ("true" as const) : undefined,
|
|
46
|
+
}),
|
|
47
|
+
{
|
|
48
|
+
markers: requiredMarkers,
|
|
49
|
+
isMarker: createGuard(requiredMarkers),
|
|
50
|
+
},
|
|
51
|
+
)
|
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
@layer fristil {
|
|
2
|
+
.fs-link {
|
|
3
|
+
color: var(--semantic-interactive-main);
|
|
4
|
+
font-family: inherit;
|
|
5
|
+
font-size: inherit;
|
|
6
|
+
line-height: 1.5;
|
|
7
|
+
text-decoration-line: underline;
|
|
8
|
+
text-decoration-thickness: 0.08em;
|
|
9
|
+
text-underline-offset: 0.14em;
|
|
10
|
+
text-decoration-color: currentColor;
|
|
11
|
+
transition:
|
|
12
|
+
color 120ms ease,
|
|
13
|
+
text-decoration-color 120ms ease;
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
.fs-link:hover {
|
|
17
|
+
color: var(--semantic-interactive-foreground);
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
.fs-link:visited {
|
|
21
|
+
color: var(--semantic-interactive-visited);
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
.fs-link:focus-visible {
|
|
25
|
+
outline: 2px solid var(--semantic-interactive-main);
|
|
26
|
+
outline-offset: 2px;
|
|
27
|
+
border-radius: var(--size-0-5);
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
.fs-link[aria-disabled="true"] {
|
|
31
|
+
color: var(--semantic-muted-foreground);
|
|
32
|
+
text-decoration: none;
|
|
33
|
+
cursor: not-allowed;
|
|
34
|
+
pointer-events: none;
|
|
35
|
+
}
|
|
36
|
+
}
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
import { attributes } from "../shared.js"
|
|
2
|
+
|
|
3
|
+
export const LINK_CLASS = "fs-link" as const
|
|
4
|
+
|
|
5
|
+
export type LinkOptions = {
|
|
6
|
+
/**
|
|
7
|
+
* Lenken er ikke klikkbar ennå. Gir `aria-disabled` framfor å fjerne
|
|
8
|
+
* `href`, slik at skjermlesere fortsatt finner den og kan si fra.
|
|
9
|
+
*/
|
|
10
|
+
disabled?: boolean
|
|
11
|
+
}
|
|
12
|
+
|
|
13
|
+
export type LinkAttributes = {
|
|
14
|
+
class: typeof LINK_CLASS
|
|
15
|
+
"aria-disabled"?: "true"
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
/**
|
|
19
|
+
* Attributtene for en lenke.
|
|
20
|
+
*
|
|
21
|
+
* ```ts
|
|
22
|
+
* <a {...link()} href="/kvittering">Se kvittering</a>
|
|
23
|
+
* ```
|
|
24
|
+
*/
|
|
25
|
+
export const link = ({ disabled = false }: LinkOptions = {}): LinkAttributes =>
|
|
26
|
+
attributes({
|
|
27
|
+
class: LINK_CLASS,
|
|
28
|
+
"aria-disabled": disabled ? ("true" as const) : undefined,
|
|
29
|
+
})
|
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
@layer fristil {
|
|
2
|
+
.fs-list {
|
|
3
|
+
box-sizing: border-box;
|
|
4
|
+
margin: 0;
|
|
5
|
+
padding-inline-start: var(--size-5);
|
|
6
|
+
font-family: inherit;
|
|
7
|
+
font-size: var(--font-size-m);
|
|
8
|
+
line-height: 1.6;
|
|
9
|
+
color: var(--semantic-page-foreground);
|
|
10
|
+
}
|
|
11
|
+
|
|
12
|
+
.fs-list li + li {
|
|
13
|
+
margin-block-start: var(--fs-list-gap, var(--size-1));
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
.fs-list .fs-list {
|
|
17
|
+
margin-block-start: var(--fs-list-gap, var(--size-1));
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
/* Uten punkter og innrykk, for lister som bærer sin egen struktur, som
|
|
21
|
+
rader med kort. Listen blir værende en liste for skjermlesere. */
|
|
22
|
+
.fs-list[data-variant="plain"] {
|
|
23
|
+
list-style: none;
|
|
24
|
+
padding-inline-start: 0;
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
.fs-list[data-variant="divided"] {
|
|
28
|
+
list-style: none;
|
|
29
|
+
padding-inline-start: 0;
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
.fs-list[data-variant="divided"] li + li {
|
|
33
|
+
margin-block-start: 0;
|
|
34
|
+
border-block-start: 1px solid var(--semantic-divider-30);
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
.fs-list[data-variant="divided"] li {
|
|
38
|
+
padding-block: var(--fs-list-gap, var(--size-2));
|
|
39
|
+
}
|
|
40
|
+
}
|
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
import { attributes, createGuard } from "../shared.js"
|
|
2
|
+
|
|
3
|
+
export const LIST_CLASS = "fs-list" as const
|
|
4
|
+
|
|
5
|
+
export const listVariants = ["default", "plain", "divided"] as const
|
|
6
|
+
|
|
7
|
+
export type ListVariant = (typeof listVariants)[number]
|
|
8
|
+
export type NonDefaultListVariant = Exclude<ListVariant, "default">
|
|
9
|
+
|
|
10
|
+
export type ListOptions = {
|
|
11
|
+
/** Punkter, rene rader, eller rader med strek mellom. Standard: `default`. */
|
|
12
|
+
variant?: ListVariant
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
export type ListAttributes = {
|
|
16
|
+
class: typeof LIST_CLASS
|
|
17
|
+
"data-variant"?: NonDefaultListVariant
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
/**
|
|
21
|
+
* Attributtene for en liste.
|
|
22
|
+
*
|
|
23
|
+
* Klassen hører på `<ul>` eller `<ol>`. `plain` og `divided` fjerner punktene
|
|
24
|
+
* visuelt, men listen blir værende en liste, så skjermleseren sier fortsatt
|
|
25
|
+
* hvor mange elementer den har. Det er grunnen til at varianten finnes: uten
|
|
26
|
+
* den ville folk brukt `<div>` for å bli kvitt punktene.
|
|
27
|
+
*
|
|
28
|
+
* ```ts
|
|
29
|
+
* <ul {...list({ variant: "divided" })}>…</ul>
|
|
30
|
+
* ```
|
|
31
|
+
*/
|
|
32
|
+
export const list = Object.assign(
|
|
33
|
+
({ variant = "default" }: ListOptions = {}): ListAttributes =>
|
|
34
|
+
attributes({
|
|
35
|
+
class: LIST_CLASS,
|
|
36
|
+
"data-variant": variant === "default" ? undefined : variant,
|
|
37
|
+
}),
|
|
38
|
+
{
|
|
39
|
+
variants: listVariants,
|
|
40
|
+
isVariant: createGuard(listVariants),
|
|
41
|
+
},
|
|
42
|
+
)
|
|
@@ -0,0 +1,77 @@
|
|
|
1
|
+
@layer fristil {
|
|
2
|
+
.fs-pagination {
|
|
3
|
+
box-sizing: border-box;
|
|
4
|
+
display: flex;
|
|
5
|
+
flex-wrap: wrap;
|
|
6
|
+
align-items: center;
|
|
7
|
+
gap: var(--fs-pagination-gap, var(--size-1));
|
|
8
|
+
margin: 0;
|
|
9
|
+
padding: 0;
|
|
10
|
+
list-style: none;
|
|
11
|
+
font-family: inherit;
|
|
12
|
+
font-size: var(--font-size-m);
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
.fs-pagination a,
|
|
16
|
+
.fs-pagination button {
|
|
17
|
+
box-sizing: border-box;
|
|
18
|
+
display: inline-flex;
|
|
19
|
+
align-items: center;
|
|
20
|
+
justify-content: center;
|
|
21
|
+
/* 40 piksler i begge retninger. WCAG 2.2 krever 24, og et nummer i en
|
|
22
|
+
lang rekke er lett å bomme på med finger. */
|
|
23
|
+
min-inline-size: var(--fs-pagination-size, var(--size-10));
|
|
24
|
+
min-block-size: var(--fs-pagination-size, var(--size-10));
|
|
25
|
+
padding-inline: var(--size-2);
|
|
26
|
+
font-family: inherit;
|
|
27
|
+
font-size: inherit;
|
|
28
|
+
line-height: 1;
|
|
29
|
+
color: var(--semantic-interactive-main);
|
|
30
|
+
background: transparent;
|
|
31
|
+
border: 1px solid transparent;
|
|
32
|
+
border-radius: var(--fs-pagination-radius, var(--size-1));
|
|
33
|
+
text-decoration: none;
|
|
34
|
+
cursor: pointer;
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
.fs-pagination a:hover,
|
|
38
|
+
.fs-pagination button:hover:not(:disabled) {
|
|
39
|
+
background: var(--semantic-interactive-background);
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
.fs-pagination a:focus-visible,
|
|
43
|
+
.fs-pagination button:focus-visible {
|
|
44
|
+
outline: 2px solid var(--semantic-interactive-main);
|
|
45
|
+
outline-offset: 2px;
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
.fs-pagination [aria-current="page"] {
|
|
49
|
+
color: var(--semantic-interactive-contrast);
|
|
50
|
+
background: var(--semantic-interactive-main);
|
|
51
|
+
border-color: var(--semantic-interactive-main);
|
|
52
|
+
font-weight: 600;
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
.fs-pagination button:disabled,
|
|
56
|
+
.fs-pagination [aria-disabled="true"] {
|
|
57
|
+
color: var(--semantic-disabled-foreground);
|
|
58
|
+
cursor: not-allowed;
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
/* Hoppet i nummerrekken, som «1 2 … 9 10». */
|
|
62
|
+
.fs-pagination__gap {
|
|
63
|
+
display: inline-flex;
|
|
64
|
+
align-items: center;
|
|
65
|
+
justify-content: center;
|
|
66
|
+
min-inline-size: var(--fs-pagination-size, var(--size-10));
|
|
67
|
+
color: var(--semantic-muted-foreground);
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
/* Høykontrast: gjeldende side skilles bare med farge. */
|
|
71
|
+
@media (forced-colors: active) {
|
|
72
|
+
.fs-pagination [aria-current="page"] {
|
|
73
|
+
background-color: Highlight;
|
|
74
|
+
color: HighlightText;
|
|
75
|
+
}
|
|
76
|
+
}
|
|
77
|
+
}
|
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
import { attributes } from "../shared.js"
|
|
2
|
+
|
|
3
|
+
export const PAGINATION_CLASS = "fs-pagination" as const
|
|
4
|
+
/** Hoppet i nummerrekken, som «1 2 … 9 10». */
|
|
5
|
+
export const PAGINATION_GAP_CLASS = "fs-pagination__gap" as const
|
|
6
|
+
|
|
7
|
+
export type PaginationAttributes = {
|
|
8
|
+
class: typeof PAGINATION_CLASS
|
|
9
|
+
}
|
|
10
|
+
|
|
11
|
+
/**
|
|
12
|
+
* Attributtene for sidenavigering.
|
|
13
|
+
*
|
|
14
|
+
* Klassen hører på en `<ul>` inne i en `<nav aria-label="Sidenavigering">`.
|
|
15
|
+
* Hver side er en lenke med egen adresse, ikke en knapp: da kan brukeren
|
|
16
|
+
* åpne side tre i ny fane, og komme tilbake med tilbakeknappen.
|
|
17
|
+
*
|
|
18
|
+
* Gjeldende side markeres med `aria-current="page"`, som både gir fargen og
|
|
19
|
+
* er det skjermleseren leser opp.
|
|
20
|
+
*
|
|
21
|
+
* ```ts
|
|
22
|
+
* <nav aria-label="Sidenavigering">
|
|
23
|
+
* <ul {...pagination()}>…</ul>
|
|
24
|
+
* </nav>
|
|
25
|
+
* ```
|
|
26
|
+
*/
|
|
27
|
+
export const pagination = Object.assign(
|
|
28
|
+
(): PaginationAttributes => attributes({ class: PAGINATION_CLASS }),
|
|
29
|
+
{
|
|
30
|
+
/** Klassen på hoppet i nummerrekken. */
|
|
31
|
+
gap: PAGINATION_GAP_CLASS,
|
|
32
|
+
},
|
|
33
|
+
)
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
@layer fristil {
|
|
2
|
+
.fs-paragraph {
|
|
3
|
+
margin: 0;
|
|
4
|
+
font-family: inherit;
|
|
5
|
+
font-size: var(--font-size-m);
|
|
6
|
+
line-height: 1.6;
|
|
7
|
+
color: var(--semantic-page-foreground);
|
|
8
|
+
/* Under 75 tegn per linje. Lengre linjer gjør det vanskelig å finne
|
|
9
|
+
tilbake til starten av neste. */
|
|
10
|
+
max-inline-size: var(--fs-paragraph-width, 70ch);
|
|
11
|
+
}
|
|
12
|
+
|
|
13
|
+
.fs-paragraph + .fs-paragraph {
|
|
14
|
+
margin-block-start: var(--fs-paragraph-gap, var(--size-3));
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
.fs-paragraph[data-size="small"] {
|
|
18
|
+
font-size: var(--font-size-s);
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
.fs-paragraph[data-size="large"] {
|
|
22
|
+
font-size: var(--font-size-l);
|
|
23
|
+
line-height: 1.55;
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
.fs-paragraph[data-variant="lead"] {
|
|
27
|
+
font-size: var(--font-size-l);
|
|
28
|
+
line-height: 1.55;
|
|
29
|
+
color: var(--semantic-muted-foreground);
|
|
30
|
+
}
|
|
31
|
+
}
|