@crowdstrike/glide-core 0.10.0 → 0.12.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.
Files changed (62) hide show
  1. package/dist/checkbox-group.d.ts +3 -0
  2. package/dist/checkbox-group.js +43 -1
  3. package/dist/checkbox-group.styles.js +12 -0
  4. package/dist/checkbox-group.test.validity.js +69 -0
  5. package/dist/checkbox.d.ts +3 -1
  6. package/dist/checkbox.js +135 -1
  7. package/dist/checkbox.styles.js +12 -0
  8. package/dist/checkbox.test.events.js +9 -0
  9. package/dist/checkbox.test.validity.js +77 -1
  10. package/dist/dropdown.d.ts +3 -0
  11. package/dist/dropdown.js +195 -1
  12. package/dist/dropdown.option.d.ts +1 -0
  13. package/dist/dropdown.option.js +1 -1
  14. package/dist/dropdown.option.test.events.js +9 -1
  15. package/dist/dropdown.option.test.interactions.single.js +2 -2
  16. package/dist/dropdown.styles.js +18 -6
  17. package/dist/dropdown.test.basics.d.ts +1 -1
  18. package/dist/dropdown.test.basics.js +19 -1
  19. package/dist/dropdown.test.basics.multiple.js +2 -1
  20. package/dist/dropdown.test.events.filterable.js +13 -2
  21. package/dist/dropdown.test.events.single.js +19 -0
  22. package/dist/dropdown.test.form.multiple.js +3 -2
  23. package/dist/dropdown.test.interactions.filterable.js +20 -0
  24. package/dist/dropdown.test.interactions.js +20 -14
  25. package/dist/dropdown.test.interactions.multiple.js +24 -10
  26. package/dist/dropdown.test.interactions.single.js +32 -0
  27. package/dist/dropdown.test.validity.js +172 -1
  28. package/dist/input.d.ts +4 -0
  29. package/dist/input.js +155 -1
  30. package/dist/input.styles.js +8 -0
  31. package/dist/input.test.validity.js +140 -62
  32. package/dist/menu.d.ts +2 -0
  33. package/dist/menu.js +1 -1
  34. package/dist/menu.test.basics.d.ts +1 -1
  35. package/dist/menu.test.basics.js +12 -27
  36. package/dist/menu.test.interactions.js +90 -0
  37. package/dist/radio-group.d.ts +3 -0
  38. package/dist/radio-group.js +45 -1
  39. package/dist/radio-group.styles.js +12 -0
  40. package/dist/radio-group.test.validity.js +82 -0
  41. package/dist/styles/variables.css +1 -1
  42. package/dist/tab.group.d.ts +1 -0
  43. package/dist/tab.group.js +1 -1
  44. package/dist/tab.group.styles.js +6 -0
  45. package/dist/tag.d.ts +1 -2
  46. package/dist/tag.js +1 -1
  47. package/dist/tag.styles.js +12 -3
  48. package/dist/tag.test.basics.js +1 -0
  49. package/dist/tag.test.interactions.js +8 -6
  50. package/dist/textarea.d.ts +3 -0
  51. package/dist/textarea.js +58 -2
  52. package/dist/textarea.styles.js +8 -0
  53. package/dist/textarea.test.events.js +0 -114
  54. package/dist/textarea.test.validity.js +64 -72
  55. package/dist/tooltip.d.ts +2 -1
  56. package/dist/tooltip.js +1 -1
  57. package/dist/tooltip.styles.js +2 -1
  58. package/dist/tree.item.menu.d.ts +1 -0
  59. package/dist/tree.item.menu.js +1 -1
  60. package/dist/tree.item.menu.test.basics.js +22 -1
  61. package/dist/tree.item.styles.js +3 -6
  62. package/package.json +1 -1
@@ -42,46 +42,6 @@ it('is invalid if no value and required', async () => {
42
42
  ?.querySelector('textarea')
43
43
  ?.getAttribute('aria-invalid')).to.equal('true');
44
44
  });
