@crowdstrike/glide-core 0.5.0 → 0.5.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- 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 -3
- 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 +1 -3
- 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 +28 -9
- 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 +13 -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 +20 -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
package/dist/modal.styles.js
CHANGED
@@ -1,4 +1,4 @@
|
|
1
|
-
|
1
|
+
import{css}from"lit";import focusOutline from"./styles/focus-outline.js";export default[css`
|
2
2
|
/* When browser support improves, we can have nicer animations with https://caniuse.com/mdn-css_at-rules_starting-style */
|
3
3
|
@keyframes backdrop-fade-in {
|
4
4
|
from {
|
@@ -43,7 +43,7 @@
|
|
43
43
|
}
|
44
44
|
|
45
45
|
&:focus-visible {
|
46
|
-
${
|
46
|
+
${focusOutline};
|
47
47
|
}
|
48
48
|
|
49
49
|
&::backdrop {
|
@@ -130,7 +130,7 @@
|
|
130
130
|
}
|
131
131
|
|
132
132
|
&:focus-visible {
|
133
|
-
${
|
133
|
+
${focusOutline};
|
134
134
|
}
|
135
135
|
}
|
136
136
|
|
@@ -166,4 +166,4 @@
|
|
166
166
|
.align-center {
|
167
167
|
align-items: center;
|
168
168
|
}
|
169
|
-
`];
|
169
|
+
`];
|
@@ -1 +1 @@
|
|
1
|
-
|
1
|
+
var __decorate=this&&this.__decorate||function(e,t,o,l){var r,i=arguments.length,a=i<3?t:null===l?l=Object.getOwnPropertyDescriptor(t,o):l;if("object"==typeof Reflect&&"function"==typeof Reflect.decorate)a=Reflect.decorate(e,t,o,l);else for(var d=e.length-1;d>=0;d--)(r=e[d])&&(a=(i<3?r(a):i>3?r(t,o,a):r(t,o))||a);return i>3&&a&&Object.defineProperty(t,o,a),a};import"./tooltip.js";import{LitElement,html}from"lit";import{createRef,ref}from"lit/directives/ref.js";import{customElement,property}from"lit/decorators.js";import{ifDefined}from"lit/directives/if-defined.js";import{owSlot}from"./library/ow.js";let GlideCoreModalTertiaryIcon=class GlideCoreModalTertiaryIcon extends LitElement{constructor(){super(...arguments),this.tooltipPlacement="bottom",this.#e=createRef()}static{this.shadowRootOptions={...LitElement.shadowRootOptions,mode:"closed"}}firstUpdated(){owSlot(this.#e.value)}render(){return html`<glide-core-tooltip placement="${this.tooltipPlacement}">${this.label} <span tabindex="0" aria-label="${ifDefined(this.label)}" slot="target"><slot @slotchange="${this.#t}" ${ref(this.#e)}></slot></span></glide-core-tooltip>`}#e;#t(){owSlot(this.#e.value)}};__decorate([property()],GlideCoreModalTertiaryIcon.prototype,"label",void 0),__decorate([property({attribute:"tooltip-placement"})],GlideCoreModalTertiaryIcon.prototype,"tooltipPlacement",void 0),GlideCoreModalTertiaryIcon=__decorate([customElement("glide-core-modal-tertiary-icon")],GlideCoreModalTertiaryIcon);export default GlideCoreModalTertiaryIcon;
|
@@ -0,0 +1,59 @@
|
|
1
|
+
import './button.js';
|
2
|
+
import { ArgumentError } from 'ow';
|
3
|
+
import { expect, fixture, html } from '@open-wc/testing';
|
4
|
+
import GlideCoreModalTertiaryIcon from './modal.tertiary-icon.js';
|
5
|
+
import sinon from 'sinon';
|
6
|
+
GlideCoreModalTertiaryIcon.shadowRootOptions.mode = 'open';
|
7
|
+
it('registers', async () => {
|
8
|
+
expect(window.customElements.get('glide-core-modal-tertiary-icon')).to.equal(GlideCoreModalTertiaryIcon);
|
9
|
+
});
|
10
|
+
it('is accessible', async () => {
|
11
|
+
const element = await fixture(html `<glide-core-modal-tertiary-icon>Test</glide-core-modal-tertiary-icon>`);
|
12
|
+
await expect(element).to.be.accessible();
|
13
|
+
});
|
14
|
+
it('renders and sets default attributes', async () => {
|
15
|
+
const element = await fixture(html `
|
16
|
+
<glide-core-modal-tertiary-icon>Test</glide-core-modal-tertiary-icon>
|
17
|
+
`);
|
18
|
+
expect(element).to.be.ok;
|
19
|
+
const spanTag = element.shadowRoot?.querySelector('span');
|
20
|
+
expect(spanTag?.getAttribute('tabindex')).to.equal('0');
|
21
|
+
const toolip = element.shadowRoot?.querySelector('glide-core-tooltip');
|
22
|
+
expect(toolip).to.not.be.null;
|
23
|
+
});
|
24
|
+
it('adds an accessible label when given', async () => {
|
25
|
+
const element = await fixture(html `<glide-core-modal-tertiary-icon label="test-label"
|
26
|
+
>Test</glide-core-modal-tertiary-icon
|
27
|
+
>`);
|
28
|
+
const spanElement = element.shadowRoot?.querySelector('span');
|
29
|
+
expect(spanElement).to.have.attribute('aria-label', 'test-label');
|
30
|
+
});
|
31
|
+
it('does not add an acceessible label when not given', async () => {
|
32
|
+
const element = await fixture(html `<glide-core-modal-tertiary-icon>Test</glide-core-modal-tertiary-icon>`);
|
33
|
+
const spanElement = element.shadowRoot?.querySelector('span');
|
34
|
+
expect(spanElement).to.not.have.attribute('aria-label');
|
35
|
+
});
|
36
|
+
it('sets the tooltip placement when attribute "tooltip-placement" is given', async () => {
|
37
|
+
const element = await fixture(html `<glide-core-modal-tertiary-icon tooltip-placement="right"
|
38
|
+
>Test</glide-core-modal-tertiary-icon
|
39
|
+
>`);
|
40
|
+
const toolTip = element.shadowRoot?.querySelector('glide-core-tooltip');
|
41
|
+
expect(toolTip).to.have.attribute('placement', 'right');
|
42
|
+
});
|
43
|
+
it('sets the tooltip placement to "bottom" when attribute "tooltip-placement" is not given', async () => {
|
44
|
+
const element = await fixture(html `<glide-core-modal-tertiary-icon>Test</glide-core-modal-tertiary-icon>`);
|
45
|
+
const toolTip = element.shadowRoot?.querySelector('glide-core-tooltip');
|
46
|
+
expect(toolTip).to.have.attribute('placement', 'bottom');
|
47
|
+
});
|
48
|
+
it('throws if it does not have a default slot', async () => {
|
49
|
+
const spy = sinon.spy();
|
50
|
+
try {
|
51
|
+
await fixture(html `<glide-core-modal-tertiary-icon></glide-core-modal-tertiary-icon>`);
|
52
|
+
}
|
53
|
+
catch (error) {
|
54
|
+
if (error instanceof ArgumentError) {
|
55
|
+
spy();
|
56
|
+
}
|
57
|
+
}
|
58
|
+
expect(spy.called).to.be.true;
|
59
|
+
});
|
@@ -0,0 +1,48 @@
|
|
1
|
+
import { expect, fixture, html } from '@open-wc/testing';
|
2
|
+
import GlideCoreModal from './modal.js';
|
3
|
+
GlideCoreModal.shadowRootOptions.mode = 'open';
|
4
|
+
it('is accessible', async () => {
|
5
|
+
const element = await fixture(html `<glide-core-modal label="Modal title">
|
6
|
+
Modal Content
|
7
|
+
</glide-core-modal>`);
|
8
|
+
await expect(element).to.be.accessible();
|
9
|
+
});
|
10
|
+
it('focuses the dialog upon opening', async () => {
|
11
|
+
const element = await fixture(html `<glide-core-modal label="Modal title">
|
12
|
+
Modal Content
|
13
|
+
</glide-core-modal>`);
|
14
|
+
element.showModal();
|
15
|
+
const dialogElement = element.shadowRoot?.querySelector('dialog');
|
16
|
+
expect(element.shadowRoot?.activeElement).to.equal(dialogElement);
|
17
|
+
});
|
18
|
+
it('sets the tabindex on the dialog to "-1"', async () => {
|
19
|
+
const element = await fixture(html `<glide-core-modal label="Modal title">
|
20
|
+
Modal Content
|
21
|
+
</glide-core-modal>`);
|
22
|
+
element.showModal();
|
23
|
+
const dialogElement = element.shadowRoot?.querySelector('dialog');
|
24
|
+
expect(dialogElement?.getAttribute('tabindex')).to.equal('-1');
|
25
|
+
});
|
26
|
+
it('sets the "toolbar" role on the header-actions section', async () => {
|
27
|
+
const element = await fixture(html `<glide-core-modal label="Modal title">
|
28
|
+
Modal Content
|
29
|
+
</glide-core-modal>`);
|
30
|
+
element.showModal();
|
31
|
+
const toolbar = element.shadowRoot?.querySelector('[role="toolbar"');
|
32
|
+
expect(toolbar).to.be.ok;
|
33
|
+
});
|
34
|
+
it('sets proper aria attributes and roles on the article', async () => {
|
35
|
+
const element = await fixture(html `<glide-core-modal label="Modal title">
|
36
|
+
Modal Content
|
37
|
+
</glide-core-modal>`);
|
38
|
+
element.showModal();
|
39
|
+
const content = element.shadowRoot?.querySelector('[role="region"');
|
40
|
+
expect(content).to.be.ok;
|
41
|
+
expect(content?.tagName).to.equal('ARTICLE');
|
42
|
+
expect(content?.getAttribute('aria-labelledby')).to.equal('heading');
|
43
|
+
expect(content?.getAttribute('tabindex')).to.equal('0');
|
44
|
+
// Verify the aria-labelledby id attribute is found
|
45
|
+
const label = element.shadowRoot?.querySelector('#heading');
|
46
|
+
expect(label).to.be.ok;
|
47
|
+
expect(label?.tagName).to.equal('H2');
|
48
|
+
});
|
@@ -0,0 +1,203 @@
|
|
1
|
+
import './button.js';
|
2
|
+
import './modal.icon-button.js';
|
3
|
+
import './modal.js';
|
4
|
+
import { ArgumentError } from 'ow';
|
5
|
+
import { expect, fixture, html } from '@open-wc/testing';
|
6
|
+
import GlideCoreModal from './modal.js';
|
7
|
+
import expectArgumentError from './library/expect-argument-error.js';
|
8
|
+
import sinon from 'sinon';
|
9
|
+
GlideCoreModal.shadowRootOptions.mode = 'open';
|
10
|
+
it('registers', async () => {
|
11
|
+
expect(window.customElements.get('glide-core-modal')).to.equal(GlideCoreModal);
|
12
|
+
});
|
13
|
+
it('is closed by default', async () => {
|
14
|
+
const element = await fixture(html `<glide-core-modal label="Modal title">
|
15
|
+
Modal Content
|
16
|
+
</glide-core-modal>`);
|
17
|
+
const dialog = element.shadowRoot?.querySelector('dialog');
|
18
|
+
expect(dialog).to.be.ok;
|
19
|
+
expect(dialog?.hasAttribute('open')).to.be.false;
|
20
|
+
});
|
21
|
+
it('renders the provided "label"', async () => {
|
22
|
+
const element = await fixture(html `<glide-core-modal label="Modal title">
|
23
|
+
Modal Content
|
24
|
+
</glide-core-modal>`);
|
25
|
+
element.showModal();
|
26
|
+
const label = element.shadowRoot?.querySelector('[data-test="heading"]');
|
27
|
+
expect(label).to.be.ok;
|
28
|
+
expect(label?.textContent?.trim()).to.equal('Modal title');
|
29
|
+
});
|
30
|
+
it('does not render the show back button in the label by default', async () => {
|
31
|
+
const element = await fixture(html `<glide-core-modal label="Modal title">
|
32
|
+
Modal Content
|
33
|
+
</glide-core-modal>`);
|
34
|
+
element.showModal();
|
35
|
+
expect(element.shadowRoot?.querySelector('[data-test="back-button"]')).to.be.null;
|
36
|
+
});
|
37
|
+
it('renders the show back button in the label when provided with "show-back-button"', async () => {
|
38
|
+
const element = await fixture(html `<glide-core-modal label="Modal title" show-back-button>
|
39
|
+
Modal Content
|
40
|
+
</glide-core-modal>`);
|
41
|
+
element.showModal();
|
42
|
+
expect(element.shadowRoot?.querySelector('[data-test="back-button"]')).to.be.ok;
|
43
|
+
});
|
44
|
+
it('renders the provided default slotted content', async () => {
|
45
|
+
const element = await fixture(html `<glide-core-modal label="Modal title">
|
46
|
+
<p data-body>Inner content</p>
|
47
|
+
</glide-core-modal>`);
|
48
|
+
element.showModal();
|
49
|
+
const body = element.querySelector('[data-body]');
|
50
|
+
expect(body).to.be.ok;
|
51
|
+
});
|
52
|
+
it('renders the provided primary slot content', async () => {
|
53
|
+
const element = await fixture(html `<glide-core-modal label="Modal title">
|
54
|
+
Modal Content
|
55
|
+
<glide-core-button slot="primary" data-primary>Primary</glide-core-button>
|
56
|
+
</glide-core-modal>`);
|
57
|
+
element.showModal();
|
58
|
+
const slotContent = element.querySelector('[data-primary]');
|
59
|
+
expect(slotContent).to.be.ok;
|
60
|
+
const slotNodes = element.shadowRoot
|
61
|
+
?.querySelector('slot[name="primary"]')
|
62
|
+
?.assignedNodes();
|
63
|
+
expect(slotNodes?.length).to.equal(1);
|
64
|
+
});
|
65
|
+
it('renders the provided secondary slot content', async () => {
|
66
|
+
const element = await fixture(html `<glide-core-modal label="Modal title">
|
67
|
+
Modal Content
|
68
|
+
<glide-core-button slot="secondary" data-secondary
|
69
|
+
>Secondary</glide-core-button
|
70
|
+
>
|
71
|
+
</glide-core-modal>`);
|
72
|
+
element.showModal();
|
73
|
+
const slotContent = element.querySelector('[data-secondary]');
|
74
|
+
expect(slotContent).to.be.ok;
|
75
|
+
const slotNodes = element.shadowRoot
|
76
|
+
?.querySelector('slot[name="secondary"]')
|
77
|
+
?.assignedNodes();
|
78
|
+
expect(slotNodes?.length).to.equal(1);
|
79
|
+
});
|
80
|
+
it('renders the provided tertiary slot content', async () => {
|
81
|
+
const element = await fixture(html `<glide-core-modal label="Modal title">
|
82
|
+
Modal Content
|
83
|
+
<glide-core-button slot="tertiary" data-tertiary
|
84
|
+
>Tertiary</glide-core-button
|
85
|
+
>
|
86
|
+
</glide-core-modal>`);
|
87
|
+
element.showModal();
|
88
|
+
const slotContent = element.querySelector('[data-tertiary]');
|
89
|
+
expect(slotContent).to.be.ok;
|
90
|
+
const slotNodes = element.shadowRoot
|
91
|
+
?.querySelector('slot[name="tertiary"]')
|
92
|
+
?.assignedNodes();
|
93
|
+
expect(slotNodes?.length).to.equal(1);
|
94
|
+
});
|
95
|
+
it('renders the provided header-actions slot content', async () => {
|
96
|
+
const element = await fixture(html `<glide-core-modal label="Modal title">
|
97
|
+
Modal Content
|
98
|
+
|
99
|
+
<glide-core-modal-icon-button slot="header-actions" data-actions="1"
|
100
|
+
>action1</glide-core-modal-icon-button
|
101
|
+
>
|
102
|
+
|
103
|
+
<glide-core-modal-icon-button slot="header-actions" data-actions="2"
|
104
|
+
>action2</glide-core-modal-icon-button
|
105
|
+
>
|
106
|
+
</glide-core-modal>`);
|
107
|
+
element.showModal();
|
108
|
+
const slotContent = element.querySelector('[data-actions]');
|
109
|
+
expect(slotContent).to.be.ok;
|
110
|
+
const slotNodes = element.shadowRoot
|
111
|
+
?.querySelector('slot[name="header-actions"]')
|
112
|
+
?.assignedNodes();
|
113
|
+
expect(slotNodes?.length).to.equal(2);
|
114
|
+
});
|
115
|
+
it('defaults the size to "medium"', async () => {
|
116
|
+
const element = await fixture(html `<glide-core-modal label="Modal title">
|
117
|
+
Modal Content
|
118
|
+
</glide-core-modal>`);
|
119
|
+
expect([
|
120
|
+
...element.shadowRoot.querySelector('dialog')
|
121
|
+
.classList,
|
122
|
+
]).to.deep.equal(['component', 'medium']);
|
123
|
+
});
|
124
|
+
it('sets the size to "small"', async () => {
|
125
|
+
const element = await fixture(html `<glide-core-modal label="Modal title" size="small">
|
126
|
+
Modal Content
|
127
|
+
</glide-core-modal>`);
|
128
|
+
expect([
|
129
|
+
...element.shadowRoot.querySelector('dialog')
|
130
|
+
.classList,
|
131
|
+
]).to.deep.equal(['component', 'small']);
|
132
|
+
});
|
133
|
+
it('sets the size to "medium"', async () => {
|
134
|
+
const element = await fixture(html `<glide-core-modal label="Modal title" size="medium">
|
135
|
+
Modal Content
|
136
|
+
</glide-core-modal>`);
|
137
|
+
expect([
|
138
|
+
...element.shadowRoot.querySelector('dialog')
|
139
|
+
.classList,
|
140
|
+
]).to.deep.equal(['component', 'medium']);
|
141
|
+
});
|
142
|
+
it('sets the size to "large"', async () => {
|
143
|
+
const element = await fixture(html `<glide-core-modal label="Modal title" size="large">
|
144
|
+
Modal Content
|
145
|
+
</glide-core-modal>`);
|
146
|
+
expect([
|
147
|
+
...element.shadowRoot.querySelector('dialog')
|
148
|
+
.classList,
|
149
|
+
]).to.deep.equal(['component', 'large']);
|
150
|
+
});
|
151
|
+
it('sets the size to "xlarge"', async () => {
|
152
|
+
const element = await fixture(html `<glide-core-modal label="Modal title" size="xlarge">
|
153
|
+
Modal Content
|
154
|
+
</glide-core-modal>`);
|
155
|
+
expect([
|
156
|
+
...element.shadowRoot.querySelector('dialog')
|
157
|
+
.classList,
|
158
|
+
]).to.deep.equal(['component', 'xlarge']);
|
159
|
+
});
|
160
|
+
it('throws if it does not have a default slot', async () => {
|
161
|
+
const spy = sinon.spy();
|
162
|
+
try {
|
163
|
+
await fixture(html `<glide-core-modal label="Modal title"></glide-core-modal>`);
|
164
|
+
}
|
165
|
+
catch (error) {
|
166
|
+
if (error instanceof ArgumentError) {
|
167
|
+
spy();
|
168
|
+
}
|
169
|
+
}
|
170
|
+
expect(spy.called).to.be.true;
|
171
|
+
});
|
172
|
+
it('throws an error when the "primary" footer slot has the incorrect type', async () => {
|
173
|
+
await expectArgumentError(() => {
|
174
|
+
return fixture(html `<glide-core-modal label="Modal title">
|
175
|
+
Modal Content
|
176
|
+
<span slot="primary">Primary</span>
|
177
|
+
</glide-core-modal>`);
|
178
|
+
});
|
179
|
+
});
|
180
|
+
it('throws an error when the "secondary" footer slot has the incorrect type', async () => {
|
181
|
+
await expectArgumentError(() => {
|
182
|
+
return fixture(html `<glide-core-modal label="Modal title">
|
183
|
+
Modal Content
|
184
|
+
<span slot="secondary">Secondary</span>
|
185
|
+
</glide-core-modal>`);
|
186
|
+
});
|
187
|
+
});
|
188
|
+
it('throws an error when the "header actions" slot has the incorrect type', async () => {
|
189
|
+
await expectArgumentError(() => {
|
190
|
+
return fixture(html `<glide-core-modal label="Modal title">
|
191
|
+
Modal Content
|
192
|
+
<span slot="header-actions">Header Action</span>
|
193
|
+
</glide-core-modal>`);
|
194
|
+
});
|
195
|
+
});
|
196
|
+
it('throws an error when the "tertiary" footer slot has the incorrect type', async () => {
|
197
|
+
await expectArgumentError(() => {
|
198
|
+
return fixture(html `<glide-core-modal label="Modal title">
|
199
|
+
Modal Content
|
200
|
+
<span slot="tertiary">Tertiary</span>
|
201
|
+
</glide-core-modal>`);
|
202
|
+
});
|
203
|
+
});
|
@@ -0,0 +1,38 @@
|
|
1
|
+
import { expect, fixture, html } from '@open-wc/testing';
|
2
|
+
import { sendKeys } from '@web/test-runner-commands';
|
3
|
+
import GlideCoreModal from './modal.js';
|
4
|
+
GlideCoreModal.shadowRootOptions.mode = 'open';
|
5
|
+
it('closes the modal when the close button is clicked', async () => {
|
6
|
+
const element = await fixture(html `<glide-core-modal label="Modal title">
|
7
|
+
Modal Content
|
8
|
+
</glide-core-modal>`);
|
9
|
+
element.showModal();
|
10
|
+
const button = element.shadowRoot.querySelector('[data-test="close-button"]');
|
11
|
+
expect(button).to.be.ok;
|
12
|
+
button?.click();
|
13
|
+
expect(element
|
14
|
+
.shadowRoot.querySelector('dialog')
|
15
|
+
?.hasAttribute('open')).to.be.false;
|
16
|
+
});
|
17
|
+
it('closes the modal when the escape key is pressed', async () => {
|
18
|
+
const element = await fixture(html `<glide-core-modal label="Modal title">
|
19
|
+
Modal Content
|
20
|
+
</glide-core-modal>`);
|
21
|
+
element.showModal();
|
22
|
+
const dialogElement = element.shadowRoot.querySelector('dialog');
|
23
|
+
expect(dialogElement?.hasAttribute('open')).to.be.true;
|
24
|
+
await sendKeys({ press: 'Escape' });
|
25
|
+
expect(dialogElement?.hasAttribute('open')).to.be.false;
|
26
|
+
});
|
27
|
+
it('closes the modal via "show-back-button"', async () => {
|
28
|
+
const element = await fixture(html `<glide-core-modal label="Modal title" show-back-button>
|
29
|
+
Modal Content
|
30
|
+
</glide-core-modal>`);
|
31
|
+
element.showModal();
|
32
|
+
const dialogElement = element.shadowRoot.querySelector('dialog');
|
33
|
+
expect(dialogElement?.hasAttribute('open')).to.be.true;
|
34
|
+
const button = element.shadowRoot.querySelector('[data-test="back-button"]');
|
35
|
+
expect(button).to.be.ok;
|
36
|
+
button?.click();
|
37
|
+
expect(dialogElement?.hasAttribute('open')).to.be.false;
|
38
|
+
});
|
@@ -0,0 +1,110 @@
|
|
1
|
+
import './modal.js';
|
2
|
+
import { expect, fixture, html } from '@open-wc/testing';
|
3
|
+
import { sendKeys, sendMouse } from '@web/test-runner-commands';
|
4
|
+
import GlideCoreModal from './modal.js';
|
5
|
+
import sinon from 'sinon';
|
6
|
+
GlideCoreModal.shadowRootOptions.mode = 'open';
|
7
|
+
it('dispatches a "close" event when the modal is closed via the "close" method', async () => {
|
8
|
+
const spy = sinon.spy();
|
9
|
+
const element = await fixture(html `<glide-core-modal label="Modal title"
|
10
|
+
>Modal Content</glide-core-modal
|
11
|
+
>`);
|
12
|
+
element.addEventListener('close', spy);
|
13
|
+
element.showModal();
|
14
|
+
expect(spy.notCalled).to.be.true;
|
15
|
+
element.close();
|
16
|
+
expect(spy.called).to.be.true;
|
17
|
+
});
|
18
|
+
it('dispatches a "close" event when the modal is closed via the close button', async () => {
|
19
|
+
const spy = sinon.spy();
|
20
|
+
const element = await fixture(html `<glide-core-modal label="Modal title"
|
21
|
+
>Modal Content</glide-core-modal
|
22
|
+
>`);
|
23
|
+
element.addEventListener('close', spy);
|
24
|
+
element.showModal();
|
25
|
+
const button = element.shadowRoot?.querySelector('[data-test="close-button"]');
|
26
|
+
expect(button).to.be.ok;
|
27
|
+
button?.click();
|
28
|
+
expect(spy.called).to.be.true;
|
29
|
+
});
|
30
|
+
it('dispatches a "close" event when the modal is closed via the escape key', async () => {
|
31
|
+
const spy = sinon.spy();
|
32
|
+
const element = await fixture(html `<glide-core-modal label="Modal title"
|
33
|
+
>Modal Content</glide-core-modal
|
34
|
+
>`);
|
35
|
+
element.addEventListener('close', spy);
|
36
|
+
element.showModal();
|
37
|
+
await sendKeys({ press: 'Escape' });
|
38
|
+
expect(spy.called).to.be.true;
|
39
|
+
});
|
40
|
+
it('does not dispatch a "close" event when the modal is open and non-escape keys are pressed', async () => {
|
41
|
+
const spy = sinon.spy();
|
42
|
+
const element = await fixture(html `<glide-core-modal label="Modal title"
|
43
|
+
>Modal Content</glide-core-modal
|
44
|
+
>`);
|
45
|
+
element.addEventListener('close', spy);
|
46
|
+
element.showModal();
|
47
|
+
// Tests only a couple keys.
|
48
|
+
await sendKeys({ press: ' ' });
|
49
|
+
expect(spy.notCalled).to.be.true;
|
50
|
+
await sendKeys({ press: 'Enter' });
|
51
|
+
expect(spy.notCalled).to.be.true;
|
52
|
+
});
|
53
|
+
it('dispatches a "close" event when the modal is closed via "show-back-button"', async () => {
|
54
|
+
const spy = sinon.spy();
|
55
|
+
const element = await fixture(html `<glide-core-modal label="Modal title" show-back-button>
|
56
|
+
Modal Content
|
57
|
+
</glide-core-modal>`);
|
58
|
+
element.addEventListener('close', spy);
|
59
|
+
element.showModal();
|
60
|
+
const button = element.shadowRoot?.querySelector('[data-test="back-button"]');
|
61
|
+
expect(button).to.be.ok;
|
62
|
+
button?.click();
|
63
|
+
expect(spy.called).to.be.true;
|
64
|
+
});
|
65
|
+
it('does not emit a "close" event when clicking inside the dialog and the mouse is not positioned on a "close" button', async () => {
|
66
|
+
const spy = sinon.spy();
|
67
|
+
const element = await fixture(html `<glide-core-modal label="Modal title"
|
68
|
+
>Modal Content</glide-core-modal
|
69
|
+
>`);
|
70
|
+
element.showModal();
|
71
|
+
element.addEventListener('close', spy);
|
72
|
+
const dialogElement = element?.shadowRoot?.querySelector('dialog');
|
73
|
+
const boundingRectangle = dialogElement?.getBoundingClientRect();
|
74
|
+
expect(boundingRectangle).is.not.null;
|
75
|
+
const { top, left } = boundingRectangle;
|
76
|
+
await sendMouse({
|
77
|
+
type: 'click',
|
78
|
+
position: [Math.ceil(left + 1), Math.ceil(top + 1)],
|
79
|
+
});
|
80
|
+
expect(spy.notCalled).to.be.true;
|
81
|
+
});
|
82
|
+
it(`does not emit a "close" event if a mousedown event's origin does not come from the dialog element`, async () => {
|
83
|
+
const spy = sinon.spy();
|
84
|
+
const element = await fixture(html `<glide-core-modal label="Modal title">
|
85
|
+
<button data-test="target">Inside Body</button>
|
86
|
+
</glide-core-modal>`);
|
87
|
+
element.showModal();
|
88
|
+
element.addEventListener('close', spy);
|
89
|
+
const button = element.querySelector('[data-test="target"]');
|
90
|
+
expect(button).to.be.ok;
|
91
|
+
button?.dispatchEvent(new Event('mousedown', { bubbles: true }));
|
92
|
+
expect(spy.notCalled).to.be.true;
|
93
|
+
});
|
94
|
+
it('emits a "close" event when clicking outside the dialog', async () => {
|
95
|
+
const spy = sinon.spy();
|
96
|
+
const element = await fixture(html `<glide-core-modal label="Modal title"
|
97
|
+
>Modal Content</glide-core-modal
|
98
|
+
>`);
|
99
|
+
element.showModal();
|
100
|
+
element.addEventListener('close', spy);
|
101
|
+
const dialogElement = element?.shadowRoot?.querySelector('dialog');
|
102
|
+
const boundingRectangle = dialogElement?.getBoundingClientRect();
|
103
|
+
expect(boundingRectangle).is.not.null;
|
104
|
+
const { top, left } = boundingRectangle;
|
105
|
+
await sendMouse({
|
106
|
+
type: 'click',
|
107
|
+
position: [Math.floor(left - 1), Math.floor(top - 1)],
|
108
|
+
});
|
109
|
+
expect(spy.called).to.be.true;
|
110
|
+
});
|
@@ -0,0 +1,76 @@
|
|
1
|
+
import * as sinon from 'sinon';
|
2
|
+
import { expect, fixture, html } from '@open-wc/testing';
|
3
|
+
import { sendKeys, sendMouse } from '@web/test-runner-commands';
|
4
|
+
import GlideCoreModal from './modal.js';
|
5
|
+
GlideCoreModal.shadowRootOptions.mode = 'open';
|
6
|
+
const addSpy = sinon.spy(document.documentElement.classList, 'add');
|
7
|
+
const removeSpy = sinon.spy(document.documentElement.classList, 'remove');
|
8
|
+
afterEach(() => {
|
9
|
+
addSpy.resetHistory();
|
10
|
+
removeSpy.resetHistory();
|
11
|
+
});
|
12
|
+
after(() => {
|
13
|
+
addSpy.restore();
|
14
|
+
removeSpy.restore();
|
15
|
+
});
|
16
|
+
it('adds the "private-glide-core-modal-lock-scroll" class to the documentElement when opened and removes it when closed', async () => {
|
17
|
+
const element = await fixture(html `<glide-core-modal label="Modal title"
|
18
|
+
>Modal Content</glide-core-modal
|
19
|
+
>`);
|
20
|
+
element.showModal();
|
21
|
+
expect(addSpy.callCount).to.equal(1);
|
22
|
+
expect(addSpy.calledWith('private-glide-core-modal-lock-scroll')).to.be.ok;
|
23
|
+
expect(removeSpy.callCount).to.equal(0);
|
24
|
+
element.close();
|
25
|
+
expect(removeSpy.callCount).to.equal(1);
|
26
|
+
expect(removeSpy.calledWith('private-glide-core-modal-lock-scroll')).to.be.ok;
|
27
|
+
// Verify `add` was not called again for some reason
|
28
|
+
expect(addSpy.callCount).to.equal(1);
|
29
|
+
});
|
30
|
+
it('removes the "private-glide-core-modal-lock-scroll" class when the close button is clicked', async () => {
|
31
|
+
const element = await fixture(html `<glide-core-modal label="Modal title"
|
32
|
+
>Modal Content</glide-core-modal
|
33
|
+
>`);
|
34
|
+
element.showModal();
|
35
|
+
expect(removeSpy.callCount).to.equal(0);
|
36
|
+
const button = element.shadowRoot.querySelector('[data-test="close-button"]');
|
37
|
+
expect(button).to.be.ok;
|
38
|
+
button?.click();
|
39
|
+
expect(removeSpy.callCount).to.equal(1);
|
40
|
+
});
|
41
|
+
it('removes the "private-glide-core-modal-lock-scroll" class when the "close" method is called', async () => {
|
42
|
+
const element = await fixture(html `<glide-core-modal label="Modal title"
|
43
|
+
>Modal Content</glide-core-modal
|
44
|
+
>`);
|
45
|
+
element.showModal();
|
46
|
+
expect(removeSpy.callCount).to.equal(0);
|
47
|
+
const dialogElement = element.shadowRoot.querySelector('dialog');
|
48
|
+
expect(dialogElement?.hasAttribute('open')).to.be.true;
|
49
|
+
element.close();
|
50
|
+
expect(removeSpy.callCount).to.equal(1);
|
51
|
+
});
|
52
|
+
it('removes the "private-glide-core-modal-lock-scroll" class when the escape key is pressed', async () => {
|
53
|
+
const element = await fixture(html `<glide-core-modal label="Modal title"
|
54
|
+
>Modal Content</glide-core-modal
|
55
|
+
>`);
|
56
|
+
element.showModal();
|
57
|
+
expect(removeSpy.callCount).to.equal(0);
|
58
|
+
await sendKeys({ press: 'Escape' });
|
59
|
+
expect(removeSpy.callCount).to.equal(1);
|
60
|
+
});
|
61
|
+
it('removes class "private-glide-core-modal-lock-scroll" from document when click is outside dialog', async () => {
|
62
|
+
const element = await fixture(html `<glide-core-modal label="Modal title"
|
63
|
+
>Modal Content</glide-core-modal
|
64
|
+
>`);
|
65
|
+
element.showModal();
|
66
|
+
const dialogElement = element?.shadowRoot?.querySelector('dialog');
|
67
|
+
const boundingRectangle = dialogElement?.getBoundingClientRect();
|
68
|
+
expect(boundingRectangle).is.not.null;
|
69
|
+
expect(document.documentElement.classList.contains('private-glide-core-modal-lock-scroll')).to.be.true;
|
70
|
+
const { top, left } = boundingRectangle;
|
71
|
+
await sendMouse({
|
72
|
+
type: 'click',
|
73
|
+
position: [Math.floor(left - 1), Math.floor(top - 1)],
|
74
|
+
});
|
75
|
+
expect(document.documentElement.classList.contains('private-glide-core-modal-lock-scroll')).to.be.false;
|
76
|
+
});
|
@@ -0,0 +1,23 @@
|
|
1
|
+
import { expect, fixture, html } from '@open-wc/testing';
|
2
|
+
import GlideCoreModal from './modal.js';
|
3
|
+
GlideCoreModal.shadowRootOptions.mode = 'open';
|
4
|
+
it('opens the modal when the "showModal" method is called and closes it when "close" is called', async () => {
|
5
|
+
const element = await fixture(html `<glide-core-modal label="Modal title">
|
6
|
+
Modal Content
|
7
|
+
</glide-core-modal>`);
|
8
|
+
element.showModal();
|
9
|
+
const dialogElement = element.shadowRoot?.querySelector('dialog');
|
10
|
+
expect(dialogElement?.hasAttribute('open')).to.be.true;
|
11
|
+
element.close();
|
12
|
+
expect(dialogElement?.hasAttribute('open')).to.be.false;
|
13
|
+
});
|
14
|
+
it('remains open when the "showModal" method is called twice', async () => {
|
15
|
+
const element = await fixture(html `<glide-core-modal label="Modal title">
|
16
|
+
Modal Content
|
17
|
+
</glide-core-modal>`);
|
18
|
+
element.showModal();
|
19
|
+
const dialogElement = element.shadowRoot?.querySelector('dialog');
|
20
|
+
expect(dialogElement?.hasAttribute('open')).to.be.true;
|
21
|
+
element.showModal();
|
22
|
+
expect(dialogElement?.hasAttribute('open')).to.be.true;
|
23
|
+
});
|
@@ -0,0 +1,19 @@
|
|
1
|
+
import './modal.js';
|
2
|
+
import * as sinon from 'sinon';
|
3
|
+
import { expect, fixture, html } from '@open-wc/testing';
|
4
|
+
import GlideCoreModal from './modal.js';
|
5
|
+
GlideCoreModal.shadowRootOptions.mode = 'open';
|
6
|
+
const cssSupportsStub = sinon.stub(window.CSS, 'supports').returns(false);
|
7
|
+
const setPropertySpy = sinon.spy(document.documentElement.style, 'setProperty');
|
8
|
+
afterEach(() => {
|
9
|
+
cssSupportsStub.restore();
|
10
|
+
setPropertySpy.restore();
|
11
|
+
});
|
12
|
+
it('sets the "--glide-scroll-size" variable when the browser does not support scrollbar-gutter', async () => {
|
13
|
+
const element = await fixture(html `<glide-core-modal label="Modal title">
|
14
|
+
Modal Content
|
15
|
+
</glide-core-modal>`);
|
16
|
+
element.showModal();
|
17
|
+
expect(cssSupportsStub.calledWith('scrollbar-gutter')).to.be.ok;
|
18
|
+
expect(setPropertySpy.callCount).to.equal(1);
|
19
|
+
});
|