@postnord/web-components
Version:
PostNord Web Components
501 lines (500 loc) • 19.5 kB
JavaScript
/*!
* 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
}
}];
}
}