@ks-digital/designsystem-angular 0.0.1-alpha.23 → 0.0.1-alpha.25

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (109) hide show
  1. package/.storybook/customTheme.ts +15 -0
  2. package/.storybook/default-args.ts +18 -0
  3. package/.storybook/main.ts +27 -0
  4. package/.storybook/manager.ts +10 -0
  5. package/.storybook/preview-head.html +16 -0
  6. package/.storybook/preview.ts +70 -0
  7. package/.storybook/themes.ts +9 -0
  8. package/.storybook/tsconfig.json +16 -0
  9. package/.storybook/vite.config.mts +5 -0
  10. package/README.md +3 -3
  11. package/eslint.config.mjs +28 -0
  12. package/ng-package.json +9 -0
  13. package/package.json +18 -27
  14. package/project.json +81 -0
  15. package/src/components/alert/alert.mdx +46 -0
  16. package/src/components/alert/alert.spec.ts +33 -0
  17. package/src/components/alert/alert.stories.ts +138 -0
  18. package/src/components/alert/alert.ts +46 -0
  19. package/src/components/alert/index.ts +1 -0
  20. package/src/components/button/button.mdx +40 -0
  21. package/src/components/button/button.spec.ts +86 -0
  22. package/src/components/button/button.stories.ts +123 -0
  23. package/src/components/button/button.ts +60 -0
  24. package/src/components/button/index.ts +1 -0
  25. package/src/components/card/card-block.ts +10 -0
  26. package/src/components/card/card.mdx +100 -0
  27. package/src/components/card/card.spec.ts +70 -0
  28. package/src/components/card/card.stories.ts +101 -0
  29. package/src/components/card/card.ts +44 -0
  30. package/src/components/card/index.ts +2 -0
  31. package/src/components/checkbox/README.md +13 -0
  32. package/src/components/checkbox/checkbox.mdx +50 -0
  33. package/src/components/checkbox/checkbox.spec.ts +21 -0
  34. package/src/components/checkbox/checkbox.stories.ts +182 -0
  35. package/src/components/checkbox/index.ts +0 -0
  36. package/src/components/colors.ts +36 -0
  37. package/src/components/common-inputs.ts +30 -0
  38. package/src/components/details/controlled-details.ts +63 -0
  39. package/src/components/details/details-content.ts +7 -0
  40. package/src/components/details/details-summary.ts +7 -0
  41. package/src/components/details/details.mdx +89 -0
  42. package/src/components/details/details.spec.ts +56 -0
  43. package/src/components/details/details.stories.ts +129 -0
  44. package/src/components/details/details.ts +69 -0
  45. package/src/components/details/index.ts +3 -0
  46. package/src/components/field/field-counter.ts +56 -0
  47. package/src/components/field/field-description.ts +10 -0
  48. package/src/components/field/field-error.ts +13 -0
  49. package/src/components/field/field-observer.ts +121 -0
  50. package/src/components/field/field-state.ts +21 -0
  51. package/src/components/field/field.mdx +40 -0
  52. package/src/components/field/field.spec.ts +131 -0
  53. package/src/components/field/field.stories.ts +98 -0
  54. package/src/components/field/field.ts +70 -0
  55. package/src/components/field/index.ts +3 -0
  56. package/src/components/fieldset/fieldset-description.ts +8 -0
  57. package/src/components/fieldset/fieldset-legend.ts +11 -0
  58. package/src/components/fieldset/fieldset.spec.ts +80 -0
  59. package/src/components/fieldset/fieldset.ts +11 -0
  60. package/src/components/fieldset/index.ts +3 -0
  61. package/src/components/input/index.ts +1 -0
  62. package/src/components/input/input.mdx +11 -0
  63. package/src/components/input/input.spec.ts +25 -0
  64. package/src/components/input/input.stories.ts +72 -0
  65. package/src/components/input/input.ts +67 -0
  66. package/src/components/label/index.ts +1 -0
  67. package/src/components/label/label.ts +17 -0
  68. package/src/components/paragraph/index.ts +1 -0
  69. package/src/components/paragraph/paragraph.ts +10 -0
  70. package/src/components/popover/controlled-popover.ts +62 -0
  71. package/src/components/popover/index.ts +1 -0
  72. package/src/components/popover/popover.mdx +81 -0
  73. package/src/components/popover/popover.spec.ts +143 -0
  74. package/src/components/popover/popover.stories.ts +63 -0
  75. package/src/components/popover/popover.ts +186 -0
  76. package/src/components/radio/radio.mdx +117 -0
  77. package/src/components/radio/radio.stories.ts +226 -0
  78. package/src/components/search/index.ts +4 -0
  79. package/src/components/search/search-button.ts +35 -0
  80. package/src/components/search/search-clear.ts +57 -0
  81. package/src/components/search/search-input.ts +18 -0
  82. package/src/components/search/search.mdx +56 -0
  83. package/src/components/search/search.spec.ts +48 -0
  84. package/src/components/search/search.stories.ts +205 -0
  85. package/src/components/search/search.ts +50 -0
  86. package/src/components/spinner/index.ts +1 -0
  87. package/src/components/spinner/spinner.mdx +24 -0
  88. package/src/components/spinner/spinner.spec.ts +13 -0
  89. package/src/components/spinner/spinner.stories.ts +54 -0
  90. package/src/components/spinner/spinner.ts +62 -0
  91. package/src/components/switch/switch.mdx +82 -0
  92. package/src/components/switch/switch.stories.ts +94 -0
  93. package/src/components/textarea/textarea.mdx +14 -0
  94. package/src/components/textarea/textarea.stories.ts +52 -0
  95. package/src/components/validation-message/index.ts +1 -0
  96. package/src/components/validation-message/validation-message.ts +11 -0
  97. package/src/index.ts +14 -0
  98. package/src/test-setup.ts +12 -0
  99. package/src/utils/log-if-devmode.ts +13 -0
  100. package/src/utils/random-id.ts +3 -0
  101. package/tsconfig.json +34 -0
  102. package/tsconfig.lib.json +28 -0
  103. package/tsconfig.lib.prod.json +9 -0
  104. package/tsconfig.spec.json +30 -0
  105. package/vite.config.mts +35 -0
  106. package/dist/README.md +0 -55
  107. package/dist/fesm2022/ks-digital-designsystem-angular.mjs +0 -1068
  108. package/dist/fesm2022/ks-digital-designsystem-angular.mjs.map +0 -1
  109. package/dist/index.d.ts +0 -315
