@mattilsynet/design 3.2.9 → 3.3.1
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/mtds/ai/AGENTS.md +892 -0
- package/mtds/ai/alert.mdx +63 -0
- package/mtds/ai/alert.stories.tsx +128 -0
- package/mtds/ai/analytics.mdx +185 -0
- package/mtds/ai/app.mdx +60 -0
- package/mtds/ai/app.stories.tsx +897 -0
- package/mtds/ai/atlas.mdx +82 -0
- package/mtds/ai/atlas.stories.tsx +424 -0
- package/mtds/ai/avatar.mdx +45 -0
- package/mtds/ai/avatar.stories.tsx +109 -0
- package/mtds/ai/badge.mdx +70 -0
- package/mtds/ai/badge.stories.tsx +122 -0
- package/mtds/ai/breadcrumbs.mdx +36 -0
- package/mtds/ai/breadcrumbs.stories.tsx +158 -0
- package/mtds/ai/button.mdx +179 -0
- package/mtds/ai/button.stories.tsx +440 -0
- package/mtds/ai/card.mdx +51 -0
- package/mtds/ai/card.stories.tsx +469 -0
- package/mtds/ai/chart.mdx +67 -0
- package/mtds/ai/chart.stories.tsx +519 -0
- package/mtds/ai/chip.mdx +71 -0
- package/mtds/ai/chip.stories.tsx +211 -0
- package/mtds/ai/details.mdx +33 -0
- package/mtds/ai/details.stories.tsx +91 -0
- package/mtds/ai/dialog.mdx +38 -0
- package/mtds/ai/dialog.stories.tsx +373 -0
- package/mtds/ai/divider.mdx +19 -0
- package/mtds/ai/divider.stories.tsx +50 -0
- package/mtds/ai/errorsummary.mdx +26 -0
- package/mtds/ai/errorsummary.stories.tsx +137 -0
- package/mtds/ai/field.mdx +86 -0
- package/mtds/ai/field.stories.tsx +863 -0
- package/mtds/ai/fieldset.mdx +126 -0
- package/mtds/ai/fieldset.stories.tsx +298 -0
- package/mtds/ai/fileupload.mdx +16 -0
- package/mtds/ai/fileupload.stories.tsx +126 -0
- package/mtds/ai/helptext.mdx +24 -0
- package/mtds/ai/helptext.stories.tsx +106 -0
- package/mtds/ai/input.mdx +223 -0
- package/mtds/ai/input.stories.tsx +352 -0
- package/mtds/ai/law.mdx +115 -0
- package/mtds/ai/law.stories.tsx +168 -0
- package/mtds/ai/layout.mdx +145 -0
- package/mtds/ai/layout.stories.tsx +443 -0
- package/mtds/ai/link.mdx +45 -0
- package/mtds/ai/link.stories.tsx +44 -0
- package/mtds/ai/logo.mdx +86 -0
- package/mtds/ai/logo.stories.tsx +146 -0
- package/mtds/ai/pagination.mdx +136 -0
- package/mtds/ai/pagination.stories.tsx +404 -0
- package/mtds/ai/popover.mdx +86 -0
- package/mtds/ai/popover.stories.tsx +355 -0
- package/mtds/ai/print.mdx +96 -0
- package/mtds/ai/print.stories.tsx +839 -0
- package/mtds/ai/progress.mdx +41 -0
- package/mtds/ai/progress.stories.tsx +141 -0
- package/mtds/ai/skeleton.mdx +26 -0
- package/mtds/ai/skeleton.stories.tsx +131 -0
- package/mtds/ai/spinner.mdx +26 -0
- package/mtds/ai/spinner.stories.tsx +72 -0
- package/mtds/ai/steps.mdx +37 -0
- package/mtds/ai/steps.stories.tsx +568 -0
- package/mtds/ai/table.mdx +124 -0
- package/mtds/ai/table.stories.tsx +1715 -0
- package/mtds/ai/tabs.mdx +106 -0
- package/mtds/ai/tabs.stories.tsx +159 -0
- package/mtds/ai/tag.mdx +49 -0
- package/mtds/ai/tag.stories.tsx +111 -0
- package/mtds/ai/toast.mdx +67 -0
- package/mtds/ai/toast.stories.tsx +215 -0
- package/mtds/ai/togglegroup.mdx +75 -0
- package/mtds/ai/togglegroup.stories.tsx +96 -0
- package/mtds/ai/tooltip.mdx +32 -0
- package/mtds/ai/tooltip.stories.tsx +34 -0
- package/mtds/ai/typography.mdx +67 -0
- package/mtds/ai/typography.stories.tsx +798 -0
- package/mtds/ai/validation.mdx +19 -0
- package/mtds/ai/validation.stories.tsx +45 -0
- package/mtds/app/app-observer.js +1 -1
- package/mtds/app/app-toggle.js +10 -26
- package/mtds/app/app-toggle.js.map +1 -1
- package/mtds/app/app-toggle2.js +26 -10
- package/mtds/app/app-toggle2.js.map +1 -1
- package/mtds/app/app.js +1 -1
- package/mtds/atlas/atlas-element.js +1 -1
- package/mtds/chart/chart-lines.js +19 -19
- package/mtds/chart/chart-lines.js.map +1 -1
- package/mtds/chart/chart.css.js +16 -1
- package/mtds/chart/chart.css.js.map +1 -1
- package/mtds/chart/chart.stories.d.ts +1 -0
- package/mtds/index.iife.js +32 -17
- package/mtds/index.js +21 -20
- package/mtds/index.js.map +1 -1
- package/mtds/package.json.js +1 -1
- package/mtds/styles.css +1 -1
- package/mtds/table/table-observer.js +26 -15
- package/mtds/table/table-observer.js.map +1 -1
- package/package.json +4 -2
|
@@ -0,0 +1,126 @@
|
|
|
1
|
+
import { Meta, Canvas } from '@storybook/addon-docs/blocks';
|
|
2
|
+
import { Example, CssVariables } from '../../.storybook/blocks';
|
|
3
|
+
import * as stories from './fieldset.stories';
|
|
4
|
+
import { Flex, Grid } from '../react';
|
|
5
|
+
import styles from '../styles.module.css';
|
|
6
|
+
|
|
7
|
+
<Meta of={stories} />
|
|
8
|
+
|
|
9
|
+
# Fieldset
|
|
10
|
+
>Fieldset brukes til å gruppere og navngi felt som naturlig hører sammen, for eksempel datofelt eller adressefelt. Komponenten hjelper med å organisere informasjon, gjøre skjemaer mer oversiktlige og forbedre tilgjengeligheten for skjermlesere.
|
|
11
|
+
|
|
12
|
+
## Kode
|
|
13
|
+
- Legg klassen `fieldset` på `<fieldset>` rundt `<legend>` og skjemafelter
|
|
14
|
+
- Dette grupperer typisk `checkbox` eller `radio` inputs
|
|
15
|
+
<Canvas of={stories.Radios} />
|
|
16
|
+
|
|
17
|
+
## Skikk og bruk
|
|
18
|
+
<Flex data-items="350">
|
|
19
|
+
{/* Vertikal vs horisontal alignment: */}
|
|
20
|
+
<Example data-color="success" text="Radiobutton- og checkboxgrupper skal i hovedsak stables vertikalt slik at alternativene er lette å lese." zoom="100%">
|
|
21
|
+
<div className={styles.grid}>
|
|
22
|
+
<label>Velg dyregruppe</label>
|
|
23
|
+
<ds-field className={styles.field}>
|
|
24
|
+
<label>Fisk</label>
|
|
25
|
+
<input type="radio" className={styles.input} name="my-radio" defaultChecked />
|
|
26
|
+
</ds-field>
|
|
27
|
+
<ds-field className={styles.field}>
|
|
28
|
+
<label>Fjørfe</label>
|
|
29
|
+
<input type="radio" className={styles.input} name="my-radio" />
|
|
30
|
+
</ds-field>
|
|
31
|
+
<ds-field className={styles.field}>
|
|
32
|
+
<label>Storfe</label>
|
|
33
|
+
<input type="radio" className={styles.input} name="my-radio" />
|
|
34
|
+
</ds-field>
|
|
35
|
+
</div>
|
|
36
|
+
</Example>
|
|
37
|
+
<Example data-color="danger" text="Radiobutton- og checkboxgrupper bør ikke legges etter hverandre. Da er det vanskeligere skanne innholdet" zoom="100%">
|
|
38
|
+
<div className={styles.grid}>
|
|
39
|
+
<label>Velg dyregruppe</label>
|
|
40
|
+
<Flex data-gap="10">
|
|
41
|
+
<ds-field className={styles.field}>
|
|
42
|
+
<label>Fisk</label>
|
|
43
|
+
<input type="radio" className={styles.input} name="my-radio" defaultChecked />
|
|
44
|
+
</ds-field>
|
|
45
|
+
<ds-field className={styles.field}>
|
|
46
|
+
<label>Fjørfe</label>
|
|
47
|
+
<input type="radio" className={styles.input} name="my-radio" />
|
|
48
|
+
</ds-field>
|
|
49
|
+
<ds-field className={styles.field}>
|
|
50
|
+
<label>Storfe</label>
|
|
51
|
+
<input type="radio" className={styles.input} name="my-radio" />
|
|
52
|
+
</ds-field>
|
|
53
|
+
</Flex>
|
|
54
|
+
</div>
|
|
55
|
+
</Example>
|
|
56
|
+
|
|
57
|
+
{/* Label + Input: */}
|
|
58
|
+
<Example data-color="success" text="Input, radiobutton- og checkboxgrupper skal alltid ha en tydelig label." zoom="100%">
|
|
59
|
+
<div className={styles.grid}>
|
|
60
|
+
<label>Velg størrelse</label>
|
|
61
|
+
<ds-field className={styles.field}>
|
|
62
|
+
<label>Liten</label>
|
|
63
|
+
<input type="radio" className={styles.input} name="my-radio" defaultChecked />
|
|
64
|
+
</ds-field>
|
|
65
|
+
<ds-field className={styles.field}>
|
|
66
|
+
<label>Medium</label>
|
|
67
|
+
<input type="radio" className={styles.input} name="my-radio" />
|
|
68
|
+
</ds-field>
|
|
69
|
+
<ds-field className={styles.field}>
|
|
70
|
+
<label>Stor</label>
|
|
71
|
+
<input type="radio" className={styles.input} name="my-radio" />
|
|
72
|
+
</ds-field>
|
|
73
|
+
</div>
|
|
74
|
+
</Example>
|
|
75
|
+
|
|
76
|
+
<Example data-color="danger" text="Uten en label kan alternativene være vanskelige eller umulige å forstå." zoom="100%">
|
|
77
|
+
<Grid>
|
|
78
|
+
<ds-field className={styles.field}>
|
|
79
|
+
<label>Liten</label>
|
|
80
|
+
<input type="radio" className={styles.input} name="my-radio" defaultChecked />
|
|
81
|
+
</ds-field>
|
|
82
|
+
<ds-field className={styles.field}>
|
|
83
|
+
<label>Medium</label>
|
|
84
|
+
<input type="radio" className={styles.input} name="my-radio" />
|
|
85
|
+
</ds-field>
|
|
86
|
+
<ds-field className={styles.field}>
|
|
87
|
+
<label>Stor</label>
|
|
88
|
+
<input type="radio" className={styles.input} name="my-radio" />
|
|
89
|
+
</ds-field>
|
|
90
|
+
</Grid>
|
|
91
|
+
</Example>
|
|
92
|
+
</Flex>
|
|
93
|
+
|
|
94
|
+
## Obligatoriske felter
|
|
95
|
+
- Dersom alle skjemafelter er påkrevd, vises dette automatisk i `<legend>`
|
|
96
|
+
- Teksten `Må fylles ut` oversettes automatisk til `Required` dersom du setter `<html lang="en">`. Du kan også selv endre tekst med CSS custom property: `--mtds-text-required: "Må fylles ut";`
|
|
97
|
+
- **Merk:** Dersom du ønsker å skru denne [lovpålagte merkingen av obligatoriske felter](https://www.designsystemet.no/monstre/obligatoriske-og-valgfrie-felt), kan du legge `data-required="hidden"` på hvilket som helst element (f.eks. `<html data-required="hidden">` for å skru av for hele dokumentet)
|
|
98
|
+
<Canvas of={stories.Radios} />
|
|
99
|
+
|
|
100
|
+
## Innebygget skjemavalidering
|
|
101
|
+
- Nettleserens innebyggede valideringsmeldinger skjules pga. begrenset styling og universell utforming
|
|
102
|
+
- Du kan allikevel få [nettleserens innebygge skjemavalidering](https://developer.mozilla.org/en-US/docs/Learn_web_development/Extensions/Forms/Form_validation#using_built-in_form_validation) til å automatisk skjule og vise [validation-komponentet](?path=/docs/designsystem-validation--docs) ved å legge `data-validation="form"` på `fieldset`
|
|
103
|
+
- **Merk:** Legg du vil vise valideringsmelding ved hvert input-element, må `data-validation="form"` legges på hvert enkelt `field`
|
|
104
|
+
<Canvas of={stories.WithValidationForm} />
|
|
105
|
+
|
|
106
|
+
## Checkboxes
|
|
107
|
+
<Canvas of={stories.Checkboxes} />
|
|
108
|
+
|
|
109
|
+
## Disabled
|
|
110
|
+
- Legg attributten `disabled` rett på `fieldset`
|
|
111
|
+
<Canvas of={stories.Disabled} />
|
|
112
|
+
|
|
113
|
+
## Read only
|
|
114
|
+
- Legg attributten `readonly disabled` på hver `input`
|
|
115
|
+
<Canvas of={stories.ReadOnly} />
|
|
116
|
+
|
|
117
|
+
{/* ## Horisontal NOT RECOMMENDED
|
|
118
|
+
- Legg attributten `field` inni en `flex` med `data-gap="9"`
|
|
119
|
+
- Brukes kun ved få svaralternativer
|
|
120
|
+
<Canvas of={stories.Horizontal} /> */}
|
|
121
|
+
|
|
122
|
+
## Feilmelding
|
|
123
|
+
- Legg klassen `validation` på et direkte barn for å knytte feilmelding til alle inputs
|
|
124
|
+
<Canvas of={stories.WithValidation} />
|
|
125
|
+
|
|
126
|
+
<CssVariables component="fieldset" />
|
|
@@ -0,0 +1,298 @@
|
|
|
1
|
+
import type { Meta, StoryObj } from "@storybook/react-vite";
|
|
2
|
+
import { Field, Fieldset } from "../react";
|
|
3
|
+
import styles from "../styles.module.css";
|
|
4
|
+
|
|
5
|
+
const meta = {
|
|
6
|
+
title: "Designsystem/Fieldset",
|
|
7
|
+
} satisfies Meta;
|
|
8
|
+
|
|
9
|
+
export default meta;
|
|
10
|
+
type Story = StoryObj<typeof meta>;
|
|
11
|
+
|
|
12
|
+
export const React: Story = {
|
|
13
|
+
render: () => (
|
|
14
|
+
<Fieldset>
|
|
15
|
+
<Fieldset.Legend>Hva foretrekker du?</Fieldset.Legend>
|
|
16
|
+
<Fieldset.Description>Fellesbeskrivelse</Fieldset.Description>
|
|
17
|
+
<Field
|
|
18
|
+
as="input"
|
|
19
|
+
defaultChecked
|
|
20
|
+
description="Beskrivelse"
|
|
21
|
+
label="Alternativ 1"
|
|
22
|
+
name="my-react-radio"
|
|
23
|
+
required
|
|
24
|
+
type="radio"
|
|
25
|
+
/>
|
|
26
|
+
<Field
|
|
27
|
+
as="input"
|
|
28
|
+
label="Alternativ 2"
|
|
29
|
+
name="my-react-radio"
|
|
30
|
+
required
|
|
31
|
+
type="radio"
|
|
32
|
+
/>
|
|
33
|
+
</Fieldset>
|
|
34
|
+
),
|
|
35
|
+
};
|
|
36
|
+
|
|
37
|
+
export const Radios: Story = {
|
|
38
|
+
parameters: {
|
|
39
|
+
showInOverview: true,
|
|
40
|
+
},
|
|
41
|
+
render: () => (
|
|
42
|
+
<fieldset className={styles.fieldset}>
|
|
43
|
+
<legend>Hva foretrekker du?</legend>
|
|
44
|
+
<p data-field="description">Fellesbeskrivelse</p>
|
|
45
|
+
<ds-field className={styles.field}>
|
|
46
|
+
<input
|
|
47
|
+
type="radio"
|
|
48
|
+
className={styles.input}
|
|
49
|
+
name="my-radio"
|
|
50
|
+
required
|
|
51
|
+
defaultChecked
|
|
52
|
+
/>
|
|
53
|
+
<label>Alternativ 1</label>
|
|
54
|
+
<p data-field="description">Beskrivelse</p>
|
|
55
|
+
</ds-field>
|
|
56
|
+
<ds-field className={styles.field}>
|
|
57
|
+
<input type="radio" className={styles.input} name="my-radio" required />
|
|
58
|
+
<label>Alternativ 2</label>
|
|
59
|
+
<p data-field="description">Beskrivelse</p>
|
|
60
|
+
</ds-field>
|
|
61
|
+
</fieldset>
|
|
62
|
+
),
|
|
63
|
+
};
|
|
64
|
+
|
|
65
|
+
export const Checkboxes: Story = {
|
|
66
|
+
parameters: {
|
|
67
|
+
showInOverview: true,
|
|
68
|
+
},
|
|
69
|
+
render: () => (
|
|
70
|
+
<fieldset className={styles.fieldset}>
|
|
71
|
+
<legend>Hvilke foretrekker du?</legend>
|
|
72
|
+
<p data-field="description">Fellesbeskrivelse</p>
|
|
73
|
+
<ds-field className={styles.field}>
|
|
74
|
+
<input
|
|
75
|
+
type="checkbox"
|
|
76
|
+
className={styles.input}
|
|
77
|
+
name="my-check"
|
|
78
|
+
defaultChecked
|
|
79
|
+
/>
|
|
80
|
+
<label>Alternativ 1</label>
|
|
81
|
+
</ds-field>
|
|
82
|
+
<ds-field className={styles.field}>
|
|
83
|
+
<input type="checkbox" className={styles.input} name="my-check" />
|
|
84
|
+
<label>Alternativ 2</label>
|
|
85
|
+
</ds-field>
|
|
86
|
+
</fieldset>
|
|
87
|
+
),
|
|
88
|
+
};
|
|
89
|
+
|
|
90
|
+
export const Disabled: Story = {
|
|
91
|
+
render: () => (
|
|
92
|
+
<fieldset className={styles.fieldset} disabled>
|
|
93
|
+
<legend>Hvilke foretrekker du?</legend>
|
|
94
|
+
<p data-field="description">Fellesbeskrivelse</p>
|
|
95
|
+
<ds-field className={styles.field}>
|
|
96
|
+
<input
|
|
97
|
+
type="checkbox"
|
|
98
|
+
className={styles.input}
|
|
99
|
+
name="my-check"
|
|
100
|
+
defaultChecked
|
|
101
|
+
/>
|
|
102
|
+
<label>Alternativ 1</label>
|
|
103
|
+
</ds-field>
|
|
104
|
+
<ds-field className={styles.field}>
|
|
105
|
+
<input type="checkbox" className={styles.input} name="my-check" />
|
|
106
|
+
<label>Alternativ 2</label>
|
|
107
|
+
</ds-field>
|
|
108
|
+
</fieldset>
|
|
109
|
+
),
|
|
110
|
+
};
|
|
111
|
+
|
|
112
|
+
export const ReadOnly: Story = {
|
|
113
|
+
render: () => (
|
|
114
|
+
<fieldset className={styles.fieldset}>
|
|
115
|
+
<legend>Hvilke foretrekker du?</legend>
|
|
116
|
+
<p data-field="description">Fellesbeskrivelse</p>
|
|
117
|
+
<ds-field className={styles.field}>
|
|
118
|
+
<input
|
|
119
|
+
type="checkbox"
|
|
120
|
+
className={styles.input}
|
|
121
|
+
name="my-check"
|
|
122
|
+
defaultChecked
|
|
123
|
+
readOnly
|
|
124
|
+
disabled
|
|
125
|
+
/>
|
|
126
|
+
<label>Alternativ 1</label>
|
|
127
|
+
</ds-field>
|
|
128
|
+
<ds-field className={styles.field}>
|
|
129
|
+
<input
|
|
130
|
+
type="checkbox"
|
|
131
|
+
className={styles.input}
|
|
132
|
+
name="my-check"
|
|
133
|
+
readOnly
|
|
134
|
+
disabled
|
|
135
|
+
/>
|
|
136
|
+
<label>Alternativ 2</label>
|
|
137
|
+
</ds-field>
|
|
138
|
+
</fieldset>
|
|
139
|
+
),
|
|
140
|
+
};
|
|
141
|
+
|
|
142
|
+
export const Horizontal: Story = {
|
|
143
|
+
render: () => (
|
|
144
|
+
<fieldset className={styles.fieldset}>
|
|
145
|
+
<legend>Hvilke foretrekker du?</legend>
|
|
146
|
+
<p data-field="description">Fellesbeskrivelse</p>
|
|
147
|
+
<div className={styles.flex} data-gap="9">
|
|
148
|
+
<ds-field className={styles.field}>
|
|
149
|
+
<input
|
|
150
|
+
type="checkbox"
|
|
151
|
+
className={styles.input}
|
|
152
|
+
name="my-check"
|
|
153
|
+
defaultChecked
|
|
154
|
+
/>
|
|
155
|
+
<label>Alternativ 1</label>
|
|
156
|
+
</ds-field>
|
|
157
|
+
<ds-field className={styles.field}>
|
|
158
|
+
<input type="checkbox" className={styles.input} name="my-check" />
|
|
159
|
+
<label>Alternativ 2</label>
|
|
160
|
+
</ds-field>
|
|
161
|
+
</div>
|
|
162
|
+
</fieldset>
|
|
163
|
+
),
|
|
164
|
+
};
|
|
165
|
+
|
|
166
|
+
export const WithValidation: Story = {
|
|
167
|
+
parameters: {
|
|
168
|
+
showInOverview: true,
|
|
169
|
+
},
|
|
170
|
+
render: () => (
|
|
171
|
+
<fieldset className={styles.fieldset}>
|
|
172
|
+
<legend>Hvilke foretrekker du?</legend>
|
|
173
|
+
<p data-field="description">Fellesbeskrivelse</p>
|
|
174
|
+
<ds-field className={styles.field}>
|
|
175
|
+
<input
|
|
176
|
+
type="checkbox"
|
|
177
|
+
className={styles.input}
|
|
178
|
+
name="my-check"
|
|
179
|
+
defaultChecked
|
|
180
|
+
/>
|
|
181
|
+
<label>Alternativ 1</label>
|
|
182
|
+
<p data-field="description">Beskrivelse</p>
|
|
183
|
+
</ds-field>
|
|
184
|
+
<ds-field className={styles.field}>
|
|
185
|
+
<input type="checkbox" className={styles.input} name="my-check" />
|
|
186
|
+
<label>Alternativ 2</label>
|
|
187
|
+
</ds-field>
|
|
188
|
+
<div className={styles.validation} data-field="validation">
|
|
189
|
+
Feilmelding
|
|
190
|
+
</div>
|
|
191
|
+
</fieldset>
|
|
192
|
+
),
|
|
193
|
+
};
|
|
194
|
+
|
|
195
|
+
export const WithValidationForm: Story = {
|
|
196
|
+
parameters: {
|
|
197
|
+
showInOverview: true,
|
|
198
|
+
},
|
|
199
|
+
render: () => (
|
|
200
|
+
<form action="#" className={styles.prose} data-validation="form">
|
|
201
|
+
<fieldset className={styles.fieldset}>
|
|
202
|
+
<legend>Hvilke foretrekker du?</legend>
|
|
203
|
+
<ds-field className={styles.field}>
|
|
204
|
+
<input
|
|
205
|
+
type="checkbox"
|
|
206
|
+
className={styles.input}
|
|
207
|
+
name="my-check-validation"
|
|
208
|
+
required
|
|
209
|
+
/>
|
|
210
|
+
<label>Checkbox 1</label>
|
|
211
|
+
<div className={styles.validation} data-field="validation" hidden>
|
|
212
|
+
Feilmelding 1
|
|
213
|
+
</div>
|
|
214
|
+
</ds-field>
|
|
215
|
+
<ds-field className={styles.field}>
|
|
216
|
+
<input
|
|
217
|
+
type="checkbox"
|
|
218
|
+
className={styles.input}
|
|
219
|
+
name="my-check-validation"
|
|
220
|
+
required
|
|
221
|
+
/>
|
|
222
|
+
<label>Checkbox 2</label>
|
|
223
|
+
<div className={styles.validation} data-field="validation" hidden>
|
|
224
|
+
Feilmelding 2
|
|
225
|
+
</div>
|
|
226
|
+
</ds-field>
|
|
227
|
+
<div className={styles.validation} data-field="validation" hidden>
|
|
228
|
+
Feilmelding
|
|
229
|
+
</div>
|
|
230
|
+
</fieldset>
|
|
231
|
+
<fieldset className={styles.fieldset}>
|
|
232
|
+
<legend>Hvilke foretrekker du?</legend>
|
|
233
|
+
<ds-field className={styles.field}>
|
|
234
|
+
<input
|
|
235
|
+
type="radio"
|
|
236
|
+
className={styles.input}
|
|
237
|
+
name="my-radio-validation"
|
|
238
|
+
required
|
|
239
|
+
/>
|
|
240
|
+
<label>Radio 1</label>
|
|
241
|
+
<div className={styles.validation} data-field="validation" hidden>
|
|
242
|
+
Feilmelding 1
|
|
243
|
+
</div>
|
|
244
|
+
</ds-field>
|
|
245
|
+
<ds-field className={styles.field}>
|
|
246
|
+
<input
|
|
247
|
+
type="radio"
|
|
248
|
+
className={styles.input}
|
|
249
|
+
name="my-radio-validation"
|
|
250
|
+
required
|
|
251
|
+
/>
|
|
252
|
+
<label>Radio 2</label>
|
|
253
|
+
<div className={styles.validation} data-field="validation" hidden>
|
|
254
|
+
Feilmelding 2
|
|
255
|
+
</div>
|
|
256
|
+
</ds-field>
|
|
257
|
+
<div className={styles.validation} data-field="validation" hidden>
|
|
258
|
+
Feilmelding
|
|
259
|
+
</div>
|
|
260
|
+
</fieldset>
|
|
261
|
+
|
|
262
|
+
<button type="submit" className={styles.button} data-variant="primary">
|
|
263
|
+
Send inn
|
|
264
|
+
</button>
|
|
265
|
+
</form>
|
|
266
|
+
),
|
|
267
|
+
};
|
|
268
|
+
|
|
269
|
+
export const WithTexts: Story = {
|
|
270
|
+
parameters: {
|
|
271
|
+
showInOverview: true,
|
|
272
|
+
},
|
|
273
|
+
render: () => (
|
|
274
|
+
<fieldset className={styles.fieldset}>
|
|
275
|
+
<legend>Hva heter du?</legend>
|
|
276
|
+
<div className={styles.grid} data-items="200" data-fixed>
|
|
277
|
+
<ds-field className={styles.field}>
|
|
278
|
+
<input
|
|
279
|
+
aria-label="Fornavn"
|
|
280
|
+
placeholder="Fornavn"
|
|
281
|
+
className={styles.input}
|
|
282
|
+
name="fornavn"
|
|
283
|
+
type="text"
|
|
284
|
+
/>
|
|
285
|
+
</ds-field>
|
|
286
|
+
<ds-field className={styles.field}>
|
|
287
|
+
<input
|
|
288
|
+
aria-label="Etternavn"
|
|
289
|
+
placeholder="Etternavn"
|
|
290
|
+
className={styles.input}
|
|
291
|
+
name="etternavn"
|
|
292
|
+
type="text"
|
|
293
|
+
/>
|
|
294
|
+
</ds-field>
|
|
295
|
+
</div>
|
|
296
|
+
</fieldset>
|
|
297
|
+
),
|
|
298
|
+
};
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
import { Meta, Canvas } from '@storybook/addon-docs/blocks';
|
|
2
|
+
import { Example, CssVariables } from '../../.storybook/blocks';
|
|
3
|
+
import * as stories from './fileupload.stories';
|
|
4
|
+
import { Flex, Grid } from '../react';
|
|
5
|
+
import styles from '../styles.module.css';
|
|
6
|
+
|
|
7
|
+
<Meta of={stories} />
|
|
8
|
+
|
|
9
|
+
# Fileupload (Eksperimentell)
|
|
10
|
+
|
|
11
|
+
## Kode
|
|
12
|
+
- Legg klassen `fileupload` på `<label>` rundt `<input type="file">`
|
|
13
|
+
- Du kan selv knytte til funkjonalitet med JavaScript
|
|
14
|
+
<Canvas of={stories.Default} />
|
|
15
|
+
|
|
16
|
+
<CssVariables component="fileupload" />
|
|
@@ -0,0 +1,126 @@
|
|
|
1
|
+
import { UploadIcon, XIcon } from "@phosphor-icons/react";
|
|
2
|
+
import type { Meta, StoryObj } from "@storybook/react-vite";
|
|
3
|
+
import { useState } from "react";
|
|
4
|
+
import { Button, Card, Fileupload, Flex, Grid } from "../react";
|
|
5
|
+
import styles from "../styles.module.css";
|
|
6
|
+
|
|
7
|
+
const meta = {
|
|
8
|
+
title: "Designsystem/Fileupload",
|
|
9
|
+
parameters: {
|
|
10
|
+
layout: "padded",
|
|
11
|
+
},
|
|
12
|
+
} satisfies Meta;
|
|
13
|
+
|
|
14
|
+
export default meta;
|
|
15
|
+
type Story = StoryObj<typeof meta>;
|
|
16
|
+
|
|
17
|
+
export const Default: Story = {
|
|
18
|
+
render: () => (
|
|
19
|
+
<label className={styles.fileupload}>
|
|
20
|
+
<UploadIcon />
|
|
21
|
+
<strong>Last opp filer</strong>
|
|
22
|
+
Dra over eller <u>last opp fil</u>
|
|
23
|
+
<small>
|
|
24
|
+
Støttede formater: PDF, JPEG, SVG
|
|
25
|
+
<br />
|
|
26
|
+
Filstørrelse under 10 MB
|
|
27
|
+
</small>
|
|
28
|
+
<input type="file" accept="image/*,.pdf" title="Last opp filer" />
|
|
29
|
+
</label>
|
|
30
|
+
),
|
|
31
|
+
};
|
|
32
|
+
|
|
33
|
+
export const React: Story = {
|
|
34
|
+
render: () => (
|
|
35
|
+
<Fileupload>
|
|
36
|
+
<UploadIcon />
|
|
37
|
+
<strong>Last opp filer</strong>
|
|
38
|
+
Dra over eller <u>last opp fil</u>
|
|
39
|
+
<small>
|
|
40
|
+
Støttede formater: PDF, JPEG, SVG
|
|
41
|
+
<br />
|
|
42
|
+
Filstørrelse under 10 MB
|
|
43
|
+
</small>
|
|
44
|
+
<input type="file" accept="image/*,.pdf" title="Last opp filer" />
|
|
45
|
+
</Fileupload>
|
|
46
|
+
),
|
|
47
|
+
};
|
|
48
|
+
|
|
49
|
+
export const Invalid: Story = {
|
|
50
|
+
render: () => (
|
|
51
|
+
<Fileupload aria-invalid="true">
|
|
52
|
+
<UploadIcon />
|
|
53
|
+
<strong>Last opp filer</strong>
|
|
54
|
+
Dra over eller <u>last opp fil</u>
|
|
55
|
+
<small>
|
|
56
|
+
Støttede formater: PDF, JPEG, SVG
|
|
57
|
+
<br />
|
|
58
|
+
Filstørrelse under 10 MB
|
|
59
|
+
</small>
|
|
60
|
+
<input type="file" accept="image/*,.pdf" title="Last opp filer" />
|
|
61
|
+
</Fileupload>
|
|
62
|
+
),
|
|
63
|
+
};
|
|
64
|
+
|
|
65
|
+
export const WithPreviewImage: Story = {
|
|
66
|
+
render: function Render() {
|
|
67
|
+
const [images, setImages] = useState<{ title: string; src: string }[]>([]);
|
|
68
|
+
const handleFile = (event: React.ChangeEvent<HTMLInputElement>) => {
|
|
69
|
+
const file = event.target.files?.[0];
|
|
70
|
+
const reader = new FileReader();
|
|
71
|
+
reader.onload = () =>
|
|
72
|
+
setImages((prev) => [
|
|
73
|
+
...prev,
|
|
74
|
+
{
|
|
75
|
+
title: file?.name || "",
|
|
76
|
+
src: reader.result as string,
|
|
77
|
+
},
|
|
78
|
+
]);
|
|
79
|
+
if (file) reader.readAsDataURL(file);
|
|
80
|
+
event.target.value = ""; // Reset file input value to allow re-uploading the same file
|
|
81
|
+
};
|
|
82
|
+
|
|
83
|
+
const handleRemove = (index: number) =>
|
|
84
|
+
setImages((prev) => prev.filter((_, i) => i !== index));
|
|
85
|
+
|
|
86
|
+
return (
|
|
87
|
+
<Grid>
|
|
88
|
+
Velg et bilde for å se:
|
|
89
|
+
<Fileupload>
|
|
90
|
+
<UploadIcon />
|
|
91
|
+
<strong>Last opp filer</strong>
|
|
92
|
+
Dra over eller <u>last opp fil</u>
|
|
93
|
+
<small>
|
|
94
|
+
Støttede formater: PDF, JPEG, SVG
|
|
95
|
+
<br />
|
|
96
|
+
Filstørrelse under 10 MB
|
|
97
|
+
</small>
|
|
98
|
+
<input
|
|
99
|
+
type="file"
|
|
100
|
+
accept="image/jpeg, image/png, image/gif"
|
|
101
|
+
title="Last opp filer"
|
|
102
|
+
onChange={handleFile}
|
|
103
|
+
/>
|
|
104
|
+
</Fileupload>
|
|
105
|
+
<Grid data-items="300" data-fixed>
|
|
106
|
+
{images.map((file, index) => (
|
|
107
|
+
<Card as={Grid} key={index.toString()}>
|
|
108
|
+
<img alt="" width="100%" src={file.src} />
|
|
109
|
+
<Flex data-align="center" data-nowrap>
|
|
110
|
+
<strong>{file.title}</strong>
|
|
111
|
+
<Button
|
|
112
|
+
data-self="auto"
|
|
113
|
+
data-fixed
|
|
114
|
+
data-size="sm"
|
|
115
|
+
onClick={() => handleRemove(index)}
|
|
116
|
+
>
|
|
117
|
+
<XIcon />
|
|
118
|
+
</Button>
|
|
119
|
+
</Flex>
|
|
120
|
+
</Card>
|
|
121
|
+
))}
|
|
122
|
+
</Grid>
|
|
123
|
+
</Grid>
|
|
124
|
+
);
|
|
125
|
+
},
|
|
126
|
+
};
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
import { Meta, Canvas } from '@storybook/addon-docs/blocks';
|
|
2
|
+
import { CssVariables } from '../../.storybook/blocks';
|
|
3
|
+
import * as stories from './helptext.stories';
|
|
4
|
+
|
|
5
|
+
<Meta of={stories} />
|
|
6
|
+
|
|
7
|
+
# Help text
|
|
8
|
+
>HelpText gir brukere en forklaring på ukjente begreper eller konsepter, hvis de trenger det.
|
|
9
|
+
|
|
10
|
+
## Kode
|
|
11
|
+
- **Merk:** Prøv å [unngå å bruke HelpText](https://www.designsystemet.no/no/blog/helptext-is-being-removed-what-should-you-do) - vurder heller [popover inline](?path=/story/designsystem-popover--with-text-inline)
|
|
12
|
+
- Bruk klassen `helptext` på `<button>` og `popovertarget="MIN-ID"`
|
|
13
|
+
- Legg klassen `popover`, attributten `popover` og `id` på `<div>` direkte etter `<button>`
|
|
14
|
+
<Canvas of={stories.Default} />
|
|
15
|
+
|
|
16
|
+
## I field
|
|
17
|
+
- Legg `helptext` like etter `label` i `field`
|
|
18
|
+
<Canvas of={stories.InField} />
|
|
19
|
+
|
|
20
|
+
## I fieldset
|
|
21
|
+
- Legg `helptext` like etter `legend` i `field`
|
|
22
|
+
<Canvas of={stories.InFieldset} />
|
|
23
|
+
|
|
24
|
+
<CssVariables component="helptext" />
|
|
@@ -0,0 +1,106 @@
|
|
|
1
|
+
import type { Meta, StoryObj } from "@storybook/react-vite";
|
|
2
|
+
import { Field, Grid, HelpText, Input } from "../react";
|
|
3
|
+
import styles from "../styles.module.css";
|
|
4
|
+
|
|
5
|
+
const meta = {
|
|
6
|
+
title: "Designsystem/Help text",
|
|
7
|
+
} satisfies Meta;
|
|
8
|
+
|
|
9
|
+
export default meta;
|
|
10
|
+
type Story = StoryObj<typeof meta>;
|
|
11
|
+
|
|
12
|
+
export const Default: Story = {
|
|
13
|
+
render: () => (
|
|
14
|
+
<>
|
|
15
|
+
<button
|
|
16
|
+
type="button"
|
|
17
|
+
className={styles.helptext}
|
|
18
|
+
popoverTarget="my-helptext"
|
|
19
|
+
aria-label="Hva menes med mottaker"
|
|
20
|
+
></button>
|
|
21
|
+
<div className={styles.popover} id="my-helptext" popover="auto">
|
|
22
|
+
Tekst som forklarer hva som menes med mottaker
|
|
23
|
+
</div>
|
|
24
|
+
</>
|
|
25
|
+
),
|
|
26
|
+
};
|
|
27
|
+
|
|
28
|
+
export const InField: Story = {
|
|
29
|
+
render: () => (
|
|
30
|
+
<div className={styles.grid}>
|
|
31
|
+
<ds-field className={styles.field}>
|
|
32
|
+
<label>Ledetekst</label>
|
|
33
|
+
<button
|
|
34
|
+
type="button"
|
|
35
|
+
className={styles.helptext}
|
|
36
|
+
aria-label="Hva menes med mottaker"
|
|
37
|
+
popoverTarget="my-helptext-field"
|
|
38
|
+
></button>
|
|
39
|
+
<div className={styles.popover} id="my-helptext-field" popover="auto">
|
|
40
|
+
Tekst som forklarer hva som menes med mottaker
|
|
41
|
+
</div>
|
|
42
|
+
<p data-field="desciption">Beskrivelse</p>
|
|
43
|
+
<input type="text" className={styles.input} />
|
|
44
|
+
</ds-field>
|
|
45
|
+
<ds-field className={styles.field}>
|
|
46
|
+
<label>Ledetekst</label>
|
|
47
|
+
<button
|
|
48
|
+
type="button"
|
|
49
|
+
className={styles.helptext}
|
|
50
|
+
aria-label="Hva menes med mottaker"
|
|
51
|
+
popoverTarget="my-helptext-field"
|
|
52
|
+
></button>
|
|
53
|
+
<div className={styles.popover} id="my-helptext-field" popover="auto">
|
|
54
|
+
Tekst som forklarer hva som menes med mottaker
|
|
55
|
+
</div>
|
|
56
|
+
<p data-field="desciption">Beskrivelse</p>
|
|
57
|
+
<input type="text" className={styles.input} readOnly disabled />
|
|
58
|
+
</ds-field>
|
|
59
|
+
</div>
|
|
60
|
+
),
|
|
61
|
+
};
|
|
62
|
+
|
|
63
|
+
export const InFieldset: Story = {
|
|
64
|
+
render: () => (
|
|
65
|
+
<fieldset className={styles.fieldset}>
|
|
66
|
+
<legend>Legendtekst</legend>
|
|
67
|
+
<button
|
|
68
|
+
type="button"
|
|
69
|
+
className={styles.helptext}
|
|
70
|
+
aria-label="Hva menes med mottaker"
|
|
71
|
+
popoverTarget="my-helptext-fieldset"
|
|
72
|
+
></button>
|
|
73
|
+
<div className={styles.popover} id="my-helptext-fieldset" popover="auto">
|
|
74
|
+
Tekst som forklarer hva som menes med mottaker
|
|
75
|
+
</div>
|
|
76
|
+
<ds-field className={styles.field}>
|
|
77
|
+
<label>Labeltekst</label>
|
|
78
|
+
<input type="checkbox" className={styles.input} />
|
|
79
|
+
</ds-field>
|
|
80
|
+
</fieldset>
|
|
81
|
+
),
|
|
82
|
+
};
|
|
83
|
+
|
|
84
|
+
export const React: Story = {
|
|
85
|
+
render: () => (
|
|
86
|
+
<Grid data-gap="10">
|
|
87
|
+
<HelpText aria-label="Hva menes med mottaker">
|
|
88
|
+
Tekst som forklarer hva som menes med mottaker
|
|
89
|
+
</HelpText>
|
|
90
|
+
<Field>
|
|
91
|
+
<Field.Label>Ledetekst</Field.Label>
|
|
92
|
+
<HelpText aria-label="Hva menes med mottaker">
|
|
93
|
+
Tekst som forklarer hva som menes med mottaker
|
|
94
|
+
</HelpText>
|
|
95
|
+
<Field.Description>Beskrivelse</Field.Description>
|
|
96
|
+
<Input />
|
|
97
|
+
</Field>
|
|
98
|
+
<Field
|
|
99
|
+
as="input"
|
|
100
|
+
label="Ledetekst"
|
|
101
|
+
helpText="Tekst som forklarer hva som menes med mottaker"
|
|
102
|
+
helpTextLabel="Hva menes med mottaker"
|
|
103
|
+
/>
|
|
104
|
+
</Grid>
|
|
105
|
+
),
|
|
106
|
+
};
|