import { recursivelyDeleteComponent } from '../componentManagement'; import { ComponentId } from '../dataModels'; import { markEventAsHandled } from '../eventHandling'; import { callRemoteMethodDiscardResponse } from '../rpc'; import { commitCss } from '../utils'; import { ComponentBase, ComponentState } from './componentBase'; export type DialogContainerState = ComponentState & { _type_: 'DialogContainer-builtin'; content?: ComponentId; owning_component_id?: ComponentId; is_modal?: boolean; is_user_closable?: boolean; }; export class DialogContainerComponent extends ComponentBase { state: Required; createElement(): HTMLElement { // Create the element let element = document.createElement('div'); element.classList.add('rio-dialog-container', 'rio-switcheroo-neutral'); // Since dialog containers aren't part of the component tree, they're // themselves responsible for adding themselves to the DOM. document.body.appendChild(element); // Animate the element requestAnimationFrame(() => { commitCss(element); element.classList.add('rio-dialog-container-enter'); }); // Listen for outside clicks element.addEventListener('click', (event) => { markEventAsHandled(event); // Is the dialog user-closable? if (!this.state.is_user_closable) { return; } // Yes! Close it. First, inform the server. callRemoteMethodDiscardResponse('dialogClosed', { dialogRootComponentId: this.id, }); // Clean up recursivelyDeleteComponent(this); }); return element; } onDestruction(): void { // Chain up super.onDestruction(); // Rather than disappearing immediately, the dialog container would like // to fade out its content. This doesn't work though, because the // content is also deleted when the dialog container is. So create a // copy of the container's HTML and animate that instead. let phony = this.element.cloneNode(true) as HTMLElement; phony.style.pointerEvents = 'none'; document.body.appendChild(phony); commitCss(phony); // Animate the element phony.classList.remove('rio-dialog-container-enter'); // Remove the element after the animation is done setTimeout(() => { phony.remove(); }, 2000); } updateElement( deltaState: DialogContainerState, latentComponents: Set ): void { super.updateElement(deltaState, latentComponents); // Content this.replaceOnlyChild(latentComponents, deltaState.content); // Modal if (deltaState.is_modal) { this.element.style.pointerEvents = 'auto'; this.element.style.removeProperty('background-color'); } else { this.element.style.pointerEvents = 'none'; this.element.style.backgroundColor = 'transparent'; } } }