@@ -0,0 +1,50 @@
1
+ import { Meta, Primary, Controls, Story } from '@storybook/addon-docs/blocks'
2
+
3
+ import * as CheckboxStories from './checkbox.stories'
4
+
5
+ <Meta of={CheckboxStories} />
6
+
7
+ # Checkbox
8
+
9
+ Vi bruker `Checkbox` for å gi brukerne valg, der de kan velge ett eller flere alternativer. Brukerne kan både velge og oppheve valgene de gjør. Bruk [`Fieldset`](#fieldset) til å gruppere flere valg.
10
+
11
+ <Primary />
12
+ <Controls />
13
+
14
+ ## Bruk
15
+
16
+ ```tsx
17
+ import {
18
+ Input,
19
+ Field,
20
+ Fieldset,
21
+ FieldsetDescription,
22
+ FieldsetLegend,
23
+ Label,
24
+ ValidationMessage,
25
+ } from '@ks-digital/designsystem-angular'
26
+ ;<fieldset ksd-fieldset>
27
+ <legend ksd-fieldset-legend>
28
+ Hvordan vil du helst at vi skal kontakte deg?
29
+ </legend>
30
+
31
+ <p ksd-fieldset-description>
32
+ Velg alle alternativene som er relevante for deg.
33
+ </p>
34
+
35
+ <ksd-field>
36
+ <ksd-label> E-post </ksd-label>
37
+ <input ksd-input type="checkbox" value="e-post" />
38
+ </ksd-field>
39
+
40
+ <ksd-field>
41
+ <ksd-label> Telefon </ksd-label>
42
+ <input ksd-input type="checkbox" value="telefon" />
43
+ </ksd-field>
44
+
45
+ <ksd-field>
46
+ <ksd-label> SMS </ksd-label>
47
+ <input ksd-input type="checkbox" value="sms" />
48
+ </ksd-field>
49
+ </fieldset>
50
+ ```
@@ -0,0 +1,21 @@
1
+ import { render, screen } from '@testing-library/angular'
2
+ import userEvent from '@testing-library/user-event'
3
+ import { Field } from '../field/field'
4
+ import { Input } from '../input/input'
5
+ import { Label } from '../label/label'
6
+
7
+ test('should not be clickable if readonly', async () => {
8
+ await render(
9
+ `
10
+ <ksd-field>
11
+ <ksd-label>My checkbox</ksd-label>
12
+ <input ksd-input type="checkbox" value="my-checkbox" readonly />
13
+ </ksd-field>
14
+ `,
15
+ { imports: [Field, Input, Label] },
16
+ )
17
+
18
+ const checkbox = screen.getByRole('checkbox') as HTMLInputElement
19
+ await userEvent.click(checkbox)
20
+ expect(checkbox.checked).toBe(false)
21
+ })
@@ -0,0 +1,182 @@
1
+ import {
2
+ argsToTemplate,
3
+ moduleMetadata,
4
+ type Meta,
5
+ type StoryObj,
6
+ } from '@storybook/angular'
7
+ import { CommonArgs } from '../../../.storybook/default-args'
8
+ import { Field } from '../field/field'
9
+ import { FieldDescription } from '../field/field-description'
10
+ import { Fieldset } from '../fieldset/fieldset'
11
+ import { FieldsetDescription } from '../fieldset/fieldset-description'
12
+ import { FieldsetLegend } from '../fieldset/fieldset-legend'
13
+ import { Input } from '../input/input'
14
+ import { Label } from '../label/label'
15
+
16
+ type InputArgs = CommonArgs & {
17
+ readonly: boolean
18
+ disabled: boolean
19
+ }
20
+
21
+ const meta: Meta<Input> = {
22
+ component: Input,
23
+ title: 'Komponenter/Checkbox',
24
+ decorators: [
25
+ moduleMetadata({
26
+ imports: [
27
+ Input,
28
+ Label,
29
+ Field,
30
+ FieldDescription,
31
+ Fieldset,
32
+ FieldsetDescription,
33
+ FieldsetLegend,
34
+ ],
35
+ }),
36
+ ],
37
+ }
38
+ export default meta
39
+ type Story = StoryObj<InputArgs>
40
+
41
+ export const Preview: Story = {
42
+ args: {
43
+ readonly: false,
44
+ disabled: false,
45
+ },
46
+
47
+ render: (args) => ({
48
+ props: args,
49
+ template: `
50
+ <ksd-field>
51
+ <ksd-label> Checkbox label </ksd-label>
52
+ <input ksd-input type="checkbox" value="some-value" ${argsToTemplate(args)} />
53
+ <p ksd-field-description>Description</p>
54
+ </ksd-field>
55
+ `,
56
+ }),
57
+ }
58
+
59
+ export const Group: Story = {
60
+ args: {
61
+ ...Preview.args,
62
+ },
63
+
64
+ render: (args) => ({
65
+ props: args,
66
+ template: `
67
+ <fieldset ksd-fieldset>
68
+ <legend ksd-fieldset-legend>
69
+ Hvordan vil du helst at vi skal kontakte deg?
70
+ </legend>
71
+ <p ksd-fieldset-description>
72
+ Velg alle alternativene som er relevante for deg.
73
+ </p>
74
+
75
+ <ksd-field>
76
+ <ksd-label> E-post </ksd-label>
77
+ <input ksd-input type="checkbox" value="e-post" ${argsToTemplate(args)} />
78
+ </ksd-field>
79
+
80
+ <ksd-field>
81
+ <ksd-label> Telefon </ksd-label>
82
+ <input ksd-input type="checkbox" value="telefon" ${argsToTemplate(args)} />
83
+ </ksd-field>
84
+
85
+ <ksd-field>
86
+ <ksd-label> SMS </ksd-label>
87
+ <input ksd-input type="checkbox" value="sms" ${argsToTemplate(args)} />
88
+ </ksd-field>
89
+
90
+ </fieldset>
91
+ `,
92
+ }),
93
+ }
94
+
95
+ export const AriaLabel: Story = {
96
+ args: {
97
+ ...Preview.args,
98
+ },
99
+
100
+ render: (args) => ({
101
+ props: args,
102
+ template: `
103
+ <ksd-field>
104
+ <input ksd-input type="checkbox" value="some-value" aria-label="Checkbox label" ${argsToTemplate(args)} />
105
+ </ksd-field>
106
+ `,
107
+ }),
108
+ }
109
+
110
+ export const ReadOnly: Story = {
111
+ args: {
112
+ ...Preview.args,
113
+ readonly: true,
114
+ },
115
+
116
+ render: (args) => ({
117
+ props: args,
118
+ template: `
119
+ <fieldset ksd-fieldset>
120
+ <legend ksd-fieldset-legend>
121
+ Hvordan vil du helst at vi skal kontakte deg?
122
+ </legend>
123
+ <p ksd-fieldset-description>
124
+ Velg alle alternativene som er relevante for deg.
125
+ </p>
126
+
127
+ <ksd-field>
128
+ <ksd-label> E-post </ksd-label>
129
+ <input ksd-input type="checkbox" value="e-post" ${argsToTemplate(args)} />
130
+ </ksd-field>
131
+
132
+ <ksd-field>
133
+ <ksd-label> Telefon </ksd-label>
134
+ <input ksd-input type="checkbox" value="telefon" ${argsToTemplate(args)} />
135
+ </ksd-field>
136
+
137
+ <ksd-field>
138
+ <ksd-label> SMS </ksd-label>
139
+ <input ksd-input type="checkbox" value="sms" ${argsToTemplate(args)} />
140
+ </ksd-field>
141
+
142
+ </fieldset>
143
+ `,
144
+ }),
145
+ }
146
+
147
+ export const Disabled: Story = {
148
+ args: {
149
+ ...Preview.args,
150
+ disabled: true,
151
+ },
152
+
153
+ render: (args) => ({
154
+ props: args,
155
+ template: `
156
+ <fieldset ksd-fieldset>
157
+ <legend ksd-fieldset-legend>
158
+ Hvordan vil du helst at vi skal kontakte deg?
159
+ </legend>
160
+ <p ksd-fieldset-description>
161
+ Velg alle alternativene som er relevante for deg.
162
+ </p>
163
+
164
+ <ksd-field>
165
+ <ksd-label> E-post </ksd-label>
166
+ <input ksd-input type="checkbox" value="e-post" ${argsToTemplate(args)} />
167
+ </ksd-field>
168
+
169
+ <ksd-field>
170
+ <ksd-label> Telefon </ksd-label>
171
+ <input ksd-input type="checkbox" value="telefon" ${argsToTemplate(args)} />
172
+ </ksd-field>
173
+
174
+ <ksd-field>
175
+ <ksd-label> SMS </ksd-label>
176
+ <input ksd-input type="checkbox" value="sms" ${argsToTemplate(args)} />
177
+ </ksd-field>
178
+
179
+ </fieldset>
180
+ `,
181
+ }),
182
+ }
File without changes
@@ -0,0 +1,36 @@
1
+ /**
2
+ Lifted from https://github.com/digdir/designsystemet/blob/main/packages/react/src/colors.ts
3
+ **/
4
+
5
+ // EmptyObject implementation from https://github.com/sindresorhus/type-fest/blob/main/source/empty-object.d.ts
6
+ declare const emptyObjectSymbol: unique symbol
7
+ type EmptyObject = { [emptyObjectSymbol]?: never }
8
+
9
+ /**
10
+ * Base interface for available colors in the design system.
11
+ * The CLI will generate augmentations of this interface to allow
12
+ * type safety of custom color names.
13
+ */
14
+
15
+ // eslint-disable-next-line
16
+ export interface MainAndSupportColors {}
17
+
18
+ /**
19
+ * If {@link MainAndSupportColors} has been extended to include color names, return T,
20
+ * otherwise return the arbitrary string type.
21
+ */
22
+ type ColorWithFallback<T> = MainAndSupportColors extends EmptyObject
23
+ ? string
24
+ : T
25
+
26
+ export type SeverityInfo = 'info'
27
+ export type SeveritySuccess = 'success'
28
+ export type SeverityWarning = 'warning'
29
+ export type SeverityDanger = 'danger'
30
+ export type SeverityColors =
31
+ | SeverityInfo
32
+ | SeveritySuccess
33
+ | SeverityWarning
34
+ | SeverityDanger
35
+
36
+ export type Color = ColorWithFallback<'neutral' | keyof MainAndSupportColors>
@@ -0,0 +1,30 @@
1
+ /* eslint-disable @angular-eslint/no-input-rename */
2
+
3
+ /**
4
+ * We use input aliasing to bridge the gap between Angular's camelCase property naming convention and our HTML data attributes.
5
+ * This approach allows us to use valid HTML data attributes as documented by Designsystemet while maintaining
6
+ * proper TypeScript intellisense support.
7
+ *
8
+ * Todo: Some components are using only a subset of colors, e.g., SeverityColors for Alert. We should reconsider this directive
9
+ */
10
+
11
+ import { Directive, input } from '@angular/core'
12
+ import { Color } from './colors'
13
+
14
+ export type Size = 'sm' | 'md' | 'lg'
15
+
16
+ @Directive()
17
+ export class CommonInputs {
18
+ /**
19
+ * Changes size for descendant Designsystemet components. Select from predefined sizes.
20
+ * @attribute data-size
21
+ */
22
+ dataSize = input<Size>(undefined, { alias: 'data-size' })
23
+
24
+ /**
25
+ * Changes color for descendant Designsystemet components.
26
+ * Select from predefined colors and colors defined using theme.designsystemet.no.
27
+ * @attribute data-color
28
+ */
29
+ dataColor = input<Color>(undefined, { alias: 'data-color' })
30
+ }
@@ -0,0 +1,63 @@
1
+ import { Component, computed, signal } from '@angular/core'
2
+ import { Button } from '../button'
3
+ import { Details } from './details'
4
+ import { DetailsContent } from './details-content'
5
+ import { DetailsSummary } from './details-summary'
6
+
7
+ @Component({
8
+ selector: 'fiks-controlled-details',
9
+ imports: [Details, DetailsContent, DetailsSummary, Button],
10
+ template: `
11
+ <button
12
+ ksd-button
13
+ variant="secondary"
14
+ style="margin-bottom: .5em;"
15
+ (click)="toggleOpen()"
16
+ >
17
+ {{ toggleOpenText() }}
18
+ </button>
19
+ <ksd-details [open]="open1()" (toggled)="open1.set(!open1())">
20
+ <ksd-details-summary>Enkeltpersonforetak</ksd-details-summary>
21
+ <ksd-details-content>
22
+ Skal du starte for deg selv? Enkeltpersonforetak er ofte den enkleste
23
+ måten å etablere bedrift på. Denne organisasjonsformen har både fordeler
24
+ og ulemper. Det gir deg stor grad av frihet, men kan også gi betydelig
25
+ risiko fordi du har personlig ansvar for økonomien.
26
+ </ksd-details-content>
27
+ </ksd-details>
28
+ <ksd-details [open]="open2()" (toggled)="open2.set(!open2())">
29
+ <ksd-details-summary>Aksjeselskap (AS)</ksd-details-summary>
30
+ <ksd-details-content>
31
+ Planlegger du å starte næringsvirksomhet alene eller sammen med andre?
32
+ Innebærer næringsvirksomheten en økonomisk risiko? Vil du ha rettigheter
33
+ som arbeidstaker og muligheten til at andre kan investere i selskapet
34
+ ditt? Da kan aksjeselskap være en hensiktsmessig organisasjonsform.
35
+ </ksd-details-content>
36
+ </ksd-details>
37
+ <ksd-details [open]="open3()" (toggled)="open3.set(!open3())">
38
+ <ksd-details-summary>Ansvarlig selskap (ANS/DA)</ksd-details-summary>
39
+ <ksd-details-content>
40
+ Skal dere starte opp egen virksomhet sammen? Samarbeider dere godt?
41
+ Krever virksomheten små investeringer og innebærer liten økonomisk
42
+ risiko? Da kan ansvarlig selskap være aktuelt.
43
+ </ksd-details-content>
44
+ </ksd-details>
45
+ `,
46
+ })
47
+ export class ControlledDetails {
48
+ open1 = signal(false)
49
+ open2 = signal(false)
50
+ open3 = signal(false)
51
+
52
+ isOpen = computed(() =>
53
+ [this.open1(), this.open2(), this.open3()].every(Boolean),
54
+ )
55
+ toggleOpenText = computed(() => (this.isOpen() ? 'Lukk alle' : 'Åpne alle'))
56
+
57
+ toggleOpen = () => {
58
+ const isOpen = this.isOpen()
59
+ this.open1.set(!isOpen)
60
+ this.open2.set(!isOpen)
61
+ this.open3.set(!isOpen)
62
+ }
63
+ }
@@ -0,0 +1,7 @@
1
+ import { Component } from '@angular/core'
2
+
3
+ @Component({
4
+ selector: 'ksd-details-content',
5
+ template: `<ng-content />`,
6
+ })
7
+ export class DetailsContent {}
@@ -0,0 +1,7 @@
1
+ import { Component } from '@angular/core'
2
+
3
+ @Component({
4
+ selector: 'ksd-details-summary',
5
+ template: `<ng-content />`,
6
+ })
7
+ export class DetailsSummary {}
@@ -0,0 +1,89 @@
1
+ import { Meta, Canvas, Controls, Primary } from '@storybook/addon-docs/blocks'
2
+ import * as DetailsStories from './details.stories'
3
+
4
+ <Meta of={DetailsStories} />
5
+
6
+ # Details
7
+
8
+ Med `Details` kan du presentera mykje innhald på liten plass i ei eller fleire rader. Heile rada er klikkbar og let brukarar opna eller lukka visninga av innhaldet under.
9
+
10
+ <Primary />
11
+ <Controls />
12
+
13
+ ## Bruk
14
+
15
+ ```html
16
+ /* Utan ramme */
17
+ <ksd-details>
18
+ <ksd-details-summary>Vedlegg</ksd-details-summary>
19
+ <ksd-details-content>Vedlegg 1, vedlegg 2, vedlegg 3</ksd-details-content>
20
+ </ksd-details>
21
+
22
+ /* Med ramme */
23
+
24
+ <article ksd-card>
25
+ <ksd-details>
26
+ <ksd-details-summary>Vedlegg</ksd-details-summary>
27
+ <ksd-details-content>Vedlegg 1, vedlegg 2, vedlegg 3</ksd-details-content>
28
+ </ksd-details>
29
+ </article>
30
+ ```
31
+
32
+ ## Kodeeksempler
33
+
34
+ ### Med ramme
35
+
36
+ `Details` kan visast med ramme ved å leggje den i eit `Card`.
37
+ Dette kan passa i tilfelle der `Details` ikkje fyller heile sida, eller når det berre er ei rad.
38
+
39
+ <Canvas of={DetailsStories.InCard} />
40
+
41
+ ### Med fargar
42
+
43
+ `Details` kan visast i fargar frå temaet ditt.
44
+
45
+ <Canvas of={DetailsStories.InCardWithColor} />
46
+
47
+ #### Kontrollert
48
+
49
+ `Details` held sjølv styr på om den er open eller lukka, men dette kan òg kontrollerast utanfrå.
50
+
51
+ <Canvas of={DetailsStories.Controlled} />
52
+
53
+ ## Retningslinjer
54
+
55
+ Ikkje bruk `Details` til å skjula innhald for å gjera sida "ryddigare". Når vi skjuler innhold er det fare for at brukerne ikke se innholdet i det hele tatt. Finn ut om du faktisk må skjula innhald og ver klar over kvifor du gjer det.
56
+
57
+ **Passar til å**
58
+
59
+ - samla innhald
60
+ - gjera det frivillig å sjå innhald som er mindre viktig
61
+ - visa tilleggsinformasjon som kan vera til hjelp for brukarane
62
+
63
+ **Passar ikkje til å**
64
+
65
+ - visa viktig innhald som alle bør sjå når dei kjem til sida
66
+ - oppsummera feilmeldingar - bruk heller [`ErrorSummary`](/docs/komponenter-errorsummary--docs)
67
+
68
+ ### Unngå nøsta lister
69
+
70
+ Ikkje legg ein `Details` inni ein annan, det vi kallar nøsta lister. Det kan bli forvirrande for brukaren å forstå kva som er opna og lukka, spesielt når fleire nivå kan opnast samtidig.
71
+
72
+ ## Tekst
73
+
74
+ Sørg for at overskrifta gjev ei god skildring av kva innhaldet i `Details` er. Overskriftene kan ha stor tyding for om brukarane finn det dei treng, om innhaldet blir lese og om det kan reknast som tilgjengeleg for alle brukarar. «Vis meir» eller «Les meir her» er ikkje gode nok titlar. Har du ein `Details` med mange nedtrekk, kan du ha ei hovudoverskrift eller temaoverskrift over heile lista.
75
+
76
+ Hold innholdet i `Details` kort for å sikre at det lett kan relateres til overskriften. Om innhaldet er for langt bør du fordela innhaldet i fleire `Details`. Ved veldig mykje innhald kan det vere betre å vurdere å lage eigne sider.
77
+
78
+ ## Tilgjengelegheit
79
+
80
+ [`Chevron`](https://aksel.nav.no/ikoner/ChevronDown)-ikonet er plassert til venstre for teksten, av omsyn til brukarar med nedsett synsfelt. Dei ser berre ein liten del av skjermen om gongen, og skannar gjerne vertikalt nedover på venstre side. Difor bør funksjonelle element stå til venstre, der dei lettare blir oppdaga. Plasseringa av chevronen bør òg vere konsekvent for å unngå forveksling med andre element.
81
+
82
+ Ikkje plasser andre interaktive element inn i `Details.Summary`, då heile rada skal vera klikkbar. Ikonet og teksten skal _ikkje_ lenka til ulike handlingar (til dømes at teksten går vidare til ei side, medan ikonet opnar lista). Brukarane ventar ikkje at ikon og tekst skal gje ulikt resultat når dei vel dei.
83
+
84
+ <kbd>Space</kbd> eller <kbd>Enter</kbd> åpnar eller lukkar `Details`.
85
+
86
+ ## Kjende manglar
87
+
88
+ I Firefox og Safari blir det ikkje spelt av animasjon når `Details` blir opna og lukka.
89
+ Sjå [interpolate-size](https://developer.mozilla.org/en-US/docs/Web/CSS/interpolate-size).
@@ -0,0 +1,56 @@
1
+ import { Component } from '@angular/core'
2
+ import { render, screen } from '@testing-library/angular'
3
+ import userEvent from '@testing-library/user-event'
4
+ import { Details } from './details'
5
+ import { DetailsContent } from './details-content'
6
+ import { DetailsSummary } from './details-summary'
7
+
8
+ describe('Details', () => {
9
+ it('should have summary, content and be open when clicked', async () => {
10
+ @Component({
11
+ template: `
12
+ <ksd-details>
13
+ <ksd-details-summary>Details Summary Text</ksd-details-summary>
14
+ <ksd-details-content
15
+ >The fantastic details content text</ksd-details-content
16
+ >
17
+ </ksd-details>
18
+ `,
19
+ imports: [Details, DetailsContent, DetailsSummary],
20
+ })
21
+ class TestDetails {}
22
+
23
+ await render(TestDetails)
24
+
25
+ const user = userEvent.setup()
26
+ const detailsExpandButton = screen.getByRole('button')
27
+
28
+ await user.click(detailsExpandButton)
29
+
30
+ expect(screen.getByText('Details Summary Text'))
31
+ expect(screen.getByText('The fantastic details content text'))
32
+ expect(detailsExpandButton).toHaveAttribute('aria-expanded', 'true')
33
+ })
34
+
35
+ it('should render details with open state as controlled', async () => {
36
+ @Component({
37
+ template: `
38
+ <ksd-details [open]="true" (toggled)="noop()">
39
+ <ksd-details-summary>Details Summary Text</ksd-details-summary>
40
+ <ksd-details-content
41
+ >The fantastic details content text</ksd-details-content
42
+ >
43
+ </ksd-details>
44
+ `,
45
+ imports: [Details, DetailsContent, DetailsSummary],
46
+ })
47
+ class TestDetails {
48
+ noop = () => undefined
49
+ }
50
+
51
+ await render(TestDetails)
52
+
53
+ const detailsExpandButton = screen.getByRole('button')
54
+ expect(detailsExpandButton).toHaveAttribute('aria-expanded', 'true')
55
+ })
56
+ })
@@ -0,0 +1,129 @@
1
+ import { Meta, moduleMetadata, StoryObj } from '@storybook/angular'
2
+ import { Card } from '../card/card'
3
+ import { ControlledDetails } from './controlled-details'
4
+ import { Details } from './details'
5
+ import { DetailsContent } from './details-content'
6
+ import { DetailsSummary } from './details-summary'
7
+
8
+ const meta: Meta<Details> = {
9
+ component: Details,
10
+ title: 'Komponenter/Details',
11
+ parameters: {
12
+ layout: 'padded',
13
+ },
14
+ decorators: [
15
+ moduleMetadata({
16
+ imports: [
17
+ Card,
18
+ Details,
19
+ DetailsContent,
20
+ DetailsSummary,
21
+ ControlledDetails,
22
+ ],
23
+ }),
24
+ ],
25
+ }
26
+ export default meta
27
+ type Story = StoryObj<Details>
28
+
29
+ export const Preview: Story = {
30
+ args: {},
31
+ parameters: {
32
+ summaryText: 'Vedlegg',
33
+ contentText: 'Vedlegg 1, vedlegg 2, vedlegg 3',
34
+ },
35
+ render: (args, context) => ({
36
+ props: {
37
+ ...args,
38
+ summary: context.parameters['summaryText'],
39
+ content: context.parameters['contentText'],
40
+ },
41
+ template: `
42
+ <ksd-details data-testid="details">
43
+ <ksd-details-summary>Vedlegg</ksd-details-summary>
44
+ <ksd-details-content>Vedlegg 1, vedlegg 2, vedlegg 3</ksd-details-content>
45
+ </ksd-details>
46
+ `,
47
+ }),
48
+ }
49
+
50
+ export const WithoutCard: Story = {
51
+ render: () => ({
52
+ template: `
53
+ <ksd-details>
54
+ <ksd-details-summary>Vedlegg</ksd-details-summary>
55
+ <ksd-details-content>Vedlegg 1, vedlegg 2, vedlegg 3</ksd-details-content>
56
+ </ksd-details>
57
+ `,
58
+ }),
59
+ }
60
+
61
+ export const InCard: Story = {
62
+ render: () => ({
63
+ template: `
64
+ <article ksd-card>
65
+ <ksd-details>
66
+ <ksd-details-summary>Vedlegg</ksd-details-summary>
67
+ <ksd-details-content>Vedlegg 1, vedlegg 2, vedlegg 3</ksd-details-content>
68
+ </ksd-details>
69
+ </article>
70
+ `,
71
+ }),
72
+ }
73
+
74
+ export const InCardWithColor: Story = {
75
+ render: () => ({
76
+ template: `
77
+ <div style="display: flex; flex-direction: column; gap: 1rem">
78
+ <article ksd-card>
79
+ <ksd-details data-color="accent">
80
+ <ksd-details-summary>Vedlegg</ksd-details-summary>
81
+ <ksd-details-content>Vedlegg 1, vedlegg 2, vedlegg 3</ksd-details-content>
82
+ </ksd-details>
83
+ </article>
84
+ <article ksd-card>
85
+ <ksd-details data-color="accent" variant="tinted">
86
+ <ksd-details-summary>Vedlegg</ksd-details-summary>
87
+ <ksd-details-content>Vedlegg 1, vedlegg 2, vedlegg 3</ksd-details-content>
88
+ </ksd-details>
89
+ </article>
90
+ </div>
91
+ `,
92
+ }),
93
+ }
94
+
95
+ export const WithDifferentSizes: Story = {
96
+ render: () => ({
97
+ template: `
98
+ <ksd-details data-size="sm">
99
+ <ksd-details-summary>Vedlegg</ksd-details-summary>
100
+ <ksd-details-content>Vedlegg 1, vedlegg 2, vedlegg 3</ksd-details-content>
101
+ </ksd-details>
102
+ <ksd-details data-size="md">
103
+ <ksd-details-summary>Vedlegg</ksd-details-summary>
104
+ <ksd-details-content>Vedlegg 1, vedlegg 2, vedlegg 3</ksd-details-content>
105
+ </ksd-details>
106
+ <ksd-details data-size="lg">
107
+ <ksd-details-summary>Vedlegg</ksd-details-summary>
108
+ <ksd-details-content>Vedlegg 1, vedlegg 2, vedlegg 3</ksd-details-content>
109
+ </ksd-details>
110
+ `,
111
+ }),
112
+ }
113
+
114
+ export const DefaultOpen: Story = {
115
+ render: () => ({
116
+ template: `
117
+ <ksd-details [defaultOpen]="true">
118
+ <ksd-details-summary>Vedlegg</ksd-details-summary>
119
+ <ksd-details-content>Vedlegg 1, vedlegg 2, vedlegg 3</ksd-details-content>
120
+ </ksd-details>
121
+ `,
122
+ }),
123
+ }
124
+
125
+ export const Controlled: StoryObj<ControlledDetails> = {
126
+ render: () => ({
127
+ template: `<fiks-controlled-details />`,
128
+ }),
129
+ }