@navikt/ds-react 6.5.0 → 6.6.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (153) hide show
  1. package/cjs/form/combobox/FilteredOptions/filteredOptionsContext.js +2 -4
  2. package/cjs/form/combobox/FilteredOptions/filteredOptionsContext.js.map +1 -1
  3. package/cjs/form/combobox/Input/Input.js +6 -1
  4. package/cjs/form/combobox/Input/Input.js.map +1 -1
  5. package/cjs/form/form-summary/FormSummary.d.ts +82 -0
  6. package/cjs/form/form-summary/FormSummary.js +81 -0
  7. package/cjs/form/form-summary/FormSummary.js.map +1 -0
  8. package/cjs/form/form-summary/FormSummaryAnswer.d.ts +11 -0
  9. package/cjs/form/form-summary/FormSummaryAnswer.js +25 -0
  10. package/cjs/form/form-summary/FormSummaryAnswer.js.map +1 -0
  11. package/cjs/form/form-summary/FormSummaryAnswers.d.ts +9 -0
  12. package/cjs/form/form-summary/FormSummaryAnswers.js +48 -0
  13. package/cjs/form/form-summary/FormSummaryAnswers.js.map +1 -0
  14. package/cjs/form/form-summary/FormSummaryEditLink.d.ts +17 -0
  15. package/cjs/form/form-summary/FormSummaryEditLink.js +49 -0
  16. package/cjs/form/form-summary/FormSummaryEditLink.js.map +1 -0
  17. package/cjs/form/form-summary/FormSummaryHeader.d.ts +9 -0
  18. package/cjs/form/form-summary/FormSummaryHeader.js +48 -0
  19. package/cjs/form/form-summary/FormSummaryHeader.js.map +1 -0
  20. package/cjs/form/form-summary/FormSummaryHeading.d.ts +14 -0
  21. package/cjs/form/form-summary/FormSummaryHeading.js +31 -0
  22. package/cjs/form/form-summary/FormSummaryHeading.js.map +1 -0
  23. package/cjs/form/form-summary/FormSummaryLabel.d.ts +6 -0
  24. package/cjs/form/form-summary/FormSummaryLabel.js +45 -0
  25. package/cjs/form/form-summary/FormSummaryLabel.js.map +1 -0
  26. package/cjs/form/form-summary/FormSummaryValue.d.ts +6 -0
  27. package/cjs/form/form-summary/FormSummaryValue.js +49 -0
  28. package/cjs/form/form-summary/FormSummaryValue.js.map +1 -0
  29. package/cjs/form/form-summary/index.d.ts +8 -0
  30. package/cjs/form/form-summary/index.js +24 -0
  31. package/cjs/form/form-summary/index.js.map +1 -0
  32. package/cjs/index.d.ts +3 -2
  33. package/cjs/index.js +5 -3
  34. package/cjs/index.js.map +1 -1
  35. package/cjs/util/hooks/descendants/descendant.js +10 -1
  36. package/cjs/util/hooks/descendants/descendant.js.map +1 -1
  37. package/cjs/util/hooks/descendants/useDescendant.js +0 -5
  38. package/cjs/util/hooks/descendants/useDescendant.js.map +1 -1
  39. package/esm/form/combobox/FilteredOptions/filteredOptionsContext.js +2 -4
  40. package/esm/form/combobox/FilteredOptions/filteredOptionsContext.js.map +1 -1
  41. package/esm/form/combobox/Input/Input.js +6 -1
  42. package/esm/form/combobox/Input/Input.js.map +1 -1
  43. package/esm/form/form-summary/FormSummary.d.ts +82 -0
  44. package/esm/form/form-summary/FormSummary.js +52 -0
  45. package/esm/form/form-summary/FormSummary.js.map +1 -0
  46. package/esm/form/form-summary/FormSummaryAnswer.d.ts +11 -0
  47. package/esm/form/form-summary/FormSummaryAnswer.js +19 -0
  48. package/esm/form/form-summary/FormSummaryAnswer.js.map +1 -0
  49. package/esm/form/form-summary/FormSummaryAnswers.d.ts +9 -0
  50. package/esm/form/form-summary/FormSummaryAnswers.js +19 -0
  51. package/esm/form/form-summary/FormSummaryAnswers.js.map +1 -0
  52. package/esm/form/form-summary/FormSummaryEditLink.d.ts +17 -0
  53. package/esm/form/form-summary/FormSummaryEditLink.js +20 -0
  54. package/esm/form/form-summary/FormSummaryEditLink.js.map +1 -0
  55. package/esm/form/form-summary/FormSummaryHeader.d.ts +9 -0
  56. package/esm/form/form-summary/FormSummaryHeader.js +19 -0
  57. package/esm/form/form-summary/FormSummaryHeader.js.map +1 -0
  58. package/esm/form/form-summary/FormSummaryHeading.d.ts +14 -0
  59. package/esm/form/form-summary/FormSummaryHeading.js +5 -0
  60. package/esm/form/form-summary/FormSummaryHeading.js.map +1 -0
  61. package/esm/form/form-summary/FormSummaryLabel.d.ts +6 -0
  62. package/esm/form/form-summary/FormSummaryLabel.js +19 -0
  63. package/esm/form/form-summary/FormSummaryLabel.js.map +1 -0
  64. package/esm/form/form-summary/FormSummaryValue.d.ts +6 -0
  65. package/esm/form/form-summary/FormSummaryValue.js +20 -0
  66. package/esm/form/form-summary/FormSummaryValue.js.map +1 -0
  67. package/esm/form/form-summary/index.d.ts +8 -0
  68. package/esm/form/form-summary/index.js +10 -0
  69. package/esm/form/form-summary/index.js.map +1 -0
  70. package/esm/index.d.ts +3 -2
  71. package/esm/index.js +2 -1
  72. package/esm/index.js.map +1 -1
  73. package/esm/util/hooks/descendants/descendant.js +10 -1
  74. package/esm/util/hooks/descendants/descendant.js.map +1 -1
  75. package/esm/util/hooks/descendants/useDescendant.js +0 -5
  76. package/esm/util/hooks/descendants/useDescendant.js.map +1 -1
  77. package/package.json +15 -4
  78. package/src/form/combobox/FilteredOptions/filteredOptionsContext.tsx +9 -1
  79. package/src/form/combobox/Input/Input.tsx +5 -0
  80. package/src/form/form-summary/FormSummary.tsx +106 -0
  81. package/src/form/form-summary/FormSummaryAnswer.tsx +27 -0
  82. package/src/form/form-summary/FormSummaryAnswers.tsx +25 -0
  83. package/src/form/form-summary/FormSummaryEditLink.tsx +35 -0
  84. package/src/form/form-summary/FormSummaryHeader.tsx +25 -0
  85. package/src/form/form-summary/FormSummaryHeading.tsx +23 -0
  86. package/src/form/form-summary/FormSummaryLabel.tsx +17 -0
  87. package/src/form/form-summary/FormSummaryValue.tsx +24 -0
  88. package/src/form/form-summary/index.ts +30 -0
  89. package/src/index.ts +16 -15
  90. package/src/util/hooks/descendants/descendant.ts +15 -1
  91. package/src/util/hooks/descendants/useDescendant.tsx +0 -5
  92. package/src/accordion/accordion.stories.tsx +0 -286
  93. package/src/alert/alert.stories.tsx +0 -306
  94. package/src/button/button.stories.tsx +0 -185
  95. package/src/chat/chat.stories.tsx +0 -341
  96. package/src/chips/chips.stories.tsx +0 -260
  97. package/src/copybutton/copy-button.stories.tsx +0 -261
  98. package/src/date/datepicker/datepicker.stories.tsx +0 -614
  99. package/src/date/monthpicker/monthpicker.stories.tsx +0 -221
  100. package/src/dropdown/dropdown.stories.tsx +0 -124
  101. package/src/expansion-card/expansion-card.stories.tsx +0 -282
  102. package/src/form/checkbox/checkbox.stories.tsx +0 -281
  103. package/src/form/combobox/combobox.stories.tsx +0 -626
  104. package/src/form/confirmation-panel/confirmation-panel.stories.tsx +0 -128
  105. package/src/form/error-summary/error-summary.stories.tsx +0 -81
  106. package/src/form/fieldset/fieldset.stories.tsx +0 -157
  107. package/src/form/file-upload/file-upload-dropzone.stories.tsx +0 -123
  108. package/src/form/file-upload/file-upload-item.stories.tsx +0 -148
  109. package/src/form/file-upload/file-upload.stories.tsx +0 -248
  110. package/src/form/radio/radio.stories.tsx +0 -230
  111. package/src/form/search/search.stories.tsx +0 -238
  112. package/src/form/select/select.stories.tsx +0 -172
  113. package/src/form/switch/switch.stories.tsx +0 -171
  114. package/src/form/textarea/textarea.stories.tsx +0 -254
  115. package/src/form/textfield/text-field.stories.tsx +0 -143
  116. package/src/guide-panel/guidepanel.stories.tsx +0 -90
  117. package/src/help-text/help-text.stories.tsx +0 -91
  118. package/src/internal-header/header.stories.tsx +0 -229
  119. package/src/layout/bleed/Bleed.stories.tsx +0 -395
  120. package/src/layout/box/Box.stories.tsx +0 -380
  121. package/src/layout/grid/h-grid.stories.tsx +0 -122
  122. package/src/layout/page/Page.stories.tsx +0 -271
  123. package/src/layout/responsive/hide.stories.tsx +0 -80
  124. package/src/layout/responsive/show.stories.tsx +0 -80
  125. package/src/layout/sidemal-test/navno-sidemal.stories.tsx +0 -69
  126. package/src/layout/stack/stack.stories.tsx +0 -183
  127. package/src/link/stories/link.stories.tsx +0 -304
  128. package/src/link-panel/link-panel.stories.tsx +0 -59
  129. package/src/list/list.stories.tsx +0 -280
  130. package/src/loader/loader.stories.tsx +0 -82
  131. package/src/modal/modal.stories.tsx +0 -391
  132. package/src/pagination/pagination.stories.tsx +0 -110
  133. package/src/popover/popover.stories.tsx +0 -113
  134. package/src/portal/Portal.stories.tsx +0 -102
  135. package/src/read-more/readmore.stories.tsx +0 -91
  136. package/src/skeleton/skeleton.stories.tsx +0 -130
  137. package/src/stepper/stepper.stories.tsx +0 -200
  138. package/src/table/stories/table-1.stories.tsx +0 -292
  139. package/src/table/stories/table-2-expandable.stories.tsx +0 -298
  140. package/src/table/stories/table-3-async.stories.tsx +0 -179
  141. package/src/table/stories/tests/table.stories.tsx +0 -102
  142. package/src/tabs/Tabs.stories.tsx +0 -311
  143. package/src/tag/tag.stories.tsx +0 -126
  144. package/src/timeline/timeline.stories.tsx +0 -445
  145. package/src/toggle-group/ToggleGroup.stories.tsx +0 -198
  146. package/src/tooltip/tooltip.stories.tsx +0 -101
  147. package/src/typography/stories/bodylong.stories.tsx +0 -209
  148. package/src/typography/stories/bodyshort.stories.tsx +0 -208
  149. package/src/typography/stories/detail.stories.tsx +0 -115
  150. package/src/typography/stories/error-message.stories.tsx +0 -122
  151. package/src/typography/stories/heading.stories.tsx +0 -169
  152. package/src/typography/stories/label.stories.tsx +0 -131
  153. package/src/util/hooks/descendants/descendant.stories.tsx +0 -147
