@crowdstrike/glide-core 0.5.1 → 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.
- package/dist/accordion.js +1 -1
- package/dist/accordion.styles.js +4 -4
- package/dist/accordion.test.basics.js +109 -0
- package/dist/accordion.test.events.js +39 -0
- package/dist/button-group.button.js +1 -1
- package/dist/button-group.button.styles.js +4 -4
- package/dist/button-group.button.test.basics.js +169 -0
- package/dist/button-group.button.test.events.js +73 -0
- package/dist/button-group.js +1 -1
- package/dist/button-group.styles.js +3 -3
- package/dist/button-group.test.basics.js +268 -0
- package/dist/button-group.test.events.js +291 -0
- package/dist/button.js +1 -1
- package/dist/button.styles.js +4 -4
- package/dist/button.test.basics.js +196 -0
- package/dist/button.test.events.js +25 -0
- package/dist/button.test.form.js +49 -0
- package/dist/checkbox-group.js +1 -1
- package/dist/checkbox-group.styles.js +2 -2
- package/dist/checkbox-group.test.basics.js +119 -0
- package/dist/checkbox-group.test.events.js +110 -0
- package/dist/checkbox-group.test.focus.js +45 -0
- package/dist/checkbox-group.test.form.js +130 -0
- package/dist/checkbox-group.test.validity.js +75 -0
- package/dist/checkbox.js +1 -1
- package/dist/checkbox.styles.js +3 -3
- package/dist/checkbox.test.basics.js +89 -0
- package/dist/checkbox.test.events.js +87 -0
- package/dist/checkbox.test.focus.js +38 -0
- package/dist/checkbox.test.form.js +115 -0
- package/dist/checkbox.test.states.js +62 -0
- package/dist/checkbox.test.validity.js +51 -0
- package/dist/drawer.d.ts +2 -2
- package/dist/drawer.js +1 -15
- package/dist/drawer.styles.js +18 -4
- package/dist/drawer.test.accessibility.js +22 -0
- package/dist/drawer.test.basics.js +43 -0
- package/dist/drawer.test.closing.js +37 -0
- package/dist/drawer.test.events.js +52 -0
- package/dist/drawer.test.methods.js +34 -0
- package/dist/dropdown.d.ts +4 -2
- package/dist/dropdown.js +1 -1
- package/dist/dropdown.option.d.ts +0 -2
- package/dist/dropdown.option.js +1 -1
- package/dist/dropdown.option.styles.js +2 -2
- package/dist/dropdown.option.test.basics.js +59 -0
- package/dist/dropdown.option.test.basics.multiple.js +26 -0
- package/dist/dropdown.option.test.basics.single.js +20 -0
- package/dist/dropdown.option.test.events.js +27 -0
- package/dist/dropdown.option.test.focus.js +11 -0
- package/dist/dropdown.option.test.interactions.multiple.js +87 -0
- package/dist/dropdown.option.test.interactions.single.js +22 -0
- package/dist/dropdown.styles.js +25 -6
- package/dist/dropdown.test.basics.filterable.js +84 -0
- package/dist/dropdown.test.basics.js +233 -0
- package/dist/dropdown.test.basics.multiple.js +270 -0
- package/dist/dropdown.test.basics.single.js +79 -0
- package/dist/dropdown.test.events.js +268 -0
- package/dist/dropdown.test.events.multiple.js +130 -0
- package/dist/dropdown.test.focus.d.ts +1 -0
- package/dist/dropdown.test.focus.filterable.js +154 -0
- package/dist/dropdown.test.focus.js +18 -0
- package/dist/dropdown.test.focus.multiple.js +181 -0
- package/dist/dropdown.test.focus.single.js +53 -0
- package/dist/dropdown.test.form.js +140 -0
- package/dist/dropdown.test.form.multiple.js +149 -0
- package/dist/dropdown.test.form.single.js +128 -0
- package/dist/dropdown.test.interactions.filterable.js +385 -0
- package/dist/dropdown.test.interactions.js +446 -0
- package/dist/dropdown.test.interactions.multiple.js +908 -0
- package/dist/dropdown.test.interactions.single.js +466 -0
- package/dist/dropdown.test.validity.js +46 -0
- package/dist/icon-button.js +1 -1
- package/dist/icon-button.styles.js +3 -3
- package/dist/icon-button.test.basics.js +103 -0
- package/dist/icons/checked.js +1 -1
- package/dist/icons/magnifying-glass.js +1 -1
- package/dist/input.js +1 -1
- package/dist/input.styles.js +3 -3
- package/dist/input.test.basics.js +169 -0
- package/dist/input.test.events.js +97 -0
- package/dist/input.test.focus.js +54 -0
- package/dist/input.test.form.js +56 -0
- package/dist/input.test.validity.js +50 -0
- package/dist/label.js +1 -1
- package/dist/label.styles.js +3 -3
- package/dist/label.test.basics.js +129 -0
- package/dist/library/expect-argument-error.js +1 -1
- package/dist/library/ow.js +1 -1
- package/dist/library/ow.test.js +55 -0
- package/dist/menu.button.d.ts +1 -2
- package/dist/menu.button.js +1 -1
- package/dist/menu.button.styles.js +3 -3
- package/dist/menu.button.test.basics.js +42 -0
- package/dist/menu.d.ts +4 -0
- package/dist/menu.js +1 -1
- package/dist/menu.link.d.ts +1 -2
- package/dist/menu.link.js +1 -1
- package/dist/menu.link.styles.js +3 -3
- package/dist/menu.link.test.basics.js +46 -0
- package/dist/menu.styles.js +6 -6
- package/dist/menu.test.basics.js +161 -0
- package/dist/menu.test.focus.d.ts +0 -1
- package/dist/menu.test.focus.js +66 -0
- package/dist/menu.test.interactions.d.ts +0 -1
- package/dist/menu.test.interactions.js +522 -0
- package/dist/modal.icon-button.js +1 -1
- package/dist/modal.icon-button.styles.js +2 -2
- package/dist/modal.icon-button.test.basics.js +45 -0
- package/dist/modal.js +1 -15
- package/dist/modal.styles.js +4 -4
- package/dist/modal.tertiary-icon.js +1 -1
- package/dist/modal.tertiary-icon.test.basics.js +59 -0
- package/dist/modal.test.accessibility.js +48 -0
- package/dist/modal.test.basics.js +203 -0
- package/dist/modal.test.close.js +38 -0
- package/dist/modal.test.events.js +110 -0
- package/dist/modal.test.lock-scroll.js +76 -0
- package/dist/modal.test.methods.js +23 -0
- package/dist/modal.test.scrollbars.js +19 -0
- package/dist/radio-group.js +1 -1
- package/dist/radio-group.styles.js +2 -2
- package/dist/radio-group.test.basics.js +323 -0
- package/dist/radio-group.test.events.js +277 -0
- package/dist/radio-group.test.focus.js +75 -0
- package/dist/radio-group.test.form.js +104 -0
- package/dist/radio-group.test.validity.js +228 -0
- package/dist/radio.js +1 -1
- package/dist/radio.styles.js +4 -4
- package/dist/split-button.d.ts +24 -0
- package/dist/split-button.js +1 -0
- package/dist/split-button.stories.d.ts +17 -0
- package/dist/split-button.styles.d.ts +2 -0
- package/dist/split-button.styles.js +103 -0
- package/dist/split-button.test.basics.d.ts +1 -0
- package/dist/split-button.test.basics.js +84 -0
- package/dist/split-container.d.ts +30 -0
- package/dist/split-container.js +1 -0
- package/dist/split-container.styles.d.ts +2 -0
- package/dist/split-container.styles.js +132 -0
- package/dist/split-container.test.basics.d.ts +3 -0
- package/dist/split-container.test.basics.js +445 -0
- package/dist/split-container.test.interactions.d.ts +1 -0
- package/dist/split-container.test.interactions.js +20 -0
- package/dist/split-link.d.ts +25 -0
- package/dist/split-link.js +1 -0
- package/dist/split-link.test.basics.d.ts +1 -0
- package/dist/split-link.test.basics.js +92 -0
- package/dist/split-link.test.interactions.d.ts +1 -0
- package/dist/split-link.test.interactions.js +19 -0
- package/dist/status-indicator.js +1 -1
- package/dist/status-indicator.styles.js +2 -2
- package/dist/status-indicator.test.basics.js +102 -0
- package/dist/styles/focus-outline.js +1 -4
- package/dist/styles/visually-hidden.js +1 -11
- package/dist/tab.group.js +1 -1
- package/dist/tab.group.styles.js +2 -2
- package/dist/tab.group.test.basics.js +185 -0
- package/dist/tab.js +1 -1
- package/dist/tab.panel.js +1 -1
- package/dist/tab.panel.styles.js +3 -3
- package/dist/tab.styles.js +2 -2
- package/dist/tab.test.basics.js +71 -0
- package/dist/tag.js +1 -1
- package/dist/tag.styles.js +3 -3
- package/dist/tag.test.basics.js +118 -0
- package/dist/tag.test.events.js +16 -0
- package/dist/tag.test.focus.js +11 -0
- package/dist/textarea.js +2 -2
- package/dist/textarea.styles.js +3 -3
- package/dist/textarea.test.basics.js +140 -0
- package/dist/textarea.test.events.js +204 -0
- package/dist/textarea.test.form.js +70 -0
- package/dist/textarea.test.validity.js +83 -0
- package/dist/toasts.js +1 -1
- package/dist/toasts.styles.js +2 -2
- package/dist/toasts.test.basics.js +94 -0
- package/dist/toasts.toast.js +1 -1
- package/dist/toasts.toast.styles.js +5 -2
- package/dist/toasts.toast.test.basics.js +139 -0
- package/dist/toggle.js +1 -1
- package/dist/toggle.styles.js +3 -3
- package/dist/toggle.test.basics.js +64 -0
- package/dist/toggle.test.events.js +29 -0
- package/dist/toggle.test.focus.js +9 -0
- package/dist/toggle.test.states.js +35 -0
- package/dist/tooltip.js +1 -1
- package/dist/tooltip.styles.js +3 -3
- package/dist/tooltip.test.basics.js +64 -0
- package/dist/tooltip.test.interactions.js +78 -0
- package/dist/tree.item.icon-button.js +1 -1
- package/dist/tree.item.icon-button.styles.js +2 -2
- package/dist/tree.item.icon-button.test.basics.js +13 -0
- package/dist/tree.item.js +1 -1
- package/dist/tree.item.menu.js +1 -1
- package/dist/tree.item.menu.styles.js +2 -2
- package/dist/tree.item.menu.test.basics.js +34 -0
- package/dist/tree.item.styles.js +2 -2
- package/dist/tree.item.test.basics.js +102 -0
- package/dist/tree.js +1 -1
- package/dist/tree.styles.js +2 -2
- package/dist/tree.test.aria.js +86 -0
- package/dist/tree.test.basics.js +123 -0
- package/dist/tree.test.events.js +19 -0
- package/dist/tree.test.focus.js +261 -0
- package/package.json +18 -16
- /package/dist/{dropdown.option.test.focus.multiple.d.ts → dropdown.option.test.focus.d.ts} +0 -0
- /package/dist/{dropdown.option.test.focus.single.d.ts → dropdown.test.events.multiple.d.ts} +0 -0
@@ -0,0 +1,466 @@
|
|
1
|
+
import { ArgumentError } from 'ow';
|
2
|
+
import { assert, elementUpdated, expect, fixture, html, } from '@open-wc/testing';
|
3
|
+
import { sendKeys } from '@web/test-runner-commands';
|
4
|
+
import GlideCoreDropdown from './dropdown.js';
|
5
|
+
import GlideCoreDropdownOption from './dropdown.option.js';
|
6
|
+
import sinon from 'sinon';
|
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">
|
11
|
+
<glide-core-dropdown-option
|
12
|
+
label="Label"
|
13
|
+
value="value"
|
14
|
+
></glide-core-dropdown-option>
|
15
|
+
</glide-core-dropdown>`);
|
16
|
+
// Calling `click()` would be sweet. The problem is it sets `event.detail` to `0`,
|
17
|
+
// which puts us in a guard in the event handler. `Event` has no `detail` property
|
18
|
+
// and would work. `CustomEvent` is used for completeness and to get us as close as
|
19
|
+
// possible to a real click. See the comment in the handler for more information.
|
20
|
+
component.shadowRoot
|
21
|
+
?.querySelector('[data-test="button"]')
|
22
|
+
?.dispatchEvent(new CustomEvent('click', { bubbles: true, detail: 1 }));
|
23
|
+
expect(component.open).to.be.true;
|
24
|
+
});
|
25
|
+
it('toggles open and closed when the button is clicked', async () => {
|
26
|
+
const component = await fixture(html `<glide-core-dropdown label="Label" placeholder="Placeholder" open>
|
27
|
+
<glide-core-dropdown-option
|
28
|
+
label="Label"
|
29
|
+
value="value"
|
30
|
+
></glide-core-dropdown-option>
|
31
|
+
</glide-core-dropdown>`);
|
32
|
+
// Calling `click()` would be sweet. The problem is it sets `event.detail` to `0`,
|
33
|
+
// which puts us in a guard in the event handler. `Event` has no `detail` property
|
34
|
+
// and would work. `CustomEvent` is used for completeness and to get us as close as
|
35
|
+
// possible to a real click. See the comment in the handler for more information.
|
36
|
+
component.shadowRoot
|
37
|
+
?.querySelector('[data-test="button"]')
|
38
|
+
?.dispatchEvent(new CustomEvent('click', { bubbles: true, detail: 1 }));
|
39
|
+
expect(component.open).to.be.false;
|
40
|
+
});
|
41
|
+
it('does not toggle open and closed when the button overflow text is clicked', async () => {
|
42
|
+
const component = await fixture(html `<glide-core-dropdown label="Label" placeholder="Placeholder" open>
|
43
|
+
<glide-core-dropdown-option
|
44
|
+
label="Label"
|
45
|
+
value="value"
|
46
|
+
></glide-core-dropdown-option>
|
47
|
+
</glide-core-dropdown>`);
|
48
|
+
// Calling `click()` would be sweet. The problem is it sets `event.detail` to `0`,
|
49
|
+
// which puts us in a guard in the event handler. `Event` has no `detail` property
|
50
|
+
// and would work. `CustomEvent` is used for completeness and to get us as close as
|
51
|
+
// possible to a real click. See the comment in the handler for more information.
|
52
|
+
component.shadowRoot
|
53
|
+
?.querySelector('[data-test="tag-overflow-text"]')
|
54
|
+
?.dispatchEvent(new CustomEvent('click', { bubbles: true, detail: 1 }));
|
55
|
+
expect(component.open).to.be.true;
|
56
|
+
});
|
57
|
+
it('selects an option on click', async () => {
|
58
|
+
const component = await fixture(html `<glide-core-dropdown label="Label" placeholder="Placeholder" open>
|
59
|
+
<glide-core-dropdown-option
|
60
|
+
label="One"
|
61
|
+
value="one"
|
62
|
+
></glide-core-dropdown-option>
|
63
|
+
</glide-core-dropdown>`);
|
64
|
+
const option = component.querySelector('glide-core-dropdown-option');
|
65
|
+
option?.click();
|
66
|
+
await elementUpdated(component);
|
67
|
+
const labels = component.shadowRoot?.querySelectorAll('[data-test="selected-option-label"]');
|
68
|
+
expect(option?.selected).to.be.true;
|
69
|
+
expect(labels?.length).to.equal(1);
|
70
|
+
expect(labels?.[0]?.textContent?.trim()).to.equal('One,');
|
71
|
+
});
|
72
|
+
it('selects an option on Space', async () => {
|
73
|
+
const component = await fixture(html `<glide-core-dropdown label="Label" placeholder="Placeholder" open>
|
74
|
+
<glide-core-dropdown-option
|
75
|
+
label="One"
|
76
|
+
value="one"
|
77
|
+
></glide-core-dropdown-option>
|
78
|
+
</glide-core-dropdown>`);
|
79
|
+
const option = component.querySelector('glide-core-dropdown-option');
|
80
|
+
option?.focus();
|
81
|
+
await sendKeys({ press: ' ' });
|
82
|
+
expect(option?.selected).to.be.true;
|
83
|
+
});
|
84
|
+
it('selects an option on Enter', async () => {
|
85
|
+
const component = await fixture(html `<glide-core-dropdown label="Label" placeholder="Placeholder" open>
|
86
|
+
<glide-core-dropdown-option
|
87
|
+
label="One"
|
88
|
+
value="one"
|
89
|
+
></glide-core-dropdown-option>
|
90
|
+
</glide-core-dropdown>`);
|
91
|
+
const option = component.querySelector('glide-core-dropdown-option');
|
92
|
+
option?.focus();
|
93
|
+
await sendKeys({ press: 'Enter' });
|
94
|
+
expect(option?.selected).to.be.true;
|
95
|
+
});
|
96
|
+
it('deactivates all other options on "mouseover"', async () => {
|
97
|
+
const component = await fixture(html `<glide-core-dropdown open>
|
98
|
+
<glide-core-dropdown-option
|
99
|
+
label="One"
|
100
|
+
value="one"
|
101
|
+
></glide-core-dropdown-option>
|
102
|
+
|
103
|
+
<glide-core-dropdown-option
|
104
|
+
label="Two"
|
105
|
+
value="two"
|
106
|
+
></glide-core-dropdown-option>
|
107
|
+
</glide-core-dropdown>`);
|
108
|
+
const options = component.querySelectorAll('glide-core-dropdown-option');
|
109
|
+
options[0]?.dispatchEvent(new MouseEvent('mouseover', { bubbles: true }));
|
110
|
+
options[1]?.dispatchEvent(new MouseEvent('mouseover', { bubbles: true }));
|
111
|
+
expect(options[0]?.privateActive).to.be.false;
|
112
|
+
expect(options[1]?.privateActive).to.be.true;
|
113
|
+
});
|
114
|
+
it('closes when an option is selected via click', async () => {
|
115
|
+
const component = await fixture(html `<glide-core-dropdown label="Label" placeholder="Placeholder" open>
|
116
|
+
<glide-core-dropdown-option
|
117
|
+
label="Label"
|
118
|
+
value="value"
|
119
|
+
></glide-core-dropdown-option>
|
120
|
+
</glide-core-dropdown>`);
|
121
|
+
component.querySelector('glide-core-dropdown-option')?.click();
|
122
|
+
expect(component.open).to.be.false;
|
123
|
+
});
|
124
|
+
it('closes when an option is selected via Enter', async () => {
|
125
|
+
const component = await fixture(html `<glide-core-dropdown label="Label" placeholder="Placeholder" open>
|
126
|
+
<glide-core-dropdown-option
|
127
|
+
label="Label"
|
128
|
+
value="value"
|
129
|
+
></glide-core-dropdown-option>
|
130
|
+
</glide-core-dropdown>`);
|
131
|
+
component.querySelector('glide-core-dropdown-option')?.focus();
|
132
|
+
await sendKeys({ press: 'Enter' });
|
133
|
+
expect(component.open).to.be.false;
|
134
|
+
});
|
135
|
+
it('closes 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="Label"
|
139
|
+
value="value"
|
140
|
+
></glide-core-dropdown-option>
|
141
|
+
</glide-core-dropdown>`);
|
142
|
+
const option = component.querySelector('glide-core-dropdown-option');
|
143
|
+
option?.focus();
|
144
|
+
await sendKeys({ press: ' ' });
|
145
|
+
expect(component.open).to.be.false;
|
146
|
+
});
|
147
|
+
it('deselects all other options when one is newly selected', async () => {
|
148
|
+
const component = await fixture(html `<glide-core-dropdown label="Label" placeholder="Placeholder">
|
149
|
+
<glide-core-dropdown-option
|
150
|
+
label="One"
|
151
|
+
value="one"
|
152
|
+
selected
|
153
|
+
></glide-core-dropdown-option>
|
154
|
+
|
155
|
+
<glide-core-dropdown-option
|
156
|
+
label="Two"
|
157
|
+
value="two"
|
158
|
+
></glide-core-dropdown-option>
|
159
|
+
|
160
|
+
<glide-core-dropdown-option
|
161
|
+
label="Three"
|
162
|
+
value="three"
|
163
|
+
></glide-core-dropdown-option>
|
164
|
+
</glide-core-dropdown>`);
|
165
|
+
component.shadowRoot
|
166
|
+
?.querySelector('[data-test="button"]')
|
167
|
+
?.dispatchEvent(new Event('click'));
|
168
|
+
const options = component.querySelectorAll('glide-core-dropdown-option');
|
169
|
+
options[1].click();
|
170
|
+
expect(options[0].selected).to.be.false;
|
171
|
+
expect(options[1].selected).to.be.true;
|
172
|
+
expect(options[2].selected).to.be.false;
|
173
|
+
});
|
174
|
+
it('selects and deselects options when `value` is changed programmatically', async () => {
|
175
|
+
const component = await fixture(html `<glide-core-dropdown label="Label" placeholder="Placeholder">
|
176
|
+
<glide-core-dropdown-option
|
177
|
+
label="One"
|
178
|
+
value="one"
|
179
|
+
selected
|
180
|
+
></glide-core-dropdown-option>
|
181
|
+
|
182
|
+
<glide-core-dropdown-option
|
183
|
+
label="Two"
|
184
|
+
value="two"
|
185
|
+
></glide-core-dropdown-option>
|
186
|
+
</glide-core-dropdown>`);
|
187
|
+
component.value = ['two'];
|
188
|
+
const options = component.querySelectorAll('glide-core-dropdown-option');
|
189
|
+
expect(options[0].selected).to.be.false;
|
190
|
+
expect(options[1].selected).to.be.true;
|
191
|
+
});
|
192
|
+
it('throws when `value` is changed programmatically to include more than one value', async () => {
|
193
|
+
const component = await fixture(html `<glide-core-dropdown label="Label" placeholder="Placeholder">
|
194
|
+
<glide-core-dropdown-option
|
195
|
+
label="One"
|
196
|
+
value="one"
|
197
|
+
></glide-core-dropdown-option>
|
198
|
+
|
199
|
+
<glide-core-dropdown-option
|
200
|
+
label="Two"
|
201
|
+
value="two"
|
202
|
+
></glide-core-dropdown-option>
|
203
|
+
</glide-core-dropdown>`);
|
204
|
+
const spy = sinon.spy();
|
205
|
+
try {
|
206
|
+
component.value = ['one', 'two'];
|
207
|
+
}
|
208
|
+
catch (error) {
|
209
|
+
if (error instanceof ArgumentError) {
|
210
|
+
spy();
|
211
|
+
}
|
212
|
+
}
|
213
|
+
expect(spy.called).to.be.true;
|
214
|
+
});
|
215
|
+
it('updates `value` when an option `value` is changed programmatically', async () => {
|
216
|
+
const component = await fixture(html `<glide-core-dropdown label="Label" placeholder="Placeholder">
|
217
|
+
<glide-core-dropdown-option
|
218
|
+
label="One"
|
219
|
+
value="one"
|
220
|
+
selected
|
221
|
+
></glide-core-dropdown-option>
|
222
|
+
</glide-core-dropdown>`);
|
223
|
+
const option = component.querySelector('glide-core-dropdown-option');
|
224
|
+
assert(option);
|
225
|
+
option.value = 'two';
|
226
|
+
expect(component.value).to.deep.equal(['two']);
|
227
|
+
});
|
228
|
+
it('updates `value` when an option is selected via click', async () => {
|
229
|
+
const component = await fixture(html `<glide-core-dropdown label="Label" placeholder="Placeholder" open>
|
230
|
+
<glide-core-dropdown-option
|
231
|
+
label="One"
|
232
|
+
value="one"
|
233
|
+
></glide-core-dropdown-option>
|
234
|
+
|
235
|
+
<glide-core-dropdown-option
|
236
|
+
label="Two"
|
237
|
+
value="two"
|
238
|
+
></glide-core-dropdown-option>
|
239
|
+
|
240
|
+
<glide-core-dropdown-option label="Three"></glide-core-dropdown-option>
|
241
|
+
</glide-core-dropdown>`);
|
242
|
+
const options = component.querySelectorAll('glide-core-dropdown-option');
|
243
|
+
options[1].click();
|
244
|
+
expect(component.value).to.deep.equal(['two']);
|
245
|
+
// Reopen it.
|
246
|
+
component.shadowRoot
|
247
|
+
?.querySelector('[data-test="button"]')
|
248
|
+
?.dispatchEvent(new CustomEvent('click', { detail: 1 }));
|
249
|
+
// Wait for it to open.
|
250
|
+
await elementUpdated(component);
|
251
|
+
options[1].click();
|
252
|
+
expect(component.value).to.deep.equal(['two']);
|
253
|
+
// Reopen it.
|
254
|
+
component.shadowRoot
|
255
|
+
?.querySelector('[data-test="button"]')
|
256
|
+
?.dispatchEvent(new CustomEvent('click', { detail: 1 }));
|
257
|
+
// Wait for it to open.
|
258
|
+
await elementUpdated(component);
|
259
|
+
options[2].click();
|
260
|
+
expect(component.value).to.deep.equal([]);
|
261
|
+
});
|
262
|
+
it('updates `value` when an option is selected via Enter', async () => {
|
263
|
+
const component = await fixture(html `<glide-core-dropdown open>
|
264
|
+
<glide-core-dropdown-option
|
265
|
+
label="One"
|
266
|
+
value="one"
|
267
|
+
></glide-core-dropdown-option>
|
268
|
+
|
269
|
+
<glide-core-dropdown-option
|
270
|
+
label="Two"
|
271
|
+
value="two"
|
272
|
+
></glide-core-dropdown-option>
|
273
|
+
|
274
|
+
<glide-core-dropdown-option label="Two"></glide-core-dropdown-option>
|
275
|
+
</glide-core-dropdown>`);
|
276
|
+
const options = component.querySelectorAll('glide-core-dropdown-option');
|
277
|
+
options[0].focus();
|
278
|
+
await sendKeys({ press: 'Enter' });
|
279
|
+
expect(component.value).to.deep.equal(['one']);
|
280
|
+
// Reopen it.
|
281
|
+
component.shadowRoot
|
282
|
+
?.querySelector('[data-test="button"]')
|
283
|
+
?.dispatchEvent(new CustomEvent('click', { bubbles: true, detail: 1 }));
|
284
|
+
// Wait for it to open.
|
285
|
+
await elementUpdated(component);
|
286
|
+
options[1].focus();
|
287
|
+
await sendKeys({ press: 'Enter' });
|
288
|
+
expect(component.value).to.deep.equal(['two']);
|
289
|
+
// Reopen it.
|
290
|
+
component.shadowRoot
|
291
|
+
?.querySelector('[data-test="button"]')
|
292
|
+
?.dispatchEvent(new CustomEvent('click', { bubbles: true, detail: 1 }));
|
293
|
+
// Wait for it to open.
|
294
|
+
await elementUpdated(component);
|
295
|
+
options[2].focus();
|
296
|
+
await sendKeys({ press: 'Enter' });
|
297
|
+
expect(component.value).to.deep.equal([]);
|
298
|
+
});
|
299
|
+
it('updates `value` when an option is selected via Space', async () => {
|
300
|
+
const component = await fixture(html `<glide-core-dropdown open>
|
301
|
+
<glide-core-dropdown-option
|
302
|
+
label="One"
|
303
|
+
value="one"
|
304
|
+
></glide-core-dropdown-option>
|
305
|
+
|
306
|
+
<glide-core-dropdown-option
|
307
|
+
label="Two"
|
308
|
+
value="two"
|
309
|
+
></glide-core-dropdown-option>
|
310
|
+
|
311
|
+
<glide-core-dropdown-option label="Three"></glide-core-dropdown-option>
|
312
|
+
</glide-core-dropdown>`);
|
313
|
+
const options = component.querySelectorAll('glide-core-dropdown-option');
|
314
|
+
options[0].focus();
|
315
|
+
await sendKeys({ press: ' ' });
|
316
|
+
expect(component.value).to.deep.equal(['one']);
|
317
|
+
// Reopen it.
|
318
|
+
component.shadowRoot
|
319
|
+
?.querySelector('[data-test="button"]')
|
320
|
+
?.dispatchEvent(new CustomEvent('click', { bubbles: true, detail: 1 }));
|
321
|
+
// Wait for it to open.
|
322
|
+
await elementUpdated(component);
|
323
|
+
options[1].focus();
|
324
|
+
await sendKeys({ press: ' ' });
|
325
|
+
expect(component.value).to.deep.equal(['two']);
|
326
|
+
// Reopen it.
|
327
|
+
component.shadowRoot
|
328
|
+
?.querySelector('[data-test="button"]')
|
329
|
+
?.dispatchEvent(new CustomEvent('click', { bubbles: true, detail: 1 }));
|
330
|
+
// Wait for it to open.
|
331
|
+
await elementUpdated(component);
|
332
|
+
options[2].focus();
|
333
|
+
await sendKeys({ press: ' ' });
|
334
|
+
expect(component.value).to.deep.equal([]);
|
335
|
+
});
|
336
|
+
it('updates `value` when `multiple` is changed to `false` programmatically', async () => {
|
337
|
+
const component = await fixture(html `<glide-core-dropdown open multiple>
|
338
|
+
<glide-core-dropdown-option
|
339
|
+
label="One"
|
340
|
+
value="one"
|
341
|
+
selected
|
342
|
+
></glide-core-dropdown-option>
|
343
|
+
|
344
|
+
<glide-core-dropdown-option
|
345
|
+
label="Two"
|
346
|
+
value="two"
|
347
|
+
selected
|
348
|
+
></glide-core-dropdown-option>
|
349
|
+
</glide-core-dropdown>`);
|
350
|
+
component.multiple = false;
|
351
|
+
const options = component.querySelectorAll('glide-core-dropdown-option');
|
352
|
+
const checkbox = options[1].shadowRoot?.querySelector('[data-test="checkbox"]');
|
353
|
+
expect(options[0].selected).to.be.false;
|
354
|
+
expect(options[1].selected).to.be.true;
|
355
|
+
expect(checkbox?.checked).to.be.true;
|
356
|
+
expect(component.value).to.deep.equal(['two']);
|
357
|
+
});
|
358
|
+
it('updates `value` when the `value` of the selected option is changed programmatically', async () => {
|
359
|
+
const component = await fixture(html `<glide-core-dropdown open>
|
360
|
+
<glide-core-dropdown-option
|
361
|
+
label="One"
|
362
|
+
value="one"
|
363
|
+
selected
|
364
|
+
></glide-core-dropdown-option>
|
365
|
+
|
366
|
+
<glide-core-dropdown-option
|
367
|
+
label="Two"
|
368
|
+
value="two"
|
369
|
+
></glide-core-dropdown-option>
|
370
|
+
</glide-core-dropdown>`);
|
371
|
+
const option = component.querySelector('glide-core-dropdown-option');
|
372
|
+
assert(option);
|
373
|
+
option.value = 'three';
|
374
|
+
expect(component.value).to.deep.equal(['three']);
|
375
|
+
});
|
376
|
+
it('updates `value` when the `value` of the selected option is removed programmatically', async () => {
|
377
|
+
const component = await fixture(html `<glide-core-dropdown open>
|
378
|
+
<glide-core-dropdown-option
|
379
|
+
label="One"
|
380
|
+
value="one"
|
381
|
+
selected
|
382
|
+
></glide-core-dropdown-option>
|
383
|
+
|
384
|
+
<glide-core-dropdown-option
|
385
|
+
label="Two"
|
386
|
+
value="two"
|
387
|
+
></glide-core-dropdown-option>
|
388
|
+
</glide-core-dropdown>`);
|
389
|
+
const option = component.querySelector('glide-core-dropdown-option');
|
390
|
+
assert(option);
|
391
|
+
option.value = '';
|
392
|
+
expect(component.value).to.deep.equal([]);
|
393
|
+
});
|
394
|
+
it('updates the its internal label when an option is newly selected', async () => {
|
395
|
+
const component = await fixture(html `<glide-core-dropdown label="Label" placeholder="Placeholder" open>
|
396
|
+
<glide-core-dropdown-option
|
397
|
+
label="One"
|
398
|
+
value="one"
|
399
|
+
></glide-core-dropdown-option>
|
400
|
+
|
401
|
+
<glide-core-dropdown-option
|
402
|
+
label="Two"
|
403
|
+
value="two"
|
404
|
+
></glide-core-dropdown-option>
|
405
|
+
</glide-core-dropdown>`);
|
406
|
+
const option = component.querySelector('glide-core-dropdown-option:last-of-type');
|
407
|
+
option?.click();
|
408
|
+
await elementUpdated(component);
|
409
|
+
const label = component.shadowRoot?.querySelector('[data-test="internal-label"]');
|
410
|
+
expect(label?.textContent?.trim()).to.equal(option?.label);
|
411
|
+
});
|
412
|
+
it('hides Select All', async () => {
|
413
|
+
const component = await fixture(html `<glide-core-dropdown
|
414
|
+
label="Label"
|
415
|
+
placeholder="Placeholder"
|
416
|
+
select-all
|
417
|
+
>
|
418
|
+
<glide-core-dropdown-option
|
419
|
+
label="One"
|
420
|
+
value="one"
|
421
|
+
selected
|
422
|
+
></glide-core-dropdown-option>
|
423
|
+
|
424
|
+
<glide-core-dropdown-option
|
425
|
+
label="Two"
|
426
|
+
value="two"
|
427
|
+
></glide-core-dropdown-option>
|
428
|
+
</glide-core-dropdown>`);
|
429
|
+
const selectAll = component.shadowRoot?.querySelector('[data-test="select-all"]');
|
430
|
+
expect(selectAll?.checkVisibility()).to.not.be.ok;
|
431
|
+
});
|
432
|
+
it('does not select an option on Enter when the option is not focused', async () => {
|
433
|
+
const component = await fixture(html `<glide-core-dropdown label="Label" placeholder="Placeholder" open>
|
434
|
+
<glide-core-dropdown-option
|
435
|
+
label="One"
|
436
|
+
value="one"
|
437
|
+
></glide-core-dropdown-option>
|
438
|
+
|
439
|
+
<glide-core-dropdown-option
|
440
|
+
label="Two"
|
441
|
+
value="two"
|
442
|
+
></glide-core-dropdown-option>
|
443
|
+
</glide-core-dropdown>`);
|
444
|
+
const option = component.querySelector('glide-core-dropdown-option');
|
445
|
+
option?.focus();
|
446
|
+
await sendKeys({ down: 'Tab' });
|
447
|
+
await sendKeys({ down: 'Shift' });
|
448
|
+
await sendKeys({ up: 'Tab' });
|
449
|
+
await sendKeys({ press: 'Enter' });
|
450
|
+
expect(option?.selected).to.be.false;
|
451
|
+
});
|
452
|
+
it('cannot be tabbed to when `disabled`', async () => {
|
453
|
+
await fixture(html `<glide-core-dropdown label="Label" placeholder="Placeholder" disabled>
|
454
|
+
<glide-core-dropdown-option
|
455
|
+
label="One"
|
456
|
+
value="one"
|
457
|
+
></glide-core-dropdown-option>
|
458
|
+
|
459
|
+
<glide-core-dropdown-option
|
460
|
+
label="Two"
|
461
|
+
value="two"
|
462
|
+
></glide-core-dropdown-option>
|
463
|
+
</glide-core-dropdown>`);
|
464
|
+
await sendKeys({ down: 'Tab' });
|
465
|
+
expect(document.activeElement).to.equal(document.body);
|
466
|
+
});
|
@@ -0,0 +1,46 @@
|
|
1
|
+
import './dropdown.option.js';
|
2
|
+
import { expect, fixture, html } from '@open-wc/testing';
|
3
|
+
import GlideCoreDropdown from './dropdown.js';
|
4
|
+
GlideCoreDropdown.shadowRootOptions.mode = 'open';
|
5
|
+
it('is valid if not required and no option is selected', async () => {
|
6
|
+
const component = await fixture(html `<glide-core-dropdown label="Label" placeholder="Placeholder">
|
7
|
+
<glide-core-dropdown-option
|
8
|
+
label="Label"
|
9
|
+
value="value"
|
10
|
+
selected
|
11
|
+
></glide-core-dropdown-option>
|
12
|
+
</glide-core-dropdown>`);
|
13
|
+
expect(component.validity.valid).to.be.true;
|
14
|
+
expect(component.validity?.valueMissing).to.be.false;
|
15
|
+
expect(component.checkValidity()).to.be.true;
|
16
|
+
expect(component.reportValidity()).to.be.true;
|
17
|
+
});
|
18
|
+
it('is invalid if required and no option is selected', async () => {
|
19
|
+
const component = await fixture(html `<glide-core-dropdown label="Label" placeholder="Placeholder" required>
|
20
|
+
<glide-core-dropdown-option
|
21
|
+
label="Label"
|
22
|
+
value="value"
|
23
|
+
></glide-core-dropdown-option>
|
24
|
+
</glide-core-dropdown>`);
|
25
|
+
expect(component.validity.valid).to.be.false;
|
26
|
+
expect(component.validity?.valueMissing).to.be.true;
|
27
|
+
expect(component.checkValidity()).to.be.false;
|
28
|
+
expect(component.reportValidity()).to.be.false;
|
29
|
+
});
|
30
|
+
it('is both invalid and valid if required but disabled and no option is selected', async () => {
|
31
|
+
const component = await fixture(html `<glide-core-dropdown
|
32
|
+
label="Label"
|
33
|
+
placeholder="Placeholder"
|
34
|
+
disabled
|
35
|
+
required
|
36
|
+
>
|
37
|
+
<glide-core-dropdown-option
|
38
|
+
label="Label"
|
39
|
+
value="value"
|
40
|
+
></glide-core-dropdown-option>
|
41
|
+
</glide-core-dropdown>`);
|
42
|
+
expect(component.validity.valid).to.be.false;
|
43
|
+
expect(component.validity?.valueMissing).to.be.true;
|
44
|
+
expect(component.checkValidity()).to.be.true;
|
45
|
+
expect(component.reportValidity()).to.be.true;
|
46
|
+
});
|
package/dist/icon-button.js
CHANGED
@@ -1 +1 @@
|
|
1
|
-
|
1
|
+
var __decorate=this&&this.__decorate||function(t,e,o,r){var l,a=arguments.length,i=a<3?e:null===r?r=Object.getOwnPropertyDescriptor(e,o):r;if("object"==typeof Reflect&&"function"==typeof Reflect.decorate)i=Reflect.decorate(t,e,o,r);else for(var s=t.length-1;s>=0;s--)(l=t[s])&&(i=(a<3?l(i):a>3?l(e,o,i):l(e,o))||i);return a>3&&i&&Object.defineProperty(e,o,i),i};import{LitElement,html}from"lit";import{classMap}from"lit/directives/class-map.js";import{createRef,ref}from"lit/directives/ref.js";import{customElement,property}from"lit/decorators.js";import{owSlot}from"./library/ow.js";import styles from"./icon-button.styles.js";let GlideCoreIconButton=class GlideCoreIconButton extends LitElement{constructor(){super(...arguments),this.ariaExpanded=null,this.ariaHasPopup=null,this.disabled=!1,this.label="",this.variant="primary",this.#t=createRef()}static{this.shadowRootOptions={...LitElement.shadowRootOptions,delegatesFocus:!0,mode:"closed"}}static{this.styles=styles}firstUpdated(){owSlot(this.#t.value)}render(){return html`<button aria-label="${this.label}" class="${classMap({component:!0,primary:"primary"===this.variant,secondary:"secondary"===this.variant,tertiary:"tertiary"===this.variant})}" type="button" ?disabled="${this.disabled}"><slot @slotchange="${this.#e}" ${ref(this.#t)}></slot></button>`}#t;#e(){owSlot(this.#t.value)}};__decorate([property({reflect:!0})],GlideCoreIconButton.prototype,"ariaExpanded",void 0),__decorate([property({reflect:!0})],GlideCoreIconButton.prototype,"ariaHasPopup",void 0),__decorate([property({type:Boolean,reflect:!0})],GlideCoreIconButton.prototype,"disabled",void 0),__decorate([property()],GlideCoreIconButton.prototype,"label",void 0),__decorate([property({reflect:!0})],GlideCoreIconButton.prototype,"variant",void 0),GlideCoreIconButton=__decorate([customElement("glide-core-icon-button")],GlideCoreIconButton);export default GlideCoreIconButton;
|
@@ -1,4 +1,4 @@
|
|
1
|
-
|
1
|
+
import{css}from"lit";import focusOutline from"./styles/focus-outline.js";export default[css`
|
2
2
|
:host {
|
3
3
|
/* Contains elements with "padding" and "width". Inline by default. */
|
4
4
|
display: inline-block;
|
@@ -25,7 +25,7 @@
|
|
25
25
|
}
|
26
26
|
|
27
27
|
&:focus-visible {
|
28
|
-
${
|
28
|
+
${focusOutline};
|
29
29
|
outline-offset: 3px;
|
30
30
|
}
|
31
31
|
|
@@ -109,4 +109,4 @@
|
|
109
109
|
}
|
110
110
|
}
|
111
111
|
}
|
112
|
-
`];
|
112
|
+
`];
|
@@ -0,0 +1,103 @@
|
|
1
|
+
import './icon-button.js';
|
2
|
+
import { ArgumentError } from 'ow';
|
3
|
+
import { expect, fixture, html } from '@open-wc/testing';
|
4
|
+
import GlideCoreIconButton from './icon-button.js';
|
5
|
+
import sinon from 'sinon';
|
6
|
+
GlideCoreIconButton.shadowRootOptions.mode = 'open';
|
7
|
+
const icon = html `<svg
|
8
|
+
width="16"
|
9
|
+
height="16"
|
10
|
+
stroke="currentColor"
|
11
|
+
fill="none"
|
12
|
+
stroke-linecap="round"
|
13
|
+
stroke-linejoin="round"
|
14
|
+
stroke-width="2"
|
15
|
+
viewBox="0 0 24 24"
|
16
|
+
aria-hidden="true"
|
17
|
+
>
|
18
|
+
<path d="M16.51 9.873l-4.459 4.31-4.458-4.31"></path>
|
19
|
+
</svg>`;
|
20
|
+
it('registers', async () => {
|
21
|
+
expect(window.customElements.get('glide-core-icon-button')).to.equal(GlideCoreIconButton);
|
22
|
+
});
|
23
|
+
it('is accessible', async () => {
|
24
|
+
const component = await fixture(html `<glide-core-icon-button label="test-icon-button"
|
25
|
+
>${icon}</glide-core-icon-button
|
26
|
+
>`);
|
27
|
+
await expect(component).to.be.accessible();
|
28
|
+
});
|
29
|
+
it('has defaults', async () => {
|
30
|
+
const component = await fixture(html `<glide-core-icon-button label="test-icon-button"
|
31
|
+
>${icon}</glide-core-icon-button
|
32
|
+
>`);
|
33
|
+
expect(component.shadowRoot?.querySelector('button')?.type).to.equal('button');
|
34
|
+
expect(component.shadowRoot?.querySelector('button')?.disabled).to.equal(false);
|
35
|
+
expect([
|
36
|
+
...component.shadowRoot.querySelector('button').classList,
|
37
|
+
]).to.deep.equal(['component', 'primary']);
|
38
|
+
});
|
39
|
+
it('delegates focus', async () => {
|
40
|
+
const component = await fixture(html `<glide-core-icon-button label="test-icon-button"
|
41
|
+
>${icon}</glide-core-icon-button
|
42
|
+
>`);
|
43
|
+
component.focus();
|
44
|
+
expect(component.shadowRoot?.activeElement).to.equal(component.shadowRoot?.querySelector('button'));
|
45
|
+
});
|
46
|
+
it('uses the provided "label" for the aria-label', async () => {
|
47
|
+
const component = await fixture(html `<glide-core-icon-button label="test-icon-button"
|
48
|
+
>${icon}</glide-core-icon-button
|
49
|
+
>`);
|
50
|
+
expect(component.shadowRoot?.querySelector('button')?.getAttribute('aria-label')).to.equal('test-icon-button');
|
51
|
+
});
|
52
|
+
it('renders a default slot', async () => {
|
53
|
+
const component = await fixture(html `<glide-core-icon-button label="test-icon-button"
|
54
|
+
><span data-content>Inner content</span></glide-core-icon-button
|
55
|
+
>`);
|
56
|
+
expect(component.querySelector('[data-content]')).to.be.ok;
|
57
|
+
expect(component.querySelector('[data-content]')).to.be.visible;
|
58
|
+
});
|
59
|
+
it('renders a primary variant', async () => {
|
60
|
+
const component = await fixture(html `<glide-core-icon-button label="test-icon-button" variant="primary"
|
61
|
+
>${icon}</glide-core-icon-button
|
62
|
+
>`);
|
63
|
+
expect([
|
64
|
+
...component.shadowRoot.querySelector('button').classList,
|
65
|
+
]).to.deep.equal(['component', 'primary']);
|
66
|
+
});
|
67
|
+
it('renders a secondary variant', async () => {
|
68
|
+
const component = await fixture(html `<glide-core-icon-button label="test-icon-button" variant="secondary"
|
69
|
+
>${icon}</glide-core-icon-button
|
70
|
+
>`);
|
71
|
+
expect([
|
72
|
+
...component.shadowRoot.querySelector('button').classList,
|
73
|
+
]).to.deep.equal(['component', 'secondary']);
|
74
|
+
});
|
75
|
+
it('renders a tertiary variant', async () => {
|
76
|
+
const component = await fixture(html `<glide-core-icon-button label="test-icon-button" variant="tertiary"
|
77
|
+
>${icon}</glide-core-icon-button
|
78
|
+
>`);
|
79
|
+
expect([
|
80
|
+
...component.shadowRoot.querySelector('button').classList,
|
81
|
+
]).to.deep.equal(['component', 'tertiary']);
|
82
|
+
});
|
83
|
+
it('sets the disabled attribute', async () => {
|
84
|
+
const component = await fixture(html `<glide-core-icon-button label="test-icon-button" disabled
|
85
|
+
>${icon}</glide-core-icon-button
|
86
|
+
>`);
|
87
|
+
expect(component.disabled).to.equal(true);
|
88
|
+
expect(component.shadowRoot?.querySelector('button')?.disabled).to.equal(true);
|
89
|
+
});
|
90
|
+
it('throws if it does not have a default slot', async () => {
|
91
|
+
const spy = sinon.spy();
|
92
|
+
try {
|
93
|
+
await fixture(html `<glide-core-icon-button
|
94
|
+
label="test-icon-button"
|
95
|
+
></glide-core-icon-button>`);
|
96
|
+
}
|
97
|
+
catch (error) {
|
98
|
+
if (error instanceof ArgumentError) {
|
99
|
+
spy();
|
100
|
+
}
|
101
|
+
}
|
102
|
+
expect(spy.called).to.be.true;
|
103
|
+
});
|
package/dist/icons/checked.js
CHANGED
@@ -1 +1 @@
|
|
1
|
-
|
1
|
+
import{svg}from"lit/static-html.js";export default svg`<svg fill="none" viewBox="0 0 24 24" style="height: var(--size, 0.875rem); width: var(--size, 0.875rem);"><path d="M20 6L9 17L4 12" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"/></svg>`;
|
@@ -1 +1 @@
|
|
1
|
-
|
1
|
+
import{svg}from"lit/static-html.js";export default svg`<svg class="search-icon" fill="none" width="16" height="16" viewBox="0 0 24 24" stroke-width="1.5" stroke="currentColor"><path stroke-linecap="round" stroke-linejoin="round" d="m21 21-5.197-5.197m0 0A7.5 7.5 0 1 0 5.196 5.196a7.5 7.5 0 0 0 10.607 10.607Z"/></svg>`;
|