UNPKG

@postnord/web-components

Version:
356 lines (355 loc) 13.4 kB
/*! * Built with Stencil * By PostNord. */ import { h, Host, forceUpdate, transformTag } from "@stencil/core"; import { ripple } from "../../../../globals/helpers"; /** * This tab should control a tab panel. * Use the `ariacontrols` and `tabid` props to connect the tab with the tab panel. * The tab panel should in turn have `aria-labelledby` set to the `tabid` of the tab. * * If you use the `href` prop, the tab will turn into an anchor element instead of a button. * This does not required the ariacontrols and tabid props. */ export class PnTab { mo; tag = 'button'; hostElement; /** Set a label for the tab. */ label; /** This is the value that will be matched with `pn-tablist` value. (required) */ value; /** Turns the tab from a `button` to an `a` element, but only if the `pn-tablist` is inside a `pn-header`. */ href; /** The SVG content of the icon you want to display */ icon; /** Use the ID of the container that this tab controls. */ ariacontrols; /** Tab ID, use if you want to have the tab container be `aria-labelledby` by this tab. */ tabid; /** Is set by `pn-tablist`, don't use this prop. @hide true */ activeTab; /** Used by `pn-tab` to communicate with `pn-tablist`. Emits the selected tab value and element. */ setActiveTab; setActiveTabHandler({ click = false, element } = {}) { if (click || this.isActive()) { const val = element?.value || this.value; const el = ((element?.value && element) || this.hostElement); this.setActiveTab.emit({ val, el, }); } } /** Used by `pn-tab` to communicate with `pn-tablist`. Emits when the tab gets focus. */ tabEnter; triggerEnter(event) { this.tabEnter.emit(event); } /** Used by `pn-tab` to communicate with `pn-tablist`. Emits when the tab is blured. */ tabLeave; triggerLeave(event) { this.tabLeave.emit(event); } connectedCallback() { this.mo = new MutationObserver(() => forceUpdate(this.hostElement)); this.mo.observe(this.hostElement, { subtree: true, childList: true }); } disconnectedCallback() { this.mo?.disconnect(); } componentWillLoad() { this.tabTag(); } componentDidUpdate() { this.setActiveTabHandler(); } componentDidLoad() { this.setActiveTabHandler(); } arrowKeyNav(event) { if (!/^(ArrowRight|ArrowLeft|Home|End)$/.test(event.key)) return; const tabName = transformTag('pn-tab'); const tablistName = transformTag('pn-tablist'); event.preventDefault(); // Get tablist parent const parent = event.target.closest(tablistName); if (!parent) return; const list = Array.from(parent.querySelectorAll(tabName)); const first = list[0]; const last = list[list.length - 1]; const nextElement = this.hostElement.nextElementSibling; const previousElement = this.hostElement.previousElementSibling; if (event.key === 'Home') this.setActiveTabHandler({ element: first }); if (event.key === 'End') this.setActiveTabHandler({ element: last }); if (event.key === 'ArrowRight') { // Check the next element value. We do this because the last element i a DIV element. If no value, go to the first element. this.setActiveTabHandler({ element: nextElement?.value ? nextElement : first }); } if (event.key === 'ArrowLeft') { // Go to the last element if there is no element to your left. this.setActiveTabHandler({ element: previousElement?.value ? previousElement : last }); } } isActive() { return this.activeTab === this.value; } tabTag() { const tablistName = transformTag('pn-tablist'); const isMenu = this.hostElement.closest(tablistName); this.tag = isMenu?.slot === 'menu' ? 'a' : 'button'; } renderProperties() { return this.tag === 'a' ? { 'href': this.href, 'aria-current': this.isActive() ? 'page' : 'false', } : { 'tabindex': this.isActive() ? 0 : -1, 'type': 'button', 'role': 'tab', 'aria-selected': this.isActive().toString(), 'aria-controls': this.ariacontrols, }; } iconColor() { return this.isActive() ? 'blue700' : 'gray900'; } handleClick(e) { this.setActiveTabHandler({ click: true }); ripple(e, this.hostElement, '.pn-tab'); } render() { const Tag = this.tag; return (h(Host, { key: '37a1d2234aa0d4fe1f5f1af6f8334f9e4109eff6' }, h(Tag, { key: '17e8e25c54b556f65b7c98ac4eaef07f1bc131ac', id: this.tabid, class: "pn-tab", ...this.renderProperties(), onClick: (e) => this.handleClick(e), onMouseEnter: (e) => this.triggerEnter(e), onFocus: (e) => this.triggerEnter(e), onMouseLeave: (e) => this.triggerLeave(e), onBlur: (e) => this.triggerLeave(e), onKeyDown: (e) => this.arrowKeyNav(e) }, !!this.icon && h("pn-icon", { key: '42c7473fd8b573ec47e8e2074a4ded3ff3e40249', icon: this.icon, color: this.iconColor() }), h("slot", { key: 'c39be583c461850d49f7e5a96c071c80b7b132da' }), h("span", { key: 'ce995d860775c71e8fda7dc4e94c2a7896759f62', class: "pn-tab-label" }, this.label)))); } static get is() { return "pn-tab"; } static get originalStyleUrls() { return { "$": ["pn-tab.scss"] }; } static get styleUrls() { return { "$": ["pn-tab.css"] }; } static get properties() { return { "label": { "type": "string", "mutable": false, "complexType": { "original": "string", "resolved": "string", "references": {} }, "required": true, "optional": false, "docs": { "tags": [], "text": "Set a label for the tab." }, "getter": false, "setter": false, "reflect": false, "attribute": "label" }, "value": { "type": "string", "mutable": false, "complexType": { "original": "string", "resolved": "string", "references": {} }, "required": true, "optional": false, "docs": { "tags": [], "text": "This is the value that will be matched with `pn-tablist` value. (required)" }, "getter": false, "setter": false, "reflect": false, "attribute": "value" }, "href": { "type": "string", "mutable": false, "complexType": { "original": "string", "resolved": "string", "references": {} }, "required": false, "optional": true, "docs": { "tags": [], "text": "Turns the tab from a `button` to an `a` element, but only if the `pn-tablist` is inside a `pn-header`." }, "getter": false, "setter": false, "reflect": false, "attribute": "href" }, "icon": { "type": "string", "mutable": false, "complexType": { "original": "string", "resolved": "string", "references": {} }, "required": false, "optional": true, "docs": { "tags": [], "text": "The SVG content of the icon you want to display" }, "getter": false, "setter": false, "reflect": false, "attribute": "icon" }, "ariacontrols": { "type": "string", "mutable": false, "complexType": { "original": "string", "resolved": "string", "references": {} }, "required": false, "optional": true, "docs": { "tags": [], "text": "Use the ID of the container that this tab controls." }, "getter": false, "setter": false, "reflect": false, "attribute": "ariacontrols" }, "tabid": { "type": "string", "mutable": false, "complexType": { "original": "string", "resolved": "string", "references": {} }, "required": false, "optional": true, "docs": { "tags": [], "text": "Tab ID, use if you want to have the tab container be `aria-labelledby` by this tab." }, "getter": false, "setter": false, "reflect": false, "attribute": "tabid" }, "activeTab": { "type": "string", "mutable": false, "complexType": { "original": "string", "resolved": "string", "references": {} }, "required": false, "optional": false, "docs": { "tags": [{ "name": "hide", "text": "true" }], "text": "Is set by `pn-tablist`, don't use this prop." }, "getter": false, "setter": false, "reflect": false, "attribute": "active-tab" } }; } static get events() { return [{ "method": "setActiveTab", "name": "setActiveTab", "bubbles": true, "cancelable": true, "composed": true, "docs": { "tags": [], "text": "Used by `pn-tab` to communicate with `pn-tablist`. Emits the selected tab value and element." }, "complexType": { "original": "{ val: string; el: HTMLElement }", "resolved": "{ val: string; el: HTMLElement; }", "references": { "HTMLElement": { "location": "global", "id": "global::HTMLElement" } } } }, { "method": "tabEnter", "name": "tabEnter", "bubbles": true, "cancelable": true, "composed": true, "docs": { "tags": [], "text": "Used by `pn-tab` to communicate with `pn-tablist`. Emits when the tab gets focus." }, "complexType": { "original": "MouseEvent | FocusEvent", "resolved": "FocusEvent | MouseEvent", "references": { "MouseEvent": { "location": "global", "id": "global::MouseEvent" }, "FocusEvent": { "location": "global", "id": "global::FocusEvent" } } } }, { "method": "tabLeave", "name": "tabLeave", "bubbles": true, "cancelable": true, "composed": true, "docs": { "tags": [], "text": "Used by `pn-tab` to communicate with `pn-tablist`. Emits when the tab is blured." }, "complexType": { "original": "MouseEvent | FocusEvent", "resolved": "FocusEvent | MouseEvent", "references": { "MouseEvent": { "location": "global", "id": "global::MouseEvent" }, "FocusEvent": { "location": "global", "id": "global::FocusEvent" } } } }]; } static get elementRef() { return "hostElement"; } }