@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,45 @@
|
|
1
|
+
import { ArgumentError } from 'ow';
|
2
|
+
import { expect, fixture, html } from '@open-wc/testing';
|
3
|
+
import GlideCoreModalIconButton from './modal.icon-button.js';
|
4
|
+
import sinon from 'sinon';
|
5
|
+
GlideCoreModalIconButton.shadowRootOptions.mode = 'open';
|
6
|
+
it('registers', async () => {
|
7
|
+
expect(window.customElements.get('glide-core-modal-icon-button')).to.equal(GlideCoreModalIconButton);
|
8
|
+
});
|
9
|
+
it('is accessible', async () => {
|
10
|
+
const element = await fixture(html `<glide-core-modal-icon-button>Test</glide-core-modal-icon-button>`);
|
11
|
+
await expect(element).to.be.accessible();
|
12
|
+
});
|
13
|
+
it('renders and sets default attributes', async () => {
|
14
|
+
const element = await fixture(html `
|
15
|
+
<glide-core-modal-icon-button>Test</glide-core-modal-icon-button>
|
16
|
+
`);
|
17
|
+
expect(element).to.be.ok;
|
18
|
+
const buttonElement = element.shadowRoot?.querySelector('glide-core-icon-button');
|
19
|
+
expect(buttonElement).to.be.not.null;
|
20
|
+
expect(buttonElement).to.have.attribute('variant', 'tertiary');
|
21
|
+
});
|
22
|
+
it('adds an accessible label when given', async () => {
|
23
|
+
const element = await fixture(html `<glide-core-modal-icon-button label="test-label"
|
24
|
+
>Test</glide-core-modal-icon-button
|
25
|
+
>`);
|
26
|
+
const buttonElement = element.shadowRoot?.querySelector('glide-core-icon-button');
|
27
|
+
expect(buttonElement).to.have.attribute('label', 'test-label');
|
28
|
+
});
|
29
|
+
it('does not add an acceessible label when not given', async () => {
|
30
|
+
const element = await fixture(html `<glide-core-modal-icon-button>Test</glide-core-modal-icon-button>`);
|
31
|
+
const buttonElement = element.shadowRoot?.querySelector('glide-core-icon-button');
|
32
|
+
expect(buttonElement).to.have.attribute('label', '');
|
33
|
+
});
|
34
|
+
it('throws if it does not have a default slot', async () => {
|
35
|
+
const spy = sinon.spy();
|
36
|
+
try {
|
37
|
+
await fixture(html `<glide-core-modal-icon-button></glide-core-modal-icon-button>`);
|
38
|
+
}
|
39
|
+
catch (error) {
|
40
|
+
if (error instanceof ArgumentError) {
|
41
|
+
spy();
|
42
|
+
}
|
43
|
+
}
|
44
|
+
expect(spy.called).to.be.true;
|
45
|
+
});
|
package/dist/modal.js
CHANGED
@@ -1,15 +1 @@
|
|
1
|
-
|
2
|
-
@supports (scrollbar-gutter: stable) {
|
3
|
-
.private-glide-core-modal-lock-scroll {
|
4
|
-
scrollbar-gutter: stable !important;
|
5
|
-
overflow: hidden !important;
|
6
|
-
}
|
7
|
-
}
|
8
|
-
`),k.insertRule(`
|
9
|
-
@supports not (scrollbar-gutter: stable) {
|
10
|
-
.private-glide-core-modal-lock-scroll {
|
11
|
-
padding-right: var(--glide-scroll-size, 0.9375rem) !important;
|
12
|
-
overflow: hidden !important;
|
13
|
-
}
|
14
|
-
}
|
15
|
-
`);let a=class extends V{constructor(){super(...arguments);i(this,w);i(this,E);i(this,y);i(this,C);i(this,M);i(this,$);i(this,L);i(this,H);this.label="";this.showBackButton=!1;this.size="medium";i(this,s,m());i(this,p,m());i(this,g,m());i(this,v,m());i(this,f,m());i(this,S,m())}close(){e(this,s).value?.open&&(document.documentElement.classList.remove("private-glide-core-modal-lock-scroll"),this.dispatchEvent(new Event("close")),e(this,s).value?.close())}connectedCallback(){super.connectedCallback(),document.adoptedStyleSheets.includes(k)||document.adoptedStyleSheets.push(k)}disconnectedCallback(){super.disconnectedCallback(),document.documentElement.classList.remove("private-glide-core-modal-lock-scroll"),document.adoptedStyleSheets=document.adoptedStyleSheets.filter(t=>t!==k)}firstUpdated(){I(e(this,p).value),d(e(this,S).value,[Z]),d(e(this,g).value,[h]),d(e(this,v).value,[h]),d(e(this,f).value,[A,h])}render(){return D`<dialog class="${U({component:!0,small:this.size==="small",medium:this.size==="medium",large:this.size==="large",xlarge:this.size==="xlarge"})}" tabindex="-1" @keydown="${r(this,L,W)}" @mousedown="${r(this,H,X)}" ${u(e(this,s))}><header class="header"><h2 class="label" data-test="heading" id="heading">${J(this.showBackButton,()=>D`<glide-core-modal-icon-button data-test="back-button" @click="${r(this,w,x)}"><svg width="20" height="20" viewBox="0 0 24 24" fill="none"><title>Dismiss</title><path d="M12 18C11.4477 18 11 18.4477 11 19C11 19.5523 11.4477 20 12 20V18ZM20 14.5C20 16.433 18.433 18 16.5 18V20C19.5376 20 22 17.5376 22 14.5H20ZM16.5 11C18.433 11 20 12.567 20 14.5H22C22 11.4624 19.5376 9 16.5 9V11ZM16.5 18H12V20H16.5V18ZM16.5 9H3V11H16.5V9Z" fill="currentColor"/><path d="M7 6L3 10L7 14" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"/></svg></glide-core-modal-icon-button>`)} ${this.label}</h2><div class="header-actions" role="toolbar"><slot name="header-actions" @slotchange="${r(this,$,O)}" ${u(e(this,S))}></slot><glide-core-modal-icon-button data-test="close-button" @click="${r(this,w,x)}"><svg width="24" height="24" viewBox="0 0 24 24" fill="none"><title>Close</title><path d="M6 6L18 18" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"/><path d="M18 6L6 18" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"/></svg></glide-core-modal-icon-button></div></header><article aria-labelledby="heading" class="body" role="region" tabindex="0"><slot @slotchange="${r(this,E,j)}" ${u(e(this,p))}></slot></article><footer class="footer"><menu class="menu"><li class="flex align-center"><slot name="tertiary" @slotchange="${r(this,M,K)}" ${u(e(this,f))}></slot></li><li><menu class="actions"><li><slot name="secondary" @slotchange="${r(this,C,P)}" ${u(e(this,v))}></slot></li><li><slot name="primary" @slotchange="${r(this,y,F)}" ${u(e(this,g))}></slot></li></menu></li></menu></footer></dialog>`}showModal(){if(!e(this,s).value?.open){if(document.documentElement.classList.add("private-glide-core-modal-lock-scroll"),!window.CSS.supports("scrollbar-gutter","stable")){const t=Math.abs(window.innerWidth-document.documentElement.clientWidth);document.documentElement.style.setProperty("--glide-scroll-size",`${t}px`)}e(this,s).value?.showModal(),e(this,s).value?.focus()}}};s=new WeakMap,p=new WeakMap,g=new WeakMap,v=new WeakMap,f=new WeakMap,S=new WeakMap,w=new WeakSet,x=function(){document.documentElement.classList.remove("private-glide-core-modal-lock-scroll"),this.dispatchEvent(new Event("close")),e(this,s).value?.close()},E=new WeakSet,j=function(){I(e(this,p).value)},y=new WeakSet,F=function(){d(e(this,g).value,[h])},C=new WeakSet,P=function(){d(e(this,v).value,[h])},M=new WeakSet,K=function(){d(e(this,f).value,[A,h])},$=new WeakSet,O=function(){d(e(this,S).value,[Z])},L=new WeakSet,W=function(t){t.key==="Escape"&&(document.documentElement.classList.remove("private-glide-core-modal-lock-scroll"),this.dispatchEvent(new Event("close")),e(this,s).value?.close())},H=new WeakSet,X=function(t){if(t.target!==e(this,s).value)return;const n=e(this,s).value?.getBoundingClientRect();n&&(n.top<=t.clientY&&t.clientY<=n.top+n.height&&n.left<=t.clientX&&t.clientX<=n.left+n.width||(document.documentElement.classList.remove("private-glide-core-modal-lock-scroll"),this.dispatchEvent(new Event("close")),e(this,s).value?.close()))},a.shadowRootOptions={...V.shadowRootOptions,mode:"closed"},a.styles=Q,b([T({reflect:!0})],a.prototype,"label",2),b([T({attribute:"show-back-button",type:Boolean,reflect:!0})],a.prototype,"showBackButton",2),b([T({reflect:!0})],a.prototype,"size",2),a=b([q("glide-core-modal")],a);export{a as default};
|
1
|
+
var __decorate=this&&this.__decorate||function(e,t,o,l){var n,r=arguments.length,i=r<3?t:null===l?l=Object.getOwnPropertyDescriptor(t,o):l;if("object"==typeof Reflect&&"function"==typeof Reflect.decorate)i=Reflect.decorate(e,t,o,l);else for(var s=e.length-1;s>=0;s--)(n=e[s])&&(i=(r<3?n(i):r>3?n(t,o,i):n(t,o))||i);return r>3&&i&&Object.defineProperty(t,o,i),i};import"./modal.icon-button.js";import{LitElement,html}from"lit";import{LocalizeController}from"./library/localize.js";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{setContainingBlock}from"./library/set-containing-block.js";import{when}from"lit/directives/when.js";import GlideCoreButton from"./button.js";import GlideCoreModalIconButton from"./modal.icon-button.js";import GlideCoreModalTertiaryIcon from"./modal.tertiary-icon.js";import styles from"./modal.styles.js";const globalStylesheet=new CSSStyleSheet;globalStylesheet.insertRule("\n @supports (scrollbar-gutter: stable) {\n .private-glide-core-modal-lock-scroll {\n scrollbar-gutter: stable !important;\n overflow: hidden !important;\n }\n }\n"),globalStylesheet.insertRule("\n @supports not (scrollbar-gutter: stable) {\n .private-glide-core-modal-lock-scroll {\n padding-right: var(--glide-scroll-size, 0.9375rem) !important;\n overflow: hidden !important;\n }\n }\n");let GlideCoreModal=class GlideCoreModal extends LitElement{constructor(){super(...arguments),this.label="",this.showBackButton=!1,this.size="medium",this.#e=createRef(),this.#t=createRef(),this.#o=createRef(),this.#l=createRef(),this.#n=createRef(),this.#r=createRef(),this.#i=new LocalizeController(this)}static{this.shadowRootOptions={...LitElement.shadowRootOptions,mode:"closed"}}static{this.styles=styles}close(){this.#e.value?.open&&(document.documentElement.classList.remove("private-glide-core-modal-lock-scroll"),this.dispatchEvent(new Event("close")),this.#e.value?.close())}connectedCallback(){super.connectedCallback();document.adoptedStyleSheets.includes(globalStylesheet)||document.adoptedStyleSheets.push(globalStylesheet)}disconnectedCallback(){super.disconnectedCallback(),document.documentElement.classList.remove("private-glide-core-modal-lock-scroll"),document.adoptedStyleSheets=document.adoptedStyleSheets.filter((e=>e!==globalStylesheet))}firstUpdated(){owSlot(this.#t.value),owSlotType(this.#r.value,[GlideCoreModalIconButton]),owSlotType(this.#o.value,[GlideCoreButton]),owSlotType(this.#l.value,[GlideCoreButton]),owSlotType(this.#n.value,[GlideCoreModalTertiaryIcon,GlideCoreButton])}render(){return html`<dialog class="${classMap({component:!0,small:"small"===this.size,medium:"medium"===this.size,large:"large"===this.size,xlarge:"xlarge"===this.size})}" tabindex="-1" @keydown="${this.#s}" @mousedown="${this.#a}" ${ref(this.#e)}><header class="header"><h2 class="label" data-test="heading" id="heading">${when(this.showBackButton,(()=>html`<glide-core-modal-icon-button data-test="back-button" @click="${this.#c}"><svg width="20" height="20" viewBox="0 0 24 24" fill="none"><title>${this.#i.term("dismiss")}</title><path d="M12 18C11.4477 18 11 18.4477 11 19C11 19.5523 11.4477 20 12 20V18ZM20 14.5C20 16.433 18.433 18 16.5 18V20C19.5376 20 22 17.5376 22 14.5H20ZM16.5 11C18.433 11 20 12.567 20 14.5H22C22 11.4624 19.5376 9 16.5 9V11ZM16.5 18H12V20H16.5V18ZM16.5 9H3V11H16.5V9Z" fill="currentColor"/><path d="M7 6L3 10L7 14" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"/></svg></glide-core-modal-icon-button>`))} ${this.label}</h2><div class="header-actions" role="toolbar"><slot name="header-actions" @slotchange="${this.#d}" ${ref(this.#r)}></slot><glide-core-modal-icon-button data-test="close-button" @click="${this.#c}"><svg width="24" height="24" viewBox="0 0 24 24" fill="none"><title>${this.#i.term("close")}</title><path d="M6 6L18 18" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"/><path d="M18 6L6 18" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"/></svg></glide-core-modal-icon-button></div></header><article aria-labelledby="heading" class="body" role="region" tabindex="0"><slot @slotchange="${this.#m}" ${ref(this.#t)}></slot></article><footer class="footer"><menu class="menu"><li class="flex align-center"><slot name="tertiary" @slotchange="${this.#h}" ${ref(this.#n)}></slot></li><li><menu class="actions"><li><slot name="secondary" @slotchange="${this.#u}" ${ref(this.#l)}></slot></li><li><slot name="primary" @slotchange="${this.#f}" ${ref(this.#o)}></slot></li></menu></li></menu></footer></dialog>`}showModal(){if(!this.#e.value?.open){if(document.documentElement.classList.add("private-glide-core-modal-lock-scroll"),!window.CSS.supports("scrollbar-gutter","stable")){const e=Math.abs(window.innerWidth-document.documentElement.clientWidth);document.documentElement.style.setProperty("--glide-scroll-size",`${e}px`)}this.#e.value?.showModal(),this.#e.value?.focus()}}#e;#t;#o;#l;#n;#r;#i;#c(){document.documentElement.classList.remove("private-glide-core-modal-lock-scroll"),this.dispatchEvent(new Event("close")),this.#e.value?.close()}#m(){owSlot(this.#t.value);const e=this.#t.value.assignedElements();setContainingBlock({elements:e,containingBlock:this.#e.value})}#f(){owSlotType(this.#o.value,[GlideCoreButton])}#u(){owSlotType(this.#l.value,[GlideCoreButton])}#h(){owSlotType(this.#n.value,[GlideCoreModalTertiaryIcon,GlideCoreButton]);const e=this.#n.value.assignedElements().filter((e=>e instanceof GlideCoreModalTertiaryIcon));for(const t of e)t.setContainingBlock(this.#e.value)}#d(){owSlotType(this.#r.value,[GlideCoreModalIconButton])}#s(e){"Escape"===e.key&&(document.documentElement.classList.remove("private-glide-core-modal-lock-scroll"),this.dispatchEvent(new Event("close")),this.#e.value?.close())}#a(e){if(e.target!==this.#e.value)return;const t=this.#e.value?.getBoundingClientRect();if(t){t.top<=e.clientY&&e.clientY<=t.top+t.height&&t.left<=e.clientX&&e.clientX<=t.left+t.width||(document.documentElement.classList.remove("private-glide-core-modal-lock-scroll"),this.dispatchEvent(new Event("close")),this.#e.value?.close())}}};__decorate([property({reflect:!0})],GlideCoreModal.prototype,"label",void 0),__decorate([property({attribute:"show-back-button",type:Boolean,reflect:!0})],GlideCoreModal.prototype,"showBackButton",void 0),__decorate([property({reflect:!0})],GlideCoreModal.prototype,"size",void 0),GlideCoreModal=__decorate([customElement("glide-core-modal")],GlideCoreModal);export default GlideCoreModal;
|
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 {
|
@@ -23,6 +23,7 @@
|
|
23
23
|
}
|
24
24
|
|
25
25
|
.component {
|
26
|
+
backdrop-filter: blur(100px);
|
26
27
|
background-color: var(--glide-core-surface-base-lighter);
|
27
28
|
border: none;
|
28
29
|
border-radius: 0.5rem;
|
@@ -42,10 +43,6 @@
|
|
42
43
|
outline: none;
|
43
44
|
}
|
44
45
|
|
45
|
-
&:focus-visible {
|
46
|
-
${e};
|
47
|
-
}
|
48
|
-
|
49
46
|
&::backdrop {
|
50
47
|
animation: backdrop-fade-in 250ms;
|
51
48
|
|
@@ -130,7 +127,7 @@
|
|
130
127
|
}
|
131
128
|
|
132
129
|
&:focus-visible {
|
133
|
-
${
|
130
|
+
${focusOutline};
|
134
131
|
}
|
135
132
|
}
|
136
133
|
|
@@ -166,4 +163,4 @@
|
|
166
163
|
.align-center {
|
167
164
|
align-items: center;
|
168
165
|
}
|
169
|
-
`];
|
166
|
+
`];
|
@@ -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 n=e.length-1;n>=0;n--)(r=e[n])&&(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";import GlideCoreTooltip from"./tooltip.js";let GlideCoreModalTertiaryIcon=class GlideCoreModalTertiaryIcon extends LitElement{constructor(){super(...arguments),this.tooltipPlacement="bottom",this.#e=createRef(),this.#t=createRef()}static{this.shadowRootOptions={...LitElement.shadowRootOptions,mode:"closed"}}firstUpdated(){owSlot(this.#e.value)}render(){return html`<glide-core-tooltip placement="${this.tooltipPlacement}" ${ref(this.#t)}>${this.label} <span tabindex="0" aria-label="${ifDefined(this.label)}" slot="target"><slot @slotchange="${this.#o}" ${ref(this.#e)}></slot></span></glide-core-tooltip>`}setContainingBlock(e){this.#t.value.containingBlock=e}#e;#t;#o(){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 @@
|
|
1
|
+
export {};
|