@crowdstrike/glide-core 0.12.2 → 0.12.3

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 (32) hide show
  1. package/dist/checkbox-group.styles.js +1 -1
  2. package/dist/dropdown.d.ts +4 -1
  3. package/dist/dropdown.js +107 -55
  4. package/dist/dropdown.option.js +1 -1
  5. package/dist/dropdown.option.styles.js +4 -2
  6. package/dist/dropdown.option.test.interactions.multiple.js +2 -2
  7. package/dist/dropdown.option.test.interactions.single.js +2 -2
  8. package/dist/dropdown.styles.js +108 -13
  9. package/dist/dropdown.test.basics.filterable.js +11 -54
  10. package/dist/dropdown.test.basics.js +24 -244
  11. package/dist/dropdown.test.basics.multiple.js +13 -60
  12. package/dist/dropdown.test.basics.single.js +2 -8
  13. package/dist/dropdown.test.events.filterable.js +12 -54
  14. package/dist/dropdown.test.events.js +75 -49
  15. package/dist/dropdown.test.events.multiple.js +17 -87
  16. package/dist/dropdown.test.events.single.js +12 -60
  17. package/dist/dropdown.test.focus.filterable.js +11 -58
  18. package/dist/dropdown.test.focus.js +62 -9
  19. package/dist/dropdown.test.focus.multiple.js +22 -38
  20. package/dist/dropdown.test.focus.single.js +22 -17
  21. package/dist/dropdown.test.interactions.filterable.js +83 -69
  22. package/dist/dropdown.test.interactions.js +225 -243
  23. package/dist/dropdown.test.interactions.multiple.js +78 -274
  24. package/dist/dropdown.test.interactions.single.js +20 -85
  25. package/dist/dropdown.test.validity.js +12 -49
  26. package/dist/label.js +1 -1
  27. package/dist/label.styles.js +7 -3
  28. package/dist/radio-group.styles.js +1 -1
  29. package/dist/tab.group.styles.js +0 -6
  30. package/dist/tab.panel.styles.js +0 -3
  31. package/dist/textarea.styles.js +1 -1
  32. package/package.json +1 -1
@@ -1,16 +1,14 @@
1
1
  /* eslint-disable @typescript-eslint/no-unused-expressions */
2
- import { aTimeout, assert, expect, fixture, html } from '@open-wc/testing';
2
+ import { aTimeout, assert, elementUpdated, expect, fixture, html, } from '@open-wc/testing';
3
3
  import { sendKeys, sendMouse } from '@web/test-runner-commands';
4
4
  import GlideCoreDropdown from './dropdown.js';
5
5
  import GlideCoreDropdownOption from './dropdown.option.js';
6
+ import sinon from 'sinon';
6
7
  GlideCoreDropdown.shadowRootOptions.mode = 'open';
7
8
  GlideCoreDropdownOption.shadowRootOptions.mode = 'open';
