UNPKG

@limetech/lime-elements

Version:
287 lines (286 loc) • 9.04 kB
import { MDCDialog } from '@material/dialog'; import { h, } from '@stencil/core'; import { isEqual } from 'lodash-es'; import { dispatchResizeEvent } from '../../util/dispatch-resize-event'; import { createRandomString } from '../../util/random-string'; /** * :::note * Regarding the `close` event: When putting other elements that emit `close` * events inside a dialog, those events must be caught and stopped inside the * dialog. If not, they will bubble to the event handler listening for `close` * events on the dialog, which will close the dialog too. * * See the example _Nested `close` events_. * ::: * * :::important * Are you developing for * [Lime CRM](https://www.lime-technologies.com/en/lime-crm/)? Please note that * you should use the [DialogRenderer](https://lundalogik.github.io/lime-web-components/versions/latest/interfaces/DialogRenderer.html) * from Lime Web Components to open dialogs in Lime CRM. * ::: * * @exampleComponent limel-example-dialog * @exampleComponent limel-example-dialog-nested-close-events * @exampleComponent limel-example-dialog-heading * @exampleComponent limel-example-dialog-heading-actions * @exampleComponent limel-example-dialog-form * @exampleComponent limel-example-dialog-size * @exampleComponent limel-example-dialog-fullscreen * @exampleComponent limel-example-dialog-closing-actions * @exampleComponent limel-example-dialog-action-buttons * @slot - Content to put inside the dialog * @slot header-actions - The dialog header buttons * @slot button - The dialog buttons */ export class Dialog { constructor() { this.heading = undefined; this.fullscreen = false; this.open = false; this.closingActions = { escapeKey: true, scrimClick: true, }; this.handleMdcOpened = this.handleMdcOpened.bind(this); this.handleMdcClosed = this.handleMdcClosed.bind(this); this.handleMdcClosing = this.handleMdcClosing.bind(this); } connectedCallback() { this.initialize(); } componentWillLoad() { this.id = createRandomString(); } componentDidLoad() { this.initialize(); } initialize() { const element = this.host.shadowRoot.querySelector('.mdc-dialog'); if (!element) { return; } this.mdcDialog = new MDCDialog(element); if (this.open) { this.mdcDialog.open(); } this.mdcDialog.listen('MDCDialog:opened', this.handleMdcOpened); this.mdcDialog.listen('MDCDialog:closed', this.handleMdcClosed); this.mdcDialog.listen('MDCDialog:closing', this.handleMdcClosing); this.setClosingActions(); } disconnectedCallback() { this.mdcDialog.unlisten('MDCDialog:opened', this.handleMdcOpened); this.mdcDialog.unlisten('MDCDialog:closed', this.handleMdcClosed); this.mdcDialog.unlisten('MDCDialog:closing', this.handleMdcClosing); this.mdcDialog.destroy(); } render() { return (h("div", { class: { 'mdc-dialog': true, 'full-screen': !!this.fullscreen, }, role: "alertdialog", "aria-modal": "true", "aria-labelledby": 'limel-dialog-title-' + this.id, "aria-describedby": 'limel-dialog-content-' + this.id }, h("input", { hidden: true, id: "initialFocusEl" }), h("div", { class: "mdc-dialog__container" }, h("div", { class: "mdc-dialog__surface" }, h("input", { type: "button", id: "initialFocusElement" }), this.renderHeading(), h("div", { class: "mdc-dialog__content", id: 'limel-dialog-content-' + this.id }, h("slot", null)), this.renderFooter())), h("div", { class: "mdc-dialog__scrim" }))); } watchHandler(newValue, oldValue) { if (oldValue === newValue) { return; } if (!this.mdcDialog) { return; } if (newValue) { this.mdcDialog.open(); } else { this.mdcDialog.close(); } } closingActionsChanged(newValue, oldValue) { if (isEqual(newValue, oldValue)) { return; } this.setClosingActions(); } handleMdcOpened() { // When the opening-animation has completed, dispatch a // resize-event so that any content that depends on // javascript for layout has a chance to update to the // final layout of the dialog. /Ads const waitForUiToRender = 100; setTimeout(dispatchResizeEvent, waitForUiToRender); } handleMdcClosed() { if (this.open) { this.close.emit(); } this.open = false; } handleMdcClosing() { this.closing.emit(); } isBadgeHeading(heading) { return typeof heading === 'object' && !!heading.title && !!heading.icon; } renderHeading() { if (this.isBadgeHeading(this.heading)) { const { title, subtitle, supportingText, icon } = this.heading; return (h("limel-header", { icon: icon, heading: title, subheading: subtitle, supportingText: supportingText }, h("slot", { name: "header-actions", slot: "actions" }))); } else if (typeof this.heading === 'string') { return h("limel-header", { heading: this.heading }); } return null; } renderFooter() { return (h("footer", { class: "mdc-dialog__actions" }, h("slot", { name: "button" }))); } setClosingActions() { this.mdcDialog.scrimClickAction = ''; if (this.closingActions.scrimClick) { this.mdcDialog.scrimClickAction = 'close'; } this.mdcDialog.escapeKeyAction = ''; if (this.closingActions.escapeKey) { this.mdcDialog.escapeKeyAction = 'close'; } } static get is() { return "limel-dialog"; } static get encapsulation() { return "shadow"; } static get originalStyleUrls() { return { "$": ["dialog.scss"] }; } static get styleUrls() { return { "$": ["dialog.css"] }; } static get properties() { return { "heading": { "type": "string", "mutable": false, "complexType": { "original": "string | DialogHeading", "resolved": "DialogHeading | string", "references": { "DialogHeading": { "location": "import", "path": "./dialog.types" } } }, "required": false, "optional": false, "docs": { "tags": [], "text": "The heading for the dialog, if any." }, "attribute": "heading", "reflect": false }, "fullscreen": { "type": "boolean", "mutable": false, "complexType": { "original": "boolean", "resolved": "boolean", "references": {} }, "required": false, "optional": false, "docs": { "tags": [], "text": "Set to `true` to make the dialog \"fullscreen\"." }, "attribute": "fullscreen", "reflect": true, "defaultValue": "false" }, "open": { "type": "boolean", "mutable": true, "complexType": { "original": "boolean", "resolved": "boolean", "references": {} }, "required": false, "optional": false, "docs": { "tags": [], "text": "`true` if the dialog is open, `false` otherwise." }, "attribute": "open", "reflect": true, "defaultValue": "false" }, "closingActions": { "type": "unknown", "mutable": false, "complexType": { "original": "ClosingActions", "resolved": "ClosingActions", "references": { "ClosingActions": { "location": "import", "path": "./dialog.types" } } }, "required": false, "optional": false, "docs": { "tags": [], "text": "Defines which action triggers a close-event." }, "defaultValue": "{\n escapeKey: true,\n scrimClick: true,\n }" } }; } static get events() { return [{ "method": "close", "name": "close", "bubbles": true, "cancelable": true, "composed": true, "docs": { "tags": [], "text": "Emitted when the dialog is closed from inside the component.\n(*Not* emitted when the consumer sets the `open`-property to `false`.)" }, "complexType": { "original": "void", "resolved": "void", "references": {} } }, { "method": "closing", "name": "closing", "bubbles": true, "cancelable": true, "composed": true, "docs": { "tags": [], "text": "Emitted when the dialog is in the process of being closed." }, "complexType": { "original": "void", "resolved": "void", "references": {} } }]; } static get elementRef() { return "host"; } static get watchers() { return [{ "propName": "open", "methodName": "watchHandler" }, { "propName": "closingActions", "methodName": "closingActionsChanged" }]; } } //# sourceMappingURL=dialog.js.map