@crowdstrike/glide-core 0.5.1 → 0.6.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 +11 -1
- package/dist/accordion.js +1 -1
- package/dist/accordion.styles.js +5 -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 +6 -5
- 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.d.ts +3 -2
- package/dist/button.js +1 -1
- package/dist/button.styles.js +5 -5
- package/dist/button.test.basics.js +202 -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 +7 -4
- 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 +14 -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.floating-components.d.ts +1 -0
- package/dist/drawer.test.floating-components.js +51 -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 +82 -0
- package/dist/dropdown.option.test.interactions.single.js +22 -0
- package/dist/dropdown.styles.js +26 -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 +28 -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 +449 -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.d.ts +3 -2
- package/dist/icon-button.js +1 -1
- package/dist/icon-button.styles.js +12 -12
- package/dist/icon-button.test.basics.js +110 -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 +4 -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 +13 -15
- package/dist/label.test.basics.js +129 -0
- package/dist/library/expect-argument-error.js +1 -1
- package/dist/library/localize.d.ts +17 -0
- package/dist/library/localize.js +1 -0
- package/dist/library/ow.js +1 -1
- package/dist/library/ow.test.js +55 -0
- package/dist/library/set-containing-block.d.ts +15 -0
- package/dist/library/set-containing-block.js +1 -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 +7 -2
- 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.options.d.ts +22 -0
- package/dist/menu.options.js +1 -0
- package/dist/menu.options.styles.d.ts +2 -0
- package/dist/menu.options.styles.js +33 -0
- package/dist/menu.options.test.basics.d.ts +2 -0
- package/dist/menu.options.test.basics.js +43 -0
- package/dist/menu.stories.d.ts +1 -0
- package/dist/menu.styles.js +7 -31
- package/dist/menu.test.basics.d.ts +1 -0
- package/dist/menu.test.basics.js +183 -0
- package/dist/menu.test.focus.d.ts +0 -1
- package/dist/menu.test.focus.js +84 -0
- package/dist/menu.test.interactions.d.ts +1 -1
- package/dist/menu.test.interactions.js +664 -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 -7
- package/dist/modal.tertiary-icon.d.ts +1 -0
- 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.floating-components.d.ts +1 -0
- package/dist/modal.test.floating-components.js +62 -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 +20 -24
- 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 +14 -31
- package/dist/split-button.d.ts +27 -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 +102 -0
- package/dist/split-button.test.basics.d.ts +1 -0
- package/dist/split-button.test.basics.js +99 -0
- package/dist/split-container.d.ts +31 -0
- package/dist/split-container.js +1 -0
- package/dist/split-container.styles.d.ts +2 -0
- package/dist/split-container.styles.js +134 -0
- package/dist/split-container.test.basics.d.ts +3 -0
- package/dist/split-container.test.basics.js +440 -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/variables.css +1 -1
- 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 +80 -55
- package/dist/tab.test.basics.js +71 -0
- package/dist/tag.js +1 -1
- package/dist/tag.styles.js +4 -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/tag.test.translations.d.ts +1 -0
- package/dist/tag.test.translations.js +25 -0
- package/dist/textarea.js +2 -2
- package/dist/textarea.styles.js +5 -4
- 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 +68 -0
- package/dist/toggle.test.events.js +29 -0
- package/dist/toggle.test.focus.js +9 -0
- package/dist/toggle.test.states.js +43 -0
- package/dist/tooltip.d.ts +2 -0
- package/dist/tooltip.js +1 -1
- package/dist/tooltip.styles.js +5 -3
- package/dist/tooltip.test.basics.js +64 -0
- package/dist/tooltip.test.interactions.js +78 -0
- package/dist/translations/en.d.ts +3 -0
- package/dist/translations/en.js +1 -0
- package/dist/translations/fr.d.ts +3 -0
- package/dist/translations/fr.js +1 -0
- package/dist/translations/ja.d.ts +3 -0
- package/dist/translations/ja.js +1 -0
- package/dist/tree.d.ts +1 -0
- package/dist/tree.item.d.ts +3 -1
- 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.d.ts +2 -0
- 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 +33 -0
- package/dist/tree.item.styles.js +23 -8
- package/dist/tree.item.test.basics.js +102 -0
- package/dist/tree.js +1 -1
- package/dist/tree.stories.d.ts +1 -0
- 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 +25 -18
- /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,228 @@
|
|
1
|
+
import { elementUpdated, expect, fixture, html } from '@open-wc/testing';
|
2
|
+
import GlideCoreRadio from './radio.js';
|
3
|
+
import GlideCoreRadioGroup from './radio-group.js';
|
4
|
+
GlideCoreRadio.shadowRootOptions.mode = 'open';
|
5
|
+
GlideCoreRadioGroup.shadowRootOptions.mode = 'open';
|
6
|
+
it('is valid if not required and radios are unchecked', async () => {
|
7
|
+
const component = await fixture(html `<glide-core-radio-group label="label" name="name">
|
8
|
+
<glide-core-radio value="value-1" label="One"></glide-core-radio>
|
9
|
+
<glide-core-radio value="value-2" label="Two"></glide-core-radio>
|
10
|
+
</glide-core-radio-group>`);
|
11
|
+
expect(component.validity.valid).to.be.true;
|
12
|
+
expect(component.validity?.valueMissing).to.be.false;
|
13
|
+
expect(component.checkValidity()).to.be.true;
|
14
|
+
expect(component.reportValidity()).to.be.true;
|
15
|
+
const radios = component.querySelectorAll('glide-core-radio');
|
16
|
+
expect(radios[0]?.invalid).to.be.false;
|
17
|
+
expect(radios[0]?.ariaInvalid).to.equal('false');
|
18
|
+
expect(radios[1]?.invalid).to.be.false;
|
19
|
+
expect(radios[1]?.ariaInvalid).to.equal('false');
|
20
|
+
});
|
21
|
+
it('is valid if required and a radio is checked', async () => {
|
22
|
+
const component = await fixture(html `<glide-core-radio-group label="label" name="name" required>
|
23
|
+
<glide-core-radio value="value-1" label="One"></glide-core-radio>
|
24
|
+
<glide-core-radio value="value-2" checked label="Two"></glide-core-radio>
|
25
|
+
</glide-core-radio-group>`);
|
26
|
+
expect(component.validity.valid).to.be.true;
|
27
|
+
expect(component.validity?.valueMissing).to.be.false;
|
28
|
+
expect(component.checkValidity()).to.be.true;
|
29
|
+
expect(component.reportValidity()).to.be.true;
|
30
|
+
const radios = component.querySelectorAll('glide-core-radio');
|
31
|
+
expect(radios[0]?.invalid).to.be.false;
|
32
|
+
expect(radios[0]?.ariaInvalid).to.equal('false');
|
33
|
+
expect(radios[1]?.invalid).to.be.false;
|
34
|
+
expect(radios[1]?.ariaInvalid).to.equal('false');
|
35
|
+
});
|
36
|
+
it('is invalid if required and no radio is checked', async () => {
|
37
|
+
const component = await fixture(html `<glide-core-radio-group label="label" name="name" required>
|
38
|
+
<glide-core-radio value="value-1" label="One"></glide-core-radio>
|
39
|
+
<glide-core-radio value="value-2" label="Two"></glide-core-radio>
|
40
|
+
</glide-core-radio-group>`);
|
41
|
+
expect(component.validity.valid).to.be.false;
|
42
|
+
expect(component.validity?.valueMissing).to.be.true;
|
43
|
+
expect(component.checkValidity()).to.be.false;
|
44
|
+
expect(component.reportValidity()).to.be.false;
|
45
|
+
});
|
46
|
+
it('is both invalid and valid if required but disabled and no radio is checked', async () => {
|
47
|
+
const component = await fixture(html `<glide-core-radio-group label="label" name="name" required disabled>
|
48
|
+
<glide-core-radio value="value-1" label="One"></glide-core-radio>
|
49
|
+
<glide-core-radio value="value-2" label="Two"></glide-core-radio>
|
50
|
+
</glide-core-radio-group>`);
|
51
|
+
expect(component.validity.valid).to.be.false;
|
52
|
+
expect(component.validity?.valueMissing).to.be.true;
|
53
|
+
expect(component.checkValidity()).to.be.true;
|
54
|
+
expect(component.reportValidity()).to.be.true;
|
55
|
+
});
|
56
|
+
it('adds an error class after submit when invalid and required', async () => {
|
57
|
+
const form = document.createElement('form');
|
58
|
+
const component = await fixture(html `<glide-core-radio-group label="label" name="name" required>
|
59
|
+
<glide-core-radio value="value-1" label="One"></glide-core-radio>
|
60
|
+
<glide-core-radio value="value-2" label="Two"></glide-core-radio>
|
61
|
+
</glide-core-radio-group>`, { parentNode: form });
|
62
|
+
form.requestSubmit();
|
63
|
+
await elementUpdated(component);
|
64
|
+
const isComponentErrorClass = component.shadowRoot
|
65
|
+
?.querySelector('.radio-container')
|
66
|
+
?.classList.contains('invalid');
|
67
|
+
expect(isComponentErrorClass).to.be.true;
|
68
|
+
});
|
69
|
+
it('adds an error class after `reportValidity` is called when invalid and required', async () => {
|
70
|
+
const form = document.createElement('form');
|
71
|
+
const component = await fixture(html `<glide-core-radio-group label="label" name="name" required>
|
72
|
+
<glide-core-radio value="value-1" label="One"></glide-core-radio>
|
73
|
+
<glide-core-radio value="value-2" label="Two"></glide-core-radio>
|
74
|
+
</glide-core-radio-group>`, { parentNode: form });
|
75
|
+
component.reportValidity();
|
76
|
+
await elementUpdated(component);
|
77
|
+
const isComponentErrorClass = component.shadowRoot
|
78
|
+
?.querySelector('.radio-container')
|
79
|
+
?.classList.contains('invalid');
|
80
|
+
expect(isComponentErrorClass).to.be.true;
|
81
|
+
const radios = document.querySelectorAll('glide-core-radio');
|
82
|
+
expect(radios[0]?.invalid).to.be.true;
|
83
|
+
expect(radios[0]).to.have.attribute('aria-invalid', 'true');
|
84
|
+
expect(radios[1]?.invalid).to.be.true;
|
85
|
+
expect(radios[1]).to.have.attribute('aria-invalid', 'true');
|
86
|
+
});
|
87
|
+
it('does not add an error class by default', async () => {
|
88
|
+
const form = document.createElement('form');
|
89
|
+
const component = await fixture(html `<glide-core-radio-group label="label" name="name" required>
|
90
|
+
<glide-core-radio value="value-1" label="One"></glide-core-radio>
|
91
|
+
<glide-core-radio value="value-2" label="Two"></glide-core-radio>
|
92
|
+
</glide-core-radio-group>`, { parentNode: form });
|
93
|
+
const isComponentErrorClass = component.shadowRoot
|
94
|
+
?.querySelector('.radio-container')
|
95
|
+
?.classList.contains('invalid');
|
96
|
+
expect(isComponentErrorClass).to.be.false;
|
97
|
+
const radios = document.querySelectorAll('glide-core-radio');
|
98
|
+
let isRadioError = radios[0].shadowRoot
|
99
|
+
?.querySelector('[data-test="radio"]')
|
100
|
+
?.classList.contains('invalid');
|
101
|
+
expect(isRadioError).to.be.false;
|
102
|
+
isRadioError = radios[1].shadowRoot
|
103
|
+
?.querySelector('[data-test="radio"]')
|
104
|
+
?.classList.contains('invalid');
|
105
|
+
expect(isRadioError).to.be.false;
|
106
|
+
expect(radios[0]?.invalid).to.be.false;
|
107
|
+
expect(radios[0]).to.have.attribute('aria-invalid', 'false');
|
108
|
+
expect(radios[1]?.invalid).to.be.false;
|
109
|
+
expect(radios[1]).to.have.attribute('aria-invalid', 'false');
|
110
|
+
});
|
111
|
+
it('does not add an error class after `reportValidity` is called when not required', async () => {
|
112
|
+
const form = document.createElement('form');
|
113
|
+
const component = await fixture(html `<glide-core-radio-group label="label" name="name">
|
114
|
+
<glide-core-radio value="value-1" label="One"></glide-core-radio>
|
115
|
+
<glide-core-radio value="value-2" label="Two"></glide-core-radio>
|
116
|
+
</glide-core-radio-group>`, { parentNode: form });
|
117
|
+
component.reportValidity();
|
118
|
+
await elementUpdated(component);
|
119
|
+
const isComponentErrorClass = component.shadowRoot
|
120
|
+
?.querySelector('.radio-container')
|
121
|
+
?.classList.contains('invalid');
|
122
|
+
expect(isComponentErrorClass).to.be.false;
|
123
|
+
const radios = document.querySelectorAll('glide-core-radio');
|
124
|
+
let isRadioError = radios[0].shadowRoot
|
125
|
+
?.querySelector('[data-test="radio"]')
|
126
|
+
?.classList.contains('invalid');
|
127
|
+
expect(isRadioError).to.be.false;
|
128
|
+
isRadioError = radios[1].shadowRoot
|
129
|
+
?.querySelector('[data-test="radio"]')
|
130
|
+
?.classList.contains('invalid');
|
131
|
+
expect(isRadioError).to.be.false;
|
132
|
+
expect(radios[0]?.invalid).to.be.false;
|
133
|
+
expect(radios[0]).to.have.attribute('aria-invalid', 'false');
|
134
|
+
expect(radios[1]?.invalid).to.be.false;
|
135
|
+
expect(radios[1]).to.have.attribute('aria-invalid', 'false');
|
136
|
+
});
|
137
|
+
it('does not add an error class after `reportValidity` is called when required and a radio is checked', async () => {
|
138
|
+
const form = document.createElement('form');
|
139
|
+
const component = await fixture(html `<glide-core-radio-group label="label" name="name" required>
|
140
|
+
<glide-core-radio value="value-1" label="One"></glide-core-radio>
|
141
|
+
<glide-core-radio value="value-2" checked label="Two"></glide-core-radio>
|
142
|
+
</glide-core-radio-group>`, { parentNode: form });
|
143
|
+
component.reportValidity();
|
144
|
+
await elementUpdated(component);
|
145
|
+
const isComponentErrorClass = component.shadowRoot
|
146
|
+
?.querySelector('.radio-container')
|
147
|
+
?.classList.contains('invalid');
|
148
|
+
expect(isComponentErrorClass).to.be.false;
|
149
|
+
const radios = document.querySelectorAll('glide-core-radio');
|
150
|
+
let isRadioError = radios[0].shadowRoot
|
151
|
+
?.querySelector('[data-test="radio"]')
|
152
|
+
?.classList.contains('invalid');
|
153
|
+
expect(isRadioError).to.be.false;
|
154
|
+
isRadioError = radios[1].shadowRoot
|
155
|
+
?.querySelector('[data-test="radio"]')
|
156
|
+
?.classList.contains('invalid');
|
157
|
+
expect(isRadioError).to.be.false;
|
158
|
+
expect(radios[0]?.invalid).to.be.false;
|
159
|
+
expect(radios[0]).to.have.attribute('aria-invalid', 'false');
|
160
|
+
expect(radios[1]?.invalid).to.be.false;
|
161
|
+
expect(radios[1]).to.have.attribute('aria-invalid', 'false');
|
162
|
+
});
|
163
|
+
it('does not add an error class after `reportValidity` is called when required but disabled', async () => {
|
164
|
+
const form = document.createElement('form');
|
165
|
+
const component = await fixture(html `<glide-core-radio-group label="label" name="name" required disabled>
|
166
|
+
<glide-core-radio value="value-1" label="One"></glide-core-radio>
|
167
|
+
<glide-core-radio value="value-2" checked label="Two"></glide-core-radio>
|
168
|
+
</glide-core-radio-group>`, { parentNode: form });
|
169
|
+
component.reportValidity();
|
170
|
+
await elementUpdated(component);
|
171
|
+
const isComponentErrorClass = component.shadowRoot
|
172
|
+
?.querySelector('.radio-container')
|
173
|
+
?.classList.contains('invalid');
|
174
|
+
expect(isComponentErrorClass).to.be.false;
|
175
|
+
const radios = document.querySelectorAll('glide-core-radio');
|
176
|
+
let isRadioError = radios[0].shadowRoot
|
177
|
+
?.querySelector('[data-test="radio"]')
|
178
|
+
?.classList.contains('invalid');
|
179
|
+
expect(isRadioError).to.be.false;
|
180
|
+
isRadioError = radios[1].shadowRoot
|
181
|
+
?.querySelector('[data-test="radio"]')
|
182
|
+
?.classList.contains('invalid');
|
183
|
+
expect(isRadioError).to.be.false;
|
184
|
+
expect(radios[0]?.invalid).to.be.false;
|
185
|
+
expect(radios[0]).to.have.attribute('aria-invalid', 'false');
|
186
|
+
expect(radios[1]?.invalid).to.be.false;
|
187
|
+
expect(radios[1]).to.have.attribute('aria-invalid', 'false');
|
188
|
+
});
|
189
|
+
it('does not add an error class after `checkValidity` is called when required', async () => {
|
190
|
+
const form = document.createElement('form');
|
191
|
+
const component = await fixture(html `<glide-core-radio-group label="label" name="name" required>
|
192
|
+
<glide-core-radio value="value-1" label="One"></glide-core-radio>
|
193
|
+
<glide-core-radio value="value-2" label="Two"></glide-core-radio>
|
194
|
+
</glide-core-radio-group>`, { parentNode: form });
|
195
|
+
component.checkValidity();
|
196
|
+
await elementUpdated(component);
|
197
|
+
const isComponentErrorClass = component.shadowRoot
|
198
|
+
?.querySelector('.radio-container')
|
199
|
+
?.classList.contains('invalid');
|
200
|
+
expect(isComponentErrorClass).to.be.false;
|
201
|
+
const radios = document.querySelectorAll('glide-core-radio');
|
202
|
+
let isRadioError = radios[0].shadowRoot
|
203
|
+
?.querySelector('[data-test="radio"]')
|
204
|
+
?.classList.contains('invalid');
|
205
|
+
expect(isRadioError).to.be.false;
|
206
|
+
isRadioError = radios[1].shadowRoot
|
207
|
+
?.querySelector('[data-test="radio"]')
|
208
|
+
?.classList.contains('invalid');
|
209
|
+
expect(isRadioError).to.be.false;
|
210
|
+
expect(radios[0]?.invalid).to.be.false;
|
211
|
+
expect(radios[0]).to.have.attribute('aria-invalid', 'false');
|
212
|
+
expect(radios[1]?.invalid).to.be.false;
|
213
|
+
expect(radios[1]).to.have.attribute('aria-invalid', 'false');
|
214
|
+
});
|
215
|
+
it('sets radios as valid initially when required', async () => {
|
216
|
+
const form = document.createElement('form');
|
217
|
+
const component = await fixture(html `<glide-core-radio-group label="label" name="name" required>
|
218
|
+
<glide-core-radio value="value-1" label="One"></glide-core-radio>
|
219
|
+
<glide-core-radio value="value-2" label="Two"></glide-core-radio>
|
220
|
+
</glide-core-radio-group>`, { parentNode: form });
|
221
|
+
component.required = false;
|
222
|
+
await elementUpdated(component);
|
223
|
+
const radios = component.querySelectorAll('glide-core-radio');
|
224
|
+
expect(radios[0]?.invalid).to.be.false;
|
225
|
+
expect(radios[0]?.ariaInvalid).to.equal('false');
|
226
|
+
expect(radios[1]?.invalid).to.be.false;
|
227
|
+
expect(radios[1]?.ariaInvalid).to.equal('false');
|
228
|
+
});
|
package/dist/radio.js
CHANGED
@@ -1 +1 @@
|
|
1
|
-
|
1
|
+
var __decorate=this&&this.__decorate||function(e,t,i,r){var o,a=arguments.length,d=a<3?t:null===r?r=Object.getOwnPropertyDescriptor(t,i):r;if("object"==typeof Reflect&&"function"==typeof Reflect.decorate)d=Reflect.decorate(e,t,i,r);else for(var s=e.length-1;s>=0;s--)(o=e[s])&&(d=(a<3?o(d):a>3?o(t,i,d):o(t,i))||d);return a>3&&d&&Object.defineProperty(t,i,d),d};import{LitElement,html}from"lit";import{classMap}from"lit/directives/class-map.js";import{customElement,property}from"lit/decorators.js";import styles from"./radio.styles.js";let GlideCoreRadio=class GlideCoreRadio extends LitElement{constructor(){super(...arguments),this.checked=!1,this.disabled=!1,this.invalid=!1,this.required=!1,this.value="",this.label=""}static{this.shadowRootOptions={...LitElement.shadowRootOptions,mode:"closed"}}static{this.styles=styles}firstUpdated(){this.role="radio",this.ariaChecked=this.checked.toString(),this.ariaDisabled=this.disabled.toString(),this.ariaInvalid=this.invalid.toString(),this.ariaRequired=this.required.toString(),this.ariaLabel=this.label}render(){return html`<span class="${classMap({component:!0,disabled:this.disabled})}"><span id="radio" class="${classMap({"radio-circle":!0,checked:this.checked})}" data-test="radio" data-test-error="${this.invalid}"></span> ${this.label}</span>`}willUpdate(e){this.hasUpdated&&(e.has("checked")&&(this.ariaChecked=this.checked.toString()),e.has("disabled")&&(this.ariaDisabled=this.disabled.toString()),e.has("required")&&(this.ariaRequired=this.required.toString()),e.has("invalid")&&(this.ariaInvalid=this.invalid.toString()),e.has("label")&&(this.ariaLabel=this.label))}};__decorate([property({type:Boolean,reflect:!0})],GlideCoreRadio.prototype,"checked",void 0),__decorate([property({type:Boolean,reflect:!0})],GlideCoreRadio.prototype,"disabled",void 0),__decorate([property({type:Boolean})],GlideCoreRadio.prototype,"invalid",void 0),__decorate([property({type:Boolean,reflect:!0})],GlideCoreRadio.prototype,"required",void 0),__decorate([property()],GlideCoreRadio.prototype,"value",void 0),__decorate([property({reflect:!0})],GlideCoreRadio.prototype,"label",void 0),GlideCoreRadio=__decorate([customElement("glide-core-radio")],GlideCoreRadio);export default GlideCoreRadio;
|
package/dist/radio.styles.js
CHANGED
@@ -1,18 +1,13 @@
|
|
1
|
-
|
1
|
+
import{css}from"lit";import focusOutline from"./styles/focus-outline.js";export default[css`
|
2
2
|
:host {
|
3
3
|
display: flex;
|
4
|
+
outline: none;
|
4
5
|
}
|
5
6
|
|
7
|
+
/* Using nesting creates an issue on Safari with :host */
|
6
8
|
/* stylelint-disable-next-line csstools/use-nesting */
|
7
|
-
:host(:focus-visible) {
|
8
|
-
|
9
|
-
|
10
|
-
& .component .radio-circle {
|
11
|
-
box-shadow: var(--glide-core-glow-sm);
|
12
|
-
|
13
|
-
${r};
|
14
|
-
outline-offset: 4px;
|
15
|
-
}
|
9
|
+
:host(:focus-visible) .component .radio-circle {
|
10
|
+
${focusOutline};
|
16
11
|
}
|
17
12
|
|
18
13
|
.component {
|
@@ -25,45 +20,33 @@
|
|
25
20
|
& .radio-circle {
|
26
21
|
align-items: center;
|
27
22
|
appearance: none;
|
28
|
-
|
29
|
-
block-size: 0.875rem;
|
23
|
+
block-size: 1rem;
|
30
24
|
border: 1px solid var(--glide-core-border-base-dark);
|
31
25
|
border-radius: 50%;
|
32
26
|
box-sizing: border-box;
|
33
27
|
content: ' ';
|
34
28
|
display: inline-flex;
|
35
|
-
inline-size:
|
29
|
+
inline-size: 1rem;
|
36
30
|
margin: 0;
|
37
31
|
margin-inline-end: 0.625rem;
|
38
|
-
min-inline-size:
|
32
|
+
min-inline-size: 1rem;
|
39
33
|
padding: 0;
|
40
34
|
position: relative;
|
41
35
|
|
42
36
|
&.checked {
|
37
|
+
background-color: var(--glide-core-color-white);
|
43
38
|
border-color: var(--glide-core-surface-primary);
|
44
39
|
|
45
40
|
&::after {
|
46
41
|
background-color: var(--glide-core-surface-primary);
|
47
|
-
|
48
|
-
/*
|
49
|
-
svg in figma has viewbox 16px, with inner circle radius of 8px, however figma element has height & width of 14px;
|
50
|
-
14px = 0.875rem;
|
51
|
-
8px * 0.875 = 7px = 0.4375rem;
|
52
|
-
*/
|
53
|
-
block-size: 0.4375rem;
|
42
|
+
block-size: 0.5rem;
|
54
43
|
border-radius: 50%;
|
55
44
|
box-sizing: border-box;
|
56
45
|
content: ' ';
|
57
46
|
display: block;
|
58
|
-
inline-size: 0.
|
59
|
-
|
60
|
-
|
61
|
-
svg in figma has viewbox 16px, however figma element has height & width of 14px;
|
62
|
-
14px/16px = 0.875;
|
63
|
-
4px radius * 0.875 = 3.5px = 0.21875rem;
|
64
|
-
*/
|
65
|
-
inset-block-start: calc(50% - 0.2187rem);
|
66
|
-
inset-inline-start: calc(50% - 0.2187rem);
|
47
|
+
inline-size: 0.5rem;
|
48
|
+
inset-block-start: calc(50% - 0.25rem);
|
49
|
+
inset-inline-start: calc(50% - 0.25rem);
|
67
50
|
position: absolute;
|
68
51
|
}
|
69
52
|
}
|
@@ -89,4 +72,4 @@
|
|
89
72
|
}
|
90
73
|
}
|
91
74
|
}
|
92
|
-
`];
|
75
|
+
`];
|
@@ -0,0 +1,27 @@
|
|
1
|
+
import './menu.js';
|
2
|
+
import { LitElement } from 'lit';
|
3
|
+
declare global {
|
4
|
+
interface HTMLElementTagNameMap {
|
5
|
+
'glide-core-split-button': GlideCoreSplitButton;
|
6
|
+
}
|
7
|
+
}
|
8
|
+
/**
|
9
|
+
* @description A button to be used in the `primary-action` slot of `glide-core-split-container`.
|
10
|
+
*
|
11
|
+
* @slot prefix - An optional icon slot to display before the label.
|
12
|
+
* @slot - A label for the contents of the button.
|
13
|
+
*/
|
14
|
+
export default class GlideCoreSplitButton extends LitElement {
|
15
|
+
#private;
|
16
|
+
static shadowRootOptions: ShadowRootInit;
|
17
|
+
static styles: import("lit").CSSResult[];
|
18
|
+
ariaControls: string | null;
|
19
|
+
ariaExpanded: 'true' | 'false' | null;
|
20
|
+
ariaHasPopup: 'true' | 'false' | 'menu' | 'listbox' | 'tree' | 'grid' | 'dialog' | null;
|
21
|
+
disabled: boolean;
|
22
|
+
variant: 'primary' | 'secondary';
|
23
|
+
size: 'large' | 'small';
|
24
|
+
firstUpdated(): void;
|
25
|
+
render(): import("lit").TemplateResult<1>;
|
26
|
+
private hasPrefixSlot;
|
27
|
+
}
|
@@ -0,0 +1 @@
|
|
1
|
+
var __decorate=this&&this.__decorate||function(t,e,o,i){var l,r=arguments.length,a=r<3?e:null===i?i=Object.getOwnPropertyDescriptor(e,o):i;if("object"==typeof Reflect&&"function"==typeof Reflect.decorate)a=Reflect.decorate(t,e,o,i);else for(var s=t.length-1;s>=0;s--)(l=t[s])&&(a=(r<3?l(a):r>3?l(e,o,a):l(e,o))||a);return r>3&&a&&Object.defineProperty(e,o,a),a};import"./menu.js";import{LitElement,html}from"lit";import{classMap}from"lit/directives/class-map.js";import{createRef,ref}from"lit/directives/ref.js";import{customElement,property,state}from"lit/decorators.js";import{ifDefined}from"lit/directives/if-defined.js";import{owSlot,owSlotType}from"./library/ow.js";import styles from"./split-button.styles.js";let GlideCoreSplitButton=class GlideCoreSplitButton extends LitElement{constructor(){super(...arguments),this.ariaControls=null,this.ariaExpanded=null,this.ariaHasPopup=null,this.disabled=!1,this.variant="primary",this.size="large",this.hasPrefixSlot=!1,this.#t=createRef(),this.#e=createRef()}static{this.shadowRootOptions={...LitElement.shadowRootOptions,delegatesFocus:!0,mode:"closed"}}static{this.styles=styles}firstUpdated(){owSlot(this.#t.value),owSlotType(this.#t.value,[Text])}render(){return html`<button aria-controls="${ifDefined(this.ariaControls??void 0)}" aria-expanded="${ifDefined(this.ariaExpanded??void 0)}" aria-haspopup="${ifDefined(this.ariaHasPopup??void 0)}" class="${classMap({component:!0,disabled:this.disabled,[this.variant]:!0,[this.size]:!0,"has-prefix":this.hasPrefixSlot})}" data-test="split-button" type="button" ?disabled="${this.disabled}"><slot name="prefix" @slotchange="${this.#o}" ${ref(this.#e)} data-test="prefix-slot"></slot><slot @slotchange="${this.#i}" ${ref(this.#t)} data-test="default-slot"></slot></button>`}#t;#e;#i(){owSlot(this.#t.value),owSlotType(this.#t.value,[Text])}#o(){const t=this.#e.value?.assignedNodes();this.hasPrefixSlot=!!(t&&t.length>0)}};__decorate([property({attribute:"aria-controls",reflect:!0})],GlideCoreSplitButton.prototype,"ariaControls",void 0),__decorate([property({attribute:"aria-expanded",reflect:!0})],GlideCoreSplitButton.prototype,"ariaExpanded",void 0),__decorate([property({attribute:"aria-haspopup",reflect:!0})],GlideCoreSplitButton.prototype,"ariaHasPopup",void 0),__decorate([property({type:Boolean,reflect:!0})],GlideCoreSplitButton.prototype,"disabled",void 0),__decorate([property({reflect:!0})],GlideCoreSplitButton.prototype,"variant",void 0),__decorate([property({reflect:!0})],GlideCoreSplitButton.prototype,"size",void 0),__decorate([state()],GlideCoreSplitButton.prototype,"hasPrefixSlot",void 0),GlideCoreSplitButton=__decorate([customElement("glide-core-split-button")],GlideCoreSplitButton);export default GlideCoreSplitButton;
|
@@ -0,0 +1,17 @@
|
|
1
|
+
import './icons/storybook.js';
|
2
|
+
import './menu.button.js';
|
3
|
+
import './menu.link.js';
|
4
|
+
import './split-button.js';
|
5
|
+
import './split-container.js';
|
6
|
+
import './split-link.js';
|
7
|
+
import type { Meta, StoryObj } from '@storybook/web-components';
|
8
|
+
declare const meta: Meta;
|
9
|
+
export default meta;
|
10
|
+
export declare const Primary: StoryObj;
|
11
|
+
export declare const PrimaryWithPrefixIcon: StoryObj;
|
12
|
+
export declare const PrimaryWithSizeSmall: StoryObj;
|
13
|
+
export declare const PrimaryWithLink: StoryObj;
|
14
|
+
export declare const Secondary: StoryObj;
|
15
|
+
export declare const SecondaryWithPrefixIcon: StoryObj;
|
16
|
+
export declare const SecondaryWithSizeSmall: StoryObj;
|
17
|
+
export declare const SecondaryWithLink: StoryObj;
|
@@ -0,0 +1,102 @@
|
|
1
|
+
import{css}from"lit";import focusOutline from"./styles/focus-outline.js";export default[css`
|
2
|
+
.component {
|
3
|
+
align-items: center;
|
4
|
+
border-color: transparent;
|
5
|
+
border-radius: 0.75rem 0 0 0.75rem;
|
6
|
+
border-style: solid;
|
7
|
+
border-width: 1px 0 1px 1px;
|
8
|
+
cursor: pointer;
|
9
|
+
display: inline-flex;
|
10
|
+
font-family: var(--glide-core-heading-xxs-font-family);
|
11
|
+
font-style: var(--glide-core-heading-xxs-font-style);
|
12
|
+
font-weight: var(--glide-core-heading-xxs-font-weight);
|
13
|
+
gap: 0.625rem;
|
14
|
+
justify-content: center;
|
15
|
+
padding-block: var(--glide-core-spacing-xs);
|
16
|
+
padding-inline: var(--glide-core-spacing-md);
|
17
|
+
padding-inline-end: var(--glide-core-spacing-xs);
|
18
|
+
text-decoration: none;
|
19
|
+
transition-duration: 150ms;
|
20
|
+
transition-property: color, background-color, border-color, fill, stroke;
|
21
|
+
transition-timing-function: cubic-bezier(0.4, 0, 0.2, 1);
|
22
|
+
user-select: none;
|
23
|
+
|
24
|
+
&:focus {
|
25
|
+
outline: none;
|
26
|
+
}
|
27
|
+
|
28
|
+
&:focus-visible {
|
29
|
+
${focusOutline};
|
30
|
+
}
|
31
|
+
|
32
|
+
&.disabled {
|
33
|
+
opacity: 1;
|
34
|
+
pointer-events: none;
|
35
|
+
}
|
36
|
+
|
37
|
+
&.primary {
|
38
|
+
background-color: var(--glide-core-surface-primary);
|
39
|
+
border-color: transparent;
|
40
|
+
color: var(--glide-core-text-selected);
|
41
|
+
|
42
|
+
/* Since the "disabled" styles are shared between a link and a button, we use a disabled class and not a pseudo-class */
|
43
|
+
&.disabled {
|
44
|
+
background-color: var(--glide-core-surface-disabled);
|
45
|
+
border-color: transparent;
|
46
|
+
color: var(--glide-core-text-tertiary-disabled);
|
47
|
+
}
|
48
|
+
|
49
|
+
&:not(.disabled):active {
|
50
|
+
background-color: var(--glide-core-surface-selected-hover);
|
51
|
+
border-color: transparent;
|
52
|
+
color: var(--glide-core-text-selected);
|
53
|
+
}
|
54
|
+
|
55
|
+
&:not(:active):hover:not(.disabled) {
|
56
|
+
background-color: var(--glide-core-surface-hover);
|
57
|
+
border-color: transparent;
|
58
|
+
box-shadow: var(--glide-core-glow-sm);
|
59
|
+
color: var(--glide-core-text-primary);
|
60
|
+
}
|
61
|
+
}
|
62
|
+
|
63
|
+
&.secondary {
|
64
|
+
background-color: transparent;
|
65
|
+
border-color: var(--glide-core-border-primary);
|
66
|
+
color: var(--glide-core-text-primary);
|
67
|
+
|
68
|
+
&.disabled {
|
69
|
+
background-color: var(--glide-core-surface-disabled);
|
70
|
+
border-color: transparent;
|
71
|
+
color: var(--glide-core-text-tertiary-disabled);
|
72
|
+
}
|
73
|
+
|
74
|
+
&:not(.disabled):active {
|
75
|
+
background-color: var(--glide-core-surface-selected-hover);
|
76
|
+
border-color: transparent;
|
77
|
+
color: var(--glide-core-text-selected);
|
78
|
+
}
|
79
|
+
|
80
|
+
&:not(:active):hover:not(.disabled) {
|
81
|
+
background-color: var(--glide-core-surface-hover);
|
82
|
+
border-color: transparent;
|
83
|
+
box-shadow: var(--glide-core-glow-sm);
|
84
|
+
color: var(--glide-core-text-primary);
|
85
|
+
}
|
86
|
+
}
|
87
|
+
|
88
|
+
&.small {
|
89
|
+
block-size: 1.75rem;
|
90
|
+
box-sizing: border-box;
|
91
|
+
font-size: var(--glide-core-body-xs-font-size);
|
92
|
+
line-height: 1rem;
|
93
|
+
}
|
94
|
+
|
95
|
+
&.large {
|
96
|
+
block-size: 2.125rem;
|
97
|
+
box-sizing: border-box;
|
98
|
+
font-size: var(--glide-core-body-xxs-font-size);
|
99
|
+
line-height: 1.5rem;
|
100
|
+
}
|
101
|
+
}
|
102
|
+
`];
|
@@ -0,0 +1 @@
|
|
1
|
+
import './split-button.js';
|
@@ -0,0 +1,99 @@
|
|
1
|
+
import './split-button.js';
|
2
|
+
import { assert, elementUpdated, expect, fixture, html, } from '@open-wc/testing';
|
3
|
+
import GlideCoreSplitButton from './split-button.js';
|
4
|
+
import expectArgumentError from './library/expect-argument-error.js';
|
5
|
+
GlideCoreSplitButton.shadowRootOptions.mode = 'open';
|
6
|
+
it('registers', async () => {
|
7
|
+
expect(window.customElements.get('glide-core-split-button')).to.equal(GlideCoreSplitButton);
|
8
|
+
});
|
9
|
+
it('is accessible', async () => {
|
10
|
+
const component = await fixture(html `
|
11
|
+
<glide-core-split-button>Button</glide-core-split-button>
|
12
|
+
`);
|
13
|
+
await expect(component).to.be.accessible();
|
14
|
+
});
|
15
|
+
it('has defaults', async () => {
|
16
|
+
const component = await fixture(html `<glide-core-split-button>Button</glide-core-split-button>`);
|
17
|
+
const button = component.shadowRoot?.querySelector('button');
|
18
|
+
assert(button);
|
19
|
+
expect(component.ariaExpanded).to.equal(null);
|
20
|
+
expect(component.ariaControls).to.equal(null);
|
21
|
+
expect(component.ariaHasPopup).to.equal(null);
|
22
|
+
expect(component.disabled).to.equal(false);
|
23
|
+
expect(component.size).to.equal('large');
|
24
|
+
expect(component.variant).to.equal('primary');
|
25
|
+
expect(button.getAttribute('aria-controls')).to.equal(null);
|
26
|
+
expect(button.ariaExpanded).to.equal(null);
|
27
|
+
expect(button.ariaHasPopup).to.equal(null);
|
28
|
+
expect(button.disabled).to.equal(false);
|
29
|
+
});
|
30
|
+
it('renders a button with a label by default', async () => {
|
31
|
+
const component = await fixture(html `
|
32
|
+
<glide-core-split-button>Button</glide-core-split-button>
|
33
|
+
`);
|
34
|
+
expect(component.textContent).to.equal('Button');
|
35
|
+
});
|
36
|
+
it('renders with size "large" and variant "primary" by default', async () => {
|
37
|
+
const component = await fixture(html `
|
38
|
+
<glide-core-split-button>Button</glide-core-split-button>
|
39
|
+
`);
|
40
|
+
const button = component?.shadowRoot?.querySelector('[data-test="split-button"]');
|
41
|
+
expect(button?.classList.contains('large')).to.be.true;
|
42
|
+
expect(button?.classList.contains('primary')).to.be.true;
|
43
|
+
});
|
44
|
+
it('adds "small" styling when "size" attribute is "small"', async () => {
|
45
|
+
const component = await fixture(html `
|
46
|
+
<glide-core-split-button size="small">Button</glide-core-split-button>
|
47
|
+
`);
|
48
|
+
const button = component?.shadowRoot?.querySelector('[data-test="split-button"]');
|
49
|
+
expect(button?.classList.contains('small')).to.be.true;
|
50
|
+
});
|
51
|
+
it('adds "secondary" styling when "variant" attribute is "secondary"', async () => {
|
52
|
+
const component = await fixture(html `
|
53
|
+
<glide-core-split-button variant="secondary"
|
54
|
+
>Button</glide-core-split-button
|
55
|
+
>
|
56
|
+
`);
|
57
|
+
const button = component?.shadowRoot?.querySelector('[data-test="split-button"]');
|
58
|
+
expect(button?.classList.contains('secondary')).to.be.true;
|
59
|
+
});
|
60
|
+
it('sets the button as "disabled" when the attribute exists', async () => {
|
61
|
+
const component = await fixture(html `
|
62
|
+
<glide-core-split-button disabled>Button</glide-core-split-button>
|
63
|
+
`);
|
64
|
+
const button = component?.shadowRoot?.querySelector('[data-test="split-button"]');
|
65
|
+
expect(button).to.have.attribute('disabled');
|
66
|
+
});
|
67
|
+
it('renders a prefix slot when given', async () => {
|
68
|
+
const component = await fixture(html `
|
69
|
+
<glide-core-split-button
|
70
|
+
><div data-prefix slot="prefix">Prefix</div>
|
71
|
+
Button</glide-core-split-button
|
72
|
+
>
|
73
|
+
`);
|
74
|
+
expect(component.querySelector('[data-prefix]')).to.be.not.null;
|
75
|
+
});
|
76
|
+
it('renders with prefix class when dynamically added and removed', async () => {
|
77
|
+
const component = await fixture(html `
|
78
|
+
<glide-core-split-button>
|
79
|
+
<span slot="prefix">prefix</span>Button</glide-core-split-button
|
80
|
+
>
|
81
|
+
`);
|
82
|
+
expect(document.querySelector('[slot="prefix"]')).to.be.not.null;
|
83
|
+
expect([
|
84
|
+
...component.shadowRoot.querySelector('[data-test="split-button"]')
|
85
|
+
.classList,
|
86
|
+
]).to.include('has-prefix');
|
87
|
+
component.querySelector('[slot="prefix"]')?.remove();
|
88
|
+
await elementUpdated(component);
|
89
|
+
expect([
|
90
|
+
...component.shadowRoot.querySelector('[data-test="split-button"]')
|
91
|
+
.classList,
|
92
|
+
]).to.not.include('has-prefix');
|
93
|
+
});
|
94
|
+
it('throws an error when there is no button label', async () => {
|
95
|
+
await expectArgumentError(() => fixture(html `<glide-core-split-button></glide-core-split-button>`));
|
96
|
+
});
|
97
|
+
it('throws an error when there is something other than text in the default slot', async () => {
|
98
|
+
await expectArgumentError(() => fixture(html `<glide-core-split-button><div>test</div></glide-core-split-button>`));
|
99
|
+
});
|
@@ -0,0 +1,31 @@
|
|
1
|
+
import './menu.js';
|
2
|
+
import './menu.options.js';
|
3
|
+
import { LitElement, type PropertyValueMap } from 'lit';
|
4
|
+
import { type Placement } from '@floating-ui/dom';
|
5
|
+
declare global {
|
6
|
+
interface HTMLElementTagNameMap {
|
7
|
+
'glide-core-split-container': GlideCoreSplitContainer;
|
8
|
+
}
|
9
|
+
}
|
10
|
+
/**
|
11
|
+
* @description A split button that provides a button action and a menu of alternate actions.
|
12
|
+
*
|
13
|
+
* @slot - One or more of `<glide-core-menu-link>` or `<glide-core-menu-button>`.
|
14
|
+
* @slot primary-action - One of either `<glide-core-split-button>` or `<glide-core-split-link>`.
|
15
|
+
*
|
16
|
+
*/
|
17
|
+
export default class GlideCoreSplitContainer extends LitElement {
|
18
|
+
#private;
|
19
|
+
static shadowRootOptions: ShadowRootInit;
|
20
|
+
static styles: import("lit").CSSResult[];
|
21
|
+
menulabel: string;
|
22
|
+
open: boolean;
|
23
|
+
disabled: boolean;
|
24
|
+
placement: Placement;
|
25
|
+
variant: 'primary' | 'secondary';
|
26
|
+
size: 'large' | 'small';
|
27
|
+
firstUpdated(): void;
|
28
|
+
focus(options?: FocusOptions): void;
|
29
|
+
render(): import("lit").TemplateResult<1>;
|
30
|
+
willUpdate(changedProperties: PropertyValueMap<GlideCoreSplitContainer>): void;
|
31
|
+
}
|
@@ -0,0 +1 @@
|
|
1
|
+
var __decorate=this&&this.__decorate||function(e,t,i,o){var l,r=arguments.length,n=r<3?t:null===o?o=Object.getOwnPropertyDescriptor(t,i):o;if("object"==typeof Reflect&&"function"==typeof Reflect.decorate)n=Reflect.decorate(e,t,i,o);else for(var s=e.length-1;s>=0;s--)(l=e[s])&&(n=(r<3?l(n):r>3?l(t,i,n):l(t,i))||n);return r>3&&n&&Object.defineProperty(t,i,n),n};import"./menu.js";import"./menu.options.js";import{LitElement,html}from"lit";import{}from"@floating-ui/dom";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,owSlotType}from"./library/ow.js";import GlideCoreMenuButton from"./menu.button.js";import GlideCoreMenuLink from"./menu.link.js";import GlideCoreSplitButton from"./split-button.js";import GlideCoreSplitLink from"./split-link.js";import styles from"./split-container.styles.js";let GlideCoreSplitContainer=class GlideCoreSplitContainer extends LitElement{constructor(){super(...arguments),this.menulabel="",this.open=!1,this.disabled=!1,this.placement="bottom-end",this.variant="primary",this.size="large",this.#e=createRef(),this.#t=createRef(),this.#i=createRef()}static{this.shadowRootOptions={...LitElement.shadowRootOptions,mode:"closed"}}static{this.styles=styles}firstUpdated(){this.#o(),this.#l();const e=this.#i.value?.assignedNodes().at(0);(e instanceof GlideCoreSplitButton||e instanceof GlideCoreSplitLink)&&(e.disabled=this.disabled,e.variant=this.variant,e.size=this.size)}focus(e){const t=this.#i.value?.assignedNodes()?.at(0);t instanceof HTMLElement&&t.focus(e)}render(){return html`<div class="${classMap({component:!0,disabled:this.disabled})}"><slot name="primary-action" @slotchange="${this.#r}" ${ref(this.#i)} data-test="primary-action"></slot><span class="${classMap({divider:!0,[this.variant]:!0})}" data-test="split-divider"></span><glide-core-menu ?open="${this.open}" size="${this.size}" placement="${this.placement}"><button slot="target" type="button" class="${classMap({"menu-button":!0,[this.variant]:!0,[this.size]:!0})}" ?disabled="${this.disabled}" aria-label="${this.menulabel}" data-test="split-menu-button" ${ref(this.#t)}><svg width="16" height="16" viewBox="0 0 24 24" fill="none" role="presentation"><path d="M6 9L12 15L18 9" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"/></svg></button><glide-core-menu-options><slot @slotchange="${this.#n}" ${ref(this.#e)}></slot></glide-core-menu-options></glide-core-menu></div>`}willUpdate(e){const t=this.#i.value?.assignedNodes().at(0);this.hasUpdated&&(t instanceof GlideCoreSplitButton||t instanceof GlideCoreSplitLink)&&(e.has("disabled")&&(t.disabled=this.disabled),e.has("variant")&&(t.variant=this.variant),e.has("size")&&(t.size=this.size))}#e;#t;#i;#n(){this.#o()}#r(){this.#l()}#o(){owSlot(this.#e.value),owSlotType(this.#e.value,[GlideCoreMenuButton,GlideCoreMenuLink])}#l(){owSlot(this.#i.value),owSlotType(this.#i.value,[GlideCoreSplitButton,GlideCoreSplitLink])}};__decorate([property({attribute:"menu-label",reflect:!0})],GlideCoreSplitContainer.prototype,"menulabel",void 0),__decorate([property({type:Boolean,reflect:!0})],GlideCoreSplitContainer.prototype,"open",void 0),__decorate([property({type:Boolean,reflect:!0})],GlideCoreSplitContainer.prototype,"disabled",void 0),__decorate([property({attribute:"menu-placement",reflect:!0})],GlideCoreSplitContainer.prototype,"placement",void 0),__decorate([property({reflect:!0})],GlideCoreSplitContainer.prototype,"variant",void 0),__decorate([property({reflect:!0})],GlideCoreSplitContainer.prototype,"size",void 0),GlideCoreSplitContainer=__decorate([customElement("glide-core-split-container")],GlideCoreSplitContainer);export default GlideCoreSplitContainer;
|