UNPKG

@limetech/lime-elements

Version:
301 lines (300 loc) • 9.95 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() { 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, }); }; this.isOpen = false; this.header = undefined; this.icon = undefined; this.invalid = false; this.actions = undefined; this.language = 'en'; } 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", { class: `${this.isOpen ? 'open' : ''}`, "aria-invalid": this.invalid, "aria-labelledby": this.header ? this.headingId : null }, h("header", null, h("button", { 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", { class: "divider-line", role: "presentation" }), this.renderHeaderSlot(), this.renderActions()), h("div", { class: "body", "aria-hidden": String(!this.isOpen), id: this.bodyId, role: "region" }, h("slot", null)))); } 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." }, "attribute": "is-open", "reflect": true, "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" }, "attribute": "header", "reflect": true }, "icon": { "type": "string", "mutable": false, "complexType": { "original": "string | Icon", "resolved": "Icon | string", "references": { "Icon": { "location": "import", "path": "../../global/shared-types/icon.types" } } }, "required": false, "optional": true, "docs": { "tags": [], "text": "Icon to display in the header of the section" }, "attribute": "icon", "reflect": false }, "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." }, "attribute": "invalid", "reflect": true, "defaultValue": "false" }, "actions": { "type": "unknown", "mutable": false, "complexType": { "original": "Action[]", "resolved": "Action[]", "references": { "Action": { "location": "import", "path": "./action" } } }, "required": false, "optional": false, "docs": { "tags": [], "text": "Actions to place to the far right inside the header" } }, "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" } } }, "required": false, "optional": false, "docs": { "tags": [], "text": "Defines the language for translations.\nWill translate the translatable strings on the components." }, "attribute": "language", "reflect": true, "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" } } } }]; } static get elementRef() { return "host"; } } //# sourceMappingURL=collapsible-section.js.map