@oslokommune/punkt-react 15.4.6 → 16.0.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 (29) hide show
  1. package/CHANGELOG.md +74 -0
  2. package/dist/index.d.ts +38 -15
  3. package/dist/punkt-react.es.js +12025 -10664
  4. package/dist/punkt-react.umd.js +562 -549
  5. package/package.json +5 -5
  6. package/src/components/accordion/Accordion.test.tsx +3 -2
  7. package/src/components/alert/Alert.test.tsx +2 -1
  8. package/src/components/backlink/BackLink.test.tsx +2 -1
  9. package/src/components/button/Button.test.tsx +4 -3
  10. package/src/components/calendar/Calendar.interaction.test.tsx +2 -1
  11. package/src/components/checkbox/Checkbox.test.tsx +2 -1
  12. package/src/components/combobox/Combobox.accessibility.test.tsx +277 -0
  13. package/src/components/combobox/Combobox.core.test.tsx +469 -0
  14. package/src/components/combobox/Combobox.interaction.test.tsx +607 -0
  15. package/src/components/combobox/Combobox.selection.test.tsx +548 -0
  16. package/src/components/combobox/Combobox.tsx +59 -54
  17. package/src/components/combobox/ComboboxInput.tsx +140 -0
  18. package/src/components/combobox/ComboboxTags.tsx +110 -0
  19. package/src/components/combobox/Listbox.tsx +172 -0
  20. package/src/components/combobox/types.ts +145 -0
  21. package/src/components/combobox/useComboboxState.ts +1141 -0
  22. package/src/components/datepicker/Datepicker.accessibility.test.tsx +5 -4
  23. package/src/components/datepicker/Datepicker.input.test.tsx +3 -2
  24. package/src/components/datepicker/Datepicker.selection.test.tsx +8 -8
  25. package/src/components/datepicker/Datepicker.validation.test.tsx +2 -1
  26. package/src/components/radio/RadioButton.test.tsx +3 -2
  27. package/src/components/searchinput/SearchInput.test.tsx +6 -5
  28. package/src/components/tabs/Tabs.test.tsx +13 -12
  29. package/src/components/tag/Tag.test.tsx +2 -1
@@ -2,6 +2,7 @@ import '@testing-library/jest-dom'
2
2
 
3
3
  import { fireEvent, render, screen } from '@testing-library/react'
4
4
  import { axe, toHaveNoViolations } from 'jest-axe'
5
+ import { vi } from 'vitest'
5
6
 
6
7
  import { IPktDatepicker, PktDatepicker } from './Datepicker'
7
8
 