45
- it('is valid when empty and does not exceed `maxlength`', async () => {
46
- const component = await fixture(html `<glide-core-textarea maxlength="3"></glide-core-textarea>`);
47
- expect(component.validity?.valid).to.be.true;
48
- expect(component.validity?.valueMissing).to.be.false;
49
- expect(component.validity?.tooLong).to.be.false;
50
- expect(component.checkValidity()).to.be.true;
51
- expect(component.reportValidity()).to.be.true;
52
- await elementUpdated(component);
53
- expect(component.shadowRoot
54
- ?.querySelector('textarea')
55
- ?.getAttribute('aria-invalid')).to.equal('false');
56
- });
57
- it('is valid when filled in and does not exceed `maxlength`', async () => {
58
- const component = await fixture(html `<glide-core-textarea maxlength="3"></glide-core-textarea>`);
59
- component.focus();
60
- await sendKeys({ type: 'abc' });
61
- expect(component.validity?.valid).to.be.true;
62
- expect(component.validity?.valueMissing).to.be.false;
63
- expect(component.validity?.tooLong).to.be.false;
64
- expect(component.checkValidity()).to.be.true;
65
- expect(component.reportValidity()).to.be.true;
66
- await elementUpdated(component);
67
- expect(component.shadowRoot
68
- ?.querySelector('textarea')
69
- ?.getAttribute('aria-invalid')).to.equal('false');
70
- });
71
- it('is invalid when filled in and exceeds `maxlength`', async () => {
72
- const component = await fixture(html `<glide-core-textarea maxlength="3"></glide-core-textarea>`);
73
- component.focus();
74
- await sendKeys({ type: 'value' });
75
- expect(component.validity?.valid).to.be.false;
76
- expect(component.validity?.valueMissing).to.be.false;
77
- expect(component.validity?.tooLong).to.be.true;
78
- expect(component.checkValidity()).to.be.false;
79
- expect(component.reportValidity()).to.be.false;
80
- await elementUpdated(component);
81
- expect(component.shadowRoot
82
- ?.querySelector('textarea')
83
- ?.getAttribute('aria-invalid')).to.equal('true');
84
- });
85
45
  it('is valid if no value but required and disabled', async () => {
86
46
  const component = await fixture(html `<glide-core-textarea required disabled></glide-core-textarea>`);
87
47
  expect(component.validity?.valid).to.be.true;
@@ -166,38 +126,6 @@ it('is valid when `value` is empty and `required` is set to `false` programmatic
166
126
  ?.querySelector('textarea')
167
127
  ?.getAttribute('aria-invalid')).to.equal('false');
168
128
  });
