@limetech/lime-elements
Version:
301 lines (300 loc) • 9.95 kB
JavaScript
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