@crowdstrike/glide-core 0.5.0 → 0.5.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.
Files changed (208) hide show
  1. package/dist/accordion.js +1 -1
  2. package/dist/accordion.styles.js +4 -4
  3. package/dist/accordion.test.basics.js +109 -0
  4. package/dist/accordion.test.events.js +39 -0
  5. package/dist/button-group.button.js +1 -1
  6. package/dist/button-group.button.styles.js +4 -4
  7. package/dist/button-group.button.test.basics.js +169 -0
  8. package/dist/button-group.button.test.events.js +73 -0
  9. package/dist/button-group.js +1 -1
  10. package/dist/button-group.styles.js +3 -3
  11. package/dist/button-group.test.basics.js +268 -0
  12. package/dist/button-group.test.events.js +291 -0
  13. package/dist/button.js +1 -1
  14. package/dist/button.styles.js +4 -4
  15. package/dist/button.test.basics.js +196 -0
  16. package/dist/button.test.events.js +25 -0
  17. package/dist/button.test.form.js +49 -0
  18. package/dist/checkbox-group.js +1 -1
  19. package/dist/checkbox-group.styles.js +2 -2
  20. package/dist/checkbox-group.test.basics.js +119 -0
  21. package/dist/checkbox-group.test.events.js +110 -0
  22. package/dist/checkbox-group.test.focus.js +45 -0
  23. package/dist/checkbox-group.test.form.js +130 -0
  24. package/dist/checkbox-group.test.validity.js +75 -0
  25. package/dist/checkbox.js +1 -1
  26. package/dist/checkbox.styles.js +3 -3
  27. package/dist/checkbox.test.basics.js +89 -0
  28. package/dist/checkbox.test.events.js +87 -0
  29. package/dist/checkbox.test.focus.js +38 -0
  30. package/dist/checkbox.test.form.js +115 -0
  31. package/dist/checkbox.test.states.js +62 -0
  32. package/dist/checkbox.test.validity.js +51 -0
  33. package/dist/drawer.d.ts +2 -2
  34. package/dist/drawer.js +1 -15
  35. package/dist/drawer.styles.js +18 -3
  36. package/dist/drawer.test.accessibility.js +22 -0
  37. package/dist/drawer.test.basics.js +43 -0
  38. package/dist/drawer.test.closing.js +37 -0
  39. package/dist/drawer.test.events.js +52 -0
  40. package/dist/drawer.test.methods.js +34 -0
  41. package/dist/dropdown.d.ts +4 -2
  42. package/dist/dropdown.js +1 -1
  43. package/dist/dropdown.option.d.ts +1 -3
  44. package/dist/dropdown.option.js +1 -1
  45. package/dist/dropdown.option.styles.js +2 -2
  46. package/dist/dropdown.option.test.basics.js +59 -0
  47. package/dist/dropdown.option.test.basics.multiple.js +26 -0
  48. package/dist/dropdown.option.test.basics.single.js +20 -0
  49. package/dist/dropdown.option.test.events.js +27 -0
  50. package/dist/dropdown.option.test.focus.js +11 -0
  51. package/dist/dropdown.option.test.interactions.multiple.js +87 -0
  52. package/dist/dropdown.option.test.interactions.single.js +22 -0
  53. package/dist/dropdown.styles.js +28 -9
  54. package/dist/dropdown.test.basics.filterable.js +84 -0
  55. package/dist/dropdown.test.basics.js +233 -0
  56. package/dist/dropdown.test.basics.multiple.js +270 -0
  57. package/dist/dropdown.test.basics.single.js +79 -0
  58. package/dist/dropdown.test.events.js +268 -0
  59. package/dist/dropdown.test.events.multiple.js +130 -0
  60. package/dist/dropdown.test.focus.d.ts +1 -0
  61. package/dist/dropdown.test.focus.filterable.js +154 -0
  62. package/dist/dropdown.test.focus.js +18 -0
  63. package/dist/dropdown.test.focus.multiple.js +181 -0
  64. package/dist/dropdown.test.focus.single.js +53 -0
  65. package/dist/dropdown.test.form.js +140 -0
  66. package/dist/dropdown.test.form.multiple.js +149 -0
  67. package/dist/dropdown.test.form.single.js +128 -0
  68. package/dist/dropdown.test.interactions.filterable.js +385 -0
  69. package/dist/dropdown.test.interactions.js +446 -0
  70. package/dist/dropdown.test.interactions.multiple.js +908 -0
  71. package/dist/dropdown.test.interactions.single.js +466 -0
  72. package/dist/dropdown.test.validity.js +46 -0
  73. package/dist/icon-button.js +1 -1
  74. package/dist/icon-button.styles.js +3 -3
  75. package/dist/icon-button.test.basics.js +103 -0
  76. package/dist/icons/checked.js +1 -1
  77. package/dist/icons/magnifying-glass.js +1 -1
  78. package/dist/input.js +1 -1
  79. package/dist/input.styles.js +3 -3
  80. package/dist/input.test.basics.js +169 -0
  81. package/dist/input.test.events.js +97 -0
  82. package/dist/input.test.focus.js +54 -0
  83. package/dist/input.test.form.js +56 -0
  84. package/dist/input.test.validity.js +50 -0
  85. package/dist/label.js +1 -1
  86. package/dist/label.styles.js +3 -3
  87. package/dist/label.test.basics.js +129 -0
  88. package/dist/library/expect-argument-error.js +1 -1
  89. package/dist/library/ow.js +1 -1
  90. package/dist/library/ow.test.js +55 -0
  91. package/dist/menu.button.d.ts +1 -2
  92. package/dist/menu.button.js +1 -1
  93. package/dist/menu.button.styles.js +3 -3
  94. package/dist/menu.button.test.basics.js +42 -0
  95. package/dist/menu.d.ts +4 -0
  96. package/dist/menu.js +1 -1
  97. package/dist/menu.link.d.ts +1 -2
  98. package/dist/menu.link.js +1 -1
  99. package/dist/menu.link.styles.js +3 -3
  100. package/dist/menu.link.test.basics.js +46 -0
  101. package/dist/menu.styles.js +13 -6
  102. package/dist/menu.test.basics.js +161 -0
  103. package/dist/menu.test.focus.d.ts +0 -1
  104. package/dist/menu.test.focus.js +66 -0
  105. package/dist/menu.test.interactions.d.ts +0 -1
  106. package/dist/menu.test.interactions.js +522 -0
  107. package/dist/modal.icon-button.js +1 -1
  108. package/dist/modal.icon-button.styles.js +2 -2
  109. package/dist/modal.icon-button.test.basics.js +45 -0
  110. package/dist/modal.js +1 -15
  111. package/dist/modal.styles.js +4 -4
  112. package/dist/modal.tertiary-icon.js +1 -1
  113. package/dist/modal.tertiary-icon.test.basics.js +59 -0
  114. package/dist/modal.test.accessibility.js +48 -0
  115. package/dist/modal.test.basics.js +203 -0
  116. package/dist/modal.test.close.js +38 -0
  117. package/dist/modal.test.events.js +110 -0
  118. package/dist/modal.test.lock-scroll.js +76 -0
  119. package/dist/modal.test.methods.js +23 -0
  120. package/dist/modal.test.scrollbars.js +19 -0
  121. package/dist/radio-group.js +1 -1
  122. package/dist/radio-group.styles.js +2 -2
  123. package/dist/radio-group.test.basics.js +323 -0
  124. package/dist/radio-group.test.events.js +277 -0
  125. package/dist/radio-group.test.focus.js +75 -0
  126. package/dist/radio-group.test.form.js +104 -0
  127. package/dist/radio-group.test.validity.js +228 -0
  128. package/dist/radio.js +1 -1
  129. package/dist/radio.styles.js +4 -4
  130. package/dist/split-button.d.ts +24 -0
  131. package/dist/split-button.js +1 -0
  132. package/dist/split-button.stories.d.ts +17 -0
  133. package/dist/split-button.styles.d.ts +2 -0
  134. package/dist/split-button.styles.js +103 -0
  135. package/dist/split-button.test.basics.d.ts +1 -0
  136. package/dist/split-button.test.basics.js +84 -0
  137. package/dist/split-container.d.ts +30 -0
  138. package/dist/split-container.js +1 -0
  139. package/dist/split-container.styles.d.ts +2 -0
  140. package/dist/split-container.styles.js +132 -0
  141. package/dist/split-container.test.basics.d.ts +3 -0
  142. package/dist/split-container.test.basics.js +445 -0
  143. package/dist/split-container.test.interactions.d.ts +1 -0
  144. package/dist/split-container.test.interactions.js +20 -0
  145. package/dist/split-link.d.ts +25 -0
  146. package/dist/split-link.js +1 -0
  147. package/dist/split-link.test.basics.d.ts +1 -0
  148. package/dist/split-link.test.basics.js +92 -0
  149. package/dist/split-link.test.interactions.d.ts +1 -0
  150. package/dist/split-link.test.interactions.js +19 -0
  151. package/dist/status-indicator.js +1 -1
  152. package/dist/status-indicator.styles.js +2 -2
  153. package/dist/status-indicator.test.basics.js +102 -0
  154. package/dist/styles/focus-outline.js +1 -4
  155. package/dist/styles/visually-hidden.js +1 -11
  156. package/dist/tab.group.js +1 -1
  157. package/dist/tab.group.styles.js +2 -2
  158. package/dist/tab.group.test.basics.js +185 -0
  159. package/dist/tab.js +1 -1
  160. package/dist/tab.panel.js +1 -1
  161. package/dist/tab.panel.styles.js +3 -3
  162. package/dist/tab.styles.js +2 -2
  163. package/dist/tab.test.basics.js +71 -0
  164. package/dist/tag.js +1 -1
  165. package/dist/tag.styles.js +3 -3
  166. package/dist/tag.test.basics.js +118 -0
  167. package/dist/tag.test.events.js +16 -0
  168. package/dist/tag.test.focus.js +11 -0
  169. package/dist/textarea.js +2 -2
  170. package/dist/textarea.styles.js +3 -3
  171. package/dist/textarea.test.basics.js +140 -0
  172. package/dist/textarea.test.events.js +204 -0
  173. package/dist/textarea.test.form.js +70 -0
  174. package/dist/textarea.test.validity.js +83 -0
  175. package/dist/toasts.js +1 -1
  176. package/dist/toasts.styles.js +2 -2
  177. package/dist/toasts.test.basics.js +94 -0
  178. package/dist/toasts.toast.js +1 -1
  179. package/dist/toasts.toast.styles.js +5 -2
  180. package/dist/toasts.toast.test.basics.js +139 -0
  181. package/dist/toggle.js +1 -1
  182. package/dist/toggle.styles.js +3 -3
  183. package/dist/toggle.test.basics.js +64 -0
  184. package/dist/toggle.test.events.js +29 -0
  185. package/dist/toggle.test.focus.js +9 -0
  186. package/dist/toggle.test.states.js +35 -0
  187. package/dist/tooltip.js +1 -1
  188. package/dist/tooltip.styles.js +3 -3
  189. package/dist/tooltip.test.basics.js +64 -0
  190. package/dist/tooltip.test.interactions.js +78 -0
  191. package/dist/tree.item.icon-button.js +1 -1
  192. package/dist/tree.item.icon-button.styles.js +2 -2
  193. package/dist/tree.item.icon-button.test.basics.js +13 -0
  194. package/dist/tree.item.js +1 -1
  195. package/dist/tree.item.menu.js +1 -1
  196. package/dist/tree.item.menu.styles.js +2 -2
  197. package/dist/tree.item.menu.test.basics.js +34 -0
  198. package/dist/tree.item.styles.js +2 -2
  199. package/dist/tree.item.test.basics.js +102 -0
  200. package/dist/tree.js +1 -1
  201. package/dist/tree.styles.js +2 -2
  202. package/dist/tree.test.aria.js +86 -0
  203. package/dist/tree.test.basics.js +123 -0
  204. package/dist/tree.test.events.js +19 -0
  205. package/dist/tree.test.focus.js +261 -0
  206. package/package.json +20 -18
  207. /package/dist/{dropdown.option.test.focus.multiple.d.ts → dropdown.option.test.focus.d.ts} +0 -0
  208. /package/dist/{dropdown.option.test.focus.single.d.ts → dropdown.test.events.multiple.d.ts} +0 -0
