UNPKG

@postnord/web-components

Version:
501 lines (500 loc) 19.5 kB
/*! * Built with Stencil * By PostNord. */ import { h, Host, forceUpdate } from "@stencil/core"; import { alert_exclamation_circle, chevron_down } from "pn-design-assets/pn-assets/icons.js"; import { uuidv4 } from "../../../index"; /** * The `pn-select` uses a native `select` element under the hood. * Use the slot to include `option` elements. * * Just like a regular `select`, you can use the `selected` prop on the nested option elements to preselect an option. * * @slot - This is the default slot, where the `option` elements go. * @slot helpertext - You can use this slot instead of the prop `helpertext`. Recommended, only if you need to include additional HTML markup. Such as a `pn-text-link`. Use a `span` element to wrap the text and link. {@since v7.25.0} * @slot error - You can use this slot instead of the prop `error`. Recommended, only if you need to include additional HTML markup. Such as a `pn-text-link`. Use a `span` element to wrap the text and link. {@since v7.25.0} * * @nativeChange Use the `change` event to listen to changes on the select element. */ export class PnSelect { id = `pn-select-${uuidv4()}`; idHelper = `${this.id}-text`; idError = `${this.id}-error`; mo; hostElement; /** Label placed above the select. */ label; /** Display a helper text underneath the select. */ helpertext; /** HTML select name. @category Native attributes */ name; /** HTML form name. @category Native attributes */ form; /** HTML autocomplete. @category Native attributes */ autocomplete; /** Set the select as required. @category Native attributes */ required = false; /** Disable the select. @category Native attributes */ disabled = false; /** Use the compact label variant. @since v7.21.0 @category Features */ compact = false; /** Display an icon to the left of the select input. @category Features */ icon; /** Trigger the invalid state. @category Features */ invalid = false; /** Display an error message and trigger the invalid state. @category Features */ error; /** Set a custom ID for the select. @since v7.25.0 @category HTML attributes */ pnId; /** * Provide the label via an aria attribute. * We strongly recommend you use the `label` prop instead. * @since v7.25.0 * @category HTML attributes */ pnAriaLabel; /** * Provide the label from another element via its ID. * We strongly recommend you use the `label` prop instead. * @since v7.25.0 * @category HTML attributes */ pnAriaLabelledby; /** Set a custom ID for the select. @deprecated Use `pn-id` instead. @category HTML attributes */ selectId; handleId() { this.idHelper = `${this.getId()}-text`; this.idError = `${this.getId()}-error`; } connectedCallback() { this.mo = new MutationObserver(() => forceUpdate(this.hostElement)); this.mo.observe(this.hostElement, { childList: true, subtree: true }); } disconnectedCallback() { if (this.mo) this.mo.disconnect(); } hasHelperText() { return this.helpertext?.length > 0 || this.checkSlottedHelper(); } /** If any `error` text is present, either via prop/slot. */ hasErrorMessage() { return this.error?.length > 0 || this.checkSlottedError(); } /** If any `error` is active, either via the prop `invalid` or `error` prop/slot. */ hasError() { return this.hasErrorMessage() || this.invalid || this.checkSlottedError(); } checkSlottedHelper() { return !!this.hostElement.querySelector('[slot=helpertext]'); } checkSlottedError() { return !!this.hostElement.querySelector('[slot=error]'); } hideHelpertext() { return this.hasErrorMessage() || !this.hasHelperText(); } hideError() { return !this.hasErrorMessage(); } getId() { return this.pnId || this.selectId || this.id; } displayLabel() { return !!this.label; } getAriaLabel() { return !this.displayLabel() && !this.pnAriaLabelledby ? this.pnAriaLabel : null; } getAriaLabelledby() { return !this.displayLabel() && !this.pnAriaLabel ? this.pnAriaLabelledby : null; } getAriaDescribedby() { const list = []; if (this.hasErrorMessage()) list.push(this.idError); else if (this.hasHelperText()) list.push(this.idHelper); return list.length ? list.join(' ') : null; } renderLabel() { if (!this.label) return null; return (h("label", { htmlFor: this.getId(), class: "pn-select-label", "data-compact": this.compact, "data-icon": !!this.icon }, h("span", null, this.label))); } render() { return (h(Host, { key: 'c00c913a1786719ef71800ed15adaf0dd47577ff' }, h("div", { key: 'c2ee0553f2c130e12e7bc5bcfb611d457071cdec', class: "pn-select", "data-error": this.hasError() }, !this.compact && this.renderLabel(), h("div", { key: '7e8d7a1ab89e30b870883ff50bec31dd2a38690d', class: "pn-select-input" }, this.icon && h("pn-icon", { key: '772eb356db3cdf4fd04a67e1666ddb98799d40c0', class: "pn-select-icon", icon: this.icon, "data-custom": true, "aria-hidden": "true" }), this.hasError() && (h("pn-icon", { key: '03ccbd0952abb83cc4828ad6bfca777e1544f7a6', class: "pn-select-icon", icon: alert_exclamation_circle, color: "warning", "data-error": true, "aria-hidden": "true" })), h("select", { key: '46db113874c38b6f2ae6a42fbc63d9a9654a9dc1', id: this.getId(), class: "pn-select-element", name: this.name, form: this.form, autocomplete: this.autocomplete, "aria-label": this.getAriaLabel(), "aria-labelledby": this.getAriaLabelledby(), "aria-describedby": this.getAriaDescribedby(), "aria-invalid": this.hasError().toString(), disabled: this.disabled, "data-compact": this.compact }, h("slot", { key: '8253ace83c8f6454d8bae7550895768d4e53f809' })), this.compact && this.renderLabel(), h("pn-icon", { key: '88b094bd13b0d9cf912103427722e8be9ea2b687', class: "pn-select-icon", icon: chevron_down, color: "blue700", "data-default": true, "aria-hidden": "true" })), h("p", { key: '03009e2b484ade6fadb9e20f161cfc50964db43a', id: this.idHelper, class: "pn-select-text", hidden: this.hideHelpertext() }, h("span", { key: '2620e53c70c4ab95efc9924faa1a3ea298ec741b' }, this.helpertext), h("slot", { key: 'bd9798ba17632021ce177292cc022f57ae52193f', name: "helpertext" })), h("p", { key: '6ba88b6a3884430e7c263803ece5000adb08abe7', id: this.idError, class: "pn-select-text", role: "alert", hidden: this.hideError() }, h("span", { key: 'dcc53f692bce2eaa5460075b9a1e191f29a777ad' }, this.error), h("slot", { key: '0cf932dadffd1df3958e400a08c090483fc7c397', name: "error" }))))); } static get is() { return "pn-select"; } static get originalStyleUrls() { return { "$": ["pn-select.scss"] }; } static get styleUrls() { return { "$": ["pn-select.css"] }; } static get properties() { return { "label": { "type": "string", "mutable": false, "complexType": { "original": "string", "resolved": "string", "references": {} }, "required": false, "optional": true, "docs": { "tags": [], "text": "Label placed above the select." }, "getter": false, "setter": false, "reflect": false, "attribute": "label" }, "helpertext": { "type": "string", "mutable": false, "complexType": { "original": "string", "resolved": "string", "references": {} }, "required": false, "optional": true, "docs": { "tags": [], "text": "Display a helper text underneath the select." }, "getter": false, "setter": false, "reflect": false, "attribute": "helpertext" }, "name": { "type": "string", "mutable": false, "complexType": { "original": "string", "resolved": "string", "references": {} }, "required": false, "optional": false, "docs": { "tags": [{ "name": "category", "text": "Native attributes" }], "text": "HTML select name." }, "getter": false, "setter": false, "reflect": false, "attribute": "name" }, "form": { "type": "string", "mutable": false, "complexType": { "original": "string", "resolved": "string", "references": {} }, "required": false, "optional": false, "docs": { "tags": [{ "name": "category", "text": "Native attributes" }], "text": "HTML form name." }, "getter": false, "setter": false, "reflect": false, "attribute": "form" }, "autocomplete": { "type": "string", "mutable": false, "complexType": { "original": "string", "resolved": "string", "references": {} }, "required": false, "optional": false, "docs": { "tags": [{ "name": "category", "text": "Native attributes" }], "text": "HTML autocomplete." }, "getter": false, "setter": false, "reflect": false, "attribute": "autocomplete" }, "required": { "type": "boolean", "mutable": false, "complexType": { "original": "boolean", "resolved": "boolean", "references": {} }, "required": false, "optional": true, "docs": { "tags": [{ "name": "category", "text": "Native attributes" }], "text": "Set the select as required." }, "getter": false, "setter": false, "reflect": false, "attribute": "required", "defaultValue": "false" }, "disabled": { "type": "boolean", "mutable": false, "complexType": { "original": "boolean", "resolved": "boolean", "references": {} }, "required": false, "optional": true, "docs": { "tags": [{ "name": "category", "text": "Native attributes" }], "text": "Disable the select." }, "getter": false, "setter": false, "reflect": false, "attribute": "disabled", "defaultValue": "false" }, "compact": { "type": "boolean", "mutable": false, "complexType": { "original": "boolean", "resolved": "boolean", "references": {} }, "required": false, "optional": true, "docs": { "tags": [{ "name": "since", "text": "v7.21.0" }, { "name": "category", "text": "Features" }], "text": "Use the compact label variant." }, "getter": false, "setter": false, "reflect": false, "attribute": "compact", "defaultValue": "false" }, "icon": { "type": "string", "mutable": false, "complexType": { "original": "string", "resolved": "string", "references": {} }, "required": false, "optional": true, "docs": { "tags": [{ "name": "category", "text": "Features" }], "text": "Display an icon to the left of the select input." }, "getter": false, "setter": false, "reflect": false, "attribute": "icon" }, "invalid": { "type": "boolean", "mutable": false, "complexType": { "original": "boolean", "resolved": "boolean", "references": {} }, "required": false, "optional": true, "docs": { "tags": [{ "name": "category", "text": "Features" }], "text": "Trigger the invalid state." }, "getter": false, "setter": false, "reflect": false, "attribute": "invalid", "defaultValue": "false" }, "error": { "type": "string", "mutable": false, "complexType": { "original": "string", "resolved": "string", "references": {} }, "required": false, "optional": true, "docs": { "tags": [{ "name": "category", "text": "Features" }], "text": "Display an error message and trigger the invalid state." }, "getter": false, "setter": false, "reflect": false, "attribute": "error" }, "pnId": { "type": "string", "mutable": false, "complexType": { "original": "string", "resolved": "string", "references": {} }, "required": false, "optional": true, "docs": { "tags": [{ "name": "since", "text": "v7.25.0" }, { "name": "category", "text": "HTML attributes" }], "text": "Set a custom ID for the select." }, "getter": false, "setter": false, "reflect": false, "attribute": "pn-id" }, "pnAriaLabel": { "type": "string", "mutable": false, "complexType": { "original": "string", "resolved": "string", "references": {} }, "required": false, "optional": true, "docs": { "tags": [{ "name": "since", "text": "v7.25.0" }, { "name": "category", "text": "HTML attributes" }], "text": "Provide the label via an aria attribute.\nWe strongly recommend you use the `label` prop instead." }, "getter": false, "setter": false, "reflect": false, "attribute": "pn-aria-label" }, "pnAriaLabelledby": { "type": "string", "mutable": false, "complexType": { "original": "string", "resolved": "string", "references": {} }, "required": false, "optional": true, "docs": { "tags": [{ "name": "since", "text": "v7.25.0" }, { "name": "category", "text": "HTML attributes" }], "text": "Provide the label from another element via its ID.\nWe strongly recommend you use the `label` prop instead." }, "getter": false, "setter": false, "reflect": false, "attribute": "pn-aria-labelledby" }, "selectId": { "type": "string", "mutable": false, "complexType": { "original": "string", "resolved": "string", "references": {} }, "required": false, "optional": true, "docs": { "tags": [{ "name": "deprecated", "text": "Use `pn-id` instead." }, { "name": "category", "text": "HTML attributes" }], "text": "Set a custom ID for the select." }, "getter": false, "setter": false, "reflect": false, "attribute": "select-id" } }; } static get elementRef() { return "hostElement"; } static get watchers() { return [{ "propName": "selectId", "methodName": "handleId" }, { "propName": "pnId", "methodName": "handleId", "handlerOptions": { "immediate": true } }]; } }