169
- it('is valid when filled in, disabled, and value exceeds `maxlength`', async () => {
170
- const component = await fixture(html `<glide-core-textarea
171
- value="value"
172
- disabled
173
- maxlength="3"
174
- ></glide-core-textarea>`);
175
- expect(component.validity?.valid).to.be.true;
176
- expect(component.validity?.valueMissing).to.be.false;
177
- expect(component.validity?.tooLong).to.be.false;
178
- expect(component.checkValidity()).to.be.true;
179
- expect(component.reportValidity()).to.be.true;
180
- await elementUpdated(component);
181
- expect(component.shadowRoot
182
- ?.querySelector('textarea')
183
- ?.getAttribute('aria-invalid')).to.equal('false');
184
- });
185
- it('is valid when filled in, readonly, and value exceeds `maxlength`', async () => {
186
- const component = await fixture(html `<glide-core-textarea
187
- value="value"
188
- readonly
189
- maxlength="3"
190
- ></glide-core-textarea>`);
191
- expect(component.validity?.valid).to.be.true;
192
- expect(component.validity?.valueMissing).to.be.false;
193
- expect(component.validity?.tooLong).to.be.false;
194
- expect(component.checkValidity()).to.be.true;
195
- expect(component.reportValidity()).to.be.true;
196
- await elementUpdated(component);
197
- expect(component.shadowRoot
198
- ?.querySelector('textarea')
199
- ?.getAttribute('aria-invalid')).to.equal('false');
200
- });
201
129
  it('blurs the textarea and reports validity if `blur` is called', async () => {
202
130
  const component = await fixture(html `<glide-core-textarea required></glide-core-textarea>`);
203
131
  component.focus();
@@ -210,3 +138,67 @@ it('blurs the textarea and reports validity if `blur` is called', async () => {
210
138
  expect(component.shadowRoot?.querySelector('glide-core-private-label')?.error)
211
139
  .to.be.true;
212
140
  });
141
+ it('sets the validity message with `setCustomValidity()`', async () => {
142
+ const component = await fixture(html `<glide-core-textarea label="Label"></glide-core-textarea>`);
143
+ component.setCustomValidity('validity message');
144
+ expect(component.validity?.valid).to.be.false;
145
+ expect(component.validity?.customError).to.be.true;
146
+ expect(component.checkValidity()).to.be.false;
147
+ await elementUpdated(component);
148
+ // Like native, the validity message shouldn't display until `reportValidity()` is called.
149
+ expect(component.shadowRoot?.querySelector('[data-test="validity-message"]')
150
+ ?.textContent).to.be.undefined;
151
+ expect(component.reportValidity()).to.be.false;
152
+ await elementUpdated(component);
153
+ expect(component.shadowRoot
154
+ ?.querySelector('textarea')
155
+ ?.getAttribute('aria-invalid')).to.equal('true');
156
+ expect(component.shadowRoot?.querySelector('[data-test="validity-message"]')
157
+ ?.textContent).to.equal('validity message');
158
+ });
159
+ it('removes a validity message with an empty argument to `setCustomValidity()`', async () => {
160
+ const component = await fixture(html `<glide-core-textarea label="Label"></glide-core-textarea>`);
161
+ component.setCustomValidity('validity message');
162
+ component.reportValidity();
163
+ await elementUpdated(component);
164
+ component.setCustomValidity('');
165
+ await elementUpdated(component);
166
+ expect(component.shadowRoot?.querySelector('[data-test="validity-message"]')
167
+ ?.textContent).to.be.undefined;
168
+ });
169
+ it('is invalid when `setValidity()` is called', async () => {
170
+ const component = await fixture(html `<glide-core-textarea label="Label"></glide-core-textarea>`);
171
+ component.setValidity({ customError: true }, 'validity message');
172
+ expect(component.validity.valid).to.be.false;
173
+ await elementUpdated(component);
174
+ // Like native, the validity message shouldn't display until `reportValidity()` is called.
175
+ expect(component.shadowRoot?.querySelector('[data-test="validity-message"]')
176
+ ?.textContent).to.be.undefined;
177
+ expect(component.validity?.customError).to.be.true;
178
+ component.reportValidity();
179
+ await elementUpdated(component);
180
+ expect(component.shadowRoot
181
+ ?.querySelector('textarea')
182
+ ?.getAttribute('aria-invalid')).to.equal('true');
183
+ expect(component.shadowRoot?.querySelector('[data-test="validity-message"]')
184
+ ?.textContent).to.equal('validity message');
185
+ });
186
+ it('is valid when `setValidity()` is called', async () => {
187
+ const component = await fixture(html `<glide-core-textarea label="Label"></glide-core-textarea>`);
188
+ component.setValidity({ customError: true }, 'validity message');
189
+ component.setValidity({});
190
+ await elementUpdated(component);
191
+ expect(component.validity.valid).to.be.true;
192
+ expect(component.validity.customError).to.be.false;
193
+ expect(component.reportValidity()).to.be.true;
194
+ await elementUpdated(component);
195
+ expect(component.shadowRoot?.querySelector('[data-test="validity-message"]')
196
+ ?.textContent).to.be.undefined;
197
+ });
198
+ it('retains existing validity state when `setCustomValidity()` is called', async () => {
199
+ const component = await fixture(html `<glide-core-textarea label="Label" required></glide-core-textarea>`);
200
+ component.setCustomValidity('validity message');
201
+ expect(component.validity?.valid).to.be.false;
202
+ expect(component.validity?.customError).to.be.true;
203
+ expect(component.validity?.valueMissing).to.be.true;
204
+ });
package/dist/tooltip.d.ts CHANGED
@@ -14,7 +14,8 @@ export default class GlideCoreTooltip extends LitElement {
14
14
  static styles: import("lit").CSSResult[];
15
15
  get disabled(): boolean;
16
16
  set disabled(isDisabled: boolean);
17
- offset: number;
17
+ get offset(): number;
18
+ set offset(offset: number);
18
19
  get open(): boolean;
19
20
  set open(isOpen: boolean);
20
21
  placement?: 'bottom' | 'left' | 'right' | 'top';
package/dist/tooltip.js CHANGED
@@ -1 +1 @@
1
- var __decorate=this&&this.__decorate||function(e,t,o,i){var l,s=arguments.length,a=s<3?t:null===i?i=Object.getOwnPropertyDescriptor(t,o):i;if("object"==typeof Reflect&&"function"==typeof Reflect.decorate)a=Reflect.decorate(e,t,o,i);else for(var r=e.length-1;r>=0;r--)(l=e[r])&&(a=(s<3?l(a):s>3?l(t,o,a):l(t,o))||a);return s>3&&a&&Object.defineProperty(t,o,a),a};import{LitElement,html}from"lit";import{arrow,autoUpdate,computePosition,flip,limitShift,offset,shift}from"@floating-ui/dom";import{choose}from"lit/directives/choose.js";import{classMap}from"lit/directives/class-map.js";import{createRef,ref}from"lit/directives/ref.js";import{customElement,property,state}from"lit/decorators.js";import{ifDefined}from"lit/directives/if-defined.js";import{map}from"lit/directives/map.js";import ow,{owSlot}from"./library/ow.js";import styles from"./tooltip.styles.js";let GlideCoreTooltip=class GlideCoreTooltip extends LitElement{constructor(){super(...arguments),this.offset=4,this.shortcut=[],this.effectivePlacement=this.placement??"bottom",this.#e=createRef(),this.#t=createRef(),this.#o=!1,this.#i=!1,this.#l=createRef(),this.#s=createRef(),this.#a=createRef()}static{this.shadowRootOptions={...LitElement.shadowRootOptions,delegatesFocus:!0,mode:"closed"}}static{this.styles=styles}get disabled(){return this.#o}set disabled(e){this.#o=e,this.open&&!e?this.#r():this.#n()}get open(){return this.#i}set open(e){this.#i=e,e&&!this.disabled?this.#r():this.#n()}disconnectedCallback(){super.disconnectedCallback(),clearTimeout(this.#f),clearTimeout(this.#h)}firstUpdated(){owSlot(this.#t.value),owSlot(this.#s.value),ow(this.#a.value,ow.object.instanceOf(HTMLElement)),this.#a.value.popover="manual",this.open&&!this.disabled&&this.#r()}render(){return html`<div class="component" data-test="component" @mouseover="${this.#p}" @mouseout="${this.#c}"><div aria-labelledby="${ifDefined(this.disabled?void 0:"tooltip")}" class="target" data-test="target" slot="target" @focusin="${this.#d}" @focusout="${this.#m}" @keydown="${this.#u}" ${ref(this.#l)}><slot @slotchange="${this.#v}" ${ref(this.#s)} name="target"></slot></div><div class="${classMap({tooltip:!0,[this.effectivePlacement]:!0})}" id="tooltip" data-test="tooltip" data-open-delay="300" data-close-delay="200" role="${ifDefined(this.disabled?void 0:"tooltip")}" ${ref(this.#a)}><div class="${classMap({arrow:!0,[this.effectivePlacement]:!0})}" data-test="arrow" ${ref(this.#e)}>${choose(this.effectivePlacement,[["top",()=>html`<svg viewBox="0 0 10 6" fill="none"><path d="M4.23178 5.07814C4.63157 5.55789 5.36843 5.55789 5.76822 5.07813L10 -7.9486e-08L-2.62268e-07 3.57628e-07L4.23178 5.07814Z" fill="#212121"/></svg>`],["right",()=>html`<svg viewBox="0 0 6 10" fill="none"><path d="M0.921865 4.23178C0.442111 4.63157 0.442112 5.36843 0.921866 5.76822L6 10L6 -2.62268e-07L0.921865 4.23178Z" fill="#212121"/></svg>`],["bottom",()=>html`<svg viewBox="0 0 10 6" fill="none"><path d="M4.23178 0.921865C4.63157 0.442111 5.36843 0.442112 5.76822 0.921866L10 6L-2.62268e-07 6L4.23178 0.921865Z" fill="#212121"/></svg>`],["left",()=>html`<svg viewBox="0 0 6 10" fill="none"><path d="M5.07814 4.23178C5.55789 4.63157 5.55789 5.36843 5.07813 5.76822L-4.37114e-07 10L0 -2.62268e-07L5.07814 4.23178Z" fill="#212121"/></svg>`]])}</div><span aria-label="${ifDefined(this.disabled?void 0:"Tooltip: ")}"></span><div class="${classMap({content:!0,reversed:"left"===this.effectivePlacement})}"><slot class="default-slot" @slotchange="${this.#g}" ${ref(this.#t)}></slot><kbd class="${classMap({shortcut:!0,reversed:"left"===this.effectivePlacement,visible:this.shortcut.length>0})}" data-test="shortcut">${1===this.shortcut.length?this.shortcut.at(0):map(this.shortcut,((e,t)=>html`<kbd>${e}</kbd> ${t===this.shortcut.length-1?"":" + "}`))}</kbd></div></div></div>`}#e;#R;#f;#t;#o;#i;#h;#l;#s;#a;#E(){clearTimeout(this.#f)}#n(){this.#a.value?.hidePopover(),this.#R&&this.#R()}#g(){owSlot(this.#t.value)}#d(){this.open=!0}#m(){this.open=!1}#u(e){"Escape"===e.key&&(this.open=!1)}#c(){this.#w(),clearTimeout(this.#h)}#p(){ow(this.#a.value,ow.object.instanceOf(HTMLElement)),this.#E(),this.#h=setTimeout((()=>{this.open=!0}),Number(this.#a.value.dataset.openDelay))}#v(){owSlot(this.#s.value)}#w(){ow(this.#a.value,ow.object.instanceOf(HTMLElement)),this.#f=setTimeout((()=>{this.open=!1}),Number(this.#a.value.dataset.closeDelay))}#r(){this.disabled||(this.#R?.(),this.#l.value&&this.#a.value&&(this.#R=autoUpdate(this.#l.value,this.#a.value,(()=>{(async()=>{if(this.#l.value&&this.#a.value&&this.#e.value){const{x:e,y:t,placement:o,middlewareData:i}=await computePosition(this.#l.value,this.#a.value,{placement:this.placement,middleware:[offset(this.offset),flip({fallbackStrategy:"initialPlacement"}),shift({limiter:limitShift({offset:20})}),arrow({element:this.#e.value})]});Object.assign(this.#a.value.style,{left:`${e}px`,top:`${t}px`}),Object.assign(this.#e.value.style,{left:i.arrow?.x?`${i.arrow.x}px`:null,top:i.arrow?.y?`${i.arrow.y}px`:null}),this.effectivePlacement=o,this.#a.value.showPopover()}})()}))))}};__decorate([property({reflect:!0,type:Boolean})],GlideCoreTooltip.prototype,"disabled",null),__decorate([property({reflect:!0,type:Number})],GlideCoreTooltip.prototype,"offset",void 0),__decorate([property({reflect:!0,type:Boolean})],GlideCoreTooltip.prototype,"open",null),__decorate([property()],GlideCoreTooltip.prototype,"placement",void 0),__decorate([property({reflect:!0,type:Array})],GlideCoreTooltip.prototype,"shortcut",void 0),__decorate([state()],GlideCoreTooltip.prototype,"effectivePlacement",void 0),GlideCoreTooltip=__decorate([customElement("glide-core-tooltip")],GlideCoreTooltip);export default GlideCoreTooltip;
1
+ var __decorate=this&&this.__decorate||function(e,t,o,l){var i,s=arguments.length,a=s<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 r=e.length-1;r>=0;r--)(i=e[r])&&(a=(s<3?i(a):s>3?i(t,o,a):i(t,o))||a);return s>3&&a&&Object.defineProperty(t,o,a),a};import{LitElement,html}from"lit";import{arrow,autoUpdate,computePosition,flip,limitShift,offset,shift}from"@floating-ui/dom";import{choose}from"lit/directives/choose.js";import{classMap}from"lit/directives/class-map.js";import{createRef,ref}from"lit/directives/ref.js";import{customElement,property,state}from"lit/decorators.js";import{ifDefined}from"lit/directives/if-defined.js";import{map}from"lit/directives/map.js";import ow,{owSlot}from"./library/ow.js";import styles from"./tooltip.styles.js";let GlideCoreTooltip=class GlideCoreTooltip extends LitElement{constructor(){super(...arguments),this.shortcut=[],this.effectivePlacement=this.placement??"bottom",this.#e=createRef(),this.#t=createRef(),this.#o=!1,this.#l=!1,this.#i=createRef(),this.#s=createRef(),this.#a=createRef()}static{this.shadowRootOptions={...LitElement.shadowRootOptions,delegatesFocus:!0,mode:"closed"}}static{this.styles=styles}get disabled(){return this.#o}set disabled(e){this.#o=e,this.open&&!e?this.#r():this.#n()}get offset(){return this.#f??Number.parseFloat(window.getComputedStyle(document.body).getPropertyValue("--glide-core-spacing-xxs"))*Number.parseFloat(window.getComputedStyle(document.documentElement).fontSize)}set offset(e){this.#f=e}get open(){return this.#l}set open(e){this.#l=e,e&&!this.disabled?this.#r():this.#n()}disconnectedCallback(){super.disconnectedCallback(),clearTimeout(this.#p),clearTimeout(this.#c)}firstUpdated(){owSlot(this.#t.value),owSlot(this.#s.value),ow(this.#a.value,ow.object.instanceOf(HTMLElement)),this.#a.value.popover="manual",this.open&&!this.disabled&&this.#r()}render(){return html`<div class="component" data-test="component" @mouseover="${this.#h}" @mouseout="${this.#d}"><div aria-labelledby="${ifDefined(this.disabled?void 0:"tooltip")}" class="target" data-test="target" slot="target" @focusin="${this.#m}" @focusout="${this.#u}" @keydown="${this.#v}" ${ref(this.#i)}><slot @slotchange="${this.#g}" ${ref(this.#s)} name="target"></slot></div><div class="${classMap({tooltip:!0,[this.effectivePlacement]:!0})}" id="tooltip" data-test="tooltip" data-open-delay="300" data-close-delay="200" role="${ifDefined(this.disabled?void 0:"tooltip")}" ${ref(this.#a)}><div class="${classMap({arrow:!0,[this.effectivePlacement]:!0})}" data-test="arrow" ${ref(this.#e)}>${choose(this.effectivePlacement,[["top",()=>html`<svg viewBox="0 0 10 6" fill="none"><path d="M4.23178 5.07814C4.63157 5.55789 5.36843 5.55789 5.76822 5.07813L10 -7.9486e-08L-2.62268e-07 3.57628e-07L4.23178 5.07814Z" fill="currentColor"/></svg>`],["right",()=>html`<svg viewBox="0 0 6 10" fill="none"><path d="M0.921865 4.23178C0.442111 4.63157 0.442112 5.36843 0.921866 5.76822L6 10L6 -2.62268e-07L0.921865 4.23178Z" fill="currentColor"/></svg>`],["bottom",()=>html`<svg viewBox="0 0 10 6" fill="none"><path d="M4.23178 0.921865C4.63157 0.442111 5.36843 0.442112 5.76822 0.921866L10 6L-2.62268e-07 6L4.23178 0.921865Z" fill="currentColor"/></svg>`],["left",()=>html`<svg viewBox="0 0 6 10" fill="none"><path d="M5.07814 4.23178C5.55789 4.63157 5.55789 5.36843 5.07813 5.76822L-4.37114e-07 10L0 -2.62268e-07L5.07814 4.23178Z" fill="currentColor"/></svg>`]])}</div><span aria-label="${ifDefined(this.disabled?void 0:"Tooltip: ")}"></span><div class="${classMap({content:!0,reversed:"left"===this.effectivePlacement})}"><slot class="default-slot" @slotchange="${this.#R}" ${ref(this.#t)}></slot><kbd class="${classMap({shortcut:!0,reversed:"left"===this.effectivePlacement,visible:this.shortcut.length>0})}" data-test="shortcut">${1===this.shortcut.length?this.shortcut.at(0):map(this.shortcut,((e,t)=>html`<kbd>${e}</kbd> ${t===this.shortcut.length-1?"":" + "}`))}</kbd></div></div></div>`}#e;#w;#p;#t;#o;#l;#f;#c;#i;#s;#a;#E(){clearTimeout(this.#p)}#n(){this.#a.value?.hidePopover(),this.#w&&this.#w()}#R(){owSlot(this.#t.value)}#m(){this.open=!0}#u(){this.open=!1}#v(e){"Escape"===e.key&&(this.open=!1)}#d(){this.#y(),clearTimeout(this.#c)}#h(){ow(this.#a.value,ow.object.instanceOf(HTMLElement)),this.#E(),this.#c=setTimeout((()=>{this.open=!0}),Number(this.#a.value.dataset.openDelay))}#g(){owSlot(this.#s.value)}#y(){ow(this.#a.value,ow.object.instanceOf(HTMLElement)),this.#p=setTimeout((()=>{this.open=!1}),Number(this.#a.value.dataset.closeDelay))}#r(){this.disabled||(this.#w?.(),this.#i.value&&this.#a.value&&(this.#w=autoUpdate(this.#i.value,this.#a.value,(()=>{(async()=>{if(this.#i.value&&this.#a.value&&this.#e.value){const{x:e,y:t,placement:o,middlewareData:l}=await computePosition(this.#i.value,this.#a.value,{placement:this.placement,middleware:[offset(this.offset),flip({fallbackStrategy:"initialPlacement"}),shift({limiter:limitShift({offset:20})}),arrow({element:this.#e.value})]});Object.assign(this.#a.value.style,{left:`${e}px`,top:`${t}px`}),Object.assign(this.#e.value.style,{left:l.arrow?.x?`${l.arrow.x}px`:null,top:l.arrow?.y?`${l.arrow.y}px`:null}),this.effectivePlacement=o,this.#a.value.showPopover()}})()}))))}};__decorate([property({reflect:!0,type:Boolean})],GlideCoreTooltip.prototype,"disabled",null),__decorate([property({reflect:!0,type:Number})],GlideCoreTooltip.prototype,"offset",null),__decorate([property({reflect:!0,type:Boolean})],GlideCoreTooltip.prototype,"open",null),__decorate([property()],GlideCoreTooltip.prototype,"placement",void 0),__decorate([property({reflect:!0,type:Array})],GlideCoreTooltip.prototype,"shortcut",void 0),__decorate([state()],GlideCoreTooltip.prototype,"effectivePlacement",void 0),GlideCoreTooltip=__decorate([customElement("glide-core-tooltip")],GlideCoreTooltip);export default GlideCoreTooltip;
@@ -80,6 +80,7 @@ import{css}from"lit";import focusOutline from"./styles/focus-outline.js";import
80
80
  --arrow-height: 0.375rem;
81
81
  --arrow-width: 0.625rem;
82
82
 
83
+ color: var(--glide-core-surface-base-dark);
83
84
  display: flex;
84
85
  position: relative;
85
86
 
@@ -117,7 +118,7 @@ import{css}from"lit";import focusOutline from"./styles/focus-outline.js";import
117
118
  }
118
119
 
119
120
  .default-slot {
120
- color: var(--glide-core-text-selected);
121
+ color: var(--glide-core-text-selected-2);
121
122
  display: block;
122
123
  hyphens: auto;
123
124
  max-inline-size: 11.25rem;
@@ -21,4 +21,5 @@ export default class GlideCoreTreeItemMenu extends LitElement {
21
21
  click(): void;
22
22
  firstUpdated(): void;
23
23
  render(): import("lit").TemplateResult<1>;
24
+ private hasCustomIcon;
24
25
  }
@@ -1 +1 @@
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"./icon-button.js";import"./menu.js";import"./menu.options.js";import{LitElement,html}from"lit";import{createRef,ref}from"lit/directives/ref.js";import{customElement,property}from"lit/decorators.js";import GlideCoreIconButton from"./icon-button.js";import GlideCoreMenuButton from"./menu.button.js";import GlideCoreMenuLink from"./menu.link.js";import ow,{owSlot,owSlotType}from"./library/ow.js";import styles from"./tree.item.menu.styles.js";let GlideCoreTreeItemMenu=class GlideCoreTreeItemMenu extends LitElement{constructor(){super(...arguments),this.placement="bottom-start",this.label="",this.#e=createRef(),this.#t=createRef(),this.#o=createRef()}static{this.shadowRootOptions={...LitElement.shadowRootOptions,mode:"closed"}}static{this.styles=styles}click(){ow(this.#t.value,ow.object.instanceOf(GlideCoreIconButton)),this.#t.value.click()}firstUpdated(){owSlot(this.#e.value),owSlotType(this.#e.value,[GlideCoreMenuButton,GlideCoreMenuLink])}render(){return html`<glide-core-menu class="component" placement="${this.placement}" ${ref(this.#o)}><glide-core-menu-options><slot @slotchange="${this.#l}" ${ref(this.#e)}></slot></glide-core-menu-options><glide-core-icon-button slot="target" variant="tertiary" label="${this.label}" ${ref(this.#t)}><svg aria-hidden="true" width="4" height="14" viewBox="0 0 4 18" fill="none" stroke="currentColor" stroke-width="2"><path d="M2 15C2.55228 15 3 15.4477 3 16C3 16.5523 2.55228 17 2 17C1.44772 17 1 16.5523 1 16C1 15.4477 1.44772 15 2 15Z"/><path d="M2 8C2.55228 8 3 8.44772 3 9C3 9.55228 2.55228 10 2 10C1.44772 10 1 9.55228 1 9C1 8.44772 1.44772 8 2 8Z"/><path d="M2 1C2.55228 1 3 1.44772 3 2C3 2.55228 2.55228 3 2 3C1.44772 3 1 2.55228 1 2C1 1.44772 1.44772 1 2 1Z"/></svg></glide-core-icon-button></glide-core-menu>`}#e;#t;#o;#l(){owSlot(this.#e.value),owSlotType(this.#e.value,[GlideCoreMenuButton,GlideCoreMenuLink])}};__decorate([property({reflect:!0})],GlideCoreTreeItemMenu.prototype,"placement",void 0),__decorate([property()],GlideCoreTreeItemMenu.prototype,"label",void 0),GlideCoreTreeItemMenu=__decorate([customElement("glide-core-tree-item-menu")],GlideCoreTreeItemMenu);export default GlideCoreTreeItemMenu;
1
+ var __decorate=this&&this.__decorate||function(e,t,o,n){var l,i=arguments.length,r=i<3?t:null===n?n=Object.getOwnPropertyDescriptor(t,o):n;if("object"==typeof Reflect&&"function"==typeof Reflect.decorate)r=Reflect.decorate(e,t,o,n);else for(var s=e.length-1;s>=0;s--)(l=e[s])&&(r=(i<3?l(r):i>3?l(t,o,r):l(t,o))||r);return i>3&&r&&Object.defineProperty(t,o,r),r};import"./icon-button.js";import"./menu.js";import"./menu.options.js";import{LitElement,html}from"lit";import{createRef,ref}from"lit/directives/ref.js";import{customElement,property,state}from"lit/decorators.js";import{when}from"lit/directives/when.js";import GlideCoreIconButton from"./icon-button.js";import GlideCoreMenuButton from"./menu.button.js";import GlideCoreMenuLink from"./menu.link.js";import ow,{owSlot,owSlotType}from"./library/ow.js";import styles from"./tree.item.menu.styles.js";let GlideCoreTreeItemMenu=class GlideCoreTreeItemMenu extends LitElement{constructor(){super(...arguments),this.placement="bottom-start",this.label="",this.hasCustomIcon=!1,this.#e=createRef(),this.#t=createRef(),this.#o=createRef(),this.#n=createRef()}static{this.shadowRootOptions={...LitElement.shadowRootOptions,mode:"closed"}}static{this.styles=styles}click(){ow(this.#t.value,ow.object.instanceOf(GlideCoreIconButton)),this.#t.value.click()}firstUpdated(){owSlot(this.#e.value),owSlotType(this.#e.value,[GlideCoreMenuButton,GlideCoreMenuLink])}render(){return html`<glide-core-menu class="component" placement="${this.placement}" ${ref(this.#n)}><glide-core-menu-options><slot @slotchange="${this.#l}" ${ref(this.#e)}></slot></glide-core-menu-options><glide-core-icon-button slot="target" variant="tertiary" label="${this.label}" ${ref(this.#t)}><slot name="icon" @slotchange="${this.#i}" ${ref(this.#o)}></slot>${when(!this.hasCustomIcon,(()=>html`<svg aria-hidden="true" width="4" height="14" viewBox="0 0 4 18" fill="none" stroke="currentColor" stroke-width="2"><path d="M2 15C2.55228 15 3 15.4477 3 16C3 16.5523 2.55228 17 2 17C1.44772 17 1 16.5523 1 16C1 15.4477 1.44772 15 2 15Z"/><path d="M2 8C2.55228 8 3 8.44772 3 9C3 9.55228 2.55228 10 2 10C1.44772 10 1 9.55228 1 9C1 8.44772 1.44772 8 2 8Z"/><path d="M2 1C2.55228 1 3 1.44772 3 2C3 2.55228 2.55228 3 2 3C1.44772 3 1 2.55228 1 2C1 1.44772 1.44772 1 2 1Z"/></svg>`))}</glide-core-icon-button></glide-core-menu>`}#e;#t;#o;#n;#l(){owSlot(this.#e.value),owSlotType(this.#e.value,[GlideCoreMenuButton,GlideCoreMenuLink])}#i(){const e=this.#o.value?.assignedNodes();this.hasCustomIcon=Boolean(e&&e.length>0)}};__decorate([property({reflect:!0})],GlideCoreTreeItemMenu.prototype,"placement",void 0),__decorate([property()],GlideCoreTreeItemMenu.prototype,"label",void 0),__decorate([state()],GlideCoreTreeItemMenu.prototype,"hasCustomIcon",void 0),GlideCoreTreeItemMenu=__decorate([customElement("glide-core-tree-item-menu")],GlideCoreTreeItemMenu);export default GlideCoreTreeItemMenu;
@@ -1,8 +1,10 @@
1
- import { expect, fixture, html, waitUntil } from '@open-wc/testing';
1
+ import { assert, expect, fixture, html, waitUntil } from '@open-wc/testing';
2
+ import GlideCoreMenu from './menu.js';
2
3
  import GlideCoreTreeItemMenu from './tree.item.menu.js';
3
4
  import expectArgumentError from './library/expect-argument-error.js';
4
5
  import sinon from 'sinon';
5
6
  GlideCoreTreeItemMenu.shadowRootOptions.mode = 'open';
7
+ GlideCoreMenu.shadowRootOptions.mode = 'open';
6
8
  it('registers', async () => {
7
9
  expect(window.customElements.get('glide-core-tree-item-menu')).to.equal(GlideCoreTreeItemMenu);
8
10
  });
@@ -63,3 +65,22 @@ it('can be opened programmatically', async () => {
63
65
  ?.querySelector('glide-core-menu')
64
66
  ?.getAttribute('open')).to.equal('');
65
67
  });
68
+ it('can set a custom icon', async () => {
69
+ const component = await fixture(html `
70
+ <glide-core-tree-item-menu placement="bottom-end">
71
+ <svg data-test-custom-icon="true" slot="icon"></svg>
72
+ <glide-core-menu-link label="One" url="/one"> </glide-core-menu-link>
73
+ </glide-core-tree-item-menu>
74
+ `);
75
+ const menu = component.shadowRoot?.querySelector('glide-core-menu');
76
+ assert(menu);
77
+ const menuTarget = menu.shadowRoot
78
+ ?.querySelector('slot[name="target"]')
79
+ ?.assignedElements()[0];
80
+ assert(menuTarget);
81
+ const icon = menuTarget
82
+ ?.querySelector('slot[name="icon"]')
83
+ ?.assignedElements()[0];
84
+ assert(icon instanceof SVGElement);
85
+ expect(icon.dataset.testCustomIcon).to.equal('true');
86
+ });
@@ -113,10 +113,6 @@ import{css}from"lit";import focusOutline from"./styles/focus-outline.js";export
113
113
  --hovered-icon-button-color: var(--glide-core-icon-hover);
114
114
  }
115
115
 
116
- ::slotted([slot='suffix']) {
117
- padding-inline: var(--glide-core-spacing-xxs);
118
- }
119
-
120
116
  .label-container:hover,
121
117
  .label-container:focus,
122
118
  .label-container:focus-within,
@@ -127,6 +123,7 @@ import{css}from"lit";import focusOutline from"./styles/focus-outline.js";export
127
123
  }
128
124
 
129
125
  .label {
126
+ margin-inline-end: auto;
130
127
  min-inline-size: 0;
131
128
  overflow: hidden;
132
129
  text-overflow: ellipsis;
@@ -150,7 +147,7 @@ import{css}from"lit";import focusOutline from"./styles/focus-outline.js";export
150
147
 
151
148
  .icon-container {
152
149
  display: flex;
153
- flex: 1;
154
- justify-content: flex-end;
150
+ gap: var(--glide-core-spacing-xxs);
151
+ padding-inline: var(--glide-core-spacing-xxs);
155
152
  }
156
153
  `];
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@crowdstrike/glide-core",
3
- "version": "0.10.0",
3
+ "version": "0.12.0",
4
4
  "description": "CrowdStrike's Glide Design System components package for providing web components",
5
5
  "author": "CrowdStrike UX Team",
6
6
  "license": "Apache-2.0",