github.com/derat/nup@v0.0.0-20230418113745-15592ba7c620/web/dialog.ts (about) 1 // Copyright 2022 Daniel Erat. 2 // All rights reserved. 3 4 import { 5 $, 6 commonStyles, 7 createElement, 8 createShadow, 9 createTemplate, 10 } from './common.js'; 11 12 const dialogStyle = createTemplate(` 13 <style> 14 :host { 15 display: inline-block; /* let width be set */ 16 text-align: left; 17 } 18 div.title { 19 color: var(--dialog-title-color); 20 font-size: 18px; 21 font-weight: bold; 22 overflow: hidden; 23 text-overflow: ellipsis; 24 user-select: none; 25 white-space: nowrap; 26 } 27 hr.title { 28 background-color: var(--border-color); 29 border: 0; 30 height: 1px; 31 margin: 4px 0; 32 } 33 div.button-container { 34 margin-top: 4px; 35 text-align: right; 36 } 37 </style> 38 `); 39 40 const msgTemplate = createTemplate(` 41 <style> 42 :host { 43 width: 400px; 44 } 45 #message { 46 line-height: 18px; 47 margin-top: 10px; 48 } 49 </style> 50 <div id="title" class="title"></div> 51 <hr class="title" /> 52 <div id="message"></div> 53 <form method="dialog"> 54 <div class="button-container"> 55 <button id="ok-button" autofocus>OK</button> 56 </div> 57 </form> 58 `); 59 60 // Number of open dialogs. 61 let numDialogs = 0; 62 63 // Creates and shows a modal dialog filled with the supplied template. 64 // |className| is added to the <dialog>. The <dialog> element is returned, and 65 // the shadow root can be accessed via |dialog.firstElementChild.shadowRoot|. 66 export function createDialog( 67 template: HTMLTemplateElement, 68 className: string | null = null 69 ): HTMLDialogElement { 70 const dialog = createElement( 71 'dialog', 72 'dialog', 73 document.body 74 ) as HTMLDialogElement; 75 if (className) dialog.classList.add(className); 76 77 dialog.addEventListener('close', () => { 78 document.body.removeChild(dialog); 79 numDialogs--; 80 }); 81 82 // It seems like it isn't possible to attach a shadow root directly to 83 // <dialog>, so add a wrapper element first. See 84 // https://dom.spec.whatwg.org/#dom-element-attachshadow and 85 // https://github.com/WICG/webcomponents/issues/110. 86 const wrapper = createElement('span', null, dialog); 87 const shadow = createShadow(wrapper, dialogStyle); 88 shadow.adoptedStyleSheets = [commonStyles]; 89 shadow.appendChild(template.content.cloneNode(true)); 90 91 dialog.showModal(); 92 numDialogs++; 93 return dialog; 94 } 95 96 // Creates and shows a modal dialog with the supplied title and text. 97 // The dialog is not returned. 98 export function showMessageDialog(title: string, message: string) { 99 const dialog = createDialog(msgTemplate); 100 const shadow = dialog.firstElementChild!.shadowRoot!; 101 $('title', shadow).innerText = title; 102 $('message', shadow).innerText = message; 103 $('ok-button', shadow).addEventListener('click', () => dialog.close()); 104 } 105 106 // Returns true if a dialog is currently shown. 107 export const isDialogShown = () => numDialogs > 0;