@@ -0,0 +1,908 @@
1
+ import { assert, elementUpdated, expect, fixture, html, } from '@open-wc/testing';
2
+ import { sendKeys } from '@web/test-runner-commands';
3
+ import { sendMouse } from '@web/test-runner-commands';
4
+ import GlideCoreDropdown from './dropdown.js';
5
+ import GlideCoreDropdownOption from './dropdown.option.js';
6
+ import GlideCoreTag from './tag.js';
7
+ GlideCoreDropdown.shadowRootOptions.mode = 'open';
8
+ GlideCoreDropdownOption.shadowRootOptions.mode = 'open';
9
+ it('opens on click', async () => {
10
+ const component = await fixture(html `<glide-core-dropdown label="Label" placeholder="Placeholder" multiple>
11
+ <glide-core-dropdown-option
12
+ label="One"
13
+ value="one"
14
+ ></glide-core-dropdown-option>
15
+
16
+ <glide-core-dropdown-option
17
+ label="Two"
18
+ value="two"
19
+ ></glide-core-dropdown-option>
20
+ </glide-core-dropdown>`);
21
+ // Calling `click()` would be sweet. The problem is it sets `event.detail` to `0`,
22
+ // which puts us in a guard in the event handler. `Event` has no `detail` property
23
+ // and would work. `CustomEvent` is used for completeness and to get us as close as
24
+ // possible to a real click. See the comment in the handler for more information.
25
+ component.shadowRoot
26
+ ?.querySelector('[data-test="button"]')
27
+ ?.dispatchEvent(new CustomEvent('click', { bubbles: true, detail: 1 }));
28
+ expect(component.open).to.be.true;
29
+ });
30
+ it('toggles open and closed when the button is clicked', async () => {
31
+ const component = await fixture(html `<glide-core-dropdown
32
+ label="Label"
33
+ placeholder="Placeholder"
34
+ open
35
+ multiple
36
+ >
37
+ <glide-core-dropdown-option
38
+ label="One"
39
+ value="one"
40
+ ></glide-core-dropdown-option>
41
+
42
+ <glide-core-dropdown-option
43
+ label="Two"
44
+ value="two"
45
+ ></glide-core-dropdown-option>
46
+ </glide-core-dropdown>`);
47
+ // Calling `click()` would be sweet. The problem is it sets `event.detail` to `0`,
48
+ // which puts us in a guard in the event handler. `Event` has no `detail` property
49
+ // and would work. `CustomEvent` is used for completeness and to get us as close as
50
+ // possible to a real click. See the comment in the handler for more information.
51
+ component.shadowRoot
52
+ ?.querySelector('[data-test="button"]')
53
+ ?.dispatchEvent(new CustomEvent('click', { bubbles: true, detail: 1 }));
54
+ expect(component.open).to.be.false;
55
+ });
56
+ it('does not toggle open and closed when the button overflow text is clicked', async () => {
57
+ const component = await fixture(html `<glide-core-dropdown
58
+ label="Label"
59
+ placeholder="Placeholder"
60
+ open
61
+ multiple
62
+ >
63
+ <glide-core-dropdown-option
64
+ label="One"
65
+ value="one"
66
+ ></glide-core-dropdown-option>
67
+
68
+ <glide-core-dropdown-option
69
+ label="Two"
70
+ value="two"
71
+ ></glide-core-dropdown-option>
72
+ </glide-core-dropdown>`);
73
+ // Calling `click()` would be sweet. The problem is it sets `event.detail` to `0`,
74
+ // which puts us in a guard in the event handler. `Event` has no `detail` property
75
+ // and would work. `CustomEvent` is used for completeness and to get us as close as
76
+ // possible to a real click. See the comment in the handler for more information.
77
+ component.shadowRoot
78
+ ?.querySelector('[data-test="tag-overflow-text"]')
79
+ ?.dispatchEvent(new CustomEvent('click', { bubbles: true, detail: 1 }));
80
+ expect(component.open).to.be.true;
81
+ });
82
+ it('selects options on click', async () => {
83
+ const component = await fixture(html `<glide-core-dropdown
84
+ label="Label"
85
+ placeholder="Placeholder"
86
+ open
87
+ multiple
88
+ >
89
+ <glide-core-dropdown-option
90
+ label="One"
91
+ value="one"
92
+ ></glide-core-dropdown-option>
93
+
94
+ <glide-core-dropdown-option
95
+ label="Two"
96
+ value="two"
97
+ ></glide-core-dropdown-option>
98
+ </glide-core-dropdown>`);
99
+ const options = component.querySelectorAll('glide-core-dropdown-option');
100
+ options[0]?.click();
101
+ options[1]?.click();
102
+ await elementUpdated(component);
103
+ const labels = component.shadowRoot?.querySelectorAll('[data-test="selected-option-label"]');
104
+ expect(options[0]?.selected).to.be.true;
105
+ expect(labels?.length).to.equal(2);
106
+ expect(labels?.[0]?.textContent?.trim()).to.equal('One,');
107
+ expect(labels?.[1]?.textContent?.trim()).to.equal('Two,');
108
+ });
109
+ it('selects options on Space', async () => {
110
+ const component = await fixture(html `<glide-core-dropdown
111
+ label="Label"
112
+ placeholder="Placeholder"
113
+ multiple
114
+ open
115
+ >
116
+ <glide-core-dropdown-option
117
+ label="One"
118
+ value="one"
119
+ ></glide-core-dropdown-option>
120
+
121
+ <glide-core-dropdown-option
122
+ label="Two"
123
+ value="two"
124
+ ></glide-core-dropdown-option>
125
+ </glide-core-dropdown>`);
126
+ const options = component.querySelectorAll('glide-core-dropdown-option');
127
+ options[0]?.focus();
128
+ await sendKeys({ press: ' ' });
129
+ options[1]?.focus();
130
+ await sendKeys({ press: ' ' });
131
+ await elementUpdated(component);
132
+ const labels = component.shadowRoot?.querySelectorAll('[data-test="selected-option-label"]');
133
+ expect(options[0]?.selected).to.be.true;
134
+ expect(options[1]?.selected).to.be.true;
135
+ expect(labels?.length).to.equal(2);
136
+ expect(labels?.[0]?.textContent?.trim()).to.equal('One,');
137
+ expect(labels?.[1]?.textContent?.trim()).to.equal('Two,');
138
+ });
139
+ it('selects options on Enter', async () => {
140
+ const component = await fixture(html `<glide-core-dropdown
141
+ label="Label"
142
+ placeholder="Placeholder"
143
+ multiple
144
+ open
145
+ >
146
+ <glide-core-dropdown-option
147
+ label="One"
148
+ value="one"
149
+ ></glide-core-dropdown-option>
150
+
151
+ <glide-core-dropdown-option
152
+ label="Two"
153
+ value="two"
154
+ ></glide-core-dropdown-option>
155
+ </glide-core-dropdown>`);
156
+ const options = component.querySelectorAll('glide-core-dropdown-option');
157
+ options[0]?.focus();
158
+ await sendKeys({ press: 'Enter' });
159
+ options[1]?.focus();
160
+ await sendKeys({ press: 'Enter' });
161
+ const labels = component.shadowRoot?.querySelectorAll('[data-test="selected-option-label"]');
162
+ expect(options[0]?.selected).to.be.true;
163
+ expect(options[1]?.selected).to.be.true;
164
+ expect(labels?.length).to.equal(2);
165
+ expect(labels?.[0]?.textContent?.trim()).to.equal('One,');
166
+ expect(labels?.[1]?.textContent?.trim()).to.equal('Two,');
167
+ });
168
+ it('activates Select All by default', async () => {
169
+ const component = await fixture(html `<glide-core-dropdown open multiple select-all>
170
+ <glide-core-dropdown-option
171
+ label="One"
172
+ value="one"
173
+ ></glide-core-dropdown-option>
174
+
175
+ <glide-core-dropdown-option
176
+ label="Two"
177
+ value="two"
178
+ ></glide-core-dropdown-option>
179
+ </glide-core-dropdown>`);
180
+ const options = component.querySelectorAll('glide-core-dropdown-option');
181
+ const selectAll = component.shadowRoot?.querySelector('[data-test="select-all"]');
182
+ expect(selectAll?.privateActive).to.be.true;
183
+ expect(options[0]?.privateActive).to.be.false;
184
+ expect(options[1]?.privateActive).to.be.false;
185
+ });
186
+ it('deactivates all other options on "mouseover"', async () => {
187
+ const component = await fixture(html `<glide-core-dropdown open multiple select-all>
188
+ <glide-core-dropdown-option
189
+ label="One"
190
+ value="one"
191
+ ></glide-core-dropdown-option>
192
+
193
+ <glide-core-dropdown-option
194
+ label="Two"
195
+ value="two"
196
+ ></glide-core-dropdown-option>
197
+ </glide-core-dropdown>`);
198
+ const options = [
199
+ ...component.querySelectorAll('glide-core-dropdown-option'),
200
+ component.shadowRoot?.querySelector('[data-test="select-all"]'),
201
+ ];
202
+ options[0]?.dispatchEvent(new MouseEvent('mouseover', { bubbles: true }));
203
+ options[1]?.dispatchEvent(new MouseEvent('mouseover', { bubbles: true }));
204
+ expect(options[0]?.privateActive).to.be.false;
205
+ expect(options[1]?.privateActive).to.be.true;
206
+ expect(options[2]?.privateActive).to.be.false;
207
+ });
208
+ it('remains open when an option is selected via click', async () => {
209
+ const component = await fixture(html `<glide-core-dropdown
210
+ label="Label"
211
+ placeholder="Placeholder"
212
+ open
213
+ multiple
214
+ >
215
+ <glide-core-dropdown-option
216
+ label="One"
217
+ value="one"
218
+ selected
219
+ ></glide-core-dropdown-option>
220
+
221
+ <glide-core-dropdown-option
222
+ label="Two"
223
+ value="two"
224
+ ></glide-core-dropdown-option>
225
+ </glide-core-dropdown>`);
226
+ component.querySelector('glide-core-dropdown-option')?.click();
227
+ expect(component.open).to.be.true;
228
+ });
229
+ it('remains open when an option is selected via Enter', async () => {
230
+ const component = await fixture(html `<glide-core-dropdown
231
+ label="Label"
232
+ placeholder="Placeholder"
233
+ open
234
+ multiple
235
+ >
236
+ <glide-core-dropdown-option
237
+ label="One"
238
+ value="one"
239
+ selected
240
+ ></glide-core-dropdown-option>
241
+
242
+ <glide-core-dropdown-option
243
+ label="Two"
244
+ value="two"
245
+ ></glide-core-dropdown-option>
246
+ </glide-core-dropdown>`);
247
+ component.querySelector('glide-core-dropdown-option')?.focus();
248
+ await sendKeys({ press: 'Enter' });
249
+ expect(component.open).to.be.true;
250
+ });
251
+ it('remains open when an option is selected via Space', async () => {
252
+ const component = await fixture(html `<glide-core-dropdown
253
+ label="Label"
254
+ placeholder="Placeholder"
255
+ open
256
+ multiple
257
+ >
258
+ <glide-core-dropdown-option
259
+ label="One"
260
+ value="one"
261
+ selected
262
+ ></glide-core-dropdown-option>
263
+
264
+ <glide-core-dropdown-option
265
+ label="Two"
266
+ value="two"
267
+ ></glide-core-dropdown-option>
268
+ </glide-core-dropdown>`);
269
+ const option = component.querySelector('glide-core-dropdown-option');
270
+ option?.focus();
271
+ await sendKeys({ press: ' ' });
272
+ expect(component.open).to.be.true;
273
+ });
274
+ it('activates Select All on "mouseover"', async () => {
275
+ const component = await fixture(html `<glide-core-dropdown open multiple select-all>
276
+ <glide-core-dropdown-option
277
+ label="One"
278
+ value="one"
279
+ ></glide-core-dropdown-option>
280
+
281
+ <glide-core-dropdown-option
282
+ label="Two"
283
+ value="two"
284
+ ></glide-core-dropdown-option>
285
+ </glide-core-dropdown>`);
286
+ const options = component.querySelectorAll('glide-core-dropdown-option');
287
+ options[0]?.dispatchEvent(new MouseEvent('mouseover', { bubbles: true }));
288
+ expect(options[0]?.privateActive).to.be.true;
289
+ });
290
+ it('does not activate the next option on ArrowDown when a tag is focused', async () => {
291
+ // This test only accounts for when ArrowDown is pressed. Other keys like
292
+ // ArrowUp and Home are left untested to avoid an additional seven or so
293
+ // tests. Only testing ArrowDown is hopefully sufficient.
294
+ const component = await fixture(html `<glide-core-dropdown
295
+ label="Label"
296
+ placeholder="Placeholder"
297
+ open
298
+ multiple
299
+ >
300
+ <glide-core-dropdown-option
301
+ label="One"
302
+ value="one"
303
+ selected
304
+ ></glide-core-dropdown-option>
305
+
306
+ <glide-core-dropdown-option
307
+ label="Two"
308
+ value="two"
309
+ ></glide-core-dropdown-option>
310
+ </glide-core-dropdown>`);
311
+ const options = component.querySelectorAll('glide-core-dropdown-option');
312
+ component.shadowRoot
313
+ ?.querySelector('[data-test="tag"]')
314
+ ?.focus();
315
+ await sendKeys({ press: 'ArrowDown' });
316
+ expect(options[0]?.privateActive).to.be.true;
317
+ });
318
+ it('selects and deselects options when `value` is changed programmatically', async () => {
319
+ const component = await fixture(html `<glide-core-dropdown label="Label" placeholder="Placeholder" multiple>
320
+ <glide-core-dropdown-option
321
+ label="One"
322
+ value="one"
323
+ selected
324
+ ></glide-core-dropdown-option>
325
+
326
+ <glide-core-dropdown-option
327
+ label="Two"
328
+ value="two"
329
+ ></glide-core-dropdown-option>
330
+
331
+ <glide-core-dropdown-option
332
+ label="Three"
333
+ value="three"
334
+ ></glide-core-dropdown-option>
335
+ </glide-core-dropdown>`);
336
+ component.value = ['two', 'three'];
337
+ const options = component.querySelectorAll('glide-core-dropdown-option');
338
+ expect(options[0].selected).to.be.false;
339
+ expect(options[1].selected).to.be.true;
340
+ expect(options[2].selected).to.be.true;
341
+ });
342
+ it('selects no options when `value` is changed programmatically to an empty string and some options have no `value`', async () => {
343
+ const component = await fixture(html `<glide-core-dropdown label="Label" placeholder="Placeholder" multiple>
344
+ <glide-core-dropdown-option label="One"></glide-core-dropdown-option>
345
+ <glide-core-dropdown-option label="Two"></glide-core-dropdown-option>
346
+
347
+ <glide-core-dropdown-option
348
+ label="Three"
349
+ value="three"
350
+ ></glide-core-dropdown-option>
351
+ </glide-core-dropdown>`);
352
+ component.value = [''];
353
+ const options = component.querySelectorAll('glide-core-dropdown-option');
354
+ expect(options[0].selected).to.be.false;
355
+ expect(options[1].selected).to.be.false;
356
+ expect(options[2].selected).to.be.false;
357
+ });
358
+ it('updates `value` when an option is selected or deselected via click', async () => {
359
+ const component = await fixture(html `<glide-core-dropdown
360
+ label="Label"
361
+ placeholder="Placeholder"
362
+ open
363
+ multiple
364
+ >
365
+ <glide-core-dropdown-option
366
+ label="One"
367
+ value="one"
368
+ selected
369
+ ></glide-core-dropdown-option>
370
+
371
+ <glide-core-dropdown-option
372
+ label="Two"
373
+ value="two"
374
+ ></glide-core-dropdown-option>
375
+
376
+ <glide-core-dropdown-option label="Three"></glide-core-dropdown-option>
377
+ </glide-core-dropdown>`);
378
+ const options = component.querySelectorAll('glide-core-dropdown-option');
379
+ options[1].click();
380
+ expect(component.value).to.deep.equal(['one', 'two']);
381
+ options[1].click();
382
+ expect(component.value).to.deep.equal(['one']);
383
+ options[2].click();
384
+ expect(component.value).to.deep.equal(['one']);
385
+ });
386
+ it('updates `value` when a option is selected or deselected via Enter', async () => {
387
+ const component = await fixture(html `<glide-core-dropdown open multiple>
388
+ <glide-core-dropdown-option
389
+ label="One"
390
+ value="one"
391
+ selected
392
+ ></glide-core-dropdown-option>
393
+
394
+ <glide-core-dropdown-option
395
+ label="Two"
396
+ value="two"
397
+ ></glide-core-dropdown-option>
398
+
399
+ <glide-core-dropdown-option label="Three"></glide-core-dropdown-option>
400
+ </glide-core-dropdown>`);
401
+ const options = component.querySelectorAll('glide-core-dropdown-option');
402
+ options[1].focus();
403
+ await sendKeys({ press: 'Enter' });
404
+ expect(component.value).to.deep.equal(['one', 'two']);
405
+ options[1].focus();
406
+ await sendKeys({ press: 'Enter' });
407
+ expect(component.value).to.deep.equal(['one']);
408
+ options[2].focus();
409
+ await sendKeys({ press: 'Enter' });
410
+ expect(component.value).to.deep.equal(['one']);
411
+ });
412
+ it('updates `value` when an option is selected or deselected via Space', async () => {
413
+ const component = await fixture(html `<glide-core-dropdown open multiple>
414
+ <glide-core-dropdown-option
415
+ label="One"
416
+ value="one"
417
+ selected
418
+ ></glide-core-dropdown-option>
419
+
420
+ <glide-core-dropdown-option
421
+ label="Two"
422
+ value="two"
423
+ ></glide-core-dropdown-option>
424
+
425
+ <glide-core-dropdown-option label="Three"></glide-core-dropdown-option>
426
+ </glide-core-dropdown>`);
427
+ const options = component.querySelectorAll('glide-core-dropdown-option');
428
+ options[1].focus();
429
+ await sendKeys({ press: ' ' });
430
+ expect(component.value).to.deep.equal(['one', 'two']);
431
+ options[1].focus();
432
+ await sendKeys({ press: ' ' });
433
+ expect(component.value).to.deep.equal(['one']);
434
+ options[2].focus();
435
+ await sendKeys({ press: ' ' });
436
+ expect(component.value).to.deep.equal(['one']);
437
+ });
438
+ it('updates `value` when `multiple` is changed to `true` programmatically', async () => {
439
+ const component = await fixture(html `<glide-core-dropdown open>
440
+ <glide-core-dropdown-option
441
+ label="One"
442
+ value="one"
443
+ ></glide-core-dropdown-option>
444
+
445
+ <glide-core-dropdown-option
446
+ label="Two"
447
+ value="two"
448
+ selected
449
+ ></glide-core-dropdown-option>
450
+ </glide-core-dropdown>`);
451
+ component.multiple = true;
452
+ const options = component.querySelectorAll('glide-core-dropdown-option');
453
+ expect(component.value).to.deep.equal(['two']);
454
+ expect(options[0].selected).to.be.false;
455
+ expect(options[1].selected).to.be.true;
456
+ await elementUpdated(options[1]);
457
+ const checkbox = options[1].shadowRoot?.querySelector('[data-test="checkbox"]');
458
+ expect(checkbox?.checked).to.be.true;
459
+ });
460
+ it('updates `value` when the `value` of a selected option is changed programmatically', async () => {
461
+ const component = await fixture(html `<glide-core-dropdown open multiple>
462
+ <glide-core-dropdown-option
463
+ label="One"
464
+ value="one"
465
+ selected
466
+ ></glide-core-dropdown-option>
467
+
468
+ <glide-core-dropdown-option
469
+ label="Two"
470
+ value="two"
471
+ selected
472
+ ></glide-core-dropdown-option>
473
+ </glide-core-dropdown>`);
474
+ const option = component.querySelector('glide-core-dropdown-option');
475
+ assert(option);
476
+ option.value = 'three';
477
+ expect(component.value).to.deep.equal(['two', 'three']);
478
+ });
479
+ it('updates `value` when the `value` of a selected option is removed programmatically', async () => {
480
+ const component = await fixture(html `<glide-core-dropdown open multiple>
481
+ <glide-core-dropdown-option
482
+ label="One"
483
+ value="one"
484
+ selected
485
+ ></glide-core-dropdown-option>
486
+
487
+ <glide-core-dropdown-option
488
+ label="Two"
489
+ value="two"
490
+ selected
491
+ ></glide-core-dropdown-option>
492
+ </glide-core-dropdown>`);
493
+ const option = component.querySelector('glide-core-dropdown-option');
494
+ assert(option);
495
+ option.value = '';
496
+ expect(component.value).to.deep.equal(['two']);
497
+ });
498
+ it('has no internal label when an option is newly selected', async () => {
499
+ const component = await fixture(html `<glide-core-dropdown
500
+ label="Label"
501
+ placeholder="Placeholder"
502
+ open
503
+ multiple
504
+ >
505
+ <glide-core-dropdown-option
506
+ label="One"
507
+ value="one"
508
+ ></glide-core-dropdown-option>
509
+
510
+ <glide-core-dropdown-option
511
+ label="Two"
512
+ value="two"
513
+ ></glide-core-dropdown-option>
514
+ </glide-core-dropdown>`);
515
+ component
516
+ .querySelector('glide-core-dropdown-option:last-of-type')
517
+ ?.click();
518
+ await elementUpdated(component);
519
+ const label = component.shadowRoot?.querySelector('[data-test="internal-label"]');
520
+ expect(label).to.not.exist;
521
+ });
522
+ it('only has so many tags when many options are selected', async () => {
523
+ const component = await fixture(html `<glide-core-dropdown label="Label" placeholder="Placeholder" multiple>
524
+ <glide-core-dropdown-option
525
+ label="One"
526
+ value="one"
527
+ ></glide-core-dropdown-option>
528
+
529
+ <glide-core-dropdown-option
530
+ label="Two"
531
+ value="two"
532
+ ></glide-core-dropdown-option>
533
+
534
+ <glide-core-dropdown-option
535
+ label="Three"
536
+ value="three"
537
+ ></glide-core-dropdown-option>
538
+
539
+ <glide-core-dropdown-option
540
+ label="Four"
541
+ value="four"
542
+ ></glide-core-dropdown-option>
543
+ </glide-core-dropdown>`);
544
+ const options = component.querySelectorAll('glide-core-dropdown-option');
545
+ options[0].selected = true;
546
+ options[1].selected = true;
547
+ options[2].selected = true;
548
+ options[3].selected = true;
549
+ await elementUpdated(component);
550
+ const tagContainers = [
551
+ ...(component.shadowRoot?.querySelectorAll('[data-test="tag-container"]') ?? []),
552
+ ].filter((element) => element.checkVisibility());
553
+ expect(tagContainers?.length).to.equal(3);
554
+ });
555
+ it('has overflow text when many options are selected', async () => {
556
+ const component = await fixture(html `<glide-core-dropdown label="Label" placeholder="Placeholder" multiple>
557
+ <glide-core-dropdown-option
558
+ label="One"
559
+ value="one"
560
+ ></glide-core-dropdown-option>
561
+
562
+ <glide-core-dropdown-option
563
+ label="Two"
564
+ value="two"
565
+ ></glide-core-dropdown-option>
566
+
567
+ <glide-core-dropdown-option
568
+ label="Three"
569
+ value="three"
570
+ ></glide-core-dropdown-option>
571
+
572
+ <glide-core-dropdown-option
573
+ label="Four"
574
+ value="four"
575
+ ></glide-core-dropdown-option>
576
+ </glide-core-dropdown>`);
577
+ const options = component.querySelectorAll('glide-core-dropdown-option');
578
+ options[0].selected = true;
579
+ options[1].selected = true;
580
+ options[2].selected = true;
581
+ options[3].selected = true;
582
+ await elementUpdated(component);
583
+ const tagOverflow = component.shadowRoot?.querySelector('[data-test="tag-overflow-count"]');
584
+ expect(tagOverflow?.textContent?.trim()).to.equal('1');
585
+ });
586
+ it('deselects the option when its tag is removed', async () => {
587
+ const component = await fixture(html `<glide-core-dropdown
588
+ label="Label"
589
+ placeholder="Placeholder"
590
+ open
591
+ multiple
592
+ >
593
+ <glide-core-dropdown-option
594
+ label="One"
595
+ value="one"
596
+ selected
597
+ ></glide-core-dropdown-option>
598
+
599
+ <glide-core-dropdown-option
600
+ label="Two"
601
+ value="two"
602
+ ></glide-core-dropdown-option>
603
+ </glide-core-dropdown>`);
604
+ component.shadowRoot
605
+ ?.querySelector('[data-test="tag"]')
606
+ ?.click();
607
+ const option = component.querySelector('glide-core-dropdown-option');
608
+ expect(option?.selected).to.be.false;
609
+ });
610
+ it('deselects all but the last selected option when `multiple` is changed to `false` programmatically', async () => {
611
+ const component = await fixture(html `<glide-core-dropdown open multiple>
612
+ <glide-core-dropdown-option
613
+ label="One"
614
+ value="one"
615
+ selected
616
+ ></glide-core-dropdown-option>
617
+
618
+ <glide-core-dropdown-option
619
+ label="Two"
620
+ value="two"
621
+ selected
622
+ ></glide-core-dropdown-option>
623
+ </glide-core-dropdown>`);
624
+ component.multiple = false;
625
+ const options = component.querySelectorAll('glide-core-dropdown-option');
626
+ expect(options[0].selected).be.false;
627
+ expect(options[1].selected).be.true;
628
+ });
629
+ it('selects all options when none are selected and Select All is clicked', async () => {
630
+ const component = await fixture(html `<glide-core-dropdown
631
+ label="Label"
632
+ placeholder="Placeholder"
633
+ multiple
634
+ select-all
635
+ >
636
+ <glide-core-dropdown-option
637
+ label="One"
638
+ value="one"
639
+ ></glide-core-dropdown-option>
640
+
641
+ <glide-core-dropdown-option
642
+ label="Two"
643
+ value="two"
644
+ ></glide-core-dropdown-option>
645
+ </glide-core-dropdown>`);
646
+ component.shadowRoot
647
+ ?.querySelector('[data-test="select-all"]')
648
+ ?.click();
649
+ const options = component.querySelectorAll('glide-core-dropdown-option');
650
+ expect(options[0].selected).to.be.true;
651
+ expect(options[1].selected).to.be.true;
652
+ });
653
+ it('selects all options when some are selected and Select All is clicked', async () => {
654
+ const component = await fixture(html `<glide-core-dropdown
655
+ label="Label"
656
+ placeholder="Placeholder"
657
+ multiple
658
+ select-all
659
+ >
660
+ <glide-core-dropdown-option
661
+ label="One"
662
+ value="one"
663
+ selected
664
+ ></glide-core-dropdown-option>
665
+
666
+ <glide-core-dropdown-option
667
+ label="Two"
668
+ value="two"
669
+ ></glide-core-dropdown-option>
670
+ </glide-core-dropdown>`);
671
+ component.shadowRoot
672
+ ?.querySelector('[data-test="select-all"]')
673
+ ?.click();
674
+ const options = component.querySelectorAll('glide-core-dropdown-option');
675
+ expect(options[0].selected).to.be.true;
676
+ expect(options[1].selected).to.be.true;
677
+ });
678
+ it('deelects all options when all are selected and Select All is clicked', async () => {
679
+ const component = await fixture(html `<glide-core-dropdown
680
+ label="Label"
681
+ placeholder="Placeholder"
682
+ multiple
683
+ select-all
684
+ >
685
+ <glide-core-dropdown-option
686
+ label="One"
687
+ value="one"
688
+ selected
689
+ ></glide-core-dropdown-option>
690
+
691
+ <glide-core-dropdown-option
692
+ label="Two"
693
+ value="two"
694
+ selected
695
+ ></glide-core-dropdown-option>
696
+ </glide-core-dropdown>`);
697
+ component.shadowRoot
698
+ ?.querySelector('[data-test="select-all"]')
699
+ ?.click();
700
+ const options = component.querySelectorAll('glide-core-dropdown-option');
701
+ expect(options[0].selected).to.be.false;
702
+ expect(options[1].selected).to.be.false;
703
+ });
704
+ it('shows Select All', async () => {
705
+ const component = await fixture(html `<glide-core-dropdown label="Label" placeholder="Placeholder" multiple>
706
+ <glide-core-dropdown-option
707
+ label="One"
708
+ value="one"
709
+ selected
710
+ ></glide-core-dropdown-option>
711
+
712
+ <glide-core-dropdown-option
713
+ label="Two"
714
+ value="two"
715
+ ></glide-core-dropdown-option>
716
+ </glide-core-dropdown>`);
717
+ component.selectAll = true;
718
+ await elementUpdated(component);
719
+ const selectAll = component.shadowRoot?.querySelector('[data-test="select-all"]');
720
+ expect(selectAll?.checkVisibility()).to.be.true;
721
+ });
722
+ it('sets Select All as selected when all options are selected', async () => {
723
+ const component = await fixture(html `<glide-core-dropdown
724
+ label="Label"
725
+ placeholder="Placeholder"
726
+ multiple
727
+ select-all
728
+ >
729
+ <glide-core-dropdown-option
730
+ label="One"
731
+ value="one"
732
+ ></glide-core-dropdown-option>
733
+
734
+ <glide-core-dropdown-option
735
+ label="Two"
736
+ value="two"
737
+ ></glide-core-dropdown-option>
738
+ </glide-core-dropdown>`);
739
+ const options = component.querySelectorAll('glide-core-dropdown-option');
740
+ options[0].click();
741
+ options[1].click();
742
+ const selectAll = component.shadowRoot?.querySelector('[data-test="select-all"]');
743
+ expect(selectAll?.selected).to.be.true;
744
+ });
745
+ it('sets Select All as deselected when no options are selected', async () => {
746
+ const component = await fixture(html `<glide-core-dropdown
747
+ label="Label"
748
+ placeholder="Placeholder"
749
+ multiple
750
+ select-all
751
+ >
752
+ <glide-core-dropdown-option
753
+ label="One"
754
+ value="one"
755
+ ></glide-core-dropdown-option>
756
+
757
+ <glide-core-dropdown-option
758
+ label="Two"
759
+ value="two"
760
+ ></glide-core-dropdown-option>
761
+ </glide-core-dropdown>`);
762
+ const options = component.querySelectorAll('glide-core-dropdown-option');
763
+ options[0].click();
764
+ options[1].click();
765
+ options[0].click();
766
+ options[1].click();
767
+ const selectAll = component.shadowRoot?.querySelector('[data-test="select-all"]');
768
+ expect(selectAll?.selected).to.be.false;
769
+ });
770
+ it('sets Select All as indeterminate when not all options are selected', async () => {
771
+ const component = await fixture(html `<glide-core-dropdown
772
+ label="Label"
773
+ placeholder="Placeholder"
774
+ multiple
775
+ select-all
776
+ >
777
+ <glide-core-dropdown-option
778
+ label="One"
779
+ value="one"
780
+ ></glide-core-dropdown-option>
781
+
782
+ <glide-core-dropdown-option
783
+ label="Two"
784
+ value="two"
785
+ ></glide-core-dropdown-option>
786
+ </glide-core-dropdown>`);
787
+ const options = component.querySelectorAll('glide-core-dropdown-option');
788
+ options[0].click();
789
+ const selectAll = component.shadowRoot?.querySelector('[data-test="select-all"]');
790
+ expect(selectAll?.privateIndeterminate).to.be.true;
791
+ });
792
+ it('does not set Select All as indeterminate when no options are selected', async () => {
793
+ const component = await fixture(html `<glide-core-dropdown
794
+ label="Label"
795
+ placeholder="Placeholder"
796
+ multiple
797
+ select-all
798
+ >
799
+ <glide-core-dropdown-option
800
+ label="One"
801
+ value="one"
802
+ ></glide-core-dropdown-option>
803
+
804
+ <glide-core-dropdown-option
805
+ label="Two"
806
+ value="two"
807
+ ></glide-core-dropdown-option>
808
+ </glide-core-dropdown>`);
809
+ const options = component.querySelectorAll('glide-core-dropdown-option');
810
+ options[0].click();
811
+ options[0].click();
812
+ const selectAll = component.shadowRoot?.querySelector('[data-test="select-all"]');
813
+ expect(selectAll?.privateIndeterminate).to.be.false;
814
+ });
815
+ it('does not set Select All as indeterminate when all options are selected', async () => {
816
+ const component = await fixture(html `<glide-core-dropdown
817
+ label="Label"
818
+ placeholder="Placeholder"
819
+ multiple
820
+ select-all
821
+ >
822
+ <glide-core-dropdown-option
823
+ label="One"
824
+ value="one"
825
+ ></glide-core-dropdown-option>
826
+
827
+ <glide-core-dropdown-option
828
+ label="Two"
829
+ value="two"
830
+ ></glide-core-dropdown-option>
831
+ </glide-core-dropdown>`);
832
+ const options = component.querySelectorAll('glide-core-dropdown-option');
833
+ options[0].click();
834
+ options[1].click();
835
+ const selectAll = component.shadowRoot?.querySelector('[data-test="select-all"]');
836
+ expect(selectAll?.privateIndeterminate).to.be.false;
837
+ });
838
+ it('remains open when a tag is clicked', async () => {
839
+ const component = await fixture(html `<glide-core-dropdown open multiple>
840
+ <glide-core-dropdown-option
841
+ label="One"
842
+ value="one"
843
+ selected
844
+ ></glide-core-dropdown-option>
845
+
846
+ <glide-core-dropdown-option
847
+ label="Two"
848
+ value="two"
849
+ ></glide-core-dropdown-option>
850
+ </glide-core-dropdown>`);
851
+ const tag = component.shadowRoot?.querySelector('[data-test="tag"]');
852
+ assert(tag);
853
+ const { x, y } = tag.getBoundingClientRect();
854
+ // A simple `tag.click()` won't do because it would remove the tag. We want to
855
+ // click elsewhere on the tag so focus is moved to `document.body`. This ensures
856
+ // Dropdown's "focusout" handler doesn't cause Dropdown to close.
857
+ await sendMouse({
858
+ type: 'click',
859
+ position: [Math.ceil(x), Math.ceil(y)],
860
+ });
861
+ await elementUpdated(component);
862
+ expect(component.open).to.be.true;
863
+ });
864
+ it('does not select an option on Enter when the option is not focused', async () => {
865
+ const component = await fixture(html `<glide-core-dropdown
866
+ label="Label"
867
+ placeholder="Placeholder"
868
+ open
869
+ multiple
870
+ >
871
+ <glide-core-dropdown-option
872
+ label="One"
873
+ value="one"
874
+ ></glide-core-dropdown-option>
875
+
876
+ <glide-core-dropdown-option
877
+ label="Two"
878
+ value="two"
879
+ ></glide-core-dropdown-option>
880
+ </glide-core-dropdown>`);
881
+ const option = component.querySelector('glide-core-dropdown-option');
882
+ option?.focus();
883
+ await sendKeys({ down: 'Tab' });
884
+ await sendKeys({ down: 'Shift' });
885
+ await sendKeys({ up: 'Tab' });
886
+ await sendKeys({ press: 'Enter' });
887
+ expect(option?.selected).to.be.false;
888
+ });
889
+ it('cannot be tabbed to when `disabled`', async () => {
890
+ await fixture(html `<glide-core-dropdown
891
+ label="Label"
892
+ placeholder="Placeholder"
893
+ disabled
894
+ multiple
895
+ >
896
+ <glide-core-dropdown-option
897
+ label="One"
898
+ value="one"
899
+ ></glide-core-dropdown-option>
900
+
901
+ <glide-core-dropdown-option
902
+ label="Two"
903
+ value="two"
904
+ ></glide-core-dropdown-option>
905
+ </glide-core-dropdown>`);
906
+ await sendKeys({ down: 'Tab' });
907
+ expect(document.activeElement).to.equal(document.body);
908
+ });