@crowdstrike/glide-core 0.6.5 → 0.7.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.
@@ -39,6 +39,7 @@ export default class GlideCoreCheckboxGroup extends LitElement {
39
39
  render(): import("lit").TemplateResult<1>;
40
40
  reportValidity(): boolean;
41
41
  constructor();
42
+ private isBlurring;
42
43
  private isCheckingValidity;
43
44
  private isReportValidityOrSubmit;
44
45
  }
@@ -1 +1 @@
1
- var __decorate=this&&this.__decorate||function(e,t,i,o){var r,l=arguments.length,s=l<3?t:null===o?o=Object.getOwnPropertyDescriptor(t,i):o;if("object"==typeof Reflect&&"function"==typeof Reflect.decorate)s=Reflect.decorate(e,t,i,o);else for(var a=e.length-1;a>=0;a--)(r=e[a])&&(s=(l<3?r(s):l>3?r(t,i,s):r(t,i))||s);return l>3&&s&&Object.defineProperty(t,i,s),s};import"./label.js";import{LitElement,html}from"lit";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{owSlot,owSlotType}from"./library/ow.js";import GlideCoreCheckbox from"./checkbox.js";import styles from"./checkbox-group.styles.js";let GlideCoreCheckboxGroup=class GlideCoreCheckboxGroup extends LitElement{static{this.formAssociated=!0}static{this.shadowRootOptions={...LitElement.shadowRootOptions,mode:"closed"}}static{this.styles=styles}get disabled(){return this.#e}set disabled(e){this.#e=e;for(const t of this.#t)t.disabled=e}get required(){return this.#i}set required(e){this.#i=e;for(const t of this.#t)e?t.setValidity(this.#o.validity," "):t.setValidity({}),t.requestUpdate()}checkValidity(){return this.isCheckingValidity=!0,this.#o.checkValidity()}disconnectedCallback(){super.disconnectedCallback(),this.form?.removeEventListener("formdata",this.#r)}firstUpdated(){if(owSlot(this.#l.value),owSlotType(this.#l.value,[GlideCoreCheckbox]),this.disabled)for(const e of this.#t)e.disabled=!0;this.value=this.#t.filter((({checked:e,disabled:t})=>e&&!t)).map((({value:e})=>e)).filter((e=>Boolean(e)));for(const e of this.#t)e.privateVariant="minimal"}get form(){return this.#o.form}get validity(){const e=this.#t.some((({checked:e})=>e));this.required&&!e?this.#o.setValidity({valueMissing:!0}," ",this.#s.value):this.#o.setValidity({});for(const e of this.#t)e.setValidity(this.#o.validity," "),e.requestUpdate();return this.#o.validity}get willValidate(){return this.#o.willValidate}focus(e){this.#t.at(0)?.focus(e)}formAssociatedCallback(){this.form?.addEventListener("formdata",this.#r)}formResetCallback(){for(const e of this.#t)e.formResetCallback()}render(){return html`<div class="component" data-test="component" ${ref(this.#s)}><glide-core-label split="${ifDefined(this.privateSplit??void 0)}" ?hide="${this.hideLabel}" ?disabled="${this.disabled}" ?error="${this.#a}" ?required="${this.required}"><slot name="tooltip" slot="tooltip"></slot><label id="label">${this.label}</label><div aria-labelledby="label description" role="group" slot="control"><slot class="checkboxes" @change="${this.#d}" @slotchange="${this.#c}" ${ref(this.#l)}></slot></div><slot id="description" name="description" slot="description"></slot></glide-core-label></div>`}reportValidity(){return this.#o.reportValidity()}constructor(){super(),this.hideLabel=!1,this.value=[],this.isCheckingValidity=!1,this.isReportValidityOrSubmit=!1,this.#s=createRef(),this.#l=createRef(),this.#e=!1,this.#i=!1,this.#r=({formData:e})=>{this.name&&this.value.length>0&&!this.disabled&&e.append(this.name,JSON.stringify(this.value))},this.#o=this.attachInternals(),this.addEventListener("invalid",(e=>{e?.preventDefault(),this.isCheckingValidity||(this.isReportValidityOrSubmit=!0,this.focus())}))}#s;#l;#o;#e;#i;get#t(){return this.#l.value?this.#l.value.assignedElements().filter((e=>e instanceof GlideCoreCheckbox)):[]}#r;get#a(){return this.required&&!this.disabled&&!this.validity.valid&&this.isReportValidityOrSubmit}#d(){this.value=this.#t.filter((({checked:e,disabled:t})=>e&&!t)).map((({value:e})=>e)).filter((e=>Boolean(e)))}#c(){owSlot(this.#l.value),owSlotType(this.#l.value,[GlideCoreCheckbox])}};__decorate([property({reflect:!0,type:Boolean})],GlideCoreCheckboxGroup.prototype,"disabled",null),__decorate([property({attribute:"hide-label",type:Boolean})],GlideCoreCheckboxGroup.prototype,"hideLabel",void 0),__decorate([property({reflect:!0})],GlideCoreCheckboxGroup.prototype,"label",void 0),__decorate([property({reflect:!0})],GlideCoreCheckboxGroup.prototype,"name",void 0),__decorate([property()],GlideCoreCheckboxGroup.prototype,"privateSplit",void 0),__decorate([property({reflect:!0,type:Boolean})],GlideCoreCheckboxGroup.prototype,"required",null),__decorate([property({reflect:!0})],GlideCoreCheckboxGroup.prototype,"summary",void 0),__decorate([property({type:Array})],GlideCoreCheckboxGroup.prototype,"value",void 0),__decorate([state()],GlideCoreCheckboxGroup.prototype,"isCheckingValidity",void 0),__decorate([state()],GlideCoreCheckboxGroup.prototype,"isReportValidityOrSubmit",void 0),GlideCoreCheckboxGroup=__decorate([customElement("glide-core-checkbox-group")],GlideCoreCheckboxGroup);export default GlideCoreCheckboxGroup;
1
+ var __decorate=this&&this.__decorate||function(e,t,i,o){var r,s=arguments.length,l=s<3?t:null===o?o=Object.getOwnPropertyDescriptor(t,i):o;if("object"==typeof Reflect&&"function"==typeof Reflect.decorate)l=Reflect.decorate(e,t,i,o);else for(var a=e.length-1;a>=0;a--)(r=e[a])&&(l=(s<3?r(l):s>3?r(t,i,l):r(t,i))||l);return s>3&&l&&Object.defineProperty(t,i,l),l};import"./label.js";import{LitElement,html}from"lit";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{owSlot,owSlotType}from"./library/ow.js";import GlideCoreCheckbox from"./checkbox.js";import styles from"./checkbox-group.styles.js";let GlideCoreCheckboxGroup=class GlideCoreCheckboxGroup extends LitElement{static{this.formAssociated=!0}static{this.shadowRootOptions={...LitElement.shadowRootOptions,mode:"closed"}}static{this.styles=styles}get disabled(){return this.#e}set disabled(e){this.#e=e;for(const t of this.#t)t.disabled=e}get required(){return this.#i}set required(e){this.#i=e;for(const t of this.#t)e?t.setValidity(this.#o.validity," "):t.setValidity({}),t.requestUpdate()}checkValidity(){this.isCheckingValidity=!0;const e=this.#o.checkValidity();return this.isCheckingValidity=!1,e}disconnectedCallback(){super.disconnectedCallback(),this.form?.removeEventListener("formdata",this.#r)}firstUpdated(){if(owSlot(this.#s.value),owSlotType(this.#s.value,[GlideCoreCheckbox]),this.disabled)for(const e of this.#t)e.disabled=!0;this.value=this.#t.filter((({checked:e,disabled:t})=>e&&!t)).map((({value:e})=>e)).filter((e=>Boolean(e)));for(const e of this.#t)e.privateVariant="minimal",e.addEventListener("blur",this.#l.bind(this))}get form(){return this.#o.form}get validity(){const e=this.#t.some((({checked:e})=>e));this.required&&!e?this.#o.setValidity({valueMissing:!0}," ",this.#a.value):this.#o.setValidity({});for(const e of this.#t)e.setValidity(this.#o.validity," "),e.requestUpdate();return this.#o.validity}get willValidate(){return this.#o.willValidate}focus(e){this.#t.at(0)?.focus(e)}formAssociatedCallback(){this.form?.addEventListener("formdata",this.#r)}formResetCallback(){for(const e of this.#t)e.formResetCallback()}render(){return html`<div class="component" data-test="component" ${ref(this.#a)}><glide-core-label split="${ifDefined(this.privateSplit??void 0)}" ?hide="${this.hideLabel}" ?disabled="${this.disabled}" ?error="${this.#d}" ?required="${this.required}"><slot name="tooltip" slot="tooltip"></slot><label id="label">${this.label}</label><div aria-labelledby="label description" role="group" slot="control"><slot class="checkboxes" @change="${this.#c}" @slotchange="${this.#n}" ${ref(this.#s)}></slot></div><slot id="description" name="description" slot="description"></slot></glide-core-label></div>`}reportValidity(){this.isReportValidityOrSubmit=!0;const e=this.#o.reportValidity();return this.requestUpdate(),e}constructor(){super(),this.hideLabel=!1,this.value=[],this.isBlurring=!1,this.isCheckingValidity=!1,this.isReportValidityOrSubmit=!1,this.#a=createRef(),this.#s=createRef(),this.#e=!1,this.#i=!1,this.#r=({formData:e})=>{this.name&&this.value.length>0&&!this.disabled&&e.append(this.name,JSON.stringify(this.value))},this.#o=this.attachInternals(),this.addEventListener("invalid",(e=>{if(e?.preventDefault(),this.isCheckingValidity||this.isBlurring)return;this.isReportValidityOrSubmit=!0;this.form?.querySelector(":invalid")===this&&this.focus()}))}#a;#s;#o;#e;#i;get#t(){return this.#s.value?this.#s.value.assignedElements().filter((e=>e instanceof GlideCoreCheckbox)):[]}#r;get#d(){return this.required&&!this.disabled&&!this.validity.valid&&this.isReportValidityOrSubmit}#h(){for(const e of this.#t)e.isReportValidityOrSubmit=!0}#l(e){const t=e.relatedTarget;t&&t instanceof GlideCoreCheckbox&&this.#t.includes(t)||this.#h()}#c(){this.value=this.#t.filter((({checked:e,disabled:t})=>e&&!t)).map((({value:e})=>e)).filter((e=>Boolean(e)))}#n(){owSlot(this.#s.value),owSlotType(this.#s.value,[GlideCoreCheckbox])}};__decorate([property({reflect:!0,type:Boolean})],GlideCoreCheckboxGroup.prototype,"disabled",null),__decorate([property({attribute:"hide-label",type:Boolean})],GlideCoreCheckboxGroup.prototype,"hideLabel",void 0),__decorate([property({reflect:!0})],GlideCoreCheckboxGroup.prototype,"label",void 0),__decorate([property({reflect:!0})],GlideCoreCheckboxGroup.prototype,"name",void 0),__decorate([property()],GlideCoreCheckboxGroup.prototype,"privateSplit",void 0),__decorate([property({reflect:!0,type:Boolean})],GlideCoreCheckboxGroup.prototype,"required",null),__decorate([property({reflect:!0})],GlideCoreCheckboxGroup.prototype,"summary",void 0),__decorate([property({type:Array})],GlideCoreCheckboxGroup.prototype,"value",void 0),__decorate([state()],GlideCoreCheckboxGroup.prototype,"isBlurring",void 0),__decorate([state()],GlideCoreCheckboxGroup.prototype,"isCheckingValidity",void 0),__decorate([state()],GlideCoreCheckboxGroup.prototype,"isReportValidityOrSubmit",void 0),GlideCoreCheckboxGroup=__decorate([customElement("glide-core-checkbox-group")],GlideCoreCheckboxGroup);export default GlideCoreCheckboxGroup;
@@ -1,7 +1,10 @@
1
1
  import './checkbox.js';
2
2
  import { expect, fixture, html } from '@open-wc/testing';
3
+ import { sendKeys } from '@web/test-runner-commands';
4
+ import GlideCoreCheckbox from './checkbox.js';
3
5
  import GlideCoreCheckboxGroup from './checkbox-group.js';
4
6
  GlideCoreCheckboxGroup.shadowRootOptions.mode = 'open';
7
+ GlideCoreCheckbox.shadowRootOptions.mode = 'open';
5
8
  it('focuses the first checkbox when `focus` is called', async () => {
6
9
  const component = await fixture(html `<glide-core-checkbox-group label="Checkbox Group">
7
10
  <glide-core-checkbox label="Checkbox"></glide-core-checkbox>
@@ -43,3 +46,23 @@ it('does not focus the input after `checkValidity` is called', async () => {
43
46
  component.checkValidity();
44
47
  expect(document.activeElement).to.not.equal(component.querySelector('glide-core-checkbox'));
45
48
  });
49
+ it('reports validity of checkboxes if blurred', async () => {
50
+ const component = await fixture(html `<glide-core-checkbox-group label="Checkbox Group" required>
51
+ <glide-core-checkbox label="Checkbox1"></glide-core-checkbox>
52
+ <glide-core-checkbox label="Checkbox2"></glide-core-checkbox>
53
+ </glide-core-checkbox-group>`);
54
+ component.focus();
55
+ const checkboxes = component.querySelectorAll('glide-core-checkbox');
56
+ expect(document.activeElement === checkboxes[0]).to.be.true;
57
+ await sendKeys({ press: 'Tab' });
58
+ expect(document.activeElement === checkboxes[1]).to.be.true;
59
+ expect(checkboxes[0].isReportValidityOrSubmit).to.equal(false);
60
+ expect(checkboxes[1].isReportValidityOrSubmit).to.equal(false);
61
+ await sendKeys({ press: 'Tab' });
62
+ expect(document.activeElement === document.body).to.be.true;
63
+ expect(component.validity.valid).to.equal(false);
64
+ expect(checkboxes[0].validity.valid).to.equal(false);
65
+ expect(checkboxes[0].isReportValidityOrSubmit).to.equal(true);
66
+ expect(checkboxes[1].validity.valid).to.equal(false);
67
+ expect(checkboxes[1].isReportValidityOrSubmit).to.equal(true);
68
+ });
@@ -32,7 +32,9 @@ export default class GlideCoreCheckbox extends LitElement {
32
32
  required: boolean;
33
33
  summary?: string;
34
34
  value?: string;
35
+ isReportValidityOrSubmit: boolean;
35
36
  get form(): HTMLFormElement | null;
37
+ blur(): void;
36
38
  checkValidity(): boolean;
37
39
  click(): void;
38
40
  disconnectedCallback(): void;
@@ -46,6 +48,6 @@ export default class GlideCoreCheckbox extends LitElement {
46
48
  get willValidate(): boolean;
47
49
  updated(): void;
48
50
  constructor();
51
+ private isBlurring;
49
52
  private isCheckingValidity;
50
- private isReportValidityOrSubmit;
51
53
  }
package/dist/checkbox.js CHANGED
@@ -1 +1 @@
1
- var __decorate=this&&this.__decorate||function(e,t,i,o){var r,a=arguments.length,s=a<3?t:null===o?o=Object.getOwnPropertyDescriptor(t,i):o;if("object"==typeof Reflect&&"function"==typeof Reflect.decorate)s=Reflect.decorate(e,t,i,o);else for(var n=e.length-1;n>=0;n--)(r=e[n])&&(s=(a<3?r(s):a>3?r(t,i,s):r(t,i))||s);return a>3&&s&&Object.defineProperty(t,i,s),s};import"./label.js";import{LitElement,html}from"lit";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{when}from"lit/directives/when.js";import checkedIcon from"./icons/checked.js";import ow from"./library/ow.js";import styles from"./checkbox.styles.js";const indeterminateIcon=html`<svg width="14" height="14" viewBox="0 0 14 14" fill="none" class="indeterminate-icon"><rect x="0.5" y="0.5" width="13" height="13" rx="3.5"/><path d="M3 5C3 3.89543 3.89543 3 5 3H9.79289C10.2383 3 10.4614 3.53857 10.1464 3.85355L3.85355 10.1464C3.53857 10.4614 3 10.2383 3 9.79289V5Z" fill="currentColor"/></svg>`;let GlideCoreCheckbox=class GlideCoreCheckbox extends LitElement{static{this.formAssociated=!0}static{this.shadowRootOptions={...LitElement.shadowRootOptions,mode:"closed"}}static{this.styles=styles}get form(){return this.#e.form}checkValidity(){return this.isCheckingValidity=!0,this.#e.checkValidity()}click(){this.#t.value?.click()}disconnectedCallback(){super.disconnectedCallback(),this.form?.removeEventListener("formdata",this.#i)}get validity(){return"minimal"===this.privateVariant||(this.required&&!this.checked?this.#e.setValidity({valueMissing:!0}," ",this.#t.value):this.#e.setValidity({})),this.#e.validity}focus(e){this.#t.value?.focus(e)}formAssociatedCallback(){this.form?.addEventListener("formdata",this.#i)}formResetCallback(){this.checked=""===this.getAttribute("checked"),this.indeterminate=""===this.getAttribute("indeterminate")}render(){return html`<div class="component" data-test="component">${when("minimal"===this.privateVariant,(()=>html`<label class="label-and-input-and-checkbox" part="private-label-and-input-and-checkbox"><div class="input-and-checkbox"><input aria-invalid="${this.#o}" data-test="input" type="checkbox" .checked="${this.checked}" .inert="${this.internallyInert}" ?disabled="${this.disabled}" ?required="${this.required}" @change="${this.#r}" ${ref(this.#t)}><div class="${classMap({checkbox:!0,disabled:this.disabled,error:this.#o})}"><div class="checked-icon">${checkedIcon}</div>${indeterminateIcon}</div></div>${this.label}</label>`),(()=>html`<glide-core-label orientation="${this.orientation}" split="${ifDefined(this.privateSplit??void 0)}" ?disabled="${this.disabled}" ?error="${this.#o}" ?hide="${this.hideLabel}" ?required="${this.required}"><slot name="tooltip" slot="tooltip"></slot><label for="input">${this.label}</label><div class="input-and-checkbox" slot="control"><input aria-describedby="summary description" aria-invalid="${this.#o}" data-test="input" id="input" type="checkbox" .checked="${this.checked}" ?disabled="${this.disabled}" ?required="${this.required}" @change="${this.#r}" ${ref(this.#t)}><div class="${classMap({checkbox:!0,disabled:this.disabled,error:this.#o})}"><div class="checked-icon">${checkedIcon}</div>${indeterminateIcon}</div></div><div id="summary" slot="summary">${this.summary}</div><slot id="description" name="description" slot="description"></slot></glide-core-label>`))}</div>`}reportValidity(){return this.#e.reportValidity()}setValidity(e,t,i){return this.#e.setValidity(e,t,i)}get willValidate(){return this.#e.willValidate}updated(){ow(this.#t.value,ow.object.instanceOf(HTMLInputElement)),this.#t.value.indeterminate=this.indeterminate}constructor(){super(),this.checked=!1,this.internallyInert=!1,this.disabled=!1,this.hideLabel=!1,this.indeterminate=!1,this.orientation="horizontal",this.required=!1,this.value="",this.isCheckingValidity=!1,this.isReportValidityOrSubmit=!1,this.#t=createRef(),this.#i=({formData:e})=>{this.checked&&this.name&&this.value&&!this.disabled&&e.append(this.name,this.value)},this.#e=this.attachInternals(),this.addEventListener("invalid",(e=>{e?.preventDefault(),this.isCheckingValidity||(this.isReportValidityOrSubmit=!0,this.focus())}))}#t;#e;#i;get#o(){return"minimal"===this.privateVariant?!this.validity.valid:this.required&&!this.disabled&&!this.validity.valid&&this.isReportValidityOrSubmit}#r(e){e.target instanceof HTMLInputElement&&(this.checked=e.target.checked),this.indeterminate=!1,this.dispatchEvent(new Event(e.type,e))}};__decorate([property({type:Boolean})],GlideCoreCheckbox.prototype,"checked",void 0),__decorate([property({attribute:"internally-inert",type:Boolean})],GlideCoreCheckbox.prototype,"internallyInert",void 0),__decorate([property({reflect:!0,type:Boolean})],GlideCoreCheckbox.prototype,"disabled",void 0),__decorate([property({attribute:"hide-label",type:Boolean})],GlideCoreCheckbox.prototype,"hideLabel",void 0),__decorate([property({type:Boolean})],GlideCoreCheckbox.prototype,"indeterminate",void 0),__decorate([property({reflect:!0})],GlideCoreCheckbox.prototype,"label",void 0),__decorate([property({reflect:!0})],GlideCoreCheckbox.prototype,"orientation",void 0),__decorate([property({reflect:!0})],GlideCoreCheckbox.prototype,"name",void 0),__decorate([property()],GlideCoreCheckbox.prototype,"privateSplit",void 0),__decorate([property({attribute:"private-variant"})],GlideCoreCheckbox.prototype,"privateVariant",void 0),__decorate([property({reflect:!0,type:Boolean})],GlideCoreCheckbox.prototype,"required",void 0),__decorate([property({reflect:!0})],GlideCoreCheckbox.prototype,"summary",void 0),__decorate([property({reflect:!0})],GlideCoreCheckbox.prototype,"value",void 0),__decorate([state()],GlideCoreCheckbox.prototype,"isCheckingValidity",void 0),__decorate([state()],GlideCoreCheckbox.prototype,"isReportValidityOrSubmit",void 0),GlideCoreCheckbox=__decorate([customElement("glide-core-checkbox")],GlideCoreCheckbox);export default GlideCoreCheckbox;
1
+ var __decorate=this&&this.__decorate||function(e,t,i,r){var o,a=arguments.length,s=a<3?t:null===r?r=Object.getOwnPropertyDescriptor(t,i):r;if("object"==typeof Reflect&&"function"==typeof Reflect.decorate)s=Reflect.decorate(e,t,i,r);else for(var n=e.length-1;n>=0;n--)(o=e[n])&&(s=(a<3?o(s):a>3?o(t,i,s):o(t,i))||s);return a>3&&s&&Object.defineProperty(t,i,s),s};import"./label.js";import{LitElement,html}from"lit";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{when}from"lit/directives/when.js";import checkedIcon from"./icons/checked.js";import ow from"./library/ow.js";import styles from"./checkbox.styles.js";const indeterminateIcon=html`<svg width="14" height="14" viewBox="0 0 14 14" fill="none" class="indeterminate-icon"><rect x="0.5" y="0.5" width="13" height="13" rx="3.5"/><path d="M3 5C3 3.89543 3.89543 3 5 3H9.79289C10.2383 3 10.4614 3.53857 10.1464 3.85355L3.85355 10.1464C3.53857 10.4614 3 10.2383 3 9.79289V5Z" fill="currentColor"/></svg>`;let GlideCoreCheckbox=class GlideCoreCheckbox extends LitElement{static{this.formAssociated=!0}static{this.shadowRootOptions={...LitElement.shadowRootOptions,mode:"closed"}}static{this.styles=styles}get form(){return this.#e.form}blur(){this.#t.value?.blur()}checkValidity(){this.isCheckingValidity=!0;const e=this.#e.checkValidity();return this.isCheckingValidity=!1,e}click(){this.#t.value?.click()}disconnectedCallback(){super.disconnectedCallback(),this.form?.removeEventListener("formdata",this.#i)}get validity(){return"minimal"===this.privateVariant||(this.required&&!this.checked?this.#e.setValidity({valueMissing:!0}," ",this.#t.value):this.#e.setValidity({})),this.#e.validity}focus(e){this.#t.value?.focus(e)}formAssociatedCallback(){this.form?.addEventListener("formdata",this.#i)}formResetCallback(){this.checked=""===this.getAttribute("checked"),this.indeterminate=""===this.getAttribute("indeterminate")}render(){return html`<div class="component" data-test="component">${when("minimal"===this.privateVariant,(()=>html`<label class="label-and-input-and-checkbox" part="private-label-and-input-and-checkbox"><div class="input-and-checkbox"><input aria-invalid="${this.#r}" data-test="input" type="checkbox" .checked="${this.checked}" .inert="${this.internallyInert}" ?disabled="${this.disabled}" ?required="${this.required}" @change="${this.#o}" ${ref(this.#t)}><div class="${classMap({checkbox:!0,disabled:this.disabled,error:this.#r})}"><div class="checked-icon">${checkedIcon}</div>${indeterminateIcon}</div></div>${this.label}</label>`),(()=>html`<glide-core-label orientation="${this.orientation}" split="${ifDefined(this.privateSplit??void 0)}" ?disabled="${this.disabled}" ?error="${this.#r}" ?hide="${this.hideLabel}" ?required="${this.required}"><slot name="tooltip" slot="tooltip"></slot><label for="input">${this.label}</label><div class="input-and-checkbox" slot="control"><input aria-describedby="summary description" aria-invalid="${this.#r}" data-test="input" id="input" type="checkbox" .checked="${this.checked}" ?disabled="${this.disabled}" ?required="${this.required}" @change="${this.#o}" @blur="${this.#a}" ${ref(this.#t)}><div class="${classMap({checkbox:!0,disabled:this.disabled,error:this.#r})}"><div class="checked-icon">${checkedIcon}</div>${indeterminateIcon}</div></div><div id="summary" slot="summary">${this.summary}</div><slot id="description" name="description" slot="description"></slot></glide-core-label>`))}</div>`}reportValidity(){this.isReportValidityOrSubmit=!0;const e=this.#e.reportValidity();return this.requestUpdate(),e}setValidity(e,t,i){return this.#e.setValidity(e,t,i)}get willValidate(){return this.#e.willValidate}updated(){ow(this.#t.value,ow.object.instanceOf(HTMLInputElement)),this.#t.value.indeterminate=this.indeterminate}constructor(){super(),this.checked=!1,this.internallyInert=!1,this.disabled=!1,this.hideLabel=!1,this.indeterminate=!1,this.orientation="horizontal",this.required=!1,this.value="",this.isReportValidityOrSubmit=!1,this.isBlurring=!1,this.isCheckingValidity=!1,this.#t=createRef(),this.#i=({formData:e})=>{this.checked&&this.name&&this.value&&!this.disabled&&e.append(this.name,this.value)},this.#e=this.attachInternals(),this.addEventListener("invalid",(e=>{if(e?.preventDefault(),this.isCheckingValidity||this.isBlurring)return;this.isReportValidityOrSubmit=!0;this.form?.querySelector(":invalid")===this&&this.focus()}))}#t;#e;#i;get#r(){return"minimal"===this.privateVariant?!this.validity.valid&&this.isReportValidityOrSubmit:this.required&&!this.disabled&&!this.validity.valid&&this.isReportValidityOrSubmit}#a(){this.isBlurring=!0,this.reportValidity(),this.isBlurring=!1}#o(e){e.target instanceof HTMLInputElement&&(this.checked=e.target.checked),this.indeterminate=!1,this.dispatchEvent(new Event(e.type,e))}};__decorate([property({type:Boolean})],GlideCoreCheckbox.prototype,"checked",void 0),__decorate([property({attribute:"internally-inert",type:Boolean})],GlideCoreCheckbox.prototype,"internallyInert",void 0),__decorate([property({reflect:!0,type:Boolean})],GlideCoreCheckbox.prototype,"disabled",void 0),__decorate([property({attribute:"hide-label",type:Boolean})],GlideCoreCheckbox.prototype,"hideLabel",void 0),__decorate([property({type:Boolean})],GlideCoreCheckbox.prototype,"indeterminate",void 0),__decorate([property({reflect:!0})],GlideCoreCheckbox.prototype,"label",void 0),__decorate([property({reflect:!0})],GlideCoreCheckbox.prototype,"orientation",void 0),__decorate([property({reflect:!0})],GlideCoreCheckbox.prototype,"name",void 0),__decorate([property()],GlideCoreCheckbox.prototype,"privateSplit",void 0),__decorate([property({attribute:"private-variant"})],GlideCoreCheckbox.prototype,"privateVariant",void 0),__decorate([property({reflect:!0,type:Boolean})],GlideCoreCheckbox.prototype,"required",void 0),__decorate([property({reflect:!0})],GlideCoreCheckbox.prototype,"summary",void 0),__decorate([property({reflect:!0})],GlideCoreCheckbox.prototype,"value",void 0),__decorate([state()],GlideCoreCheckbox.prototype,"isReportValidityOrSubmit",void 0),__decorate([state()],GlideCoreCheckbox.prototype,"isBlurring",void 0),__decorate([state()],GlideCoreCheckbox.prototype,"isCheckingValidity",void 0),GlideCoreCheckbox=__decorate([customElement("glide-core-checkbox")],GlideCoreCheckbox);export default GlideCoreCheckbox;
@@ -83,7 +83,8 @@ when browsers support them.
83
83
  border-color: var(--glide-core-surface-primary-disabled);
84
84
  }
85
85
 
86
- &:focus-visible ~ .checkbox {
86
+ &:focus-visible ~ .checkbox,
87
+ &:focus ~ .checkbox.error {
87
88
  ${focusOutline};
88
89
  }
89
90
 
@@ -36,3 +36,14 @@ it('does not focus the input after `checkValidity` is called', async () => {
36
36
  component.checkValidity();
37
37
  expect(component.shadowRoot?.activeElement).to.equal(null);
38
38
  });
39
+ it('blurs the input and reports validity if `blur` is called', async () => {
40
+ const component = await fixture(html `<glide-core-checkbox required></glide-core-checkbox>`);
41
+ component.focus();
42
+ const input = component.shadowRoot?.querySelector('[data-test="input"]');
43
+ expect(component.shadowRoot?.activeElement).to.equal(input);
44
+ component.blur();
45
+ await component.updateComplete;
46
+ expect(component.shadowRoot?.activeElement).to.equal(null);
47
+ expect(component.validity.valid).to.equal(false);
48
+ expect(component.shadowRoot?.querySelector('glide-core-label')?.error).to.equal(true);
49
+ });
@@ -12,9 +12,6 @@ import{css}from"lit";export default[css`
12
12
  opacity: 0;
13
13
  position: absolute;
14
14
  transform: translateX(100%);
15
- transition:
16
- transform 0.2s ease-out,
17
- opacity 0.3s ease-out;
18
15
  visibility: hidden;
19
16
 
20
17
  &.pinned {
@@ -36,10 +33,14 @@ import{css}from"lit";export default[css`
36
33
  inset: 0 0 0 auto;
37
34
  opacity: 1;
38
35
  transform: none;
36
+ transition:
37
+ transform 0.3s cubic-bezier(0.33, 1, 0.68, 1),
38
+ opacity 0.3s ease-in;
39
39
  visibility: visible;
40
40
  }
41
41
 
42
42
  .closing {
43
43
  transform: translateX(100%);
44
+ transition: transform 0.3s cubic-bezier(0.33, 1, 0.68, 1);
44
45
  }
45
46
  `];
@@ -61,6 +61,7 @@ export default class GlideCoreDropdown extends LitElement {
61
61
  reportValidity(): boolean;
62
62
  constructor();
63
63
  private ariaActivedescendant;
64
+ private isBlurring;
64
65
  private isCheckingValidity;
65
66
  private isEveryOptionFilteredOut;
66
67
  private isFilterable;
package/dist/dropdown.js CHANGED
@@ -1 +1 @@
1
- var _a,GlideCoreDropdown_1,__decorate=this&&this.__decorate||function(e,t,i,l){var o,s=arguments.length,n=s<3?t:null===l?l=Object.getOwnPropertyDescriptor(t,i):l;if("object"==typeof Reflect&&"function"==typeof Reflect.decorate)n=Reflect.decorate(e,t,i,l);else for(var a=e.length-1;a>=0;a--)(o=e[a])&&(n=(s<3?o(n):s>3?o(t,i,n):o(t,i))||n);return s>3&&n&&Object.defineProperty(t,i,n),n};import"./checkbox.js";import"./dropdown.option.js";import"./label.js";import{LitElement,html}from"lit";import{LocalizeController}from"./library/localize.js";import{classMap}from"lit/directives/class-map.js";import{createRef,ref}from"lit/directives/ref.js";import{customElement,property,state}from"lit/decorators.js";import{ifDefined}from"lit/directives/if-defined.js";import{repeat}from"lit/directives/repeat.js";import{svg}from"lit/static-html.js";import{when}from"lit/directives/when.js";import GlideCoreDropdownOption from"./dropdown.option.js";import GlideCoreTag from"./tag.js";import magnifyingGlassIcon from"./icons/magnifying-glass.js";import ow,{owSlotType}from"./library/ow.js";import styles from"./dropdown.styles.js";let GlideCoreDropdown=class GlideCoreDropdown extends LitElement{static{GlideCoreDropdown_1=this}static{this.formAssociated=!0}static{this.shadowRootOptions={...LitElement.shadowRootOptions,mode:"closed"}}static{this.styles=styles}get size(){return this.#e}set size(e){if(this.#e=e,this.#t)for(const t of this.#t)t.privateSize=e}get multiple(){return this.#i}set multiple(e){const t=this.#i&&!e,i=!this.#i&&e;this.#i=e;for(const i of this.#l)i.privateMultiple=e,t&&i!==this.lastSelectedOption&&(i.selected=!1);t&&this.lastSelectedOption?.value?this.#o=[this.lastSelectedOption.value]:i&&this.lastSelectedOption&&this.lastSelectedOption.privateUpdateCheckbox()}get value(){return this.#o}set value(e){this.#o=e,ow(this.multiple||!this.multiple&&e.length<=1,ow.boolean.true.message("Only one value is allowed when not `multiple`."));for(const t of this.#l)this.#s=!0,t.selected=e.some((e=>e&&e===t.value));this.dispatchEvent(new Event("change",{bubbles:!0})),this.dispatchEvent(new Event("input",{bubbles:!0}))}get selectedOptions(){return this.#l.filter((e=>e instanceof GlideCoreDropdownOption&&e.selected))}get lastSelectedOption(){return this.#l.findLast((e=>e.selected))}get isAllSelected(){return this.#l.filter((({selected:e})=>e)).length===this.#l.length}get isSomeSelected(){return this.#l.some((({selected:e})=>e))}get activeOption(){return this.#t?.find((({privateActive:e})=>e))}get internalLabel(){return this.isFilterable||0!==this.selectedOptions.length?this.multiple||this.isFilterable||!this.selectedOptions.at(-1)?.label?"":this.selectedOptions.at(-1)?.label:this.placeholder}checkValidity(){return this.isCheckingValidity=!0,this.#n.checkValidity()}connectedCallback(){super.connectedCallback(),document.addEventListener("click",this.#a,{capture:!0})}createRenderRoot(){return this.#r=super.createRenderRoot(),this.#r}disconnectedCallback(){super.disconnectedCallback(),this.form?.removeEventListener("formdata",this.#d),document.removeEventListener("click",this.#a,{capture:!0})}firstUpdated(){owSlotType(this.#p.value,[GlideCoreDropdownOption,Text])}focus(){this.isFilterable?this.#c.value?.focus():this.#h.value?.focus()}get form(){return this.#n.form}get validity(){return this.required&&0===this.selectedOptions.length?this.#n.setValidity({valueMissing:!0}," ",this.#c.value):this.#n.setValidity({}),this.#n.validity}get willValidate(){return this.#n.willValidate}formAssociatedCallback(){this.form?.addEventListener("formdata",this.#d)}formResetCallback(){for(const e of this.#l){e.hasAttribute("selected")||(e.selected=!1)}const e=this.#l.filter((e=>e.hasAttribute("selected"))),t=e.at(-1)?.value;this.#o=this.multiple&&e.length>0?e.map((({value:e})=>e)):!this.multiple&&t?[t]:[]}render(){return html`<div class="${classMap({component:!0,horizontal:"horizontal"===this.orientation,vertical:"vertical"===this.orientation})}"><glide-core-label split="${ifDefined(this.privateSplit??void 0)}" orientation="${this.orientation}" ?disabled="${this.disabled}" ?error="${this.#u}" ?hide="${this.hideLabel}" ?required="${this.required}"><label id="label">${this.label}</label><slot name="tooltip" slot="tooltip"></slot><div class="dropdown-and-options" slot="control" @focusout="${this.#v}" @keydown="${this.#f}"><div class="${classMap({dropdown:!0,quiet:"quiet"===this.variant,disabled:this.disabled,error:this.#u,readonly:this.readonly,multiple:this.multiple})}" @click="${this.#m}" @mousedown="${this.#g}"><span class="selected-option-labels" id="selected-option-labels">${this.selectedOptions.filter((({label:e})=>"string"==typeof e)).map((({label:e})=>html`<span data-test="selected-option-label">${e},</span>`))} </span>${when(this.multiple&&this.selectedOptions.length>0,(()=>html`<ul aria-describedby="tag-overflow-text" class="tags" ${ref(this.#b)}>${when(this.multiple&&this.selectedOptions.length>0,(()=>html`${repeat(this.selectedOptions,(({id:e})=>e),(({id:e,label:t},i)=>html`<li class="${classMap({"tag-container":!0,hidden:i>this.#E-1})}" data-test="tag-container" data-test-hidden="${i>this.#E-1}"><glide-core-tag data-test="tag" data-id="${e}" removable-label="${t??""}" @remove="${this.#w.bind(this,e)}">${t}</glide-core-tag></li>`))}`))}</ul>`))} ${when(this.isFilterable,(()=>html`<input aria-activedescendant="${this.ariaActivedescendant}" aria-controls="options" aria-describedby="description" aria-expanded="${this.open}" aria-labelledby="selected-option-labels label" autocapitalize="off" autocomplete="off" class="${classMap({input:!0,selection:Boolean(this.selectedOptions.at(0)),single:!this.multiple})}" data-test="input" id="input" placeholder="${this.multiple||!this.selectedOptions.at(-1)?.label?this.placeholder??"":this.selectedOptions.at(-1)?.label??""}" role="combobox" spellcheck="false" tabindex="${this.disabled?"-1":"0"}" ?disabled="${this.disabled}" ?readonly="${this.readonly}" @input="${this.#y}" @keydown="${this.#O}" ${ref(this.#c)}>`))} ${when(this.internalLabel,(()=>html`<div data-test="internal-label">${this.internalLabel}</div>`))} ${when(this.selectedOptions.length>this.#E,(()=>html`<div aria-hidden="true" class="tag-overflow-text" id="tag-overflow-text" data-test="tag-overflow-text">+ <span data-test="tag-overflow-count">${this.selectedOptions.length-this.#E} </span>more</div>`))} <button aria-hidden="${this.isFilterable}" aria-expanded="${this.open}" aria-haspopup="listbox" aria-labelledby="selected-option-labels label" aria-describedby="description" aria-controls="options" class="button" data-test="button" id="button" tabindex="${this.isFilterable||this.disabled?"-1":"0"}" type="button" ${ref(this.#h)}>${when(this.isFiltering,(()=>html`<div data-test="magnifying-glass-icon">${magnifyingGlassIcon}</div>`),(()=>svg`<svg aria-label="${this.#A.term("open")}" class="${classMap({"caret-icon":!0,disabled:this.disabled,readonly:this.readonly})}" width="16" height="16" viewBox="0 0 24 24" fill="none"><path d="M6 9L12 15L18 9" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"/></svg>`))}</button></div><div aria-labelledby="${this.isFilterable?"input":"button"}" class="${classMap({options:!0,visible:this.open&&!this.disabled&&!this.isEveryOptionFilteredOut})}" data-test="options" data-test-visible="${this.open&&!this.disabled&&!this.isEveryOptionFilteredOut}" id="options" role="listbox" @focusin="${this.#S}" @mousedown="${this.#C}" @mouseover="${this.#D}"><glide-core-dropdown-option class="select-all" data-test="select-all" label="${this.#A.term("selectAll")}" ?hidden="${!this.selectAll||!this.multiple||this.isFiltering}" @private-selected-change="${this.#R}" ${ref(this.#$)}></glide-core-dropdown-option><slot @private-selected-change="${this.#G}" @private-value-change="${this.#_}" @slotchange="${this.#k}" ${ref(this.#p)}></slot></div></div><slot id="description" name="description" slot="description"></slot></glide-core-label></div>`}reportValidity(){return this.#n.reportValidity()}constructor(){super(),this.disabled=!1,this.hideLabel=!1,this.open=!1,this.orientation="horizontal",this.readonly=!1,this.selectAll=!1,this.required=!1,this.ariaActivedescendant="",this.isCheckingValidity=!1,this.isEveryOptionFilteredOut=!1,this.isFilterable=!1,this.isFiltering=!1,this.isReportValidityOrSubmit=!1,this.#h=createRef(),this.#p=createRef(),this.#c=createRef(),this.#s=!1,this.#I=!1,this.#i=!1,this.#F=!1,this.#x=!1,this.#A=new LocalizeController(this),this.#$=createRef(),this.#e="large",this.#E=3,this.#b=createRef(),this.#o=[],this.#a=e=>{this.multiple&&!(e.target instanceof GlideCoreDropdown_1||e.target instanceof GlideCoreDropdownOption)?(this.open=!1,this.ariaActivedescendant=""):this.multiple||e.target instanceof GlideCoreDropdown_1||(this.open=!1,this.ariaActivedescendant="")},this.#d=({formData:e})=>{this.name&&this.value.length>0&&!this.disabled&&e.append(this.name,JSON.stringify(this.value))},this.#n=this.attachInternals(),this.addEventListener("invalid",(e=>{e?.preventDefault(),this.isCheckingValidity||(this.isReportValidityOrSubmit=!0,this.focus())}))}#h;#p;#c;#n;#s;#I;#i;#F;#x;#A;#$;#r;#e;#E;#b;#o;#a;#d;get#l(){return this.#p.value?.assignedElements().filter((e=>e instanceof GlideCoreDropdownOption))??[]}get#t(){const e=this.#p.value?.assignedElements().filter((e=>e instanceof GlideCoreDropdownOption));if(e&&this.#$.value)return[this.#$.value,...e]}get#V(){return this.#p.value?.assignedElements().filter((e=>e instanceof GlideCoreDropdownOption&&!e.hidden))}get#L(){const e=this.#p.value?.assignedElements().filter((e=>e instanceof GlideCoreDropdownOption&&!e.hidden));return this.#$.value&&!this.#$.value.hidden&&e?[this.#$.value,...e]:e}#M(){if(this.#t)for(const e of this.#t)e.privateActive=!1}get#u(){return this.required&&!this.disabled&&!this.validity.valid&&this.isReportValidityOrSubmit}#k(){if(owSlotType(this.#p.value,[GlideCoreDropdownOption,Text]),this.isFilterable=this.#l.length>10,this.#t)for(const e of this.#t)e.privateSize=this.size,e.privateMultiple=this.multiple;const e=this.#L?.at(0);this.lastSelectedOption?(this.#M(),this.lastSelectedOption.privateActive=!0,this.ariaActivedescendant=this.open?this.lastSelectedOption.id:""):e&&(this.#M(),e.privateActive=!0,this.ariaActivedescendant=this.open?e.id:""),this.#$.value&&(this.#I=!0,this.#$.value.selected=this.isAllSelected,this.#$.value.privateIndeterminate=this.isSomeSelected&&!this.isAllSelected),this.multiple?this.#o=this.selectedOptions.filter((e=>Boolean(e.value))).map((({value:e})=>e)):this.lastSelectedOption?.value&&(this.#o=[this.lastSelectedOption.value]),this.requestUpdate()}#v(e){(null===e.relatedTarget||e.relatedTarget instanceof Node&&!this.shadowRoot?.contains(e.relatedTarget)&&!this.contains(e.relatedTarget))&&!this.#F&&(this.open=!1,this.ariaActivedescendant="")}#f(e){if(this.disabled||this.readonly)return;if("Escape"===e.key)return this.open=!1,this.ariaActivedescendant="",void this.focus();const t=e.target===this.#h.value||e.target===this.#c.value||e.target instanceof GlideCoreDropdownOption;if(!this.multiple||t){if(!this.open&&[" ","ArrowUp","ArrowDown"].includes(e.key)&&this.activeOption)return e.preventDefault(),this.open=!0,void(this.ariaActivedescendant=this.activeOption.id);if(this.activeOption&&this.open){if("Enter"===e.key||" "===e.key){if(this.#x=!0,"Enter"===e.key)return void(this.activeOption.selected=!this.activeOption?.selected);if(" "===e.key&&!this.isFilterable)return void(this.activeOption.selected=!this.activeOption?.selected)}const t=this.#L?.indexOf(this.activeOption);if("ArrowUp"===e.key&&!e.metaKey&&this.#L&&"number"==typeof t){e.preventDefault();const i=this.#L.at(t-1);return void(i&&0!==t&&(this.#M(),i.privateActive=!0,this.ariaActivedescendant=i.id))}if("ArrowDown"===e.key&&!e.metaKey&&this.#L&&"number"==typeof t){e.preventDefault();const i=this.#L.at(t+1);return void(i&&(this.#M(),i.privateActive=!0,this.ariaActivedescendant=i.id))}if(("ArrowUp"===e.key&&e.metaKey||"Home"===e.key||"PageUp"===e.key)&&this.#L){e.preventDefault();const t=this.#L.at(0);return void(t&&(this.#M(),t.privateActive=!0,this.ariaActivedescendant=t.id))}if(("ArrowDown"===e.key&&e.metaKey||"End"===e.key||"PageDown"===e.key)&&this.#L){e.preventDefault();const t=this.#L.at(-1);return void(t&&(this.#M(),t.privateActive=!0,this.ariaActivedescendant=t.id))}}}}#m(e){this.disabled||this.readonly||(this.#F?this.#F=!1:e.target instanceof Node&&this.#h.value?.contains(e.target)&&!this.#x&&this.open?(this.open=!1,this.ariaActivedescendant=""):!this.open&&0!==e.detail&&this.activeOption&&(this.open=!0,this.ariaActivedescendant=this.activeOption.id))}#g(e){e.target instanceof GlideCoreTag||!this.isFilterable?e.target instanceof GlideCoreTag||e.preventDefault():(e.preventDefault(),this.focus())}#y(){if(ow(this.#c.value,ow.object.instanceOf(HTMLInputElement)),this.activeOption){this.open=!0,this.ariaActivedescendant=this.activeOption.id,this.isFiltering=""!==this.#c.value.value.trim();for(const e of this.#l)e.hidden=!e.label?.toLowerCase().includes(this.#c.value?.value.toLowerCase().trim());const e=this.#V?.at(0);e&&this.activeOption?.hidden&&(this.#M(),e.privateActive=!0,this.ariaActivedescendant=e.id),this.isEveryOptionFilteredOut=!this.#V||0===this.#V.length}}#O(e){const t=this.selectedOptions.filter(((e,t)=>t<=this.#E-1)).at(-1);t&&"Backspace"===e.key&&this.multiple&&this.#c.value&&0===this.#c.value.selectionStart&&(t.selected=!1)}#S(e){e.target instanceof GlideCoreDropdownOption&&(this.#M(),e.target.privateActive=!0)}#C(e){this.isFilterable&&e.preventDefault()}#D(e){if(e.target instanceof GlideCoreDropdownOption&&this.#L){this.#M(),e.target.privateActive=!0;for(const e of this.#L)e.privateActive&&(this.ariaActivedescendant=e.id)}}#G(e){if(this.#$.value&&e.target!==this.#$.value&&(this.#I=!0,this.#$.value.selected=this.isAllSelected,this.#$.value.privateIndeterminate=this.isSomeSelected&&!this.isAllSelected),this.isFilterable&&this.#c.value){this.#c.value.value="",this.isFiltering=!1;for(const e of this.#l)e.hidden=!1}e.target instanceof GlideCoreDropdownOption&&(this.multiple?(this.#o=e.target.selected&&e.target.value?[...this.value,e.target.value]:this.value.filter((t=>e.target instanceof GlideCoreDropdownOption&&t!==e.target.value)),this.#s||(this.dispatchEvent(new Event("change",{bubbles:!0})),this.dispatchEvent(new Event("input",{bubbles:!0})))):!this.multiple&&e.target.selected&&(this.#o=e.target.value?[e.target.value]:[],this.open=!1,this.ariaActivedescendant="",this.focus(),this.isFilterable&&this.#c.value&&(this.isFiltering=!1),this.#s||(this.dispatchEvent(new Event("change",{bubbles:!0})),this.dispatchEvent(new Event("input",{bubbles:!0}))))),this.requestUpdate()}#_(e){e.target instanceof GlideCoreDropdownOption&&this.multiple&&e.target.selected&&e.target.value?this.#o=[...this.value.filter((t=>t!==e.detail)),e.target.value]:e.target instanceof GlideCoreDropdownOption&&this.multiple?this.#o=this.value.filter((t=>e.target instanceof GlideCoreDropdownOption&&t!==e.detail)):e.target instanceof GlideCoreDropdownOption&&(this.#o=e.target.value?[e.target.value]:[])}#R(){if(this.#I)return void(this.#I=!1);this.#s=!0;const e=this.isAllSelected;for(const t of this.#l)t.selected=!e;this.#s=!1,this.dispatchEvent(new Event("change",{bubbles:!0})),this.dispatchEvent(new Event("input",{bubbles:!0}))}async#w(e){this.#F=!0;for(const t of this.#l)t.id===e&&(t.selected=!1,this.#o=this.value.filter((e=>e!==t.value)));const t=this.#b.value?.querySelectorAll("glide-core-tag");if(t&&this.value.length>0){const i=[...t].findIndex((t=>t.dataset.id===e));await this.updateComplete,t[i<t.length-1?i+1:i-1]?.focus()}else this.focus()}};__decorate([property({reflect:!0,type:Boolean})],GlideCoreDropdown.prototype,"disabled",void 0),__decorate([property({attribute:"hide-label",reflect:!0,type:Boolean})],GlideCoreDropdown.prototype,"hideLabel",void 0),__decorate([property({reflect:!0})],GlideCoreDropdown.prototype,"label",void 0),__decorate([property({reflect:!0})],GlideCoreDropdown.prototype,"name",void 0),__decorate([property({reflect:!0,type:Boolean})],GlideCoreDropdown.prototype,"open",void 0),__decorate([property({reflect:!0})],GlideCoreDropdown.prototype,"orientation",void 0),__decorate([property({reflect:!0})],GlideCoreDropdown.prototype,"placeholder",void 0),__decorate([property()],GlideCoreDropdown.prototype,"privateSplit",void 0),__decorate([property({type:Boolean})],GlideCoreDropdown.prototype,"readonly",void 0),__decorate([property({attribute:"select-all",reflect:!0,type:Boolean})],GlideCoreDropdown.prototype,"selectAll",void 0),__decorate([property({reflect:!0})],GlideCoreDropdown.prototype,"size",null),__decorate([property({reflect:!0,type:Boolean})],GlideCoreDropdown.prototype,"multiple",null),__decorate([property({reflect:!0,type:Boolean})],GlideCoreDropdown.prototype,"required",void 0),__decorate([property({type:Array})],GlideCoreDropdown.prototype,"value",null),__decorate([property({reflect:!0})],GlideCoreDropdown.prototype,"variant",void 0),__decorate([state()],GlideCoreDropdown.prototype,"ariaActivedescendant",void 0),__decorate([state()],GlideCoreDropdown.prototype,"isCheckingValidity",void 0),__decorate([state()],GlideCoreDropdown.prototype,"isEveryOptionFilteredOut",void 0),__decorate([state()],GlideCoreDropdown.prototype,"isFilterable",void 0),__decorate([state()],GlideCoreDropdown.prototype,"isFiltering",void 0),__decorate([state()],GlideCoreDropdown.prototype,"isReportValidityOrSubmit",void 0),GlideCoreDropdown=GlideCoreDropdown_1=__decorate([customElement("glide-core-dropdown")],GlideCoreDropdown);export default GlideCoreDropdown;
1
+ var _a,GlideCoreDropdown_1,__decorate=this&&this.__decorate||function(e,t,i,l){var o,s=arguments.length,n=s<3?t:null===l?l=Object.getOwnPropertyDescriptor(t,i):l;if("object"==typeof Reflect&&"function"==typeof Reflect.decorate)n=Reflect.decorate(e,t,i,l);else for(var a=e.length-1;a>=0;a--)(o=e[a])&&(n=(s<3?o(n):s>3?o(t,i,n):o(t,i))||n);return s>3&&n&&Object.defineProperty(t,i,n),n};import"./checkbox.js";import"./dropdown.option.js";import"./label.js";import{LitElement,html}from"lit";import{LocalizeController}from"./library/localize.js";import{classMap}from"lit/directives/class-map.js";import{createRef,ref}from"lit/directives/ref.js";import{customElement,property,state}from"lit/decorators.js";import{ifDefined}from"lit/directives/if-defined.js";import{repeat}from"lit/directives/repeat.js";import{svg}from"lit/static-html.js";import{when}from"lit/directives/when.js";import GlideCoreDropdownOption from"./dropdown.option.js";import GlideCoreTag from"./tag.js";import magnifyingGlassIcon from"./icons/magnifying-glass.js";import ow,{owSlotType}from"./library/ow.js";import styles from"./dropdown.styles.js";let GlideCoreDropdown=class GlideCoreDropdown extends LitElement{static{GlideCoreDropdown_1=this}static{this.formAssociated=!0}static{this.shadowRootOptions={...LitElement.shadowRootOptions,mode:"closed"}}static{this.styles=styles}get size(){return this.#e}set size(e){if(this.#e=e,this.#t)for(const t of this.#t)t.privateSize=e}get multiple(){return this.#i}set multiple(e){const t=this.#i&&!e,i=!this.#i&&e;this.#i=e;for(const i of this.#l)i.privateMultiple=e,t&&i!==this.lastSelectedOption&&(i.selected=!1);t&&this.lastSelectedOption?.value?this.#o=[this.lastSelectedOption.value]:i&&this.lastSelectedOption&&this.lastSelectedOption.privateUpdateCheckbox()}get value(){return this.#o}set value(e){this.#o=e,ow(this.multiple||!this.multiple&&e.length<=1,ow.boolean.true.message("Only one value is allowed when not `multiple`."));for(const t of this.#l)this.#s=!0,t.selected=e.some((e=>e&&e===t.value));this.#s=!1,this.dispatchEvent(new Event("change",{bubbles:!0})),this.dispatchEvent(new Event("input",{bubbles:!0}))}get selectedOptions(){return this.#l.filter((e=>e instanceof GlideCoreDropdownOption&&e.selected))}get lastSelectedOption(){return this.#l.findLast((e=>e.selected))}get isAllSelected(){return this.#l.filter((({selected:e})=>e)).length===this.#l.length}get isSomeSelected(){return this.#l.some((({selected:e})=>e))}get activeOption(){return this.#t?.find((({privateActive:e})=>e))}get internalLabel(){return this.isFilterable||0!==this.selectedOptions.length?this.multiple||this.isFilterable||!this.selectedOptions.at(-1)?.label?"":this.selectedOptions.at(-1)?.label:html`<span class="placeholder">${this.placeholder}</span>`}checkValidity(){this.isCheckingValidity=!0;const e=this.#n.checkValidity();return this.isCheckingValidity=!1,e}connectedCallback(){super.connectedCallback(),document.addEventListener("click",this.#a,{capture:!0})}createRenderRoot(){return this.#r=super.createRenderRoot(),this.#r}disconnectedCallback(){super.disconnectedCallback(),this.form?.removeEventListener("formdata",this.#d),document.removeEventListener("click",this.#a,{capture:!0})}firstUpdated(){owSlotType(this.#p.value,[GlideCoreDropdownOption,Text])}focus(){this.isFilterable?this.#c.value?.focus():this.#h.value?.focus()}get form(){return this.#n.form}get validity(){return this.required&&0===this.selectedOptions.length?this.#n.setValidity({valueMissing:!0}," ",this.#c.value):this.#n.setValidity({}),this.#n.validity}get willValidate(){return this.#n.willValidate}formAssociatedCallback(){this.form?.addEventListener("formdata",this.#d)}formResetCallback(){for(const e of this.#l){e.hasAttribute("selected")||(e.selected=!1)}const e=this.#l.filter((e=>e.hasAttribute("selected"))),t=e.at(-1)?.value;this.#o=this.multiple&&e.length>0?e.map((({value:e})=>e)):!this.multiple&&t?[t]:[]}render(){return html`<div class="${classMap({component:!0,horizontal:"horizontal"===this.orientation,vertical:"vertical"===this.orientation})}" @blur="${this.#u}"><glide-core-label split="${ifDefined(this.privateSplit??void 0)}" orientation="${this.orientation}" ?disabled="${this.disabled}" ?error="${this.#v}" ?hide="${this.hideLabel}" ?required="${this.required}" @blur="${this.#u}"><label id="label">${this.label}</label><slot name="tooltip" slot="tooltip"></slot><div class="dropdown-and-options" slot="control" @focusout="${this.#f}" @keydown="${this.#m}"><div class="${classMap({dropdown:!0,quiet:"quiet"===this.variant,disabled:this.disabled,error:this.#v,readonly:this.readonly,multiple:this.multiple})}" @click="${this.#g}" @mousedown="${this.#b}"><span class="selected-option-labels" id="selected-option-labels">${this.selectedOptions.filter((({label:e})=>"string"==typeof e)).map((({label:e})=>html`<span data-test="selected-option-label">${e},</span>`))} </span>${when(this.multiple&&this.selectedOptions.length>0,(()=>html`<ul aria-describedby="tag-overflow-text" class="tags" ${ref(this.#E)}>${when(this.multiple&&this.selectedOptions.length>0,(()=>html`${repeat(this.selectedOptions,(({id:e})=>e),(({id:e,label:t},i)=>html`<li class="${classMap({"tag-container":!0,hidden:i>this.#w-1})}" data-test="tag-container" data-test-hidden="${i>this.#w-1}"><glide-core-tag data-test="tag" data-id="${e}" removable-label="${t??""}" @remove="${this.#y.bind(this,e)}">${t}</glide-core-tag></li>`))}`))}</ul>`))} ${when(this.isFilterable,(()=>html`<input aria-activedescendant="${this.ariaActivedescendant}" aria-controls="options" aria-describedby="description" aria-expanded="${this.open}" aria-labelledby="selected-option-labels label" autocapitalize="off" autocomplete="off" class="${classMap({input:!0,selection:Boolean(this.selectedOptions.at(0)),single:!this.multiple})}" data-test="input" id="input" placeholder="${this.multiple||!this.selectedOptions.at(-1)?.label?this.placeholder??"":this.selectedOptions.at(-1)?.label??""}" role="combobox" spellcheck="false" tabindex="${this.disabled?"-1":"0"}" ?disabled="${this.disabled}" ?readonly="${this.readonly}" @input="${this.#O}" @keydown="${this.#A}" ${ref(this.#c)}>`))} ${when(this.internalLabel,(()=>html`<div data-test="internal-label">${this.internalLabel}</div>`))} ${when(this.selectedOptions.length>this.#w,(()=>html`<div aria-hidden="true" class="tag-overflow-text" id="tag-overflow-text" data-test="tag-overflow-text">+ <span data-test="tag-overflow-count">${this.selectedOptions.length-this.#w} </span>more</div>`))} <button aria-hidden="${this.isFilterable}" aria-expanded="${this.open}" aria-haspopup="listbox" aria-labelledby="selected-option-labels label" aria-describedby="description" aria-controls="options" class="button" data-test="button" id="button" tabindex="${this.isFilterable||this.disabled?"-1":"0"}" type="button" ${ref(this.#h)}>${when(this.isFiltering,(()=>html`<div data-test="magnifying-glass-icon">${magnifyingGlassIcon}</div>`),(()=>svg`<svg aria-label="${this.#S.term("open")}" class="${classMap({"caret-icon":!0,disabled:this.disabled,readonly:this.readonly})}" width="16" height="16" viewBox="0 0 24 24" fill="none"><path d="M6 9L12 15L18 9" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"/></svg>`))}</button></div><div aria-labelledby="${this.isFilterable?"input":"button"}" class="${classMap({options:!0,visible:this.open&&!this.disabled&&!this.isEveryOptionFilteredOut})}" data-test="options" data-test-visible="${this.open&&!this.disabled&&!this.isEveryOptionFilteredOut}" id="options" role="listbox" @focusin="${this.#C}" @mousedown="${this.#D}" @mouseover="${this.#R}"><glide-core-dropdown-option class="select-all" data-test="select-all" label="${this.#S.term("selectAll")}" ?hidden="${!this.selectAll||!this.multiple||this.isFiltering}" @private-selected-change="${this.#$}" ${ref(this.#_)}></glide-core-dropdown-option><slot @private-selected-change="${this.#G}" @private-value-change="${this.#k}" @slotchange="${this.#I}" ${ref(this.#p)}></slot></div></div><slot id="description" name="description" slot="description"></slot></glide-core-label></div>`}reportValidity(){this.isReportValidityOrSubmit=!0;const e=this.#n.reportValidity();return this.requestUpdate(),e}constructor(){super(),this.disabled=!1,this.hideLabel=!1,this.open=!1,this.orientation="horizontal",this.readonly=!1,this.selectAll=!1,this.required=!1,this.ariaActivedescendant="",this.isBlurring=!1,this.isCheckingValidity=!1,this.isEveryOptionFilteredOut=!1,this.isFilterable=!1,this.isFiltering=!1,this.isReportValidityOrSubmit=!1,this.#h=createRef(),this.#p=createRef(),this.#c=createRef(),this.#s=!1,this.#F=!1,this.#i=!1,this.#x=!1,this.#V=!1,this.#S=new LocalizeController(this),this.#_=createRef(),this.#e="large",this.#w=3,this.#E=createRef(),this.#o=[],this.#a=e=>{this.multiple&&!(e.target instanceof GlideCoreDropdown_1||e.target instanceof GlideCoreDropdownOption)?(this.open=!1,this.ariaActivedescendant=""):this.multiple||e.target instanceof GlideCoreDropdown_1||(this.open=!1,this.ariaActivedescendant="")},this.#d=({formData:e})=>{this.name&&this.value.length>0&&!this.disabled&&e.append(this.name,JSON.stringify(this.value))},this.#n=this.attachInternals(),this.addEventListener("invalid",(e=>{if(e?.preventDefault(),this.isCheckingValidity||this.isBlurring)return;this.isReportValidityOrSubmit=!0;this.form?.querySelector(":invalid")===this&&this.focus()}))}#h;#p;#c;#n;#s;#F;#i;#x;#V;#S;#_;#r;#e;#w;#E;#o;#a;#d;get#l(){return this.#p.value?.assignedElements().filter((e=>e instanceof GlideCoreDropdownOption))??[]}get#t(){const e=this.#p.value?.assignedElements().filter((e=>e instanceof GlideCoreDropdownOption));if(e&&this.#_.value)return[this.#_.value,...e]}get#L(){return this.#p.value?.assignedElements().filter((e=>e instanceof GlideCoreDropdownOption&&!e.hidden))}get#M(){const e=this.#p.value?.assignedElements().filter((e=>e instanceof GlideCoreDropdownOption&&!e.hidden));return this.#_.value&&!this.#_.value.hidden&&e?[this.#_.value,...e]:e}#j(){if(this.#t)for(const e of this.#t)e.privateActive=!1}get#v(){return this.required&&!this.disabled&&!this.validity.valid&&this.isReportValidityOrSubmit}#u(){this.isBlurring=!0,this.reportValidity(),this.isBlurring=!1}#I(){if(owSlotType(this.#p.value,[GlideCoreDropdownOption,Text]),this.isFilterable=this.#l.length>10,this.#t)for(const e of this.#t)e.privateSize=this.size,e.privateMultiple=this.multiple;const e=this.#M?.at(0);this.lastSelectedOption?(this.#j(),this.lastSelectedOption.privateActive=!0,this.ariaActivedescendant=this.open?this.lastSelectedOption.id:""):e&&(this.#j(),e.privateActive=!0,this.ariaActivedescendant=this.open?e.id:""),this.#_.value&&(this.#F=!0,this.#_.value.selected=this.isAllSelected,this.#_.value.privateIndeterminate=this.isSomeSelected&&!this.isAllSelected),this.multiple?this.#o=this.selectedOptions.filter((e=>Boolean(e.value))).map((({value:e})=>e)):this.lastSelectedOption?.value&&(this.#o=[this.lastSelectedOption.value]),this.requestUpdate()}#f(e){(null===e.relatedTarget||e.relatedTarget instanceof Node&&!this.shadowRoot?.contains(e.relatedTarget)&&!this.contains(e.relatedTarget))&&!this.#x&&(this.open=!1,this.ariaActivedescendant=""),this.#u()}#m(e){if(this.disabled||this.readonly)return;if("Escape"===e.key)return this.open=!1,this.ariaActivedescendant="",void this.focus();const t=e.target===this.#h.value||e.target===this.#c.value||e.target instanceof GlideCoreDropdownOption;if(!this.multiple||t){if(!this.open&&[" ","ArrowUp","ArrowDown"].includes(e.key)&&this.activeOption)return e.preventDefault(),this.open=!0,void(this.ariaActivedescendant=this.activeOption.id);if(this.activeOption&&this.open){if("Enter"===e.key||" "===e.key){if(this.#V=!0,"Enter"===e.key)return void(this.activeOption.selected=!this.activeOption?.selected);if(" "===e.key&&!this.isFilterable)return void(this.activeOption.selected=!this.activeOption?.selected)}const t=this.#M?.indexOf(this.activeOption);if("ArrowUp"===e.key&&!e.metaKey&&this.#M&&"number"==typeof t){e.preventDefault();const i=this.#M.at(t-1);return void(i&&0!==t&&(this.#j(),i.privateActive=!0,this.ariaActivedescendant=i.id))}if("ArrowDown"===e.key&&!e.metaKey&&this.#M&&"number"==typeof t){e.preventDefault();const i=this.#M.at(t+1);return void(i&&(this.#j(),i.privateActive=!0,this.ariaActivedescendant=i.id))}if(("ArrowUp"===e.key&&e.metaKey||"Home"===e.key||"PageUp"===e.key)&&this.#M){e.preventDefault();const t=this.#M.at(0);return void(t&&(this.#j(),t.privateActive=!0,this.ariaActivedescendant=t.id))}if(("ArrowDown"===e.key&&e.metaKey||"End"===e.key||"PageDown"===e.key)&&this.#M){e.preventDefault();const t=this.#M.at(-1);return void(t&&(this.#j(),t.privateActive=!0,this.ariaActivedescendant=t.id))}}}}#g(e){this.disabled||this.readonly||(this.#x?this.#x=!1:e.target instanceof Node&&this.#h.value?.contains(e.target)&&!this.#V&&this.open?(this.open=!1,this.ariaActivedescendant=""):!this.open&&0!==e.detail&&this.activeOption&&(this.open=!0,this.ariaActivedescendant=this.activeOption.id))}#b(e){e.target instanceof GlideCoreTag||!this.isFilterable?e.target instanceof GlideCoreTag||e.preventDefault():(e.preventDefault(),this.focus())}#O(){if(ow(this.#c.value,ow.object.instanceOf(HTMLInputElement)),this.activeOption){this.open=!0,this.ariaActivedescendant=this.activeOption.id,this.isFiltering=""!==this.#c.value.value.trim();for(const e of this.#l)e.hidden=!e.label?.toLowerCase().includes(this.#c.value?.value.toLowerCase().trim());const e=this.#L?.at(0);e&&this.activeOption?.hidden&&(this.#j(),e.privateActive=!0,this.ariaActivedescendant=e.id),this.isEveryOptionFilteredOut=!this.#L||0===this.#L.length}}#A(e){const t=this.selectedOptions.filter(((e,t)=>t<=this.#w-1)).at(-1);t&&"Backspace"===e.key&&this.multiple&&this.#c.value&&0===this.#c.value.selectionStart&&(t.selected=!1)}#C(e){e.target instanceof GlideCoreDropdownOption&&(this.#j(),e.target.privateActive=!0)}#D(e){this.isFilterable&&e.preventDefault()}#R(e){if(e.target instanceof GlideCoreDropdownOption&&this.#M){this.#j(),e.target.privateActive=!0;for(const e of this.#M)e.privateActive&&(this.ariaActivedescendant=e.id)}}#G(e){if(this.#_.value&&e.target!==this.#_.value&&(this.#F=!0,this.#_.value.selected=this.isAllSelected,this.#_.value.privateIndeterminate=this.isSomeSelected&&!this.isAllSelected),this.isFilterable&&this.#c.value){this.#c.value.value="",this.isFiltering=!1;for(const e of this.#l)e.hidden=!1}e.target instanceof GlideCoreDropdownOption&&(this.multiple?(this.#o=e.target.selected&&e.target.value?[...this.value,e.target.value]:this.value.filter((t=>e.target instanceof GlideCoreDropdownOption&&t!==e.target.value)),this.#s||(this.dispatchEvent(new Event("change",{bubbles:!0})),this.dispatchEvent(new Event("input",{bubbles:!0})))):!this.multiple&&e.target.selected&&(this.#o=e.target.value?[e.target.value]:[],this.open=!1,this.ariaActivedescendant="",this.isFilterable&&this.#c.value&&(this.isFiltering=!1),this.#s||(this.dispatchEvent(new Event("change",{bubbles:!0})),this.dispatchEvent(new Event("input",{bubbles:!0}))))),this.requestUpdate()}#k(e){e.target instanceof GlideCoreDropdownOption&&this.multiple&&e.target.selected&&e.target.value?this.#o=[...this.value.filter((t=>t!==e.detail)),e.target.value]:e.target instanceof GlideCoreDropdownOption&&this.multiple?this.#o=this.value.filter((t=>e.target instanceof GlideCoreDropdownOption&&t!==e.detail)):e.target instanceof GlideCoreDropdownOption&&(this.#o=e.target.value?[e.target.value]:[])}#$(){if(this.#F)return void(this.#F=!1);this.#s=!0;const e=this.isAllSelected;for(const t of this.#l)t.selected=!e;this.#s=!1,this.dispatchEvent(new Event("change",{bubbles:!0})),this.dispatchEvent(new Event("input",{bubbles:!0}))}async#y(e){this.#x=!0;for(const t of this.#l)t.id===e&&(t.selected=!1,this.#o=this.value.filter((e=>e!==t.value)));const t=this.#E.value?.querySelectorAll("glide-core-tag");if(t&&this.value.length>0){const i=[...t].findIndex((t=>t.dataset.id===e));await this.updateComplete,t[i<t.length-1?i+1:i-1]?.focus()}else this.focus()}};__decorate([property({reflect:!0,type:Boolean})],GlideCoreDropdown.prototype,"disabled",void 0),__decorate([property({attribute:"hide-label",reflect:!0,type:Boolean})],GlideCoreDropdown.prototype,"hideLabel",void 0),__decorate([property({reflect:!0})],GlideCoreDropdown.prototype,"label",void 0),__decorate([property({reflect:!0})],GlideCoreDropdown.prototype,"name",void 0),__decorate([property({reflect:!0,type:Boolean})],GlideCoreDropdown.prototype,"open",void 0),__decorate([property({reflect:!0})],GlideCoreDropdown.prototype,"orientation",void 0),__decorate([property({reflect:!0})],GlideCoreDropdown.prototype,"placeholder",void 0),__decorate([property()],GlideCoreDropdown.prototype,"privateSplit",void 0),__decorate([property({type:Boolean})],GlideCoreDropdown.prototype,"readonly",void 0),__decorate([property({attribute:"select-all",reflect:!0,type:Boolean})],GlideCoreDropdown.prototype,"selectAll",void 0),__decorate([property({reflect:!0})],GlideCoreDropdown.prototype,"size",null),__decorate([property({reflect:!0,type:Boolean})],GlideCoreDropdown.prototype,"multiple",null),__decorate([property({reflect:!0,type:Boolean})],GlideCoreDropdown.prototype,"required",void 0),__decorate([property({type:Array})],GlideCoreDropdown.prototype,"value",null),__decorate([property({reflect:!0})],GlideCoreDropdown.prototype,"variant",void 0),__decorate([state()],GlideCoreDropdown.prototype,"ariaActivedescendant",void 0),__decorate([state()],GlideCoreDropdown.prototype,"isBlurring",void 0),__decorate([state()],GlideCoreDropdown.prototype,"isCheckingValidity",void 0),__decorate([state()],GlideCoreDropdown.prototype,"isEveryOptionFilteredOut",void 0),__decorate([state()],GlideCoreDropdown.prototype,"isFilterable",void 0),__decorate([state()],GlideCoreDropdown.prototype,"isFiltering",void 0),__decorate([state()],GlideCoreDropdown.prototype,"isReportValidityOrSubmit",void 0),GlideCoreDropdown=GlideCoreDropdown_1=__decorate([customElement("glide-core-dropdown")],GlideCoreDropdown);export default GlideCoreDropdown;
@@ -114,6 +114,10 @@ import{css}from"lit";import focusOutline from"./styles/focus-outline.js";import
114
114
  }
115
115
  }
116
116
 
117
+ .placeholder {
118
+ color: var(--glide-core-text-placeholder);
119
+ }
120
+
117
121
  .tags {
118
122
  display: flex;
119
123
  gap: var(--glide-core-spacing-xs);
@@ -1,5 +1,5 @@
1
1
  import * as sinon from 'sinon';
2
- import { aTimeout, expect, fixture, html } from '@open-wc/testing';
2
+ import { aTimeout, expect, fixture, html, oneEvent } from '@open-wc/testing';
3
3
  import GlideCoreDropdown from './dropdown.js';
4
4
  import GlideCoreDropdownOption from './dropdown.option.js';
5
5
  GlideCoreDropdown.shadowRootOptions.mode = 'open';
@@ -93,6 +93,39 @@ it('dispatches one "change" event when `value` is changed programmatically', asy
93
93
  await aTimeout(0);
94
94
  expect(spy.calledOnce).to.be.true;
95
95
  });
96
+ it('continues to dispatch "change" events upon selection after `value` is changed programmatically', async () => {
97
+ const component = await fixture(html `<glide-core-dropdown
98
+ label="Label"
99
+ placeholder="Placeholder"
100
+ open
101
+ multiple
102
+ >
103
+ <glide-core-dropdown-option
104
+ label="One"
105
+ value="one"
106
+ ></glide-core-dropdown-option>
107
+
108
+ <glide-core-dropdown-option
109
+ label="Two"
110
+ value="two"
111
+ selected
112
+ ></glide-core-dropdown-option>
113
+
114
+ <glide-core-dropdown-option
115
+ label="Three"
116
+ value="three"
117
+ selected
118
+ ></glide-core-dropdown-option>
119
+ </glide-core-dropdown>`);
120
+ component.value = ['one', 'two'];
121
+ setTimeout(() => {
122
+ component
123
+ .querySelector('glide-core-dropdown-option:last-of-type')
124
+ ?.click();
125
+ });
126
+ const event = await oneEvent(component, 'change');
127
+ expect(event instanceof Event).to.be.true;
128
+ });
96
129
  it('dispatches one "input" event when `value` is changed programmatically', async () => {
97
130
  const component = await fixture(html `<glide-core-dropdown
98
131
  label="Label"
@@ -124,6 +157,39 @@ it('dispatches one "input" event when `value` is changed programmatically', asyn
124
157
  await aTimeout(0);
125
158
  expect(spy.calledOnce).to.be.true;
126
159
  });
160
+ it('continues to dispatch "input" events upon selection after `value` is changed programmatically', async () => {
161
+ const component = await fixture(html `<glide-core-dropdown
162
+ label="Label"
163
+ placeholder="Placeholder"
164
+ open
165
+ multiple
166
+ >
167
+ <glide-core-dropdown-option
168
+ label="One"
169
+ value="one"
170
+ ></glide-core-dropdown-option>
171
+
172
+ <glide-core-dropdown-option
173
+ label="Two"
174
+ value="two"
175
+ selected
176
+ ></glide-core-dropdown-option>
177
+
178
+ <glide-core-dropdown-option
179
+ label="Three"
180
+ value="three"
181
+ selected
182
+ ></glide-core-dropdown-option>
183
+ </glide-core-dropdown>`);
184
+ component.value = ['one', 'two'];
185
+ setTimeout(() => {
186
+ component
187
+ .querySelector('glide-core-dropdown-option:last-of-type')
188
+ ?.click();
189
+ });
190
+ const event = await oneEvent(component, 'input');
191
+ expect(event instanceof Event).to.be.true;
192
+ });
127
193
  it('dispatches a "change" event when an option is selected after Select All is clicked', async () => {
128
194
  const component = await fixture(html `<glide-core-dropdown
129
195
  label="Label"
@@ -1,6 +1,6 @@
1
1
  import './dropdown.option.js';
2
2
  import * as sinon from 'sinon';
3
- import { aTimeout, expect, fixture, html } from '@open-wc/testing';
3
+ import { aTimeout, expect, fixture, html, oneEvent } from '@open-wc/testing';
4
4
  import GlideCoreDropdown from './dropdown.js';
5
5
  GlideCoreDropdown.shadowRootOptions.mode = 'open';
6
6
  it('dispatches one "change" event when `value` is changed programmatically', async () => {
@@ -24,6 +24,26 @@ it('dispatches one "change" event when `value` is changed programmatically', asy
24
24
  await aTimeout(0);
25
25
  expect(spy.calledOnce).to.be.true;
26
26
  });
27
+ it('continues to dispatch "change" events upon selection after `value` is changed programmatically', async () => {
28
+ const component = await fixture(html `<glide-core-dropdown label="Label" placeholder="Placeholder" open>
29
+ <glide-core-dropdown-option
30
+ label="One"
31
+ value="one"
32
+ ></glide-core-dropdown-option>
33
+
34
+ <glide-core-dropdown-option
35
+ label="Two"
36
+ value="two"
37
+ selected
38
+ ></glide-core-dropdown-option>
39
+ </glide-core-dropdown>`);
40
+ component.value = ['two'];
41
+ setTimeout(() => {
42
+ component.querySelector('glide-core-dropdown-option')?.click();
43
+ });
44
+ const event = await oneEvent(component, 'change');
45
+ expect(event instanceof Event).to.be.true;
46
+ });
27
47
  it('dispatches one "input" event when `value` is changed programmatically', async () => {
28
48
  const component = await fixture(html `<glide-core-dropdown label="Label" placeholder="Placeholder" open>
29
49
  <glide-core-dropdown-option
@@ -45,3 +65,23 @@ it('dispatches one "input" event when `value` is changed programmatically', asyn
45
65
  await aTimeout(0);
46
66
  expect(spy.calledOnce).to.be.true;
47
67
  });
68
+ it('continues to dispatch "input" events upon selection after `value` is changed programmatically', async () => {
69
+ const component = await fixture(html `<glide-core-dropdown label="Label" placeholder="Placeholder" open>
70
+ <glide-core-dropdown-option
71
+ label="One"
72
+ value="one"
73
+ ></glide-core-dropdown-option>
74
+
75
+ <glide-core-dropdown-option
76
+ label="Two"
77
+ value="two"
78
+ selected
79
+ ></glide-core-dropdown-option>
80
+ </glide-core-dropdown>`);
81
+ component.value = ['two'];
82
+ setTimeout(() => {
83
+ component.querySelector('glide-core-dropdown-option')?.click();
84
+ });
85
+ const event = await oneEvent(component, 'input');
86
+ expect(event instanceof Event).to.be.true;
87
+ });
@@ -5,9 +5,14 @@ import GlideCoreDropdown from './dropdown.js';
5
5
  import GlideCoreDropdownOption from './dropdown.option.js';
6
6
  GlideCoreDropdown.shadowRootOptions.mode = 'open';
7
7
  GlideCoreDropdownOption.shadowRootOptions.mode = 'open';
8
- it('closes when it loses focus', async () => {
8
+ it('closes and reports validity when it loses focus', async () => {
9
9
  const div = document.createElement('div');
10
- const component = await fixture(html `<glide-core-dropdown label="Label" placeholder="Placeholder" open>
10
+ const component = await fixture(html `<glide-core-dropdown
11
+ label="Label"
12
+ placeholder="Placeholder"
13
+ open
14
+ required
15
+ >
11
16
  <glide-core-dropdown-option
12
17
  label="Label"
13
18
  value="value"
@@ -25,4 +30,7 @@ it('closes when it loses focus', async () => {
25
30
  await sendKeys({ down: 'Shift' });
26
31
  await sendKeys({ press: 'Tab' });
27
32
  expect(component.open).to.be.false;
33
+ expect(component.shadowRoot?.activeElement).to.equal(null);
34
+ expect(component.validity.valid).to.equal(false);
35
+ expect(component.shadowRoot?.querySelector('glide-core-label')?.error).to.equal(true);
28
36
  });
package/dist/input.d.ts CHANGED
@@ -61,7 +61,8 @@ export default class GlideCoreInput extends LitElement {
61
61
  get valueCharacterCount(): number;
62
62
  constructor();
63
63
  private hasFocus;
64
- private isCheckingValidity?;
64
+ private isBlurring;
65
+ private isCheckingValidity;
65
66
  private isReportValidityOrSubmit;
66
67
  private passwordVisible;
67
68
  }
package/dist/input.js CHANGED
@@ -1 +1 @@
1
- var __decorate=this&&this.__decorate||function(e,t,i,o){var r,s=arguments.length,a=s<3?t:null===o?o=Object.getOwnPropertyDescriptor(t,i):o;if("object"==typeof Reflect&&"function"==typeof Reflect.decorate)a=Reflect.decorate(e,t,i,o);else for(var l=e.length-1;l>=0;l--)(r=e[l])&&(a=(s<3?r(a):s>3?r(t,i,a):r(t,i))||a);return s>3&&a&&Object.defineProperty(t,i,a),a};import"./icon-button.js";import"./label.js";import{LitElement,html,nothing}from"lit";import{LocalizeController}from"./library/localize.js";import{classMap}from"lit/directives/class-map.js";import{createRef,ref}from"lit/directives/ref.js";import{customElement,property,queryAssignedNodes,state}from"lit/decorators.js";import{ifDefined}from"lit/directives/if-defined.js";import magnifyingGlassIcon from"./icons/magnifying-glass.js";import ow from"./library/ow.js";import styles from"./input.styles.js";export const SUPPORTED_TYPES=["email","number","password","search","tel","text","url"];let GlideCoreInput=class GlideCoreInput extends LitElement{static{this.formAssociated=!0}static{this.shadowRootOptions={...LitElement.shadowRootOptions,mode:"closed",delegatesFocus:!0}}static{this.styles=styles}get form(){return this.#e.form}get validity(){return this.#e.validity}get willValidate(){return this.#e.willValidate}blur(){this.#t?.blur()}checkValidity(){return this.isCheckingValidity=!0,this.#e.checkValidity()}disconnectedCallback(){super.disconnectedCallback(),this.form?.removeEventListener("formdata",this.#i)}firstUpdated(){this.#o()}formAssociatedCallback(){this.form?.addEventListener("formdata",this.#i)}formResetCallback(){this.value=this.getAttribute("value")??""}get isTypeSearch(){return"search"===this.type}get hasClearIcon(){return this.clearable&&!this.disabled&&!this.readonly}get isClearIconVisible(){return this.hasClearIcon&&this.value.length>0}render(){return html`<glide-core-label class="${classMap({left:"left"===this.privateSplit,middle:"middle"===this.privateSplit})}" orientation="${this.orientation}" split="${ifDefined(this.privateSplit??void 0)}" ?disabled="${this.disabled}" ?error="${this.#r||this.#s}" ?hide="${this.hideLabel}" ?required="${this.required}"><slot name="tooltip" slot="tooltip"></slot><label for="input">${this.label}</label><div class="${classMap({"input-box":!0,focused:this.hasFocus,empty:""===this.value,disabled:this.disabled,readonly:this.readonly&&!this.disabled,error:this.#r||this.#s})}" slot="control"><slot name="prefix"></slot><input aria-describedby="meta" id="input" type="${"password"===this.type&&this.passwordVisible?"text":this.type}" .value="${this.value}" placeholder="${ifDefined(this.placeholder)}" autocapitalize="${ifDefined(this.autocapitalize)}" spellcheck="${this.spellcheck}" ?required="${this.required}" ?readonly="${this.readonly}" ?disabled="${this.disabled}" @focus="${this.#a}" @blur="${this.#l}" @change="${this.#n}" @input="${this.#d}" ${ref(this.#p)}> ${this.hasClearIcon?html`<glide-core-icon-button variant="tertiary" class="${classMap({"clear-icon-button":!0,"clear-icon-button--visible":this.isClearIconVisible})}" aria-label="${this.#h.term("clearEntry")}" @click="${this.#c}" tabindex="-1"><slot name="clear-icon"><svg width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor"><path d="M6 6L18 18" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"/><path d="M18 6L6 18" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"/></svg></slot></glide-core-icon-button>`:""} ${"password"===this.type&&this.passwordToggle&&!this.disabled?html`<glide-core-icon-button variant="tertiary" class="password-toggle" aria-label="${this.passwordVisible?"Hide password":"Show password"}" aria-controls="input" aria-expanded="${this.passwordVisible?"true":"false"}" @click="${this.#u}" tabindex="-1">${this.passwordVisible?html`<svg width="16" height="16" fill="none" viewBox="0 0 24 24" stroke-width="1.5" stroke="currentColor"><path stroke-linecap="round" stroke-linejoin="round" d="M3.98 8.223A10.477 10.477 0 0 0 1.934 12C3.226 16.338 7.244 19.5 12 19.5c.993 0 1.953-.138 2.863-.395M6.228 6.228A10.451 10.451 0 0 1 12 4.5c4.756 0 8.773 3.162 10.065 7.498a10.522 10.522 0 0 1-4.293 5.774M6.228 6.228 3 3m3.228 3.228 3.65 3.65m7.894 7.894L21 21m-3.228-3.228-3.65-3.65m0 0a3 3 0 1 0-4.243-4.243m4.242 4.242L9.88 9.88"/></svg>`:html`<svg width="16" height="16" fill="none" viewBox="0 0 24 24" stroke-width="1.5" stroke="currentColor"><path stroke-linecap="round" stroke-linejoin="round" d="M2.036 12.322a1.012 1.012 0 0 1 0-.639C3.423 7.51 7.36 4.5 12 4.5c4.638 0 8.573 3.007 9.963 7.178.07.207.07.431 0 .639C20.577 16.49 16.64 19.5 12 19.5c-4.638 0-8.573-3.007-9.963-7.178Z"/><path stroke-linecap="round" stroke-linejoin="round" d="M15 12a3 3 0 1 1-6 0 3 3 0 0 1 6 0Z"/></svg>`}</glide-core-icon-button>`:""}<div class="suffix">${this.isTypeSearch?magnifyingGlassIcon:html`<slot name="suffix"></slot>`}</div></div><div class="meta" id="meta" slot="description"><slot class="description" name="description"></slot>${this.maxlength?html`<div class="${classMap({"character-count":!0,error:this.#s})}">${this.valueCharacterCount}/${this.maxlength}</div>`:nothing}</div></glide-core-label>`}reportValidity(){return this.#e.reportValidity()}get valueCharacterCount(){return this.value.length}constructor(){super(),this.type="text",this.value="",this.hideLabel=!1,this.orientation="horizontal",this.clearable=!1,this.spellcheck=!1,this.autocapitalize="on",this.passwordToggle=!1,this.required=!1,this.readonly=!1,this.disabled=!1,this.hasFocus=!1,this.isReportValidityOrSubmit=!1,this.passwordVisible=!1,this.#p=createRef(),this.#h=new LocalizeController(this),this.#i=({formData:e})=>{this.name&&this.value&&!this.disabled&&e.append(this.name,this.value)},this.#e=this.attachInternals(),this.addEventListener("invalid",(e=>{e?.preventDefault(),this.isCheckingValidity||(this.isReportValidityOrSubmit=!0,this.focus())}))}#p;#e;#h;#i;get#s(){return Boolean(this.maxlength&&this.valueCharacterCount>this.maxlength)}get#r(){return!this.disabled&&!this.validity?.valid&&this.isReportValidityOrSubmit}get#t(){return this.#p.value}#l(){this.hasFocus=!1}#n(e){ow(this.#t,ow.object.instanceOf(HTMLInputElement)),this.value=this.#t.value,this.#o(),this.dispatchEvent(new Event(e.type,e))}#c(e){this.value="",this.dispatchEvent(new Event("clear",{bubbles:!0})),this.#t?.focus(),this.#o(),e.stopPropagation()}#a(){this.hasFocus=!0}#d(){ow(this.#t,ow.object.instanceOf(HTMLInputElement)),this.value=this.#t.value,this.#o()}#u(){this.passwordVisible=!this.passwordVisible}async#o(){await this.updateComplete,this.#e.setValidity(this.#t?.validity,this.#t?.validationMessage,this.#t)}};__decorate([property()],GlideCoreInput.prototype,"type",void 0),__decorate([property({reflect:!0})],GlideCoreInput.prototype,"name",void 0),__decorate([property()],GlideCoreInput.prototype,"value",void 0),__decorate([property()],GlideCoreInput.prototype,"label",void 0),__decorate([property({attribute:"hide-label",type:Boolean})],GlideCoreInput.prototype,"hideLabel",void 0),__decorate([property({reflect:!0})],GlideCoreInput.prototype,"orientation",void 0),__decorate([property()],GlideCoreInput.prototype,"placeholder",void 0),__decorate([property({type:Boolean})],GlideCoreInput.prototype,"clearable",void 0),__decorate([property({type:Boolean})],GlideCoreInput.prototype,"spellcheck",void 0),__decorate([property()],GlideCoreInput.prototype,"autocapitalize",void 0),__decorate([property({attribute:"password-toggle",type:Boolean})],GlideCoreInput.prototype,"passwordToggle",void 0),__decorate([property({reflect:!0,type:Boolean})],GlideCoreInput.prototype,"required",void 0),__decorate([property({type:Boolean})],GlideCoreInput.prototype,"readonly",void 0),__decorate([property({type:Boolean})],GlideCoreInput.prototype,"disabled",void 0),__decorate([property()],GlideCoreInput.prototype,"privateSplit",void 0),__decorate([property({type:Number,converter:e=>e&&Number.parseInt(e,10)})],GlideCoreInput.prototype,"maxlength",void 0),__decorate([queryAssignedNodes({slot:"description"})],GlideCoreInput.prototype,"descriptionNodes",void 0),__decorate([queryAssignedNodes({slot:"prefix"})],GlideCoreInput.prototype,"prefixIconNodes",void 0),__decorate([queryAssignedNodes({slot:"suffix"})],GlideCoreInput.prototype,"suffixIconNodes",void 0),__decorate([state()],GlideCoreInput.prototype,"hasFocus",void 0),__decorate([state()],GlideCoreInput.prototype,"isCheckingValidity",void 0),__decorate([state()],GlideCoreInput.prototype,"isReportValidityOrSubmit",void 0),__decorate([state()],GlideCoreInput.prototype,"passwordVisible",void 0),GlideCoreInput=__decorate([customElement("glide-core-input")],GlideCoreInput);export default GlideCoreInput;
1
+ var __decorate=this&&this.__decorate||function(t,e,i,o){var r,s=arguments.length,a=s<3?e:null===o?o=Object.getOwnPropertyDescriptor(e,i):o;if("object"==typeof Reflect&&"function"==typeof Reflect.decorate)a=Reflect.decorate(t,e,i,o);else for(var l=t.length-1;l>=0;l--)(r=t[l])&&(a=(s<3?r(a):s>3?r(e,i,a):r(e,i))||a);return s>3&&a&&Object.defineProperty(e,i,a),a};import"./icon-button.js";import"./label.js";import{LitElement,html,nothing}from"lit";import{LocalizeController}from"./library/localize.js";import{classMap}from"lit/directives/class-map.js";import{createRef,ref}from"lit/directives/ref.js";import{customElement,property,queryAssignedNodes,state}from"lit/decorators.js";import{ifDefined}from"lit/directives/if-defined.js";import magnifyingGlassIcon from"./icons/magnifying-glass.js";import ow from"./library/ow.js";import styles from"./input.styles.js";export const SUPPORTED_TYPES=["email","number","password","search","tel","text","url"];let GlideCoreInput=class GlideCoreInput extends LitElement{static{this.formAssociated=!0}static{this.shadowRootOptions={...LitElement.shadowRootOptions,mode:"closed",delegatesFocus:!0}}static{this.styles=styles}get form(){return this.#t.form}get validity(){return this.#t.validity}get willValidate(){return this.#t.willValidate}blur(){this.#e?.blur()}checkValidity(){this.isCheckingValidity=!0;const t=this.#t.checkValidity();return this.isCheckingValidity=!1,t}disconnectedCallback(){super.disconnectedCallback(),this.form?.removeEventListener("formdata",this.#i)}firstUpdated(){this.#o()}formAssociatedCallback(){this.form?.addEventListener("formdata",this.#i)}formResetCallback(){this.value=this.getAttribute("value")??""}get isTypeSearch(){return"search"===this.type}get hasClearIcon(){return this.clearable&&!this.disabled&&!this.readonly}get isClearIconVisible(){return this.hasClearIcon&&this.value.length>0}render(){return html`<glide-core-label class="${classMap({left:"left"===this.privateSplit,middle:"middle"===this.privateSplit})}" orientation="${this.orientation}" split="${ifDefined(this.privateSplit??void 0)}" ?disabled="${this.disabled}" ?error="${this.#r||this.#s}" ?hide="${this.hideLabel}" ?required="${this.required}"><slot name="tooltip" slot="tooltip"></slot><label for="input">${this.label}</label><div class="${classMap({"input-box":!0,focused:this.hasFocus,empty:""===this.value,disabled:this.disabled,readonly:this.readonly&&!this.disabled,error:this.#r||this.#s})}" slot="control"><slot name="prefix"></slot><input aria-describedby="meta" id="input" type="${"password"===this.type&&this.passwordVisible?"text":this.type}" .value="${this.value}" placeholder="${ifDefined(this.placeholder)}" autocapitalize="${ifDefined(this.autocapitalize)}" spellcheck="${this.spellcheck}" ?required="${this.required}" ?readonly="${this.readonly}" ?disabled="${this.disabled}" @focus="${this.#a}" @blur="${this.#l}" @change="${this.#n}" @input="${this.#d}" ${ref(this.#p)}> ${this.hasClearIcon?html`<glide-core-icon-button variant="tertiary" class="${classMap({"clear-icon-button":!0,"clear-icon-button--visible":this.isClearIconVisible})}" aria-label="${this.#h.term("clearEntry")}" @click="${this.#c}" tabindex="-1"><slot name="clear-icon"><svg width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor"><path d="M6 6L18 18" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"/><path d="M18 6L6 18" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"/></svg></slot></glide-core-icon-button>`:""} ${"password"===this.type&&this.passwordToggle&&!this.disabled?html`<glide-core-icon-button variant="tertiary" class="password-toggle" aria-label="${this.passwordVisible?"Hide password":"Show password"}" aria-controls="input" aria-expanded="${this.passwordVisible?"true":"false"}" @click="${this.#u}" tabindex="-1">${this.passwordVisible?html`<svg width="16" height="16" fill="none" viewBox="0 0 24 24" stroke-width="1.5" stroke="currentColor"><path stroke-linecap="round" stroke-linejoin="round" d="M3.98 8.223A10.477 10.477 0 0 0 1.934 12C3.226 16.338 7.244 19.5 12 19.5c.993 0 1.953-.138 2.863-.395M6.228 6.228A10.451 10.451 0 0 1 12 4.5c4.756 0 8.773 3.162 10.065 7.498a10.522 10.522 0 0 1-4.293 5.774M6.228 6.228 3 3m3.228 3.228 3.65 3.65m7.894 7.894L21 21m-3.228-3.228-3.65-3.65m0 0a3 3 0 1 0-4.243-4.243m4.242 4.242L9.88 9.88"/></svg>`:html`<svg width="16" height="16" fill="none" viewBox="0 0 24 24" stroke-width="1.5" stroke="currentColor"><path stroke-linecap="round" stroke-linejoin="round" d="M2.036 12.322a1.012 1.012 0 0 1 0-.639C3.423 7.51 7.36 4.5 12 4.5c4.638 0 8.573 3.007 9.963 7.178.07.207.07.431 0 .639C20.577 16.49 16.64 19.5 12 19.5c-4.638 0-8.573-3.007-9.963-7.178Z"/><path stroke-linecap="round" stroke-linejoin="round" d="M15 12a3 3 0 1 1-6 0 3 3 0 0 1 6 0Z"/></svg>`}</glide-core-icon-button>`:""}<div class="suffix">${this.isTypeSearch?magnifyingGlassIcon:html`<slot name="suffix"></slot>`}</div></div><div class="meta" id="meta" slot="description"><slot class="description" name="description"></slot>${this.maxlength?html`<div class="${classMap({"character-count":!0,error:this.#s})}">${this.valueCharacterCount}/${this.maxlength}</div>`:nothing}</div></glide-core-label>`}reportValidity(){this.isReportValidityOrSubmit=!0;const t=this.#t.reportValidity();return this.requestUpdate(),t}get valueCharacterCount(){return this.value.length}constructor(){super(),this.type="text",this.value="",this.hideLabel=!1,this.orientation="horizontal",this.clearable=!1,this.spellcheck=!1,this.autocapitalize="on",this.passwordToggle=!1,this.required=!1,this.readonly=!1,this.disabled=!1,this.hasFocus=!1,this.isBlurring=!1,this.isCheckingValidity=!1,this.isReportValidityOrSubmit=!1,this.passwordVisible=!1,this.#p=createRef(),this.#h=new LocalizeController(this),this.#i=({formData:t})=>{this.name&&this.value&&!this.disabled&&t.append(this.name,this.value)},this.#t=this.attachInternals(),this.addEventListener("invalid",(t=>{if(t?.preventDefault(),this.isCheckingValidity||this.isBlurring)return;this.isReportValidityOrSubmit=!0;this.form?.querySelector(":invalid")===this&&this.focus()}))}#p;#t;#h;#i;get#s(){return Boolean(this.maxlength&&this.valueCharacterCount>this.maxlength)}get#r(){return!this.disabled&&!this.validity?.valid&&this.isReportValidityOrSubmit}get#e(){return this.#p.value}#l(){this.isBlurring=!0,this.reportValidity(),this.isBlurring=!1,this.hasFocus=!1}#n(t){ow(this.#e,ow.object.instanceOf(HTMLInputElement)),this.value=this.#e.value,this.#o(),this.dispatchEvent(new Event(t.type,t))}#c(t){this.value="",this.dispatchEvent(new Event("clear",{bubbles:!0})),this.#e?.focus(),this.#o(),t.stopPropagation()}#a(){this.hasFocus=!0}#d(){ow(this.#e,ow.object.instanceOf(HTMLInputElement)),this.value=this.#e.value,this.#o()}#u(){this.passwordVisible=!this.passwordVisible}async#o(){await this.updateComplete,this.#t.setValidity(this.#e?.validity,this.#e?.validationMessage,this.#e),this.isReportValidityOrSubmit&&this.reportValidity()}};__decorate([property()],GlideCoreInput.prototype,"type",void 0),__decorate([property({reflect:!0})],GlideCoreInput.prototype,"name",void 0),__decorate([property()],GlideCoreInput.prototype,"value",void 0),__decorate([property()],GlideCoreInput.prototype,"label",void 0),__decorate([property({attribute:"hide-label",type:Boolean})],GlideCoreInput.prototype,"hideLabel",void 0),__decorate([property({reflect:!0})],GlideCoreInput.prototype,"orientation",void 0),__decorate([property()],GlideCoreInput.prototype,"placeholder",void 0),__decorate([property({type:Boolean})],GlideCoreInput.prototype,"clearable",void 0),__decorate([property({type:Boolean})],GlideCoreInput.prototype,"spellcheck",void 0),__decorate([property()],GlideCoreInput.prototype,"autocapitalize",void 0),__decorate([property({attribute:"password-toggle",type:Boolean})],GlideCoreInput.prototype,"passwordToggle",void 0),__decorate([property({reflect:!0,type:Boolean})],GlideCoreInput.prototype,"required",void 0),__decorate([property({type:Boolean})],GlideCoreInput.prototype,"readonly",void 0),__decorate([property({type:Boolean})],GlideCoreInput.prototype,"disabled",void 0),__decorate([property()],GlideCoreInput.prototype,"privateSplit",void 0),__decorate([property({type:Number,converter:t=>t&&Number.parseInt(t,10)})],GlideCoreInput.prototype,"maxlength",void 0),__decorate([queryAssignedNodes({slot:"description"})],GlideCoreInput.prototype,"descriptionNodes",void 0),__decorate([queryAssignedNodes({slot:"prefix"})],GlideCoreInput.prototype,"prefixIconNodes",void 0),__decorate([queryAssignedNodes({slot:"suffix"})],GlideCoreInput.prototype,"suffixIconNodes",void 0),__decorate([state()],GlideCoreInput.prototype,"hasFocus",void 0),__decorate([state()],GlideCoreInput.prototype,"isBlurring",void 0),__decorate([state()],GlideCoreInput.prototype,"isCheckingValidity",void 0),__decorate([state()],GlideCoreInput.prototype,"isReportValidityOrSubmit",void 0),__decorate([state()],GlideCoreInput.prototype,"passwordVisible",void 0),GlideCoreInput=__decorate([customElement("glide-core-input")],GlideCoreInput);export default GlideCoreInput;
@@ -17,7 +17,7 @@ it('focuses the input after submit when required and no value', async () => {
17
17
  const inputElement = input.shadowRoot?.querySelector('input');
18
18
  expect(input.shadowRoot?.activeElement).to.be.equal(inputElement);
19
19
  });
20
- it('blurs the input if `blur` is called', async () => {
20
+ it('blurs the input and reports validity if `blur` is called', async () => {
21
21
  const input = await fixture(html `<glide-core-input required></glide-core-input>`);
22
22
  input.focus();
23
23
  const inputElement = input.shadowRoot?.querySelector('input');
@@ -25,6 +25,8 @@ it('blurs the input if `blur` is called', async () => {
25
25
  input.blur();
26
26
  await input.updateComplete;
27
27
  expect(input.shadowRoot?.activeElement).to.equal(null);
28
+ expect(input.validity.valid).to.equal(false);
29
+ expect(input.shadowRoot?.querySelector('glide-core-label')?.error).to.equal(true);
28
30
  });
29
31
  it('focuses the input after `reportValidity` is called when required and no value', async () => {
30
32
  const form = document.createElement('form');
@@ -42,7 +44,7 @@ it('focuses the input after `requestSubmit` is called when required and no value
42
44
  });
43
45
  form.requestSubmit();
44
46
  const inputElement = input.shadowRoot?.querySelector('input');
45
- expect(input.shadowRoot?.activeElement).to.equal(inputElement);
47
+ expect(input.shadowRoot?.activeElement === inputElement).to.be.true;
46
48
  });
47
49
  it('does not focus the input after `checkValidity` is called', async () => {
48
50
  const form = document.createElement('form');
@@ -50,5 +52,5 @@ it('does not focus the input after `checkValidity` is called', async () => {
50
52
  parentNode: form,
51
53
  });
52
54
  input.checkValidity();
53
- expect(input.shadowRoot?.activeElement).to.equal(null);
55
+ expect(input.shadowRoot?.activeElement === null).to.be.true;
54
56
  });
@@ -44,6 +44,7 @@ export default class GlideCoreRadioGroup extends LitElement {
44
44
  updated(changedProperties: PropertyValueMap<GlideCoreRadioGroup>): void;
45
45
  willUpdate(changedProperties: PropertyValueMap<GlideCoreRadioGroup>): void;
46
46
  constructor();
47
+ private isBlurring;
47
48
  private isCheckingValidity;
48
49
  private isReportValidityOrSubmit;
49
50
  }
@@ -1 +1 @@
1
- var __decorate=this&&this.__decorate||function(e,i,t,o){var s,d=arguments.length,a=d<3?i:null===o?o=Object.getOwnPropertyDescriptor(i,t):o;if("object"==typeof Reflect&&"function"==typeof Reflect.decorate)a=Reflect.decorate(e,i,t,o);else for(var r=e.length-1;r>=0;r--)(s=e[r])&&(a=(d<3?s(a):d>3?s(i,t,a):s(i,t))||a);return d>3&&a&&Object.defineProperty(i,t,a),a};import"./label.js";import"./tooltip.js";import{LitElement,html}from"lit";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{owSlot,owSlotType}from"./library/ow.js";import GlideCoreRadio from"./radio.js";import styles from"./radio-group.styles.js";let GlideCoreRadioGroup=class GlideCoreRadioGroup extends LitElement{static{this.formAssociated=!0}static{this.shadowRootOptions={...LitElement.shadowRootOptions,mode:"closed"}}static{this.styles=styles}checkValidity(){return this.isCheckingValidity=!0,this.#e.checkValidity()}disconnectedCallback(){super.disconnectedCallback(),this.form?.removeEventListener("formdata",this.#i),this.#t=void 0}firstUpdated(){owSlot(this.#o.value),owSlotType(this.#o.value,[GlideCoreRadio]),this.#t=this.#s.find((e=>e.checked)),this.#d()}focus(e){let i=this.#s.find((e=>e.checked));i||(i=this.#s.find((e=>0===e.tabIndex))),i?.focus(e)}get form(){return this.#e.form}get validity(){return this.#e.validity}get willValidate(){return this.#e.willValidate}formAssociatedCallback(){this.form?.addEventListener("formdata",this.#i)}formResetCallback(){if(this.#t&&this.contains(this.#t))for(const e of this.#s)this.#a(e===this.#t,e)}render(){return html`<div class="component" @click="${this.#r}" @keydown="${this.#l}" ${ref(this.#n)}><glide-core-label orientation="horizontal" split="${ifDefined(this.privateSplit??void 0)}" ?disabled="${this.disabled}" ?error="${this.#h}" ?hide="${this.hideLabel}" ?required="${this.required}"><label id="label" data-test="label">${this.label}</label><div class="${classMap({"radio-container":!0,vertical:!0,invalid:this.#h})}" role="radiogroup" slot="control" aria-labelledby="label description"><slot ${ref(this.#o)} @slotchange="${this.#c}"></slot></div><slot name="tooltip" slot="tooltip"></slot><slot id="description" name="description" slot="description"></slot></glide-core-label></div>`}reportValidity(){return this.#e.reportValidity()}updated(e){this.hasUpdated&&(e.has("value")||e.has("required"))&&(this.#p(),this.#f(!this.#e.validity.valid),this.requestUpdate())}willUpdate(e){if(this.hasUpdated){if(e.has("required")&&this.#u(),e.has("disabled")){for(const e of this.#s)this.#R(this.disabled,e);!this.disabled&&this.#m()}if(e.has("value"))for(const e of this.#s)e.checked=e.value===this.value}}constructor(){super(),this.description="",this.disabled=!1,this.label="",this.hideLabel=!1,this.name="",this.required=!1,this.value="",this.isCheckingValidity=!1,this.isReportValidityOrSubmit=!1,this.#n=createRef(),this.#o=createRef(),this.#t=void 0,this.#i=({formData:e})=>{this.name&&this.value.length>0&&!this.disabled&&e.append(this.name,this.value)},this.#e=this.attachInternals(),this.addEventListener("invalid",this.#b)}#n;#o;#t;#e;#v;#i;#d(){const e=this.#s.find((e=>e.checked));this.value=e?.value??this.#t?.value??"",this.#v=e??this.#t,this.required&&this.#u();for(const e of this.#s)this.disabled?this.#R(this.disabled,e):this.#R(e.disabled,e);!this.disabled&&this.#m()}get#h(){const e=!this.disabled&&!this.validity.valid&&this.isReportValidityOrSubmit;return this.#f(e),e}#r(e){if(this.disabled)return;if(e.target instanceof GlideCoreRadio&&e.target.disabled&&this.#v&&!this.#v.disabled)return void this.#v?.focus();const i=e.target;if(i instanceof GlideCoreRadio&&i&&!i.disabled){this.#a(!0,i);for(const e of this.#s)e!==i&&this.#a(!1,e)}}#c(){owSlot(this.#o.value),owSlotType(this.#o.value,[GlideCoreRadio]),this.#d()}#b(e){e.preventDefault(),this.isCheckingValidity||(this.isReportValidityOrSubmit=!0,this.focus())}#l(e){if(!(this.disabled||e.target instanceof GlideCoreRadio&&e.target?.disabled)&&e.target instanceof GlideCoreRadio){const i=e.target;switch(e.key){case"ArrowUp":case"ArrowLeft":{e.preventDefault();let t=i.previousElementSibling;for(;(!t||t instanceof GlideCoreRadio&&t.disabled||!(t instanceof GlideCoreRadio))&&t!==i;)if(null===t){const e=this.#s.at(-1);e&&(t=e)}else t=t.previousElementSibling;t&&t instanceof GlideCoreRadio&&!t.disabled&&t!==i&&(this.#a(!1,i),this.#a(!0,t));break}case"ArrowDown":case"ArrowRight":{e.preventDefault();let t=i.nextElementSibling;for(;(!t||t instanceof GlideCoreRadio&&t.disabled||!(t instanceof GlideCoreRadio))&&t!==i;)if(null===t){const e=this.#s.at(0);e&&(t=e)}else t=t.nextElementSibling;t&&t instanceof GlideCoreRadio&&!t.disabled&&t!==i&&(this.#a(!1,i),this.#a(!0,t));break}case" ":if(e.preventDefault(),!i.disabled&&!i.checked){this.#a(!0,i);for(const e of this.#s)e!==i&&this.#a(!1,e)}}}}#p(){const e=this.#s.find((e=>e.checked));this.required&&!e?this.#e.setValidity({valueMissing:!0}," ",this.#n.value):this.#e.setValidity({})}get#s(){return this.#o.value?.assignedElements().filter((e=>e instanceof GlideCoreRadio))??[]}#a(e,i){i.checked=e,i.tabIndex=e?0:-1,e&&(this.#v=i,this.value=i.value,i.focus(),i.dispatchEvent(new Event("change",{bubbles:!0})),i.dispatchEvent(new Event("input",{bubbles:!0})))}#R(e,i){i.disabled=e,e&&(i.tabIndex=-1)}#f(e){for(const i of this.#s)i.invalid=e}#m(){if(this.disabled||this.#s.every((e=>e.disabled)))return;let e=null;const i=this.#s.find((e=>!e.disabled&&e.checked));if(i)e=i;else{const i=this.#s.find((e=>!e.disabled));i&&(e=i)}if(e)for(const i of this.#s)i.tabIndex=i===e?0:-1}#u(){for(const e of this.#s)e.required=this.required}};__decorate([property()],GlideCoreRadioGroup.prototype,"description",void 0),__decorate([property({type:Boolean,reflect:!0})],GlideCoreRadioGroup.prototype,"disabled",void 0),__decorate([property()],GlideCoreRadioGroup.prototype,"label",void 0),__decorate([property({attribute:"hide-label",type:Boolean})],GlideCoreRadioGroup.prototype,"hideLabel",void 0),__decorate([property()],GlideCoreRadioGroup.prototype,"name",void 0),__decorate([property()],GlideCoreRadioGroup.prototype,"privateSplit",void 0),__decorate([property({type:Boolean,reflect:!0})],GlideCoreRadioGroup.prototype,"required",void 0),__decorate([property({reflect:!0})],GlideCoreRadioGroup.prototype,"value",void 0),__decorate([state()],GlideCoreRadioGroup.prototype,"isCheckingValidity",void 0),__decorate([state()],GlideCoreRadioGroup.prototype,"isReportValidityOrSubmit",void 0),GlideCoreRadioGroup=__decorate([customElement("glide-core-radio-group")],GlideCoreRadioGroup);export default GlideCoreRadioGroup;
1
+ var __decorate=this&&this.__decorate||function(e,i,t,o){var s,d=arguments.length,a=d<3?i:null===o?o=Object.getOwnPropertyDescriptor(i,t):o;if("object"==typeof Reflect&&"function"==typeof Reflect.decorate)a=Reflect.decorate(e,i,t,o);else for(var r=e.length-1;r>=0;r--)(s=e[r])&&(a=(d<3?s(a):d>3?s(i,t,a):s(i,t))||a);return d>3&&a&&Object.defineProperty(i,t,a),a};import"./label.js";import"./tooltip.js";import{LitElement,html}from"lit";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{owSlot,owSlotType}from"./library/ow.js";import GlideCoreRadio from"./radio.js";import styles from"./radio-group.styles.js";let GlideCoreRadioGroup=class GlideCoreRadioGroup extends LitElement{static{this.formAssociated=!0}static{this.shadowRootOptions={...LitElement.shadowRootOptions,mode:"closed"}}static{this.styles=styles}checkValidity(){this.isCheckingValidity=!0;const e=this.#e.checkValidity();return this.isCheckingValidity=!1,e}disconnectedCallback(){super.disconnectedCallback(),this.form?.removeEventListener("formdata",this.#i),this.#t=void 0}firstUpdated(){owSlot(this.#o.value),owSlotType(this.#o.value,[GlideCoreRadio]),this.#t=this.#s.find((e=>e.checked)),this.#d()}focus(e){let i=this.#s.find((e=>e.checked));i||(i=this.#s.find((e=>0===e.tabIndex))),i?.focus(e)}get form(){return this.#e.form}get validity(){return this.#e.validity}get willValidate(){return this.#e.willValidate}formAssociatedCallback(){this.form?.addEventListener("formdata",this.#i)}formResetCallback(){if(this.#t&&this.contains(this.#t))for(const e of this.#s)this.#a(e===this.#t,e)}render(){return html`<div class="component" @click="${this.#r}" @keydown="${this.#l}" ${ref(this.#n)}><glide-core-label orientation="horizontal" split="${ifDefined(this.privateSplit??void 0)}" ?disabled="${this.disabled}" ?error="${this.#h}" ?hide="${this.hideLabel}" ?required="${this.required}"><label id="label" data-test="label">${this.label}</label><div class="${classMap({"radio-container":!0,vertical:!0,invalid:this.#h})}" role="radiogroup" slot="control" aria-labelledby="label description" @blur="${this.#c}"><slot ${ref(this.#o)} @slotchange="${this.#p}"></slot></div><slot name="tooltip" slot="tooltip"></slot><slot id="description" name="description" slot="description"></slot></glide-core-label></div>`}reportValidity(){this.isReportValidityOrSubmit=!0;const e=this.#e.reportValidity();return this.requestUpdate(),e}updated(e){this.hasUpdated&&(e.has("value")||e.has("required"))&&(this.#f(),this.#u(!this.#e.validity.valid),this.requestUpdate())}willUpdate(e){if(this.hasUpdated){if(e.has("required")&&this.#R(),e.has("disabled")){for(const e of this.#s)this.#m(this.disabled,e);!this.disabled&&this.#b()}if(e.has("value"))for(const e of this.#s)e.checked=e.value===this.value}}constructor(){super(),this.description="",this.disabled=!1,this.label="",this.hideLabel=!1,this.name="",this.required=!1,this.value="",this.isBlurring=!1,this.isCheckingValidity=!1,this.isReportValidityOrSubmit=!1,this.#n=createRef(),this.#o=createRef(),this.#t=void 0,this.#i=({formData:e})=>{this.name&&this.value.length>0&&!this.disabled&&e.append(this.name,this.value)},this.#e=this.attachInternals(),this.addEventListener("invalid",this.#v)}#n;#o;#t;#e;#C;#i;#d(){const e=this.#s.find((e=>e.checked));this.value=e?.value??this.#t?.value??"",this.#C=e??this.#t,this.required&&this.#R();for(const e of this.#s)this.disabled?this.#m(this.disabled,e):this.#m(e.disabled,e),e.addEventListener("blur",this.#y.bind(this));!this.disabled&&this.#b()}get#h(){const e=!this.disabled&&!this.validity.valid&&this.isReportValidityOrSubmit;return this.#u(e),e}#c(){this.isBlurring=!0,this.reportValidity(),this.isBlurring=!1}#r(e){if(this.disabled)return;if(e.target instanceof GlideCoreRadio&&e.target.disabled&&this.#C&&!this.#C.disabled)return void this.#C?.focus();const i=e.target;if(i instanceof GlideCoreRadio&&i&&!i.disabled){this.#a(!0,i);for(const e of this.#s)e!==i&&this.#a(!1,e)}}#p(){owSlot(this.#o.value),owSlotType(this.#o.value,[GlideCoreRadio]),this.#d()}#v(e){if(e.preventDefault(),!this.isCheckingValidity){if(e?.preventDefault(),this.isCheckingValidity||this.isBlurring)return;this.isReportValidityOrSubmit=!0;this.form?.querySelector(":invalid")===this&&this.focus()}}#l(e){if(!(this.disabled||e.target instanceof GlideCoreRadio&&e.target?.disabled)&&e.target instanceof GlideCoreRadio){const i=e.target;switch(e.key){case"ArrowUp":case"ArrowLeft":{e.preventDefault();let t=i.previousElementSibling;for(;(!t||t instanceof GlideCoreRadio&&t.disabled||!(t instanceof GlideCoreRadio))&&t!==i;)if(null===t){const e=this.#s.at(-1);e&&(t=e)}else t=t.previousElementSibling;t&&t instanceof GlideCoreRadio&&!t.disabled&&t!==i&&(this.#a(!1,i),this.#a(!0,t));break}case"ArrowDown":case"ArrowRight":{e.preventDefault();let t=i.nextElementSibling;for(;(!t||t instanceof GlideCoreRadio&&t.disabled||!(t instanceof GlideCoreRadio))&&t!==i;)if(null===t){const e=this.#s.at(0);e&&(t=e)}else t=t.nextElementSibling;t&&t instanceof GlideCoreRadio&&!t.disabled&&t!==i&&(this.#a(!1,i),this.#a(!0,t));break}case" ":if(e.preventDefault(),!i.disabled&&!i.checked){this.#a(!0,i);for(const e of this.#s)e!==i&&this.#a(!1,e)}}}}#y(e){const i=e.relatedTarget;i&&i instanceof GlideCoreRadio&&this.#s.includes(i)||this.#c()}#f(){const e=this.#s.find((e=>e.checked));this.required&&!e?this.#e.setValidity({valueMissing:!0}," ",this.#n.value):this.#e.setValidity({})}get#s(){return this.#o.value?.assignedElements().filter((e=>e instanceof GlideCoreRadio))??[]}#a(e,i){i.checked=e,i.tabIndex=e?0:-1,e&&(this.#C=i,this.value=i.value,i.focus(),i.dispatchEvent(new Event("change",{bubbles:!0})),i.dispatchEvent(new Event("input",{bubbles:!0})))}#m(e,i){i.disabled=e,e&&(i.tabIndex=-1)}#u(e){for(const i of this.#s)i.invalid=e}#b(){if(this.disabled||this.#s.every((e=>e.disabled)))return;let e=null;const i=this.#s.find((e=>!e.disabled&&e.checked));if(i)e=i;else{const i=this.#s.find((e=>!e.disabled));i&&(e=i)}if(e)for(const i of this.#s)i.tabIndex=i===e?0:-1}#R(){for(const e of this.#s)e.required=this.required}};__decorate([property()],GlideCoreRadioGroup.prototype,"description",void 0),__decorate([property({type:Boolean,reflect:!0})],GlideCoreRadioGroup.prototype,"disabled",void 0),__decorate([property()],GlideCoreRadioGroup.prototype,"label",void 0),__decorate([property({attribute:"hide-label",type:Boolean})],GlideCoreRadioGroup.prototype,"hideLabel",void 0),__decorate([property()],GlideCoreRadioGroup.prototype,"name",void 0),__decorate([property()],GlideCoreRadioGroup.prototype,"privateSplit",void 0),__decorate([property({type:Boolean,reflect:!0})],GlideCoreRadioGroup.prototype,"required",void 0),__decorate([property({reflect:!0})],GlideCoreRadioGroup.prototype,"value",void 0),__decorate([state()],GlideCoreRadioGroup.prototype,"isBlurring",void 0),__decorate([state()],GlideCoreRadioGroup.prototype,"isCheckingValidity",void 0),__decorate([state()],GlideCoreRadioGroup.prototype,"isReportValidityOrSubmit",void 0),GlideCoreRadioGroup=__decorate([customElement("glide-core-radio-group")],GlideCoreRadioGroup);export default GlideCoreRadioGroup;
@@ -1,6 +1,7 @@
1
1
  import './radio-group.js';
2
2
  import './radio.js';
3
3
  import { expect, fixture, html } from '@open-wc/testing';
4
+ import { sendKeys } from '@web/test-runner-commands';
4
5
  import GlideCoreRadio from './radio.js';
5
6
  import GlideCoreRadioGroup from './radio-group.js';
6
7
  GlideCoreRadio.shadowRootOptions.mode = 'open';
@@ -73,3 +74,21 @@ it('focuses the first tabbable radio when none are checked', async () => {
73
74
  const radio = component.querySelector('glide-core-radio[value="value-2"]');
74
75
  expect(radio).to.have.focus;
75
76
  });
77
+ it('reports validity if blurred', async () => {
78
+ const component = await fixture(html `<glide-core-radio-group label="Checkbox Group" required>
79
+ <glide-core-radio value="value-1" label="One"></glide-core-radio>
80
+ <glide-core-radio value="value-2" label="Two"></glide-core-radio>
81
+ </glide-core-radio-group>`);
82
+ component.focus();
83
+ const radioItems = component.querySelectorAll('glide-core-radio');
84
+ expect(document.activeElement === radioItems[0]).to.be.true;
85
+ expect(component.shadowRoot
86
+ ?.querySelector('glide-core-label')
87
+ ?.hasAttribute('error')).to.be.false;
88
+ await sendKeys({ press: 'Tab' });
89
+ expect(document.activeElement === document.body).to.be.true;
90
+ expect(component.validity.valid).to.equal(false);
91
+ expect(component.shadowRoot
92
+ ?.querySelector('glide-core-label')
93
+ ?.hasAttribute('error')).to.be.true;
94
+ });
@@ -45,6 +45,7 @@ export default class GlideCoreTextarea extends LitElement {
45
45
  reportValidity(): boolean;
46
46
  updated(): void;
47
47
  constructor();
48
+ private isBlurring;
48
49
  private isCheckingValidity;
49
50
  private isReportValidityOrSubmit;
50
51
  }
package/dist/textarea.js CHANGED
@@ -1,2 +1,2 @@
1
- var __decorate=this&&this.__decorate||function(e,t,i,a){var r,o=arguments.length,l=o<3?t:null===a?a=Object.getOwnPropertyDescriptor(t,i):a;if("object"==typeof Reflect&&"function"==typeof Reflect.decorate)l=Reflect.decorate(e,t,i,a);else for(var s=e.length-1;s>=0;s--)(r=e[s])&&(l=(o<3?r(l):o>3?r(t,i,l):r(t,i))||l);return o>3&&l&&Object.defineProperty(t,i,l),l};import"./label.js";import{LitElement,html}from"lit";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{when}from"lit/directives/when.js";import ow from"./library/ow.js";import styles from"./textarea.styles.js";let GlideCoreTextarea=class GlideCoreTextarea extends LitElement{static{this.formAssociated=!0}static{this.shadowRootOptions={...LitElement.shadowRootOptions,mode:"closed",delegatesFocus:!0}}static{this.styles=styles}blur(){this.#e.value?.blur()}checkValidity(){return this.isCheckingValidity=!0,this.#t.checkValidity()}disconnectedCallback(){super.disconnectedCallback(),this.form?.removeEventListener("formdata",this.#i),this.removeEventListener("invalid",this.#a)}get form(){return this.#t.form}get validity(){return this.#t.validity}get willValidate(){return this.#t.willValidate}formAssociatedCallback(){this.form?.addEventListener("formdata",this.#i)}formResetCallback(){this.value=this.getAttribute("value")??""}render(){return html`<glide-core-label split="${ifDefined(this.privateSplit??void 0)}" orientation="${this.orientation}" ?disabled="${this.disabled}" ?error="${this.#r||this.#o}" ?hide="${this.hideLabel}" ?required="${this.required}"><slot name="tooltip" slot="tooltip"></slot><label class="label" for="textarea">${this.label}</label><div class="textarea-container" slot="control"><textarea class="${classMap({error:this.#r||this.#o})}" id="textarea" name="${ifDefined(this.name)}" placeholder="${ifDefined(this.placeholder)}" rows="${this.rows}" autocapitalize="${ifDefined(this.autocapitalize)}" spellcheck="${this.spellcheck}" ?required="${this.required}" ?readonly="${this.readonly}" ?disabled="${this.disabled}" aria-describedby="meta" ${ref(this.#e)} @input="${this.#l}" @change="${this.#s}">
2
- </textarea></div><div class="meta" data-test-description-container id="meta" slot="description"><slot name="description"></slot>${when(this.maxlength,(()=>html`<div class="${classMap({"character-count":!0,error:this.#o})}" data-test-maxlength>${this.value.length}/${this.maxlength}</div>`))}</div></glide-core-label>`}reportValidity(){return this.#t.reportValidity()}updated(){this.#e.value&&(this.#e.value.value=this.value),this.#d()}constructor(){super(),this.value="",this.label="",this.hideLabel=!1,this.orientation="horizontal",this.placeholder="",this.rows=2,this.required=!1,this.readonly=!1,this.disabled=!1,this.spellcheck=!1,this.autocapitalize="on",this.isCheckingValidity=!1,this.isReportValidityOrSubmit=!1,this.#e=createRef(),this.#i=({formData:e})=>{this.value.length>0&&this.name&&this.value&&!this.disabled&&e.append(this.name,this.value)},this.#t=this.attachInternals(),this.addEventListener("invalid",this.#a)}#t;#e;#i;get#r(){return!this.disabled&&!this.readonly&&!this.validity.valid&&this.isReportValidityOrSubmit}get#o(){return!(!this.maxlength||this.disabled)&&this.value.length>this.maxlength}#s(e){ow(this.#e.value,ow.object.instanceOf(HTMLTextAreaElement));const t=this.#e.value.value;this.value=t,this.#d(),this.dispatchEvent(new Event(e.type,e))}#l(){ow(this.#e.value,ow.object.instanceOf(HTMLTextAreaElement));const e=this.#e.value.value;this.value=e,this.#t.setFormValue(this.value),this.#d()}#a(e){e.preventDefault(),this.isCheckingValidity||(this.isCheckingValidity=!1,this.isReportValidityOrSubmit=!0)}async#d(){const e=this.#e.value;this.#o?this.#t.setValidity({...e?.validity,tooLong:!0}," ",e):this.#t.setValidity(e?.validity,e?.validationMessage,e),await this.updateComplete}};__decorate([property()],GlideCoreTextarea.prototype,"value",void 0),__decorate([property()],GlideCoreTextarea.prototype,"label",void 0),__decorate([property({attribute:"hide-label",type:Boolean})],GlideCoreTextarea.prototype,"hideLabel",void 0),__decorate([property({reflect:!0})],GlideCoreTextarea.prototype,"orientation",void 0),__decorate([property()],GlideCoreTextarea.prototype,"placeholder",void 0),__decorate([property({reflect:!0,type:Number})],GlideCoreTextarea.prototype,"rows",void 0),__decorate([property({type:Boolean})],GlideCoreTextarea.prototype,"required",void 0),__decorate([property({type:Boolean})],GlideCoreTextarea.prototype,"readonly",void 0),__decorate([property({type:Boolean})],GlideCoreTextarea.prototype,"disabled",void 0),__decorate([property({type:Number,converter:e=>e&&Number.parseInt(e,10)})],GlideCoreTextarea.prototype,"maxlength",void 0),__decorate([property({reflect:!0})],GlideCoreTextarea.prototype,"name",void 0),__decorate([property({type:Boolean})],GlideCoreTextarea.prototype,"spellcheck",void 0),__decorate([property()],GlideCoreTextarea.prototype,"autocapitalize",void 0),__decorate([property()],GlideCoreTextarea.prototype,"privateSplit",void 0),__decorate([state()],GlideCoreTextarea.prototype,"isCheckingValidity",void 0),__decorate([state()],GlideCoreTextarea.prototype,"isReportValidityOrSubmit",void 0),GlideCoreTextarea=__decorate([customElement("glide-core-textarea")],GlideCoreTextarea);export default GlideCoreTextarea;
1
+ var __decorate=this&&this.__decorate||function(e,t,i,a){var r,o=arguments.length,l=o<3?t:null===a?a=Object.getOwnPropertyDescriptor(t,i):a;if("object"==typeof Reflect&&"function"==typeof Reflect.decorate)l=Reflect.decorate(e,t,i,a);else for(var s=e.length-1;s>=0;s--)(r=e[s])&&(l=(o<3?r(l):o>3?r(t,i,l):r(t,i))||l);return o>3&&l&&Object.defineProperty(t,i,l),l};import"./label.js";import{LitElement,html}from"lit";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{when}from"lit/directives/when.js";import ow from"./library/ow.js";import styles from"./textarea.styles.js";let GlideCoreTextarea=class GlideCoreTextarea extends LitElement{static{this.formAssociated=!0}static{this.shadowRootOptions={...LitElement.shadowRootOptions,mode:"closed",delegatesFocus:!0}}static{this.styles=styles}blur(){this.#e.value?.blur()}checkValidity(){this.isCheckingValidity=!0;const e=this.#t.checkValidity();return this.isCheckingValidity=!1,e}disconnectedCallback(){super.disconnectedCallback(),this.form?.removeEventListener("formdata",this.#i),this.removeEventListener("invalid",this.#a)}get form(){return this.#t.form}get validity(){return this.#t.validity}get willValidate(){return this.#t.willValidate}formAssociatedCallback(){this.form?.addEventListener("formdata",this.#i)}formResetCallback(){this.value=this.getAttribute("value")??""}render(){return html`<glide-core-label split="${ifDefined(this.privateSplit??void 0)}" orientation="${this.orientation}" ?disabled="${this.disabled}" ?error="${this.#r||this.#o}" ?hide="${this.hideLabel}" ?required="${this.required}"><slot name="tooltip" slot="tooltip"></slot><label class="label" for="textarea">${this.label}</label><div class="textarea-container" slot="control"><textarea class="${classMap({error:this.#r||this.#o})}" id="textarea" name="${ifDefined(this.name)}" placeholder="${ifDefined(this.placeholder)}" rows="${this.rows}" autocapitalize="${ifDefined(this.autocapitalize)}" spellcheck="${this.spellcheck}" ?required="${this.required}" ?readonly="${this.readonly}" ?disabled="${this.disabled}" aria-describedby="meta" ${ref(this.#e)} @input="${this.#l}" @change="${this.#s}" @blur="${this.#d}">
2
+ </textarea></div><div class="meta" data-test-description-container id="meta" slot="description"><slot name="description"></slot>${when(this.maxlength,(()=>html`<div class="${classMap({"character-count":!0,error:this.#o})}" data-test-maxlength>${this.value.length}/${this.maxlength}</div>`))}</div></glide-core-label>`}reportValidity(){this.isReportValidityOrSubmit=!0;const e=this.#t.reportValidity();return this.requestUpdate(),e}updated(){this.#e.value&&(this.#e.value.value=this.value),this.#n()}constructor(){super(),this.value="",this.label="",this.hideLabel=!1,this.orientation="horizontal",this.placeholder="",this.rows=2,this.required=!1,this.readonly=!1,this.disabled=!1,this.spellcheck=!1,this.autocapitalize="on",this.isBlurring=!1,this.isCheckingValidity=!1,this.isReportValidityOrSubmit=!1,this.#e=createRef(),this.#i=({formData:e})=>{this.value.length>0&&this.name&&this.value&&!this.disabled&&e.append(this.name,this.value)},this.#t=this.attachInternals(),this.addEventListener("invalid",this.#a)}#t;#e;#i;get#r(){return!this.disabled&&!this.readonly&&!this.validity.valid&&this.isReportValidityOrSubmit}get#o(){return!(!this.maxlength||this.disabled)&&this.value.length>this.maxlength}#d(){this.isBlurring=!0,this.reportValidity(),this.isBlurring=!1}#s(e){ow(this.#e.value,ow.object.instanceOf(HTMLTextAreaElement));const t=this.#e.value.value;this.value=t,this.#n(),this.dispatchEvent(new Event(e.type,e))}#l(){ow(this.#e.value,ow.object.instanceOf(HTMLTextAreaElement));const e=this.#e.value.value;this.value=e,this.#t.setFormValue(this.value),this.#n()}#a(e){if(e?.preventDefault(),this.isCheckingValidity||this.isBlurring)return;this.isReportValidityOrSubmit=!0;this.form?.querySelector(":invalid")===this&&this.focus()}async#n(){const e=this.#e.value;this.#o?this.#t.setValidity({...e?.validity,tooLong:!0}," ",e):this.#t.setValidity(e?.validity,e?.validationMessage,e),await this.updateComplete}};__decorate([property()],GlideCoreTextarea.prototype,"value",void 0),__decorate([property()],GlideCoreTextarea.prototype,"label",void 0),__decorate([property({attribute:"hide-label",type:Boolean})],GlideCoreTextarea.prototype,"hideLabel",void 0),__decorate([property({reflect:!0})],GlideCoreTextarea.prototype,"orientation",void 0),__decorate([property()],GlideCoreTextarea.prototype,"placeholder",void 0),__decorate([property({reflect:!0,type:Number})],GlideCoreTextarea.prototype,"rows",void 0),__decorate([property({type:Boolean})],GlideCoreTextarea.prototype,"required",void 0),__decorate([property({type:Boolean})],GlideCoreTextarea.prototype,"readonly",void 0),__decorate([property({type:Boolean})],GlideCoreTextarea.prototype,"disabled",void 0),__decorate([property({type:Number,converter:e=>e&&Number.parseInt(e,10)})],GlideCoreTextarea.prototype,"maxlength",void 0),__decorate([property({reflect:!0})],GlideCoreTextarea.prototype,"name",void 0),__decorate([property({type:Boolean})],GlideCoreTextarea.prototype,"spellcheck",void 0),__decorate([property()],GlideCoreTextarea.prototype,"autocapitalize",void 0),__decorate([property()],GlideCoreTextarea.prototype,"privateSplit",void 0),__decorate([state()],GlideCoreTextarea.prototype,"isBlurring",void 0),__decorate([state()],GlideCoreTextarea.prototype,"isCheckingValidity",void 0),__decorate([state()],GlideCoreTextarea.prototype,"isReportValidityOrSubmit",void 0),GlideCoreTextarea=__decorate([customElement("glide-core-textarea")],GlideCoreTextarea);export default GlideCoreTextarea;
@@ -1,4 +1,4 @@
1
- import { expect, fixture } from '@open-wc/testing';
1
+ import { expect, fixture, html } from '@open-wc/testing';
2
2
  import { sendKeys } from '@web/test-runner-commands';
3
3
  import GlideCoreTextarea from './textarea.js';
4
4
  GlideCoreTextarea.shadowRootOptions.mode = 'open';
@@ -81,3 +81,15 @@ it('is valid when filled in, disabled, and exceeds `maxlength`', async () => {
81
81
  expect(textarea.checkValidity()).to.be.true;
82
82
  expect(textarea.reportValidity()).to.be.true;
83
83
  });
84
+ it('blurs the textarea and reports validity if `blur` is called', async () => {
85
+ const textarea = await fixture(html `<glide-core-textarea required></glide-core-textarea>`);
86
+ textarea.focus();
87
+ const textareaElement = textarea.shadowRoot?.querySelector('textarea');
88
+ expect(textarea.shadowRoot?.activeElement === textareaElement).to.be.true;
89
+ textarea.blur();
90
+ await textarea.updateComplete;
91
+ expect(textarea.shadowRoot?.activeElement === null).to.be.true;
92
+ expect(textarea.validity.valid).to.equal(false);
93
+ expect(textarea.shadowRoot?.querySelector('glide-core-label')?.error).to.be
94
+ .true;
95
+ });
@@ -22,6 +22,8 @@ export default class GlideCoreTreeItem extends LitElement {
22
22
  label: string;
23
23
  level: number;
24
24
  selected: boolean;
25
+ removeIndentation: boolean;
26
+ nonCollapsible: boolean;
25
27
  menuSlotAssignedElements: GlideCoreMenu[];
26
28
  prefixSlotAssignedElements: HTMLElement[];
27
29
  slotElements: GlideCoreTreeItem[];
@@ -29,6 +31,7 @@ export default class GlideCoreTreeItem extends LitElement {
29
31
  firstUpdated(): void;
30
32
  focus(): void;
31
33
  get hasChildTreeItems(): boolean;
34
+ get hasExpandIcon(): boolean;
32
35
  render(): import("lit").TemplateResult<1>;
33
36
  /**
34
37
  * Traverses down the tree, selecting the passed-in item,
package/dist/tree.item.js CHANGED
@@ -1 +1 @@
1
- var __decorate=this&&this.__decorate||function(e,t,i,s){var r,o=arguments.length,l=o<3?t:null===s?s=Object.getOwnPropertyDescriptor(t,i):s;if("object"==typeof Reflect&&"function"==typeof Reflect.decorate)l=Reflect.decorate(e,t,i,s);else for(var d=e.length-1;d>=0;d--)(r=e[d])&&(l=(o<3?r(l):o>3?r(t,i,l):r(t,i))||l);return o>3&&l&&Object.defineProperty(t,i,l),l};import"./tree.item.menu.js";import{LitElement,html}from"lit";import{classMap}from"lit/directives/class-map.js";import{createRef,ref}from"lit/directives/ref.js";import{customElement,property,queryAssignedElements,state}from"lit/decorators.js";import{ifDefined}from"lit/directives/if-defined.js";import GlideCoreMenu from"./menu.js";import{when}from"lit/directives/when.js";import styles from"./tree.item.styles.js";let GlideCoreTreeItem=class GlideCoreTreeItem extends LitElement{constructor(){super(...arguments),this.expanded=!1,this.label="",this.level=1,this.selected=!1,this.childTreeItems=[],this.#e=createRef()}static{this.shadowRootOptions={...LitElement.shadowRootOptions,delegatesFocus:!0,mode:"closed"}}static{this.styles=styles}firstUpdated(){this.#t()}focus(){this.#e.value?.focus()}get hasChildTreeItems(){return this.childTreeItems.length>0}render(){return html`<div class="${classMap({component:!0,expanded:this.expanded,selected:this.selected})}" role="treeitem" aria-label="${this.label}" aria-selected="${ifDefined(this.#i)}" aria-expanded="${ifDefined(this.#s)}"><div class="${classMap({"label-container":!0})}" tabindex="-1" ${ref(this.#e)}><div style="flex-shrink: 0; width:${this.#r};"></div><div class="expand-icon-container">${when(this.hasChildTreeItems,(()=>html`<div><svg aria-hidden="true" class="${classMap({"expand-icon":!0,"expand-icon-expanded":this.expanded})}" width="16" height="16" viewBox="0 0 24 24" fill="none"><path d="M9 18L15 12L9 6" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"/></svg></div>`))}</div><slot name="prefix"></slot><div class="label">${this.label}</div><div class="icon-container"><slot name="menu"></slot><slot name="suffix"></slot></div></div><div class="child-items" role="group"><slot></slot></div></div>`}selectItem(e){let t;for(const i of this.slotElements)if(e===i)i.setAttribute("selected","true"),t=i;else{i.removeAttribute("selected");const s=i.selectItem(e);s&&(t=s)}return t}setContainingBlock(e){for(const t of this.menuSlotAssignedElements)t.setContainingBlock(e)}toggleExpand(){this.expanded=!this.expanded}#e;get#s(){return this.hasChildTreeItems?this.expanded?"true":"false":void 0}get#i(){return this.hasChildTreeItems?void 0:this.selected?"true":"false"}get#r(){return 20*(this.level-1)+"px"}#t(){const e=[];for(const t of this.slotElements)t.level=this.level+1,e.push(t);this.childTreeItems=e}};__decorate([property({type:Boolean})],GlideCoreTreeItem.prototype,"expanded",void 0),__decorate([property({reflect:!0})],GlideCoreTreeItem.prototype,"label",void 0),__decorate([property({type:Number})],GlideCoreTreeItem.prototype,"level",void 0),__decorate([property({type:Boolean})],GlideCoreTreeItem.prototype,"selected",void 0),__decorate([queryAssignedElements({slot:"menu"})],GlideCoreTreeItem.prototype,"menuSlotAssignedElements",void 0),__decorate([queryAssignedElements({slot:"prefix"})],GlideCoreTreeItem.prototype,"prefixSlotAssignedElements",void 0),__decorate([queryAssignedElements()],GlideCoreTreeItem.prototype,"slotElements",void 0),__decorate([queryAssignedElements({slot:"suffix"})],GlideCoreTreeItem.prototype,"suffixSlotAssignedElements",void 0),__decorate([state()],GlideCoreTreeItem.prototype,"childTreeItems",void 0),GlideCoreTreeItem=__decorate([customElement("glide-core-tree-item")],GlideCoreTreeItem);export default GlideCoreTreeItem;
1
+ var __decorate=this&&this.__decorate||function(e,t,i,o){var s,r=arguments.length,l=r<3?t:null===o?o=Object.getOwnPropertyDescriptor(t,i):o;if("object"==typeof Reflect&&"function"==typeof Reflect.decorate)l=Reflect.decorate(e,t,i,o);else for(var n=e.length-1;n>=0;n--)(s=e[n])&&(l=(r<3?s(l):r>3?s(t,i,l):s(t,i))||l);return r>3&&l&&Object.defineProperty(t,i,l),l};import"./tree.item.menu.js";import{LitElement,html}from"lit";import{classMap}from"lit/directives/class-map.js";import{createRef,ref}from"lit/directives/ref.js";import{customElement,property,queryAssignedElements,state}from"lit/decorators.js";import{ifDefined}from"lit/directives/if-defined.js";import GlideCoreMenu from"./menu.js";import{when}from"lit/directives/when.js";import styles from"./tree.item.styles.js";let GlideCoreTreeItem=class GlideCoreTreeItem extends LitElement{constructor(){super(...arguments),this.expanded=!1,this.label="",this.level=1,this.selected=!1,this.removeIndentation=!1,this.nonCollapsible=!1,this.childTreeItems=[],this.#e=createRef()}static{this.shadowRootOptions={...LitElement.shadowRootOptions,delegatesFocus:!0,mode:"closed"}}static{this.styles=styles}firstUpdated(){this.#t()}focus(){this.#e.value?.focus()}get hasChildTreeItems(){return this.childTreeItems.length>0}get hasExpandIcon(){return this.hasChildTreeItems&&!this.nonCollapsible}render(){return html`<div class="${classMap({component:!0,expanded:this.expanded,selected:this.selected})}" role="treeitem" aria-label="${this.label}" aria-selected="${ifDefined(this.#i)}" aria-expanded="${ifDefined(this.#o)}"><div class="${classMap({"label-container":!0})}" tabindex="-1" ${ref(this.#e)}><div style="flex-shrink: 0; width:${this.#s};"></div>${when(!this.removeIndentation||this.hasExpandIcon,(()=>html`<div class="expand-icon-container">${when(this.hasExpandIcon,(()=>html`<div><svg aria-hidden="true" class="${classMap({"expand-icon":!0,"expand-icon-expanded":this.expanded})}" width="16" height="16" viewBox="0 0 24 24" fill="none"><path d="M9 18L15 12L9 6" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"/></svg></div>`))}</div>`))}<slot name="prefix"></slot><div class="label">${this.label}</div><div class="icon-container"><slot name="menu"></slot><slot name="suffix"></slot></div></div><div class="child-items" role="group"><slot></slot></div></div>`}selectItem(e){let t;for(const i of this.slotElements)if(e===i)i.setAttribute("selected","true"),t=i;else{i.removeAttribute("selected");const o=i.selectItem(e);o&&(t=o)}return t}setContainingBlock(e){for(const t of this.menuSlotAssignedElements)t.setContainingBlock(e)}toggleExpand(){this.expanded=!this.expanded}#e;get#o(){return this.hasChildTreeItems?this.expanded?"true":"false":void 0}get#i(){return this.hasChildTreeItems?void 0:this.selected?"true":"false"}get#s(){return 20*(this.level-1)+"px"}#t(){const e=[];for(const t of this.slotElements)t.level=this.level+1,e.push(t);this.childTreeItems=e}};__decorate([property({type:Boolean})],GlideCoreTreeItem.prototype,"expanded",void 0),__decorate([property({reflect:!0})],GlideCoreTreeItem.prototype,"label",void 0),__decorate([property({type:Number})],GlideCoreTreeItem.prototype,"level",void 0),__decorate([property({type:Boolean})],GlideCoreTreeItem.prototype,"selected",void 0),__decorate([property({type:Boolean,attribute:"remove-indentation"})],GlideCoreTreeItem.prototype,"removeIndentation",void 0),__decorate([property({type:Boolean,attribute:"non-collapsible"})],GlideCoreTreeItem.prototype,"nonCollapsible",void 0),__decorate([queryAssignedElements({slot:"menu"})],GlideCoreTreeItem.prototype,"menuSlotAssignedElements",void 0),__decorate([queryAssignedElements({slot:"prefix"})],GlideCoreTreeItem.prototype,"prefixSlotAssignedElements",void 0),__decorate([queryAssignedElements()],GlideCoreTreeItem.prototype,"slotElements",void 0),__decorate([queryAssignedElements({slot:"suffix"})],GlideCoreTreeItem.prototype,"suffixSlotAssignedElements",void 0),__decorate([state()],GlideCoreTreeItem.prototype,"childTreeItems",void 0),GlideCoreTreeItem=__decorate([customElement("glide-core-tree-item")],GlideCoreTreeItem);export default GlideCoreTreeItem;
@@ -11,6 +11,17 @@ it('renders and sets default attributes', async () => {
11
11
  expect(treeItem.expanded).to.equal(false);
12
12
  expect(treeItem.label).to.equal('Item');
13
13
  expect(treeItem.level).to.equal(1);
14
+ expect(treeItem.shadowRoot?.querySelector('.expand-icon-container')).to.be.ok;
15
+ });
16
+ it('does not render expand-icon-container if remove-indentation is set', async () => {
17
+ const treeItem = await fixture(html `
18
+ <glide-core-tree-item
19
+ label="Item"
20
+ remove-indentation
21
+ ></glide-core-tree-item>
22
+ `);
23
+ expect(treeItem.shadowRoot?.querySelector('.expand-icon-container')).to.be
24
+ .null;
14
25
  });
15
26
  it('renders with a prefix slot', async () => {
16
27
  await fixture(html `
package/dist/tree.js CHANGED
@@ -1 +1 @@
1
- var __decorate=this&&this.__decorate||function(e,t,o,s){var r,l=arguments.length,i=l<3?t:null===s?s=Object.getOwnPropertyDescriptor(t,o):s;if("object"==typeof Reflect&&"function"==typeof Reflect.decorate)i=Reflect.decorate(e,t,o,s);else for(var n=e.length-1;n>=0;n--)(r=e[n])&&(i=(l<3?r(i):l>3?r(t,o,i):r(t,o))||i);return l>3&&i&&Object.defineProperty(t,o,i),i};import{LitElement,html}from"lit";import{createRef,ref}from"lit/directives/ref.js";import{customElement,queryAssignedElements,state}from"lit/decorators.js";import{owSlot,owSlotType}from"./library/ow.js";import GlideCoreTreeItem from"./tree.item.js";import styles from"./tree.styles.js";let GlideCoreTree=class GlideCoreTree extends LitElement{static{this.shadowRootOptions={...LitElement.shadowRootOptions,mode:"closed"}}static{this.styles=styles}disconnectedCallback(){super.disconnectedCallback(),this.removeEventListener("focusin",this.#e),this.removeEventListener("focusout",this.#t)}firstUpdated(){owSlot(this.#o.value),owSlotType(this.#o.value,[GlideCoreTreeItem])}render(){return html`<div class="component" role="tree" tabindex="${this.privateTabIndex}" @click="${this.#s}" @keydown="${this.#r}"><slot @slotchange="${this.#l}" ${ref(this.#o)}></slot></div>`}selectItem(e){for(const t of this.slotElements)if(e===t)t.setAttribute("selected","true"),this.selectedItem=t;else{t.removeAttribute("selected");const o=t.selectItem(e);o&&(this.selectedItem=o)}this.dispatchEvent(new CustomEvent("item-selected",{bubbles:!0,detail:e}))}setContainingBlock(e){for(const t of this.#i())t.setContainingBlock(e)}constructor(){super(),this.privateTabIndex=0,this.#o=createRef(),this.addEventListener("focusin",this.#e),this.addEventListener("focusout",this.#t)}#o;#n(e){e?.focus(),this.focusedItem=e}#i(){return[...this.querySelectorAll("glide-core-tree-item")]}#d(){const e=this.#i(),t=new Set;return e.filter((e=>{const o=e.parentElement?.closest("glide-core-tree-item");return!o||o.expanded&&!t.has(o)||t.add(e),!t.has(e)}))}#s(e){const t=e.target;if(t.closest("glide-core-tree-item-icon-button")??t.closest("glide-core-tree-item-menu"))return;const o=t.closest("glide-core-tree-item");o&&(o.hasChildTreeItems?o.toggleExpand():this.selectItem(o))}#e(e){let t;e.target===this?t=this.selectedItem??this.slotElements[0]:e.target instanceof GlideCoreTreeItem&&(t=e.target,this.privateTabIndex=-1),this.#n(t)}#t(e){const t=e.relatedTarget;t&&this.contains(t)||(this.privateTabIndex=0,this.focusedItem=void 0)}#r(e){if(!["ArrowRight","ArrowLeft","ArrowDown","ArrowUp","Home","End","Enter"].includes(e.key))return;const t=this.#d(),{focusedItem:o}=this,s=t.findIndex((e=>e.matches(":focus")));if("ArrowRight"===e.key&&o?.hasChildTreeItems&&(o.expanded?this.#n(o.slotElements[0]):o.toggleExpand()),"ArrowLeft"===e.key)if(o?.expanded)o.toggleExpand();else{const e=o?.parentElement?.closest("glide-core-tree-item");this.#n(e)}"ArrowDown"===e.key&&-1!==s&&s<t.length-1&&this.#n(t[s+1]),"ArrowUp"===e.key&&s>0&&this.#n(t[s-1]),"Home"===e.key&&this.#n(t[0]),"End"===e.key&&this.#n(t.at(-1)),"Enter"===e.key&&o&&(o.hasChildTreeItems?o.toggleExpand():this.selectItem(o))}#l(){owSlot(this.#o.value),owSlotType(this.#o.value,[GlideCoreTreeItem])}};__decorate([state()],GlideCoreTree.prototype,"selectedItem",void 0),__decorate([state()],GlideCoreTree.prototype,"focusedItem",void 0),__decorate([state()],GlideCoreTree.prototype,"privateTabIndex",void 0),__decorate([queryAssignedElements()],GlideCoreTree.prototype,"slotElements",void 0),GlideCoreTree=__decorate([customElement("glide-core-tree")],GlideCoreTree);export default GlideCoreTree;
1
+ var __decorate=this&&this.__decorate||function(e,t,o,s){var l,r=arguments.length,i=r<3?t:null===s?s=Object.getOwnPropertyDescriptor(t,o):s;if("object"==typeof Reflect&&"function"==typeof Reflect.decorate)i=Reflect.decorate(e,t,o,s);else for(var n=e.length-1;n>=0;n--)(l=e[n])&&(i=(r<3?l(i):r>3?l(t,o,i):l(t,o))||i);return r>3&&i&&Object.defineProperty(t,o,i),i};import{LitElement,html}from"lit";import{createRef,ref}from"lit/directives/ref.js";import{customElement,queryAssignedElements,state}from"lit/decorators.js";import{owSlot,owSlotType}from"./library/ow.js";import GlideCoreTreeItem from"./tree.item.js";import styles from"./tree.styles.js";let GlideCoreTree=class GlideCoreTree extends LitElement{static{this.shadowRootOptions={...LitElement.shadowRootOptions,mode:"closed"}}static{this.styles=styles}disconnectedCallback(){super.disconnectedCallback(),this.removeEventListener("focusin",this.#e),this.removeEventListener("focusout",this.#t)}firstUpdated(){owSlot(this.#o.value),owSlotType(this.#o.value,[GlideCoreTreeItem])}render(){return html`<div class="component" role="tree" tabindex="${this.privateTabIndex}" @click="${this.#s}" @keydown="${this.#l}"><slot @slotchange="${this.#r}" ${ref(this.#o)}></slot></div>`}selectItem(e){for(const t of this.slotElements){e===t?(t.setAttribute("selected","true"),this.selectedItem=t):t.removeAttribute("selected");const o=t.selectItem(e);o&&(this.selectedItem=o)}this.dispatchEvent(new CustomEvent("item-selected",{bubbles:!0,detail:e}))}setContainingBlock(e){for(const t of this.#i())t.setContainingBlock(e)}constructor(){super(),this.privateTabIndex=0,this.#o=createRef(),this.addEventListener("focusin",this.#e),this.addEventListener("focusout",this.#t)}#o;#n(e){e?.focus(),this.focusedItem=e}#i(){return[...this.querySelectorAll("glide-core-tree-item")]}#d(){const e=this.#i(),t=new Set;return e.filter((e=>{const o=e.parentElement?.closest("glide-core-tree-item");return!o||o.expanded&&!t.has(o)||t.add(e),!t.has(e)}))}#s(e){const t=e.target;if(t.closest("glide-core-tree-item-icon-button")??t.closest("glide-core-tree-item-menu"))return;const o=t.closest("glide-core-tree-item");o&&(o.hasChildTreeItems&&!o.nonCollapsible?o.toggleExpand():this.selectItem(o))}#e(e){let t;e.target===this?t=this.selectedItem??this.slotElements[0]:e.target instanceof GlideCoreTreeItem&&(t=e.target,this.privateTabIndex=-1),this.#n(t)}#t(e){const t=e.relatedTarget;t&&this.contains(t)||(this.privateTabIndex=0,this.focusedItem=void 0)}#l(e){if(!["ArrowRight","ArrowLeft","ArrowDown","ArrowUp","Home","End","Enter"].includes(e.key))return;const t=this.#d(),{focusedItem:o}=this,s=t.findIndex((e=>e.matches(":focus")));if("ArrowRight"===e.key&&o?.hasChildTreeItems&&(o.expanded?this.#n(o.slotElements[0]):o.toggleExpand()),"ArrowLeft"===e.key)if(o?.expanded&&!o.nonCollapsible)o.toggleExpand();else{const e=o?.parentElement?.closest("glide-core-tree-item");this.#n(e)}"ArrowDown"===e.key&&-1!==s&&s<t.length-1&&this.#n(t[s+1]),"ArrowUp"===e.key&&s>0&&this.#n(t[s-1]),"Home"===e.key&&this.#n(t[0]),"End"===e.key&&this.#n(t.at(-1)),"Enter"===e.key&&o&&(o.hasChildTreeItems&&!o.nonCollapsible?o.toggleExpand():this.selectItem(o))}#r(){owSlot(this.#o.value),owSlotType(this.#o.value,[GlideCoreTreeItem])}};__decorate([state()],GlideCoreTree.prototype,"selectedItem",void 0),__decorate([state()],GlideCoreTree.prototype,"focusedItem",void 0),__decorate([state()],GlideCoreTree.prototype,"privateTabIndex",void 0),__decorate([queryAssignedElements()],GlideCoreTree.prototype,"slotElements",void 0),GlideCoreTree=__decorate([customElement("glide-core-tree")],GlideCoreTree);export default GlideCoreTree;
@@ -12,6 +12,7 @@ export declare const TreeItemDefault: StoryObj;
12
12
  export declare const TreeItemSelected: StoryObj;
13
13
  export declare const TreeItemWithChildItemsCollapsed: StoryObj;
14
14
  export declare const TreeItemWithChildItemsExpanded: StoryObj;
15
+ export declare const TreeItemWithChildItemsNonCollapsible: StoryObj;
15
16
  export declare const TreeItemWithPrefixIcon: StoryObj;
16
17
  export declare const TreeItemWithSuffixIconButton: StoryObj;
17
18
  export declare const TreeItemWithMenu: StoryObj;
@@ -47,6 +47,9 @@ it('can click child and grandchild items to expand or select them', async () =>
47
47
  <glide-core-tree-item label="Child Item 2">
48
48
  <glide-core-tree-item label="Grandchild Item 1"></glide-core-tree-item>
49
49
  </glide-core-tree-item>
50
+ <glide-core-tree-item label="Child Item 3" expanded non-collapsible>
51
+ <glide-core-tree-item label="Grandchild Item 2"></glide-core-tree-item>
52
+ </glide-core-tree-item>
50
53
  </glide-core-tree>
51
54
  `);
52
55
  const childItems = tree.slotElements;
@@ -63,6 +66,9 @@ it('can click child and grandchild items to expand or select them', async () =>
63
66
  // Can click and select a grandchild item
64
67
  grandchildItems[0].click();
65
68
  expect(grandchildItems[0].selected).to.equal(true);
69
+ // Can click and select a non-collapsible parent item
70
+ childItems[2].click();
71
+ expect(childItems[2].selected).to.equal(true);
66
72
  });
67
73
  it('does not select an item if a tree-item-icon-button is clicked', async () => {
68
74
  const tree = await fixture(html `
@@ -81,6 +81,22 @@ it('collapses an expanded tree item if left arrow is pressed', async () => {
81
81
  assert(document.activeElement instanceof GlideCoreTreeItem);
82
82
  expect(document.activeElement?.label).to.equal(childItems[0].label, 'focus does not move');
83
83
  });
84
+ it(`focuses on a non-collapsible tree item's parent if left arrow is pressed`, async () => {
85
+ const tree = await fixture(html `
86
+ <glide-core-tree>
87
+ <glide-core-tree-item label="Child Item 1" expanded non-collapsible>
88
+ <glide-core-tree-item label="Grandchild Item 1"></glide-core-tree-item>
89
+ </glide-core-tree-item>
90
+ <glide-core-tree-item label="Child Item 2"></glide-core-tree-item>
91
+ </glide-core-tree>
92
+ `);
93
+ const childItems = tree.slotElements;
94
+ const grandchildItems = childItems[0].slotElements;
95
+ grandchildItems[0].focus();
96
+ await sendKeys({ press: 'ArrowLeft' });
97
+ assert(document.activeElement instanceof GlideCoreTreeItem);
98
+ expect(document.activeElement?.label).to.equal(childItems[0].label);
99
+ });
84
100
  it(`focuses on a collapsed tree item's parent if left arrow is pressed`, async () => {
85
101
  const tree = await fixture(html `
86
102
  <glide-core-tree>
@@ -206,6 +222,22 @@ it('selects or expands/collapses node when Enter is pressed', async () => {
206
222
  await sendKeys({ press: 'Enter' });
207
223
  expect(grandchildItems[0].selected).to.equal(true);
208
224
  });
225
+ it('selects a non-collapsible parent node when Enter is pressed', async () => {
226
+ const tree = await fixture(html `
227
+ <glide-core-tree>
228
+ <glide-core-tree-item label="Child Item 1" expanded non-collapsible>
229
+ <glide-core-tree-item label="Grandchild Item 1"></glide-core-tree-item>
230
+ </glide-core-tree-item>
231
+ </glide-core-tree>
232
+ `);
233
+ const childItems = tree.slotElements;
234
+ const grandchildItems = childItems?.[0].slotElements;
235
+ grandchildItems[0].focus();
236
+ childItems[0].focus();
237
+ await sendKeys({ press: 'Enter' });
238
+ expect(grandchildItems[0].selected).to.equal(false);
239
+ expect(childItems[0].selected).to.equal(true);
240
+ });
209
241
  it('does nothing if some other key is pressed', async () => {
210
242
  const tree = await fixture(html `
211
243
  <glide-core-tree>
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@crowdstrike/glide-core",
3
- "version": "0.6.5",
3
+ "version": "0.7.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",
@@ -132,6 +132,6 @@
132
132
  "test:development:web-test-runner": "web-test-runner --watch",
133
133
  "test:production": "npm-run-all --parallel test:production:* start:production:stylesheets --aggregate-output --print-label",
134
134
  "test:production:web-test-runner": "web-test-runner",
135
- "postinstall": "pnpm dlx playwright install --with-deps"
135
+ "postinstall": "pnpm dlx playwright@1.45.3 install --with-deps"
136
136
  }
137
137
  }