@@ -1,626 +0,0 @@
1
- import { Meta, StoryFn, StoryObj } from "@storybook/react";
2
- import { expect, fn, userEvent, within } from "@storybook/test";
3
- import React, { useMemo, useRef, useState } from "react";
4
- import { Chips } from "../../chips";
5
- import { TextField } from "../textfield";
6
- import { ComboboxProps, UNSAFE_Combobox } from "./index";
7
-
8
- export default {
9
- title: "ds-react/Combobox",
10
- component: UNSAFE_Combobox,
11
- decorators: [(story) => <div style={{ width: "300px" }}>{story()}</div>],
12
- } satisfies Meta<typeof UNSAFE_Combobox>;
13
-
14
- type StoryObject = StoryObj<typeof UNSAFE_Combobox>;
15
- type StoryFunction = StoryFn<typeof UNSAFE_Combobox>;
16
-
17
- const options = [
18
- "banana",
19
- "apple",
20
- "apple pie",
21
- "tangerine",
22
- "pear",
23
- "grape",
24
- "kiwi",
25
- "mango",
26
- "passion fruit",
27
- "pineapple",
28
- "strawberry",
29
- "watermelon",
30
- "grape fruit",
31
- ];
32
-
33
- export const Default: StoryFunction = (props) => (
34
- <UNSAFE_Combobox {...props} id="combobox" />
35
- );
36
-
37
- Default.args = {
38
- options,
39
- label: "Hva er dine favorittfrukter?",
40
- shouldAutocomplete: true,
41
- isLoading: false,
42
- isMultiSelect: false,
43
- allowNewValues: false,
44
- };
45
- Default.argTypes = {
46
- isListOpen: {
47
- control: { type: "boolean" },
48
- },
49
- maxSelected: {
50
- control: { type: "number" },
51
- },
52
- size: {
53
- options: ["medium", "small"],
54
- defaultValue: "medium",
55
- control: { type: "radio" },
56
- },
57
- };
58
-
59
- export const MultiSelect: StoryFunction = (props) => {
60
- return (
61
- <UNSAFE_Combobox
62
- id="combobox-with-multiselect"
63
- label="Komboboks - velg flere"
64
- options={props.options}
65
- isMultiSelect={props.isMultiSelect}
66
- size={props.size}
67
- />
68
- );
69
- };
70
-
71
- MultiSelect.args = {
72
- options,
73
- isMultiSelect: true,
74
- size: "medium",
75
- };
76
-
77
- export const MultiSelectWithComplexOptions: StoryFunction = (props) => {
78
- const [selectedOptions, setSelectedOptions] = useState<string[]>([]);
79
- return (
80
- <>
81
- <UNSAFE_Combobox
82
- {...props}
83
- options={props.options.map((option) => ({
84
- ...option,
85
- label: `${option.label} [${option.value}]`,
86
- }))}
87
- id="combobox-with-complex-options"
88
- label="Velg temakoder"
89
- allowNewValues
90
- onToggleSelected={(value, isSelected) =>
91
- isSelected
92
- ? setSelectedOptions([...selectedOptions, value])
93
- : setSelectedOptions(selectedOptions.filter((o) => o !== value))
94
- }
95
- selectedOptions={selectedOptions}
96
- />
97
- </>
98
- );
99
- };
100
-
101
- MultiSelectWithComplexOptions.args = {
102
- options: [
103
- { label: "Hjelpemidler", value: "HJE" },
104
- { label: "Oppfølging", value: "OPP" },
105
- { label: "Sykepenger", value: "SYK" },
106
- { label: "Sykemelding", value: "SYM" },
107
- { label: "Foreldre- og svangerskapspenger", value: "FOR" },
108
- { label: "Arbeidsavklaringspenger", value: "AAP" },
109
- { label: "Uføretrygd", value: "UFO" },
110
- { label: "Pensjon", value: "PEN" },
111
- { label: "Barnetrygd", value: "BAR" },
112
- { label: "Kontantstøtte", value: "KON" },
113
- { label: "Bostøtte", value: "BOS" },
114
- { label: "Barnebidrag", value: "BBI" },
115
- { label: "Bidragsforskudd", value: "BIF" },
116
- { label: "Grunn- og hjelpestønad", value: "GRU" },
117
- ],
118
- isMultiSelect: true,
119
- size: "medium",
120
- };
121
-
122
- export const WithAddNewOptions: StoryFunction = (props) => {
123
- return (
124
- <UNSAFE_Combobox
125
- id="combobox-with-add-new-options"
126
- label="Komboboks med mulighet for å legge til nye verdier"
127
- options={props.options}
128
- allowNewValues={props.allowNewValues}
129
- shouldAutocomplete={props.shouldAutocomplete}
130
- />
131
- );
132
- };
133
-
134
- WithAddNewOptions.args = {
135
- options,
136
- allowNewValues: true,
137
- shouldAutocomplete: true,
138
- };
139
-
140
- export const MultiSelectWithAddNewOptions: StoryFunction = (props) => {
141
- return (
142
- <UNSAFE_Combobox
143
- id="combobox-with-multiselect-and-add-new-options"
144
- isMultiSelect={props.isMultiSelect}
145
- label="Multiselect komboboks med mulighet for å legge til nye verdier"
146
- options={props.options}
147
- allowNewValues={props.allowNewValues}
148
- />
149
- );
150
- };
151
-
152
- MultiSelectWithAddNewOptions.args = {
153
- allowNewValues: true,
154
- isMultiSelect: true,
155
- options,
156
- shouldAutocomplete: false,
157
- };
158
-
159
- export const MultiSelectWithExternalChips: StoryFn<{
160
- controlled: boolean;
161
- options: ComboboxProps["options"];
162
- }> = (props) => {
163
- const [selectedOptions, setSelectedOptions] = useState<string[]>([]);
164
- const [value, setValue] = useState("");
165
-
166
- const toggleSelected = (option: string) =>
167
- selectedOptions.includes(option)
168
- ? setSelectedOptions(selectedOptions.filter((opt) => opt !== option))
169
- : setSelectedOptions([...selectedOptions, option]);
170
- return (
171
- <>
172
- {selectedOptions && (
173
- <Chips>
174
- {selectedOptions.map((option) => (
175
- <Chips.Removable
176
- key={option}
177
- onPointerUp={() => toggleSelected(option)}
178
- onKeyUp={(e) => e.key === "Enter" && toggleSelected(option)}
179
- >
180
- {option}
181
- </Chips.Removable>
182
- ))}
183
- </Chips>
184
- )}
185
- <UNSAFE_Combobox
186
- id="combobox-with-external-chips"
187
- options={props.options}
188
- selectedOptions={selectedOptions}
189
- onToggleSelected={(option) => toggleSelected(option)}
190
- isMultiSelect
191
- value={props.controlled ? value : undefined}
192
- onChange={(event) =>
193
- props.controlled
194
- ? setValue(event?.currentTarget.value || "")
195
- : undefined
196
- }
197
- label="Komboboks"
198
- size="medium"
199
- shouldShowSelectedOptions={false}
200
- />
201
- </>
202
- );
203
- };
204
-
205
- MultiSelectWithExternalChips.args = {
206
- controlled: false,
207
- options,
208
- };
209
-
210
- export const Loading: StoryFunction = (props) => (
211
- <UNSAFE_Combobox
212
- id="combobox-with-loading-indicator"
213
- label="Komboboks (laster)"
214
- options={[]}
215
- selectedOptions={[]}
216
- isListOpen={props.isListOpen}
217
- isLoading={props.isLoading}
218
- />
219
- );
220
-
221
- Loading.args = {
222
- isLoading: true,
223
- isListOpen: true,
224
- };
225
-
226
- export const ComboboxWithNoHits: StoryFunction = (props) => {
227
- const [value, setValue] = useState(props.value);
228
- return (
229
- <UNSAFE_Combobox
230
- id="combobox-with-no-hits"
231
- label="Komboboks (uten søketreff)"
232
- options={props.options}
233
- value={value}
234
- onChange={(event) => setValue(event?.currentTarget.value)}
235
- isListOpen={true}
236
- />
237
- );
238
- };
239
-
240
- ComboboxWithNoHits.args = {
241
- options,
242
- value: "Orange",
243
- };
244
-
245
- export const Controlled: StoryFn<{
246
- value: string;
247
- options: string[];
248
- initialSelectedOptions: string[];
249
- }> = (props) => {
250
- const [value, setValue] = useState(props.value);
251
- const [selectedOptions, setSelectedOptions] = useState(
252
- props.initialSelectedOptions,
253
- );
254
- const filteredOptions = useMemo(
255
- () => props.options.filter((option) => option.includes(value)),
256
- [props.options, value],
257
- );
258
-
259
- const onToggleSelected = (option: string, isSelected: boolean) => {
260
- if (isSelected) {
261
- setSelectedOptions([...selectedOptions, option]);
262
- } else {
263
- setSelectedOptions(selectedOptions.filter((o) => o !== option));
264
- }
265
- };
266
-
267
- return (
268
- <>
269
- <TextField
270
- label="Overstyr value"
271
- onChange={(event) => setValue(event.target.value)}
272
- value={value}
273
- />
274
- <br />
275
- <UNSAFE_Combobox
276
- label="Hva er dine favorittfrukter?"
277
- id="combobox-controlled"
278
- filteredOptions={filteredOptions}
279
- isMultiSelect
280
- options={props.options}
281
- onChange={(event) => setValue(event?.target.value || "")}
282
- onToggleSelected={onToggleSelected}
283
- selectedOptions={selectedOptions}
284
- value={value}
285
- />
286
- </>
287
- );
288
- };
289
-
290
- Controlled.args = {
291
- value: "apple",
292
- options,
293
- initialSelectedOptions: ["passion fruit", "grape fruit"],
294
- };
295
-
296
- export const ComboboxSizes = () => (
297
- <>
298
- <UNSAFE_Combobox
299
- label="Hva er dine favorittfrukter?"
300
- description="Medium single-select"
301
- options={options}
302
- />
303
- <br />
304
- <UNSAFE_Combobox
305
- label="Hva er dine favorittfrukter?"
306
- description="Small single-select"
307
- options={options}
308
- size="small"
309
- />
310
- <br />
311
- <UNSAFE_Combobox
312
- label="Hva er dine favorittfrukter?"
313
- description="Medium multiselect"
314
- options={options}
315
- isMultiSelect
316
- allowNewValues
317
- />
318
- <br />
319
- <UNSAFE_Combobox
320
- label="Hva er dine favorittfrukter?"
321
- description="Small multiselect"
322
- options={options}
323
- isMultiSelect
324
- size="small"
325
- allowNewValues
326
- />
327
- </>
328
- );
329
-
330
- export const MaxSelectedOptions: StoryFunction = () => {
331
- const [value, setValue] = useState<string | undefined>("");
332
- const [selectedOptions, setSelectedOptions] = useState([
333
- options[0],
334
- options[1],
335
- ]);
336
- const comboboxRef = useRef<HTMLInputElement>(null);
337
- return (
338
- <UNSAFE_Combobox
339
- id="combobox-with-max-selected-options"
340
- label="Komboboks med begrenset antall valg"
341
- options={options}
342
- maxSelected={{ limit: 2 }}
343
- selectedOptions={selectedOptions}
344
- onToggleSelected={(option, isSelected) =>
345
- isSelected
346
- ? setSelectedOptions([...selectedOptions, option])
347
- : setSelectedOptions(selectedOptions.filter((o) => o !== option))
348
- }
349
- isMultiSelect
350
- allowNewValues
351
- isListOpen={comboboxRef.current ? undefined : true}
352
- value={value}
353
- onChange={(event) => setValue(event?.target.value)}
354
- ref={comboboxRef}
355
- />
356
- );
357
- };
358
-
359
- export const WithError: StoryFunction = (props) => {
360
- const [hasSelectedValue, setHasSelectedValue] = useState(false);
361
- const [isLoading, setIsLoading] = useState(false);
362
- return (
363
- <UNSAFE_Combobox
364
- filteredOptions={isLoading ? [] : undefined}
365
- options={options}
366
- label="Hva er dine favorittfrukter?"
367
- error={!hasSelectedValue && props.error}
368
- isLoading={isLoading}
369
- onChange={() => {
370
- setIsLoading(true);
371
- setTimeout(() => setIsLoading(false), 2000);
372
- }}
373
- onToggleSelected={(_, isSelected) => setHasSelectedValue(isSelected)}
374
- />
375
- );
376
- };
377
- WithError.args = {
378
- error: "Du må velge en favorittfrukt.",
379
- };
380
-
381
- function sleep(ms: number) {
382
- return new Promise((resolve) => setTimeout(resolve, ms));
383
- }
384
-
385
- export const CancelInputTest: StoryObject = {
386
- render: () => {
387
- return (
388
- <UNSAFE_Combobox options={options} label="Hva er dine favorittfrukter?" />
389
- );
390
- },
391
- play: async ({ canvasElement }) => {
392
- const canvas = within(canvasElement);
393
-
394
- const input = canvas.getByLabelText("Hva er dine favorittfrukter?");
395
-
396
- userEvent.click(input);
397
- await userEvent.type(input, "apple", { delay: 200 });
398
- await sleep(1000);
399
-
400
- userEvent.keyboard("{ArrowDown}");
401
- await sleep(1000);
402
- userEvent.keyboard("{Escape}");
403
- await sleep(1000);
404
- userEvent.keyboard("{ArrowDown}");
405
- await sleep(500);
406
- const banana = canvas.getByText("banana");
407
- userEvent.click(banana);
408
- },
409
- };
410
-
411
- export const RemoveSelectedMultiSelectTest: StoryObject = {
412
- render: () => {
413
- return (
414
- <UNSAFE_Combobox
415
- options={options}
416
- label="Hva er dine favorittfrukter?"
417
- isMultiSelect
418
- />
419
- );
420
- },
421
- play: async ({ canvasElement }) => {
422
- const canvas = within(canvasElement);
423
-
424
- const input = canvas.getByLabelText("Hva er dine favorittfrukter?");
425
-
426
- userEvent.click(input);
427
- await userEvent.type(input, "apple", { delay: 200 });
428
- await sleep(250);
429
-
430
- userEvent.keyboard("{ArrowDown}");
431
- await sleep(250);
432
- userEvent.keyboard("{Enter}");
433
- await sleep(250);
434
- userEvent.keyboard("{Escape}");
435
- await sleep(250);
436
-
437
- userEvent.click(input);
438
- await userEvent.type(input, "banana", { delay: 200 });
439
- await sleep(250);
440
-
441
- userEvent.keyboard("{ArrowDown}");
442
- await sleep(250);
443
- userEvent.keyboard("{Enter}");
444
- await sleep(250);
445
-
446
- const appleSlett = canvas.getByLabelText("apple slett");
447
- appleSlett.focus();
448
- await sleep(250);
449
- userEvent.click(appleSlett);
450
- await sleep(250);
451
- const appleOption = canvas.getByRole("option", {
452
- name: "apple",
453
- selected: false,
454
- });
455
- expect(appleOption).toBeVisible();
456
- userEvent.keyboard("{Escape}");
457
- await sleep(250);
458
- expect(appleOption).not.toBeVisible();
459
-
460
- const bananaSlett = canvas.getByLabelText("banana slett");
461
- expect(bananaSlett).toBeInTheDocument();
462
- const appleSlettAgain = canvas.queryByLabelText("apple slett");
463
- expect(appleSlettAgain).not.toBeInTheDocument();
464
- },
465
- };
466
-
467
- export const AddWhenAddNewDisabledTest: StoryObject = {
468
- render: () => {
469
- return (
470
- <UNSAFE_Combobox
471
- options={options}
472
- label="Hva er dine favorittfrukter?"
473
- isMultiSelect
474
- />
475
- );
476
- },
477
- play: async ({ canvasElement }) => {
478
- const canvas = within(canvasElement);
479
-
480
- const input = canvas.getByLabelText("Hva er dine favorittfrukter?");
481
-
482
- userEvent.click(input);
483
- await userEvent.type(input, "aaa", { delay: 200 });
484
- await sleep(250);
485
-
486
- userEvent.keyboard("{ArrowDown}");
487
- await sleep(250);
488
- userEvent.keyboard("{ArrowDown}");
489
- await sleep(250);
490
- userEvent.keyboard("{Enter}");
491
- await sleep(250);
492
- userEvent.keyboard("{Escape}");
493
- await sleep(250);
494
-
495
- const invalidSelect = canvas.queryByLabelText("aaa slett");
496
- expect(invalidSelect).not.toBeInTheDocument();
497
- },
498
- };
499
-
500
- export const TestThatCallbacksOnlyFireWhenExpected: StoryObj<{
501
- onChange: ReturnType<typeof fn>;
502
- onClear: ReturnType<typeof fn>;
503
- onToggleSelected: ReturnType<typeof fn>;
504
- }> = {
505
- args: {
506
- onChange: fn(),
507
- onClear: fn(),
508
- onToggleSelected: fn(),
509
- },
510
- render: (props) => {
511
- return (
512
- <UNSAFE_Combobox
513
- options={options}
514
- label="Hva er dine favorittfrukter?"
515
- {...props}
516
- />
517
- );
518
- },
519
- play: async ({ canvasElement, args }) => {
520
- args.onToggleSelected.mockClear();
521
- args.onClear.mockClear();
522
- args.onChange.mockClear();
523
- const canvas = within(canvasElement);
524
-
525
- const input = canvas.getByLabelText("Hva er dine favorittfrukter?");
526
- const searchWord = "tangerine";
527
-
528
- userEvent.click(input);
529
- await userEvent.type(input, searchWord, { delay: 200 });
530
- await sleep(250);
531
- userEvent.keyboard("{ArrowDown}");
532
- await sleep(250);
533
- userEvent.keyboard("{Enter}");
534
- await sleep(250);
535
- expect(args.onClear.mock.calls).toHaveLength(1);
536
- expect(args.onToggleSelected.mock.calls).toHaveLength(1);
537
- expect(args.onChange.mock.calls).toHaveLength(searchWord.length + 1);
538
- },
539
- };
540
-
541
- export const TestCasingWhenAutoCompleting = {
542
- args: {
543
- onChange: fn(),
544
- onClear: fn(),
545
- onToggleSelected: fn(),
546
- },
547
- render: (props) => {
548
- return (
549
- <UNSAFE_Combobox
550
- options={["Camel Case", "lowercase", "UPPERCASE"]}
551
- label="Liker du best store eller små bokstaver?"
552
- shouldAutocomplete
553
- allowNewValues
554
- {...props}
555
- />
556
- );
557
- },
558
- play: async ({ canvasElement }) => {
559
- const canvas = within(canvasElement);
560
- const input = canvas.getByRole<HTMLInputElement>("combobox");
561
-
562
- // With exisiting option
563
- userEvent.click(input);
564
- await userEvent.type(input, "cAmEl CaSe", { delay: 250 });
565
- await sleep(250);
566
- expect(input.value).toBe("cAmEl CaSe");
567
- await userEvent.type(input, "{Enter}");
568
- await sleep(250);
569
- const chips = canvas.getAllByRole("list")[0];
570
- const selectedUpperCaseChip = within(chips).getAllByRole("listitem")[0];
571
- expect(selectedUpperCaseChip).toHaveTextContent("Camel Case"); // A weird issue is preventing the accessible name from being used in the test, even if it works in VoiceOver
572
-
573
- // With custom option
574
- userEvent.click(input);
575
- await userEvent.type(input, "cAmEl{Backspace}", { delay: 250 });
576
- await sleep(250);
577
- expect(input.value).toBe("cAmEl");
578
- await userEvent.type(input, "{Enter}");
579
- await sleep(250);
580
- const selectedNewValueChip = within(chips).getAllByRole("listitem")[0];
581
- expect(selectedNewValueChip).toHaveTextContent("cAmEl"); // A weird issue is preventing the accessible name from being used in the test, even if it works in VoiceOver
582
- },
583
- };
584
-
585
- export const TestHoverAndFocusSwitching: StoryObject = {
586
- render: () => {
587
- return (
588
- <UNSAFE_Combobox options={options} label="Hva er dine favorittfrukter?" />
589
- );
590
- },
591
- play: async ({ canvasElement }) => {
592
- const canvas = within(canvasElement);
593
-
594
- await sleep(500);
595
-
596
- const getInput = () =>
597
- canvas.getByRole("combobox", {
598
- name: "Hva er dine favorittfrukter?",
599
- });
600
-
601
- userEvent.click(getInput());
602
- expect(getInput().getAttribute("aria-expanded")).toEqual("false");
603
- expect(getInput().getAttribute("aria-activedescendant")).toBeNull();
604
-
605
- await sleep(250);
606
- userEvent.keyboard("{ArrowDown}");
607
- await sleep(250);
608
- const bananaOption = canvas.getByRole("option", { name: "banana" });
609
- expect(getInput().getAttribute("aria-activedescendant")).toBe(
610
- bananaOption.getAttribute("id"),
611
- );
612
-
613
- userEvent.keyboard("{ArrowDown}");
614
- await sleep(250);
615
- const appleOption = canvas.getByRole("option", { name: "apple" });
616
- expect(getInput().getAttribute("aria-activedescendant")).toBe(
617
- appleOption.getAttribute("id"),
618
- );
619
-
620
- userEvent.hover(bananaOption);
621
- await sleep(250);
622
- expect(getInput().getAttribute("aria-activedescendant")).toBe(
623
- bananaOption.getAttribute("id"),
624
- );
625
- },
626
- };