8
9
  it('opens when opened programmatically', async () => {
9
10
  const component = await fixture(html `<glide-core-dropdown label="Label" placeholder="Placeholder">
10
- <glide-core-dropdown-option
11
- label="Label"
12
- value="value"
13
- ></glide-core-dropdown-option>
11
+ <glide-core-dropdown-option label="Label"></glide-core-dropdown-option>
14
12
  </glide-core-dropdown>`);
15
13
  component.open = true;
16
14
  await aTimeout(0);
@@ -19,10 +17,7 @@ it('opens when opened programmatically', async () => {
19
17
  });
20
18
  it('opens on ArrowUp', async () => {
21
19
  const component = await fixture(html `<glide-core-dropdown label="Label" placeholder="Placeholder">
22
- <glide-core-dropdown-option
23
- label="Label"
24
- value="value"
25
- ></glide-core-dropdown-option>
20
+ <glide-core-dropdown-option label="Label"></glide-core-dropdown-option>
26
21
  </glide-core-dropdown>`);
27
22
  component.focus();
28
23
  await sendKeys({ press: 'ArrowUp' });
@@ -32,10 +27,7 @@ it('opens on ArrowUp', async () => {
32
27
  });
33
28
  it('does not open on ArrowUp when `disabled`', async () => {
34
29
  const component = await fixture(html `<glide-core-dropdown label="Label" placeholder="Placeholder" disabled>
35
- <glide-core-dropdown-option
36
- label="Label"
37
- value="value"
38
- ></glide-core-dropdown-option>
30
+ <glide-core-dropdown-option label="Label"></glide-core-dropdown-option>
39
31
  </glide-core-dropdown>`);
40
32
  component.focus();
41
33
  await sendKeys({ press: 'ArrowUp' });
@@ -45,10 +37,7 @@ it('does not open on ArrowUp when `disabled`', async () => {
45
37
  });
46
38
  it('does not open on ArrowUp when `readonly`', async () => {
47
39
  const component = await fixture(html `<glide-core-dropdown label="Label" placeholder="Placeholder" readonly>
48
- <glide-core-dropdown-option
49
- label="Label"
50
- value="value"
51
- ></glide-core-dropdown-option>
40
+ <glide-core-dropdown-option label="Label"></glide-core-dropdown-option>
52
41
  </glide-core-dropdown>`);
53
42
  component.focus();
54
43
  await sendKeys({ press: 'ArrowUp' });
@@ -58,15 +47,8 @@ it('does not open on ArrowUp when `readonly`', async () => {
58
47
  });
59
48
  it('opens on ArrowDown', async () => {
60
49
  const component = await fixture(html `<glide-core-dropdown label="Label" placeholder="Placeholder">
61
- <glide-core-dropdown-option
62
- label="One"
63
- value="one"
64
- ></glide-core-dropdown-option>
65
-
66
- <glide-core-dropdown-option
67
- label="Two"
68
- value="two"
69
- ></glide-core-dropdown-option>
50
+ <glide-core-dropdown-option label="One"></glide-core-dropdown-option>
51
+ <glide-core-dropdown-option label="Two"></glide-core-dropdown-option>
70
52
  </glide-core-dropdown>`);
71
53
  component.focus();
72
54
  await sendKeys({ press: 'ArrowDown' });
@@ -76,15 +58,8 @@ it('opens on ArrowDown', async () => {
76
58
  });
77
59
  it('does not open on ArrowDown when `disabled`', async () => {
78
60
  const component = await fixture(html `<glide-core-dropdown label="Label" placeholder="Placeholder" disabled>
79
- <glide-core-dropdown-option
80
- label="One"
81
- value="one"
82
- ></glide-core-dropdown-option>
83
-
84
- <glide-core-dropdown-option
85
- label="Two"
86
- value="two"
87
- ></glide-core-dropdown-option>
61
+ <glide-core-dropdown-option label="One"></glide-core-dropdown-option>
62
+ <glide-core-dropdown-option label="Two"></glide-core-dropdown-option>
88
63
  </glide-core-dropdown>`);
89
64
  component.focus();
90
65
  await sendKeys({ press: 'ArrowDown' });
@@ -94,15 +69,8 @@ it('does not open on ArrowDown when `disabled`', async () => {
94
69
  });
95
70
  it('does not open on ArrowDown when `readonly`', async () => {
96
71
  const component = await fixture(html `<glide-core-dropdown label="Label" placeholder="Placeholder" readonly>
97
- <glide-core-dropdown-option
98
- label="One"
99
- value="one"
100
- ></glide-core-dropdown-option>
101
-
102
- <glide-core-dropdown-option
103
- label="Two"
104
- value="two"
105
- ></glide-core-dropdown-option>
72
+ <glide-core-dropdown-option label="One"></glide-core-dropdown-option>
73
+ <glide-core-dropdown-option label="Two"></glide-core-dropdown-option>
106
74
  </glide-core-dropdown>`);
107
75
  component.focus();
108
76
  await sendKeys({ press: 'ArrowDown' });
@@ -110,6 +78,30 @@ it('does not open on ArrowDown when `readonly`', async () => {
110
78
  expect(component.open).to.be.false;
111
79
  expect(options?.checkVisibility()).to.be.false;
112
80
  });
81
+ it('does not scroll the page on ArrowDown when the Add button has focus', async () => {
82
+ document.body.style.height = '200vh';
83
+ document.body.style.scrollBehavior = 'auto';
84
+ const component = await fixture(html `<glide-core-dropdown
85
+ add-button-label="Add"
86
+ label="Label"
87
+ placeholder="Placeholder"
88
+ open
89
+ >
90
+ <glide-core-dropdown-option label="Label"></glide-core-dropdown-option>
91
+ </glide-core-dropdown>`);
92
+ // Wait for it to open.
93
+ await aTimeout(0);
94
+ component.focus();
95
+ await sendKeys({ press: 'ArrowDown' }); // Add button
96
+ const spy = sinon.spy();
97
+ document.addEventListener('scroll', spy);
98
+ await sendKeys({ press: 'ArrowDown' }); // Still Add button
99
+ // The browser apparently inserts a slight delay after arrowing before scrolling,
100
+ // even when smooth scrolling is disabled. `100` is a round number that comfortably
101
+ // gets us past that delay.
102
+ await aTimeout(100);
103
+ expect(spy.callCount).to.equal(0);
104
+ });
113
105
  it('opens on Space', async () => {
114
106
  const component = await fixture(html `<glide-core-dropdown label="Label" placeholder="Placeholder">
115
107
  <glide-core-dropdown-option
@@ -125,10 +117,7 @@ it('opens on Space', async () => {
125
117
  });
126
118
  it('does not open on Space when `disabled`', async () => {
127
119
  const component = await fixture(html `<glide-core-dropdown label="Label" placeholder="Placeholder" disabled>
128
- <glide-core-dropdown-option
129
- label="Label"
130
- value="value"
131
- ></glide-core-dropdown-option>
120
+ <glide-core-dropdown-option label="Label"></glide-core-dropdown-option>
132
121
  </glide-core-dropdown>`);
133
122
  component.focus();
134
123
  await sendKeys({ press: ' ' });
@@ -138,10 +127,7 @@ it('does not open on Space when `disabled`', async () => {
138
127
  });
139
128
  it('does not open on Space when `readonly`', async () => {
140
129
  const component = await fixture(html `<glide-core-dropdown label="Label" placeholder="Placeholder" readonly>
141
- <glide-core-dropdown-option
142
- label="Label"
143
- value="value"
144
- ></glide-core-dropdown-option>
130
+ <glide-core-dropdown-option label="Label"></glide-core-dropdown-option>
145
131
  </glide-core-dropdown>`);
146
132
  component.focus();
147
133
  await sendKeys({ press: ' ' });
@@ -153,10 +139,7 @@ it('does not open on Space when `readonly`', async () => {
153
139
  it('opens when opened programmatically via the click handler of another element', async () => {
154
140
  const div = document.createElement('div');
155
141
  const component = await fixture(html `<glide-core-dropdown label="Label" placeholder="Placeholder">
156
- <glide-core-dropdown-option
157
- label="Label"
158
- value="value"
159
- ></glide-core-dropdown-option>
142
+ <glide-core-dropdown-option label="Label"></glide-core-dropdown-option>
160
143
  </glide-core-dropdown>`, { parentNode: div });
161
144
  const button = document.createElement('button');
162
145
  button.addEventListener('click', () => (component.open = true));
@@ -177,15 +160,13 @@ it('closes when something outside of it is clicked', async () => {
177
160
  >
178
161
  <glide-core-dropdown-option
179
162
  label="One"
180
- value="one"
181
163
  selected
182
164
  ></glide-core-dropdown-option>
183
165
 
184
- <glide-core-dropdown-option
185
- label="Two"
186
- value="two"
187
- ></glide-core-dropdown-option>
166
+ <glide-core-dropdown-option label="Two"></glide-core-dropdown-option>
188
167
  </glide-core-dropdown>`);
168
+ // Wait for it to open.
169
+ await aTimeout(0);
189
170
  document.body.click();
190
171
  expect(component.open).to.be.false;
191
172
  });
@@ -198,15 +179,13 @@ it('closes on Escape', async () => {
198
179
  >
199
180
  <glide-core-dropdown-option
200
181
  label="One"
201
- value="one"
202
182
  selected
203
183
  ></glide-core-dropdown-option>
204
184
 
205
- <glide-core-dropdown-option
206
- label="Two"
207
- value="two"
208
- ></glide-core-dropdown-option>
185
+ <glide-core-dropdown-option label="Two"></glide-core-dropdown-option>
209
186
  </glide-core-dropdown>`);
187
+ // Wait for it to open.
188
+ await aTimeout(0);
210
189
  component.focus();
211
190
  await sendKeys({ press: 'Escape' });
212
191
  expect(component.open).to.be.false;
@@ -227,6 +206,22 @@ it('closes on edit via click', async () => {
227
206
  ?.click();
228
207
  expect(component.open).to.be.false;
229
208
  });
209
+ it('closes when the Add button is clicked', async () => {
210
+ const component = await fixture(html `<glide-core-dropdown
211
+ add-button-label="Add"
212
+ label="Label"
213
+ placeholder="Placeholder"
214
+ open
215
+ >
216
+ <glide-core-dropdown-option label="Label"></glide-core-dropdown-option>
217
+ </glide-core-dropdown>`);
218
+ // Wait for it to open.
219
+ await aTimeout(0);
220
+ component.shadowRoot
221
+ ?.querySelector('[data-test="add-button"]')
222
+ ?.click();
223
+ expect(component.open).to.be.false;
224
+ });
230
225
  it('opens when open and enabled programmatically', async () => {
231
226
  const component = await fixture(html `<glide-core-dropdown
232
227
  label="Label"
@@ -236,14 +231,10 @@ it('opens when open and enabled programmatically', async () => {
236
231
  >
237
232
  <glide-core-dropdown-option
238
233
  label="One"
239
- value="one"
240
234
  selected
241
235
  ></glide-core-dropdown-option>
242
236
 
243
- <glide-core-dropdown-option
244
- label="Two"
245
- value="two"
246
- ></glide-core-dropdown-option>
237
+ <glide-core-dropdown-option label="Two"></glide-core-dropdown-option>
247
238
  </glide-core-dropdown>`);
248
239
  component.disabled = false;
249
240
  // Wait for it to open.
@@ -255,14 +246,10 @@ it('closes when open and disabled programmatically', async () => {
255
246
  const component = await fixture(html `<glide-core-dropdown label="Label" placeholder="Placeholder" open>
256
247
  <glide-core-dropdown-option
257
248
  label="One"
258
- value="one"
259
249
  selected
260
250
  ></glide-core-dropdown-option>
261
251
 
262
- <glide-core-dropdown-option
263
- label="Two"
264
- value="two"
265
- ></glide-core-dropdown-option>
252
+ <glide-core-dropdown-option label="Two"></glide-core-dropdown-option>
266
253
  </glide-core-dropdown>`);
267
254
  // Wait for it to open.
268
255
  await aTimeout(0);
@@ -272,38 +259,25 @@ it('closes when open and disabled programmatically', async () => {
272
259
  });
273
260
  it('activates an option on "mouseover"', async () => {
274
261
  const component = await fixture(html `<glide-core-dropdown open>
275
- <glide-core-dropdown-option
276
- label="One"
277
- value="one"
278
- ></glide-core-dropdown-option>
279
-
280
- <glide-core-dropdown-option
281
- label="Two"
282
- value="two"
283
- ></glide-core-dropdown-option>
262
+ <glide-core-dropdown-option label="One"></glide-core-dropdown-option>
263
+ <glide-core-dropdown-option label="Two"></glide-core-dropdown-option>
284
264
  </glide-core-dropdown>`);
285
265
  const options = component.querySelectorAll('glide-core-dropdown-option');
286
266
  options[1]?.dispatchEvent(new MouseEvent('mouseover', { bubbles: true }));
267
+ await elementUpdated(component);
287
268
  expect(options[0]?.privateActive).to.be.false;
288
269
  expect(options[1]?.privateActive).to.be.true;
289
270
  });
290
271
  it('activates the next option on ArrowDown', async () => {
291
272
  const component = await fixture(html `<glide-core-dropdown label="Label" placeholder="Placeholder" open>
292
- <glide-core-dropdown-option
293
- label="One"
294
- value="one"
295
- ></glide-core-dropdown-option>
296
-
297
- <glide-core-dropdown-option
298
- label="Two"
299
- value="two"
300
- ></glide-core-dropdown-option>
273
+ <glide-core-dropdown-option label="One"></glide-core-dropdown-option>
274
+ <glide-core-dropdown-option label="Two"></glide-core-dropdown-option>
301
275
  </glide-core-dropdown>`);
302
276
  // Wait for it to open.
303
277
  await aTimeout(0);
278
+ component.focus();
279
+ await sendKeys({ press: 'ArrowDown' }); // Two
304
280
  const options = component.querySelectorAll('glide-core-dropdown-option');
305
- options[0]?.focus();
306
- await sendKeys({ press: 'ArrowDown' });
307
281
  expect(options[0]?.privateActive).to.be.false;
308
282
  expect(options[1]?.privateActive).to.be.true;
309
283
  });
@@ -318,9 +292,9 @@ it('activates the Edit button on ArrowDown', async () => {
318
292
  </glide-core-dropdown>`);
319
293
  // Wait for it to open.
320
294
  await aTimeout(0);
295
+ component.focus();
296
+ await sendKeys({ press: 'ArrowDown' }); // One's edit button
321
297
  const options = component.querySelectorAll('glide-core-dropdown-option');
322
- options[0]?.focus();
323
- await sendKeys({ press: 'ArrowDown' });
324
298
  expect(options[0]?.privateActive).to.be.true;
325
299
  expect(options[0]?.privateIsEditActive).true;
326
300
  expect(options[0]?.privateIsOpenTooltip).false;
@@ -338,10 +312,10 @@ it('activates the next option on ArrowDown when the Edit button is active', asyn
338
312
  </glide-core-dropdown>`);
339
313
  // Wait for it to open.
340
314
  await aTimeout(0);
315
+ component.focus();
316
+ await sendKeys({ press: 'ArrowDown' }); // One's edit button
317
+ await sendKeys({ press: 'ArrowDown' }); // Two
341
318
  const options = component.querySelectorAll('glide-core-dropdown-option');
342
- options[0]?.focus();
343
- await sendKeys({ press: 'ArrowDown' });
344
- await sendKeys({ press: 'ArrowDown' });
345
319
  expect(options[0]?.privateActive).to.be.false;
346
320
  expect(options[0]?.privateIsEditActive).false;
347
321
  expect(options[1]?.privateActive).to.be.true;
@@ -350,23 +324,15 @@ it('activates the next option on ArrowDown when the Edit button is active', asyn
350
324
  });
351
325
  it('activates the previous option on ArrowUp', async () => {
352
326
  const component = await fixture(html `<glide-core-dropdown label="Label" placeholder="Placeholder" open>
353
- <glide-core-dropdown-option
354
- label="One"
355
- value="one"
356
- ></glide-core-dropdown-option>
357
-
358
- <glide-core-dropdown-option
359
- label="Two"
360
- value="two"
361
- ></glide-core-dropdown-option>
327
+ <glide-core-dropdown-option label="One"></glide-core-dropdown-option>
328
+ <glide-core-dropdown-option label="Two"></glide-core-dropdown-option>
362
329
  </glide-core-dropdown>`);
363
330
  // Wait for it to open.
364
331
  await aTimeout(0);
332
+ component.focus();
333
+ await sendKeys({ press: 'ArrowDown' }); // Two
334
+ await sendKeys({ press: 'ArrowUp' }); // One
365
335
  const options = component.querySelectorAll('glide-core-dropdown-option');
366
- options[1]?.dispatchEvent(new MouseEvent('mouseover', { bubbles: true }));
367
- options[1]?.focus();
368
- expect(options[1]?.privateActive).to.be.true;
369
- await sendKeys({ press: 'ArrowUp' });
370
336
  expect(options[0]?.privateActive).to.be.true;
371
337
  expect(options[1]?.privateActive).to.be.false;
372
338
  });
@@ -377,15 +343,20 @@ it('activates the Edit button on on ArrowUp', async () => {
377
343
  editable
378
344
  ></glide-core-dropdown-option>
379
345
 
380
- <glide-core-dropdown-option label="Two"></glide-core-dropdown-option>
346
+ <glide-core-dropdown-option
347
+ label="Two"
348
+ editable
349
+ ></glide-core-dropdown-option>
381
350
  </glide-core-dropdown>`);
382
351
  // Wait for it to open.
383
352
  await aTimeout(0);
353
+ component.focus();
354
+ await sendKeys({ press: 'ArrowDown' }); // One's Edit button
355
+ await sendKeys({ press: 'ArrowDown' }); // Two
356
+ await sendKeys({ press: 'ArrowDown' }); // Two's Edit button
357
+ await sendKeys({ press: 'ArrowUp' }); // Two
358
+ await sendKeys({ press: 'ArrowUp' }); // One's Edit button
384
359
  const options = component.querySelectorAll('glide-core-dropdown-option');
385
- options[1]?.dispatchEvent(new MouseEvent('mouseover', { bubbles: true }));
386
- options[1]?.focus();
387
- expect(options[1]?.privateActive).to.be.true;
388
- await sendKeys({ press: 'ArrowUp' });
389
360
  expect(options[0]?.privateActive).to.be.true;
390
361
  expect(options[0]?.privateIsEditActive).to.be.true;
391
362
  expect(options[0]?.privateIsOpenTooltip).false;
@@ -393,52 +364,70 @@ it('activates the Edit button on on ArrowUp', async () => {
393
364
  expect(options[1]?.privateIsEditActive).to.be.false;
394
365
  expect(options[1]?.privateIsOpenTooltip).to.be.false;
395
366
  });
396
- it('activates the previous option on ArrowUp when the Edit button is active', async () => {
397
- const component = await fixture(html `<glide-core-dropdown label="Label" placeholder="Placeholder" open>
398
- <glide-core-dropdown-option
399
- label="One"
400
- editable
401
- ></glide-core-dropdown-option>
367
+ it('activates previously active option on ArrowUp', async () => {
368
+ const component = await fixture(html `<glide-core-dropdown
369
+ add-button-label="Add"
370
+ label="Label"
371
+ placeholder="Placeholder"
372
+ open
373
+ >
374
+ <glide-core-dropdown-option label="One"></glide-core-dropdown-option>
375
+ <glide-core-dropdown-option label="Two"></glide-core-dropdown-option>
376
+ </glide-core-dropdown>`);
377
+ // Wait for it to open.
378
+ await aTimeout(0);
379
+ component.focus();
380
+ await sendKeys({ press: 'ArrowDown' }); // Two
381
+ await sendKeys({ press: 'ArrowDown' }); // Add button
382
+ await sendKeys({ press: 'ArrowUp' }); // Two
383
+ const options = component.querySelectorAll('glide-core-dropdown-option');
384
+ expect(options[0]?.privateActive).to.be.false;
385
+ expect(options[0]?.privateIsEditActive).to.be.false;
386
+ expect(options[0]?.privateIsOpenTooltip).to.be.false;
387
+ expect(options[1]?.privateActive).to.be.true;
388
+ expect(options[1]?.privateIsOpenTooltip).to.be.true;
389
+ expect(options[1]?.privateIsEditActive).to.be.false;
390
+ });
391
+ it('activates the Edit button on ArrowUp', async () => {
392
+ const component = await fixture(html `<glide-core-dropdown
393
+ add-button-label="Add"
394
+ label="Label"
395
+ placeholder="Placeholder"
396
+ open
397
+ >
398
+ <glide-core-dropdown-option label="One"></glide-core-dropdown-option>
402
399
 
403
400
  <glide-core-dropdown-option
404
401
  label="Two"
405
402
  editable
406
403
  ></glide-core-dropdown-option>
407
-
408
- <glide-core-dropdown-option label="Two"></glide-core-dropdown-option>
409
404
  </glide-core-dropdown>`);
410
405
  // Wait for it to open.
411
406
  await aTimeout(0);
407
+ component.focus();
408
+ await sendKeys({ press: 'ArrowDown' }); // Two
409
+ await sendKeys({ press: 'ArrowDown' }); // Two's Edit button
410
+ await sendKeys({ press: 'ArrowDown' }); // Add button
411
+ await sendKeys({ press: 'ArrowUp' }); // Two's Edit button
412
412
  const options = component.querySelectorAll('glide-core-dropdown-option');
413
- options[1]?.focus();
414
- await sendKeys({ press: 'ArrowUp' });
415
- await sendKeys({ press: 'ArrowUp' });
416
- expect(options[0]?.privateActive).to.be.true;
413
+ expect(options[0]?.privateActive).to.be.false;
417
414
  expect(options[0]?.privateIsEditActive).to.be.false;
418
- expect(options[0]?.privateIsOpenTooltip).to.be.true;
419
- expect(options[1]?.privateActive).to.be.false;
420
- expect(options[1]?.privateIsEditActive).to.be.false;
415
+ expect(options[0]?.privateIsOpenTooltip).to.be.false;
416
+ expect(options[1]?.privateActive).to.be.true;
417
+ expect(options[1]?.privateIsEditActive).to.be.true;
421
418
  expect(options[1]?.privateIsOpenTooltip).to.be.false;
422
419
  });
423
420
  it('activates the first option on Home', async () => {
424
421
  const component = await fixture(html `<glide-core-dropdown label="Label" placeholder="Placeholder" open>
425
- <glide-core-dropdown-option
426
- label="One"
427
- value="one"
428
- ></glide-core-dropdown-option>
429
-
430
- <glide-core-dropdown-option
431
- label="Two"
432
- value="two"
433
- ></glide-core-dropdown-option>
422
+ <glide-core-dropdown-option label="One"></glide-core-dropdown-option>
423
+ <glide-core-dropdown-option label="Two"></glide-core-dropdown-option>
434
424
  </glide-core-dropdown>`);
435
425
  // Wait for it to open.
436
426
  await aTimeout(0);
437
- const options = component.querySelectorAll('glide-core-dropdown-option');
438
- options[1]?.dispatchEvent(new MouseEvent('mouseover', { bubbles: true }));
439
- expect(options[1].privateActive).to.be.true;
440
- options[1].focus();
427
+ component.focus();
428
+ await sendKeys({ press: 'End' });
441
429
  await sendKeys({ press: 'Home' });
430
+ const options = component.querySelectorAll('glide-core-dropdown-option');
442
431
  expect(options[0]?.privateActive).to.be.true;
443
432
  expect(options[0]?.privateIsEditActive).to.be.false;
444
433
  expect(options[0]?.privateIsOpenTooltip).to.be.true;
@@ -448,23 +437,15 @@ it('activates the first option on Home', async () => {
448
437
  });
449
438
  it('activates the first option on PageUp', async () => {
450
439
  const component = await fixture(html `<glide-core-dropdown label="Label" placeholder="Placeholder" open>
451
- <glide-core-dropdown-option
452
- label="One"
453
- value="one"
454
- ></glide-core-dropdown-option>
455
-
456
- <glide-core-dropdown-option
457
- label="Two"
458
- value="two"
459
- ></glide-core-dropdown-option>
440
+ <glide-core-dropdown-option label="One"></glide-core-dropdown-option>
441
+ <glide-core-dropdown-option label="Two"></glide-core-dropdown-option>
460
442
  </glide-core-dropdown>`);
461
443
  // Wait for it to open.
462
444
  await aTimeout(0);
463
- const options = component.querySelectorAll('glide-core-dropdown-option');
464
- options[1].dispatchEvent(new MouseEvent('mouseover', { bubbles: true }));
465
- options[1].focus();
466
- expect(options[1]?.privateActive).to.be.true;
445
+ component.focus();
446
+ await sendKeys({ press: 'PageDown' });
467
447
  await sendKeys({ press: 'PageUp' });
448
+ const options = component.querySelectorAll('glide-core-dropdown-option');
468
449
  expect(options[0]?.privateActive).to.be.true;
469
450
  expect(options[0]?.privateIsEditActive).to.be.false;
470
451
  expect(options[0]?.privateIsOpenTooltip).to.be.true;
@@ -474,24 +455,17 @@ it('activates the first option on PageUp', async () => {
474
455
  });
475
456
  it('activates the first option on ArrowUp + Meta', async () => {
476
457
  const component = await fixture(html `<glide-core-dropdown label="Label" placeholder="Placeholder" open>
477
- <glide-core-dropdown-option
478
- label="One"
479
- value="one"
480
- ></glide-core-dropdown-option>
481
-
482
- <glide-core-dropdown-option
483
- label="Two"
484
- value="two"
485
- ></glide-core-dropdown-option>
458
+ <glide-core-dropdown-option label="One"></glide-core-dropdown-option>
459
+ <glide-core-dropdown-option label="Two"></glide-core-dropdown-option>
486
460
  </glide-core-dropdown>`);
487
461
  // Wait for it to open.
488
462
  await aTimeout(0);
489
- const options = component.querySelectorAll('glide-core-dropdown-option');
490
- options[1]?.dispatchEvent(new MouseEvent('mouseover', { bubbles: true }));
491
- options[1].focus();
463
+ component.focus();
464
+ await sendKeys({ press: 'End' });
492
465
  await sendKeys({ down: 'Meta' });
493
466
  await sendKeys({ press: 'ArrowUp' });
494
467
  await sendKeys({ up: 'Meta' });
468
+ const options = component.querySelectorAll('glide-core-dropdown-option');
495
469
  expect(options[0]?.privateActive).to.be.true;
496
470
  expect(options[0]?.privateIsEditActive).to.be.false;
497
471
  expect(options[0]?.privateIsOpenTooltip).to.be.true;
@@ -501,21 +475,14 @@ it('activates the first option on ArrowUp + Meta', async () => {
501
475
  });
502
476
  it('activates the last option on End', async () => {
503
477
  const component = await fixture(html `<glide-core-dropdown label="Label" placeholder="Placeholder" open>
504
- <glide-core-dropdown-option
505
- label="One"
506
- value="one"
507
- ></glide-core-dropdown-option>
508
-
509
- <glide-core-dropdown-option
510
- label="Two"
511
- value="two"
512
- ></glide-core-dropdown-option>
478
+ <glide-core-dropdown-option label="One"></glide-core-dropdown-option>
479
+ <glide-core-dropdown-option label="Two"></glide-core-dropdown-option>
513
480
  </glide-core-dropdown>`);
514
481
  // Wait for it to open.
515
482
  await aTimeout(0);
516
- const options = component.querySelectorAll('glide-core-dropdown-option');
517
- options[0]?.focus();
483
+ component.focus();
518
484
  await sendKeys({ press: 'End' });
485
+ const options = component.querySelectorAll('glide-core-dropdown-option');
519
486
  expect(options[0]?.privateActive).to.be.false;
520
487
  expect(options[0]?.privateIsEditActive).to.be.false;
521
488
  expect(options[0]?.privateIsOpenTooltip).to.be.false;
@@ -525,21 +492,14 @@ it('activates the last option on End', async () => {
525
492
  });
526
493
  it('activates the last option on PageDown', async () => {
527
494
  const component = await fixture(html `<glide-core-dropdown label="Label" placeholder="Placeholder" open>
528
- <glide-core-dropdown-option
529
- label="One"
530
- value="one"
531
- ></glide-core-dropdown-option>
532
-
533
- <glide-core-dropdown-option
534
- label="Two"
535
- value="two"
536
- ></glide-core-dropdown-option>
495
+ <glide-core-dropdown-option label="One"></glide-core-dropdown-option>
496
+ <glide-core-dropdown-option label="Two"></glide-core-dropdown-option>
537
497
  </glide-core-dropdown>`);
538
498
  // Wait for it to open.
539
499
  await aTimeout(0);
540
- const options = component.querySelectorAll('glide-core-dropdown-option');
541
- options[0]?.focus();
500
+ component.focus();
542
501
  await sendKeys({ press: 'PageDown' });
502
+ const options = component.querySelectorAll('glide-core-dropdown-option');
543
503
  expect(options[0]?.privateActive).to.be.false;
544
504
  expect(options[0]?.privateIsEditActive).to.be.false;
545
505
  expect(options[0]?.privateIsOpenTooltip).to.be.false;
@@ -549,80 +509,105 @@ it('activates the last option on PageDown', async () => {
549
509
  });
550
510
  it('activates the last option on Meta + ArrowDown', async () => {
551
511
  const component = await fixture(html `<glide-core-dropdown label="Label" placeholder="Placeholder" open>
552
- <glide-core-dropdown-option
553
- label="One"
554
- value="one"
555
- ></glide-core-dropdown-option>
556
-
557
- <glide-core-dropdown-option
558
- label="Two"
559
- value="two"
560
- ></glide-core-dropdown-option>
512
+ <glide-core-dropdown-option label="One"></glide-core-dropdown-option>
513
+ <glide-core-dropdown-option label="Two"></glide-core-dropdown-option>
561
514
  </glide-core-dropdown>`);
562
515
  // Wait for it to open.
563
516
  await aTimeout(0);
564
- const options = component.querySelectorAll('glide-core-dropdown-option');
565
- options[0]?.focus();
517
+ component.focus();
566
518
  await sendKeys({ down: 'Meta' });
567
519
  await sendKeys({ press: 'ArrowDown' });
568
520
  await sendKeys({ up: 'Meta' });
521
+ const options = component.querySelectorAll('glide-core-dropdown-option');
522
+ expect(options[0]?.privateActive).to.be.false;
523
+ expect(options[0]?.privateIsEditActive).to.be.false;
524
+ expect(options[0]?.privateIsOpenTooltip).to.be.false;
525
+ expect(options[1]?.privateActive).to.be.true;
526
+ expect(options[1]?.privateIsEditActive).to.be.false;
527
+ expect(options[1]?.privateIsOpenTooltip).to.be.true;
528
+ });
529
+ it('activates the previously active option when tabbing back from the Add button', async () => {
530
+ const component = await fixture(html `<glide-core-dropdown
531
+ add-button-label="Add"
532
+ label="Label"
533
+ placeholder="Placeholder"
534
+ open
535
+ >
536
+ <glide-core-dropdown-option label="One"></glide-core-dropdown-option>
537
+ <glide-core-dropdown-option label="Two"></glide-core-dropdown-option>
538
+ <glide-core-dropdown-option label="Three"></glide-core-dropdown-option>
539
+ </glide-core-dropdown>`);
540
+ // Wait for it to open.
541
+ await aTimeout(0);
542
+ component.focus();
543
+ await sendKeys({ press: 'ArrowDown' }); // Two
544
+ await sendKeys({ press: 'Tab' });
545
+ await sendKeys({ down: 'Shift' });
546
+ await sendKeys({ press: 'Tab' });
547
+ await sendKeys({ up: 'Shift' });
548
+ const options = component.querySelectorAll('glide-core-dropdown-option');
569
549
  expect(options[0]?.privateActive).to.be.false;
570
550
  expect(options[0]?.privateIsEditActive).to.be.false;
571
551
  expect(options[0]?.privateIsOpenTooltip).to.be.false;
572
552
  expect(options[1]?.privateActive).to.be.true;
573
553
  expect(options[1]?.privateIsEditActive).to.be.false;
574
554
  expect(options[1]?.privateIsOpenTooltip).to.be.true;
555
+ expect(options[2]?.privateActive).to.be.false;
556
+ expect(options[2]?.privateIsEditActive).to.be.false;
557
+ expect(options[2]?.privateIsOpenTooltip).to.be.false;
558
+ });
559
+ it('deactivates the active option when the Add button is tabbed to', async () => {
560
+ const component = await fixture(html `<glide-core-dropdown
561
+ add-button-label="Add"
562
+ label="Label"
563
+ placeholder="Placeholder"
564
+ open
565
+ >
566
+ <glide-core-dropdown-option label="One"></glide-core-dropdown-option>
567
+ <glide-core-dropdown-option label="Two"></glide-core-dropdown-option>
568
+ <glide-core-dropdown-option label="Three"></glide-core-dropdown-option>
569
+ </glide-core-dropdown>`);
570
+ // Wait for it to open.
571
+ await aTimeout(0);
572
+ component.focus();
573
+ await sendKeys({ press: 'Tab' });
574
+ const options = component.querySelectorAll('glide-core-dropdown-option');
575
+ expect(options[0]?.privateActive).to.be.false;
576
+ expect(options[0]?.privateIsEditActive).to.be.false;
577
+ expect(options[0]?.privateIsOpenTooltip).to.be.false;
578
+ expect(options[1]?.privateActive).to.be.false;
575
579
  });
576
580
  it('does not wrap on ArrowUp', async () => {
577
581
  const component = await fixture(html `<glide-core-dropdown open>
578
- <glide-core-dropdown-option
579
- label="One"
580
- value="one"
581
- ></glide-core-dropdown-option>
582
-
583
- <glide-core-dropdown-option
584
- label="Two"
585
- value="two"
586
- ></glide-core-dropdown-option>
582
+ <glide-core-dropdown-option label="One"></glide-core-dropdown-option>
583
+ <glide-core-dropdown-option label="Two"></glide-core-dropdown-option>
587
584
  </glide-core-dropdown>`);
588
- const options = component.querySelectorAll('glide-core-dropdown-option');
589
- options[0]?.dispatchEvent(new MouseEvent('mouseover', { bubbles: true }));
590
- options[0]?.focus();
585
+ // Wait for it to open.
586
+ await aTimeout(0);
587
+ component.focus();
591
588
  await sendKeys({ press: 'ArrowUp' });
589
+ const options = component.querySelectorAll('glide-core-dropdown-option');
592
590
  expect(options[0]?.privateActive).to.be.true;
593
591
  expect(options[1]?.privateActive).to.be.false;
594
592
  });
595
593
  it('does not wrap on ArrowDown', async () => {
596
594
  const component = await fixture(html `<glide-core-dropdown open>
597
- <glide-core-dropdown-option
598
- label="One"
599
- value="one"
600
- ></glide-core-dropdown-option>
601
-
602
- <glide-core-dropdown-option
603
- label="Two"
604
- value="two"
605
- ></glide-core-dropdown-option>
595
+ <glide-core-dropdown-option label="One"></glide-core-dropdown-option>
596
+ <glide-core-dropdown-option label="Two"></glide-core-dropdown-option>
606
597
  </glide-core-dropdown>`);
598
+ // Wait for it to open.
599
+ await aTimeout(0);
600
+ component.focus();
601
+ await sendKeys({ press: 'ArrowDown' }); // Two
602
+ await sendKeys({ press: 'ArrowDown' }); // Two
607
603
  const options = component.querySelectorAll('glide-core-dropdown-option');
608
- options[1]?.dispatchEvent(new MouseEvent('mouseover', { bubbles: true }));
609
- expect(options[1].privateActive).to.be.true;
610
- options[1]?.focus();
611
- await sendKeys({ press: 'ArrowDown' });
612
604
  expect(options[0]?.privateActive).to.be.false;
613
605
  expect(options[1]?.privateActive).to.be.true;
614
606
  });
615
607
  it('updates `privateSize` on every option when `size` is changed programmatically', async () => {
616
608
  const component = await fixture(html `<glide-core-dropdown label="Label" placeholder="Placeholder">
617
- <glide-core-dropdown-option
618
- label="One"
619
- value="one"
620
- ></glide-core-dropdown-option>
621
-
622
- <glide-core-dropdown-option
623
- label="Two"
624
- value="two"
625
- ></glide-core-dropdown-option>
609
+ <glide-core-dropdown-option label="One"></glide-core-dropdown-option>
610
+ <glide-core-dropdown-option label="Two"></glide-core-dropdown-option>
626
611
  </glide-core-dropdown>`);
627
612
  component.size = 'small';
628
613
  const options = component.querySelectorAll('glide-core-dropdown-option');
@@ -631,10 +616,7 @@ it('updates `privateSize` on every option when `size` is changed programmaticall
631
616
  });
632
617
  it('opens when something other than the primary button is clicked', async () => {
633
618
  const component = await fixture(html `<glide-core-dropdown label="Label" placeholder="Placeholder">
634
- <glide-core-dropdown-option
635
- label="Label"
636
- value="value"
637
- ></glide-core-dropdown-option>
619
+ <glide-core-dropdown-option label="Label"></glide-core-dropdown-option>
638
620
  </glide-core-dropdown>`);
639
621
  const internalLabel = component.shadowRoot?.querySelector('[data-test="internal-label"]');
640
622
  assert(internalLabel);