@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.
Files changed (208) hide show
  1. package/dist/accordion.js +1 -1
  2. package/dist/accordion.styles.js +4 -4
  3. package/dist/accordion.test.basics.js +109 -0
  4. package/dist/accordion.test.events.js +39 -0
  5. package/dist/button-group.button.js +1 -1
  6. package/dist/button-group.button.styles.js +4 -4
  7. package/dist/button-group.button.test.basics.js +169 -0
  8. package/dist/button-group.button.test.events.js +73 -0
  9. package/dist/button-group.js +1 -1
  10. package/dist/button-group.styles.js +3 -3
  11. package/dist/button-group.test.basics.js +268 -0
  12. package/dist/button-group.test.events.js +291 -0
  13. package/dist/button.js +1 -1
  14. package/dist/button.styles.js +4 -4
  15. package/dist/button.test.basics.js +196 -0
  16. package/dist/button.test.events.js +25 -0
  17. package/dist/button.test.form.js +49 -0
  18. package/dist/checkbox-group.js +1 -1
  19. package/dist/checkbox-group.styles.js +2 -2
  20. package/dist/checkbox-group.test.basics.js +119 -0
  21. package/dist/checkbox-group.test.events.js +110 -0
  22. package/dist/checkbox-group.test.focus.js +45 -0
  23. package/dist/checkbox-group.test.form.js +130 -0
  24. package/dist/checkbox-group.test.validity.js +75 -0
  25. package/dist/checkbox.js +1 -1
  26. package/dist/checkbox.styles.js +3 -3
  27. package/dist/checkbox.test.basics.js +89 -0
  28. package/dist/checkbox.test.events.js +87 -0
  29. package/dist/checkbox.test.focus.js +38 -0
  30. package/dist/checkbox.test.form.js +115 -0
  31. package/dist/checkbox.test.states.js +62 -0
  32. package/dist/checkbox.test.validity.js +51 -0
  33. package/dist/drawer.d.ts +2 -2
  34. package/dist/drawer.js +1 -15
  35. package/dist/drawer.styles.js +18 -3
  36. package/dist/drawer.test.accessibility.js +22 -0
  37. package/dist/drawer.test.basics.js +43 -0
  38. package/dist/drawer.test.closing.js +37 -0
  39. package/dist/drawer.test.events.js +52 -0
  40. package/dist/drawer.test.methods.js +34 -0
  41. package/dist/dropdown.d.ts +4 -2
  42. package/dist/dropdown.js +1 -1
  43. package/dist/dropdown.option.d.ts +1 -3
  44. package/dist/dropdown.option.js +1 -1
  45. package/dist/dropdown.option.styles.js +2 -2
  46. package/dist/dropdown.option.test.basics.js +59 -0
  47. package/dist/dropdown.option.test.basics.multiple.js +26 -0
  48. package/dist/dropdown.option.test.basics.single.js +20 -0
  49. package/dist/dropdown.option.test.events.js +27 -0
  50. package/dist/dropdown.option.test.focus.js +11 -0
  51. package/dist/dropdown.option.test.interactions.multiple.js +87 -0
  52. package/dist/dropdown.option.test.interactions.single.js +22 -0
  53. package/dist/dropdown.styles.js +28 -9
  54. package/dist/dropdown.test.basics.filterable.js +84 -0
  55. package/dist/dropdown.test.basics.js +233 -0
  56. package/dist/dropdown.test.basics.multiple.js +270 -0
  57. package/dist/dropdown.test.basics.single.js +79 -0
  58. package/dist/dropdown.test.events.js +268 -0
  59. package/dist/dropdown.test.events.multiple.js +130 -0
  60. package/dist/dropdown.test.focus.d.ts +1 -0
  61. package/dist/dropdown.test.focus.filterable.js +154 -0
  62. package/dist/dropdown.test.focus.js +18 -0
  63. package/dist/dropdown.test.focus.multiple.js +181 -0
  64. package/dist/dropdown.test.focus.single.js +53 -0
  65. package/dist/dropdown.test.form.js +140 -0
  66. package/dist/dropdown.test.form.multiple.js +149 -0
  67. package/dist/dropdown.test.form.single.js +128 -0
  68. package/dist/dropdown.test.interactions.filterable.js +385 -0
  69. package/dist/dropdown.test.interactions.js +446 -0
  70. package/dist/dropdown.test.interactions.multiple.js +908 -0
  71. package/dist/dropdown.test.interactions.single.js +466 -0
  72. package/dist/dropdown.test.validity.js +46 -0
  73. package/dist/icon-button.js +1 -1
  74. package/dist/icon-button.styles.js +3 -3
  75. package/dist/icon-button.test.basics.js +103 -0
  76. package/dist/icons/checked.js +1 -1
  77. package/dist/icons/magnifying-glass.js +1 -1
  78. package/dist/input.js +1 -1
  79. package/dist/input.styles.js +3 -3
  80. package/dist/input.test.basics.js +169 -0
  81. package/dist/input.test.events.js +97 -0
  82. package/dist/input.test.focus.js +54 -0
  83. package/dist/input.test.form.js +56 -0
  84. package/dist/input.test.validity.js +50 -0
  85. package/dist/label.js +1 -1
  86. package/dist/label.styles.js +3 -3
  87. package/dist/label.test.basics.js +129 -0
  88. package/dist/library/expect-argument-error.js +1 -1
  89. package/dist/library/ow.js +1 -1
  90. package/dist/library/ow.test.js +55 -0
  91. package/dist/menu.button.d.ts +1 -2
  92. package/dist/menu.button.js +1 -1
  93. package/dist/menu.button.styles.js +3 -3
  94. package/dist/menu.button.test.basics.js +42 -0
  95. package/dist/menu.d.ts +4 -0
  96. package/dist/menu.js +1 -1
  97. package/dist/menu.link.d.ts +1 -2
  98. package/dist/menu.link.js +1 -1
  99. package/dist/menu.link.styles.js +3 -3
  100. package/dist/menu.link.test.basics.js +46 -0
  101. package/dist/menu.styles.js +13 -6
  102. package/dist/menu.test.basics.js +161 -0
  103. package/dist/menu.test.focus.d.ts +0 -1
  104. package/dist/menu.test.focus.js +66 -0
  105. package/dist/menu.test.interactions.d.ts +0 -1
  106. package/dist/menu.test.interactions.js +522 -0
  107. package/dist/modal.icon-button.js +1 -1
  108. package/dist/modal.icon-button.styles.js +2 -2
  109. package/dist/modal.icon-button.test.basics.js +45 -0
  110. package/dist/modal.js +1 -15
  111. package/dist/modal.styles.js +4 -4
  112. package/dist/modal.tertiary-icon.js +1 -1
  113. package/dist/modal.tertiary-icon.test.basics.js +59 -0
  114. package/dist/modal.test.accessibility.js +48 -0
  115. package/dist/modal.test.basics.js +203 -0
  116. package/dist/modal.test.close.js +38 -0
  117. package/dist/modal.test.events.js +110 -0
  118. package/dist/modal.test.lock-scroll.js +76 -0
  119. package/dist/modal.test.methods.js +23 -0
  120. package/dist/modal.test.scrollbars.js +19 -0
  121. package/dist/radio-group.js +1 -1
  122. package/dist/radio-group.styles.js +2 -2
  123. package/dist/radio-group.test.basics.js +323 -0
  124. package/dist/radio-group.test.events.js +277 -0
  125. package/dist/radio-group.test.focus.js +75 -0
  126. package/dist/radio-group.test.form.js +104 -0
  127. package/dist/radio-group.test.validity.js +228 -0
  128. package/dist/radio.js +1 -1
  129. package/dist/radio.styles.js +4 -4
  130. package/dist/split-button.d.ts +24 -0
  131. package/dist/split-button.js +1 -0
  132. package/dist/split-button.stories.d.ts +17 -0
  133. package/dist/split-button.styles.d.ts +2 -0
  134. package/dist/split-button.styles.js +103 -0
  135. package/dist/split-button.test.basics.d.ts +1 -0
  136. package/dist/split-button.test.basics.js +84 -0
  137. package/dist/split-container.d.ts +30 -0
  138. package/dist/split-container.js +1 -0
  139. package/dist/split-container.styles.d.ts +2 -0
  140. package/dist/split-container.styles.js +132 -0
  141. package/dist/split-container.test.basics.d.ts +3 -0
  142. package/dist/split-container.test.basics.js +445 -0
  143. package/dist/split-container.test.interactions.d.ts +1 -0
  144. package/dist/split-container.test.interactions.js +20 -0
  145. package/dist/split-link.d.ts +25 -0
  146. package/dist/split-link.js +1 -0
  147. package/dist/split-link.test.basics.d.ts +1 -0
  148. package/dist/split-link.test.basics.js +92 -0
  149. package/dist/split-link.test.interactions.d.ts +1 -0
  150. package/dist/split-link.test.interactions.js +19 -0
  151. package/dist/status-indicator.js +1 -1
  152. package/dist/status-indicator.styles.js +2 -2
  153. package/dist/status-indicator.test.basics.js +102 -0
  154. package/dist/styles/focus-outline.js +1 -4
  155. package/dist/styles/visually-hidden.js +1 -11
  156. package/dist/tab.group.js +1 -1
  157. package/dist/tab.group.styles.js +2 -2
  158. package/dist/tab.group.test.basics.js +185 -0
  159. package/dist/tab.js +1 -1
  160. package/dist/tab.panel.js +1 -1
  161. package/dist/tab.panel.styles.js +3 -3
  162. package/dist/tab.styles.js +2 -2
  163. package/dist/tab.test.basics.js +71 -0
  164. package/dist/tag.js +1 -1
  165. package/dist/tag.styles.js +3 -3
  166. package/dist/tag.test.basics.js +118 -0
  167. package/dist/tag.test.events.js +16 -0
  168. package/dist/tag.test.focus.js +11 -0
  169. package/dist/textarea.js +2 -2
  170. package/dist/textarea.styles.js +3 -3
  171. package/dist/textarea.test.basics.js +140 -0
  172. package/dist/textarea.test.events.js +204 -0
  173. package/dist/textarea.test.form.js +70 -0
  174. package/dist/textarea.test.validity.js +83 -0
  175. package/dist/toasts.js +1 -1
  176. package/dist/toasts.styles.js +2 -2
  177. package/dist/toasts.test.basics.js +94 -0
  178. package/dist/toasts.toast.js +1 -1
  179. package/dist/toasts.toast.styles.js +5 -2
  180. package/dist/toasts.toast.test.basics.js +139 -0
  181. package/dist/toggle.js +1 -1
  182. package/dist/toggle.styles.js +3 -3
  183. package/dist/toggle.test.basics.js +64 -0
  184. package/dist/toggle.test.events.js +29 -0
  185. package/dist/toggle.test.focus.js +9 -0
  186. package/dist/toggle.test.states.js +35 -0
  187. package/dist/tooltip.js +1 -1
  188. package/dist/tooltip.styles.js +3 -3
  189. package/dist/tooltip.test.basics.js +64 -0
  190. package/dist/tooltip.test.interactions.js +78 -0
  191. package/dist/tree.item.icon-button.js +1 -1
  192. package/dist/tree.item.icon-button.styles.js +2 -2
  193. package/dist/tree.item.icon-button.test.basics.js +13 -0
  194. package/dist/tree.item.js +1 -1
  195. package/dist/tree.item.menu.js +1 -1
  196. package/dist/tree.item.menu.styles.js +2 -2
  197. package/dist/tree.item.menu.test.basics.js +34 -0
  198. package/dist/tree.item.styles.js +2 -2
  199. package/dist/tree.item.test.basics.js +102 -0
  200. package/dist/tree.js +1 -1
  201. package/dist/tree.styles.js +2 -2
  202. package/dist/tree.test.aria.js +86 -0
  203. package/dist/tree.test.basics.js +123 -0
  204. package/dist/tree.test.events.js +19 -0
  205. package/dist/tree.test.focus.js +261 -0
  206. package/package.json +20 -18
  207. /package/dist/{dropdown.option.test.focus.multiple.d.ts → dropdown.option.test.focus.d.ts} +0 -0
  208. /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
