@oslokommune/punkt-elements 15.4.5 → 16.0.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +34 -0
- package/dist/{card-CnPjrdre.js → card-CmfUyl_s.js} +1 -1
- package/dist/{card-5S2r9UD1.cjs → card-Db9QSEqh.cjs} +1 -1
- package/dist/{checkbox-D98_NjcU.cjs → checkbox-Cpyay9_l.cjs} +1 -1
- package/dist/{checkbox-BSz71IeT.js → checkbox-D6nltMuc.js} +1 -1
- package/dist/combobox-Bv37b6cI.cjs +135 -0
- package/dist/combobox-CoO8T-F-.js +818 -0
- package/dist/{datepicker-SEKblnRR.cjs → datepicker-CrvQ5Y5w.cjs} +1 -1
- package/dist/{datepicker-nnyTW0vf.js → datepicker-DbsIuC5Z.js} +2 -2
- package/dist/index.d.ts +157 -90
- package/dist/{input-element-Bkv6Yxld.js → input-element-BGNbdzy2.js} +1 -1
- package/dist/{input-element-DM0tY799.cjs → input-element-CSDVA3Y6.cjs} +1 -1
- package/dist/listbox-Dm2mKp6_.cjs +101 -0
- package/dist/listbox-OdkIn9_A.js +431 -0
- package/dist/pkt-card.cjs +1 -1
- package/dist/pkt-card.js +1 -1
- package/dist/pkt-checkbox.cjs +1 -1
- package/dist/pkt-checkbox.js +1 -1
- package/dist/pkt-combobox.cjs +1 -1
- package/dist/pkt-combobox.js +1 -1
- package/dist/pkt-datepicker.cjs +1 -1
- package/dist/pkt-datepicker.js +2 -2
- package/dist/pkt-header.cjs +1 -1
- package/dist/pkt-header.js +1 -1
- package/dist/pkt-index.cjs +1 -1
- package/dist/pkt-index.js +9 -9
- package/dist/pkt-listbox.cjs +1 -1
- package/dist/pkt-listbox.js +1 -1
- package/dist/pkt-options-controller-BogGk-6J.cjs +1 -0
- package/dist/{pkt-options-controller-BcGywCmf.js → pkt-options-controller-Z-bPox7n.js} +2 -2
- package/dist/pkt-radiobutton.cjs +1 -1
- package/dist/pkt-radiobutton.js +1 -1
- package/dist/pkt-select.cjs +1 -1
- package/dist/pkt-select.js +1 -1
- package/dist/pkt-tag.cjs +1 -1
- package/dist/pkt-tag.js +1 -1
- package/dist/pkt-textarea.cjs +1 -1
- package/dist/pkt-textarea.js +1 -1
- package/dist/pkt-textinput.cjs +1 -1
- package/dist/pkt-textinput.js +1 -1
- package/dist/{radiobutton-95wp024h.cjs → radiobutton-CNHCpKn0.cjs} +1 -1
- package/dist/{radiobutton-CTFAV5GU.js → radiobutton-DgC27mb0.js} +1 -1
- package/dist/{select-YLvYAQX6.js → select-7VuYtPZv.js} +2 -2
- package/dist/{select-CZ_Lx5W6.cjs → select-PWPy5gTB.cjs} +1 -1
- package/dist/{tag-68q0_Sn0.js → tag-DZPqFiem.js} +37 -33
- package/dist/tag-DmbgBCKu.cjs +27 -0
- package/dist/{textarea-CuTsE1WX.cjs → textarea-CO7Ikug5.cjs} +1 -1
- package/dist/{textarea-DhWH99qN.js → textarea-VpCEjVFx.js} +1 -1
- package/dist/{textinput-BCi9p0Du.js → textinput-C2AZ9ss2.js} +1 -1
- package/dist/{textinput-st4Vml5J.cjs → textinput-DRFZU3dA.cjs} +1 -1
- package/package.json +4 -4
- package/src/components/card/card.ts +1 -0
- package/src/components/combobox/combobox-base.ts +158 -0
- package/src/components/combobox/combobox-handlers.ts +419 -0
- package/src/components/combobox/combobox-types.ts +10 -0
- package/src/components/combobox/combobox-utils.ts +135 -0
- package/src/components/combobox/combobox-value.ts +248 -0
- package/src/components/combobox/combobox.accessibility.test.ts +243 -0
- package/src/components/combobox/{combobox.test.ts → combobox.core.test.ts} +104 -46
- package/src/components/combobox/combobox.interaction.test.ts +436 -0
- package/src/components/combobox/combobox.selection.test.ts +543 -0
- package/src/components/combobox/combobox.ts +260 -734
- package/src/components/listbox/index.ts +2 -0
- package/src/components/listbox/listbox.interaction.test.ts +580 -0
- package/src/components/listbox/listbox.test.ts +32 -6
- package/src/components/listbox/listbox.ts +109 -126
- package/src/components/tag/tag.ts +3 -0
- package/dist/combobox-C5YcNVSZ.cjs +0 -128
- package/dist/combobox-cer7PLSE.js +0 -533
- package/dist/listbox-C7NEa9SU.cjs +0 -96
- package/dist/listbox-Cykec1bj.js +0 -361
- package/dist/pkt-options-controller-BnTmkl3g.cjs +0 -1
- package/dist/tag-BnT5onW2.cjs +0 -26
|
@@ -0,0 +1,436 @@
|
|
|
1
|
+
import '@testing-library/jest-dom'
|
|
2
|
+
import { fireEvent } from '@testing-library/dom'
|
|
3
|
+
|
|
4
|
+
import './combobox'
|
|
5
|
+
import { PktCombobox } from './combobox'
|
|
6
|
+
import type { IPktComboboxOption } from './combobox'
|
|
7
|
+
|
|
8
|
+
const waitForCustomElements = async () => {
|
|
9
|
+
await customElements.whenDefined('pkt-combobox')
|
|
10
|
+
}
|
|
11
|
+
|
|
12
|
+
const createCombobox = async (comboboxProps = '') => {
|
|
13
|
+
const container = document.createElement('div')
|
|
14
|
+
container.innerHTML = `
|
|
15
|
+
<pkt-combobox ${comboboxProps}></pkt-combobox>
|
|
16
|
+
`
|
|
17
|
+
document.body.appendChild(container)
|
|
18
|
+
await waitForCustomElements()
|
|
19
|
+
return container
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
const defaultOptions: IPktComboboxOption[] = [
|
|
23
|
+
{ value: 'apple', label: 'Apple' },
|
|
24
|
+
{ value: 'banana', label: 'Banana' },
|
|
25
|
+
{ value: 'cherry', label: 'Cherry' },
|
|
26
|
+
{ value: 'date', label: 'Date' },
|
|
27
|
+
]
|
|
28
|
+
|
|
29
|
+
afterEach(() => {
|
|
30
|
+
document.body.innerHTML = ''
|
|
31
|
+
})
|
|
32
|
+
|
|
33
|
+
describe('PktCombobox', () => {
|
|
34
|
+
describe('Keyboard navigation', () => {
|
|
35
|
+
test('opens dropdown with Enter on arrow button', async () => {
|
|
36
|
+
const container = await createCombobox('id="test" name="test" label="Test"')
|
|
37
|
+
const combobox = container.querySelector('pkt-combobox') as PktCombobox
|
|
38
|
+
await combobox.updateComplete
|
|
39
|
+
|
|
40
|
+
const arrowButton = combobox.querySelector('.pkt-combobox__input')
|
|
41
|
+
fireEvent.keyDown(arrowButton!, { key: 'Enter' })
|
|
42
|
+
await combobox.updateComplete
|
|
43
|
+
|
|
44
|
+
expect(combobox['_isOptionsOpen']).toBe(true)
|
|
45
|
+
})
|
|
46
|
+
|
|
47
|
+
test('opens dropdown with Space on arrow button', async () => {
|
|
48
|
+
const container = await createCombobox('id="test" name="test" label="Test"')
|
|
49
|
+
const combobox = container.querySelector('pkt-combobox') as PktCombobox
|
|
50
|
+
await combobox.updateComplete
|
|
51
|
+
|
|
52
|
+
const arrowButton = combobox.querySelector('.pkt-combobox__input')
|
|
53
|
+
fireEvent.keyDown(arrowButton!, { key: ' ' })
|
|
54
|
+
await combobox.updateComplete
|
|
55
|
+
|
|
56
|
+
expect(combobox['_isOptionsOpen']).toBe(true)
|
|
57
|
+
})
|
|
58
|
+
|
|
59
|
+
test('opens dropdown with ArrowDown on arrow button', async () => {
|
|
60
|
+
const container = await createCombobox('id="test" name="test" label="Test"')
|
|
61
|
+
const combobox = container.querySelector('pkt-combobox') as PktCombobox
|
|
62
|
+
await combobox.updateComplete
|
|
63
|
+
|
|
64
|
+
const arrowButton = combobox.querySelector('.pkt-combobox__input')
|
|
65
|
+
fireEvent.keyDown(arrowButton!, { key: 'ArrowDown' })
|
|
66
|
+
await combobox.updateComplete
|
|
67
|
+
|
|
68
|
+
expect(combobox['_isOptionsOpen']).toBe(true)
|
|
69
|
+
})
|
|
70
|
+
|
|
71
|
+
test('toggles dropdown closed with Enter on arrow button', async () => {
|
|
72
|
+
const container = await createCombobox('id="test" name="test" label="Test"')
|
|
73
|
+
const combobox = container.querySelector('pkt-combobox') as PktCombobox
|
|
74
|
+
await combobox.updateComplete
|
|
75
|
+
|
|
76
|
+
const arrowButton = combobox.querySelector('.pkt-combobox__input')
|
|
77
|
+
|
|
78
|
+
// Open
|
|
79
|
+
fireEvent.keyDown(arrowButton!, { key: 'Enter' })
|
|
80
|
+
await combobox.updateComplete
|
|
81
|
+
expect(combobox['_isOptionsOpen']).toBe(true)
|
|
82
|
+
|
|
83
|
+
// Close
|
|
84
|
+
fireEvent.keyDown(arrowButton!, { key: 'Enter' })
|
|
85
|
+
await combobox.updateComplete
|
|
86
|
+
expect(combobox['_isOptionsOpen']).toBe(false)
|
|
87
|
+
})
|
|
88
|
+
|
|
89
|
+
test('does not toggle on non-toggle keys', async () => {
|
|
90
|
+
const container = await createCombobox('id="test" name="test" label="Test"')
|
|
91
|
+
const combobox = container.querySelector('pkt-combobox') as PktCombobox
|
|
92
|
+
await combobox.updateComplete
|
|
93
|
+
|
|
94
|
+
const arrowButton = combobox.querySelector('.pkt-combobox__input')
|
|
95
|
+
fireEvent.keyDown(arrowButton!, { key: 'Escape' })
|
|
96
|
+
await combobox.updateComplete
|
|
97
|
+
|
|
98
|
+
expect(combobox['_isOptionsOpen']).toBe(false)
|
|
99
|
+
})
|
|
100
|
+
|
|
101
|
+
test('submits value with Enter in text input', async () => {
|
|
102
|
+
const container = await createCombobox('id="test" name="test" label="Test" allow-user-input')
|
|
103
|
+
const combobox = container.querySelector('pkt-combobox') as PktCombobox
|
|
104
|
+
combobox.options = [...defaultOptions]
|
|
105
|
+
await combobox.updateComplete
|
|
106
|
+
|
|
107
|
+
const input = combobox.querySelector('input[type="text"]') as HTMLInputElement
|
|
108
|
+
fireEvent.focus(input)
|
|
109
|
+
await combobox.updateComplete
|
|
110
|
+
|
|
111
|
+
input.value = 'apple'
|
|
112
|
+
fireEvent.keyDown(input, { key: 'Enter' })
|
|
113
|
+
await combobox.updateComplete
|
|
114
|
+
|
|
115
|
+
expect(combobox['_value']).toContain('apple')
|
|
116
|
+
})
|
|
117
|
+
|
|
118
|
+
test('closes dropdown with Escape in text input', async () => {
|
|
119
|
+
const container = await createCombobox('id="test" name="test" label="Test" allow-user-input')
|
|
120
|
+
const combobox = container.querySelector('pkt-combobox') as PktCombobox
|
|
121
|
+
combobox.options = [...defaultOptions]
|
|
122
|
+
await combobox.updateComplete
|
|
123
|
+
|
|
124
|
+
const input = combobox.querySelector('input[type="text"]') as HTMLInputElement
|
|
125
|
+
fireEvent.focus(input)
|
|
126
|
+
await combobox.updateComplete
|
|
127
|
+
expect(combobox['_isOptionsOpen']).toBe(true)
|
|
128
|
+
|
|
129
|
+
fireEvent.keyDown(input, { key: 'Escape' })
|
|
130
|
+
await combobox.updateComplete
|
|
131
|
+
|
|
132
|
+
expect(combobox['_isOptionsOpen']).toBe(false)
|
|
133
|
+
})
|
|
134
|
+
|
|
135
|
+
test('does not open dropdown when disabled', async () => {
|
|
136
|
+
const container = await createCombobox('id="test" name="test" label="Test" disabled')
|
|
137
|
+
const combobox = container.querySelector('pkt-combobox') as PktCombobox
|
|
138
|
+
await combobox.updateComplete
|
|
139
|
+
|
|
140
|
+
const arrowButton = combobox.querySelector('.pkt-combobox__input')
|
|
141
|
+
fireEvent.keyDown(arrowButton!, { key: 'Enter' })
|
|
142
|
+
await combobox.updateComplete
|
|
143
|
+
|
|
144
|
+
expect(combobox['_isOptionsOpen']).toBe(false)
|
|
145
|
+
})
|
|
146
|
+
})
|
|
147
|
+
|
|
148
|
+
describe('Focus handling', () => {
|
|
149
|
+
test('opens dropdown on input focus', async () => {
|
|
150
|
+
const container = await createCombobox('id="test" name="test" label="Test" allow-user-input')
|
|
151
|
+
const combobox = container.querySelector('pkt-combobox') as PktCombobox
|
|
152
|
+
combobox.options = [...defaultOptions]
|
|
153
|
+
await combobox.updateComplete
|
|
154
|
+
|
|
155
|
+
const input = combobox.querySelector('input[type="text"]') as HTMLInputElement
|
|
156
|
+
fireEvent.focus(input)
|
|
157
|
+
await combobox.updateComplete
|
|
158
|
+
|
|
159
|
+
expect(combobox['_isOptionsOpen']).toBe(true)
|
|
160
|
+
expect(combobox['_inputFocus']).toBe(true)
|
|
161
|
+
})
|
|
162
|
+
|
|
163
|
+
test('populates input with current value on focus in single-select', async () => {
|
|
164
|
+
const container = await createCombobox(
|
|
165
|
+
'id="test" name="test" label="Test" allow-user-input value="apple"',
|
|
166
|
+
)
|
|
167
|
+
const combobox = container.querySelector('pkt-combobox') as PktCombobox
|
|
168
|
+
combobox.options = [...defaultOptions]
|
|
169
|
+
await combobox.updateComplete
|
|
170
|
+
|
|
171
|
+
const input = combobox.querySelector('input[type="text"]') as HTMLInputElement
|
|
172
|
+
fireEvent.focus(input)
|
|
173
|
+
await combobox.updateComplete
|
|
174
|
+
|
|
175
|
+
expect(input.value).toBe('Apple')
|
|
176
|
+
})
|
|
177
|
+
|
|
178
|
+
test('handles blur correctly', async () => {
|
|
179
|
+
const container = await createCombobox('id="test" name="test" label="Test" allow-user-input')
|
|
180
|
+
const combobox = container.querySelector('pkt-combobox') as PktCombobox
|
|
181
|
+
await combobox.updateComplete
|
|
182
|
+
|
|
183
|
+
const input = combobox.querySelector('input[type="text"]') as HTMLInputElement
|
|
184
|
+
fireEvent.focus(input)
|
|
185
|
+
await combobox.updateComplete
|
|
186
|
+
|
|
187
|
+
fireEvent.blur(input)
|
|
188
|
+
await combobox.updateComplete
|
|
189
|
+
|
|
190
|
+
expect(combobox['_inputFocus']).toBe(false)
|
|
191
|
+
})
|
|
192
|
+
|
|
193
|
+
test('opens dropdown on input container click', async () => {
|
|
194
|
+
const container = await createCombobox('id="test" name="test" label="Test"')
|
|
195
|
+
const combobox = container.querySelector('pkt-combobox') as PktCombobox
|
|
196
|
+
await combobox.updateComplete
|
|
197
|
+
|
|
198
|
+
const inputDiv = combobox.querySelector('.pkt-combobox__input')
|
|
199
|
+
fireEvent.click(inputDiv!)
|
|
200
|
+
await combobox.updateComplete
|
|
201
|
+
|
|
202
|
+
expect(combobox['_isOptionsOpen']).toBe(true)
|
|
203
|
+
})
|
|
204
|
+
|
|
205
|
+
test('does not open when disabled and input container is clicked', async () => {
|
|
206
|
+
const container = await createCombobox('id="test" name="test" label="Test" disabled')
|
|
207
|
+
const combobox = container.querySelector('pkt-combobox') as PktCombobox
|
|
208
|
+
await combobox.updateComplete
|
|
209
|
+
|
|
210
|
+
const inputDiv = combobox.querySelector('.pkt-combobox__input')
|
|
211
|
+
fireEvent.click(inputDiv!)
|
|
212
|
+
await combobox.updateComplete
|
|
213
|
+
|
|
214
|
+
expect(combobox['_isOptionsOpen']).toBe(false)
|
|
215
|
+
})
|
|
216
|
+
})
|
|
217
|
+
|
|
218
|
+
describe('Focus-out behavior', () => {
|
|
219
|
+
test('closes dropdown when clicking outside combobox', async () => {
|
|
220
|
+
const container = await createCombobox('id="test" name="test" label="Test"')
|
|
221
|
+
const combobox = container.querySelector('pkt-combobox') as PktCombobox
|
|
222
|
+
await combobox.updateComplete
|
|
223
|
+
|
|
224
|
+
const arrowButton = combobox.querySelector('.pkt-combobox__input')
|
|
225
|
+
fireEvent.click(arrowButton!)
|
|
226
|
+
await combobox.updateComplete
|
|
227
|
+
expect(combobox['_isOptionsOpen']).toBe(true)
|
|
228
|
+
|
|
229
|
+
fireEvent.click(document.body)
|
|
230
|
+
await combobox.updateComplete
|
|
231
|
+
|
|
232
|
+
expect(combobox['_isOptionsOpen']).toBe(false)
|
|
233
|
+
})
|
|
234
|
+
|
|
235
|
+
test('selects matching option on focus-out when allowUserInput is off', async () => {
|
|
236
|
+
const container = await createCombobox('id="test" name="test" label="Test" typeahead')
|
|
237
|
+
const combobox = container.querySelector('pkt-combobox') as PktCombobox
|
|
238
|
+
combobox.options = [...defaultOptions]
|
|
239
|
+
await combobox.updateComplete
|
|
240
|
+
|
|
241
|
+
const input = combobox.querySelector('input[type="text"]') as HTMLInputElement
|
|
242
|
+
fireEvent.focus(input)
|
|
243
|
+
await combobox.updateComplete
|
|
244
|
+
|
|
245
|
+
input.value = 'Apple'
|
|
246
|
+
combobox['_isOptionsOpen'] = true
|
|
247
|
+
await combobox.updateComplete
|
|
248
|
+
;(combobox as any).closeAndProcessInput()
|
|
249
|
+
await combobox.updateComplete
|
|
250
|
+
|
|
251
|
+
expect(combobox['_value']).toContain('apple')
|
|
252
|
+
})
|
|
253
|
+
|
|
254
|
+
test('adds custom value on focus-out when allowUserInput is on', async () => {
|
|
255
|
+
const container = await createCombobox('id="test" name="test" label="Test" allow-user-input')
|
|
256
|
+
const combobox = container.querySelector('pkt-combobox') as PktCombobox
|
|
257
|
+
combobox.options = [...defaultOptions]
|
|
258
|
+
await combobox.updateComplete
|
|
259
|
+
|
|
260
|
+
const input = combobox.querySelector('input[type="text"]') as HTMLInputElement
|
|
261
|
+
fireEvent.focus(input)
|
|
262
|
+
await combobox.updateComplete
|
|
263
|
+
|
|
264
|
+
input.value = 'NewFruit'
|
|
265
|
+
combobox['_isOptionsOpen'] = true
|
|
266
|
+
await combobox.updateComplete
|
|
267
|
+
;(combobox as any).closeAndProcessInput()
|
|
268
|
+
await combobox.updateComplete
|
|
269
|
+
|
|
270
|
+
expect(combobox['_value']).toContain('NewFruit')
|
|
271
|
+
})
|
|
272
|
+
})
|
|
273
|
+
|
|
274
|
+
describe('Search and filtering', () => {
|
|
275
|
+
test('filters options when typing in typeahead mode', async () => {
|
|
276
|
+
const container = await createCombobox('id="test" name="test" label="Test" typeahead')
|
|
277
|
+
const combobox = container.querySelector('pkt-combobox') as PktCombobox
|
|
278
|
+
combobox.options = [...defaultOptions]
|
|
279
|
+
await combobox.updateComplete
|
|
280
|
+
|
|
281
|
+
const input = combobox.querySelector('input[type="text"]') as HTMLInputElement
|
|
282
|
+
fireEvent.focus(input)
|
|
283
|
+
await combobox.updateComplete
|
|
284
|
+
|
|
285
|
+
// Type to filter
|
|
286
|
+
input.value = 'app'
|
|
287
|
+
fireEvent.input(input, { target: { value: 'app' } })
|
|
288
|
+
await combobox.updateComplete
|
|
289
|
+
|
|
290
|
+
const listbox = combobox.querySelector('pkt-listbox') as any
|
|
291
|
+
await listbox?.updateComplete
|
|
292
|
+
|
|
293
|
+
// Internal _options should be filtered
|
|
294
|
+
const filteredCount = combobox['_options'].length
|
|
295
|
+
expect(filteredCount).toBeLessThan(defaultOptions.length)
|
|
296
|
+
})
|
|
297
|
+
|
|
298
|
+
test('shows no-match message when search has no results and allowUserInput is off', async () => {
|
|
299
|
+
const container = await createCombobox('id="test" name="test" label="Test" typeahead')
|
|
300
|
+
const combobox = container.querySelector('pkt-combobox') as PktCombobox
|
|
301
|
+
combobox.options = [...defaultOptions]
|
|
302
|
+
await combobox.updateComplete
|
|
303
|
+
|
|
304
|
+
const input = combobox.querySelector('input[type="text"]') as HTMLInputElement
|
|
305
|
+
fireEvent.focus(input)
|
|
306
|
+
await combobox.updateComplete
|
|
307
|
+
|
|
308
|
+
input.value = 'zzzzz'
|
|
309
|
+
fireEvent.input(input, { target: { value: 'zzzzz' } })
|
|
310
|
+
await combobox.updateComplete
|
|
311
|
+
|
|
312
|
+
const listbox = combobox.querySelector('pkt-listbox') as any
|
|
313
|
+
await listbox?.updateComplete
|
|
314
|
+
|
|
315
|
+
const visibleOptions = combobox.querySelectorAll('.pkt-listbox__option')
|
|
316
|
+
expect(visibleOptions.length).toBe(0)
|
|
317
|
+
})
|
|
318
|
+
|
|
319
|
+
test('shows add-value banner when search has no exact match and allowUserInput is on', async () => {
|
|
320
|
+
const container = await createCombobox('id="test" name="test" label="Test" allow-user-input')
|
|
321
|
+
const combobox = container.querySelector('pkt-combobox') as PktCombobox
|
|
322
|
+
combobox.options = [...defaultOptions]
|
|
323
|
+
await combobox.updateComplete
|
|
324
|
+
|
|
325
|
+
const input = combobox.querySelector('input[type="text"]') as HTMLInputElement
|
|
326
|
+
fireEvent.focus(input)
|
|
327
|
+
await combobox.updateComplete
|
|
328
|
+
|
|
329
|
+
input.value = 'NewFruit'
|
|
330
|
+
fireEvent.input(input, { target: { value: 'NewFruit' } })
|
|
331
|
+
await combobox.updateComplete
|
|
332
|
+
|
|
333
|
+
const listbox = combobox.querySelector('pkt-listbox') as any
|
|
334
|
+
await listbox?.updateComplete
|
|
335
|
+
|
|
336
|
+
const addBanner = combobox.querySelector('.pkt-listbox__banner--new-option')
|
|
337
|
+
expect(addBanner).toBeInTheDocument()
|
|
338
|
+
})
|
|
339
|
+
|
|
340
|
+
test('dispatches search event on internal search state change', async () => {
|
|
341
|
+
const container = await createCombobox('id="test" name="test" label="Test" include-search')
|
|
342
|
+
const combobox = container.querySelector('pkt-combobox') as PktCombobox
|
|
343
|
+
await combobox.updateComplete
|
|
344
|
+
|
|
345
|
+
let searchEventDetail: string | null = null
|
|
346
|
+
combobox.addEventListener('search', (e: Event) => {
|
|
347
|
+
searchEventDetail = (e as CustomEvent).detail
|
|
348
|
+
})
|
|
349
|
+
|
|
350
|
+
combobox['_search'] = 'test query'
|
|
351
|
+
await combobox.updateComplete
|
|
352
|
+
|
|
353
|
+
expect(searchEventDetail).toBe('test query')
|
|
354
|
+
})
|
|
355
|
+
|
|
356
|
+
test('resets search when option is selected via toggleValue', async () => {
|
|
357
|
+
const container = await createCombobox('id="test" name="test" label="Test" typeahead')
|
|
358
|
+
const combobox = container.querySelector('pkt-combobox') as PktCombobox
|
|
359
|
+
combobox.options = [...defaultOptions]
|
|
360
|
+
await combobox.updateComplete
|
|
361
|
+
|
|
362
|
+
// Set some search state
|
|
363
|
+
combobox['_search'] = 'app'
|
|
364
|
+
await combobox.updateComplete
|
|
365
|
+
|
|
366
|
+
// Select an option
|
|
367
|
+
;(combobox as any).toggleValue('apple')
|
|
368
|
+
await combobox.updateComplete
|
|
369
|
+
|
|
370
|
+
expect(combobox['_search']).toBe('')
|
|
371
|
+
})
|
|
372
|
+
})
|
|
373
|
+
|
|
374
|
+
describe('Listbox search (includeSearch)', () => {
|
|
375
|
+
test('passes includeSearch to listbox', async () => {
|
|
376
|
+
const container = await createCombobox('id="test" name="test" label="Test" include-search')
|
|
377
|
+
const combobox = container.querySelector('pkt-combobox') as PktCombobox
|
|
378
|
+
await combobox.updateComplete
|
|
379
|
+
|
|
380
|
+
const listbox = combobox.querySelector('pkt-listbox')
|
|
381
|
+
expect(listbox?.hasAttribute('include-search')).toBe(true)
|
|
382
|
+
})
|
|
383
|
+
|
|
384
|
+
test('passes searchPlaceholder to listbox', async () => {
|
|
385
|
+
const container = await createCombobox(
|
|
386
|
+
'id="test" name="test" label="Test" include-search search-placeholder="Søk her..."',
|
|
387
|
+
)
|
|
388
|
+
const combobox = container.querySelector('pkt-combobox') as PktCombobox
|
|
389
|
+
await combobox.updateComplete
|
|
390
|
+
|
|
391
|
+
const listbox = combobox.querySelector('pkt-listbox') as any
|
|
392
|
+
expect(listbox?.searchPlaceholder).toBe('Søk her...')
|
|
393
|
+
})
|
|
394
|
+
|
|
395
|
+
test('updates search state on listbox search-change event', async () => {
|
|
396
|
+
const container = await createCombobox('id="test" name="test" label="Test" include-search')
|
|
397
|
+
const combobox = container.querySelector('pkt-combobox') as PktCombobox
|
|
398
|
+
combobox.options = [...defaultOptions]
|
|
399
|
+
await combobox.updateComplete
|
|
400
|
+
|
|
401
|
+
// Open dropdown first
|
|
402
|
+
const arrowButton = combobox.querySelector('.pkt-combobox__input')
|
|
403
|
+
fireEvent.click(arrowButton!)
|
|
404
|
+
await combobox.updateComplete
|
|
405
|
+
|
|
406
|
+
// Simulate search input in the listbox search field
|
|
407
|
+
const listbox = combobox.querySelector('pkt-listbox') as any
|
|
408
|
+
await listbox?.updateComplete
|
|
409
|
+
|
|
410
|
+
const searchInput = combobox.querySelector('[role="searchbox"]') as HTMLInputElement
|
|
411
|
+
if (searchInput) {
|
|
412
|
+
fireEvent.input(searchInput, { target: { value: 'app' } })
|
|
413
|
+
await combobox.updateComplete
|
|
414
|
+
}
|
|
415
|
+
|
|
416
|
+
expect(combobox['_search']).toBe('app')
|
|
417
|
+
})
|
|
418
|
+
})
|
|
419
|
+
|
|
420
|
+
describe('Disconnected callback cleanup', () => {
|
|
421
|
+
test('cleans up body click handler on disconnect', async () => {
|
|
422
|
+
const container = await createCombobox('id="test" name="test" label="Test"')
|
|
423
|
+
const combobox = container.querySelector('pkt-combobox') as PktCombobox
|
|
424
|
+
await combobox.updateComplete
|
|
425
|
+
|
|
426
|
+
const arrowButton = combobox.querySelector('.pkt-combobox__input')
|
|
427
|
+
fireEvent.click(arrowButton!)
|
|
428
|
+
await combobox.updateComplete
|
|
429
|
+
expect(combobox['_isOptionsOpen']).toBe(true)
|
|
430
|
+
|
|
431
|
+
combobox.remove()
|
|
432
|
+
|
|
433
|
+
expect(() => fireEvent.click(document.body)).not.toThrow()
|
|
434
|
+
})
|
|
435
|
+
})
|
|
436
|
+
})
|