UNPKG

@postnord/web-components

Version:

PostNord Web Components

275 lines (274 loc) 10.5 kB
/*! * Built with Stencil * By PostNord. */ import { h, Host } from "@stencil/core"; import { uuidv4 } from "../../../index"; /** * The open/closing of the dropdown is handled by the component itself. * * @nativeClick Use the `click` event to listen when the button is clicked. */ export class PnButtonDropdown { id = `pn-button-${uuidv4()}`; focusableElements; container; dropdownButtonId = `${this.id}-dropdown`; dropdownContentId = `${this.id}-content`; hostElement; right = false; top = false; /** The required label on the button. */ label; /** The optional SVG content of the icon you want. */ icon; /** Select between `light` and `warning`. */ appearance = ''; /** Select between `outlined` and `borderless`. */ variant = ''; /** Smaller button. */ small = false; /** Tooltip (required for Icon Only). */ tooltip; /** Open/close the dropdown without user interaction. */ open = false; openHandler() { this.toggleDropdown(); if (this.open) { document.addEventListener('click', this.globalHandler); document.addEventListener('keyup', this.globalHandler); } else { document.removeEventListener('click', this.globalHandler); document.removeEventListener('keyup', this.globalHandler); } } componentDidLoad() { if (this.open) this.openHandler(); } getRect(element) { return element.getBoundingClientRect(); } globalHandler = (e) => { // global events that we want to track to close the select, like "click outside" or tab out if (!this.hostElement.contains(e.target) || e?.key === 'Escape') { this.open = false; } }; toggleDropdown() { this.right = this.hostElement.offsetLeft > window.innerWidth / 2; requestAnimationFrame(() => { if (this.open) { this.container.style.transition = 'none'; this.container.style.transform = 'none'; } const containerRect = this.getRect(this.container); const hostElementRect = this.getRect(this.hostElement); // Calculate if dropdown should open upwards // if there is enough space above button const enoughSpaceAbove = hostElementRect.top > containerRect.height + window.innerWidth * 0.025; this.top = enoughSpaceAbove && hostElementRect.top + hostElementRect.height + containerRect.height > window.innerHeight - window.innerWidth * 0.025; let xAxis = 0; if (containerRect.right > window.innerWidth || containerRect.x < 0) { // 0.025 because the max width of the element is 95vw and we want the same margin on both sides xAxis = containerRect.x + containerRect.width + window.innerWidth * 0.025 - window.innerWidth; } this.container.style.transform = ''; requestAnimationFrame(() => { this.container.style.transition = ''; this.container.style.transform = this.open ? `scale(1) translateX(-${xAxis}px)` : ''; requestAnimationFrame(() => { this.hostElement.querySelector('.pn-button-dropdown').dataset.open = `${this.open}`; }); }); }); } toggle = () => { this.open = !this.open; }; render() { return (h(Host, { key: '7398ec85382fc0abe7b81849e739a7bc26bdd084' }, h("div", { key: '6ca6e2a0f28ce2fb03e0a2eca02309dbc50cbabb', class: "pn-button-dropdown" }, h("pn-button", { key: '629cec46e4cdf9cd346ff4160596cf255dea6187', label: this.label, buttonId: this.dropdownButtonId, class: "pn-button-dropdown-label", appearance: this.appearance, variant: this.variant, small: this.small, icon: this.icon, ariacontrols: this.dropdownContentId, ariahaspopup: "true", ariaexpanded: this.open.toString(), onPnClick: this.toggle, tooltip: this.tooltip, tooltipUp: !this.top, iconOnly: !!this.tooltip && !!this.icon && !this.label }), h("div", { key: '51c980101ab122802f27634488b2ae6ef6c59ced', ref: el => (this.container = el), id: this.dropdownContentId, class: "pn-button-dropdown-container", role: "region", "aria-labelledby": this.dropdownButtonId, "data-right": this.right, "data-top": this.top }, h("div", { key: 'e6d703cfcc8e123b4e84e98fb4e7471911bc28bb', class: "pn-button-dropdown-content" }, h("slot", { key: 'ee5450952fb2c7df077cb56debcd7873cfc86739' })))))); } static get is() { return "pn-button-dropdown"; } static get originalStyleUrls() { return { "$": ["pn-button-dropdown.scss"] }; } static get styleUrls() { return { "$": ["pn-button-dropdown.css"] }; } static get properties() { return { "label": { "type": "string", "mutable": false, "complexType": { "original": "string", "resolved": "string", "references": {} }, "required": true, "optional": false, "docs": { "tags": [], "text": "The required label on the button." }, "getter": false, "setter": false, "attribute": "label", "reflect": false }, "icon": { "type": "string", "mutable": false, "complexType": { "original": "string", "resolved": "string", "references": {} }, "required": false, "optional": true, "docs": { "tags": [], "text": "The optional SVG content of the icon you want." }, "getter": false, "setter": false, "attribute": "icon", "reflect": false }, "appearance": { "type": "string", "mutable": false, "complexType": { "original": "PnButtonAppearance", "resolved": "\"\" | \"light\" | \"warning\"", "references": { "PnButtonAppearance": { "location": "import", "path": "@/index", "id": "src/index.ts::PnButtonAppearance" } } }, "required": false, "optional": true, "docs": { "tags": [], "text": "Select between `light` and `warning`." }, "getter": false, "setter": false, "attribute": "appearance", "reflect": false, "defaultValue": "''" }, "variant": { "type": "string", "mutable": false, "complexType": { "original": "PnButtonVariant", "resolved": "\"\" | \"borderless\" | \"outlined\"", "references": { "PnButtonVariant": { "location": "import", "path": "@/index", "id": "src/index.ts::PnButtonVariant" } } }, "required": false, "optional": true, "docs": { "tags": [], "text": "Select between `outlined` and `borderless`." }, "getter": false, "setter": false, "attribute": "variant", "reflect": false, "defaultValue": "''" }, "small": { "type": "boolean", "mutable": false, "complexType": { "original": "boolean", "resolved": "boolean", "references": {} }, "required": false, "optional": false, "docs": { "tags": [], "text": "Smaller button." }, "getter": false, "setter": false, "attribute": "small", "reflect": false, "defaultValue": "false" }, "tooltip": { "type": "string", "mutable": false, "complexType": { "original": "string", "resolved": "string", "references": {} }, "required": false, "optional": false, "docs": { "tags": [], "text": "Tooltip (required for Icon Only)." }, "getter": false, "setter": false, "attribute": "tooltip", "reflect": false }, "open": { "type": "boolean", "mutable": true, "complexType": { "original": "boolean", "resolved": "boolean", "references": {} }, "required": false, "optional": false, "docs": { "tags": [], "text": "Open/close the dropdown without user interaction." }, "getter": false, "setter": false, "attribute": "open", "reflect": true, "defaultValue": "false" } }; } static get states() { return { "right": {}, "top": {} }; } static get elementRef() { return "hostElement"; } static get watchers() { return [{ "propName": "open", "methodName": "openHandler" }]; } } //# sourceMappingURL=pn-button-dropdown.js.map