- "use strict";import{ArgumentError as e}from"ow";import{expect as i}from"@open-wc/testing";import c from"sinon";export default async function(r){const n=window.onerror;window.onerror=null;const o=c.spy();try{await r.call(context)}catch(t){t instanceof e&&o()}i(o.called).to.be.true,window.onerror=n}
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}
@@ -1 +1 @@
1
- "use strict";import e from"ow";const i=window.location.host.startsWith("localhost")||window.location.host.startsWith("127.0.0.1");export function owSlot(o){i&&(e(o,e.object.is(t=>t instanceof HTMLSlotElement)),e(o.assignedNodes().length,e.number.is(t=>t>0).message(o.name?`Expected a "${o.name}" slot.`:"Expected a default slot.")))}export function owSlotType(o,t=[]){if(i&&(e(o,e.object.is(s=>s instanceof HTMLSlotElement)),o.assignedNodes().length!==0&&t.length>0)){const s=o.assignedNodes({flatten:!0}).filter(n=>n instanceof Text&&t.includes(Text)?!0:!(n instanceof Text));e(s.length,e.number.is(n=>n>0).message(`Expected a slotted node that extends ${t.map(({name:n})=>n).join(" or ")}.`));for(const n of s){const c=`Expected slotted node to extend ${t.map(({name:a})=>a).join(" or ")}. Extends ${n.constructor.name} instead.`,l=t.some(a=>n instanceof a);e(l,e.boolean.true.message(c))}}}const r=new Proxy(()=>{},{get:()=>r,apply:()=>r}),m=i?e:r;export default m;
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
+ });
@@ -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
- privateIsFocused: boolean;
19
- focus(): void;
18
+ connectedCallback(): void;
20
19
  render(): import("lit").TemplateResult<1>;
