@postnord/web-components
Version:
PostNord Web Components
356 lines (355 loc) • 13.4 kB
JavaScript
/*!
* 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"; }
}