import * as colors from './00colors.js'; import * as plugins from './00plugins.js'; import { demoFunc } from './dees-modal.demo.js'; import { customElement, html, DeesElement, property, type TemplateResult, cssManager, css, type CSSResult, unsafeCSS, unsafeHTML, state, } from '@design.estate/dees-element'; import * as domtools from '@design.estate/dees-domtools'; import { DeesWindowLayer } from './dees-windowlayer.js'; declare global { interface HTMLElementTagNameMap { 'dees-modal': DeesModal; } } @customElement('dees-modal') export class DeesModal extends DeesElement { // STATIC public static demo = demoFunc; public static async createAndShow(optionsArg: { heading: string; content: TemplateResult; menuOptions: plugins.tsclass.website.IMenuItem[]; }) { const body = document.body; const modal = new DeesModal(); modal.heading = optionsArg.heading; modal.content = optionsArg.content; modal.menuOptions = optionsArg.menuOptions; modal.windowLayer = await DeesWindowLayer.createAndShow({ blur: true, }); modal.windowLayer.addEventListener('click', async () => { await modal.destroy(); }); body.append(modal.windowLayer); body.append(modal); } // INSTANCE @property({ type: String, }) public heading = ''; @state({}) public content: TemplateResult; @state({}) public menuOptions: plugins.tsclass.website.IMenuItem[] = []; constructor() { super(); } public static styles = [ cssManager.defaultStyles, css` :host { font-family: 'Geist Sans', sans-serif; color: ${cssManager.bdTheme('#333', '#fff')}; will-change: transform; } .modalContainer { display: flex; position: fixed; top: 0px; left: 0px; width: 100vw; height: 100vh; box-sizing: border-box; align-items: center; justify-content: center; z-index: 2000; } .modal { will-change: transform; transform: translateY(0px) scale(0.95); opacity: 0; width: 480px; min-height: 120px; background: #111; border-radius: 8px; border: 1px solid #222; transition: all 0.2s; overflow: hidden; box-shadow: 0px 2px 5px #00000080; } .modal.show { opacity: 1; transform: translateY(0px) scale(1); } .modal.show.predestroy { opacity: 0; transform: translateY(10px) scale(1); } .modal .heading { height: 32px; font-family: 'Geist Sans', sans-serif; line-height: 32px; text-align: center; font-weight: 600; font-size: 12px; border-bottom: 1px solid #222; } .modal .content { padding: 16px; } .modal .bottomButtons { display: flex; flex-direction: row; border-top: 1px solid #222; justify-content: flex-end; } .modal .bottomButtons .bottomButton { margin: 8px 0px; padding: 8px 12px; border-radius: 4px; line-height: 16px; text-align: center; font-size: 14px; cursor: default; user-select: none; } .modal .bottomButtons .bottomButton:first-child { margin-left: 8px; } .modal .bottomButtons .bottomButton:last-child { margin-right: 8px; } .modal .bottomButtons .bottomButton:hover { background: ${cssManager.bdTheme(colors.bright.blue, colors.dark.blue)}; } .modal .bottomButtons .bottomButton:active { background: ${cssManager.bdTheme(colors.bright.blueActive, colors.dark.blueActive)}; } .modal .bottomButtons .bottomButton:last-child { border-right: none; } `, ]; public render(): TemplateResult { return html`
`; } private windowLayer: DeesWindowLayer; public async firstUpdated(_changedProperties: Map) { super.firstUpdated(_changedProperties); const domtools = await this.domtoolsPromise; await domtools.convenience.smartdelay.delayFor(30); const modal = this.shadowRoot.querySelector('.modal'); modal.classList.add('show'); } public async handleOutsideClick(eventArg: MouseEvent) { eventArg.stopPropagation(); const modalContainer = this.shadowRoot.querySelector('.modalContainer'); if (eventArg.target === modalContainer) { await this.destroy(); } } public async destroy() { const domtools = await this.domtoolsPromise; const modal = this.shadowRoot.querySelector('.modal'); modal.classList.add('predestroy'); await domtools.convenience.smartdelay.delayFor(200); document.body.removeChild(this); await this.windowLayer.destroy(); } }