@@ -23,7 +24,7 @@ const createDatepickerTest = (props: Partial<IPktDatepicker> = {}) => {
23
24
  describe('PktDatepicker', () => {
24
25
  describe('Event handling', () => {
25
26
  test('dispatches onChange event when value changes', () => {
26
- const handleChange = jest.fn()
27
+ const handleChange = vi.fn()
27
28
  const { container } = createDatepickerTest({
28
29
  onChange: handleChange,
29
30
  })
@@ -35,7 +36,7 @@ describe('PktDatepicker', () => {
35
36
  })
36
37
 
37
38
  test('dispatches onValueChange event when value changes', () => {
38
- const handleValueChange = jest.fn()
39
+ const handleValueChange = vi.fn()
39
40
  const { container } = createDatepickerTest({
40
41
  onValueChange: handleValueChange,
41
42
  })
@@ -67,8 +68,8 @@ describe('PktDatepicker', () => {
67
68
  })
68
69
 
69
70
  test('dispatches both onChange and onValueChange', () => {
70
- const handleChange = jest.fn()
71
- const handleValueChange = jest.fn()
71
+ const handleChange = vi.fn()
72
+ const handleValueChange = vi.fn()
72
73
  const { container } = createDatepickerTest({
73
74
  onChange: handleChange,
74
75
  onValueChange: handleValueChange,
@@ -1,6 +1,7 @@
1
1
  import '@testing-library/jest-dom'
2
2
 
3
3
  import { fireEvent, render, screen } from '@testing-library/react'
4
+ import { vi } from 'vitest'
4
5
 
5
6
  import { IPktDatepicker, PktDatepicker } from './Datepicker'
6
7
 
@@ -20,7 +21,7 @@ const createDatepickerTest = (props: Partial<IPktDatepicker> = {}) => {
20
21
  describe('PktDatepicker', () => {
21
22
  describe('Input field behavior', () => {
22
23
  test('allows manual date entry via change event', () => {
23
- const handleValueChange = jest.fn()
24
+ const handleValueChange = vi.fn()
24
25
  const { container } = createDatepickerTest({
25
26
  onValueChange: handleValueChange,
26
27
  })
@@ -62,7 +63,7 @@ describe('PktDatepicker', () => {
62
63
  })
63
64
 
64
65
  test('clears value when empty string entered', () => {
65
- const handleValueChange = jest.fn()
66
+ const handleValueChange = vi.fn()
66
67
  const { container } = createDatepickerTest({
67
68
  value: '2024-06-15',
68
69
  onValueChange: handleValueChange,
@@ -32,7 +32,7 @@ describe('PktDatepicker', () => {
32
32
  })
33
33
 
34
34
  test('removes dates when clicking tag close button', async () => {
35
- const handleValueChange = jest.fn()
35
+ const handleValueChange = vi.fn()
36
36
  const { container } = createDatepickerTest({
37
37
  multiple: true,
38
38
  value: ['2024-06-15', '2024-06-20'],
@@ -107,7 +107,7 @@ describe('PktDatepicker', () => {
107
107
  })
108
108
 
109
109
  test('dispatches onValueChange with remaining dates when tag removed', async () => {
110
- const handleValueChange = jest.fn()
110
+ const handleValueChange = vi.fn()
111
111
  const { container } = createDatepickerTest({
112
112
  multiple: true,
113
113
  value: ['2024-06-15', '2024-06-20', '2024-06-25'],
@@ -199,7 +199,7 @@ describe('PktDatepicker', () => {
199
199
  })
200
200
 
201
201
  test('dispatches onValueChange for partial range (only from)', () => {
202
- const handleValueChange = jest.fn()
202
+ const handleValueChange = vi.fn()
203
203
  const { container } = createDatepickerTest({
204
204
  range: true,
205
205
  onValueChange: handleValueChange,
@@ -212,7 +212,7 @@ describe('PktDatepicker', () => {
212
212
  })
213
213
 
214
214
  test('dispatches onValueChange when both range dates are present', () => {
215
- const handleValueChange = jest.fn()
215
+ const handleValueChange = vi.fn()
216
216
  const { container } = createDatepickerTest({
217
217
  range: true,
218
218
  value: ['2024-06-15'],
@@ -226,7 +226,7 @@ describe('PktDatepicker', () => {
226
226
  })
227
227
 
228
228
  test('validates range order on blur (rejects end before start)', () => {
229
- const handleValueChange = jest.fn()
229
+ const handleValueChange = vi.fn()
230
230
  const { container } = createDatepickerTest({
231
231
  range: true,
232
232
  value: ['2024-06-25', '2024-06-15'],
@@ -300,7 +300,7 @@ describe('PktDatepicker', () => {
300
300
 
301
301
  describe('Single date selection', () => {
302
302
  test('dispatches onChange when input value changes', () => {
303
- const handleChange = jest.fn()
303
+ const handleChange = vi.fn()
304
304
  const { container } = createDatepickerTest({
305
305
  onChange: handleChange,
306
306
  })
@@ -312,7 +312,7 @@ describe('PktDatepicker', () => {
312
312
  })
313
313
 
314
314
  test('dispatches onValueChange with array when input value changes', () => {
315
- const handleValueChange = jest.fn()
315
+ const handleValueChange = vi.fn()
316
316
  const { container } = createDatepickerTest({
317
317
  onValueChange: handleValueChange,
318
318
  })
@@ -324,7 +324,7 @@ describe('PktDatepicker', () => {
324
324
  })
325
325
 
326
326
  test('dispatches onValueChange with empty array when cleared', () => {
327
- const handleValueChange = jest.fn()
327
+ const handleValueChange = vi.fn()
328
328
  const { container } = createDatepickerTest({
329
329
  value: '2024-06-15',
330
330
  onValueChange: handleValueChange,
@@ -1,6 +1,7 @@
1
1
  import '@testing-library/jest-dom'
2
2
 
3
3
  import { fireEvent, render } from '@testing-library/react'
4
+ import { vi } from 'vitest'
4
5
 
5
6
  import { IPktDatepicker, PktDatepicker } from './Datepicker'
6
7
 
@@ -301,7 +302,7 @@ describe('PktDatepicker', () => {
301
302
  })
302
303
 
303
304
  test('submits form on Enter key press', () => {
304
- const submitHandler = jest.fn((e: Event) => e.preventDefault())
305
+ const submitHandler = vi.fn((e: Event) => e.preventDefault())
305
306
  const { container } = render(
306
307
  <form onSubmit={submitHandler as unknown as React.FormEventHandler}>
307
308
  <PktDatepicker id={datePickerId} label={label} value="2024-06-15" />
@@ -2,6 +2,7 @@ import '@testing-library/jest-dom'
2
2
 
3
3
  import { fireEvent, render } from '@testing-library/react'
4
4
  import { axe, toHaveNoViolations } from 'jest-axe'
5
+ import { vi } from 'vitest'
5
6
 
6
7
  import { PktInputWrapper } from '../inputwrapper/InputWrapper'
7
8
  import { PktRadioButton } from './RadioButton'
@@ -21,7 +22,7 @@ describe('PktRadiobutton', () => {
21
22
  })
22
23
 
23
24
  it('allows selecting one option from the group', async () => {
24
- const handleChange = jest.fn()
25
+ const handleChange = vi.fn()
25
26
  const { container } = render(
26
27
  <PktInputWrapper forId="radioGroup" label="Etikett" hasFieldset>
27
28
  <PktRadioButton
@@ -42,7 +43,7 @@ describe('PktRadiobutton', () => {
42
43
  expect(option1).toBeInTheDocument()
43
44
  expect(option2).toBeInTheDocument()
44
45
 
45
- const changeHandler = jest.fn()
46
+ const changeHandler = vi.fn()
46
47
  option2?.addEventListener('change', changeHandler)
47
48
 
48
49
  // Manually dispatch a change event
@@ -3,6 +3,7 @@ import '@testing-library/jest-dom'
3
3
  import { fireEvent, render, screen } from '@testing-library/react'
4
4
  import { axe, toHaveNoViolations } from 'jest-axe'
5
5
  import { ChangeEvent, useState } from 'react'
6
+ import { vi } from 'vitest'
6
7
 
7
8
  import { PktSearchInput } from './SearchInput'
8
9
 
@@ -49,7 +50,7 @@ describe('PktSearchInput', () => {
49
50
  })
50
51
 
51
52
  it('calls onSearch prop with input value on button click', async () => {
52
- const mockOnSearch = jest.fn()
53
+ const mockOnSearch = vi.fn()
53
54
  const { getByRole, getByPlaceholderText } = render(<Wrapper onChange={mockOnSearch} />)
54
55
  await window.customElements.whenDefined('pkt-icon')
55
56
 
@@ -70,8 +71,8 @@ describe('PktSearchInput', () => {
70
71
 
71
72
  it('renders search suggestions when suggestions prop exists', async () => {
72
73
  const suggestions = [
73
- { title: 'Suggestion 1', onClick: jest.fn() },
74
- { title: 'Suggestion 2', onClick: jest.fn() },
74
+ { title: 'Suggestion 1', onClick: vi.fn() },
75
+ { title: 'Suggestion 2', onClick: vi.fn() },
75
76
  ]
76
77
 
77
78
  render(<PktSearchInput id="test-search-input" suggestions={suggestions} />)
@@ -86,8 +87,8 @@ describe('PktSearchInput', () => {
86
87
  describe('accessibility', () => {
87
88
  it('renders with no wcag errors with axe', async () => {
88
89
  const suggestions = [
89
- { title: 'Suggestion 1', onClick: jest.fn() },
90
- { title: 'Suggestion 2', onClick: jest.fn() },
90
+ { title: 'Suggestion 1', onClick: vi.fn() },
91
+ { title: 'Suggestion 2', onClick: vi.fn() },
91
92
  ]
92
93
  const { container } = render(<PktSearchInput id="test-search-input" label="My label" suggestions={suggestions} />)
93
94
  await window.customElements.whenDefined('pkt-icon')
@@ -2,6 +2,7 @@ import '@testing-library/jest-dom'
2
2
 
3
3
  import { fireEvent, render } from '@testing-library/react'
4
4
  import { axe, toHaveNoViolations } from 'jest-axe'
5
+ import { vi } from 'vitest'
5
6
 
6
7
  import { PktTabItem, PktTabs } from './Tabs'
7
8
 
@@ -9,8 +10,8 @@ expect.extend(toHaveNoViolations)
9
10
 
10
11
  describe('Tabs component', () => {
11
12
  const tabs = [
12
- { text: 'Tab 1', href: '#', action: jest.fn() },
13
- { text: 'Tab 2', action: jest.fn() },
13
+ { text: 'Tab 1', href: '#', action: vi.fn() },
14
+ { text: 'Tab 2', action: vi.fn() },
14
15
  ]
15
16
 
16
17
  it('renders tabs with links and buttons', () => {
@@ -36,7 +37,7 @@ describe('Tabs component', () => {
36
37
  })
37
38
 
38
39
  it('calls onTabSelected prop when a tab is clicked', () => {
39
- const onTabSelected = jest.fn()
40
+ const onTabSelected = vi.fn()
40
41
  const { getByText } = render(<PktTabs tabs={tabs} onTabSelected={onTabSelected} />)
41
42
  tabs.forEach((tab, index) => {
42
43
  const tabElement = getByText(tab.text)
@@ -47,8 +48,8 @@ describe('Tabs component', () => {
47
48
  describe('accessibility', () => {
48
49
  it('renders with no wcag errors with axe', async () => {
49
50
  const tabs = [
50
- { text: 'Tab 1', href: '/page1', action: jest.fn() },
51
- { text: 'Tab 2', action: jest.fn() },
51
+ { text: 'Tab 1', href: '/page1', action: vi.fn() },
52
+ { text: 'Tab 2', action: vi.fn() },
52
53
  ]
53
54
  const { container } = render(<PktTabs tabs={tabs} />)
54
55
  const results = await axe(container)
@@ -89,7 +90,7 @@ describe('PktTabItem children format', () => {
89
90
  })
90
91
 
91
92
  it('calls onClick handler when tab is clicked', () => {
92
- const handleClick = jest.fn()
93
+ const handleClick = vi.fn()
93
94
  const { getByText } = render(
94
95
  <PktTabs>
95
96
  <PktTabItem index={0}>First Tab</PktTabItem>
@@ -106,7 +107,7 @@ describe('PktTabItem children format', () => {
106
107
  })
107
108
 
108
109
  it('calls onTabSelected when tab is clicked', () => {
109
- const handleTabSelected = jest.fn()
110
+ const handleTabSelected = vi.fn()
110
111
  const { getByText } = render(
111
112
  <PktTabs onTabSelected={handleTabSelected}>
112
113
  <PktTabItem index={0}>First Tab</PktTabItem>
@@ -120,8 +121,8 @@ describe('PktTabItem children format', () => {
120
121
  })
121
122
 
122
123
  it('calls both onClick and onTabSelected when tab is clicked', () => {
123
- const handleClick = jest.fn()
124
- const handleTabSelected = jest.fn()
124
+ const handleClick = vi.fn()
125
+ const handleTabSelected = vi.fn()
125
126
  const { getByText } = render(
126
127
  <PktTabs onTabSelected={handleTabSelected}>
127
128
  <PktTabItem index={0}>First Tab</PktTabItem>
@@ -268,7 +269,7 @@ describe('PktTabItem children format', () => {
268
269
  })
269
270
 
270
271
  it('selects tab when Space key is pressed', () => {
271
- const handleTabSelected = jest.fn()
272
+ const handleTabSelected = vi.fn()
272
273
  const { getByText } = render(
273
274
  <PktTabs onTabSelected={handleTabSelected}>
274
275
  <PktTabItem index={0}>First Tab</PktTabItem>
@@ -283,7 +284,7 @@ describe('PktTabItem children format', () => {
283
284
  })
284
285
 
285
286
  it('selects tab when ArrowDown key is pressed', () => {
286
- const handleTabSelected = jest.fn()
287
+ const handleTabSelected = vi.fn()
287
288
  const { getByText } = render(
288
289
  <PktTabs onTabSelected={handleTabSelected}>
289
290
  <PktTabItem index={0}>First Tab</PktTabItem>
@@ -357,7 +358,7 @@ describe('PktTabItem children format', () => {
357
358
 
358
359
  it('works with mapped children when explicit index is provided', () => {
359
360
  const items = ['First', 'Second', 'Third']
360
- const handleTabSelected = jest.fn()
361
+ const handleTabSelected = vi.fn()
361
362
 
362
363
  const { getByText } = render(
363
364
  <PktTabs onTabSelected={handleTabSelected}>
@@ -3,6 +3,7 @@ import '@testing-library/jest-dom'
3
3
  import { fireEvent, render as originalRender, RenderOptions, RenderResult } from '@testing-library/react'
4
4
  import { axe, toHaveNoViolations } from 'jest-axe'
5
5
  import { createRef, ReactNode } from 'react'
6
+ import { vi } from 'vitest'
6
7
 
7
8
  import { PktTag } from './Tag'
8
9
 
@@ -68,7 +69,7 @@ describe('PktTag', () => {
68
69
  })
69
70
 
70
71
  it('calls onClose when tag is clicked', async () => {
71
- const onClose = jest.fn()
72
+ const onClose = vi.fn()
72
73
  const { getByText } = await render(
73
74
  <PktTag closeTag={true} onClose={onClose}>
74
75
  Closeable Tag