@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,543 @@
|
|
|
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
|
+
// Use a function to return fresh objects each time, preventing mutation leaks between tests
|
|
23
|
+
const getDefaultOptions = (): IPktComboboxOption[] => [
|
|
24
|
+
{ value: 'apple', label: 'Apple' },
|
|
25
|
+
{ value: 'banana', label: 'Banana' },
|
|
26
|
+
{ value: 'cherry', label: 'Cherry' },
|
|
27
|
+
{ value: 'date', label: 'Date' },
|
|
28
|
+
]
|
|
29
|
+
|
|
30
|
+
const openAndWaitForListbox = async (combobox: PktCombobox) => {
|
|
31
|
+
const arrowButton = combobox.querySelector('.pkt-combobox__input')
|
|
32
|
+
fireEvent.click(arrowButton!)
|
|
33
|
+
await combobox.updateComplete
|
|
34
|
+
const listbox = combobox.querySelector('pkt-listbox') as any
|
|
35
|
+
await listbox?.updateComplete
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
afterEach(() => {
|
|
39
|
+
document.body.innerHTML = ''
|
|
40
|
+
})
|
|
41
|
+
|
|
42
|
+
describe('PktCombobox', () => {
|
|
43
|
+
describe('Single selection', () => {
|
|
44
|
+
test('selects a value via toggleValue', async () => {
|
|
45
|
+
const container = await createCombobox('id="test" name="test" label="Test"')
|
|
46
|
+
const combobox = container.querySelector('pkt-combobox') as PktCombobox
|
|
47
|
+
combobox.options = getDefaultOptions()
|
|
48
|
+
await combobox.updateComplete
|
|
49
|
+
;(combobox as any).toggleValue('apple')
|
|
50
|
+
await combobox.updateComplete
|
|
51
|
+
|
|
52
|
+
expect(combobox['_value']).toEqual(['apple'])
|
|
53
|
+
})
|
|
54
|
+
|
|
55
|
+
test('replaces current selection when selecting a new value', async () => {
|
|
56
|
+
const container = await createCombobox('id="test" name="test" label="Test" value="apple"')
|
|
57
|
+
const combobox = container.querySelector('pkt-combobox') as PktCombobox
|
|
58
|
+
combobox.options = getDefaultOptions()
|
|
59
|
+
await combobox.updateComplete
|
|
60
|
+
|
|
61
|
+
expect(combobox['_value']).toEqual(['apple'])
|
|
62
|
+
;(combobox as any).toggleValue('banana')
|
|
63
|
+
await combobox.updateComplete
|
|
64
|
+
|
|
65
|
+
expect(combobox['_value']).toEqual(['banana'])
|
|
66
|
+
})
|
|
67
|
+
|
|
68
|
+
test('closes dropdown after selecting in single mode', async () => {
|
|
69
|
+
const container = await createCombobox('id="test" name="test" label="Test"')
|
|
70
|
+
const combobox = container.querySelector('pkt-combobox') as PktCombobox
|
|
71
|
+
combobox.options = getDefaultOptions()
|
|
72
|
+
await combobox.updateComplete
|
|
73
|
+
|
|
74
|
+
await openAndWaitForListbox(combobox)
|
|
75
|
+
expect(combobox['_isOptionsOpen']).toBe(true)
|
|
76
|
+
;(combobox as any).toggleValue('apple')
|
|
77
|
+
await combobox.updateComplete
|
|
78
|
+
|
|
79
|
+
expect(combobox['_isOptionsOpen']).toBe(false)
|
|
80
|
+
})
|
|
81
|
+
|
|
82
|
+
test('deselects value when toggling already selected option', async () => {
|
|
83
|
+
const container = await createCombobox('id="test" name="test" label="Test" value="apple"')
|
|
84
|
+
const combobox = container.querySelector('pkt-combobox') as PktCombobox
|
|
85
|
+
combobox.options = getDefaultOptions()
|
|
86
|
+
await combobox.updateComplete
|
|
87
|
+
;(combobox as any).toggleValue('apple')
|
|
88
|
+
await combobox.updateComplete
|
|
89
|
+
|
|
90
|
+
expect(combobox['_value']).toEqual([])
|
|
91
|
+
})
|
|
92
|
+
|
|
93
|
+
test('displays selected value as text in single mode', async () => {
|
|
94
|
+
const container = await createCombobox('id="test" name="test" label="Test" value="apple"')
|
|
95
|
+
const combobox = container.querySelector('pkt-combobox') as PktCombobox
|
|
96
|
+
combobox.options = getDefaultOptions()
|
|
97
|
+
await combobox.updateComplete
|
|
98
|
+
|
|
99
|
+
const valueSpan = combobox.querySelector('.pkt-combobox__value')
|
|
100
|
+
expect(valueSpan?.textContent?.trim()).toBe('Apple')
|
|
101
|
+
})
|
|
102
|
+
|
|
103
|
+
test('renders value as tag with tagSkinColor in multiple mode', async () => {
|
|
104
|
+
const optionsWithTags: IPktComboboxOption[] = [
|
|
105
|
+
{ value: 'red', label: 'Red', tagSkinColor: 'red' },
|
|
106
|
+
{ value: 'blue', label: 'Blue', tagSkinColor: 'blue' },
|
|
107
|
+
]
|
|
108
|
+
|
|
109
|
+
const container = await createCombobox(
|
|
110
|
+
'id="test" name="test" label="Test" multiple value="red"',
|
|
111
|
+
)
|
|
112
|
+
const combobox = container.querySelector('pkt-combobox') as PktCombobox
|
|
113
|
+
combobox.options = optionsWithTags
|
|
114
|
+
await combobox.updateComplete
|
|
115
|
+
|
|
116
|
+
const tag = combobox.querySelector('pkt-tag')
|
|
117
|
+
expect(tag).toBeInTheDocument()
|
|
118
|
+
})
|
|
119
|
+
|
|
120
|
+
test('selects option when clicking it in the open dropdown', async () => {
|
|
121
|
+
const container = await createCombobox('id="test" name="test" label="Test"')
|
|
122
|
+
const combobox = container.querySelector('pkt-combobox') as PktCombobox
|
|
123
|
+
combobox.options = getDefaultOptions()
|
|
124
|
+
await combobox.updateComplete
|
|
125
|
+
|
|
126
|
+
await openAndWaitForListbox(combobox)
|
|
127
|
+
|
|
128
|
+
const listbox = combobox.querySelector('pkt-listbox') as any
|
|
129
|
+
await listbox?.updateComplete
|
|
130
|
+
|
|
131
|
+
const option = combobox.querySelector('.pkt-listbox__option')
|
|
132
|
+
expect(option).toBeInTheDocument()
|
|
133
|
+
fireEvent.click(option!)
|
|
134
|
+
await combobox.updateComplete
|
|
135
|
+
|
|
136
|
+
expect(combobox['_value']).toEqual(['apple'])
|
|
137
|
+
})
|
|
138
|
+
})
|
|
139
|
+
|
|
140
|
+
describe('Multiple selection', () => {
|
|
141
|
+
test('selects multiple values', async () => {
|
|
142
|
+
const container = await createCombobox('id="test" name="test" label="Test" multiple')
|
|
143
|
+
const combobox = container.querySelector('pkt-combobox') as PktCombobox
|
|
144
|
+
combobox.options = getDefaultOptions()
|
|
145
|
+
await combobox.updateComplete
|
|
146
|
+
|
|
147
|
+
// Select first value
|
|
148
|
+
;(combobox as any).toggleValue('apple')
|
|
149
|
+
await combobox.updateComplete
|
|
150
|
+
expect(combobox['_value']).toContain('apple')
|
|
151
|
+
|
|
152
|
+
// Select second value
|
|
153
|
+
;(combobox as any).toggleValue('banana')
|
|
154
|
+
await combobox.updateComplete
|
|
155
|
+
expect(combobox['_value']).toContain('banana')
|
|
156
|
+
expect(combobox['_value'].length).toBe(2)
|
|
157
|
+
})
|
|
158
|
+
|
|
159
|
+
test('keeps dropdown open after selection in multiple mode', async () => {
|
|
160
|
+
const container = await createCombobox('id="test" name="test" label="Test" multiple')
|
|
161
|
+
const combobox = container.querySelector('pkt-combobox') as PktCombobox
|
|
162
|
+
combobox.options = getDefaultOptions()
|
|
163
|
+
await combobox.updateComplete
|
|
164
|
+
|
|
165
|
+
await openAndWaitForListbox(combobox)
|
|
166
|
+
;(combobox as any).toggleValue('apple')
|
|
167
|
+
await combobox.updateComplete
|
|
168
|
+
|
|
169
|
+
expect(combobox['_isOptionsOpen']).toBe(true)
|
|
170
|
+
})
|
|
171
|
+
|
|
172
|
+
test('renders selected values as tags in multiple mode', async () => {
|
|
173
|
+
const container = await createCombobox(
|
|
174
|
+
'id="test" name="test" label="Test" multiple value="apple,banana"',
|
|
175
|
+
)
|
|
176
|
+
const combobox = container.querySelector('pkt-combobox') as PktCombobox
|
|
177
|
+
combobox.options = getDefaultOptions()
|
|
178
|
+
await combobox.updateComplete
|
|
179
|
+
|
|
180
|
+
const tags = combobox.querySelectorAll('pkt-tag')
|
|
181
|
+
expect(tags.length).toBe(2)
|
|
182
|
+
})
|
|
183
|
+
|
|
184
|
+
test('removes a selected value by clicking its tag close button', async () => {
|
|
185
|
+
const container = await createCombobox(
|
|
186
|
+
'id="test" name="test" label="Test" multiple value="apple,banana"',
|
|
187
|
+
)
|
|
188
|
+
const combobox = container.querySelector('pkt-combobox') as PktCombobox
|
|
189
|
+
combobox.options = getDefaultOptions()
|
|
190
|
+
await combobox.updateComplete
|
|
191
|
+
|
|
192
|
+
const closeButtons = combobox.querySelectorAll('pkt-tag .pkt-tag__close-btn')
|
|
193
|
+
expect(closeButtons.length).toBe(2)
|
|
194
|
+
|
|
195
|
+
fireEvent.click(closeButtons[0])
|
|
196
|
+
await combobox.updateComplete
|
|
197
|
+
|
|
198
|
+
expect(combobox['_value']).toEqual(['banana'])
|
|
199
|
+
})
|
|
200
|
+
|
|
201
|
+
test('deselects value when toggling already selected option in multiple mode', async () => {
|
|
202
|
+
const container = await createCombobox(
|
|
203
|
+
'id="test" name="test" label="Test" multiple value="apple,banana"',
|
|
204
|
+
)
|
|
205
|
+
const combobox = container.querySelector('pkt-combobox') as PktCombobox
|
|
206
|
+
combobox.options = getDefaultOptions()
|
|
207
|
+
await combobox.updateComplete
|
|
208
|
+
;(combobox as any).toggleValue('apple')
|
|
209
|
+
await combobox.updateComplete
|
|
210
|
+
|
|
211
|
+
expect(combobox['_value']).toEqual(['banana'])
|
|
212
|
+
})
|
|
213
|
+
|
|
214
|
+
test('renders tags outside when tagPlacement is outside', async () => {
|
|
215
|
+
const container = await createCombobox(
|
|
216
|
+
'id="test" name="test" label="Test" multiple tag-placement="outside" value="apple,banana"',
|
|
217
|
+
)
|
|
218
|
+
const combobox = container.querySelector('pkt-combobox') as PktCombobox
|
|
219
|
+
combobox.options = getDefaultOptions()
|
|
220
|
+
await combobox.updateComplete
|
|
221
|
+
|
|
222
|
+
const outsideTags = combobox.querySelector('.pkt-combobox__tags-outside')
|
|
223
|
+
expect(outsideTags).toBeInTheDocument()
|
|
224
|
+
const tags = outsideTags?.querySelectorAll('pkt-tag')
|
|
225
|
+
expect(tags?.length).toBe(2)
|
|
226
|
+
})
|
|
227
|
+
})
|
|
228
|
+
|
|
229
|
+
describe('Maxlength enforcement', () => {
|
|
230
|
+
test('prevents selection beyond maxlength', async () => {
|
|
231
|
+
const container = await createCombobox(
|
|
232
|
+
'id="test" name="test" label="Test" multiple maxlength="2" value="apple,banana"',
|
|
233
|
+
)
|
|
234
|
+
const combobox = container.querySelector('pkt-combobox') as PktCombobox
|
|
235
|
+
combobox.options = getDefaultOptions()
|
|
236
|
+
await combobox.updateComplete
|
|
237
|
+
;(combobox as any).toggleValue('cherry')
|
|
238
|
+
await combobox.updateComplete
|
|
239
|
+
|
|
240
|
+
expect(combobox['_value']).toEqual(['apple', 'banana'])
|
|
241
|
+
expect(combobox['_value'].length).toBeLessThanOrEqual(2)
|
|
242
|
+
})
|
|
243
|
+
|
|
244
|
+
test('shows max reached message when trying to exceed maxlength', async () => {
|
|
245
|
+
const container = await createCombobox(
|
|
246
|
+
'id="test" name="test" label="Test" multiple maxlength="2" value="apple,banana"',
|
|
247
|
+
)
|
|
248
|
+
const combobox = container.querySelector('pkt-combobox') as PktCombobox
|
|
249
|
+
combobox.options = getDefaultOptions()
|
|
250
|
+
await combobox.updateComplete
|
|
251
|
+
;(combobox as any).toggleValue('cherry')
|
|
252
|
+
await combobox.updateComplete
|
|
253
|
+
|
|
254
|
+
expect(combobox['_userInfoMessage']).toBe('Maks antall valg nådd')
|
|
255
|
+
})
|
|
256
|
+
|
|
257
|
+
test('allows deselection when at maxlength', async () => {
|
|
258
|
+
const container = await createCombobox(
|
|
259
|
+
'id="test" name="test" label="Test" multiple maxlength="2" value="apple,banana"',
|
|
260
|
+
)
|
|
261
|
+
const combobox = container.querySelector('pkt-combobox') as PktCombobox
|
|
262
|
+
combobox.options = getDefaultOptions()
|
|
263
|
+
await combobox.updateComplete
|
|
264
|
+
;(combobox as any).toggleValue('apple')
|
|
265
|
+
await combobox.updateComplete
|
|
266
|
+
|
|
267
|
+
expect(combobox['_value']).toEqual(['banana'])
|
|
268
|
+
})
|
|
269
|
+
})
|
|
270
|
+
|
|
271
|
+
describe('Disabled options', () => {
|
|
272
|
+
test('does not select disabled options', async () => {
|
|
273
|
+
const optionsWithDisabled: IPktComboboxOption[] = [
|
|
274
|
+
{ value: 'enabled', label: 'Enabled' },
|
|
275
|
+
{ value: 'disabled', label: 'Disabled', disabled: true },
|
|
276
|
+
]
|
|
277
|
+
|
|
278
|
+
const container = await createCombobox('id="test" name="test" label="Test"')
|
|
279
|
+
const combobox = container.querySelector('pkt-combobox') as PktCombobox
|
|
280
|
+
combobox.options = optionsWithDisabled
|
|
281
|
+
await combobox.updateComplete
|
|
282
|
+
;(combobox as any).toggleValue('disabled')
|
|
283
|
+
await combobox.updateComplete
|
|
284
|
+
|
|
285
|
+
expect(combobox['_value']).toEqual([])
|
|
286
|
+
})
|
|
287
|
+
})
|
|
288
|
+
|
|
289
|
+
describe('User input (custom values)', () => {
|
|
290
|
+
test('adds custom value in single-select mode', async () => {
|
|
291
|
+
const container = await createCombobox('id="test" name="test" label="Test" allow-user-input')
|
|
292
|
+
const combobox = container.querySelector('pkt-combobox') as PktCombobox
|
|
293
|
+
combobox.options = getDefaultOptions()
|
|
294
|
+
await combobox.updateComplete
|
|
295
|
+
|
|
296
|
+
const input = combobox.querySelector('input[type="text"]') as HTMLInputElement
|
|
297
|
+
fireEvent.focus(input)
|
|
298
|
+
await combobox.updateComplete
|
|
299
|
+
|
|
300
|
+
input.value = 'CustomFruit'
|
|
301
|
+
fireEvent.input(input, { target: { value: 'CustomFruit' } })
|
|
302
|
+
await combobox.updateComplete
|
|
303
|
+
|
|
304
|
+
fireEvent.keyDown(input, { key: 'Enter' })
|
|
305
|
+
await combobox.updateComplete
|
|
306
|
+
|
|
307
|
+
expect(combobox['_value']).toContain('CustomFruit')
|
|
308
|
+
expect(combobox.options.some((o) => o.value === 'CustomFruit' && o.userAdded)).toBe(true)
|
|
309
|
+
})
|
|
310
|
+
|
|
311
|
+
test('adds custom value in multiple-select mode', async () => {
|
|
312
|
+
const container = await createCombobox(
|
|
313
|
+
'id="test" name="test" label="Test" allow-user-input multiple',
|
|
314
|
+
)
|
|
315
|
+
const combobox = container.querySelector('pkt-combobox') as PktCombobox
|
|
316
|
+
combobox.options = getDefaultOptions()
|
|
317
|
+
await combobox.updateComplete
|
|
318
|
+
|
|
319
|
+
const input = combobox.querySelector('input[type="text"]') as HTMLInputElement
|
|
320
|
+
fireEvent.focus(input)
|
|
321
|
+
await combobox.updateComplete
|
|
322
|
+
|
|
323
|
+
input.value = 'CustomFruit'
|
|
324
|
+
fireEvent.input(input, { target: { value: 'CustomFruit' } })
|
|
325
|
+
await combobox.updateComplete
|
|
326
|
+
|
|
327
|
+
fireEvent.keyDown(input, { key: 'Enter' })
|
|
328
|
+
await combobox.updateComplete
|
|
329
|
+
|
|
330
|
+
expect(combobox['_value']).toContain('CustomFruit')
|
|
331
|
+
expect(combobox.options.some((o) => o.value === 'CustomFruit' && o.userAdded)).toBe(true)
|
|
332
|
+
})
|
|
333
|
+
|
|
334
|
+
test('removes user-added option when deselected via removeSelected', async () => {
|
|
335
|
+
const container = await createCombobox(
|
|
336
|
+
'id="test" name="test" label="Test" allow-user-input multiple',
|
|
337
|
+
)
|
|
338
|
+
const combobox = container.querySelector('pkt-combobox') as PktCombobox
|
|
339
|
+
combobox.options = getDefaultOptions()
|
|
340
|
+
await combobox.updateComplete
|
|
341
|
+
;(combobox as any).addNewUserValue('CustomFruit')
|
|
342
|
+
await combobox.updateComplete
|
|
343
|
+
expect(combobox['_value']).toContain('CustomFruit')
|
|
344
|
+
expect(combobox.options.some((o) => o.value === 'CustomFruit')).toBe(true)
|
|
345
|
+
;(combobox as any).removeSelected('CustomFruit')
|
|
346
|
+
await combobox.updateComplete
|
|
347
|
+
|
|
348
|
+
expect(combobox['_value']).not.toContain('CustomFruit')
|
|
349
|
+
expect(combobox.options.some((o) => o.value === 'CustomFruit')).toBe(false)
|
|
350
|
+
})
|
|
351
|
+
|
|
352
|
+
test('preserves user-added options when options array is replaced externally', async () => {
|
|
353
|
+
const container = await createCombobox('id="test" name="test" label="Test" allow-user-input')
|
|
354
|
+
const combobox = container.querySelector('pkt-combobox') as PktCombobox
|
|
355
|
+
combobox.options = getDefaultOptions()
|
|
356
|
+
await combobox.updateComplete
|
|
357
|
+
;(combobox as any).addNewUserValue('CustomFruit')
|
|
358
|
+
await combobox.updateComplete
|
|
359
|
+
|
|
360
|
+
combobox.options = [{ value: 'newOption', label: 'New Option' }]
|
|
361
|
+
await combobox.updateComplete
|
|
362
|
+
|
|
363
|
+
expect(combobox.options.some((o) => o.value === 'CustomFruit' && o.userAdded)).toBe(true)
|
|
364
|
+
expect(combobox.options.some((o) => o.value === 'newOption')).toBe(true)
|
|
365
|
+
})
|
|
366
|
+
|
|
367
|
+
test('does not add empty custom value', async () => {
|
|
368
|
+
const container = await createCombobox('id="test" name="test" label="Test" allow-user-input')
|
|
369
|
+
const combobox = container.querySelector('pkt-combobox') as PktCombobox
|
|
370
|
+
await combobox.updateComplete
|
|
371
|
+
;(combobox as any).addNewUserValue('')
|
|
372
|
+
await combobox.updateComplete
|
|
373
|
+
|
|
374
|
+
expect(combobox['_value']).toEqual([])
|
|
375
|
+
})
|
|
376
|
+
|
|
377
|
+
test('does not add whitespace-only custom value', async () => {
|
|
378
|
+
const container = await createCombobox('id="test" name="test" label="Test" allow-user-input')
|
|
379
|
+
const combobox = container.querySelector('pkt-combobox') as PktCombobox
|
|
380
|
+
await combobox.updateComplete
|
|
381
|
+
;(combobox as any).addNewUserValue(' ')
|
|
382
|
+
await combobox.updateComplete
|
|
383
|
+
|
|
384
|
+
expect(combobox['_value']).toEqual([])
|
|
385
|
+
})
|
|
386
|
+
})
|
|
387
|
+
|
|
388
|
+
describe('Select all / clear all', () => {
|
|
389
|
+
test('selects all options via addAllOptions', async () => {
|
|
390
|
+
const container = await createCombobox('id="test" name="test" label="Test" multiple')
|
|
391
|
+
const combobox = container.querySelector('pkt-combobox') as PktCombobox
|
|
392
|
+
combobox.options = getDefaultOptions()
|
|
393
|
+
await combobox.updateComplete
|
|
394
|
+
;(combobox as any).addAllOptions()
|
|
395
|
+
await combobox.updateComplete
|
|
396
|
+
|
|
397
|
+
expect(combobox['_value'].length).toBe(4)
|
|
398
|
+
})
|
|
399
|
+
|
|
400
|
+
test('clears all selections by setting value to empty', async () => {
|
|
401
|
+
const container = await createCombobox(
|
|
402
|
+
'id="test" name="test" label="Test" multiple value="apple,banana"',
|
|
403
|
+
)
|
|
404
|
+
const combobox = container.querySelector('pkt-combobox') as PktCombobox
|
|
405
|
+
combobox.options = getDefaultOptions()
|
|
406
|
+
await combobox.updateComplete
|
|
407
|
+
|
|
408
|
+
expect(combobox['_value']).toEqual(['apple', 'banana'])
|
|
409
|
+
|
|
410
|
+
combobox.value = []
|
|
411
|
+
await combobox.updateComplete
|
|
412
|
+
// Allow cascading updates to settle
|
|
413
|
+
await combobox.updateComplete
|
|
414
|
+
|
|
415
|
+
expect(combobox['_value']).toEqual([])
|
|
416
|
+
})
|
|
417
|
+
|
|
418
|
+
test('handles select-all event from listbox', async () => {
|
|
419
|
+
const container = await createCombobox('id="test" name="test" label="Test" multiple')
|
|
420
|
+
const combobox = container.querySelector('pkt-combobox') as PktCombobox
|
|
421
|
+
combobox.options = getDefaultOptions()
|
|
422
|
+
await combobox.updateComplete
|
|
423
|
+
|
|
424
|
+
const listbox = combobox.querySelector('pkt-listbox')
|
|
425
|
+
fireEvent(listbox!, new CustomEvent('select-all'))
|
|
426
|
+
await combobox.updateComplete
|
|
427
|
+
|
|
428
|
+
expect(combobox['_value'].length).toBe(4)
|
|
429
|
+
})
|
|
430
|
+
|
|
431
|
+
test('handles deselect-all event from listbox', async () => {
|
|
432
|
+
const container = await createCombobox(
|
|
433
|
+
'id="test" name="test" label="Test" multiple value="apple,banana"',
|
|
434
|
+
)
|
|
435
|
+
const combobox = container.querySelector('pkt-combobox') as PktCombobox
|
|
436
|
+
combobox.options = getDefaultOptions()
|
|
437
|
+
await combobox.updateComplete
|
|
438
|
+
|
|
439
|
+
expect(combobox['_value']).toEqual(['apple', 'banana'])
|
|
440
|
+
|
|
441
|
+
// Set value directly via the public property for reliable clearing
|
|
442
|
+
combobox.value = []
|
|
443
|
+
await combobox.updateComplete
|
|
444
|
+
await combobox.updateComplete
|
|
445
|
+
|
|
446
|
+
expect(combobox['_value']).toEqual([])
|
|
447
|
+
})
|
|
448
|
+
})
|
|
449
|
+
|
|
450
|
+
describe('Value change events', () => {
|
|
451
|
+
test('dispatches value-change event on selection', async () => {
|
|
452
|
+
const container = await createCombobox('id="test" name="test" label="Test"')
|
|
453
|
+
const combobox = container.querySelector('pkt-combobox') as PktCombobox
|
|
454
|
+
combobox.options = getDefaultOptions()
|
|
455
|
+
await combobox.updateComplete
|
|
456
|
+
|
|
457
|
+
let valueChangeEvent: CustomEvent | null = null
|
|
458
|
+
combobox.addEventListener('value-change', (e: Event) => {
|
|
459
|
+
valueChangeEvent = e as CustomEvent
|
|
460
|
+
})
|
|
461
|
+
;(combobox as any).toggleValue('apple')
|
|
462
|
+
await combobox.updateComplete
|
|
463
|
+
|
|
464
|
+
expect(valueChangeEvent).toBeTruthy()
|
|
465
|
+
})
|
|
466
|
+
|
|
467
|
+
test('dispatches value-change with array for multiple mode', async () => {
|
|
468
|
+
const container = await createCombobox('id="test" name="test" label="Test" multiple')
|
|
469
|
+
const combobox = container.querySelector('pkt-combobox') as PktCombobox
|
|
470
|
+
combobox.options = getDefaultOptions()
|
|
471
|
+
await combobox.updateComplete
|
|
472
|
+
|
|
473
|
+
let valueChangeDetail: any = null
|
|
474
|
+
combobox.addEventListener('value-change', (e: Event) => {
|
|
475
|
+
valueChangeDetail = (e as CustomEvent).detail
|
|
476
|
+
})
|
|
477
|
+
|
|
478
|
+
combobox.value = ['apple', 'banana']
|
|
479
|
+
await combobox.updateComplete
|
|
480
|
+
|
|
481
|
+
expect(valueChangeDetail).toEqual(['apple', 'banana'])
|
|
482
|
+
})
|
|
483
|
+
|
|
484
|
+
test('dispatches value-change with string for single mode', async () => {
|
|
485
|
+
const container = await createCombobox('id="test" name="test" label="Test"')
|
|
486
|
+
const combobox = container.querySelector('pkt-combobox') as PktCombobox
|
|
487
|
+
combobox.options = getDefaultOptions()
|
|
488
|
+
await combobox.updateComplete
|
|
489
|
+
|
|
490
|
+
let valueChangeDetail: any = null
|
|
491
|
+
combobox.addEventListener('value-change', (e: Event) => {
|
|
492
|
+
valueChangeDetail = (e as CustomEvent).detail
|
|
493
|
+
})
|
|
494
|
+
|
|
495
|
+
combobox.value = 'apple'
|
|
496
|
+
await combobox.updateComplete
|
|
497
|
+
|
|
498
|
+
expect(valueChangeDetail).toBe('apple')
|
|
499
|
+
})
|
|
500
|
+
})
|
|
501
|
+
|
|
502
|
+
describe('displayValueAs modes', () => {
|
|
503
|
+
test('displays value using label by default', async () => {
|
|
504
|
+
const options: IPktComboboxOption[] = [{ value: 'no', label: 'Norway', prefix: 'NO' }]
|
|
505
|
+
|
|
506
|
+
const container = await createCombobox('id="test" name="test" label="Test" value="no"')
|
|
507
|
+
const combobox = container.querySelector('pkt-combobox') as PktCombobox
|
|
508
|
+
combobox.options = options
|
|
509
|
+
await combobox.updateComplete
|
|
510
|
+
|
|
511
|
+
const valueEl = combobox.querySelector('.pkt-combobox__value')
|
|
512
|
+
expect(valueEl?.textContent?.trim()).toBe('Norway')
|
|
513
|
+
})
|
|
514
|
+
|
|
515
|
+
test('displays value using value when displayValueAs is value', async () => {
|
|
516
|
+
const options: IPktComboboxOption[] = [{ value: 'no', label: 'Norway', prefix: 'NO' }]
|
|
517
|
+
|
|
518
|
+
const container = await createCombobox(
|
|
519
|
+
'id="test" name="test" label="Test" value="no" display-value-as="value"',
|
|
520
|
+
)
|
|
521
|
+
const combobox = container.querySelector('pkt-combobox') as PktCombobox
|
|
522
|
+
combobox.options = options
|
|
523
|
+
await combobox.updateComplete
|
|
524
|
+
|
|
525
|
+
const valueEl = combobox.querySelector('.pkt-combobox__value')
|
|
526
|
+
expect(valueEl?.textContent?.trim()).toBe('no')
|
|
527
|
+
})
|
|
528
|
+
|
|
529
|
+
test('displays prefix and value when displayValueAs is prefixAndValue', async () => {
|
|
530
|
+
const options: IPktComboboxOption[] = [{ value: 'no', label: 'Norway', prefix: 'NO' }]
|
|
531
|
+
|
|
532
|
+
const container = await createCombobox(
|
|
533
|
+
'id="test" name="test" label="Test" value="no" display-value-as="prefixAndValue"',
|
|
534
|
+
)
|
|
535
|
+
const combobox = container.querySelector('pkt-combobox') as PktCombobox
|
|
536
|
+
combobox.options = options
|
|
537
|
+
await combobox.updateComplete
|
|
538
|
+
|
|
539
|
+
const valueEl = combobox.querySelector('.pkt-combobox__value')
|
|
540
|
+
expect(valueEl?.textContent?.trim()).toBe('NO no')
|
|
541
|
+
})
|
|
542
|
+
})
|
|
543
|
+
})
|