@postnord/web-components
Version:
PostNord Web Components
588 lines (587 loc) • 24 kB
JavaScript
/*!
* Built with Stencil
* By PostNord.
*/
import { uuidv4 } from "../../../globals/helpers";
import { h, Host, Mixin } from "@stencil/core";
import { animateHeightFactory } from "../../../globals/mixins/index";
/**
* The `pn-checkbox` is built with a native `input[type="checkbox"]` in the background.
* This means you can use native events to listen to the changes.
*
* @nativeChange Use the `change` event to listen when the checkbox state is being toggled.
*
* @slot - The default slot for adding custom HTML under the label/helpertext. {@since v7.17.0}
* @slot helpertext - Use this slot to add custom HTML inside of the helpertext element.
* Only recommended if you need a link without the `tile` prop. {@since v7.17.0}
* @slot content - When using the `tile` and `expand` props, this slot will be revealed when the input is checked. {@since v7.17.0}
*/
export class PnCheckbox extends Mixin(animateHeightFactory) {
constructor() {
super();
}
id = `pn-checkbox-${uuidv4()}`;
idHelpertext = `${this.id}-helpertext`;
contentArea;
hostElement;
/** The checkbox label, this is required for the checkbox to be 100% accessible out of the box. */
label;
/** This adds an optional helpertext under the label. */
helpertext;
/** This will be emitted on change and input events. @category Native attributes */
value;
/** The name of the checkbox group. @category Native attributes */
name;
/** Programmatically check the input. @category Native attributes */
checked = false;
/** Set the checkbox as required. @category Native attributes */
required = false;
/** Disable the checkbox. @category Native attributes */
disabled = false;
/**
* If set to true, color scheme will turn red, indicating that there is an issue related to the checkbox.
* @category Native attributes
*/
invalid = false;
/**
* Sets the checkbox to an indeterminate state, allowing for a mixed or intermediate checkbox state.
* @category Native attributes
*/
indeterminate = false;
/**
* Turn the checkbox into a clickable tile. A border and padding is added.
*
* **Do not** use interactive elements (links/buttons) inside of the slots when using this prop.
* An exception is made when using the `tile` + `expand` props together,
* which allows you to use interactive elements.
*
* @category Features
*/
tile = false;
/**
* Allow the checkbox to control the slot area "content".
* When checked, the area is visible, when unchecked, the area is hidden.
*
* The prop `tile` must be used at the same time.
* @see {@link tile}
* @since v7.17.0
* @category Features
*/
expand = false;
/**
* Add an icon on the right of your checkbox tile. The `tile` prop must be `true` for the icon to work.
* @see {@link tile}
* @category Features
*/
icon = null;
/** A unique HTML ID for the checkbox. @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;
/** A unique HTML ID for the checkbox. @deprecated Use `pn-id` instead. @category HTML attributes */
checkboxid;
handleId() {
this.idHelpertext = `${this.getId()}-helpertext`;
}
handleChecked() {
if (this.displayContent()) {
this.checked ? this.openDropdown(this.contentArea) : this.closeDropdown(this.contentArea);
}
}
/**
* This is the same as the native `change` event, but without bubbling.
* This is useful when you want to listen to the event directly on the `pn-checkbox` element without
* having to worry about catching events from nested pn-checkboxes.
*
* @since v7.25.0
**/
pnCheckboxChange;
componentDidLoad() {
if (this.displayContent() && this.checked) {
requestAnimationFrame(() => this.openDropdown(this.contentArea));
}
}
getId() {
return this.pnId || this.checkboxid || this.id;
}
handleChange(e) {
const { checked } = e.target;
this.indeterminate = false;
this.checked = checked;
this.pnCheckboxChange.emit(e);
}
isInvalid() {
return this.invalid && !this.disabled;
}
displayText() {
return this.displayLabel() || this.displayHelpertext();
}
displayLabel() {
return !!this.label;
}
displayHelpertext() {
return !!(this.helpertext || this.hostElement.querySelector('[slot="helpertext"]')?.textContent);
}
displayIcon() {
return this.tile && !!this.icon;
}
/** Allow the checkbox to expand and control the slot area "content". */
displayContent() {
return this.tile && this.expand;
}
getAriaLabel() {
return !this.displayLabel() && !this.pnAriaLabelledby ? this.pnAriaLabel : null;
}
getAriaLabelledby() {
return !this.displayLabel() && !this.pnAriaLabel ? this.pnAriaLabelledby : null;
}
render() {
return (h(Host, { key: '4952d473c243232a6ee267cfac9414c8feb3e9c7' }, h("input", { key: 'e478ca15bde8fdf54833fe5b5a834513813db65e', type: "checkbox", id: this.getId(), class: "pn-checkbox-input", value: this.value, name: this.name, disabled: this.disabled, checked: this.checked, required: this.required, indeterminate: this.indeterminate, "aria-label": this.getAriaLabel(), "aria-labelledby": this.getAriaLabelledby(), "aria-describedby": this.displayHelpertext() && this.idHelpertext, "aria-invalid": this.isInvalid()?.toString(), "data-tile": this.tile, "data-expand": this.expand, onChange: e => this.handleChange(e) }), h("div", { key: 'e918f05ea8a0f5e26a7963dcdbd9cef7a1ae8a57', class: "pn-checkbox", "data-tile": this.tile, "data-expand": this.expand, "data-invalid": this.isInvalid() }, h("div", { key: 'e876cc7ae77d0496c745da65de5883404d0a01c7', class: "pn-checkbox-outer" }, h("svg", { key: '2349e0a978e6824658b572462eb5baf9ccda2ec9', class: "pn-checkbox-svg", xmlns: "http://www.w3.org/2000/svg", viewBox: "0 0 24 24", fill: "none" }, h("polyline", { key: 'c01925a07dfb5bbed352ecb741a3e9c830a32b3b', class: "pn-checkbox-svg-line pn-checkbox-svg-checkmark", points: "4,12 9,17 20,6", "stroke-width": "3" }), h("polyline", { key: '0d4dfa8da28e602bf0c579c6ca48fda9f1748a38', class: "pn-checkbox-svg-line pn-checkbox-svg-indeterminate", points: "4,12 20,12", "stroke-width": "3" }))), h("div", { key: 'd3c1f4a8d7aa27d7d9ca192438b84619574fcf39', class: "pn-checkbox-content", hidden: !this.displayText() }, h("label", { key: '467ca071291cbd977670300bb45affc7153ae7f4', htmlFor: this.getId(), class: "pn-checkbox-label", hidden: !this.displayLabel() }, this.label), h("p", { key: '5c790a6b8583415168a3e92c7b6d3a38125b39cd', id: this.idHelpertext, class: "pn-checkbox-helpertext", hidden: !this.displayHelpertext() }, this.helpertext && h("span", { key: 'e35b4ac4a6abd759d7fb5e1d41fd2f198515e106' }, this.helpertext), h("slot", { key: 'ac060762533af07379cc80225a83de6e01ca26e4', name: "helpertext" })), h("slot", { key: '4f0309028f9266d016f19d8983343ff010d89195' })), this.displayIcon() && h("pn-icon", { key: '742b544ed4ed61ff311de992eea37b768cc6efef', icon: this.icon, color: "gray900" }), h("div", { key: '45cdad0df43248b340feed887659d6c63e90b85f', class: "pn-checkbox-container", "data-open": this.checked, hidden: !this.displayContent(), style: { height: '0px' }, ref: el => (this.contentArea = el) }, h("div", { key: '060550d9876021ba85a1821c51c60b1bb34b8a3c', class: "pn-checkbox-area" }, h("slot", { key: 'bbe34f9d29a922ab20b8696595a9ed469005f59e', name: "content" }))))));
}
static get is() { return "pn-checkbox"; }
static get originalStyleUrls() {
return {
"$": ["pn-checkbox.scss"]
};
}
static get styleUrls() {
return {
"$": ["pn-checkbox.css"]
};
}
static get properties() {
return {
"label": {
"type": "string",
"mutable": false,
"complexType": {
"original": "string",
"resolved": "string",
"references": {}
},
"required": false,
"optional": true,
"docs": {
"tags": [],
"text": "The checkbox label, this is required for the checkbox to be 100% accessible out of the box."
},
"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": "This adds an optional helpertext under the label."
},
"getter": false,
"setter": false,
"reflect": false,
"attribute": "helpertext"
},
"value": {
"type": "string",
"mutable": false,
"complexType": {
"original": "string",
"resolved": "string",
"references": {}
},
"required": true,
"optional": false,
"docs": {
"tags": [{
"name": "category",
"text": "Native attributes"
}],
"text": "This will be emitted on change and input events."
},
"getter": false,
"setter": false,
"reflect": true,
"attribute": "value"
},
"name": {
"type": "string",
"mutable": false,
"complexType": {
"original": "string",
"resolved": "string",
"references": {}
},
"required": false,
"optional": true,
"docs": {
"tags": [{
"name": "category",
"text": "Native attributes"
}],
"text": "The name of the checkbox group."
},
"getter": false,
"setter": false,
"reflect": false,
"attribute": "name"
},
"checked": {
"type": "boolean",
"mutable": true,
"complexType": {
"original": "boolean",
"resolved": "boolean",
"references": {}
},
"required": false,
"optional": true,
"docs": {
"tags": [{
"name": "category",
"text": "Native attributes"
}],
"text": "Programmatically check the input."
},
"getter": false,
"setter": false,
"reflect": true,
"attribute": "checked",
"defaultValue": "false"
},
"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 checkbox 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 checkbox."
},
"getter": false,
"setter": false,
"reflect": false,
"attribute": "disabled",
"defaultValue": "false"
},
"invalid": {
"type": "boolean",
"mutable": false,
"complexType": {
"original": "boolean",
"resolved": "boolean",
"references": {}
},
"required": false,
"optional": true,
"docs": {
"tags": [{
"name": "category",
"text": "Native attributes"
}],
"text": "If set to true, color scheme will turn red, indicating that there is an issue related to the checkbox."
},
"getter": false,
"setter": false,
"reflect": false,
"attribute": "invalid",
"defaultValue": "false"
},
"indeterminate": {
"type": "boolean",
"mutable": true,
"complexType": {
"original": "boolean",
"resolved": "boolean",
"references": {}
},
"required": false,
"optional": false,
"docs": {
"tags": [{
"name": "category",
"text": "Native attributes"
}],
"text": "Sets the checkbox to an indeterminate state, allowing for a mixed or intermediate checkbox state."
},
"getter": false,
"setter": false,
"reflect": false,
"attribute": "indeterminate",
"defaultValue": "false"
},
"tile": {
"type": "boolean",
"mutable": false,
"complexType": {
"original": "boolean",
"resolved": "boolean",
"references": {}
},
"required": false,
"optional": true,
"docs": {
"tags": [{
"name": "category",
"text": "Features"
}],
"text": "Turn the checkbox into a clickable tile. A border and padding is added.\n\n**Do not** use interactive elements (links/buttons) inside of the slots when using this prop.\nAn exception is made when using the `tile` + `expand` props together,\nwhich allows you to use interactive elements."
},
"getter": false,
"setter": false,
"reflect": false,
"attribute": "tile",
"defaultValue": "false"
},
"expand": {
"type": "boolean",
"mutable": false,
"complexType": {
"original": "boolean",
"resolved": "boolean",
"references": {}
},
"required": false,
"optional": true,
"docs": {
"tags": [{
"name": "see",
"text": "{@link tile }"
}, {
"name": "since",
"text": "v7.17.0"
}, {
"name": "category",
"text": "Features"
}],
"text": "Allow the checkbox to control the slot area \"content\".\nWhen checked, the area is visible, when unchecked, the area is hidden.\n\nThe prop `tile` must be used at the same time."
},
"getter": false,
"setter": false,
"reflect": false,
"attribute": "expand",
"defaultValue": "false"
},
"icon": {
"type": "string",
"mutable": false,
"complexType": {
"original": "string",
"resolved": "string",
"references": {}
},
"required": false,
"optional": true,
"docs": {
"tags": [{
"name": "see",
"text": "{@link tile }"
}, {
"name": "category",
"text": "Features"
}],
"text": "Add an icon on the right of your checkbox tile. The `tile` prop must be `true` for the icon to work."
},
"getter": false,
"setter": false,
"reflect": false,
"attribute": "icon",
"defaultValue": "null"
},
"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": "A unique HTML ID for the checkbox."
},
"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"
},
"checkboxid": {
"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": "A unique HTML ID for the checkbox."
},
"getter": false,
"setter": false,
"reflect": false,
"attribute": "checkboxid"
}
};
}
static get events() {
return [{
"method": "pnCheckboxChange",
"name": "pnCheckboxChange",
"bubbles": false,
"cancelable": true,
"composed": true,
"docs": {
"tags": [{
"name": "since",
"text": "v7.25.0"
}],
"text": "This is the same as the native `change` event, but without bubbling.\nThis is useful when you want to listen to the event directly on the `pn-checkbox` element without\nhaving to worry about catching events from nested pn-checkboxes."
},
"complexType": {
"original": "Event",
"resolved": "Event",
"references": {
"Event": {
"location": "import",
"path": "@stencil/core",
"id": "node_modules::Event",
"referenceLocation": "Event"
}
}
}
}];
}
static get elementRef() { return "hostElement"; }
static get watchers() {
return [{
"propName": "checkboxid",
"methodName": "handleId"
}, {
"propName": "pnId",
"methodName": "handleId",
"handlerOptions": {
"immediate": true
}
}, {
"propName": "checked",
"methodName": "handleChecked"
}];
}
}