@crowdstrike/glide-core 0.9.5 → 0.10.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.
- package/README.md +17 -53
- package/dist/accordion.d.ts +10 -10
- package/dist/accordion.js +1 -1
- package/dist/accordion.stories.d.ts +0 -1
- package/dist/accordion.styles.js +36 -38
- package/dist/accordion.test.basics.js +13 -95
- package/dist/accordion.test.events.js +21 -33
- package/dist/accordion.test.focus.d.ts +1 -0
- package/dist/accordion.test.focus.js +11 -0
- package/dist/accordion.test.interactions.d.ts +1 -0
- package/dist/accordion.test.interactions.js +75 -0
- package/dist/button-group.button.d.ts +2 -4
- package/dist/button-group.button.js +1 -1
- package/dist/button-group.button.styles.js +6 -14
- package/dist/button-group.button.test.basics.js +8 -17
- package/dist/button-group.button.test.interactions.js +4 -4
- package/dist/button-group.d.ts +0 -2
- package/dist/button-group.test.basics.js +10 -10
- package/dist/button-group.test.events.js +2 -2
- package/dist/button-group.test.interactions.js +1 -1
- package/dist/button.d.ts +7 -10
- package/dist/button.js +1 -1
- package/dist/button.styles.js +4 -7
- package/dist/button.test.basics.js +10 -26
- package/dist/button.test.events.js +9 -9
- package/dist/checkbox-group.d.ts +3 -4
- package/dist/checkbox-group.js +1 -1
- package/dist/checkbox-group.styles.js +13 -1
- package/dist/checkbox-group.test.basics.js +8 -12
- package/dist/checkbox-group.test.focus.js +7 -7
- package/dist/checkbox-group.test.interactions.d.ts +1 -0
- package/dist/checkbox-group.test.interactions.js +82 -0
- package/dist/checkbox.d.ts +5 -4
- package/dist/checkbox.js +1 -1
- package/dist/checkbox.styles.js +35 -15
- package/dist/checkbox.test.basics.js +6 -15
- package/dist/checkbox.test.focus.js +4 -2
- package/dist/checkbox.test.interactions.js +11 -11
- package/dist/drawer.d.ts +2 -5
- package/dist/drawer.js +1 -1
- package/dist/drawer.test.accessibility.js +8 -8
- package/dist/drawer.test.basics.js +16 -16
- package/dist/drawer.test.closing.js +18 -16
- package/dist/drawer.test.events.js +13 -24
- package/dist/drawer.test.methods.js +22 -22
- package/dist/dropdown.d.ts +7 -5
- package/dist/dropdown.js +1 -1
- package/dist/dropdown.option.d.ts +1 -3
- package/dist/dropdown.option.js +1 -1
- package/dist/dropdown.option.styles.js +31 -19
- package/dist/dropdown.option.test.basics.js +4 -4
- package/dist/dropdown.styles.js +39 -3
- package/dist/dropdown.test.basics.js +8 -13
- package/dist/dropdown.test.basics.multiple.js +63 -31
- package/dist/dropdown.test.basics.single.js +49 -0
- package/dist/dropdown.test.focus.filterable.js +12 -3
- package/dist/dropdown.test.focus.js +18 -2
- package/dist/dropdown.test.interactions.filterable.js +121 -45
- package/dist/dropdown.test.interactions.multiple.js +71 -30
- package/dist/dropdown.test.interactions.single.js +26 -4
- package/dist/form-controls-layout.d.ts +0 -2
- package/dist/icon-button.d.ts +2 -4
- package/dist/icon-button.js +1 -1
- package/dist/icon-button.test.basics.js +14 -82
- package/dist/icon-button.test.focus.d.ts +1 -0
- package/dist/icon-button.test.focus.js +13 -0
- package/dist/input.d.ts +4 -5
- package/dist/input.js +1 -1
- package/dist/input.styles.js +4 -4
- package/dist/input.test.basics.js +0 -52
- package/dist/input.test.events.js +27 -27
- package/dist/input.test.focus.js +27 -26
- package/dist/input.test.form.js +6 -6
- package/dist/input.test.validity.js +130 -130
- package/dist/label.d.ts +1 -3
- package/dist/label.js +1 -1
- package/dist/label.styles.js +5 -6
- package/dist/label.test.basics.js +4 -4
- package/dist/library/ow.js +1 -1
- package/dist/menu.button.d.ts +0 -2
- package/dist/menu.button.test.basics.js +3 -3
- package/dist/menu.d.ts +1 -4
- package/dist/menu.js +1 -1
- package/dist/menu.link.d.ts +1 -2
- package/dist/menu.link.js +1 -1
- package/dist/menu.options.d.ts +0 -2
- package/dist/menu.test.events.js +6 -6
- package/dist/menu.test.focus.js +5 -18
- package/dist/menu.test.interactions.js +48 -24
- package/dist/modal.d.ts +6 -17
- package/dist/modal.icon-button.d.ts +0 -2
- package/dist/modal.icon-button.test.basics.js +3 -3
- package/dist/modal.js +1 -1
- package/dist/modal.styles.js +13 -19
- package/dist/modal.tertiary-icon.d.ts +0 -3
- package/dist/modal.tertiary-icon.test.basics.js +3 -3
- package/dist/modal.test.basics.js +9 -5
- package/dist/modal.test.close.js +2 -2
- package/dist/modal.test.events.js +2 -2
- package/dist/radio-group.d.ts +0 -3
- package/dist/radio-group.js +1 -1
- package/dist/radio-group.test.basics.js +61 -61
- package/dist/radio-group.test.events.js +13 -13
- package/dist/radio-group.test.focus.js +1 -1
- package/dist/radio-group.test.form.js +2 -2
- package/dist/radio-group.test.validity.js +12 -12
- package/dist/radio.d.ts +0 -3
- package/dist/radio.styles.js +4 -12
- package/dist/split-button.d.ts +8 -11
- package/dist/split-button.js +1 -1
- package/dist/split-button.primary-button.d.ts +21 -0
- package/dist/split-button.primary-button.js +1 -0
- package/dist/split-button.primary-button.styles.js +96 -0
- package/dist/split-button.primary-button.test.basics.d.ts +1 -0
- package/dist/split-button.primary-button.test.basics.js +31 -0
- package/dist/split-button.primary-button.test.focus.d.ts +1 -0
- package/dist/split-button.primary-button.test.focus.js +14 -0
- package/dist/split-button.primary-link.d.ts +19 -0
- package/dist/split-button.primary-link.js +1 -0
- package/dist/split-button.primary-link.test.basics.d.ts +1 -0
- package/dist/split-button.primary-link.test.basics.js +30 -0
- package/dist/split-button.primary-link.test.focus.d.ts +1 -0
- package/dist/split-button.primary-link.test.focus.js +15 -0
- package/dist/split-button.secondary-button.d.ts +25 -0
- package/dist/split-button.secondary-button.js +1 -0
- package/dist/split-button.secondary-button.styles.js +103 -0
- package/dist/split-button.secondary-button.test.basics.d.ts +1 -0
- package/dist/split-button.secondary-button.test.basics.js +58 -0
- package/dist/split-button.secondary-button.test.focus.d.ts +1 -0
- package/dist/split-button.secondary-button.test.focus.js +14 -0
- package/dist/split-button.secondary-button.test.interactions.d.ts +2 -0
- package/dist/split-button.secondary-button.test.interactions.js +30 -0
- package/dist/split-button.stories.d.ts +4 -3
- package/dist/split-button.styles.js +1 -94
- package/dist/split-button.test.basics.d.ts +2 -1
- package/dist/split-button.test.basics.js +67 -80
- package/dist/split-button.test.interactions.d.ts +4 -0
- package/dist/split-button.test.interactions.js +51 -0
- package/dist/styles/opacity-and-scale-animation.js +2 -6
- package/dist/styles/variables.css +1 -1
- package/dist/tab.d.ts +2 -11
- package/dist/tab.group.d.ts +2 -5
- package/dist/tab.group.styles.js +12 -15
- package/dist/tab.group.test.basics.js +49 -34
- package/dist/tab.group.test.interactions.js +17 -14
- package/dist/tab.panel.d.ts +0 -3
- package/dist/tab.test.basics.js +6 -5
- package/dist/tag.d.ts +6 -4
- package/dist/tag.js +1 -1
- package/dist/tag.styles.js +36 -36
- package/dist/tag.test.basics.js +16 -109
- package/dist/tag.test.events.js +12 -8
- package/dist/tag.test.focus.js +2 -3
- package/dist/tag.test.interactions.d.ts +1 -0
- package/dist/tag.test.interactions.js +34 -0
- package/dist/textarea.d.ts +2 -3
- package/dist/textarea.js +2 -2
- package/dist/textarea.test.basics.js +8 -8
- package/dist/textarea.test.events.js +55 -55
- package/dist/textarea.test.form.js +9 -9
- package/dist/textarea.test.validity.js +167 -135
- package/dist/toasts.d.ts +1 -5
- package/dist/toasts.test.basics.js +2 -1
- package/dist/toasts.toast.d.ts +1 -4
- package/dist/toasts.toast.js +1 -1
- package/dist/toasts.toast.styles.js +12 -0
- package/dist/toggle.d.ts +0 -2
- package/dist/toggle.styles.js +1 -5
- package/dist/toggle.test.basics.js +2 -2
- package/dist/toggle.test.interactions.js +7 -7
- package/dist/tooltip.d.ts +2 -1
- package/dist/tooltip.js +1 -1
- package/dist/tooltip.styles.js +37 -14
- package/dist/tooltip.test.basics.d.ts +1 -1
- package/dist/tooltip.test.basics.js +19 -19
- package/dist/tree.d.ts +0 -2
- package/dist/tree.item.d.ts +5 -7
- package/dist/tree.item.icon-button.d.ts +1 -4
- package/dist/tree.item.js +1 -1
- package/dist/tree.item.menu.d.ts +0 -2
- package/dist/tree.item.menu.test.basics.js +9 -9
- package/dist/tree.item.styles.js +4 -3
- package/dist/tree.item.test.basics.js +43 -31
- package/dist/tree.test.basics.js +29 -29
- package/dist/tree.test.focus.js +77 -74
- package/package.json +12 -14
- package/dist/split-container.d.ts +0 -31
- package/dist/split-container.js +0 -1
- package/dist/split-container.styles.js +0 -132
- package/dist/split-container.test.basics.d.ts +0 -3
- package/dist/split-container.test.basics.js +0 -445
- package/dist/split-container.test.interactions.d.ts +0 -1
- package/dist/split-container.test.interactions.js +0 -20
- package/dist/split-link.d.ts +0 -25
- package/dist/split-link.js +0 -1
- package/dist/split-link.test.basics.d.ts +0 -1
- package/dist/split-link.test.basics.js +0 -93
- package/dist/split-link.test.interactions.d.ts +0 -1
- package/dist/split-link.test.interactions.js +0 -20
- package/dist/status-indicator.d.ts +0 -30
- package/dist/status-indicator.js +0 -1
- package/dist/status-indicator.stories.d.ts +0 -5
- package/dist/status-indicator.styles.js +0 -58
- package/dist/status-indicator.test.basics.d.ts +0 -1
- package/dist/status-indicator.test.basics.js +0 -102
- /package/dist/{split-container.styles.d.ts → split-button.primary-button.styles.d.ts} +0 -0
- /package/dist/{status-indicator.styles.d.ts → split-button.secondary-button.styles.d.ts} +0 -0
@@ -75,37 +75,6 @@ it('has a tag when an option is initially selected', async () => {
|
|
75
75
|
expect(tag?.checkVisibility()).to.be.true;
|
76
76
|
expect(tag?.textContent?.trim()).to.equal('One');
|
77
77
|
});
|
78
|
-
it('only has so many tags when many options are initially selected', async () => {
|
79
|
-
const component = await fixture(html `<glide-core-dropdown label="Label" placeholder="Placeholder" multiple>
|
80
|
-
<glide-core-dropdown-option
|
81
|
-
label="One"
|
82
|
-
value="one"
|
83
|
-
selected
|
84
|
-
></glide-core-dropdown-option>
|
85
|
-
|
86
|
-
<glide-core-dropdown-option
|
87
|
-
label="Two"
|
88
|
-
value="two"
|
89
|
-
selected
|
90
|
-
></glide-core-dropdown-option>
|
91
|
-
|
92
|
-
<glide-core-dropdown-option
|
93
|
-
label="Three"
|
94
|
-
value="three"
|
95
|
-
selected
|
96
|
-
></glide-core-dropdown-option>
|
97
|
-
|
98
|
-
<glide-core-dropdown-option
|
99
|
-
label="Four"
|
100
|
-
value="four"
|
101
|
-
selected
|
102
|
-
></glide-core-dropdown-option>
|
103
|
-
</glide-core-dropdown>`);
|
104
|
-
const tagContainers = [
|
105
|
-
...(component.shadowRoot?.querySelectorAll('[data-test="tag-container"]') ?? []),
|
106
|
-
].filter((element) => element.checkVisibility());
|
107
|
-
expect(tagContainers?.length).to.equal(3);
|
108
|
-
});
|
109
78
|
it('shows Select All', async () => {
|
110
79
|
const component = await fixture(html `<glide-core-dropdown
|
111
80
|
label="Label"
|
@@ -271,3 +240,66 @@ it('has no internal label when an option is initially selected', async () => {
|
|
271
240
|
const label = component.shadowRoot?.querySelector('[data-test="internal-label"]');
|
272
241
|
expect(label).to.not.exist;
|
273
242
|
});
|
243
|
+
it('has a "multiselect" icon for each selected option with a value', async () => {
|
244
|
+
const component = await fixture(html `<glide-core-dropdown label="Label" placeholder="Placeholder" multiple>
|
245
|
+
<div slot="icon:one">✓</div>
|
246
|
+
<div slot="icon:two">✓</div>
|
247
|
+
<div slot="icon:three">✓</div>
|
248
|
+
|
249
|
+
<glide-core-dropdown-option
|
250
|
+
label="One"
|
251
|
+
value="one"
|
252
|
+
selected
|
253
|
+
></glide-core-dropdown-option>
|
254
|
+
|
255
|
+
<glide-core-dropdown-option
|
256
|
+
label="Two"
|
257
|
+
value="two"
|
258
|
+
selected
|
259
|
+
></glide-core-dropdown-option>
|
260
|
+
|
261
|
+
<glide-core-dropdown-option
|
262
|
+
label="Three"
|
263
|
+
selected
|
264
|
+
></glide-core-dropdown-option>
|
265
|
+
</glide-core-dropdown>`);
|
266
|
+
const icons = component.shadowRoot?.querySelectorAll('[data-test="multiselect-icon-slot"]');
|
267
|
+
expect(icons?.length).to.equal(2);
|
268
|
+
});
|
269
|
+
it('has no "multiselect" icons', async () => {
|
270
|
+
const component = await fixture(html `<glide-core-dropdown label="Label" placeholder="Placeholder" multiple>
|
271
|
+
<div slot="icon:one">✓</div>
|
272
|
+
<div slot="icon:two">✓</div>
|
273
|
+
|
274
|
+
<glide-core-dropdown-option
|
275
|
+
label="One"
|
276
|
+
value="one"
|
277
|
+
></glide-core-dropdown-option>
|
278
|
+
|
279
|
+
<glide-core-dropdown-option
|
280
|
+
label="Two"
|
281
|
+
value="two"
|
282
|
+
></glide-core-dropdown-option>
|
283
|
+
</glide-core-dropdown>`);
|
284
|
+
const icons = component.shadowRoot?.querySelectorAll('[data-test="multiselect-icon-slot"]');
|
285
|
+
expect(icons?.length).to.equal(0);
|
286
|
+
});
|
287
|
+
it('has no "single-select" icon', async () => {
|
288
|
+
const component = await fixture(html `<glide-core-dropdown label="Label" placeholder="Placeholder" multiple>
|
289
|
+
<div slot="icon:one">✓</div>
|
290
|
+
<div slot="icon:two">✓</div>
|
291
|
+
|
292
|
+
<glide-core-dropdown-option
|
293
|
+
label="One"
|
294
|
+
value="one"
|
295
|
+
selected
|
296
|
+
></glide-core-dropdown-option>
|
297
|
+
|
298
|
+
<glide-core-dropdown-option
|
299
|
+
label="Two"
|
300
|
+
value="two"
|
301
|
+
></glide-core-dropdown-option>
|
302
|
+
</glide-core-dropdown>`);
|
303
|
+
const iconSlot = component.shadowRoot?.querySelector('[data-test="single-select-icon-slot"]');
|
304
|
+
expect(iconSlot).to.be.null;
|
305
|
+
});
|
@@ -77,3 +77,52 @@ it('hides Select All', async () => {
|
|
77
77
|
const selectAll = component.shadowRoot?.querySelector('[data-test="select-all"]');
|
78
78
|
expect(selectAll?.checkVisibility()).to.not.be.ok;
|
79
79
|
});
|
80
|
+
it('has an icon when an option with a value is selected', async () => {
|
81
|
+
const component = await fixture(html `<glide-core-dropdown label="Label" placeholder="Placeholder">
|
82
|
+
<div slot="icon:one">✓</div>
|
83
|
+
<div slot="icon:two">✓</div>
|
84
|
+
|
85
|
+
<glide-core-dropdown-option label="One" value="one" selected>
|
86
|
+
<div slot="icon">✓</div>
|
87
|
+
</glide-core-dropdown-option>
|
88
|
+
|
89
|
+
<glide-core-dropdown-option label="Two" value="two">
|
90
|
+
<div slot="icon">✓</div>
|
91
|
+
</glide-core-dropdown-option>
|
92
|
+
</glide-core-dropdown>`);
|
93
|
+
const iconSlot = component.shadowRoot?.querySelector('[data-test="single-select-icon-slot"]');
|
94
|
+
expect(iconSlot instanceof HTMLSlotElement).to.be.true;
|
95
|
+
expect(iconSlot?.assignedElements().at(0)?.slot).to.equal('icon:one');
|
96
|
+
});
|
97
|
+
it('has no icon when an option without a value is selected', async () => {
|
98
|
+
const component = await fixture(html `<glide-core-dropdown label="Label" placeholder="Placeholder">
|
99
|
+
<div slot="icon:one">✓</div>
|
100
|
+
<div slot="icon:two">✓</div>
|
101
|
+
|
102
|
+
<glide-core-dropdown-option label="One" selected>
|
103
|
+
<div slot="icon">✓</div>
|
104
|
+
</glide-core-dropdown-option>
|
105
|
+
|
106
|
+
<glide-core-dropdown-option label="Two" value="two">
|
107
|
+
<div slot="icon">✓</div>
|
108
|
+
</glide-core-dropdown-option>
|
109
|
+
</glide-core-dropdown>`);
|
110
|
+
const iconSlot = component.shadowRoot?.querySelector('[data-test="single-select-icon-slot"]');
|
111
|
+
expect(iconSlot).to.be.null;
|
112
|
+
});
|
113
|
+
it('has no icon when no option is selected', async () => {
|
114
|
+
const component = await fixture(html `<glide-core-dropdown label="Label" placeholder="Placeholder">
|
115
|
+
<div slot="icon:one">✓</div>
|
116
|
+
<div slot="icon:two">✓</div>
|
117
|
+
|
118
|
+
<glide-core-dropdown-option label="One" value="one">
|
119
|
+
<div slot="icon">✓</div>
|
120
|
+
</glide-core-dropdown-option>
|
121
|
+
|
122
|
+
<glide-core-dropdown-option label="Two" value="two">
|
123
|
+
<div slot="icon">✓</div>
|
124
|
+
</glide-core-dropdown-option>
|
125
|
+
</glide-core-dropdown>`);
|
126
|
+
const iconSlot = component.shadowRoot?.querySelector('[data-test="single-select-icon-slot"]');
|
127
|
+
expect(iconSlot).to.be.null;
|
128
|
+
});
|
@@ -158,8 +158,7 @@ it('does not focus the input when `checkValidity` is called', async () => {
|
|
158
158
|
component.checkValidity();
|
159
159
|
expect(component.shadowRoot?.activeElement).to.equal(null);
|
160
160
|
});
|
161
|
-
it('sets the `value` of
|
162
|
-
document.body.tabIndex = -1;
|
161
|
+
it('sets the `value` of its `<input>` to the selected option when focus is lost', async () => {
|
163
162
|
const component = await fixture(html `<glide-core-dropdown label="Label" placeholder="Placeholder" open>
|
164
163
|
${defaultSlot}
|
165
164
|
</glide-core-dropdown>`);
|
@@ -172,7 +171,17 @@ it('sets the `value` of the `<input>` to the selected option when focus is lost'
|
|
172
171
|
// back to "One" when focus is lost.
|
173
172
|
component.focus();
|
174
173
|
await sendKeys({ type: 'o' });
|
175
|
-
|
174
|
+
component.blur();
|
176
175
|
const input = component.shadowRoot?.querySelector('[data-test="input"]');
|
177
176
|
expect(input?.value).to.equal('One');
|
178
177
|
});
|
178
|
+
it('selects the filter text on focus', async () => {
|
179
|
+
const component = await fixture(html `<glide-core-dropdown label="Label" placeholder="Placeholder">
|
180
|
+
${defaultSlot}
|
181
|
+
</glide-core-dropdown>`);
|
182
|
+
component.focus();
|
183
|
+
await sendKeys({ type: 'one' });
|
184
|
+
component.blur();
|
185
|
+
component.focus();
|
186
|
+
expect(window.getSelection()?.toString()).to.equal('one');
|
187
|
+
});
|
@@ -33,6 +33,22 @@ it('closes and reports validity when it loses focus', async () => {
|
|
33
33
|
await sendKeys({ up: 'Shift' });
|
34
34
|
expect(component.open).to.be.false;
|
35
35
|
expect(component.shadowRoot?.activeElement).to.equal(null);
|
36
|
-
expect(component.validity.valid).to.
|
37
|
-
expect(component.shadowRoot?.querySelector('glide-core-private-label')?.error)
|
36
|
+
expect(component.validity.valid).to.be.false;
|
37
|
+
expect(component.shadowRoot?.querySelector('glide-core-private-label')?.error)
|
38
|
+
.to.be.true;
|
39
|
+
});
|
40
|
+
it('is focused when clicked', async () => {
|
41
|
+
const component = await fixture(html `<glide-core-dropdown label="Label" placeholder="Placeholder">
|
42
|
+
<glide-core-dropdown-option
|
43
|
+
label="Label"
|
44
|
+
value="value"
|
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
|
+
const button = component.shadowRoot?.querySelector('[data-test="button"]');
|
52
|
+
button?.dispatchEvent(new CustomEvent('click', { bubbles: true, detail: 1 }));
|
53
|
+
expect(component.shadowRoot?.activeElement).to.equal(button);
|
38
54
|
});
|
@@ -83,7 +83,7 @@ it('filters', async () => {
|
|
83
83
|
${defaultSlot}
|
84
84
|
</glide-core-dropdown>`);
|
85
85
|
component.focus();
|
86
|
-
await sendKeys({ type: '
|
86
|
+
await sendKeys({ type: 'one' });
|
87
87
|
const options = [
|
88
88
|
...component.querySelectorAll('glide-core-dropdown-option'),
|
89
89
|
].filter(({ hidden }) => !hidden);
|
@@ -96,7 +96,7 @@ it('unfilters when an option is selected via click', async () => {
|
|
96
96
|
// Wait for it to open.
|
97
97
|
await aTimeout(0);
|
98
98
|
component.focus();
|
99
|
-
await sendKeys({ type: '
|
99
|
+
await sendKeys({ type: 'one' });
|
100
100
|
[...component.querySelectorAll('glide-core-dropdown-option')]
|
101
101
|
.find(({ hidden }) => !hidden)
|
102
102
|
?.click();
|
@@ -110,37 +110,71 @@ it('unfilters when an option is selected via Enter', async () => {
|
|
110
110
|
${defaultSlot}
|
111
111
|
</glide-core-dropdown>`);
|
112
112
|
component.focus();
|
113
|
-
await sendKeys({ type: '
|
113
|
+
await sendKeys({ type: 'one' });
|
114
114
|
await sendKeys({ press: 'Enter' });
|
115
115
|
const options = [
|
116
116
|
...component.querySelectorAll('glide-core-dropdown-option'),
|
117
117
|
].filter(({ hidden }) => !hidden);
|
118
118
|
expect(options.length).to.equal(11);
|
119
119
|
});
|
120
|
-
it('
|
120
|
+
it('does nothing on Enter when every option is filtered out', async () => {
|
121
121
|
const component = await fixture(html `<glide-core-dropdown label="Label" placeholder="Placeholder">
|
122
122
|
${defaultSlot}
|
123
123
|
</glide-core-dropdown>`);
|
124
124
|
component.focus();
|
125
|
-
await sendKeys({ type: '
|
125
|
+
await sendKeys({ type: 'blah' });
|
126
|
+
await sendKeys({ press: 'Enter' });
|
127
|
+
const input = component.shadowRoot?.querySelector('[data-test="input"]');
|
128
|
+
const hiddenOptions = [
|
129
|
+
...component.querySelectorAll('glide-core-dropdown-option'),
|
130
|
+
].filter(({ hidden }) => hidden);
|
131
|
+
const selectedOptions = [
|
132
|
+
...component.querySelectorAll('glide-core-dropdown-option'),
|
133
|
+
].filter(({ selected }) => selected);
|
134
|
+
expect(input?.value).to.equal('blah');
|
135
|
+
expect(hiddenOptions.length).to.equal(11);
|
136
|
+
expect(selectedOptions.length).to.equal(0);
|
137
|
+
});
|
138
|
+
it('shows its magnifying glass icon when single-select and filtering', async () => {
|
139
|
+
const component = await fixture(html `<glide-core-dropdown label="Label" placeholder="Placeholder">
|
140
|
+
${defaultSlot}
|
141
|
+
</glide-core-dropdown>`);
|
142
|
+
component.focus();
|
143
|
+
await sendKeys({ type: 'one' });
|
126
144
|
const icon = component?.shadowRoot?.querySelector('[data-test="magnifying-glass-icon"]');
|
127
145
|
expect(icon?.checkVisibility()).to.be.true;
|
128
146
|
});
|
129
|
-
it('hides
|
147
|
+
it('hides its magnifying glass icon when single-select and not filtering', async () => {
|
130
148
|
const component = await fixture(html `<glide-core-dropdown label="Label" placeholder="Placeholder">
|
131
149
|
${defaultSlot}
|
132
150
|
</glide-core-dropdown>`);
|
151
|
+
component.focus();
|
152
|
+
await sendKeys({ type: 'o' });
|
153
|
+
await sendKeys({ press: 'Backspace' });
|
133
154
|
const icon = component?.shadowRoot?.querySelector('[data-test="magnifying-glass-icon"]');
|
134
155
|
expect(icon?.checkVisibility()).to.be.not.ok;
|
135
156
|
});
|
136
|
-
it('hides
|
157
|
+
it('hides its magnifying glass icon when single-select and the filter is label of the selected option', async () => {
|
158
|
+
const component = await fixture(html `<glide-core-dropdown label="Label" placeholder="Placeholder">
|
159
|
+
${defaultSlot}
|
160
|
+
</glide-core-dropdown>`);
|
161
|
+
const option = [
|
162
|
+
...component.querySelectorAll('glide-core-dropdown-option'),
|
163
|
+
].find(({ hidden }) => !hidden);
|
164
|
+
option?.click();
|
165
|
+
component.focus();
|
166
|
+
await sendKeys({ type: 'One' });
|
167
|
+
const icon = component?.shadowRoot?.querySelector('[data-test="magnifying-glass-icon"]');
|
168
|
+
expect(icon?.checkVisibility()).to.be.not.ok;
|
169
|
+
});
|
170
|
+
it('hides its magnifying glass icon when single-select and an option is selected', async () => {
|
137
171
|
const component = await fixture(html `<glide-core-dropdown label="Label" placeholder="Placeholder" open>
|
138
172
|
${defaultSlot}
|
139
173
|
</glide-core-dropdown>`);
|
140
174
|
// Wait for it to open.
|
141
175
|
await aTimeout(0);
|
142
176
|
component.focus();
|
143
|
-
await sendKeys({ type: '
|
177
|
+
await sendKeys({ type: 'one' });
|
144
178
|
const option = [
|
145
179
|
...component.querySelectorAll('glide-core-dropdown-option'),
|
146
180
|
].find(({ hidden }) => !hidden);
|
@@ -149,7 +183,7 @@ it('hides the magnifying glass icon when an option is selected', async () => {
|
|
149
183
|
await elementUpdated(component);
|
150
184
|
expect(icon?.checkVisibility()).to.be.not.ok;
|
151
185
|
});
|
152
|
-
it('hides
|
186
|
+
it('hides its magnifying glass icon when single-select and closed programmatically and an option is selected', async () => {
|
153
187
|
const component = await fixture(html `<glide-core-dropdown label="Label" placeholder="Placeholder" open>
|
154
188
|
${defaultSlot}
|
155
189
|
</glide-core-dropdown>`);
|
@@ -163,6 +197,25 @@ it('hides the magnifying glass icon when closed programmatically and an option i
|
|
163
197
|
const icon = component?.shadowRoot?.querySelector('[data-test="magnifying-glass-icon"]');
|
164
198
|
component.open = false;
|
165
199
|
await elementUpdated(component);
|
200
|
+
expect(icon?.checkVisibility()).to.not.be.ok;
|
201
|
+
});
|
202
|
+
it('shows its magnifying glass icon when multiselect and filtering', async () => {
|
203
|
+
const component = await fixture(html `<glide-core-dropdown label="Label" placeholder="Placeholder" multiple>
|
204
|
+
${defaultSlot}
|
205
|
+
</glide-core-dropdown>`);
|
206
|
+
component.focus();
|
207
|
+
await sendKeys({ type: 'one' });
|
208
|
+
const icon = component?.shadowRoot?.querySelector('[data-test="magnifying-glass-icon"]');
|
209
|
+
expect(icon?.checkVisibility()).to.be.true;
|
210
|
+
});
|
211
|
+
it('hides its magnifying glass icon when multiselect and not filtering', async () => {
|
212
|
+
const component = await fixture(html `<glide-core-dropdown label="Label" placeholder="Placeholder" multiple>
|
213
|
+
${defaultSlot}
|
214
|
+
</glide-core-dropdown>`);
|
215
|
+
component.focus();
|
216
|
+
await sendKeys({ type: 'o' });
|
217
|
+
await sendKeys({ press: 'Backspace' });
|
218
|
+
const icon = component?.shadowRoot?.querySelector('[data-test="magnifying-glass-icon"]');
|
166
219
|
expect(icon?.checkVisibility()).to.be.not.ok;
|
167
220
|
});
|
168
221
|
it('does not filter on only whitespace', async () => {
|
@@ -231,6 +284,26 @@ it('updates `value` when an option `value` is changed programmatically', async (
|
|
231
284
|
option.value = 'two';
|
232
285
|
expect(component.value).to.deep.equal(['two']);
|
233
286
|
});
|
287
|
+
it('sets the `value` of its `<input>` when made filterable', async () => {
|
288
|
+
const component = await fixture(html `<glide-core-dropdown label="Label" placeholder="Placeholder">
|
289
|
+
<glide-core-dropdown-option
|
290
|
+
label="One"
|
291
|
+
value="one"
|
292
|
+
selected
|
293
|
+
></glide-core-dropdown-option>
|
294
|
+
|
295
|
+
<glide-core-dropdown-option
|
296
|
+
label="Two"
|
297
|
+
value="two"
|
298
|
+
></glide-core-dropdown-option>
|
299
|
+
</glide-core-dropdown>`);
|
300
|
+
component.filterable = true;
|
301
|
+
await elementUpdated(component);
|
302
|
+
const input = component.shadowRoot?.querySelector('[data-test="input"]');
|
303
|
+
// Wait for the `filterable` setter to do its thing.
|
304
|
+
await aTimeout(0);
|
305
|
+
expect(input?.value).to.equal('One');
|
306
|
+
});
|
234
307
|
it('does not select options on Space', async () => {
|
235
308
|
const component = await fixture(html `<glide-core-dropdown
|
236
309
|
label="Label"
|
@@ -282,7 +355,7 @@ it('deselects all options on Meta + Backspace', async () => {
|
|
282
355
|
expect(options[1].selected).to.be.false;
|
283
356
|
expect(options[0].selected).to.be.false;
|
284
357
|
});
|
285
|
-
it('
|
358
|
+
it('sets the `value` of its `<input>` to the label of the selected option when not `multiple`', async () => {
|
286
359
|
const component = await fixture(html `<glide-core-dropdown label="Label" placeholder="Placeholder">
|
287
360
|
${defaultSlot}
|
288
361
|
</glide-core-dropdown>`);
|
@@ -291,7 +364,18 @@ it('set the `value` of the `<input>` to the label of the selected option when no
|
|
291
364
|
const input = component.shadowRoot?.querySelector('[data-test="input"]');
|
292
365
|
expect(input?.value).to.equal(option?.label);
|
293
366
|
});
|
294
|
-
it('
|
367
|
+
it('clears the `value` of its `<input>` when multiselect and an option is selected', async () => {
|
368
|
+
const component = await fixture(html `<glide-core-dropdown label="Label" placeholder="Placeholder" multiple>
|
369
|
+
${defaultSlot}
|
370
|
+
</glide-core-dropdown>`);
|
371
|
+
component.focus();
|
372
|
+
await sendKeys({ type: 'one' });
|
373
|
+
const option = component?.querySelector('glide-core-dropdown-option');
|
374
|
+
option?.click();
|
375
|
+
const input = component.shadowRoot?.querySelector('[data-test="input"]');
|
376
|
+
expect(input?.value).to.be.empty.string;
|
377
|
+
});
|
378
|
+
it('uses `placeholder` as a placeholder when multiselect and no option is selected', async () => {
|
295
379
|
const component = await fixture(html `<glide-core-dropdown label="Label" placeholder="Placeholder" multiple>
|
296
380
|
${defaultSlot}
|
297
381
|
</glide-core-dropdown>`);
|
@@ -538,7 +622,7 @@ it('cannot be tabbed to when `disabled`', async () => {
|
|
538
622
|
await sendKeys({ press: 'Tab' });
|
539
623
|
expect(document.activeElement).to.equal(document.body);
|
540
624
|
});
|
541
|
-
it('sets the `value` of
|
625
|
+
it('sets the `value` of its `<input>` back to the label of selected option when something other than it is clicked', async () => {
|
542
626
|
const component = await fixture(html `<glide-core-dropdown label="Label" placeholder="Placeholder" open>
|
543
627
|
${defaultSlot}
|
544
628
|
</glide-core-dropdown>`);
|
@@ -564,39 +648,6 @@ it('selects the filter text when `click()` is called', async () => {
|
|
564
648
|
component.click();
|
565
649
|
expect(window.getSelection()?.toString()).to.equal('one');
|
566
650
|
});
|
567
|
-
it('selects the filter text when the `<input>` is clicked', async () => {
|
568
|
-
const component = await fixture(html `<glide-core-dropdown label="Label" placeholder="Placeholder">
|
569
|
-
${defaultSlot}
|
570
|
-
</glide-core-dropdown>`);
|
571
|
-
component.focus();
|
572
|
-
await sendKeys({ type: 'one' });
|
573
|
-
// Calling `click()` would be sweet. The problem is it sets `event.detail` to `0`,
|
574
|
-
// which puts us in a guard in the event handler. `Event` has no `detail` property
|
575
|
-
// and would work. `CustomEvent` is used for completeness and to get us as close as
|
576
|
-
// possible to a real click. See the comment in the handler for more information.
|
577
|
-
component.shadowRoot
|
578
|
-
?.querySelector('[data-test="input"]')
|
579
|
-
?.dispatchEvent(new CustomEvent('click', { bubbles: true, detail: 1 }));
|
580
|
-
expect(window.getSelection()?.toString()).to.equal('one');
|
581
|
-
});
|
582
|
-
it('selects the filter text when closed and the button is clicked', async () => {
|
583
|
-
const component = await fixture(html `<glide-core-dropdown label="Label" placeholder="Placeholder">
|
584
|
-
${defaultSlot}
|
585
|
-
</glide-core-dropdown>`);
|
586
|
-
component.focus();
|
587
|
-
await sendKeys({ type: 'one' });
|
588
|
-
component.open = false;
|
589
|
-
await elementUpdated(component);
|
590
|
-
// Calling `click()` would be sweet. The problem is it sets `event.detail` to `0`,
|
591
|
-
// which puts us in a guard in the event handler. `Event` has no `detail` property
|
592
|
-
// and would work. `CustomEvent` is used for completeness and to get us as close as
|
593
|
-
// possible to a real click. See the comment in the handler for more information.
|
594
|
-
component.shadowRoot
|
595
|
-
?.querySelector('[data-test="button"]')
|
596
|
-
?.dispatchEvent(new CustomEvent('click', { bubbles: true, detail: 1 }));
|
597
|
-
await elementUpdated(component);
|
598
|
-
expect(window.getSelection()?.toString()).to.equal('one');
|
599
|
-
});
|
600
651
|
it('clicks the `<input>` when `click()` is called', async () => {
|
601
652
|
const component = await fixture(html `<glide-core-dropdown label="Label" placeholder="Placeholder">
|
602
653
|
${defaultSlot}
|
@@ -609,3 +660,28 @@ it('clicks the `<input>` when `click()` is called', async () => {
|
|
609
660
|
const event = await oneEvent(button, 'click');
|
610
661
|
expect(event instanceof PointerEvent).to.be.true;
|
611
662
|
});
|
663
|
+
it('has no icon when filtering and an option is selected', async () => {
|
664
|
+
const component = await fixture(html `<glide-core-dropdown
|
665
|
+
label="Label"
|
666
|
+
placeholder="Placeholder"
|
667
|
+
filterable
|
668
|
+
>
|
669
|
+
<div slot="icon:one">✓</div>
|
670
|
+
<div slot="icon:two">✓</div>
|
671
|
+
|
672
|
+
<glide-core-dropdown-option
|
673
|
+
label="One"
|
674
|
+
value="one"
|
675
|
+
selected
|
676
|
+
></glide-core-dropdown-option>
|
677
|
+
|
678
|
+
<glide-core-dropdown-option
|
679
|
+
label="Two"
|
680
|
+
value="two"
|
681
|
+
></glide-core-dropdown-option>
|
682
|
+
</glide-core-dropdown>`);
|
683
|
+
component.focus();
|
684
|
+
await sendKeys({ type: 'one' });
|
685
|
+
const iconSlot = component.shadowRoot?.querySelector('[data-test="single-select-icon-slot"]');
|
686
|
+
expect(iconSlot).to.be.null;
|
687
|
+
});
|
@@ -1,11 +1,45 @@
|
|
1
1
|
/* eslint-disable @typescript-eslint/no-unused-expressions */
|
2
|
+
var __decorate = (this && this.__decorate) || function (decorators, target, key, desc) {
|
3
|
+
var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
|
4
|
+
if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc);
|
5
|
+
else for (var i = decorators.length - 1; i >= 0; i--) if (d = decorators[i]) r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r;
|
6
|
+
return c > 3 && r && Object.defineProperty(target, key, r), r;
|
7
|
+
};
|
8
|
+
import { LitElement } from 'lit';
|
2
9
|
import { aTimeout, assert, elementUpdated, expect, fixture, html, oneEvent, } from '@open-wc/testing';
|
10
|
+
import { customElement } from 'lit/decorators.js';
|
3
11
|
import { sendKeys } from '@web/test-runner-commands';
|
4
12
|
import { sendMouse } from '@web/test-runner-commands';
|
5
13
|
import GlideCoreDropdown from './dropdown.js';
|
6
14
|
import GlideCoreDropdownOption from './dropdown.option.js';
|
15
|
+
let GlideCoreDropdownInAnotherComponent = class GlideCoreDropdownInAnotherComponent extends LitElement {
|
16
|
+
static { this.shadowRootOptions = {
|
17
|
+
...LitElement.shadowRootOptions,
|
18
|
+
mode: 'closed',
|
19
|
+
}; }
|
20
|
+
render() {
|
21
|
+
return html `<glide-core-dropdown
|
22
|
+
label="Label"
|
23
|
+
placeholder="Placeholder"
|
24
|
+
multiple
|
25
|
+
open
|
26
|
+
>
|
27
|
+
<glide-core-dropdown-option
|
28
|
+
label="One"
|
29
|
+
value="one"
|
30
|
+
></glide-core-dropdown-option>
|
31
|
+
|
32
|
+
<glide-core-dropdown-option label="Two"></glide-core-dropdown-option>
|
33
|
+
<glide-core-dropdown-option label="Three"></glide-core-dropdown-option>
|
34
|
+
</glide-core-dropdown>`;
|
35
|
+
}
|
36
|
+
};
|
37
|
+
GlideCoreDropdownInAnotherComponent = __decorate([
|
38
|
+
customElement('glide-core-dropdown-in-another-component')
|
39
|
+
], GlideCoreDropdownInAnotherComponent);
|
7
40
|
GlideCoreDropdown.shadowRootOptions.mode = 'open';
|
8
41
|
GlideCoreDropdownOption.shadowRootOptions.mode = 'open';
|
42
|
+
GlideCoreDropdownInAnotherComponent.shadowRootOptions.mode = 'open';
|
9
43
|
it('opens on click', async () => {
|
10
44
|
const component = await fixture(html `<glide-core-dropdown label="Label" placeholder="Placeholder" multiple>
|
11
45
|
<glide-core-dropdown-option
|
@@ -221,25 +255,20 @@ it('deactivates all other options on "mouseover"', async () => {
|
|
221
255
|
expect(options[2]?.privateActive).to.be.false;
|
222
256
|
});
|
223
257
|
it('remains open when an option is selected via click', async () => {
|
224
|
-
const component = await fixture(html `<glide-core-dropdown
|
225
|
-
|
226
|
-
|
227
|
-
|
228
|
-
|
229
|
-
|
230
|
-
|
231
|
-
|
232
|
-
|
233
|
-
|
234
|
-
|
235
|
-
|
236
|
-
|
237
|
-
|
238
|
-
value="two"
|
239
|
-
></glide-core-dropdown-option>
|
240
|
-
</glide-core-dropdown>`);
|
241
|
-
component.querySelector('glide-core-dropdown-option')?.click();
|
242
|
-
expect(component.open).to.be.true;
|
258
|
+
const component = await fixture(html `<glide-core-dropdown-in-another-component></glide-core-dropdown-in-another-component>`);
|
259
|
+
// Wait for it to open.
|
260
|
+
await aTimeout(0);
|
261
|
+
const option = component.shadowRoot?.querySelector('glide-core-dropdown-option');
|
262
|
+
assert(option);
|
263
|
+
const { x, y } = option.getBoundingClientRect();
|
264
|
+
// Calling `click()` won't do because Dropdown relies on a "mouseup" event to
|
265
|
+
// decide if it should close.
|
266
|
+
await sendMouse({
|
267
|
+
type: 'click',
|
268
|
+
position: [Math.ceil(x), Math.ceil(y)],
|
269
|
+
});
|
270
|
+
const dropdown = component.shadowRoot?.querySelector('glide-core-dropdown');
|
271
|
+
expect(dropdown?.open).to.be.true;
|
243
272
|
});
|
244
273
|
it('remains open when an option is selected via Enter', async () => {
|
245
274
|
const component = await fixture(html `<glide-core-dropdown
|
@@ -454,7 +483,7 @@ it('updates `value` when an option is selected or deselected via Space', async (
|
|
454
483
|
await sendKeys({ press: ' ' });
|
455
484
|
expect(component.value).to.deep.equal(['one']);
|
456
485
|
});
|
457
|
-
it('updates `value` when
|
486
|
+
it('updates `value` when multiselect is changed to `true` programmatically', async () => {
|
458
487
|
const component = await fixture(html `<glide-core-dropdown open>
|
459
488
|
<glide-core-dropdown-option
|
460
489
|
label="One"
|
@@ -493,9 +522,9 @@ it('updates `value` when the `value` of a selected option is changed programmati
|
|
493
522
|
const option = component.querySelector('glide-core-dropdown-option');
|
494
523
|
assert(option);
|
495
524
|
option.value = 'three';
|
496
|
-
expect(component.value).to.deep.equal(['
|
525
|
+
expect(component.value).to.deep.equal(['three', 'two']);
|
497
526
|
});
|
498
|
-
it('updates `value` when the `value` of a selected option is
|
527
|
+
it('updates `value` when the `value` of a selected option is emptied programmatically', async () => {
|
499
528
|
const component = await fixture(html `<glide-core-dropdown open multiple>
|
500
529
|
<glide-core-dropdown-option
|
501
530
|
label="One"
|
@@ -538,8 +567,13 @@ it('has no internal label when an option is newly selected', async () => {
|
|
538
567
|
const label = component.shadowRoot?.querySelector('[data-test="internal-label"]');
|
539
568
|
expect(label).to.not.exist;
|
540
569
|
});
|
541
|
-
it('
|
542
|
-
const component = await fixture(html `<glide-core-dropdown
|
570
|
+
it('hides tags to prevent overflow', async () => {
|
571
|
+
const component = await fixture(html `<glide-core-dropdown
|
572
|
+
label="Label"
|
573
|
+
placeholder="Placeholder"
|
574
|
+
multiple
|
575
|
+
style="display: block; max-width: 20rem;"
|
576
|
+
>
|
543
577
|
<glide-core-dropdown-option
|
544
578
|
label="One"
|
545
579
|
value="one"
|
@@ -565,14 +599,20 @@ it('only has so many tags when many options are selected', async () => {
|
|
565
599
|
options[1].selected = true;
|
566
600
|
options[2].selected = true;
|
567
601
|
options[3].selected = true;
|
568
|
-
|
602
|
+
// Wait for the Resize Observer to do its thing.
|
603
|
+
await aTimeout(0);
|
569
604
|
const tagContainers = [
|
570
605
|
...(component.shadowRoot?.querySelectorAll('[data-test="tag-container"]') ?? []),
|
571
606
|
].filter((element) => element.checkVisibility());
|
572
|
-
expect(tagContainers?.length).to.equal(
|
607
|
+
expect(tagContainers?.length).to.equal(2);
|
573
608
|
});
|
574
|
-
it('has overflow text when
|
575
|
-
const component = await fixture(html `<glide-core-dropdown
|
609
|
+
it('has overflow text when its tags are overflowing', async () => {
|
610
|
+
const component = await fixture(html `<glide-core-dropdown
|
611
|
+
label="Label"
|
612
|
+
placeholder="Placeholder"
|
613
|
+
multiple
|
614
|
+
style="display: block; max-width: 20rem;"
|
615
|
+
>
|
576
616
|
<glide-core-dropdown-option
|
577
617
|
label="One"
|
578
618
|
value="one"
|
@@ -598,9 +638,10 @@ it('has overflow text when many options are selected', async () => {
|
|
598
638
|
options[1].selected = true;
|
599
639
|
options[2].selected = true;
|
600
640
|
options[3].selected = true;
|
601
|
-
|
641
|
+
// Wait for the Resize Observer to do its thing.
|
642
|
+
await aTimeout(0);
|
602
643
|
const tagOverflow = component.shadowRoot?.querySelector('[data-test="tag-overflow-count"]');
|
603
|
-
expect(tagOverflow?.textContent?.trim()).to.equal('
|
644
|
+
expect(tagOverflow?.textContent?.trim()).to.equal('2');
|
604
645
|
});
|
605
646
|
it('deselects the option when its tag is removed', async () => {
|
606
647
|
const component = await fixture(html `<glide-core-dropdown
|