@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
@@ -0,0 +1,129 @@
|
|
1
|
+
import { ArgumentError } from 'ow';
|
2
|
+
import { expect, fixture, html } from '@open-wc/testing';
|
3
|
+
import GlideCoreLabel from './label.js';
|
4
|
+
import sinon from 'sinon';
|
5
|
+
GlideCoreLabel.shadowRootOptions.mode = 'open';
|
6
|
+
it('registers', async () => {
|
7
|
+
expect(window.customElements.get('glide-core-label')).to.equal(GlideCoreLabel);
|
8
|
+
});
|
9
|
+
it('has defaults', async () => {
|
10
|
+
const component = await fixture(html `<glide-core-label>
|
11
|
+
<label for="input">Label</label>
|
12
|
+
<input id="input" slot="control" />
|
13
|
+
</glide-core-label>`);
|
14
|
+
expect(component.getAttribute('error')).to.equal(null);
|
15
|
+
expect(component.error).to.equal(false);
|
16
|
+
expect(component.getAttribute('hide')).to.equal(null);
|
17
|
+
expect(component.hide).to.equal(false);
|
18
|
+
expect(component.getAttribute('orientation')).to.equal('horizontal');
|
19
|
+
expect(component.orientation).to.equal('horizontal');
|
20
|
+
expect(component.hasAttribute('required')).to.be.false;
|
21
|
+
expect(component.required).to.be.false;
|
22
|
+
});
|
23
|
+
it('is accessible', async () => {
|
24
|
+
const component = await fixture(html `<glide-core-label>
|
25
|
+
<label for="input">Label</label>
|
26
|
+
<input id="input" slot="control" />
|
27
|
+
<div slot="tooltip">Tooltip</div>
|
28
|
+
<div slot="description">Description</div>
|
29
|
+
</glide-core-label>`);
|
30
|
+
await expect(component).to.be.accessible();
|
31
|
+
});
|
32
|
+
it('can have a label', async () => {
|
33
|
+
const component = await fixture(html `<glide-core-label>
|
34
|
+
<label for="input">Label</label>
|
35
|
+
<input id="input" slot="control" />
|
36
|
+
</glide-core-label>`);
|
37
|
+
const assignedElements = component.shadowRoot
|
38
|
+
?.querySelector('slot:not([name])')
|
39
|
+
?.assignedElements();
|
40
|
+
expect(assignedElements?.at(0)?.textContent).to.equal('Label');
|
41
|
+
});
|
42
|
+
it('can have a description', async () => {
|
43
|
+
const component = await fixture(html `<glide-core-label>
|
44
|
+
<label for="input">Label</label>
|
45
|
+
<input id="input" slot="control" />
|
46
|
+
<div slot="description">Description</div>
|
47
|
+
</glide-core-label>`);
|
48
|
+
const assignedElements = component.shadowRoot
|
49
|
+
?.querySelector('slot[name="description"]')
|
50
|
+
?.assignedElements();
|
51
|
+
expect(assignedElements?.at(0)?.textContent).to.equal('Description');
|
52
|
+
});
|
53
|
+
it('can have a tooltip', async () => {
|
54
|
+
const component = await fixture(html `<glide-core-label>
|
55
|
+
<label for="input">Label</label>
|
56
|
+
<input id="input" slot="control" />
|
57
|
+
<div slot="tooltip">Tooltip</div>
|
58
|
+
</glide-core-label>`);
|
59
|
+
const assignedElements = component.shadowRoot
|
60
|
+
?.querySelector('slot[name="tooltip"]')
|
61
|
+
?.assignedElements();
|
62
|
+
expect(assignedElements?.at(0)?.textContent).to.equal('Tooltip');
|
63
|
+
});
|
64
|
+
it('can be required', async () => {
|
65
|
+
const component = await fixture(html `<glide-core-label required>
|
66
|
+
<label for="input">Label</label>
|
67
|
+
<input id="input" slot="control" />
|
68
|
+
</glide-core-label>`);
|
69
|
+
expect(component.hasAttribute('required')).to.be.true;
|
70
|
+
expect(component.required).to.equal(true);
|
71
|
+
const label = component.shadowRoot?.querySelector('[data-test="label"]');
|
72
|
+
expect(label?.textContent?.includes('*')).to.be.true;
|
73
|
+
});
|
74
|
+
it('can have an `error`', async () => {
|
75
|
+
const component = await fixture(html `<glide-core-label ?error=${true}>
|
76
|
+
<label for="input">Label</label>
|
77
|
+
<input id="input" slot="control" />
|
78
|
+
</glide-core-label>`);
|
79
|
+
expect(component.hasAttribute('error')).to.be.true;
|
80
|
+
expect(component.error).to.equal(true);
|
81
|
+
});
|
82
|
+
it('places the tooltip on the bottom when horizontal', async () => {
|
83
|
+
const component = await fixture(html `<glide-core-label>
|
84
|
+
<label for="input">Label</label>
|
85
|
+
<input id="input" slot="control" />
|
86
|
+
<div slot="tooltip">Tooltip</div>
|
87
|
+
</glide-core-label>`);
|
88
|
+
expect(component.shadowRoot
|
89
|
+
?.querySelector('glide-core-tooltip')
|
90
|
+
?.getAttribute('placement')).to.equal('bottom');
|
91
|
+
});
|
92
|
+
it('places the tooltip on the right when vertical', async () => {
|
93
|
+
const component = await fixture(html `<glide-core-label orientation="vertical">
|
94
|
+
<label for="input">Label</label>
|
95
|
+
<input id="input" slot="control" />
|
96
|
+
<div slot="tooltip">Tooltip</div>
|
97
|
+
</glide-core-label>`);
|
98
|
+
expect(component.shadowRoot
|
99
|
+
?.querySelector('glide-core-tooltip')
|
100
|
+
?.getAttribute('placement')).to.equal('right');
|
101
|
+
});
|
102
|
+
it('throws if it does not have a default slot', async () => {
|
103
|
+
const spy = sinon.spy();
|
104
|
+
try {
|
105
|
+
await fixture(html `<glide-core-label orientation="vertical"
|
106
|
+
><input slot="control"
|
107
|
+
/></glide-core-label>`);
|
108
|
+
}
|
109
|
+
catch (error) {
|
110
|
+
if (error instanceof ArgumentError) {
|
111
|
+
spy();
|
112
|
+
}
|
113
|
+
}
|
114
|
+
expect(spy.called).to.be.true;
|
115
|
+
});
|
116
|
+
it('throws if it does not have a "control" slot', async () => {
|
117
|
+
const spy = sinon.spy();
|
118
|
+
try {
|
119
|
+
await fixture(html `<glide-core-label orientation="vertical">
|
120
|
+
<label>Label</label>
|
121
|
+
</glide-core-label>`);
|
122
|
+
}
|
123
|
+
catch (error) {
|
124
|
+
if (error instanceof ArgumentError) {
|
125
|
+
spy();
|
126
|
+
}
|
127
|
+
}
|
128
|
+
expect(spy.called).to.be.true;
|
129
|
+
});
|
@@ -1 +1 @@
|
|
1
|
-
|
1
|
+
import{ArgumentError}from"ow";import{expect}from"@open-wc/testing";import sinon from"sinon";export default async function(o){const r=window.onerror;window.onerror=null;const n=sinon.spy();try{await o.call(context)}catch(o){o instanceof ArgumentError&&n()}expect(n.called).to.be.true,window.onerror=r}
|
package/dist/library/ow.js
CHANGED
@@ -1 +1 @@
|
|
1
|
-
|
1
|
+
import ow,{}from"ow";const isDevelopment=window.location.host.startsWith("localhost")||window.location.host.startsWith("127.0.0.1");export function owSlot(e){isDevelopment&&(ow(e,ow.object.is((e=>e instanceof HTMLSlotElement))),ow(e.assignedNodes().length,ow.number.is((e=>e>0)).message(e.name?`Expected a "${e.name}" slot.`:"Expected a default slot.")))}export function owSlotType(e,o=[]){if(isDevelopment&&(ow(e,ow.object.is((e=>e instanceof HTMLSlotElement))),0!==e.assignedNodes().length&&o.length>0)){const t=e.assignedNodes({flatten:!0}).filter((e=>!!(e instanceof Text&&o.includes(Text))||!(e instanceof Text)));ow(t.length,ow.number.is((e=>e>0)).message(`Expected a slotted node that extends ${o.map((({name:e})=>e)).join(" or ")}.`));for(const e of t){const t=`Expected slotted node to extend ${o.map((({name:e})=>e)).join(" or ")}. Extends ${e.constructor.name} instead.`,n=o.some((o=>e instanceof o));ow(n,ow.boolean.true.message(t))}}}const shim=new Proxy((()=>{}),{get:()=>shim,apply:()=>shim}),owOrShim=isDevelopment?ow:shim;export default owOrShim;
|
@@ -0,0 +1,55 @@
|
|
1
|
+
var __decorate = (this && this.__decorate) || function (decorators, target, key, desc) {
|
2
|
+
var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
|
3
|
+
if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc);
|
4
|
+
else for (var i = decorators.length - 1; i >= 0; i--) if (d = decorators[i]) r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r;
|
5
|
+
return c > 3 && r && Object.defineProperty(target, key, r), r;
|
6
|
+
};
|
7
|
+
/* eslint-disable @crowdstrike/glide-core-eslint-plugin/prefer-closed-shadow-root */
|
8
|
+
/* This is a test file that doesn't contain one of our components, so we don't need to enforce this rule. */
|
9
|
+
import { LitElement } from 'lit';
|
10
|
+
import { assert, expect, fixture, html } from '@open-wc/testing';
|
11
|
+
import { customElement } from 'lit/decorators.js';
|
12
|
+
import { owSlot, owSlotType } from './ow.js';
|
13
|
+
let GlideCoreSlot = class GlideCoreSlot extends LitElement {
|
14
|
+
render() {
|
15
|
+
return html `<slot></slot>`;
|
16
|
+
}
|
17
|
+
};
|
18
|
+
GlideCoreSlot = __decorate([
|
19
|
+
customElement('glide-core-slot')
|
20
|
+
], GlideCoreSlot);
|
21
|
+
export default GlideCoreSlot;
|
22
|
+
it('throws when a slot lacks a node', async () => {
|
23
|
+
const component = await fixture(html `<glide-core-slot></glide-core-slot>`);
|
24
|
+
const slot = component.shadowRoot?.querySelector('slot');
|
25
|
+
assert(slot !== null);
|
26
|
+
expect(() => owSlot(slot)).to.throw();
|
27
|
+
});
|
28
|
+
it('throws when a slot lacks a specific node', async () => {
|
29
|
+
const component = await fixture(html `<glide-core-slot>
|
30
|
+
<span>Span</span>
|
31
|
+
</glide-core-slot>`);
|
32
|
+
const slot = component.shadowRoot?.querySelector('slot');
|
33
|
+
assert(slot !== null);
|
34
|
+
expect(() => owSlotType(slot, [HTMLButtonElement])).to.throw();
|
35
|
+
});
|
36
|
+
it('does not throw when a slot has a node', async () => {
|
37
|
+
const component = await fixture(html `<glide-core-slot>
|
38
|
+
<span>Span</span>
|
39
|
+
</glide-core-slot>`);
|
40
|
+
const slot = component.shadowRoot?.querySelector('slot');
|
41
|
+
assert(slot !== null);
|
42
|
+
expect(() => owSlot(slot)).to.not.throw();
|
43
|
+
});
|
44
|
+
it('does not throw when a slot has a specific node', async () => {
|
45
|
+
const component = await fixture(html `<glide-core-slot> Text </glide-core-slot>`);
|
46
|
+
const slot = component.shadowRoot?.querySelector('slot');
|
47
|
+
assert(slot !== null);
|
48
|
+
expect(() => owSlotType(slot, [Text])).to.not.throw();
|
49
|
+
});
|
50
|
+
it('does not throw when a slot has no nodes', async () => {
|
51
|
+
const component = await fixture(html `<glide-core-slot></glide-core-slot>`);
|
52
|
+
const slot = component.shadowRoot?.querySelector('slot');
|
53
|
+
assert(slot !== null);
|
54
|
+
expect(() => owSlotType(slot, [HTMLButtonElement])).to.not.throw();
|
55
|
+
});
|
package/dist/menu.button.d.ts
CHANGED
@@ -15,7 +15,6 @@ export default class GlideCoreMenuButton extends LitElement {
|
|
15
15
|
static styles: import("lit").CSSResult[];
|
16
16
|
label?: string;
|
17
17
|
privateActive: boolean;
|
18
|
-
|
19
|
-
focus(): void;
|
18
|
+
connectedCallback(): void;
|
20
19
|
render(): import("lit").TemplateResult<1>;
|
21
20
|
}
|
package/dist/menu.button.js
CHANGED
@@ -1 +1 @@
|
|
1
|
-
|
1
|
+
var __decorate=this&&this.__decorate||function(t,e,o,r){var i,n=arguments.length,s=n<3?e:null===r?r=Object.getOwnPropertyDescriptor(e,o):r;if("object"==typeof Reflect&&"function"==typeof Reflect.decorate)s=Reflect.decorate(t,e,o,r);else for(var l=t.length-1;l>=0;l--)(i=t[l])&&(s=(n<3?i(s):n>3?i(e,o,s):i(e,o))||s);return n>3&&s&&Object.defineProperty(e,o,s),s};import{LitElement,html}from"lit";import{classMap}from"lit/directives/class-map.js";import{customElement,property}from"lit/decorators.js";import styles from"./menu.button.styles.js";let GlideCoreMenuButton=class GlideCoreMenuButton extends LitElement{constructor(){super(...arguments),this.privateActive=!1,this.#t=window.crypto.randomUUID()}static{this.shadowRootOptions={...LitElement.shadowRootOptions,mode:"closed"}}static{this.styles=styles}connectedCallback(){super.connectedCallback(),this.id=this.#t,this.role="menuitem",this.tabIndex=-1}render(){return html`<button class="${classMap({component:!0,active:this.privateActive})}" data-test="component" type="button"><slot name="icon"></slot>${this.label}</button>`}#t};__decorate([property({reflect:!0})],GlideCoreMenuButton.prototype,"label",void 0),__decorate([property({type:Boolean})],GlideCoreMenuButton.prototype,"privateActive",void 0),GlideCoreMenuButton=__decorate([customElement("glide-core-menu-button")],GlideCoreMenuButton);export default GlideCoreMenuButton;
|
@@ -1,4 +1,4 @@
|
|
1
|
-
|
1
|
+
import{css}from"lit";export default[css`
|
2
2
|
.component {
|
3
3
|
align-items: center;
|
4
4
|
background-color: transparent;
|
@@ -13,8 +13,8 @@
|
|
13
13
|
padding-inline: var(--padding-inline);
|
14
14
|
user-select: none;
|
15
15
|
|
16
|
-
&.
|
16
|
+
&.active {
|
17
17
|
background-color: var(--glide-core-surface-hover);
|
18
18
|
}
|
19
19
|
}
|
20
|
-
`];
|
20
|
+
`];
|
@@ -0,0 +1,42 @@
|
|
1
|
+
import { expect, fixture, html } from '@open-wc/testing';
|
2
|
+
import GlideCoreMenuButton from './menu.button.js';
|
3
|
+
GlideCoreMenuButton.shadowRootOptions.mode = 'open';
|
4
|
+
it('registers', async () => {
|
5
|
+
expect(window.customElements.get('glide-core-menu-button')).to.equal(GlideCoreMenuButton);
|
6
|
+
});
|
7
|
+
it('has defaults', async () => {
|
8
|
+
// Required attributes are supplied and not asserted below. The idea is that
|
9
|
+
// this test shouldn't fail to typecheck if these templates are eventually
|
10
|
+
// typechecked, which means supplying required attributes up front.
|
11
|
+
const component = await fixture(html `<glide-core-menu-button label="Label"></glide-core-menu-button>`);
|
12
|
+
// Not reflected. So no attribute assertions are necessary.
|
13
|
+
expect(component.privateActive).to.equal(false);
|
14
|
+
});
|
15
|
+
it('can have a label', async () => {
|
16
|
+
const button = await fixture(html `<glide-core-menu-button label="Label"></glide-core-menu-button>`);
|
17
|
+
expect(button.shadowRoot?.textContent?.trim()).to.equal('Label');
|
18
|
+
});
|
19
|
+
it('can have an icon', async () => {
|
20
|
+
const component = await fixture(html `<glide-core-menu-button label="Label">
|
21
|
+
<svg
|
22
|
+
slot="icon"
|
23
|
+
width="16"
|
24
|
+
height="16"
|
25
|
+
fill="none"
|
26
|
+
viewBox="0 0 24 24"
|
27
|
+
stroke-width="1.5"
|
28
|
+
stroke="currentColor"
|
29
|
+
>
|
30
|
+
<path
|
31
|
+
stroke-linecap="round"
|
32
|
+
stroke-linejoin="round"
|
33
|
+
d="m16.862 4.487 1.687-1.688a1.875 1.875 0 1 1 2.652 2.652L10.582 16.07a4.5 4.5 0 0 1-1.897 1.13L6 18l.8-2.685a4.5 4.5 0 0 1 1.13-1.897l8.932-8.931Zm0 0L19.5 7.125M18 14v4.75A2.25 2.25 0 0 1 15.75 21H5.25A2.25 2.25 0 0 1 3 18.75V8.25A2.25 2.25 0 0 1 5.25 6H10"
|
34
|
+
/>
|
35
|
+
</svg>
|
36
|
+
</glide-core-menu-button>`);
|
37
|
+
const icon = component?.shadowRoot
|
38
|
+
?.querySelector('slot[name="icon"]')
|
39
|
+
?.assignedElements()
|
40
|
+
.at(0);
|
41
|
+
expect(icon instanceof Element).to.be.true;
|
42
|
+
});
|
package/dist/menu.d.ts
CHANGED
@@ -19,9 +19,13 @@ export default class GlideCoreMenu extends LitElement {
|
|
19
19
|
set open(isOpen: boolean);
|
20
20
|
placement: Placement;
|
21
21
|
size: 'small' | 'large';
|
22
|
+
private get activeOption();
|
22
23
|
connectedCallback(): void;
|
24
|
+
createRenderRoot(): ShadowRoot;
|
23
25
|
disconnectedCallback(): void;
|
24
26
|
firstUpdated(): void;
|
25
27
|
focus(): void;
|
26
28
|
render(): import("lit").TemplateResult<1>;
|
29
|
+
private ariaActivedescendant;
|
30
|
+
private isTargetDisabled;
|
27
31
|
}
|
package/dist/menu.js
CHANGED
@@ -1 +1 @@
|
|
1
|
-
|
1
|
+
var __decorate=this&&this.__decorate||function(e,t,i,n){var o,s=arguments.length,a=s<3?t:null===n?n=Object.getOwnPropertyDescriptor(t,i):n;if("object"==typeof Reflect&&"function"==typeof Reflect.decorate)a=Reflect.decorate(e,t,i,n);else for(var l=e.length-1;l>=0;l--)(o=e[l])&&(a=(s<3?o(a):s>3?o(t,i,a):o(t,i))||a);return s>3&&a&&Object.defineProperty(t,i,a),a};import{LitElement,html}from"lit";import{autoUpdate,computePosition,flip,offset}from"@floating-ui/dom";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{owSlot,owSlotType}from"./library/ow.js";import GlideCoreMenuButton from"./menu.button.js";import GlideCoreMenuLink from"./menu.link.js";import styles from"./menu.styles.js";let GlideCoreMenu=class GlideCoreMenu extends LitElement{constructor(){super(...arguments),this.placement="bottom-start",this.size="large",this.ariaActivedescendant="",this.isTargetDisabled=!1,this.#e=createRef(),this.#t=createRef(),this.#i=!1,this.#n=!1,this.#o=createRef(),this.#s=createRef(),this.#a=e=>{e.target&&this.contains(e.target)||(this.open=!1,this.ariaActivedescendant="")}}static{this.shadowRootOptions={...LitElement.shadowRootOptions,mode:"closed"}}static{this.styles=styles}get open(){return this.#n}set open(e){this.#n=e,e&&!this.isTargetDisabled?(this.#l(),this.ariaActivedescendant=this.activeOption?.id??""):(this.#r?.(),this.ariaActivedescendant=""),this.#c&&(this.#c.ariaExpanded=e&&!this.isTargetDisabled?"true":"false")}get activeOption(){return this.#d?.find((({privateActive:e})=>e))}connectedCallback(){super.connectedCallback(),document.addEventListener("click",this.#a,{capture:!0})}createRenderRoot(){return this.#p=super.createRenderRoot(),this.#p}disconnectedCallback(){super.disconnectedCallback(),document.removeEventListener("click",this.#a,{capture:!0})}firstUpdated(){owSlot(this.#t.value),owSlot(this.#s.value),owSlotType(this.#t.value,[GlideCoreMenuButton,GlideCoreMenuLink,Text]);const e=this.#d.at(0);this.open&&e&&(this.#l(),e.privateActive=!0,this.ariaActivedescendant=e.id)}focus(){this.#c&&"focus"in this.#c&&this.#c?.focus()}render(){return html`<div class="component" @focusout="${this.#h}" ${ref(this.#e)}><div class="container" id="container"><slot name="target" @click="${this.#u}" @keydown="${this.#m}" @slotchange="${this.#f}" ${ref(this.#s)}></slot></div><div aria-activedescendant="${this.ariaActivedescendant}" aria-labelledby="container" class="${classMap({menu:!0,large:"large"===this.size,small:"small"===this.size,visible:this.open&&!this.isTargetDisabled})}" data-test="menu" role="menu" tabindex="-1" ${ref(this.#o)}><slot @click="${this.#v}" @focusin="${this.#g}" @keydown="${this.#m}" @mouseover="${this.#E}" @slotchange="${this.#y}" ${ref(this.#t)}></slot></div></div>`}#r;#e;#t;#i;#n;#o;#p;#s;#a;#y(){owSlot(this.#t.value),owSlotType(this.#t.value,[GlideCoreMenuButton,GlideCoreMenuLink,Text]);const e=this.#d.at(0);e&&(e.privateActive=!0)}#v(){this.open=!1,this.ariaActivedescendant=""}#g(e){(e.target instanceof GlideCoreMenuButton||e.target instanceof GlideCoreMenuLink)&&this.activeOption&&(this.activeOption.privateActive=!1,e.target.privateActive=!0,this.ariaActivedescendant=e.target.id)}#E(e){if(e.target instanceof GlideCoreMenuLink||e.target instanceof GlideCoreMenuButton){for(const t of this.#d)t.privateActive=t===e.target;this.ariaActivedescendant=e.target.id}}#h(e){const t=e.relatedTarget instanceof HTMLElement&&this.#p?.contains(e.relatedTarget),i=e.relatedTarget instanceof HTMLElement&&this.contains(e.relatedTarget);t||i||(this.open=!1)}#m(e){if([" ","Enter","Escape"].includes(e.key)&&this.open)return this.open=!1,this.ariaActivedescendant="",this.focus(),void(this.#i=!0);if([" ","ArrowUp","ArrowDown"].includes(e.key)&&!this.open&&this.activeOption)return e.preventDefault(),this.open=!0,void(this.ariaActivedescendant=this.activeOption.id);if(this.open&&this.activeOption){const t=this.#d.indexOf(this.activeOption);if("ArrowUp"===e.key&&!e.metaKey){e.preventDefault();const i=this.#d.at(t-1);return void(i&&0!==t&&(this.activeOption.privateActive=!1,this.ariaActivedescendant=i.id,i.privateActive=!0))}if("ArrowDown"===e.key&&!e.metaKey){e.preventDefault();const i=this.#d.at(t+1);return void(i&&(this.activeOption.privateActive=!1,this.ariaActivedescendant=i.id,i.privateActive=!0))}if("ArrowUp"===e.key&&e.metaKey||"Home"===e.key||"PageUp"===e.key){e.preventDefault();const t=this.#d.at(0);return void(t&&(this.activeOption.privateActive=!1,this.ariaActivedescendant=t.id,t.privateActive=!0))}if("ArrowDown"===e.key&&e.metaKey||"End"===e.key||"PageDown"===e.key){e.preventDefault();const t=this.#d.at(-1);return void(t&&(this.activeOption.privateActive=!1,this.ariaActivedescendant=t.id,t.privateActive=!0))}}}#f(){owSlot(this.#s.value);const e=this.#c&&"disabled"in this.#c&&this.#c.disabled,t=this.#c&&"true"===this.#c.ariaDisabled;this.isTargetDisabled=Boolean(e)||Boolean(t),this.#c&&this.#o.value&&(this.#c.ariaHasPopup="true",this.#c.ariaExpanded=this.open&&!this.isTargetDisabled?"true":"false")}#u(){this.isTargetDisabled||this.#i?this.#i=!1:(this.#c instanceof HTMLElement&&(this.#c.ariaExpanded=this.open?"true":"false"),this.open=!this.open,this.open&&this.activeOption?this.ariaActivedescendant=this.activeOption.id:this.open||(this.ariaActivedescendant="",this.focus()))}get#d(){return(this.#t.value?.assignedElements({flatten:!0})??[]).filter((e=>e instanceof GlideCoreMenuLink||e instanceof GlideCoreMenuButton))}#l(){this.#c&&this.#o.value&&(this.#r=autoUpdate(this.#c,this.#o.value,(()=>{(async()=>{if(this.#c&&this.#o.value){const{x:e,y:t,placement:i}=await computePosition(this.#c,this.#o.value,{placement:this.placement,middleware:[offset({mainAxis:16*Number.parseFloat(window.getComputedStyle(document.body).getPropertyValue("--glide-core-spacing-xxs"))}),flip()]});this.#o.value.dataset.placement=i,Object.assign(this.#o.value.style,{left:`${e}px`,top:`${t}px`})}})()})))}get#c(){return this.#s.value?.assignedElements().at(0)}};__decorate([property({reflect:!0,type:Boolean})],GlideCoreMenu.prototype,"open",null),__decorate([property({reflect:!0})],GlideCoreMenu.prototype,"placement",void 0),__decorate([property({reflect:!0})],GlideCoreMenu.prototype,"size",void 0),__decorate([state()],GlideCoreMenu.prototype,"ariaActivedescendant",void 0),__decorate([state()],GlideCoreMenu.prototype,"isTargetDisabled",void 0),GlideCoreMenu=__decorate([customElement("glide-core-menu")],GlideCoreMenu);export default GlideCoreMenu;
|
package/dist/menu.link.d.ts
CHANGED
package/dist/menu.link.js
CHANGED
@@ -1 +1 @@
|
|
1
|
-
|
1
|
+
var __decorate=this&&this.__decorate||function(e,t,o,i){var r,n=arguments.length,l=n<3?t:null===i?i=Object.getOwnPropertyDescriptor(t,o):i;if("object"==typeof Reflect&&"function"==typeof Reflect.decorate)l=Reflect.decorate(e,t,o,i);else for(var s=e.length-1;s>=0;s--)(r=e[s])&&(l=(n<3?r(l):n>3?r(t,o,l):r(t,o))||l);return n>3&&l&&Object.defineProperty(t,o,l),l};import{LitElement,html}from"lit";import{classMap}from"lit/directives/class-map.js";import{customElement,property}from"lit/decorators.js";import{ifDefined}from"lit/directives/if-defined.js";import styles from"./menu.link.styles.js";let GlideCoreMenuLink=class GlideCoreMenuLink extends LitElement{constructor(){super(...arguments),this.privateActive=!1,this.#e=window.crypto.randomUUID()}static{this.shadowRootOptions={...LitElement.shadowRootOptions,mode:"closed"}}static{this.styles=styles}connectedCallback(){super.connectedCallback(),this.id=this.#e,this.role="menuitem",this.tabIndex=-1}render(){return html`<a class="${classMap({component:!0,active:this.privateActive})}" data-test="component" href="${ifDefined(this.url)}"><slot name="icon"></slot>${this.label}</a>`}#e};__decorate([property({reflect:!0})],GlideCoreMenuLink.prototype,"label",void 0),__decorate([property({reflect:!0})],GlideCoreMenuLink.prototype,"url",void 0),__decorate([property({type:Boolean})],GlideCoreMenuLink.prototype,"privateActive",void 0),GlideCoreMenuLink=__decorate([customElement("glide-core-menu-link")],GlideCoreMenuLink);export default GlideCoreMenuLink;
|
package/dist/menu.link.styles.js
CHANGED
@@ -1,4 +1,4 @@
|
|
1
|
-
|
1
|
+
import{css}from"lit";export default[css`
|
2
2
|
.component {
|
3
3
|
align-items: center;
|
4
4
|
background-color: transparent;
|
@@ -15,8 +15,8 @@
|
|
15
15
|
text-decoration: none;
|
16
16
|
user-select: none;
|
17
17
|
|
18
|
-
&.
|
18
|
+
&.active {
|
19
19
|
background-color: var(--glide-core-surface-hover);
|
20
20
|
}
|
21
21
|
}
|
22
|
-
`];
|
22
|
+
`];
|
@@ -0,0 +1,46 @@
|
|
1
|
+
import { expect, fixture, html } from '@open-wc/testing';
|
2
|
+
import GlideCoreMenuLink from './menu.link.js';
|
3
|
+
GlideCoreMenuLink.shadowRootOptions.mode = 'open';
|
4
|
+
it('registers', async () => {
|
5
|
+
expect(window.customElements.get('glide-core-menu-link')).to.equal(GlideCoreMenuLink);
|
6
|
+
});
|
7
|
+
it('has defaults', async () => {
|
8
|
+
// Required attributes are supplied and not asserted below. The idea is that
|
9
|
+
// this test shouldn't fail to typecheck if these templates are eventually
|
10
|
+
// typechecked, which means supplying required attributes up front.
|
11
|
+
const component = await fixture(html `<glide-core-menu-link label="Label" url="/"></glide-core-menu-link>`);
|
12
|
+
// Not reflected. So no attribute assertions are necessary.
|
13
|
+
expect(component.privateActive).to.be.false;
|
14
|
+
});
|
15
|
+
it('can have a label', async () => {
|
16
|
+
const component = await fixture(html `<glide-core-menu-link label="Label" url="/"></glide-core-menu-link>`);
|
17
|
+
expect(component.shadowRoot?.textContent?.trim()).to.equal('Label');
|
18
|
+
});
|
19
|
+
it('can have a URL', async () => {
|
20
|
+
const component = await fixture(html `<glide-core-menu-link label="Label" url="/"></glide-core-menu-link>`);
|
21
|
+
expect(component.url).to.equal('/');
|
22
|
+
});
|
23
|
+
it('can have an icon', async () => {
|
24
|
+
const component = await fixture(html `<glide-core-menu-link label="Label">
|
25
|
+
<svg
|
26
|
+
slot="icon"
|
27
|
+
width="16"
|
28
|
+
height="16"
|
29
|
+
fill="none"
|
30
|
+
viewBox="0 0 24 24"
|
31
|
+
stroke-width="1.5"
|
32
|
+
stroke="currentColor"
|
33
|
+
>
|
34
|
+
<path
|
35
|
+
stroke-linecap="round"
|
36
|
+
stroke-linejoin="round"
|
37
|
+
d="m16.862 4.487 1.687-1.688a1.875 1.875 0 1 1 2.652 2.652L10.582 16.07a4.5 4.5 0 0 1-1.897 1.13L6 18l.8-2.685a4.5 4.5 0 0 1 1.13-1.897l8.932-8.931Zm0 0L19.5 7.125M18 14v4.75A2.25 2.25 0 0 1 15.75 21H5.25A2.25 2.25 0 0 1 3 18.75V8.25A2.25 2.25 0 0 1 5.25 6H10"
|
38
|
+
/>
|
39
|
+
</svg>
|
40
|
+
</glide-core-menu-link>`);
|
41
|
+
const icon = component?.shadowRoot
|
42
|
+
?.querySelector('slot[name="icon"]')
|
43
|
+
?.assignedElements()
|
44
|
+
.at(0);
|
45
|
+
expect(icon instanceof Element).to.be.true;
|
46
|
+
});
|
package/dist/menu.styles.js
CHANGED
@@ -1,4 +1,4 @@
|
|
1
|
-
|
1
|
+
import{css}from"lit";export default[css`
|
2
2
|
:host {
|
3
3
|
/* Contains elements with "padding", "margin", and "width". Inline by default. */
|
4
4
|
display: inline-block;
|
@@ -9,14 +9,14 @@
|
|
9
9
|
display: flex;
|
10
10
|
}
|
11
11
|
|
12
|
-
.
|
12
|
+
.container {
|
13
13
|
display: flex;
|
14
14
|
position: relative;
|
15
15
|
}
|
16
16
|
|
17
|
-
.
|
18
|
-
background-color: var(--glide-core-surface-
|
19
|
-
border: 1px solid var(--glide-core-
|
17
|
+
.menu {
|
18
|
+
background-color: var(--glide-core-surface-modal);
|
19
|
+
border: 1px solid var(--glide-core-surface-modal);
|
20
20
|
border-radius: var(--glide-core-spacing-xs);
|
21
21
|
box-shadow: var(--glide-core-shadow-lg);
|
22
22
|
box-sizing: border-box;
|
@@ -29,6 +29,13 @@
|
|
29
29
|
position: absolute;
|
30
30
|
visibility: hidden;
|
31
31
|
|
32
|
+
/*
|
33
|
+
".container" is relative and many Menus may be stacked in a column.
|
34
|
+
This ensures the ".menu" of Menus earlier in the column aren't obscured
|
35
|
+
by the ".target-container" that come later.
|
36
|
+
*/
|
37
|
+
z-index: 1;
|
38
|
+
|
32
39
|
&.visible {
|
33
40
|
visibility: visible;
|
34
41
|
}
|
@@ -58,4 +65,4 @@
|
|
58
65
|
line-height: var(--glide-core-body-xs-line-height);
|
59
66
|
}
|
60
67
|
}
|
61
|
-
`];
|
68
|
+
`];
|