21
20
  }
@@ -1 +1 @@
1
- "use strict";var y=Object.defineProperty;var E=Object.getOwnPropertyDescriptor;var c=(e,t,o,a)=>{for(var i=a>1?void 0:a?E(t,o):t,p=e.length-1,f;p>=0;p--)(f=e[p])&&(i=(a?f(t,o,i):f(i))||i);return a&&i&&y(t,o,i),i};var u=(e,t,o)=>{if(!t.has(e))throw TypeError("Cannot "+o)};var v=(e,t,o)=>(u(e,t,"read from private field"),o?o.call(e):t.get(e)),m=(e,t,o)=>{if(t.has(e))throw TypeError("Cannot add the same private member more than once");t instanceof WeakSet?t.add(e):t.set(e,o)};var d=(e,t,o)=>(u(e,t,"access private method"),o);var r,l,$,n,g;import{LitElement as h,html as F}from"lit";import{classMap as R}from"lit/directives/class-map.js";import{createRef as I,ref as w}from"lit/directives/ref.js";import{customElement as x,property as b}from"lit/decorators.js";import A from"./menu.button.styles.js";let s=class extends h{constructor(){super(...arguments);m(this,l);m(this,n);this.privateActive=!1;this.privateIsFocused=!1;m(this,r,I())}focus(){v(this,r).value?.focus()}render(){return F`<button class="${R({component:!0,"component-active":this.privateActive})}" data-test="component" role="menuitem" tabindex="${this.privateActive?"0":"-1"}" type="button" @focusin="${d(this,l,$)}" @focusout="${d(this,n,g)}" ${w(v(this,r))}><slot name="icon"></slot>${this.label}</button>`}};r=new WeakMap,l=new WeakSet,$=function(){this.privateIsFocused=!0},n=new WeakSet,g=function(){this.privateIsFocused=!1},s.shadowRootOptions={...h.shadowRootOptions,mode:"closed"},s.styles=A,c([b({reflect:!0})],s.prototype,"label",2),c([b({type:Boolean})],s.prototype,"privateActive",2),s=c([x("glide-core-menu-button")],s);export{s as default};
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
- "use strict";import{css as e}from"lit";export default[e`
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
- &.component-active {
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
- "use strict";var et=Object.defineProperty;var it=Object.getOwnPropertyDescriptor;var g=(n,a,t,i)=>{for(var r=i>1?void 0:i?it(a,t):a,o=n.length-1,F;o>=0;o--)(F=n[o])&&(r=(i?F(a,t,r):F(r))||r);return i&&r&&et(a,t,r),r};var z=(n,a,t)=>{if(!a.has(n))throw TypeError("Cannot "+t)};var e=(n,a,t)=>(z(n,a,"read from private field"),t?t.call(n):a.get(n)),s=(n,a,t)=>{if(a.has(n))throw TypeError("Cannot add the same private member more than once");a instanceof WeakSet?a.add(n):a.set(n,t)},B=(n,a,t,i)=>(z(n,a,"write to private field"),i?i.call(n,t):a.set(n,t),t);var l=(n,a,t)=>(z(n,a,"access private method"),t);var y,D,m,E,h,v,k,w,N,L,J,U,Q,C,W,K,X,S,Y,R,Z,H,_,M,G,P,tt,p,u,A,j,c,f;import{LitElement as V,html as ot}from"lit";import{autoUpdate as st,computePosition as at,flip as nt,offset as rt}from"@floating-ui/dom";import{classMap as lt}from"lit/directives/class-map.js";import{createRef as T,ref as $}from"lit/directives/ref.js";import{customElement as ct,property as I}from"lit/decorators.js";import{owSlot as b,owSlotType as q}from"./library/ow.js";import x from"./menu.button.js";import O from"./menu.link.js";import pt from"./menu.styles.js";let d=class extends V{constructor(){super(...arguments);s(this,w);s(this,L);s(this,U);s(this,C);s(this,K);s(this,S);s(this,R);s(this,H);s(this,M);s(this,P);s(this,p);s(this,A);s(this,c);this.placement="bottom-start";this.size="large";s(this,y,void 0);s(this,D,T());s(this,m,T());s(this,E,!1);s(this,h,T());s(this,v,T());s(this,k,t=>{t.target&&this.contains(t.target)||(this.open=!1)})}get open(){return e(this,E)}set open(t){var i;B(this,E,t),t?l(this,A,j).call(this):(i=e(this,y))==null||i.call(this),e(this,c,f)&&(e(this,c,f).ariaExpanded=t?"true":"false")}connectedCallback(){super.connectedCallback(),document.addEventListener("click",e(this,k),{capture:!0})}disconnectedCallback(){super.disconnectedCallback(),document.removeEventListener("click",e(this,k),{capture:!0})}firstUpdated(){b(e(this,m).value),b(e(this,v).value),q(e(this,m).value,[x,O,Text]),l(this,A,j).call(this);const t=e(this,p,u).at(0);t&&(t.privateActive=!0),e(this,c,f)&&e(this,h).value&&(e(this,c,f).ariaHasPopup="true",e(this,c,f).ariaExpanded=this.open?"true":"false")}focus(){const t=e(this,v).value?.assignedElements().at(0);t&&"focus"in t&&t?.focus()}render(){return ot`<div @focusout="${l(this,S,Y)}" @keydown="${l(this,R,Z)}" ${$(e(this,D))} class="component"><div class="target-container" @click="${l(this,H,_)}" @keydown="${l(this,M,G)}" id="target-container"><slot name="target" @slotchange="${l(this,P,tt)}" ${$(e(this,v))}></slot></div><div aria-labelledby="target-container" class="${lt({options:!0,large:this.size==="large",small:this.size==="small",visible:this.open})}" role="menu" ${$(e(this,h))}><slot @click="${l(this,U,Q)}" @keydown="${l(this,C,W)}" @mouseover="${l(this,K,X)}" @slotchange="${l(this,L,J)}" ${$(e(this,m))}></slot></div></div>`}};y=new WeakMap,D=new WeakMap,m=new WeakMap,E=new WeakMap,h=new WeakMap,v=new WeakMap,k=new WeakMap,w=new WeakSet,N=async function(){const t=e(this,p,u).find(i=>i.privateActive);t&&(await this.updateComplete,t.focus())},L=new WeakSet,J=function(){b(e(this,m).value),q(e(this,m).value,[x,O,Text])},U=new WeakSet,Q=function(){this.open=!1},C=new WeakSet,W=function(t){if([" ","Enter"].includes(t.key)){this.open=!1,this.focus();return}const i=e(this,p,u).findIndex(o=>o.privateActive),r=e(this,p,u).at(i);if(r){if(t.key==="ArrowUp"&&!t.metaKey){t.preventDefault();const o=e(this,p,u).at(i-1);o&&i!==0&&(r.privateActive=!1,o.privateActive=!0,o.focus());return}if(t.key==="ArrowDown"&&!t.metaKey){t.preventDefault();const o=e(this,p,u).at(i+1);o&&(r.privateActive=!1,o.privateActive=!0,o.focus());return}if(t.key==="ArrowUp"&&t.metaKey||t.key==="Home"||t.key==="PageUp"){t.preventDefault();const o=e(this,p,u).at(0);o&&(r.privateActive=!1,o.privateActive=!0,o.focus());return}if(t.key==="ArrowDown"&&t.metaKey||t.key==="End"||t.key==="PageDown"){t.preventDefault();const o=e(this,p,u).at(-1);o&&(r.privateActive=!1,o.privateActive=!0,o.focus());return}}},K=new WeakSet,X=function(t){if(t.target instanceof O||t.target instanceof x){for(const i of e(this,p,u))i.privateActive=i===t.target;t.target.focus()}},S=new WeakSet,Y=function(){setTimeout(()=>{e(this,p,u).some(({privateIsFocused:i})=>i)||(this.open=!1)})},R=new WeakSet,Z=function(t){t.key==="Escape"&&(this.open=!1,this.focus())},H=new WeakSet,_=function(){e(this,c,f)instanceof HTMLElement&&(e(this,c,f).ariaExpanded=this.open?"true":"false"),this.open=!this.open,this.open?l(this,w,N).call(this):this.focus()},M=new WeakSet,G=function(t){[" ","ArrowUp","ArrowDown"].includes(t.key)&&(t.preventDefault(),this.open=!0,l(this,w,N).call(this))},P=new WeakSet,tt=function(){b(e(this,v).value)},p=new WeakSet,u=function(){return(e(this,m).value?.assignedElements({flatten:!0})??[]).filter(t=>t instanceof O||t instanceof x)},A=new WeakSet,j=function(){e(this,c,f)&&e(this,h).value&&B(this,y,st(e(this,c,f),e(this,h).value,()=>{(async()=>{if(e(this,c,f)&&e(this,h).value){const{x:t,y:i,placement:r}=await at(e(this,c,f),e(this,h).value,{placement:this.placement,middleware:[rt({mainAxis:Number.parseFloat(window.getComputedStyle(document.body).getPropertyValue("--glide-core-spacing-xxs"))*16}),nt()]});e(this,h).value.dataset.placement=r,Object.assign(e(this,h).value.style,{left:`${t}px`,top:`${i}px`})}})()}))},c=new WeakSet,f=function(){return e(this,v).value?.assignedElements().at(0)},d.shadowRootOptions={...V.shadowRootOptions,mode:"closed"},d.styles=pt,g([I({reflect:!0,type:Boolean})],d.prototype,"open",1),g([I({reflect:!0})],d.prototype,"placement",2),g([I({reflect:!0})],d.prototype,"size",2),d=g([ct("glide-core-menu")],d);export{d as default};
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;
@@ -16,7 +16,6 @@ export default class GlideCoreMenuLink extends LitElement {
16
16
  label?: string;
17
17
  url?: string;
18
18
  privateActive: boolean;
19
- privateIsFocused: boolean;
20
- focus(): void;
19
+ connectedCallback(): void;
21
20
  render(): import("lit").TemplateResult<1>;
22
21
  }
package/dist/menu.link.js CHANGED
@@ -1 +1 @@
1
- "use strict";var F=Object.defineProperty;var R=Object.getOwnPropertyDescriptor;var a=(e,t,o,c)=>{for(var r=c>1?void 0:c?R(t,o):t,f=e.length-1,n;f>=0;f--)(n=e[f])&&(r=(c?n(t,o,r):n(r))||r);return c&&r&&F(t,o,r),r};var d=(e,t,o)=>{if(!t.has(e))throw TypeError("Cannot "+o)};var u=(e,t,o)=>(d(e,t,"read from private field"),o?o.call(e):t.get(e)),m=(e,t,o)=>{if(t.has(e))throw TypeError("Cannot add the same private member more than once");t instanceof WeakSet?t.add(e):t.set(e,o)};var h=(e,t,o)=>(d(e,t,"access private method"),o);var i,l,g,p,E;import{LitElement as $,html as b}from"lit";import{classMap as y}from"lit/directives/class-map.js";import{createRef as I,ref as w}from"lit/directives/ref.js";import{customElement as x,property as v}from"lit/decorators.js";import{ifDefined as A}from"lit/directives/if-defined.js";import T from"./menu.link.styles.js";let s=class extends ${constructor(){super(...arguments);m(this,l);m(this,p);this.privateActive=!1;this.privateIsFocused=!1;m(this,i,I())}focus(){u(this,i).value?.focus()}render(){return b`<a class="${y({component:!0,"component-active":this.privateActive})}" data-test="component" href="${A(this.url)}" role="menuitem" tabindex="${this.privateActive?"0":"-1"}" @focusin="${h(this,l,g)}" @focusout="${h(this,p,E)}" ${w(u(this,i))}><slot name="icon"></slot>${this.label}</a>`}};i=new WeakMap,l=new WeakSet,g=function(){this.privateIsFocused=!0},p=new WeakSet,E=function(){this.privateIsFocused=!1},s.shadowRootOptions={...$.shadowRootOptions,mode:"closed"},s.styles=T,a([v({reflect:!0})],s.prototype,"label",2),a([v({reflect:!0})],s.prototype,"url",2),a([v({type:Boolean})],s.prototype,"privateActive",2),s=a([x("glide-core-menu-link")],s);export{s as default};
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;
@@ -1,4 +1,4 @@
1
- "use strict";import{css as e}from"lit";export default[e`
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
- &.component-active {
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
+ });
@@ -1,4 +1,4 @@
1
- "use strict";import{css as i}from"lit";export default[i`
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
- .target-container {
12
+ .container {
13
13
  display: flex;
14
14
  position: relative;
15
15
  }
16
16
 
17
- .options {
18
- background-color: var(--glide-core-surface-base-lighter);
19
- border: 1px solid var(--glide-core-border-base-lighter);
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
+ `];