@crowdstrike/glide-core 0.7.0 → 0.9.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 (203) hide show
  1. package/README.md +44 -5
  2. package/dist/accordion.test.basics.js +1 -0
  3. package/dist/accordion.test.events.js +1 -0
  4. package/dist/button-group.button.d.ts +14 -15
  5. package/dist/button-group.button.js +1 -1
  6. package/dist/button-group.button.styles.js +75 -52
  7. package/dist/button-group.button.test.basics.d.ts +1 -1
  8. package/dist/button-group.button.test.basics.js +84 -147
  9. package/dist/button-group.button.test.events.js +9 -67
  10. package/dist/button-group.button.test.focus.js +13 -0
  11. package/dist/button-group.button.test.interactions.d.ts +1 -0
  12. package/dist/button-group.button.test.interactions.js +42 -0
  13. package/dist/button-group.d.ts +7 -10
  14. package/dist/button-group.js +1 -1
  15. package/dist/button-group.stories.d.ts +1 -5
  16. package/dist/button-group.styles.js +18 -6
  17. package/dist/button-group.test.basics.js +114 -234
  18. package/dist/button-group.test.events.js +211 -263
  19. package/dist/button-group.test.focus.d.ts +1 -0
  20. package/dist/button-group.test.focus.js +39 -0
  21. package/dist/button-group.test.interactions.d.ts +1 -0
  22. package/dist/button-group.test.interactions.js +91 -0
  23. package/dist/button.test.basics.js +2 -1
  24. package/dist/button.test.events.js +1 -0
  25. package/dist/button.test.form.js +1 -0
  26. package/dist/checkbox-group.js +1 -1
  27. package/dist/checkbox-group.styles.js +1 -1
  28. package/dist/checkbox-group.test.basics.js +2 -1
  29. package/dist/checkbox-group.test.events.js +5 -4
  30. package/dist/checkbox-group.test.focus.js +5 -3
  31. package/dist/checkbox-group.test.form.js +1 -0
  32. package/dist/checkbox-group.test.validity.js +1 -0
  33. package/dist/checkbox.d.ts +7 -1
  34. package/dist/checkbox.js +1 -1
  35. package/dist/checkbox.styles.js +11 -3
  36. package/dist/checkbox.test.basics.js +1 -0
  37. package/dist/checkbox.test.events.js +5 -4
  38. package/dist/checkbox.test.focus.js +2 -2
  39. package/dist/checkbox.test.form.js +1 -0
  40. package/dist/{checkbox.test.states.js → checkbox.test.interactions.js} +25 -1
  41. package/dist/checkbox.test.validity.js +1 -0
  42. package/dist/drawer.js +1 -1
  43. package/dist/drawer.test.basics.js +1 -0
  44. package/dist/drawer.test.closing.js +1 -0
  45. package/dist/drawer.test.events.js +1 -0
  46. package/dist/drawer.test.methods.js +1 -0
  47. package/dist/dropdown.d.ts +6 -4
  48. package/dist/dropdown.js +1 -1
  49. package/dist/dropdown.option.d.ts +7 -2
  50. package/dist/dropdown.option.js +1 -1
  51. package/dist/dropdown.option.styles.js +13 -0
  52. package/dist/dropdown.option.test.basics.js +7 -3
  53. package/dist/dropdown.option.test.basics.multiple.js +1 -0
  54. package/dist/dropdown.option.test.basics.single.js +1 -0
  55. package/dist/dropdown.option.test.events.js +2 -1
  56. package/dist/dropdown.option.test.focus.js +1 -1
  57. package/dist/dropdown.option.test.interactions.multiple.js +2 -54
  58. package/dist/dropdown.option.test.interactions.single.js +52 -9
  59. package/dist/dropdown.styles.js +20 -19
  60. package/dist/dropdown.test.basics.filterable.js +1 -0
  61. package/dist/dropdown.test.basics.js +144 -2
  62. package/dist/dropdown.test.basics.multiple.js +6 -3
  63. package/dist/dropdown.test.basics.single.js +1 -1
  64. package/dist/dropdown.test.events.filterable.js +74 -0
  65. package/dist/dropdown.test.events.js +50 -160
  66. package/dist/dropdown.test.events.multiple.js +268 -10
  67. package/dist/dropdown.test.events.single.js +202 -4
  68. package/dist/dropdown.test.focus.filterable.js +9 -5
  69. package/dist/dropdown.test.focus.js +2 -1
  70. package/dist/dropdown.test.focus.multiple.js +1 -2
  71. package/dist/dropdown.test.focus.single.js +1 -1
  72. package/dist/dropdown.test.form.js +1 -0
  73. package/dist/dropdown.test.form.multiple.js +1 -0
  74. package/dist/dropdown.test.form.single.js +1 -0
  75. package/dist/dropdown.test.interactions.filterable.js +69 -11
  76. package/dist/dropdown.test.interactions.js +95 -5
  77. package/dist/dropdown.test.interactions.multiple.js +203 -6
  78. package/dist/dropdown.test.interactions.single.js +69 -6
  79. package/dist/dropdown.test.validity.js +1 -0
  80. package/dist/form-controls-layout.test.basics.js +2 -1
  81. package/dist/icon-button.test.basics.js +2 -1
  82. package/dist/icons/checked.d.ts +1 -1
  83. package/dist/icons/checked.js +1 -1
  84. package/dist/icons/magnifying-glass.js +1 -1
  85. package/dist/input.d.ts +0 -6
  86. package/dist/input.js +1 -1
  87. package/dist/input.styles.js +7 -2
  88. package/dist/input.test.basics.js +20 -5
  89. package/dist/input.test.events.js +5 -4
  90. package/dist/input.test.focus.js +5 -4
  91. package/dist/input.test.form.js +1 -0
  92. package/dist/input.test.translations.d.ts +1 -0
  93. package/dist/input.test.translations.js +38 -0
  94. package/dist/input.test.validity.js +134 -4
  95. package/dist/label.d.ts +1 -1
  96. package/dist/label.js +1 -1
  97. package/dist/label.styles.js +29 -20
  98. package/dist/label.test.basics.js +27 -24
  99. package/dist/library/expect-argument-error.js +1 -1
  100. package/dist/library/localize.d.ts +5 -1
  101. package/dist/library/ow.test.d.ts +2 -1
  102. package/dist/library/ow.test.js +8 -3
  103. package/dist/menu.button.test.basics.js +1 -0
  104. package/dist/menu.d.ts +3 -5
  105. package/dist/menu.js +1 -1
  106. package/dist/menu.link.test.basics.js +1 -0
  107. package/dist/menu.options.test.basics.js +3 -2
  108. package/dist/menu.styles.js +1 -15
  109. package/dist/menu.test.basics.d.ts +1 -2
  110. package/dist/menu.test.basics.js +23 -6
  111. package/dist/menu.test.events.d.ts +1 -0
  112. package/dist/menu.test.events.js +2 -1
  113. package/dist/menu.test.focus.d.ts +1 -0
  114. package/dist/menu.test.focus.js +14 -6
  115. package/dist/menu.test.interactions.js +213 -56
  116. package/dist/modal.icon-button.test.basics.js +2 -1
  117. package/dist/modal.js +1 -1
  118. package/dist/modal.styles.js +18 -13
  119. package/dist/modal.tertiary-icon.d.ts +0 -1
  120. package/dist/modal.tertiary-icon.js +1 -1
  121. package/dist/modal.tertiary-icon.test.basics.js +2 -1
  122. package/dist/modal.test.accessibility.js +1 -0
  123. package/dist/modal.test.basics.js +2 -1
  124. package/dist/modal.test.close.js +1 -0
  125. package/dist/modal.test.events.js +11 -10
  126. package/dist/modal.test.lock-scroll.js +1 -0
  127. package/dist/modal.test.methods.js +1 -0
  128. package/dist/modal.test.scrollbars.js +1 -0
  129. package/dist/radio-group.js +1 -1
  130. package/dist/radio-group.styles.js +1 -1
  131. package/dist/radio-group.test.basics.js +1 -0
  132. package/dist/radio-group.test.events.js +1 -0
  133. package/dist/radio-group.test.focus.js +4 -3
  134. package/dist/radio-group.test.form.js +1 -0
  135. package/dist/radio-group.test.validity.js +1 -0
  136. package/dist/radio.d.ts +1 -0
  137. package/dist/radio.js +1 -1
  138. package/dist/radio.styles.js +33 -0
  139. package/dist/split-button.test.basics.js +1 -0
  140. package/dist/split-container.test.basics.js +5 -0
  141. package/dist/split-link.test.basics.js +1 -0
  142. package/dist/split-link.test.interactions.js +2 -1
  143. package/dist/styles/variables.css +1 -1
  144. package/dist/tab.d.ts +1 -3
  145. package/dist/tab.group.d.ts +3 -5
  146. package/dist/tab.group.js +1 -1
  147. package/dist/tab.group.styles.js +27 -13
  148. package/dist/tab.group.test.basics.js +8 -57
  149. package/dist/tab.group.test.interactions.d.ts +3 -0
  150. package/dist/tab.group.test.interactions.js +454 -0
  151. package/dist/tab.js +1 -1
  152. package/dist/tab.panel.d.ts +1 -0
  153. package/dist/tab.panel.js +1 -1
  154. package/dist/tab.panel.styles.js +11 -1
  155. package/dist/tab.styles.js +7 -68
  156. package/dist/tab.test.basics.js +0 -20
  157. package/dist/tabs.stories.d.ts +1 -2
  158. package/dist/tag.test.basics.js +3 -2
  159. package/dist/textarea.d.ts +0 -1
  160. package/dist/textarea.js +2 -2
  161. package/dist/textarea.stories.d.ts +3 -4
  162. package/dist/textarea.styles.js +14 -3
  163. package/dist/textarea.test.basics.js +81 -44
  164. package/dist/textarea.test.events.js +57 -41
  165. package/dist/textarea.test.form.js +1 -0
  166. package/dist/textarea.test.translations.d.ts +1 -0
  167. package/dist/textarea.test.translations.js +34 -0
  168. package/dist/textarea.test.validity.js +105 -20
  169. package/dist/toasts.js +1 -1
  170. package/dist/toasts.styles.js +8 -1
  171. package/dist/toasts.test.basics.js +20 -0
  172. package/dist/toggle.js +1 -1
  173. package/dist/toggle.test.basics.js +1 -0
  174. package/dist/toggle.test.events.js +1 -0
  175. package/dist/toggle.test.focus.js +1 -1
  176. package/dist/toggle.test.interactions.d.ts +1 -0
  177. package/dist/{toggle.test.states.js → toggle.test.interactions.js} +1 -0
  178. package/dist/tooltip.d.ts +7 -5
  179. package/dist/tooltip.js +1 -1
  180. package/dist/tooltip.styles.js +90 -25
  181. package/dist/tooltip.test.basics.js +39 -3
  182. package/dist/tooltip.test.interactions.js +137 -34
  183. package/dist/translations/en.js +1 -1
  184. package/dist/translations/fr.js +1 -1
  185. package/dist/translations/ja.js +1 -1
  186. package/dist/tree.d.ts +0 -1
  187. package/dist/tree.item.d.ts +2 -3
  188. package/dist/tree.item.js +1 -1
  189. package/dist/tree.item.menu.d.ts +0 -1
  190. package/dist/tree.item.menu.js +1 -1
  191. package/dist/tree.item.test.basics.js +1 -0
  192. package/dist/tree.js +1 -1
  193. package/dist/tree.test.basics.js +2 -1
  194. package/dist/tree.test.events.js +1 -1
  195. package/package.json +40 -29
  196. package/dist/drawer.test.floating-components.d.ts +0 -1
  197. package/dist/drawer.test.floating-components.js +0 -51
  198. package/dist/library/set-containing-block.d.ts +0 -15
  199. package/dist/library/set-containing-block.js +0 -1
  200. package/dist/modal.test.floating-components.js +0 -62
  201. /package/dist/{checkbox.test.states.d.ts → button-group.button.test.focus.d.ts} +0 -0
  202. /package/dist/{modal.test.floating-components.d.ts → checkbox.test.interactions.d.ts} +0 -0
  203. /package/dist/{toggle.test.states.d.ts → dropdown.test.events.filterable.d.ts} +0 -0
