@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,26 @@
|
|
1
|
+
import { expect, fixture, html } from '@open-wc/testing';
|
2
|
+
import GlideCoreDropdownOption from './dropdown.option.js';
|
3
|
+
GlideCoreDropdownOption.shadowRootOptions.mode = 'open';
|
4
|
+
it('is selected when initially selected', async () => {
|
5
|
+
const component = await fixture(html `<glide-core-dropdown-option
|
6
|
+
label="Label"
|
7
|
+
value="value"
|
8
|
+
private-multiple
|
9
|
+
selected
|
10
|
+
></glide-core-dropdown-option>`);
|
11
|
+
const checkbox = component.shadowRoot?.querySelector('glide-core-checkbox');
|
12
|
+
expect(component.selected).to.be.true;
|
13
|
+
expect(component.ariaSelected).to.equal('true');
|
14
|
+
expect(checkbox?.checked).to.be.true;
|
15
|
+
});
|
16
|
+
it('is deselected when initially deselected', async () => {
|
17
|
+
const component = await fixture(html `<glide-core-dropdown-option
|
18
|
+
label="Label"
|
19
|
+
value="value"
|
20
|
+
private-multiple
|
21
|
+
></glide-core-dropdown-option>`);
|
22
|
+
const checkbox = component.shadowRoot?.querySelector('glide-core-checkbox');
|
23
|
+
expect(component.selected).to.be.false;
|
24
|
+
expect(component.ariaSelected).to.equal('false');
|
25
|
+
expect(checkbox?.checked).to.be.false;
|
26
|
+
});
|
@@ -0,0 +1,20 @@
|
|
1
|
+
import { expect, fixture, html } from '@open-wc/testing';
|
2
|
+
import GlideCoreDropdownOption from './dropdown.option.js';
|
3
|
+
GlideCoreDropdownOption.shadowRootOptions.mode = 'open';
|
4
|
+
it('is selected when initially selected', async () => {
|
5
|
+
const component = await fixture(html `<glide-core-dropdown-option
|
6
|
+
label="Label"
|
7
|
+
value="value"
|
8
|
+
selected
|
9
|
+
></glide-core-dropdown-option>`);
|
10
|
+
expect(component.selected).to.be.true;
|
11
|
+
expect(component.ariaSelected).to.equal('true');
|
12
|
+
});
|
13
|
+
it('is deselected when initially deselected', async () => {
|
14
|
+
const component = await fixture(html `<glide-core-dropdown-option
|
15
|
+
label="Label"
|
16
|
+
value="value"
|
17
|
+
></glide-core-dropdown-option>`);
|
18
|
+
expect(component.selected).to.be.false;
|
19
|
+
expect(component.ariaSelected).to.equal('false');
|
20
|
+
});
|
@@ -0,0 +1,27 @@
|
|
1
|
+
import { expect, fixture, html, oneEvent } from '@open-wc/testing';
|
2
|
+
import GlideCoreDropdownOption from './dropdown.option.js';
|
3
|
+
GlideCoreDropdownOption.shadowRootOptions.mode = 'open';
|
4
|
+
it('dispatches a "private-selected-change" event', async () => {
|
5
|
+
const component = await fixture(html `<glide-core-dropdown-option
|
6
|
+
label="Label"
|
7
|
+
value="value"
|
8
|
+
></glide-core-dropdown-option>`);
|
9
|
+
setTimeout(() => {
|
10
|
+
component.click();
|
11
|
+
});
|
12
|
+
const event = await oneEvent(component, 'private-selected-change');
|
13
|
+
expect(event instanceof Event).to.be.true;
|
14
|
+
expect(event.bubbles).to.be.true;
|
15
|
+
});
|
16
|
+
it('dispatches a "private-value-change" event', async () => {
|
17
|
+
const component = await fixture(html `<glide-core-dropdown-option
|
18
|
+
label="Label"
|
19
|
+
value="value"
|
20
|
+
></glide-core-dropdown-option>`);
|
21
|
+
setTimeout(() => {
|
22
|
+
component.value = '';
|
23
|
+
});
|
24
|
+
const event = await oneEvent(component, 'private-value-change');
|
25
|
+
expect(event instanceof Event).to.be.true;
|
26
|
+
expect(event.bubbles).to.be.true;
|
27
|
+
});
|
@@ -0,0 +1,11 @@
|
|
1
|
+
import { expect, fixture, html } from '@open-wc/testing';
|
2
|
+
import GlideCoreDropdownOption from './dropdown.option.js';
|
3
|
+
GlideCoreDropdownOption.shadowRootOptions.mode = 'open';
|
4
|
+
it('focuses itself when `focus` is called', async () => {
|
5
|
+
const component = await fixture(html `<glide-core-dropdown-option
|
6
|
+
label="Label"
|
7
|
+
value="value"
|
8
|
+
></glide-core-dropdown-option>`);
|
9
|
+
component.focus();
|
10
|
+
expect(document.activeElement).to.equal(component);
|
11
|
+
});
|
@@ -0,0 +1,87 @@
|
|
1
|
+
import { elementUpdated, expect, fixture, html, waitUntil, } from '@open-wc/testing';
|
2
|
+
import GlideCoreCheckbox from './checkbox.js';
|
3
|
+
import GlideCoreDropdownOption from './dropdown.option.js';
|
4
|
+
GlideCoreDropdownOption.shadowRootOptions.mode = 'open';
|
5
|
+
it('is selected on click', async () => {
|
6
|
+
const component = await fixture(html `<glide-core-dropdown-option
|
7
|
+
label="Label"
|
8
|
+
private-multiple
|
9
|
+
></glide-core-dropdown-option>`);
|
10
|
+
component.click();
|
11
|
+
await elementUpdated(component);
|
12
|
+
expect(component.selected).to.be.true;
|
13
|
+
expect(component.ariaSelected).to.equal('true');
|
14
|
+
});
|
15
|
+
it('is deselected on click', async () => {
|
16
|
+
const component = await fixture(html `<glide-core-dropdown-option
|
17
|
+
label="Label"
|
18
|
+
private-multiple
|
19
|
+
selected
|
20
|
+
></glide-core-dropdown-option>`);
|
21
|
+
component.click();
|
22
|
+
await elementUpdated(component);
|
23
|
+
expect(component.selected).to.be.false;
|
24
|
+
expect(component.ariaSelected).to.equal('false');
|
25
|
+
});
|
26
|
+
it('is selected on click when the checkbox itself is clicked', async () => {
|
27
|
+
const component = await fixture(html `<glide-core-dropdown-option
|
28
|
+
label="Label"
|
29
|
+
private-multiple
|
30
|
+
></glide-core-dropdown-option>`);
|
31
|
+
// Checkbox has its own lifecycle. Wait until it's ready.
|
32
|
+
waitUntil(() => {
|
33
|
+
return (component.shadowRoot?.querySelector('[data-test="checkbox"]') instanceof
|
34
|
+
GlideCoreCheckbox);
|
35
|
+
});
|
36
|
+
const checkbox = component.shadowRoot?.querySelector('[data-test="checkbox"]');
|
37
|
+
checkbox?.click();
|
38
|
+
await elementUpdated(component);
|
39
|
+
expect(component.selected).to.be.true;
|
40
|
+
expect(component.ariaSelected).to.equal('true');
|
41
|
+
expect(checkbox?.checked).to.be.true;
|
42
|
+
});
|
43
|
+
it('is deselected on click when the checkbox itself is clicked', async () => {
|
44
|
+
const component = await fixture(html `<glide-core-dropdown-option
|
45
|
+
label="Label"
|
46
|
+
private-multiple
|
47
|
+
selected
|
48
|
+
></glide-core-dropdown-option>`);
|
49
|
+
// Checkbox has its own lifecycle. Wait until it's ready.
|
50
|
+
waitUntil(() => {
|
51
|
+
return (component.shadowRoot?.querySelector('[data-test="checkbox"]') instanceof
|
52
|
+
GlideCoreCheckbox);
|
53
|
+
});
|
54
|
+
const checkbox = component.shadowRoot?.querySelector('[data-test="checkbox"]');
|
55
|
+
checkbox?.click();
|
56
|
+
await elementUpdated(component);
|
57
|
+
expect(component.selected).to.be.false;
|
58
|
+
expect(component.ariaSelected).to.equal('false');
|
59
|
+
expect(checkbox?.checked).to.be.false;
|
60
|
+
});
|
61
|
+
it('is selected when programmatically selected', async () => {
|
62
|
+
const component = await fixture(html `<glide-core-dropdown-option
|
63
|
+
label="Label"
|
64
|
+
value="value"
|
65
|
+
private-multiple
|
66
|
+
></glide-core-dropdown-option>`);
|
67
|
+
component.selected = true;
|
68
|
+
await elementUpdated(component);
|
69
|
+
const checkbox = component.shadowRoot?.querySelector('[data-test="checkbox"]');
|
70
|
+
expect(component.selected).to.be.true;
|
71
|
+
expect(component.ariaSelected).to.equal('true');
|
72
|
+
expect(checkbox?.checked).to.be.true;
|
73
|
+
});
|
74
|
+
it('is deselected when programmatically deselected', async () => {
|
75
|
+
const component = await fixture(html `<glide-core-dropdown-option
|
76
|
+
label="Label"
|
77
|
+
value="value"
|
78
|
+
private-multiple
|
79
|
+
selected
|
80
|
+
></glide-core-dropdown-option>`);
|
81
|
+
component.selected = false;
|
82
|
+
await elementUpdated(component);
|
83
|
+
const checkbox = component.shadowRoot?.querySelector('[data-test="checkbox"]');
|
84
|
+
expect(component.selected).to.be.false;
|
85
|
+
expect(component.ariaSelected).to.equal('false');
|
86
|
+
expect(checkbox?.checked).to.be.false;
|
87
|
+
});
|
@@ -0,0 +1,22 @@
|
|
1
|
+
import { elementUpdated, expect, fixture, html } from '@open-wc/testing';
|
2
|
+
import GlideCoreDropdownOption from './dropdown.option.js';
|
3
|
+
GlideCoreDropdownOption.shadowRootOptions.mode = 'open';
|
4
|
+
it('is selected on click', async () => {
|
5
|
+
const component = await fixture(html `<glide-core-dropdown-option
|
6
|
+
label="Label"
|
7
|
+
></glide-core-dropdown-option>`);
|
8
|
+
component.click();
|
9
|
+
await elementUpdated(component);
|
10
|
+
expect(component.selected).to.be.true;
|
11
|
+
expect(component.ariaSelected).to.equal('true');
|
12
|
+
});
|
13
|
+
it('is selected when programmatically selected', async () => {
|
14
|
+
const component = await fixture(html `<glide-core-dropdown-option
|
15
|
+
label="Label"
|
16
|
+
value="value"
|
17
|
+
></glide-core-dropdown-option>`);
|
18
|
+
component.selected = true;
|
19
|
+
await elementUpdated(component);
|
20
|
+
expect(component.selected).to.be.true;
|
21
|
+
expect(component.ariaSelected).to.equal('true');
|
22
|
+
});
|
package/dist/dropdown.styles.js
CHANGED
@@ -1,10 +1,14 @@
|
|
1
|
-
|
1
|
+
import{css}from"lit";import focusOutline from"./styles/focus-outline.js";import visuallyHidden from"./styles/visually-hidden.js";export default[css`
|
2
2
|
.component {
|
3
3
|
--min-inline-size: 9.375rem;
|
4
4
|
|
5
5
|
font-family: var(--glide-core-font-sans);
|
6
6
|
}
|
7
7
|
|
8
|
+
.selected-option-labels {
|
9
|
+
${visuallyHidden};
|
10
|
+
}
|
11
|
+
|
8
12
|
.dropdown-and-options {
|
9
13
|
display: flex;
|
10
14
|
position: relative;
|
@@ -46,7 +50,7 @@
|
|
46
50
|
}
|
47
51
|
|
48
52
|
&.disabled {
|
49
|
-
background: var(--glide-core-surface-
|
53
|
+
background: var(--glide-core-surface-disabled);
|
50
54
|
color: var(--glide-core-text-tertiary-disabled);
|
51
55
|
}
|
52
56
|
|
@@ -55,15 +59,20 @@
|
|
55
59
|
color: var(--glide-core-status-error);
|
56
60
|
}
|
57
61
|
|
62
|
+
&.readonly {
|
63
|
+
border-color: transparent;
|
64
|
+
padding-inline-start: 0;
|
65
|
+
}
|
66
|
+
|
58
67
|
&:has(.button:focus-visible, .input:focus-visible) {
|
59
|
-
${
|
68
|
+
${focusOutline};
|
60
69
|
}
|
61
70
|
|
62
|
-
&:hover:not(&.error, &.disabled) {
|
71
|
+
&:hover:not(&.error, &.disabled, &.readonly) {
|
63
72
|
border-color: var(--glide-core-border-base);
|
64
73
|
}
|
65
74
|
|
66
|
-
&.quiet:hover:not(&.error, &.disabled, &.multiple) {
|
75
|
+
&.quiet:hover:not(&.error, &.disabled, &.multiple, &.readonly) {
|
67
76
|
background-color: var(--glide-core-surface-hover);
|
68
77
|
}
|
69
78
|
}
|
@@ -130,6 +139,7 @@
|
|
130
139
|
background: none;
|
131
140
|
block-size: var(--button-and-input-height);
|
132
141
|
border: none;
|
142
|
+
cursor: inherit;
|
133
143
|
display: flex;
|
134
144
|
padding: 0;
|
135
145
|
|
@@ -139,8 +149,10 @@
|
|
139
149
|
}
|
140
150
|
|
141
151
|
.input {
|
152
|
+
background-color: transparent;
|
142
153
|
block-size: var(--button-and-input-height);
|
143
154
|
border: none;
|
155
|
+
cursor: inherit;
|
144
156
|
font-size: inherit;
|
145
157
|
min-inline-size: var(--min-inline-size);
|
146
158
|
padding: 0;
|
@@ -159,4 +171,11 @@
|
|
159
171
|
font-family: var(--glide-core-font-sans);
|
160
172
|
}
|
161
173
|
}
|
162
|
-
|
174
|
+
|
175
|
+
.caret-icon {
|
176
|
+
&.disabled,
|
177
|
+
&.readonly {
|
178
|
+
color: var(--glide-core-surface-selected-disabled);
|
179
|
+
}
|
180
|
+
}
|
181
|
+
`];
|
@@ -0,0 +1,84 @@
|
|
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
|
+
const defaultSlot = html `
|
6
|
+
<glide-core-dropdown-option
|
7
|
+
label="One"
|
8
|
+
value="one"
|
9
|
+
></glide-core-dropdown-option>
|
10
|
+
|
11
|
+
<glide-core-dropdown-option
|
12
|
+
label="Two"
|
13
|
+
value="two"
|
14
|
+
></glide-core-dropdown-option>
|
15
|
+
|
16
|
+
<glide-core-dropdown-option
|
17
|
+
label="Three"
|
18
|
+
value="three"
|
19
|
+
></glide-core-dropdown-option>
|
20
|
+
|
21
|
+
<glide-core-dropdown-option
|
22
|
+
label="Four"
|
23
|
+
value="four"
|
24
|
+
></glide-core-dropdown-option>
|
25
|
+
|
26
|
+
<glide-core-dropdown-option
|
27
|
+
label="Five"
|
28
|
+
value="five"
|
29
|
+
></glide-core-dropdown-option>
|
30
|
+
|
31
|
+
<glide-core-dropdown-option
|
32
|
+
label="Six"
|
33
|
+
value="six"
|
34
|
+
></glide-core-dropdown-option>
|
35
|
+
|
36
|
+
<glide-core-dropdown-option
|
37
|
+
label="Seven"
|
38
|
+
value="seven"
|
39
|
+
></glide-core-dropdown-option>
|
40
|
+
|
41
|
+
<glide-core-dropdown-option
|
42
|
+
label="Eight"
|
43
|
+
value="eight"
|
44
|
+
></glide-core-dropdown-option>
|
45
|
+
|
46
|
+
<glide-core-dropdown-option
|
47
|
+
label="Nine"
|
48
|
+
value="nine"
|
49
|
+
></glide-core-dropdown-option>
|
50
|
+
|
51
|
+
<glide-core-dropdown-option
|
52
|
+
label="Ten"
|
53
|
+
value="ten"
|
54
|
+
></glide-core-dropdown-option>
|
55
|
+
|
56
|
+
<glide-core-dropdown-option
|
57
|
+
label="Eleven"
|
58
|
+
value="eleven"
|
59
|
+
></glide-core-dropdown-option>
|
60
|
+
`;
|
61
|
+
it('is accessible', async () => {
|
62
|
+
const component = await fixture(html `<glide-core-dropdown label="Label" placeholder="Placeholder" multiple>
|
63
|
+
${defaultSlot}
|
64
|
+
</glide-core-dropdown>`);
|
65
|
+
await expect(component).to.be.accessible({
|
66
|
+
// Axe doesn't search within slots when determining whether an element
|
67
|
+
// has an ID that matches `aria-activedescendant` exists.
|
68
|
+
ignoredRules: ['aria-valid-attr-value'],
|
69
|
+
});
|
70
|
+
});
|
71
|
+
it('is filterable', async () => {
|
72
|
+
const component = await fixture(html `<glide-core-dropdown label="Label" placeholder="Placeholder" multiple>
|
73
|
+
${defaultSlot}
|
74
|
+
</glide-core-dropdown>`);
|
75
|
+
const input = component.shadowRoot?.querySelector('[data-test="input"]');
|
76
|
+
expect(input?.checkVisibility()).to.be.true;
|
77
|
+
});
|
78
|
+
it('uses `placeholder` as a placeholder when not `multiple` and no option is selected', async () => {
|
79
|
+
const component = await fixture(html `<glide-core-dropdown label="Label" placeholder="Placeholder">
|
80
|
+
${defaultSlot}
|
81
|
+
</glide-core-dropdown>`);
|
82
|
+
const input = component.shadowRoot?.querySelector('[data-test="input"]');
|
83
|
+
expect(input?.placeholder).to.equal('Placeholder');
|
84
|
+
});
|
@@ -0,0 +1,233 @@
|
|
1
|
+
import './dropdown.option.js';
|
2
|
+
import { ArgumentError } from 'ow';
|
3
|
+
import { expect, fixture, html } from '@open-wc/testing';
|
4
|
+
import { repeat } from 'lit/directives/repeat.js';
|
5
|
+
import GlideCoreDropdown from './dropdown.js';
|
6
|
+
import expectArgumentError from './library/expect-argument-error.js';
|
7
|
+
import sinon from 'sinon';
|
8
|
+
// You'll notice quite a few duplicated tests among the "*.single.ts", "*.multiple.ts",
|
9
|
+
// and "*.filterable.ts" test suites. The thinking is that a test warrants
|
10
|
+
// duplication whenever Dropdown's internal logic isn't shared among all three
|
11
|
+
// of those states or if one state goes down a significantly different code path.
|
12
|
+
//
|
13
|
+
// There are still gaps. And there are exceptions to avoid excessive duplication
|
14
|
+
// for the sake of organization. Many of the tests in `dropdown.test.interactions.ts`,
|
15
|
+
// for example, don't apply to the filterable case and so aren't common among all
|
16
|
+
// three states. They nonetheless reside there because moving them out and
|
17
|
+
// duplicating them in both `dropdown.test.interactions.single.ts` and
|
18
|
+
// `dropdown.test.interactions.multiple.ts` would add a ton of test weight.
|
19
|
+
GlideCoreDropdown.shadowRootOptions.mode = 'open';
|
20
|
+
it('registers', async () => {
|
21
|
+
expect(window.customElements.get('glide-core-dropdown')).to.equal(GlideCoreDropdown);
|
22
|
+
});
|
23
|
+
it('has defaults', async () => {
|
24
|
+
// Required attributes are supplied here and thus left unasserted below. The
|
25
|
+
// idea is that this test shouldn't fail to typecheck if these templates are
|
26
|
+
// eventually typechecked, which means supplying all required attributes and slots.
|
27
|
+
const component = await fixture(html `<glide-core-dropdown label="Label" placeholder="Placeholder">
|
28
|
+
<glide-core-dropdown-option
|
29
|
+
label="Label"
|
30
|
+
value="value"
|
31
|
+
></glide-core-dropdown-option>
|
32
|
+
</glide-core-dropdown>`);
|
33
|
+
expect(component.hasAttribute('disabled')).to.be.false;
|
34
|
+
expect(component.disabled).to.equal(false);
|
35
|
+
expect(component.getAttribute('name')).to.be.null;
|
36
|
+
expect(component.name).to.equal(undefined);
|
37
|
+
expect(component.hasAttribute('required')).to.be.false;
|
38
|
+
expect(component.required).to.equal(false);
|
39
|
+
expect(component.getAttribute('size')).to.equal('large');
|
40
|
+
expect(component.size).to.equal('large');
|
41
|
+
// Not reflected, so no attribute assertion is necessary.
|
42
|
+
expect(component.value).to.deep.equal([]);
|
43
|
+
});
|
44
|
+
it('can have a label', async () => {
|
45
|
+
const component = await fixture(html `<glide-core-dropdown label="Label" placeholder="Placeholder">
|
46
|
+
<glide-core-dropdown-option
|
47
|
+
label="Label"
|
48
|
+
value="value"
|
49
|
+
></glide-core-dropdown-option>
|
50
|
+
</glide-core-dropdown>`);
|
51
|
+
expect(component.getAttribute('label')).to.equal('Label');
|
52
|
+
expect(component.label).to.equal('Label');
|
53
|
+
});
|
54
|
+
it('can have a placeholder', async () => {
|
55
|
+
const component = await fixture(html `<glide-core-dropdown label="Label" placeholder="Placeholder">
|
56
|
+
<glide-core-dropdown-option
|
57
|
+
label="Label"
|
58
|
+
value="value"
|
59
|
+
></glide-core-dropdown-option>
|
60
|
+
</glide-core-dropdown>`);
|
61
|
+
expect(component.getAttribute('placeholder')).to.equal('Placeholder');
|
62
|
+
expect(component.placeholder).to.equal('Placeholder');
|
63
|
+
});
|
64
|
+
it('can have a description', async () => {
|
65
|
+
const component = await fixture(html `<glide-core-dropdown label="Label" placeholder="Placeholder">
|
66
|
+
<div slot="description">Description</div>
|
67
|
+
<glide-core-dropdown-option
|
68
|
+
label="Label"
|
69
|
+
value="value"
|
70
|
+
></glide-core-dropdown-option>
|
71
|
+
</glide-core-dropdown>`);
|
72
|
+
const assignedElements = component.shadowRoot
|
73
|
+
?.querySelector('slot[name="description"]')
|
74
|
+
?.assignedElements();
|
75
|
+
expect(assignedElements?.at(0)?.textContent).to.equal('Description');
|
76
|
+
});
|
77
|
+
it('can have a tooltip', async () => {
|
78
|
+
const component = await fixture(html `<glide-core-dropdown label="Label" placeholder="Placeholder">
|
79
|
+
<glide-core-dropdown-option
|
80
|
+
label="Label"
|
81
|
+
value="value"
|
82
|
+
></glide-core-dropdown-option>
|
83
|
+
<div slot="tooltip">Tooltip</div>
|
84
|
+
</glide-core-dropdown>`);
|
85
|
+
const assignedElements = component.shadowRoot
|
86
|
+
?.querySelector('slot[name="tooltip"]')
|
87
|
+
?.assignedElements();
|
88
|
+
expect(assignedElements?.at(0)?.textContent).to.equal('Tooltip');
|
89
|
+
});
|
90
|
+
it('can have a `name`', async () => {
|
91
|
+
const component = await fixture(html `<glide-core-dropdown
|
92
|
+
label="Label"
|
93
|
+
placeholder="Placeholder"
|
94
|
+
name="name"
|
95
|
+
>
|
96
|
+
<glide-core-dropdown-option
|
97
|
+
label="Label"
|
98
|
+
value="value"
|
99
|
+
></glide-core-dropdown-option>
|
100
|
+
</glide-core-dropdown>`);
|
101
|
+
expect(component.getAttribute('name')).to.equal('name');
|
102
|
+
expect(component.name).to.equal('name');
|
103
|
+
});
|
104
|
+
it('can have a `size`', async () => {
|
105
|
+
const component = await fixture(html `<glide-core-dropdown
|
106
|
+
label="Label"
|
107
|
+
placeholder="Placeholder"
|
108
|
+
size="small"
|
109
|
+
>
|
110
|
+
<glide-core-dropdown-option
|
111
|
+
label="Label"
|
112
|
+
value="value"
|
113
|
+
></glide-core-dropdown-option>
|
114
|
+
</glide-core-dropdown>`);
|
115
|
+
expect(component.getAttribute('size')).to.equal('small');
|
116
|
+
expect(component.size).to.equal('small');
|
117
|
+
const option = component.querySelector('glide-core-dropdown-option');
|
118
|
+
expect(option?.privateSize).to.equal('small');
|
119
|
+
});
|
120
|
+
it('can be `disabled`', async () => {
|
121
|
+
const component = await fixture(html `<glide-core-dropdown label="Label" placeholder="Placeholder" disabled>
|
122
|
+
<glide-core-dropdown-option
|
123
|
+
label="Label"
|
124
|
+
value="value"
|
125
|
+
></glide-core-dropdown-option>
|
126
|
+
</glide-core-dropdown>`);
|
127
|
+
expect(component.hasAttribute('disabled')).to.be.true;
|
128
|
+
expect(component.disabled).to.equal(true);
|
129
|
+
});
|
130
|
+
it('can be `required`', async () => {
|
131
|
+
const component = await fixture(html `<glide-core-dropdown label="Label" placeholder="Placeholder" required>
|
132
|
+
<glide-core-dropdown-option
|
133
|
+
label="Label"
|
134
|
+
value="value"
|
135
|
+
></glide-core-dropdown-option>
|
136
|
+
</glide-core-dropdown>`);
|
137
|
+
expect(component.hasAttribute('required')).to.be.true;
|
138
|
+
expect(component.required).to.equal(true);
|
139
|
+
});
|
140
|
+
it('can be `multiple`', async () => {
|
141
|
+
const component = await fixture(html `<glide-core-dropdown label="Label" placeholder="Placeholder" multiple>
|
142
|
+
<glide-core-dropdown-option
|
143
|
+
label="One"
|
144
|
+
value="one"
|
145
|
+
></glide-core-dropdown-option>
|
146
|
+
|
147
|
+
<glide-core-dropdown-option
|
148
|
+
label="Two"
|
149
|
+
value="two"
|
150
|
+
></glide-core-dropdown-option>
|
151
|
+
</glide-core-dropdown>`);
|
152
|
+
expect(component.hasAttribute('multiple')).to.be.true;
|
153
|
+
expect(component.multiple).to.equal(true);
|
154
|
+
});
|
155
|
+
it('can be `select-all`', async () => {
|
156
|
+
const component = await fixture(html `<glide-core-dropdown
|
157
|
+
label="Label"
|
158
|
+
placeholder="Placeholder"
|
159
|
+
multiple
|
160
|
+
select-all
|
161
|
+
>
|
162
|
+
<glide-core-dropdown-option
|
163
|
+
label="Label"
|
164
|
+
value="value"
|
165
|
+
></glide-core-dropdown-option>
|
166
|
+
</glide-core-dropdown>`);
|
167
|
+
expect(component.hasAttribute('select-all')).to.be.true;
|
168
|
+
expect(component.selectAll).to.equal(true);
|
169
|
+
});
|
170
|
+
it('activates the first option when no options are initially selected', async () => {
|
171
|
+
const component = await fixture(html `<glide-core-dropdown open>
|
172
|
+
<glide-core-dropdown-option
|
173
|
+
label="One"
|
174
|
+
value="one"
|
175
|
+
></glide-core-dropdown-option>
|
176
|
+
|
177
|
+
<glide-core-dropdown-option
|
178
|
+
label="Two"
|
179
|
+
value="two"
|
180
|
+
></glide-core-dropdown-option>
|
181
|
+
</glide-core-dropdown>`);
|
182
|
+
const options = component.querySelectorAll('glide-core-dropdown-option');
|
183
|
+
expect(options[0]?.privateActive).to.be.true;
|
184
|
+
expect(options[1]?.privateActive).to.be.false;
|
185
|
+
});
|
186
|
+
it('activates the last selected option when options are initially selected', async () => {
|
187
|
+
const component = await fixture(html `<glide-core-dropdown open>
|
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
|
+
selected
|
197
|
+
></glide-core-dropdown-option>
|
198
|
+
|
199
|
+
<glide-core-dropdown-option
|
200
|
+
label="Three"
|
201
|
+
value="three"
|
202
|
+
selected
|
203
|
+
></glide-core-dropdown-option>
|
204
|
+
</glide-core-dropdown>`);
|
205
|
+
const options = component.querySelectorAll('glide-core-dropdown-option');
|
206
|
+
expect(options[0]?.privateActive).to.be.false;
|
207
|
+
expect(options[1]?.privateActive).to.be.false;
|
208
|
+
expect(options[2]?.privateActive).to.be.true;
|
209
|
+
});
|
210
|
+
it('throws if the default slot is the incorrect type', async () => {
|
211
|
+
await expectArgumentError(() => {
|
212
|
+
return fixture(html `<glide-core-dropdown label="Label" placeholder="Placeholder">
|
213
|
+
<button>Button</button>
|
214
|
+
</glide-core-dropdown>`);
|
215
|
+
});
|
216
|
+
});
|
217
|
+
it('does not throw if the default slot only contains whitespace', async () => {
|
218
|
+
const spy = sinon.spy();
|
219
|
+
try {
|
220
|
+
await fixture(html `<glide-core-dropdown label="Label" placeholder="Placeholder">
|
221
|
+
${repeat([], () => html `<glide-core-dropdown-option
|
222
|
+
label="Option"
|
223
|
+
value="option"
|
224
|
+
></glide-core-dropdown-option>`)}
|
225
|
+
</glide-core-dropdown>`);
|
226
|
+
}
|
227
|
+
catch (error) {
|
228
|
+
if (error instanceof ArgumentError) {
|
229
|
+
spy();
|
230
|
+
}
|
231
|
+
}
|
232
|
+
expect(spy.notCalled).to.be.true;
|
233
|
+
});
|