@crowdstrike/glide-core 0.6.5 → 0.8.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +44 -5
- package/dist/accordion.test.basics.js +1 -0
- package/dist/accordion.test.events.js +1 -0
- package/dist/button-group.button.test.basics.js +1 -0
- package/dist/button-group.button.test.events.js +1 -0
- package/dist/button-group.test.basics.js +1 -0
- package/dist/button-group.test.events.js +1 -0
- package/dist/button.test.basics.js +1 -0
- package/dist/button.test.events.js +1 -0
- package/dist/button.test.form.js +1 -0
- package/dist/checkbox-group.d.ts +1 -0
- package/dist/checkbox-group.js +1 -1
- package/dist/checkbox-group.test.basics.js +1 -0
- package/dist/checkbox-group.test.events.js +1 -0
- package/dist/checkbox-group.test.focus.js +24 -0
- package/dist/checkbox-group.test.form.js +1 -0
- package/dist/checkbox-group.test.validity.js +1 -0
- package/dist/checkbox.d.ts +3 -1
- package/dist/checkbox.js +1 -1
- package/dist/checkbox.styles.js +4 -5
- package/dist/checkbox.test.basics.js +1 -0
- package/dist/checkbox.test.events.js +1 -0
- package/dist/checkbox.test.focus.js +11 -0
- package/dist/checkbox.test.form.js +1 -0
- package/dist/checkbox.test.states.js +1 -0
- package/dist/checkbox.test.validity.js +1 -0
- package/dist/drawer.styles.js +4 -3
- package/dist/drawer.test.basics.js +1 -0
- package/dist/drawer.test.closing.js +1 -0
- package/dist/drawer.test.events.js +1 -0
- package/dist/drawer.test.floating-components.js +1 -0
- package/dist/drawer.test.methods.js +1 -0
- package/dist/dropdown.d.ts +1 -0
- package/dist/dropdown.js +1 -1
- package/dist/dropdown.option.d.ts +1 -0
- package/dist/dropdown.option.js +1 -1
- package/dist/dropdown.option.test.basics.js +1 -0
- package/dist/dropdown.option.test.basics.multiple.js +1 -0
- package/dist/dropdown.option.test.basics.single.js +1 -0
- package/dist/dropdown.option.test.events.js +1 -0
- package/dist/dropdown.option.test.interactions.multiple.js +1 -0
- package/dist/dropdown.option.test.interactions.single.js +1 -0
- package/dist/dropdown.styles.js +8 -4
- package/dist/dropdown.test.basics.filterable.js +1 -0
- package/dist/dropdown.test.basics.js +1 -0
- package/dist/dropdown.test.basics.multiple.js +1 -1
- package/dist/dropdown.test.basics.single.js +1 -1
- package/dist/dropdown.test.events.js +1 -0
- package/dist/dropdown.test.events.multiple.js +72 -5
- package/dist/dropdown.test.events.single.js +46 -5
- package/dist/dropdown.test.focus.js +11 -2
- package/dist/dropdown.test.focus.multiple.js +0 -1
- package/dist/dropdown.test.form.js +1 -0
- package/dist/dropdown.test.form.multiple.js +1 -0
- package/dist/dropdown.test.form.single.js +1 -0
- package/dist/dropdown.test.interactions.filterable.js +1 -0
- package/dist/dropdown.test.interactions.js +1 -0
- package/dist/dropdown.test.interactions.multiple.js +1 -1
- package/dist/dropdown.test.interactions.single.js +1 -0
- package/dist/dropdown.test.validity.js +1 -0
- package/dist/form-controls-layout.test.basics.js +1 -0
- package/dist/icon-button.test.basics.js +1 -0
- package/dist/input.d.ts +2 -1
- package/dist/input.js +1 -1
- package/dist/input.test.basics.js +1 -0
- package/dist/input.test.events.js +1 -0
- package/dist/input.test.focus.js +6 -3
- package/dist/input.test.form.js +1 -0
- package/dist/input.test.validity.js +1 -0
- package/dist/label.styles.js +11 -11
- package/dist/label.test.basics.js +1 -0
- package/dist/library/localize.d.ts +2 -0
- package/dist/library/ow.test.d.ts +2 -1
- package/dist/library/ow.test.js +8 -3
- package/dist/menu.button.test.basics.js +1 -0
- package/dist/menu.link.test.basics.js +1 -0
- package/dist/menu.options.test.basics.js +1 -0
- package/dist/menu.styles.js +4 -4
- package/dist/menu.test.basics.js +1 -0
- package/dist/menu.test.events.d.ts +1 -0
- package/dist/menu.test.events.js +2 -1
- package/dist/menu.test.focus.js +1 -0
- package/dist/menu.test.interactions.js +1 -0
- package/dist/modal.icon-button.test.basics.js +1 -0
- package/dist/modal.tertiary-icon.test.basics.js +1 -0
- package/dist/modal.test.accessibility.js +1 -0
- package/dist/modal.test.basics.js +1 -0
- package/dist/modal.test.close.js +1 -0
- package/dist/modal.test.events.js +1 -0
- package/dist/modal.test.floating-components.js +1 -0
- package/dist/modal.test.lock-scroll.js +1 -0
- package/dist/modal.test.methods.js +1 -0
- package/dist/modal.test.scrollbars.js +1 -0
- package/dist/radio-group.d.ts +1 -0
- package/dist/radio-group.js +1 -1
- package/dist/radio-group.test.basics.js +1 -0
- package/dist/radio-group.test.events.js +1 -0
- package/dist/radio-group.test.focus.js +20 -0
- package/dist/radio-group.test.form.js +1 -0
- package/dist/radio-group.test.validity.js +1 -0
- package/dist/split-button.test.basics.js +1 -0
- package/dist/split-container.test.basics.js +1 -0
- package/dist/split-link.test.basics.js +1 -0
- package/dist/split-link.test.interactions.js +1 -0
- package/dist/tab.d.ts +0 -2
- package/dist/tab.group.d.ts +3 -5
- package/dist/tab.group.js +1 -1
- package/dist/tab.group.styles.js +27 -13
- package/dist/tab.group.test.basics.js +7 -56
- package/dist/tab.group.test.interactions.d.ts +3 -0
- package/dist/tab.group.test.interactions.js +258 -0
- package/dist/tab.js +1 -1
- package/dist/tab.styles.js +7 -68
- package/dist/tab.test.basics.js +0 -20
- package/dist/tabs.stories.d.ts +1 -2
- package/dist/tag.test.basics.js +1 -0
- package/dist/textarea.d.ts +1 -0
- package/dist/textarea.js +2 -2
- package/dist/textarea.test.basics.js +1 -0
- package/dist/textarea.test.events.js +1 -0
- package/dist/textarea.test.form.js +1 -0
- package/dist/textarea.test.validity.js +14 -1
- package/dist/toggle.test.basics.js +1 -0
- package/dist/toggle.test.events.js +1 -0
- package/dist/toggle.test.states.js +1 -0
- package/dist/tooltip.test.basics.js +1 -0
- package/dist/tooltip.test.interactions.js +1 -0
- package/dist/translations/en.js +1 -1
- package/dist/translations/fr.js +1 -1
- package/dist/translations/ja.js +1 -1
- package/dist/tree.item.d.ts +4 -1
- package/dist/tree.item.js +1 -1
- package/dist/tree.item.menu.js +1 -1
- package/dist/tree.item.test.basics.js +12 -0
- package/dist/tree.js +1 -1
- package/dist/tree.stories.d.ts +1 -0
- package/dist/tree.test.basics.js +7 -0
- package/dist/tree.test.events.js +1 -1
- package/dist/tree.test.focus.js +32 -0
- package/package.json +39 -26
package/dist/modal.test.close.js
CHANGED
package/dist/radio-group.d.ts
CHANGED
@@ -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
|
}
|
package/dist/radio-group.js
CHANGED
@@ -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(){
|
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,8 @@
|
|
1
|
+
/* eslint-disable @typescript-eslint/no-unused-expressions */
|
1
2
|
import './radio-group.js';
|
2
3
|
import './radio.js';
|
3
4
|
import { expect, fixture, html } from '@open-wc/testing';
|
5
|
+
import { sendKeys } from '@web/test-runner-commands';
|
4
6
|
import GlideCoreRadio from './radio.js';
|
5
7
|
import GlideCoreRadioGroup from './radio-group.js';
|
6
8
|
GlideCoreRadio.shadowRootOptions.mode = 'open';
|
@@ -73,3 +75,21 @@ it('focuses the first tabbable radio when none are checked', async () => {
|
|
73
75
|
const radio = component.querySelector('glide-core-radio[value="value-2"]');
|
74
76
|
expect(radio).to.have.focus;
|
75
77
|
});
|
78
|
+
it('reports validity if blurred', async () => {
|
79
|
+
const component = await fixture(html `<glide-core-radio-group label="Checkbox Group" required>
|
80
|
+
<glide-core-radio value="value-1" label="One"></glide-core-radio>
|
81
|
+
<glide-core-radio value="value-2" label="Two"></glide-core-radio>
|
82
|
+
</glide-core-radio-group>`);
|
83
|
+
component.focus();
|
84
|
+
const radioItems = component.querySelectorAll('glide-core-radio');
|
85
|
+
expect(document.activeElement === radioItems[0]).to.be.true;
|
86
|
+
expect(component.shadowRoot
|
87
|
+
?.querySelector('glide-core-label')
|
88
|
+
?.hasAttribute('error')).to.be.false;
|
89
|
+
await sendKeys({ press: 'Tab' });
|
90
|
+
expect(document.activeElement === document.body).to.be.true;
|
91
|
+
expect(component.validity.valid).to.equal(false);
|
92
|
+
expect(component.shadowRoot
|
93
|
+
?.querySelector('glide-core-label')
|
94
|
+
?.hasAttribute('error')).to.be.true;
|
95
|
+
});
|
package/dist/tab.d.ts
CHANGED
@@ -22,8 +22,6 @@ export default class GlideCoreTab extends LitElement {
|
|
22
22
|
panel: string;
|
23
23
|
/** Sets the active attribute on the tab. */
|
24
24
|
active: boolean;
|
25
|
-
/** Sets the variant attribute on the tab. */
|
26
|
-
variant: string;
|
27
25
|
/** Disables the tab. */
|
28
26
|
disabled: boolean;
|
29
27
|
protected firstUpdated(): void;
|
package/dist/tab.group.d.ts
CHANGED
@@ -18,17 +18,15 @@ export default class GlideCoreTabGroup extends LitElement {
|
|
18
18
|
#private;
|
19
19
|
static shadowRootOptions: ShadowRootInit;
|
20
20
|
static styles: import("lit").CSSResult[];
|
21
|
-
/**
|
22
|
-
* Sets the variant attribute on the tab group.
|
23
|
-
* Automatically sets this variant on all <glide-core-tab> components inside the default slot
|
24
|
-
* */
|
25
|
-
variant: string;
|
26
21
|
/**
|
27
22
|
* The tab element that is currently active
|
28
23
|
* */
|
29
24
|
activeTab?: GlideCoreTab;
|
25
|
+
isShowOverflowStartButton: boolean;
|
26
|
+
isShowOverflowEndButton: boolean;
|
30
27
|
panelElements: GlideCoreTabPanel[];
|
31
28
|
tabElements: GlideCoreTab[];
|
29
|
+
disconnectedCallback(): void;
|
32
30
|
firstUpdated(): void;
|
33
31
|
render(): import("lit").TemplateResult<1>;
|
34
32
|
updated(): void;
|
package/dist/tab.group.js
CHANGED
@@ -1 +1 @@
|
|
1
|
-
var __decorate=this&&this.__decorate||function(e,
|
1
|
+
var __decorate=this&&this.__decorate||function(t,e,o,i){var s,l=arguments.length,n=l<3?e:null===i?i=Object.getOwnPropertyDescriptor(e,o):i;if("object"==typeof Reflect&&"function"==typeof Reflect.decorate)n=Reflect.decorate(t,e,o,i);else for(var r=t.length-1;r>=0;r--)(s=t[r])&&(n=(l<3?s(n):l>3?s(e,o,n):s(e,o))||n);return l>3&&n&&Object.defineProperty(e,o,n),n};import"./icon-button.js";import{LitElement,html}from"lit";import{LocalizeController}from"./library/localize.js";import{createRef,ref}from"lit/directives/ref.js";import{customElement,queryAssignedElements,state}from"lit/decorators.js";import{when}from"lit/directives/when.js";import GlideCoreTab from"./tab.js";import GlideCoreTabPanel from"./tab.panel.js";import ow,{owSlotType}from"./library/ow.js";import styles from"./tab.group.styles.js";let GlideCoreTabGroup=class GlideCoreTabGroup extends LitElement{constructor(){super(...arguments),this.isShowOverflowStartButton=!1,this.isShowOverflowEndButton=!1,this.#t=100,this.#e=createRef(),this.#o=new LocalizeController(this),this.#i=createRef(),this.#s=createRef(),this.#l=createRef(),this.#n=null,this.#r=null,this.#a=null,this.#h=createRef(),this.#c=t=>{const e=t.target.closest("glide-core-tab");e&&e instanceof GlideCoreTab&&!e.disabled&&this.#u(e)},this.#f=()=>{this.#d("right",!0)},this.#b=()=>{this.#d("left",!0)},this.#v=t=>{const e=t.target.closest("glide-core-tab");if(["Enter"," "].includes(t.key)&&e&&e instanceof GlideCoreTab&&!e.disabled&&(this.#u(e),t.preventDefault()),["ArrowLeft","ArrowRight","ArrowUp","ArrowDown","Home","End"].includes(t.key)){const e=this.tabElements.find((t=>t.matches(":focus")));if("glide-core-tab"===e?.tagName.toLowerCase()){let o=this.tabElements.indexOf(e);switch(t.key){case"Home":o=0;break;case"End":o=this.tabElements.length-1;break;case"ArrowLeft":o--;break;case"ArrowRight":o++}if(o<0&&(o=this.tabElements.length-1),o>this.tabElements.length-1&&(o=0),this.tabElements[o].focus({preventScroll:!1}),this.#m(),this.isShowOverflowStartButton&&this.#l.value&&"ArrowLeft"===t.key){const t=Number.parseInt(window.getComputedStyle(document.documentElement).fontSize),e=this.#l.value?.getBoundingClientRect(),{right:i}=e,s=this.tabElements[o]?.getBoundingClientRect(),{right:l}=s;i>l-t&&this.#d("left")}if(this.isShowOverflowEndButton&&this.#s.value&&"ArrowRight"===t.key){const t=Number.parseInt(window.getComputedStyle(document.documentElement).fontSize),e=this.#s.value?.getBoundingClientRect(),{left:i}=e,s=this.tabElements[o]?.getBoundingClientRect(),{left:l}=s;i<l+t&&this.#d("right")}t.preventDefault()}}},this.#m=()=>{this.#w(),this.#E()}}static{this.shadowRootOptions={...LitElement.shadowRootOptions,mode:"closed"}}static{this.styles=styles}disconnectedCallback(){this.#n?.disconnect(),this.#n=null}firstUpdated(){owSlotType(this.#i.value,[GlideCoreTab]),owSlotType(this.#e.value,[GlideCoreTabPanel]),this.#p(),this.#g(),this.#T()}render(){return html`<div class="component" @click="${this.#c}" @keydown="${this.#v}"><div class="tab-container"><div class="overflow-button-container" style="height: ${this.#h.value?.clientHeight}px">${when(this.isShowOverflowStartButton,(()=>html`<button style="height: ${this.#h.value?.clientHeight}px" class="overflow" @click="${this.#b}" tabindex="-1" aria-label="${this.#o.term("previousTab")}" data-test="overflow-start-button" ${ref(this.#l)}><svg aria-hidden="true" width="18" height="18" viewBox="0 0 24 24" fill="none"><path d="M15 6L9 12L15 18" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"/></svg></button>`))}</div><div role="tablist" class="tab-group" ${ref(this.#h)} @scroll="${this.#R}"><slot name="nav" @slotchange="${this.#y}" ${ref(this.#i)}></slot></div><div class="overflow-button-container" style="height: ${this.#h.value?.clientHeight}px">${when(this.isShowOverflowEndButton,(()=>html`<button style="height: ${this.#h.value?.clientHeight}px" class="overflow" @click="${this.#f}" tabindex="-1" aria-label="${this.#o.term("nextTab")}" data-test="overflow-end-button" ${ref(this.#s)}><svg aria-hidden="true" width="18" height="18" 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></button>`))}</div></div><slot @slotchange="${this.#S}" ${ref(this.#e)}></slot></div>`}updated(){this.#p()}#t;#e;#o;#i;#s;#l;#n;#r;#a;#h;#c;#f;#b;#v;#m;#S(){owSlotType(this.#e.value,[GlideCoreTabPanel])}#y(){owSlotType(this.#i.value,[GlideCoreTab]),this.#m()}#R(){this.#a&&clearTimeout(this.#a),this.#a=setTimeout((()=>{this.#m()}),this.#t)}#d(t,e){const o="right"===t?1:-1;ow(this.#h.value,ow.object.instanceOf(HTMLElement));const i=o*this.#h.value?.clientWidth*.5;this.#h.value?.scrollBy({left:i,top:0,behavior:e?"smooth":"auto"})}#g(){for(const[t,e]of this.tabElements.entries()){let o;this.activeTab||0!==t?o=this.activeTab===e:(this.activeTab=e,o=!0),e.active=o}for(const t of this.panelElements){const e=this.activeTab?.getAttribute("panel"),o=t.getAttribute("name");t.isActive=o===e}}#E(){const t=this.#h.value,e=t?.getBoundingClientRect();ow(t,ow.object.instanceOf(HTMLElement));if(e){const{width:o}=e,i=t.scrollLeft+o,s=t.scrollWidth;this.isShowOverflowEndButton=s-i>1}}#w(){ow(this.#h.value,ow.object.instanceOf(HTMLElement)),this.isShowOverflowStartButton=this.#h.value.scrollLeft>0}#T(){this.#n=new ResizeObserver((t=>{t?.at(0)?.target===this.#h.value&&(this.#r&&clearTimeout(this.#r),this.#r=setTimeout((()=>{this.#m()}),this.#t))})),ow(this.#h.value,ow.object.instanceOf(HTMLElement)),this.#n.observe(this.#h.value)}#p(){for(const t of this.tabElements)for(const e of this.panelElements)t.setAttribute("aria-controls",e.getAttribute("id")),e.setAttribute("aria-labelledby",t.getAttribute("id"))}#u(t){this.activeTab=t,this.#g(),this.dispatchEvent(new CustomEvent("tab-show",{bubbles:!0,detail:{panel:t.panel}}))}};__decorate([state()],GlideCoreTabGroup.prototype,"activeTab",void 0),__decorate([state()],GlideCoreTabGroup.prototype,"isShowOverflowStartButton",void 0),__decorate([state()],GlideCoreTabGroup.prototype,"isShowOverflowEndButton",void 0),__decorate([queryAssignedElements()],GlideCoreTabGroup.prototype,"panelElements",void 0),__decorate([queryAssignedElements({slot:"nav"})],GlideCoreTabGroup.prototype,"tabElements",void 0),GlideCoreTabGroup=__decorate([customElement("glide-core-tab-group")],GlideCoreTabGroup);export default GlideCoreTabGroup;
|
package/dist/tab.group.styles.js
CHANGED
@@ -1,27 +1,41 @@
|
|
1
1
|
import{css}from"lit";export default[css`
|
2
2
|
.component {
|
3
|
+
background-color: transparent;
|
3
4
|
display: flex;
|
4
5
|
flex-direction: column;
|
5
6
|
|
6
|
-
|
7
|
-
|
7
|
+
& .tab-container {
|
8
|
+
border-block-end: 1px solid var(--glide-core-border-base-lighter);
|
9
|
+
display: flex;
|
10
|
+
|
11
|
+
& .overflow-button-container {
|
12
|
+
flex-shrink: 0;
|
13
|
+
inline-size: 1.875rem;
|
14
|
+
}
|
8
15
|
}
|
9
|
-
}
|
10
16
|
|
11
|
-
|
12
|
-
|
17
|
+
& .tab-group {
|
18
|
+
display: flex;
|
19
|
+
overflow: auto hidden;
|
20
|
+
scrollbar-width: none;
|
21
|
+
white-space: nowrap;
|
13
22
|
|
14
|
-
|
15
|
-
border-block-end: 1px solid var(--glide-core-border-primary);
|
16
|
-
}
|
23
|
+
/* "-webkit-scrollbar" is needed for Safari */
|
17
24
|
|
18
|
-
|
19
|
-
|
25
|
+
&::-webkit-scrollbar {
|
26
|
+
block-size: 0;
|
27
|
+
inline-size: 0;
|
28
|
+
}
|
20
29
|
}
|
21
30
|
|
22
|
-
|
23
|
-
|
24
|
-
|
31
|
+
& .overflow {
|
32
|
+
background-color: transparent;
|
33
|
+
border: none;
|
34
|
+
cursor: pointer;
|
35
|
+
inline-size: 1.875rem;
|
36
|
+
margin: 0;
|
37
|
+
outline: none;
|
38
|
+
padding: 0;
|
25
39
|
}
|
26
40
|
}
|
27
41
|
`];
|
@@ -1,3 +1,4 @@
|
|
1
|
+
/* eslint-disable @typescript-eslint/no-unused-expressions */
|
1
2
|
import './tab.group.js';
|
2
3
|
import './tab.js';
|
3
4
|
import './tab.panel.js';
|
@@ -8,6 +9,9 @@ import GlideCoreTabPanel from './tab.panel.js';
|
|
8
9
|
import expectArgumentError from './library/expect-argument-error.js';
|
9
10
|
GlideCoreTabGroup.shadowRootOptions.mode = 'open';
|
10
11
|
GlideCoreTabPanel.shadowRootOptions.mode = 'open';
|
12
|
+
function isPanelHidden(panel) {
|
13
|
+
return panel.shadowRoot?.firstElementChild?.classList.contains('hidden');
|
14
|
+
}
|
11
15
|
it('registers', async () => {
|
12
16
|
expect(window.customElements.get('glide-core-tab-group')).to.equal(GlideCoreTabGroup);
|
13
17
|
expect(window.customElements.get('glide-core-tab-panel')).to.equal(GlideCoreTabPanel);
|
@@ -22,39 +26,16 @@ it('renders correct markup and sets correct attributes for the default case', as
|
|
22
26
|
await expect(tabGroup).to.be.accessible();
|
23
27
|
const [firstTab] = tabGroup.tabElements;
|
24
28
|
expect(tabGroup.activeTab).to.equal(firstTab, 'activeTab defaults to first tab');
|
25
|
-
expect(tabGroup.variant).to.equal('primary');
|
26
29
|
expect([...tabGroup.shadowRoot.firstElementChild.classList]).to.deep.equal([
|
27
30
|
'component',
|
28
31
|
]);
|
29
32
|
expect([
|
30
33
|
...tabGroup.shadowRoot.querySelector('.tab-group').classList,
|
31
|
-
]).to.deep.equal(['tab-group'
|
34
|
+
]).to.deep.equal(['tab-group']);
|
32
35
|
const slot = tabGroup.shadowRoot.querySelector('slot:not([name="nav"])');
|
33
36
|
expect(slot).to.exist;
|
34
37
|
expect(slot.assignedElements.length).to.equal(0);
|
35
38
|
});
|
36
|
-
it('renders a secondary variant', async () => {
|
37
|
-
const element = await fixture(html `
|
38
|
-
<glide-core-tab-group variant="secondary">
|
39
|
-
<glide-core-tab slot="nav" panel="1">Tab 1</glide-core-tab>
|
40
|
-
<glide-core-tab-panel name="1">Content for Tab 1</glide-core-tab-panel>
|
41
|
-
</glide-core-tab-group>
|
42
|
-
`);
|
43
|
-
expect([
|
44
|
-
...element.shadowRoot.querySelector('.tab-group').classList,
|
45
|
-
]).to.deep.equal(['tab-group', 'secondary']);
|
46
|
-
});
|
47
|
-
it('renders a vertical variant', async () => {
|
48
|
-
const element = await fixture(html `
|
49
|
-
<glide-core-tab-group variant="vertical">
|
50
|
-
<glide-core-tab slot="nav" panel="1">Tab 1</glide-core-tab>
|
51
|
-
<glide-core-tab-panel name="1">Content for Tab 1</glide-core-tab-panel>
|
52
|
-
</glide-core-tab-group>
|
53
|
-
`);
|
54
|
-
expect([
|
55
|
-
...element.shadowRoot.querySelector('.tab-group').classList,
|
56
|
-
]).to.deep.equal(['tab-group', 'vertical']);
|
57
|
-
});
|
58
39
|
it('can switch tabs', async () => {
|
59
40
|
const tabGroup = await fixture(html `
|
60
41
|
<glide-core-tab-group>
|
@@ -133,37 +114,10 @@ it('can use left/right, home and end keys to focus on tabs', async () => {
|
|
133
114
|
await sendKeys({ press: 'Enter' });
|
134
115
|
expect(thirdTab.active).to.equal(true);
|
135
116
|
});
|
136
|
-
it('can use up/down keys to focus on vertical tabs', async () => {
|
137
|
-
const tabGroup = await fixture(html `
|
138
|
-
<glide-core-tab-group variant="vertical">
|
139
|
-
<glide-core-tab slot="nav" panel="1">Tab 1</glide-core-tab>
|
140
|
-
<glide-core-tab slot="nav" panel="2">Tab 2</glide-core-tab>
|
141
|
-
<glide-core-tab slot="nav" panel="3">Tab 3</glide-core-tab>
|
142
|
-
|
143
|
-
<glide-core-tab-panel name="1">Content for Tab 1</glide-core-tab-panel>
|
144
|
-
<glide-core-tab-panel name="2">Content for Tab 2</glide-core-tab-panel>
|
145
|
-
<glide-core-tab-panel name="3">Content for Tab 3</glide-core-tab-panel>
|
146
|
-
</glide-core-tab-group>
|
147
|
-
`);
|
148
|
-
const [firstTab, secondTab, thirdTab] = tabGroup.tabElements;
|
149
|
-
firstTab.focus();
|
150
|
-
await sendKeys({ press: 'ArrowDown' });
|
151
|
-
await sendKeys({ press: 'Enter' });
|
152
|
-
expect(secondTab.active).to.equal(true, 'down works');
|
153
|
-
await sendKeys({ press: 'ArrowUp' });
|
154
|
-
await sendKeys({ press: 'Enter' });
|
155
|
-
expect(firstTab.active).to.equal(true, 'up works');
|
156
|
-
await sendKeys({ press: 'ArrowUp' });
|
157
|
-
await sendKeys({ press: 'Enter' });
|
158
|
-
expect(thirdTab.active).to.equal(true, 'up from first goes to last');
|
159
|
-
await sendKeys({ press: 'ArrowDown' });
|
160
|
-
await sendKeys({ press: 'Enter' });
|
161
|
-
expect(firstTab.active).to.equal(true, 'down from last goes to first');
|
162
|
-
});
|
163
117
|
it('throws an error when an element other than `glide-core-tab` is a child of the `nav` slot', async () => {
|
164
118
|
await expectArgumentError(() => {
|
165
119
|
return fixture(html `
|
166
|
-
<glide-core-tab-group
|
120
|
+
<glide-core-tab-group>
|
167
121
|
<div slot="nav">Tab 1</div>
|
168
122
|
<glide-core-tab-panel name="1">Content for Tab 1</glide-core-tab-panel>
|
169
123
|
</glide-core-tab-group>
|
@@ -173,13 +127,10 @@ it('throws an error when an element other than `glide-core-tab` is a child of th
|
|
173
127
|
it('throws an error when an element other than `glide-core-tab-panel` is a child of the default slot', async () => {
|
174
128
|
await expectArgumentError(() => {
|
175
129
|
return fixture(html `
|
176
|
-
<glide-core-tab-group
|
130
|
+
<glide-core-tab-group>
|
177
131
|
<glide-core-tab slot="nav" panel="1">Tab 1</glide-core-tab>
|
178
132
|
<div>Default Content</div>
|
179
133
|
</glide-core-tab-group>
|
180
134
|
`);
|
181
135
|
});
|
182
136
|
});
|
183
|
-
function isPanelHidden(panel) {
|
184
|
-
return panel.shadowRoot?.firstElementChild?.classList.contains('hidden');
|
185
|
-
}
|