@@ -1,9 +1,165 @@
1
+ /* eslint-disable @typescript-eslint/no-unused-expressions */
1
2
  import './dropdown.option.js';
2
3
  import * as sinon from 'sinon';
3
4
  import { aTimeout, expect, fixture, html, oneEvent } from '@open-wc/testing';
5
+ import { sendKeys } from '@web/test-runner-commands';
4
6
  import GlideCoreDropdown from './dropdown.js';
5
7
  GlideCoreDropdown.shadowRootOptions.mode = 'open';
6
- it('dispatches one "change" event when `value` is changed programmatically', async () => {
8
+ it('dispatches one "change" event when an option is selected via click', async () => {
9
+ const component = await fixture(html `<glide-core-dropdown label="Label" placeholder="Placeholder" open>
10
+ <glide-core-dropdown-option
11
+ label="One"
12
+ value="one"
13
+ ></glide-core-dropdown-option>
14
+
15
+ <glide-core-dropdown-option
16
+ label="Two"
17
+ value="two"
18
+ selected
19
+ ></glide-core-dropdown-option>
20
+ </glide-core-dropdown>`);
21
+ const spy = sinon.spy();
22
+ component.addEventListener('change', spy);
23
+ setTimeout(() => {
24
+ component.querySelector('glide-core-dropdown-option')?.click();
25
+ });
26
+ const event = await oneEvent(component, 'change');
27
+ expect(event instanceof Event).to.be.true;
28
+ expect(event.bubbles).to.be.true;
29
+ expect(spy.callCount).to.equal(1);
30
+ });
31
+ it('dispatches one "change" event when an option is selected via Enter', async () => {
32
+ const component = await fixture(html `<glide-core-dropdown label="Label" placeholder="Placeholder" open>
33
+ <glide-core-dropdown-option
34
+ label="One"
35
+ value="one"
36
+ ></glide-core-dropdown-option>
37
+
38
+ <glide-core-dropdown-option
39
+ label="Two"
40
+ value="two"
41
+ selected
42
+ ></glide-core-dropdown-option>
43
+ </glide-core-dropdown>`);
44
+ const spy = sinon.spy();
45
+ component.addEventListener('change', spy);
46
+ // Activate the first option before selecting it. The second option is
47
+ // currently active because it's selected.
48
+ component
49
+ .querySelector('glide-core-dropdown-option')
50
+ ?.dispatchEvent(new MouseEvent('mouseover', { bubbles: true }));
51
+ component.focus();
52
+ sendKeys({ press: 'Enter' });
53
+ const event = await oneEvent(component, 'change');
54
+ expect(event instanceof Event).to.be.true;
55
+ expect(event.bubbles).to.be.true;
56
+ expect(spy.callCount).to.equal(1);
57
+ });
58
+ it('dispatches one "change" event when an option is selected via Space', async () => {
59
+ const component = await fixture(html `<glide-core-dropdown label="Label" placeholder="Placeholder" open>
60
+ <glide-core-dropdown-option
61
+ label="One"
62
+ value="one"
63
+ ></glide-core-dropdown-option>
64
+
65
+ <glide-core-dropdown-option
66
+ label="Two"
67
+ value="two"
68
+ selected
69
+ ></glide-core-dropdown-option>
70
+ </glide-core-dropdown>`);
71
+ const spy = sinon.spy();
72
+ component.addEventListener('change', spy);
73
+ // Activate the first option before selecting it. The second option is
74
+ // currently active because it's selected.
75
+ component
76
+ .querySelector('glide-core-dropdown-option')
77
+ ?.dispatchEvent(new MouseEvent('mouseover', { bubbles: true }));
78
+ component.focus();
79
+ sendKeys({ press: ' ' });
80
+ const event = await oneEvent(component, 'change');
81
+ expect(event instanceof Event).to.be.true;
82
+ expect(event.bubbles).to.be.true;
83
+ expect(spy.callCount).to.equal(1);
84
+ });
85
+ it('dispatches one "input" event when an option is selected via click', async () => {
86
+ const component = await fixture(html `<glide-core-dropdown label="Label" placeholder="Placeholder" open>
87
+ <glide-core-dropdown-option
88
+ label="One"
89
+ value="one"
90
+ ></glide-core-dropdown-option>
91
+
92
+ <glide-core-dropdown-option
93
+ label="Two"
94
+ value="two"
95
+ selected
96
+ ></glide-core-dropdown-option>
97
+ </glide-core-dropdown>`);
98
+ const spy = sinon.spy();
99
+ component.addEventListener('input', spy);
100
+ setTimeout(() => {
101
+ component.querySelector('glide-core-dropdown-option')?.click();
102
+ });
103
+ const event = await oneEvent(component, 'input');
104
+ expect(event instanceof Event).to.be.true;
105
+ expect(event.bubbles).to.be.true;
106
+ expect(spy.callCount).to.equal(1);
107
+ });
108
+ it('dispatches one "input" event when an option is selected via Enter', async () => {
109
+ const component = await fixture(html `<glide-core-dropdown label="Label" placeholder="Placeholder" open>
110
+ <glide-core-dropdown-option
111
+ label="One"
112
+ value="one"
113
+ ></glide-core-dropdown-option>
114
+
115
+ <glide-core-dropdown-option
116
+ label="Two"
117
+ value="two"
118
+ selected
119
+ ></glide-core-dropdown-option>
120
+ </glide-core-dropdown>`);
121
+ const spy = sinon.spy();
122
+ component.addEventListener('input', spy);
123
+ // Activate the first option before selecting it. The second option is
124
+ // currently active because it's selected.
125
+ component
126
+ .querySelector('glide-core-dropdown-option')
127
+ ?.dispatchEvent(new MouseEvent('mouseover', { bubbles: true }));
128
+ component.focus();
129
+ sendKeys({ press: 'Enter' });
130
+ const event = await oneEvent(component, 'input');
131
+ expect(event instanceof Event).to.be.true;
132
+ expect(event.bubbles).to.be.true;
133
+ expect(spy.callCount).to.equal(1);
134
+ });
135
+ it('dispatches one "input" event when an option is selected via Space', async () => {
136
+ const component = await fixture(html `<glide-core-dropdown label="Label" placeholder="Placeholder" open>
137
+ <glide-core-dropdown-option
138
+ label="One"
139
+ value="one"
140
+ ></glide-core-dropdown-option>
141
+
142
+ <glide-core-dropdown-option
143
+ label="Two"
144
+ value="two"
145
+ selected
146
+ ></glide-core-dropdown-option>
147
+ </glide-core-dropdown>`);
148
+ const spy = sinon.spy();
149
+ component.addEventListener('input', spy);
150
+ // Activate the first option before selecting it. The second option is
151
+ // currently active because it's selected.
152
+ component
153
+ .querySelector('glide-core-dropdown-option')
154
+ ?.dispatchEvent(new MouseEvent('mouseover', { bubbles: true }));
155
+ component.focus();
156
+ sendKeys({ press: ' ' });
157
+ const event = await oneEvent(component, 'input');
158
+ expect(event instanceof Event).to.be.true;
159
+ expect(event.bubbles).to.be.true;
160
+ expect(spy.callCount).to.equal(1);
161
+ });
162
+ it('does not dispatch a "change" event when `value` is changed programmatically', async () => {
7
163
  const component = await fixture(html `<glide-core-dropdown label="Label" placeholder="Placeholder" open>
8
164
  <glide-core-dropdown-option
9
165
  label="One"
@@ -22,7 +178,7 @@ it('dispatches one "change" event when `value` is changed programmatically', asy
22
178
  component.value = ['one'];
23
179
  });
24
180
  await aTimeout(0);
25
- expect(spy.calledOnce).to.be.true;
181
+ expect(spy.callCount).to.equal(0);
26
182
  });
27
183
  it('continues to dispatch "change" events upon selection after `value` is changed programmatically', async () => {
28
184
  const component = await fixture(html `<glide-core-dropdown label="Label" placeholder="Placeholder" open>
@@ -44,7 +200,7 @@ it('continues to dispatch "change" events upon selection after `value` is change
44
200
  const event = await oneEvent(component, 'change');
45
201
  expect(event instanceof Event).to.be.true;
46
202
  });
47
- it('dispatches one "input" event when `value` is changed programmatically', async () => {
203
+ it('does not dispatch an "input" event when `value` is changed programmatically', async () => {
48
204
  const component = await fixture(html `<glide-core-dropdown label="Label" placeholder="Placeholder" open>
49
205
  <glide-core-dropdown-option
50
206
  label="One"
@@ -63,7 +219,49 @@ it('dispatches one "input" event when `value` is changed programmatically', asyn
63
219
  component.value = ['one'];
64
220
  });
65
221
  await aTimeout(0);
66
- expect(spy.calledOnce).to.be.true;
222
+ expect(spy.callCount).to.equal(0);
223
+ });
224
+ it('does not dispatch a "change" event when an already selected option is selected', async () => {
225
+ const component = await fixture(html `<glide-core-dropdown label="Label" placeholder="Placeholder" open>
226
+ <glide-core-dropdown-option
227
+ label="One"
228
+ value="one"
229
+ selected
230
+ ></glide-core-dropdown-option>
231
+
232
+ <glide-core-dropdown-option
233
+ label="Two"
234
+ value="two"
235
+ ></glide-core-dropdown-option>
236
+ </glide-core-dropdown>`);
237
+ const spy = sinon.spy();
238
+ component.addEventListener('change', spy);
239
+ setTimeout(() => {
240
+ component.querySelector('glide-core-dropdown-option')?.click();
241
+ });
242
+ await aTimeout(0);
243
+ expect(spy.callCount).to.equal(0);
244
+ });
245
+ it('does not dispatch an "input" event when an already selected option is selected', async () => {
246
+ const component = await fixture(html `<glide-core-dropdown label="Label" placeholder="Placeholder" open>
247
+ <glide-core-dropdown-option
248
+ label="One"
249
+ value="one"
250
+ selected
251
+ ></glide-core-dropdown-option>
252
+
253
+ <glide-core-dropdown-option
254
+ label="Two"
255
+ value="two"
256
+ ></glide-core-dropdown-option>
257
+ </glide-core-dropdown>`);
258
+ const spy = sinon.spy();
259
+ component.addEventListener('input', spy);
260
+ setTimeout(() => {
261
+ component.querySelector('glide-core-dropdown-option')?.click();
262
+ });
263
+ await aTimeout(0);
264
+ expect(spy.callCount).to.equal(0);
67
265
  });
68
266
  it('continues to dispatch "input" events upon selection after `value` is changed programmatically', async () => {
69
267
  const component = await fixture(html `<glide-core-dropdown label="Label" placeholder="Placeholder" open>
@@ -1,5 +1,5 @@
1
1
  import './dropdown.option.js';
2
- import { assert, expect, fixture, html } from '@open-wc/testing';
2
+ import { aTimeout, assert, expect, fixture, html } from '@open-wc/testing';
3
3
  import { sendMouse } from '@web/test-runner-commands';
4
4
  import GlideCoreDropdown from './dropdown.js';
5
5
  import GlideCoreDropdownOption from './dropdown.option.js';
@@ -61,7 +61,7 @@ const defaultSlot = html `
61
61
  value="eleven"
62
62
  ></glide-core-dropdown-option>
63
63
  `;
64
- it('focuses the input when `focus` is called', async () => {
64
+ it('focuses the input when `focus()` is called', async () => {
65
65
  const component = await fixture(html `<glide-core-dropdown label="Label" placeholder="Placeholder">
66
66
  ${defaultSlot}
67
67
  </glide-core-dropdown>`);
@@ -78,12 +78,14 @@ it('retains focus on the input when an option is selected via click', async () =
78
78
  >
79
79
  ${defaultSlot}
80
80
  </glide-core-dropdown>`);
81
+ // Wait for it to open.
82
+ await aTimeout(0);
81
83
  component.focus();
82
84
  const option = component.querySelector('glide-core-dropdown-option');
83
85
  assert(option);
84
86
  const { x, y } = option.getBoundingClientRect();
85
87
  // A simple `option.click()` won't do because we need a "mousedown" so that
86
- // `#onOptionsMousedown` gets covered.
88
+ // `#onOptionsMousedown` is covered.
87
89
  await sendMouse({
88
90
  type: 'click',
89
91
  position: [Math.ceil(x), Math.ceil(y)],
@@ -92,9 +94,11 @@ it('retains focus on the input when an option is selected via click', async () =
92
94
  expect(component.shadowRoot?.activeElement).to.equal(input);
93
95
  });
94
96
  it('retains focus on the the input when an option is selected via Enter', async () => {
95
- const component = await fixture(html `<glide-core-dropdown label="Label" placeholder="Placeholder">
97
+ const component = await fixture(html `<glide-core-dropdown label="Label" placeholder="Placeholder" open>
96
98
  ${defaultSlot}
97
99
  </glide-core-dropdown>`);
100
+ // Wait for it to open.
101
+ await aTimeout(0);
98
102
  component.focus();
99
103
  component
100
104
  .querySelector('glide-core-dropdown-option')
@@ -104,7 +108,7 @@ it('retains focus on the the input when an option is selected via Enter', async
104
108
  expect(component.shadowRoot?.activeElement).to.equal(input);
105
109
  });
106
110
  it('retains focus on the the input when the button is clicked', async () => {
107
- const component = await fixture(html `<glide-core-dropdown label="Label" placeholder="Placeholder">
111
+ const component = await fixture(html `<glide-core-dropdown label="Label" placeholder="Placeholder" open>
108
112
  ${defaultSlot}
109
113
  </glide-core-dropdown>`);
110
114
  component.focus();
@@ -1,3 +1,4 @@
1
+ /* eslint-disable @typescript-eslint/no-unused-expressions */
1
2
  import './dropdown.option.js';
2
3
  import { expect, fixture, html } from '@open-wc/testing';
3
4
  import { sendKeys } from '@web/test-runner-commands';
@@ -32,5 +33,5 @@ it('closes and reports validity when it loses focus', async () => {
32
33
  expect(component.open).to.be.false;
33
34
  expect(component.shadowRoot?.activeElement).to.equal(null);
34
35
  expect(component.validity.valid).to.equal(false);
35
- expect(component.shadowRoot?.querySelector('glide-core-label')?.error).to.equal(true);
36
+ expect(component.shadowRoot?.querySelector('glide-core-private-label')?.error).to.equal(true);
36
37
  });
@@ -2,10 +2,9 @@ import './dropdown.option.js';
2
2
  import { elementUpdated, expect, fixture, html } from '@open-wc/testing';
3
3
  import GlideCoreDropdown from './dropdown.js';
4
4
  import GlideCoreDropdownOption from './dropdown.option.js';
5
- import GlideCoreTag from './tag.js';
6
5
  GlideCoreDropdown.shadowRootOptions.mode = 'open';
7
6
  GlideCoreDropdownOption.shadowRootOptions.mode = 'open';
8
- it('focuses the button when `focus` is called', async () => {
7
+ it('focuses the button when `focus()` is called', async () => {
9
8
  const component = await fixture(html `<glide-core-dropdown label="Label" placeholder="Placeholder" multiple>
10
9
  <glide-core-dropdown-option
11
10
  label="One"
@@ -4,7 +4,7 @@ import GlideCoreDropdown from './dropdown.js';
4
4
  import GlideCoreDropdownOption from './dropdown.option.js';
5
5
  GlideCoreDropdown.shadowRootOptions.mode = 'open';
6
6
  GlideCoreDropdownOption.shadowRootOptions.mode = 'open';
7
- it('focuses the button when `focus` is called', async () => {
7
+ it('focuses the button when `focus()` is called', async () => {
8
8
  const component = await fixture(html `<glide-core-dropdown label="Label" placeholder="Placeholder">
9
9
  <glide-core-dropdown-option
10
10
  label="Label"
@@ -1,3 +1,4 @@
1
+ /* eslint-disable @typescript-eslint/no-unused-expressions */
1
2
  import './dropdown.option.js';
2
3
  import { elementUpdated, expect, fixture, html } from '@open-wc/testing';
3
4
  import GlideCoreDropdown from './dropdown.js';
@@ -1,3 +1,4 @@
1
+ /* eslint-disable @typescript-eslint/no-unused-expressions */
1
2
  import './dropdown.option.js';
2
3
  import { elementUpdated, expect, fixture, html } from '@open-wc/testing';
3
4
  import GlideCoreDropdown from './dropdown.js';
@@ -1,3 +1,4 @@
1
+ /* eslint-disable @typescript-eslint/no-unused-expressions */
1
2
  import './dropdown.option.js';
2
3
  import { elementUpdated, expect, fixture, html } from '@open-wc/testing';
3
4
  import GlideCoreDropdown from './dropdown.js';
@@ -1,4 +1,5 @@
1
- import { assert, elementUpdated, expect, fixture, html, } from '@open-wc/testing';
1
+ /* eslint-disable @typescript-eslint/no-unused-expressions */
2
+ import { aTimeout, assert, elementUpdated, expect, fixture, html, } from '@open-wc/testing';
2
3
  import { sendKeys } from '@web/test-runner-commands';
3
4
  import GlideCoreDropdown from './dropdown.js';
4
5
  import GlideCoreDropdownOption from './dropdown.option.js';
@@ -71,7 +72,11 @@ it('opens on click', async () => {
71
72
  component.shadowRoot
72
73
  ?.querySelector('[data-test="input"]')
73
74
  ?.dispatchEvent(new CustomEvent('click', { bubbles: true, detail: 1 }));
75
+ // Wait for it to open.
76
+ await aTimeout(0);
77
+ const options = component.shadowRoot?.querySelector('[data-test="options"]');
74
78
  expect(component.open).to.be.true;
79
+ expect(options?.checkVisibility()).to.be.true;
75
80
  });
76
81
  it('filters', async () => {
77
82
  const component = await fixture(html `<glide-core-dropdown label="Label" placeholder="Placeholder">
@@ -84,10 +89,12 @@ it('filters', async () => {
84
89
  ].filter(({ hidden }) => !hidden);
85
90
  expect(options.length).to.equal(1);
86
91
  });
87
- it('clears the filter term when an option is selected', async () => {
92
+ it('unfilters when an option is selected via click', async () => {
88
93
  const component = await fixture(html `<glide-core-dropdown label="Label" placeholder="Placeholder">
89
94
  ${defaultSlot}
90
95
  </glide-core-dropdown>`);
96
+ // Wait for it to open.
97
+ await aTimeout(0);
91
98
  component.focus();
92
99
  await sendKeys({ type: ' one ' });
93
100
  const option = [
@@ -101,6 +108,20 @@ it('clears the filter term when an option is selected', async () => {
101
108
  expect(input?.value).to.equal('');
102
109
  expect(options.length).to.equal(11);
103
110
  });
111
+ it('unfilters when an option is selected via Enter', async () => {
112
+ const component = await fixture(html `<glide-core-dropdown label="Label" placeholder="Placeholder">
113
+ ${defaultSlot}
114
+ </glide-core-dropdown>`);
115
+ component.focus();
116
+ await sendKeys({ type: ' one ' });
117
+ await sendKeys({ press: 'Enter' });
118
+ const input = component.shadowRoot?.querySelector('[data-test="input"]');
119
+ const options = [
120
+ ...component.querySelectorAll('glide-core-dropdown-option'),
121
+ ].filter(({ hidden }) => !hidden);
122
+ expect(input?.value).to.equal('');
123
+ expect(options.length).to.equal(11);
124
+ });
104
125
  it('shows the magnifying glass icon when there is a filter term', async () => {
105
126
  const component = await fixture(html `<glide-core-dropdown label="Label" placeholder="Placeholder">
106
127
  ${defaultSlot}
@@ -118,9 +139,11 @@ it('hides the magnifying glass icon when there is no filter term', async () => {
118
139
  expect(icon?.checkVisibility()).to.be.not.ok;
119
140
  });
120
141
  it('hides the magnifying glass icon when an option is selected', async () => {
121
- const component = await fixture(html `<glide-core-dropdown label="Label" placeholder="Placeholder">
142
+ const component = await fixture(html `<glide-core-dropdown label="Label" placeholder="Placeholder" open>
122
143
  ${defaultSlot}
123
144
  </glide-core-dropdown>`);
145
+ // Wait for it to open.
146
+ await aTimeout(0);
124
147
  component.focus();
125
148
  await sendKeys({ type: ' one ' });
126
149
  const option = [
@@ -146,10 +169,14 @@ it('hides the options when all of them are filtered out', async () => {
146
169
  const component = await fixture(html `<glide-core-dropdown label="Label" placeholder="Placeholder" open>
147
170
  ${defaultSlot}
148
171
  </glide-core-dropdown>`);
172
+ // Wait for it to open.
173
+ await aTimeout(0);
149
174
  component.focus();
150
- await sendKeys({ type: 'twelve' });
175
+ await sendKeys({ type: 'fifty' });
176
+ // Wait for it to close.
177
+ await aTimeout(0);
151
178
  const options = component.shadowRoot?.querySelector('[data-test="options"]');
152
- expect(options?.dataset.testVisible).to.equal('false');
179
+ expect(options?.checkVisibility()).to.be.false;
153
180
  });
154
181
  it('hides Select All when filtering', async () => {
155
182
  const component = await fixture(html `<glide-core-dropdown
@@ -193,6 +220,20 @@ it('updates `value` when an option `value` is changed programmatically', async (
193
220
  option.value = 'two';
194
221
  expect(component.value).to.deep.equal(['two']);
195
222
  });
223
+ it('does not select options on Space', async () => {
224
+ const component = await fixture(html `<glide-core-dropdown
225
+ label="Label"
226
+ placeholder="Placeholder"
227
+ multiple
228
+ open
229
+ >
230
+ ${defaultSlot}
231
+ </glide-core-dropdown>`);
232
+ const options = component.querySelectorAll('glide-core-dropdown-option');
233
+ options[0]?.focus();
234
+ await sendKeys({ press: ' ' });
235
+ expect(options[0]?.selected).to.be.false;
236
+ });
196
237
  it('deselects options on Backspace', async () => {
197
238
  const component = await fixture(html `<glide-core-dropdown label="Label" placeholder="Placeholder" multiple>
198
239
  ${defaultSlot}
@@ -243,6 +284,8 @@ it('sets `aria-activedescendant` on ArrowDown', async () => {
243
284
  >
244
285
  ${defaultSlot}
245
286
  </glide-core-dropdown>`);
287
+ // Wait for it to open.
288
+ await aTimeout(0);
246
289
  const options = component.querySelectorAll('glide-core-dropdown-option');
247
290
  options[0]?.focus();
248
291
  await sendKeys({ press: 'ArrowDown' });
@@ -258,6 +301,8 @@ it('sets `aria-activedescendant` on ArrowUp', async () => {
258
301
  >
259
302
  ${defaultSlot}
260
303
  </glide-core-dropdown>`);
304
+ // Wait for it to open.
305
+ await aTimeout(0);
261
306
  const options = component.querySelectorAll('glide-core-dropdown-option');
262
307
  options[1]?.dispatchEvent(new MouseEvent('mouseover', { bubbles: true }));
263
308
  options[1]?.focus();
@@ -274,6 +319,8 @@ it('sets `aria-activedescendant` on Home', async () => {
274
319
  >
275
320
  ${defaultSlot}
276
321
  </glide-core-dropdown>`);
322
+ // Wait for it to open.
323
+ await aTimeout(0);
277
324
  const options = component.querySelectorAll('glide-core-dropdown-option');
278
325
  options[1]?.dispatchEvent(new MouseEvent('mouseover', { bubbles: true }));
279
326
  options[1].focus();
@@ -290,6 +337,8 @@ it('sets `aria-activedescendant` on PageUp', async () => {
290
337
  >
291
338
  ${defaultSlot}
292
339
  </glide-core-dropdown>`);
340
+ // Wait for it to open.
341
+ await aTimeout(0);
293
342
  const options = component.querySelectorAll('glide-core-dropdown-option');
294
343
  options[1].dispatchEvent(new MouseEvent('mouseover', { bubbles: true }));
295
344
  options[1].focus();
@@ -297,7 +346,7 @@ it('sets `aria-activedescendant` on PageUp', async () => {
297
346
  const input = component.shadowRoot?.querySelector('[data-test="input"]');
298
347
  expect(input?.getAttribute('aria-activedescendant')).to.equal(options[0].id);
299
348
  });
300
- it('sets `aria-activedescendant` on ArrowUp + Meta', async () => {
349
+ it('sets `aria-activedescendant` on Meta + ArrowUp', async () => {
301
350
  const component = await fixture(html `<glide-core-dropdown
302
351
  label="Label"
303
352
  placeholder="Placeholder"
@@ -306,9 +355,11 @@ it('sets `aria-activedescendant` on ArrowUp + Meta', async () => {
306
355
  >
307
356
  ${defaultSlot}
308
357
  </glide-core-dropdown>`);
358
+ // Wait for it to open.
359
+ await aTimeout(0);
360
+ component.focus();
309
361
  const options = component.querySelectorAll('glide-core-dropdown-option');
310
362
  options[1]?.dispatchEvent(new MouseEvent('mouseover', { bubbles: true }));
311
- options[1].focus();
312
363
  await sendKeys({ down: 'Meta' });
313
364
  await sendKeys({ press: 'ArrowUp' });
314
365
  await sendKeys({ up: 'Meta' });
@@ -326,7 +377,8 @@ it('sets `aria-activedescendant` on open via click', async () => {
326
377
  component.shadowRoot
327
378
  ?.querySelector('[data-test="button"]')
328
379
  ?.dispatchEvent(new CustomEvent('click', { bubbles: true, detail: 1 }));
329
- await elementUpdated(component);
380
+ // Wait for it to open.
381
+ await aTimeout(0);
330
382
  const input = component.shadowRoot?.querySelector('[data-test="input"]');
331
383
  const option = component.querySelector('glide-core-dropdown-option');
332
384
  expect(input?.getAttribute('aria-activedescendant')).to.equal(option?.id);
@@ -350,11 +402,13 @@ it('sets `aria-activedescendant` on End', async () => {
350
402
  >
351
403
  ${defaultSlot}
352
404
  </glide-core-dropdown>`);
405
+ // Wait for it to open.
406
+ await aTimeout(0);
407
+ component.focus();
353
408
  // Made into an array because the linter forces `at(-1)` instead of
354
409
  // `[options.length - 1]` but doesn't take into account that `options`
355
410
  // isn't an actual array and doesn't have an `at()` method.
356
411
  const options = [...component.querySelectorAll('glide-core-dropdown-option')];
357
- options[0]?.focus();
358
412
  await sendKeys({ press: 'End' });
359
413
  const input = component.shadowRoot?.querySelector('[data-test="input"]');
360
414
  expect(input?.getAttribute('aria-activedescendant')).to.equal(options.at(-1)?.id);
@@ -368,11 +422,13 @@ it('sets `aria-activedescendant` on PageDown', async () => {
368
422
  >
369
423
  ${defaultSlot}
370
424
  </glide-core-dropdown>`);
425
+ // Wait for it to open.
426
+ await aTimeout(0);
427
+ component.focus();
371
428
  // Made into an array because the linter forces `at(-1)` instead of
372
429
  // `[options.length - 1]` but doesn't take into account that `options`
373
430
  // isn't an actual array and doesn't have an `at()` method.
374
431
  const options = [...component.querySelectorAll('glide-core-dropdown-option')];
375
- options[0]?.focus();
376
432
  await sendKeys({ press: 'PageDown' });
377
433
  const input = component.shadowRoot?.querySelector('[data-test="input"]');
378
434
  expect(input?.getAttribute('aria-activedescendant')).to.equal(options.at(-1)?.id);
@@ -386,11 +442,13 @@ it('sets `aria-activedescendant` on Meta + ArrowDown', async () => {
386
442
  >
387
443
  ${defaultSlot}
388
444
  </glide-core-dropdown>`);
445
+ // Wait for it to open.
446
+ await aTimeout(0);
447
+ component.focus();
389
448
  // Spread into an array because the linter forces `at(-1)` instead of
390
449
  // `[options.length - 1]` but doesn't take into account that `options`
391
450
  // isn't an actual array and doesn't have an `at()` method.
392
451
  const options = [...component.querySelectorAll('glide-core-dropdown-option')];
393
- options[0]?.focus();
394
452
  await sendKeys({ down: 'Meta' });
395
453
  await sendKeys({ press: 'ArrowDown' });
396
454
  await sendKeys({ up: 'Meta' });