UNPKG

@esri/calcite-components

Version:

Web Components for Esri's Calcite Design System.

482 lines (481 loc) • 25.8 kB
/*! All material copyright ESRI, All Rights Reserved, unless otherwise specified. See https://github.com/Esri/calcite-design-system/blob/dev/LICENSE.md for details. v3.2.1 */ import { a as resizeShiftStep, c as customElement } from "../../chunks/runtime.js"; import { keyed } from "lit-html/directives/keyed.js"; import { i as interact } from "../../chunks/interact.min.js"; import { html } from "lit"; import { createRef, ref } from "lit-html/directives/ref.js"; import { LitElement, createEvent, safeClassMap } from "@arcgis/lumina"; import { h as focusFirstTabbable, k as getStylePixelValue } from "../../chunks/dom.js"; import { c as componentFocusable } from "../../chunks/component.js"; import { c as createObserver } from "../../chunks/observers.js"; import { g as getDimensionClass } from "../../chunks/dynamicClasses.js"; import { o as onToggleOpenCloseComponent } from "../../chunks/openCloseComponent.js"; import { S as SLOTS$1 } from "../../chunks/resources3.js"; import { u as useT9n } from "../../chunks/useT9n.js"; import { u as useFocusTrap } from "../../chunks/useFocusTrap.js"; import { u as usePreventDocumentScroll } from "../../chunks/usePreventDocumentScroll.js"; import { css } from "@lit/reactive-element/css-tag.js"; const CSS = { dialog: "dialog", panel: "panel", scrim: "scrim", container: "container", containerOpen: "container--open", containerEmbedded: "container--embedded", assistiveText: "assistive-text", openingActive: "dialog--opening-active" }; const SLOTS = { actionBar: "action-bar", alerts: "alerts", content: "content", customContent: "custom-content", contentTop: "content-top", contentBottom: "content-bottom", headerActionsStart: "header-actions-start", headerActionsEnd: "header-actions-end", headerMenuActions: "header-menu-actions", headerContent: "header-content", fab: "fab", footer: "footer", footerStart: "footer-start", footerEnd: "footer-end" }; const initialDragPosition = { x: null, y: null }; const initialResizePosition = { top: null, right: null, bottom: null, left: null }; const styles = css`:host{--calcite-dialog-scrim-background-color: rgba(0, 0, 0, .85);pointer-events:none;inset:0;z-index:var(--calcite-z-index-overlay);display:flex;--calcite-internal-dialog-animation-offset: 20px}:host([modal]){position:absolute}.container{pointer-events:auto;position:fixed;inset:0;z-index:var(--calcite-z-index-overlay);display:flex;align-items:center;justify-content:center;overflow:hidden;color:var(--calcite-color-text-2);opacity:0;visibility:hidden;transition:visibility 0ms linear var(--calcite-internal-animation-timing-slow),opacity var(--calcite-internal-animation-timing-slow) cubic-bezier(.215,.44,.42,.88)}:host([placement=top]) .container{align-items:flex-start;justify-content:center}:host([placement=top-start]) .container{align-items:flex-start;justify-content:flex-start}:host([placement=top-end]) .container{align-items:flex-start;justify-content:flex-end}:host([placement=bottom]) .container{align-items:flex-end;justify-content:center}:host([placement=bottom-start]) .container{align-items:flex-end;justify-content:flex-start}:host([placement=bottom-end]) .container{align-items:flex-end;justify-content:flex-end}:host(:not([modal])) .container{pointer-events:none}:host([scale=s]){--calcite-internal-dialog-content-padding: var(--calcite-dialog-content-space, var(--calcite-spacing-sm));--calcite-internal-dialog-min-size-x: 198px;--calcite-internal-dialog-min-size-y: 140px}:host([scale=m]){--calcite-internal-dialog-content-padding: var(--calcite-dialog-content-space, var(--calcite-spacing-md));--calcite-internal-dialog-min-size-x: 288px;--calcite-internal-dialog-min-size-y: 180px}:host([scale=l]){--calcite-internal-dialog-content-padding: var(--calcite-dialog-content-space, var(--calcite-spacing-md-plus));--calcite-internal-dialog-min-size-x: 388px;--calcite-internal-dialog-min-size-y: 220px}.scrim{--calcite-scrim-background: var(--calcite-dialog-scrim-background-color, var(--calcite-color-transparent-scrim));--calcite-scrim-background-color: var( --calcite-dialog-scrim-background-color, var(--calcite-color-transparent-scrim) );position:fixed;inset:0;display:flex;overflow-y:hidden}calcite-panel{--calcite-panel-content-space: var(--calcite-dialog-content-space, var(--calcite-internal-dialog-content-padding));--calcite-panel-footer-space: var(--calcite-dialog-footer-space);--calcite-panel-border-color: var(--calcite-dialog-border-color);--calcite-panel-background-color: var(--calcite-dialog-background-color, var(--calcite-color-foreground-1))}::slotted(*){--calcite-panel-background-color: initial}.dialog{pointer-events:none;position:relative;z-index:var(--calcite-z-index-modal);margin:1.5rem;box-sizing:border-box;display:flex;inline-size:100%;flex-direction:column;border-radius:.25rem;opacity:0;--tw-shadow: 0 2px 12px -4px rgba(0, 0, 0, .2), 0 2px 4px -2px rgba(0, 0, 0, .16);--tw-shadow-colored: 0 2px 12px -4px var(--tw-shadow-color), 0 2px 4px -2px var(--tw-shadow-color);box-shadow:var(--tw-ring-offset-shadow, 0 0 #0000),var(--tw-ring-shadow, 0 0 #0000),var(--tw-shadow);-webkit-overflow-scrolling:touch;visibility:hidden;transition:inset-block var(--calcite-internal-animation-timing-slow) cubic-bezier(.215,.44,.42,.88),opacity var(--calcite-internal-animation-timing-slow) cubic-bezier(.215,.44,.42,.88);min-inline-size:var(--calcite-dialog-min-size-x, var(--calcite-internal-dialog-min-size-x));max-inline-size:var(--calcite-dialog-max-size-x, 100%);min-block-size:var(--calcite-dialog-min-size-y, var(--calcite-internal-dialog-min-size-y));max-block-size:var(--calcite-dialog-max-size-y, 100%);--calcite-internal-dialog-hidden-position: calc( var(--calcite-dialog-offset-y, 0px) + var(--calcite-internal-dialog-animation-offset) );--calcite-internal-dialog-shown-position: var(--calcite-dialog-offset-y, 0);inset-inline-start:var(--calcite-dialog-offset-x, 0);inset-block-start:var(--calcite-internal-dialog-hidden-position)}.dialog--opening-active{inset-block-start:var(--calcite-internal-dialog-shown-position)}:host([menu-open]) .dialog{transition:visibility 0ms linear var(--calcite-internal-animation-timing-slow),opacity var(--calcite-internal-animation-timing-slow) cubic-bezier(.215,.44,.42,.88)}.panel{border-radius:.25rem}.container--open{opacity:1;visibility:visible;transition-delay:0ms}.container--open .dialog{pointer-events:auto;visibility:visible;opacity:1;transition:inset-block var(--calcite-internal-animation-timing-slow) cubic-bezier(.215,.44,.42,.88),opacity var(--calcite-internal-animation-timing-slow) cubic-bezier(.215,.44,.42,.88);transition-delay:0ms}.width-s{inline-size:auto;inline-size:var(--calcite-dialog-size-x, 32rem);block-size:var(--calcite-dialog-size-y, auto)}@media screen and (max-width: 35rem){.width-s{margin:0;block-size:100%;max-block-size:100%;inline-size:100%;max-inline-size:100%;inset-inline-start:0;inset-block-start:var(--calcite-internal-dialog-animation-offset)}.width-s.dialog--opening-active{inset-block-start:0}}.width-m{inline-size:var(--calcite-dialog-size-x, 48rem);block-size:var(--calcite-dialog-size-y, auto)}@media screen and (max-width: 51rem){.width-m{margin:0;block-size:100%;max-block-size:100%;inline-size:100%;max-inline-size:100%;inset-inline-start:0;inset-block-start:var(--calcite-internal-dialog-animation-offset)}.width-m.dialog--opening-active{inset-block-start:0}}.width-l{inline-size:var(--calcite-dialog-size-x, 94rem);block-size:var(--calcite-dialog-size-y, auto)}@media screen and (max-width: 97rem){.width-l{margin:0;block-size:100%;max-block-size:100%;inline-size:100%;max-inline-size:100%;inset-inline-start:0;inset-block-start:var(--calcite-internal-dialog-animation-offset)}.width-l.dialog--opening-active{inset-block-start:0}}:host([placement=cover]) .dialog{margin:0;block-size:100%;max-block-size:100%;inline-size:100%;max-inline-size:100%;border-radius:0}:host([placement=cover]) .panel{border-radius:0}:host([kind]) .panel{border-start-start-radius:0px;border-start-end-radius:0px}:host([kind=brand]) .dialog{border-color:var(--calcite-color-brand)}:host([kind=danger]) .dialog{border-color:var(--calcite-color-status-danger)}:host([kind=info]) .dialog{border-color:var(--calcite-color-status-info)}:host([kind=success]) .dialog{border-color:var(--calcite-color-status-success)}:host([kind=warning]) .dialog{border-color:var(--calcite-color-status-warning)}:host([kind=brand][open]) .dialog,:host([kind=danger][open]) .dialog,:host([kind=info][open]) .dialog,:host([kind=success][open]) .dialog,:host([kind=warning][open]) .dialog{border-width:0px;border-block-start-width:4px;border-style:solid}.container--embedded{position:absolute;pointer-events:auto}.container--embedded calcite-scrim{position:absolute}.assistive-text{position:absolute;inline-size:1px;block-size:1px;padding:0;margin:-1px;overflow:hidden;clip:rect(0,0,0,0);white-space:nowrap;border-width:0}:host([hidden]){display:none}[hidden]{display:none}`; class Dialog extends LitElement { constructor() { super(...arguments); this.dragPosition = { ...initialDragPosition }; this.focusTrap = useFocusTrap({ triggerProp: "open", focusTrapOptions: { // scrim closes on click, so we let it take over clickOutsideDeactivates: () => !this.modal || this.embedded, escapeDeactivates: (event) => { if (!event.defaultPrevented && !this.escapeDisabled) { this.open = false; event.preventDefault(); } return false; } } })(this); this.usePreventDocumentScroll = usePreventDocumentScroll()(this); this.ignoreOpenChange = false; this.mutationObserver = createObserver("mutation", () => this.handleMutationObserver()); this._open = false; this.openProp = "opened"; this.transitionProp = "opacity"; this.panelEl = createRef(); this.resizePosition = { ...initialResizePosition }; this.messages = useT9n(); this.assistiveText = null; this.hasContentBottom = false; this.hasContentTop = false; this.hasFooter = true; this.opened = false; this.closeDisabled = false; this.dragEnabled = false; this.embedded = false; this.escapeDisabled = false; this.loading = false; this.menuOpen = false; this.modal = false; this.focusTrapDisabled = false; this.outsideCloseDisabled = false; this.overlayPositioning = "absolute"; this.placement = "center"; this.resizable = false; this.scale = "m"; this.widthScale = "m"; this.calciteDialogBeforeClose = createEvent({ cancelable: false }); this.calciteDialogBeforeOpen = createEvent({ cancelable: false }); this.calciteDialogClose = createEvent({ cancelable: false }); this.calciteDialogOpen = createEvent({ cancelable: false }); this.calciteDialogScroll = createEvent({ cancelable: false }); } static { this.properties = { assistiveText: [16, {}, { state: true }], hasContentBottom: [16, {}, { state: true }], hasContentTop: [16, {}, { state: true }], hasFooter: [16, {}, { state: true }], opened: [16, {}, { state: true }], preventDocumentScroll: [16, {}, { state: true }], beforeClose: [0, {}, { attribute: false }], closeDisabled: [7, {}, { reflect: true, type: Boolean }], description: 1, dragEnabled: [7, {}, { reflect: true, type: Boolean }], embedded: [5, {}, { type: Boolean }], escapeDisabled: [7, {}, { reflect: true, type: Boolean }], focusTrapOptions: [0, {}, { attribute: false }], heading: 1, headingLevel: [11, {}, { type: Number, reflect: true }], kind: [3, {}, { reflect: true }], loading: [7, {}, { reflect: true, type: Boolean }], menuOpen: [7, {}, { reflect: true, type: Boolean }], messageOverrides: [0, {}, { attribute: false }], modal: [7, {}, { reflect: true, type: Boolean }], focusTrapDisabled: [7, {}, { reflect: true, type: Boolean }], open: [7, {}, { reflect: true, type: Boolean }], outsideCloseDisabled: [7, {}, { reflect: true, type: Boolean }], overlayPositioning: [3, {}, { reflect: true }], placement: [3, {}, { reflect: true }], resizable: [7, {}, { reflect: true, type: Boolean }], scale: [3, {}, { reflect: true }], widthScale: [3, {}, { reflect: true }], width: [3, {}, { reflect: true }] }; } static { this.styles = styles; } get preventDocumentScroll() { return !this.embedded && this.modal; } get open() { return this._open; } set open(open) { const oldOpen = this._open; if (open !== oldOpen) { this._open = open; this.toggleDialog(open); } } async scrollContentTo(options) { await this.panelEl.value?.scrollContentTo(options); } async setFocus() { await componentFocusable(this); return this.panelEl.value?.setFocus() ?? focusFirstTabbable(this.el); } async updateFocusTrapElements(extraContainers) { this.focusTrap.setExtraContainers(extraContainers); this.focusTrap.updateContainerElements(); } connectedCallback() { super.connectedCallback(); this.mutationObserver?.observe(this.el, { childList: true, subtree: true }); this.setupInteractions(); } willUpdate(changes) { if (changes.has("open") && (this.hasUpdated || this.open !== false) || changes.has("placement") && (this.hasUpdated || this.placement !== "center") || changes.has("resizable") && (this.hasUpdated || this.resizable !== false) || changes.has("dragEnabled") && (this.hasUpdated || this.dragEnabled !== false)) { this.setupInteractions(); } if (changes.has("messages") || changes.has("dragEnabled") && (this.hasUpdated || this.dragEnabled !== false) || changes.has("resizable") && (this.hasUpdated || this.resizable !== false)) { this.updateAssistiveText(); } if (changes.has("opened") && (this.hasUpdated || this.opened !== false)) { this.handleOpenedChange(this.opened); } } disconnectedCallback() { super.disconnectedCallback(); this.mutationObserver?.disconnect(); this.embedded = false; this.cleanupInteractions(); } focusTrapDisabledOverride() { return !this.modal && this.focusTrapDisabled; } updateAssistiveText() { const { messages } = this; this.assistiveText = messages && (this.dragEnabled || this.resizable) ? `${this.dragEnabled ? messages.dragEnabled : ""} ${this.resizable ? messages.resizeEnabled : ""}` : null; } onBeforeOpen() { this.calciteDialogBeforeOpen.emit(); } onOpen() { if (this.focusTrapDisabled) { this.setFocus(); } this.focusTrap.activate(); this.calciteDialogOpen.emit(); } onBeforeClose() { this.calciteDialogBeforeClose.emit(); } onClose() { this.focusTrap.deactivate(); this.calciteDialogClose.emit(); } toggleDialog(value) { if (this.ignoreOpenChange) { return; } if (value) { this.openDialog(); } else { this.closeDialog(); } } handleOpenedChange(value) { const { transitionEl } = this; if (!transitionEl) { return; } transitionEl.classList.toggle(CSS.openingActive, value); onToggleOpenCloseComponent(this); } async triggerInteractModifiers() { const { interaction } = this; if (!interaction) { return; } await interaction.reflow({ name: "drag" }); await interaction.reflow({ name: "resize" }); } getTransitionElDOMRect() { return this.transitionEl.getBoundingClientRect(); } handleKeyDown(event) { const { key, shiftKey, defaultPrevented } = event; const { dragEnabled, resizable, resizePosition, dragPosition, transitionEl } = this; const keys = ["ArrowUp", "ArrowDown", "ArrowLeft", "ArrowRight"]; if (defaultPrevented || !keys.includes(key)) { return; } switch (key) { case "ArrowUp": if (shiftKey && resizable && transitionEl) { this.updateSize({ size: this.getTransitionElDOMRect().height - resizeShiftStep, type: "blockSize" }); resizePosition.bottom -= resizeShiftStep; this.updateTransform(); this.triggerInteractModifiers(); event.preventDefault(); } else if (dragEnabled) { dragPosition.y -= resizeShiftStep; this.updateTransform(); this.triggerInteractModifiers(); event.preventDefault(); } break; case "ArrowDown": if (shiftKey && resizable && transitionEl) { this.updateSize({ size: this.getTransitionElDOMRect().height + resizeShiftStep, type: "blockSize" }); resizePosition.bottom += resizeShiftStep; this.updateTransform(); this.triggerInteractModifiers(); event.preventDefault(); } else if (dragEnabled) { dragPosition.y += resizeShiftStep; this.updateTransform(); this.triggerInteractModifiers(); event.preventDefault(); } break; case "ArrowLeft": if (shiftKey && resizable && transitionEl) { this.updateSize({ size: this.getTransitionElDOMRect().width - resizeShiftStep, type: "inlineSize" }); resizePosition.right -= resizeShiftStep; this.updateTransform(); this.triggerInteractModifiers(); event.preventDefault(); } else if (dragEnabled) { dragPosition.x -= resizeShiftStep; this.updateTransform(); this.triggerInteractModifiers(); event.preventDefault(); } break; case "ArrowRight": if (shiftKey && resizable && transitionEl) { this.updateSize({ size: this.getTransitionElDOMRect().width + resizeShiftStep, type: "inlineSize" }); resizePosition.right += resizeShiftStep; this.updateTransform(); this.triggerInteractModifiers(); event.preventDefault(); } else if (dragEnabled) { dragPosition.x += resizeShiftStep; this.updateTransform(); this.triggerInteractModifiers(); event.preventDefault(); } break; } } updateTransform() { const { dragPosition: { x, y }, resizePosition, transitionEl, dragEnabled, resizable } = this; if (!transitionEl) { return; } if (!dragEnabled && !resizable) { transitionEl.style.transform = null; return; } const { top, right, bottom, left } = this.getAdjustedResizePosition(resizePosition); const translateX = Math.round(x + left + right); const translateY = Math.round(y + top + bottom); transitionEl.style.transform = translateX || translateY ? `translate(${translateX}px, ${translateY}px)` : null; } updateSize({ type, size }) { const { transitionEl } = this; if (!transitionEl) { return; } transitionEl.style[type] = size !== null ? `${Math.round(size)}px` : null; } cleanupInteractions() { this.interaction?.unset(); this.updateSize({ size: null, type: "inlineSize" }); this.updateSize({ size: null, type: "blockSize" }); this.dragPosition = { ...initialDragPosition }; this.resizePosition = { ...initialResizePosition }; this.updateTransform(); } async setupInteractions() { this.cleanupInteractions(); const { el, transitionEl, resizable, dragEnabled, resizePosition, dragPosition } = this; if (!transitionEl || !this.open) { return; } if (resizable || dragEnabled) { this.interaction = interact(transitionEl, { context: el.ownerDocument }); } if (resizable) { await this.el.componentOnReady(); const { minInlineSize, minBlockSize, maxInlineSize, maxBlockSize } = window.getComputedStyle(transitionEl); this.interaction.resizable({ edges: { top: true, right: true, bottom: true, left: true }, modifiers: [ interact.modifiers.restrictSize({ min: { width: getStylePixelValue(minInlineSize), height: getStylePixelValue(minBlockSize) }, max: { width: getStylePixelValue(maxInlineSize) || window.innerWidth, height: getStylePixelValue(maxBlockSize) || window.innerHeight } }), interact.modifiers.restrict({ restriction: "parent" }) ], listeners: { move: ({ rect, deltaRect }) => { if (deltaRect) { resizePosition.top += deltaRect.top; resizePosition.right += deltaRect.right; resizePosition.bottom += deltaRect.bottom; resizePosition.left += deltaRect.left; } this.updateSize({ size: rect.width, type: "inlineSize" }); this.updateSize({ size: rect.height, type: "blockSize" }); this.updateTransform(); } } }); } if (dragEnabled) { this.interaction.draggable({ modifiers: [ interact.modifiers.restrictRect({ restriction: "parent" }) ], listeners: { move: ({ dx, dy }) => { dragPosition.x += dx; dragPosition.y += dy; this.updateTransform(); } } }); } } getAdjustedResizePosition({ top, right, bottom, left }) { const halfTop = top / 2; const halfRight = right / 2; const halfBottom = bottom / 2; const halfLeft = left / 2; switch (this.placement) { case "top": return { top, right: halfRight, bottom: 0, left: halfLeft }; case "top-start": return { top, right: 0, bottom: 0, left }; case "top-end": return { top, right, bottom: 0, left: 0 }; case "bottom": return { top: 0, right: halfRight, bottom, left: halfLeft }; case "bottom-start": return { top: 0, right: 0, bottom, left }; case "bottom-end": return { top: 0, right, bottom, left: 0 }; case "cover": case "center": default: return { top: halfTop, right: halfRight, bottom: halfBottom, left: halfLeft }; } } setTransitionEl(el) { if (!el) { return; } this.transitionEl = el; this.setupInteractions(); } handleInternalPanelScroll(event) { if (event.target !== this.panelEl.value) { return; } event.stopPropagation(); this.calciteDialogScroll.emit(); } handleInternalPanelCloseClick(event) { if (event.target !== this.panelEl.value) { return; } event.stopPropagation(); this.open = false; } handlePanelKeyDown(event) { if (this.escapeDisabled && event.key === "Escape") { event.preventDefault(); } } async openDialog() { await this.componentOnReady(); this.opened = true; } handleOutsideClose() { if (this.outsideCloseDisabled) { return; } this.open = false; } async closeDialog() { if (this.beforeClose) { try { await this.beforeClose(); } catch { requestAnimationFrame(() => { this.ignoreOpenChange = true; this.open = true; this.ignoreOpenChange = false; }); return; } } this.opened = false; } handleMutationObserver() { this.focusTrap.updateContainerElements(); } render() { const { assistiveText, description, heading, opened } = this; return html`<div class=${safeClassMap({ [CSS.container]: true, [CSS.containerOpen]: opened, [CSS.containerEmbedded]: this.embedded })}>${this.modal ? html`<calcite-scrim class=${safeClassMap(CSS.scrim)} @click=${this.handleOutsideClose}></calcite-scrim>` : null}<div .ariaDescription=${description} .ariaLabel=${heading} .ariaModal=${this.modal} class=${safeClassMap({ [CSS.dialog]: true, [getDimensionClass("width", this.width, this.widthScale)]: !!(this.width || this.widthScale) })} @keydown=${this.handleKeyDown} role=dialog ${ref(this.setTransitionEl)}>${assistiveText ? keyed("assistive-text", html`<div aria-live=polite class=${safeClassMap(CSS.assistiveText)}>${assistiveText}</div>`) : null}<slot name=${SLOTS.customContent}><slot name=${SLOTS.content}><calcite-panel .beforeClose=${this.beforeClose} class=${safeClassMap(CSS.panel)} .closable=${!this.closeDisabled} .closed=${!opened} .description=${description} .heading=${heading} .headingLevel=${this.headingLevel} .loading=${this.loading} .menuOpen=${this.menuOpen} .messageOverrides=${this.messageOverrides} @keydown=${this.handlePanelKeyDown} @calcitePanelClose=${this.handleInternalPanelCloseClick} @calcitePanelScroll=${this.handleInternalPanelScroll} .overlayPositioning=${this.overlayPositioning} .scale=${this.scale} ${ref(this.panelEl)}><slot name=${SLOTS.actionBar} slot=${SLOTS$1.actionBar}></slot><slot name=${SLOTS.alerts} slot=${SLOTS$1.alerts}></slot><slot name=${SLOTS.headerActionsStart} slot=${SLOTS$1.headerActionsStart}></slot><slot name=${SLOTS.headerActionsEnd} slot=${SLOTS$1.headerActionsEnd}></slot><slot name=${SLOTS.headerContent} slot=${SLOTS$1.headerContent}></slot><slot name=${SLOTS.headerMenuActions} slot=${SLOTS$1.headerMenuActions}></slot><slot name=${SLOTS.fab} slot=${SLOTS$1.fab}></slot><slot name=${SLOTS.contentTop} slot=${SLOTS$1.contentTop}></slot><slot name=${SLOTS.contentBottom} slot=${SLOTS$1.contentBottom}></slot><slot name=${SLOTS.footerStart} slot=${SLOTS$1.footerStart}></slot><slot name=${SLOTS.footer} slot=${SLOTS$1.footer}></slot><slot name=${SLOTS.footerEnd} slot=${SLOTS$1.footerEnd}></slot><slot></slot></calcite-panel></slot></slot></div></div>`; } } customElement("calcite-dialog", Dialog); export { Dialog };