UNPKG

@limetech/lime-elements

Version:
328 lines (327 loc) • 13.5 kB
import { h, } from "@stencil/core"; import { dispatchResizeEvent } from "../../util/dispatch-resize-event"; import { makeEnterClickable, removeEnterClickable, } from "../../util/make-enter-clickable"; import { createRandomString } from "../../util/random-string"; import { getIconColor, getIconName, getIconTitle, } from "../icon/get-icon-props"; import translate from "../../global/translations"; /** * A collapsible section can be used to group related content together * and hide the group when not needed. * Using this component can help to: * - Save vertical space by hiding non-essential content * - Improve content organization and scannability of the user interface * - Reduce cognitive load by displaying only a set of relevant information at a time * - Or disclose complex information, progressively to the user * * @slot - Content to put inside the collapsible section * @slot header - Optional slot for custom header content * * @exampleComponent limel-example-collapsible-section-basic * @exampleComponent limel-example-collapsible-section-actions * @exampleComponent limel-example-collapsible-section-with-custom-header-component * @exampleComponent limel-example-collapsible-section-external-control * @exampleComponent limel-example-collapsible-section-with-slider * @exampleComponent limel-example-collapsible-section-invalid * @exampleComponent limel-example-collapsible-section-icon * @exampleComponent limel-example-collapsible-section-css-props */ export class CollapsibleSection { constructor() { /** * `true` if the section is expanded, `false` if collapsed. */ this.isOpen = false; /** * `true` if the section is invalid, `false` if valid. * This can be used to indicate that the content inside the section is invalid. */ this.invalid = false; /** * Defines the language for translations. * Will translate the translatable strings on the components. */ this.language = 'en'; this.bodyId = createRandomString(); this.headingId = createRandomString(); this.onClick = () => { this.handleInteraction(); }; this.handleInteraction = () => { this.isOpen = !this.isOpen; if (this.isOpen) { this.open.emit(); const waitForUiToRender = 100; setTimeout(dispatchResizeEvent, waitForUiToRender); } else { this.close.emit(); } }; this.renderExpandCollapseSign = () => { return (h("div", { class: "expand-icon", role: "presentation", "aria-hidden": "true" }, h("div", { class: "line" }), h("div", { class: "line" }), h("div", { class: "line" }), h("div", { class: "line" }))); }; this.renderIcon = () => { if (!this.icon) { return; } const name = getIconName(this.icon); const color = getIconColor(this.icon); const title = getIconTitle(this.icon); return (h("limel-icon", { name: name, "aria-label": title, "aria-hidden": title ? null : 'true', style: { color: `${color}`, } })); }; this.renderHeading = () => { if (!this.header) { return; } return (h("h2", { class: "title mdc-typography mdc-typography--headline2", id: this.headingId }, this.header)); }; this.renderActions = () => { if (!this.actions) { return; } return (h("div", { class: "actions" }, this.actions.map(this.renderActionButton))); }; this.renderActionButton = (action) => { return (h("limel-icon-button", { icon: action.icon, label: action.label, disabled: action.disabled, onClick: this.handleActionClick(action) })); }; this.handleActionClick = (action) => (event) => { event.stopPropagation(); this.action.emit(action); }; this.getCollapsibleSectionAriaLabel = () => { const heading = this.header ? `"${this.header}"` : ' '; if (!this.isOpen) { return translate.get('collapsible-section.open', this.language, { header: heading, }); } return translate.get('collapsible-section.close', this.language, { header: heading, }); }; } componentDidRender() { const button = this.host.shadowRoot.querySelector('.open-close-toggle'); makeEnterClickable(button); } disconnectedCallback() { const button = this.host.shadowRoot.querySelector('.open-close-toggle'); removeEnterClickable(button); } render() { return (h("section", { key: 'a40f48753cc7e5ae281b0e2a169e19510e54cc55', class: `${this.isOpen ? 'open' : ''}`, "aria-invalid": this.invalid, "aria-labelledby": this.header ? this.headingId : null }, h("header", { key: '55784166942971de68e351914a6d96dc77ea75c4' }, h("button", { key: '0432b0b5a4af99b94fea4073de496785c8f87d36', class: "open-close-toggle", onClick: this.onClick, "aria-controls": this.bodyId, "aria-expanded": this.isOpen ? 'true' : 'false', "aria-label": this.getCollapsibleSectionAriaLabel(), type: "button" }), this.renderExpandCollapseSign(), this.renderIcon(), this.renderHeading(), h("div", { key: '11efcd91907a79ed0945749b4672809e466c1e00', class: "divider-line", role: "presentation" }), this.renderHeaderSlot(), this.renderActions()), h("div", { key: '4b74f9d5fc9533eb14180a23e20c402a436b53f7', class: "body", "aria-hidden": String(!this.isOpen), id: this.bodyId, role: "region" }, h("slot", { key: '42c969ae7787768247a41952f9cf6d528ca7d4fd' })))); } renderHeaderSlot() { return h("slot", { name: "header" }); } static get is() { return "limel-collapsible-section"; } static get encapsulation() { return "shadow"; } static get originalStyleUrls() { return { "$": ["collapsible-section.scss"] }; } static get styleUrls() { return { "$": ["collapsible-section.css"] }; } static get properties() { return { "isOpen": { "type": "boolean", "mutable": true, "complexType": { "original": "boolean", "resolved": "boolean", "references": {} }, "required": false, "optional": false, "docs": { "tags": [], "text": "`true` if the section is expanded, `false` if collapsed." }, "getter": false, "setter": false, "reflect": true, "attribute": "is-open", "defaultValue": "false" }, "header": { "type": "string", "mutable": false, "complexType": { "original": "string", "resolved": "string", "references": {} }, "required": false, "optional": false, "docs": { "tags": [], "text": "Text to display in the header of the section" }, "getter": false, "setter": false, "reflect": true, "attribute": "header" }, "icon": { "type": "string", "mutable": false, "complexType": { "original": "string | Icon", "resolved": "Icon | string", "references": { "Icon": { "location": "import", "path": "../../global/shared-types/icon.types", "id": "src/global/shared-types/icon.types.ts::Icon", "referenceLocation": "Icon" } } }, "required": false, "optional": true, "docs": { "tags": [], "text": "Icon to display in the header of the section" }, "getter": false, "setter": false, "reflect": false, "attribute": "icon" }, "invalid": { "type": "boolean", "mutable": false, "complexType": { "original": "boolean", "resolved": "boolean", "references": {} }, "required": false, "optional": false, "docs": { "tags": [], "text": "`true` if the section is invalid, `false` if valid.\nThis can be used to indicate that the content inside the section is invalid." }, "getter": false, "setter": false, "reflect": true, "attribute": "invalid", "defaultValue": "false" }, "actions": { "type": "unknown", "mutable": false, "complexType": { "original": "Action[]", "resolved": "Action[]", "references": { "Action": { "location": "import", "path": "./action", "id": "src/components/collapsible-section/action.ts::Action", "referenceLocation": "Action" } } }, "required": false, "optional": false, "docs": { "tags": [], "text": "Actions to place to the far right inside the header" }, "getter": false, "setter": false }, "language": { "type": "string", "mutable": false, "complexType": { "original": "Languages", "resolved": "\"da\" | \"de\" | \"en\" | \"fi\" | \"fr\" | \"nb\" | \"nl\" | \"no\" | \"sv\"", "references": { "Languages": { "location": "import", "path": "../date-picker/date.types", "id": "src/components/date-picker/date.types.ts::Languages", "referenceLocation": "Languages" } } }, "required": false, "optional": false, "docs": { "tags": [], "text": "Defines the language for translations.\nWill translate the translatable strings on the components." }, "getter": false, "setter": false, "reflect": true, "attribute": "language", "defaultValue": "'en'" } }; } static get events() { return [{ "method": "open", "name": "open", "bubbles": true, "cancelable": true, "composed": true, "docs": { "tags": [], "text": "Emitted when the section is expanded" }, "complexType": { "original": "void", "resolved": "void", "references": {} } }, { "method": "close", "name": "close", "bubbles": true, "cancelable": true, "composed": true, "docs": { "tags": [], "text": "Emitted when the section is collapsed" }, "complexType": { "original": "void", "resolved": "void", "references": {} } }, { "method": "action", "name": "action", "bubbles": true, "cancelable": true, "composed": true, "docs": { "tags": [], "text": "Emitted when an action is clicked inside the header" }, "complexType": { "original": "Action", "resolved": "Action", "references": { "Action": { "location": "import", "path": "./action", "id": "src/components/collapsible-section/action.ts::Action", "referenceLocation": "Action" } } } }]; } static get elementRef() { return "host"; } }