import { html, css, render } from 'lit'; import { KeyboardShortcut, Scope } from './KeyboardShortcut'; import { KeyboardShortcutManager, ParsedKeyboardShortcut } from './KeyboardShortcutManager'; import { Dialog, DialogOverlay } from '@vaadin/dialog'; import { Grid } from '@vaadin/grid'; import '@vaadin/grid'; export class KeyboardShortcutDialog extends Dialog { shortcuts: ParsedKeyboardShortcut[] = []; private static HEADER_ID = 'header'; private static GRID_ID = 'shortcuts'; private headerText = 'Keyboard Shortcuts'; static get properties() { return { ...(Dialog as PrivateStaticDialog).properties, headerText: String }; } constructor() { super(); this.setGlobalStyles(); this.draggable = true; this.resizable = true; this.renderer = this.overlayRenderer; this.headerRenderer = this.overlayHeaderRenderer; this.addEventListener('opened-changed', () => { const id = 'vcf-keyboard-shortcut-dialog-overlay'; if (this.overlay && this.overlay.id !== id) this.overlay.id = id; }); } static get is() { return 'vcf-keyboard-shortcut-dialog'; } get overlay() { return this.private.$?.overlay ?? null; } get header() { let header = null; if (this.overlay) { header = this.overlay.querySelector(`#${KeyboardShortcutDialog.HEADER_ID}`) as HTMLHeadingElement | null; } return header; } open() { this.opened = true; } close() { this.opened = false; } get grid() { let grid = null; if (this.overlay) { grid = this.overlay.querySelector(`#${KeyboardShortcutDialog.GRID_ID}`) as Grid | null; } return grid; } private get private() { return this as PrivateDialog; } private overlayRenderer = (root: any) => { root.removeAttribute('with-backdrop'); render( html` `, root ); this.setPIModifierInfo(root); }; private setPIModifierInfo(root: HTMLElement) { requestAnimationFrame(() => { const { LIB_MODIFIER } = KeyboardShortcutManager; const content = root.querySelectorAll('vaadin-grid-cell-content'); const mods = Array.from(content).filter((i) => i.textContent?.includes(LIB_MODIFIER)) as HTMLElement[]; mods.forEach((mod) => { mod.innerText = mod.innerText.replace(LIB_MODIFIER, 'Command/Control'); }); }); } private overlayHeaderRenderer = (root: any) => { render(html``, root); }; private get items() { if (!this.shortcuts.length) { throw new Error('No shortcuts defined.'); } return this.shortcuts.map((s) => { const item = { command: s.description, keys: s.parsedKeyBinding, scope: this.getScopeName(s.scope) }; return item; }); } private getScopeName(scope?: Scope) { let name = 'Window'; if (scope && scope !== window) { const el = scope as HTMLElement; if (el.id) name = `#${el.id}`; else name = `${el.tagName}${el.className ? `.${el.className}` : ''}`; } return name; } private setGlobalStyles() { const styles = css` #vcf-keyboard-shortcut-dialog-overlay #header { margin: 0; } `; const styleElement = document.createElement('style'); styleElement.id = 'vcf-keyboard-shortcut-dialog-styles'; styleElement.innerHTML = styles.toString(); document.head.appendChild(styleElement); } } customElements.define(KeyboardShortcutDialog.is, KeyboardShortcutDialog); export { DialogOverlay as KeyboardShortcutOverlay }; /* PRIVATE TYPES */ type PrivateStaticDialog = typeof Dialog & { readonly properties: any }; type PrivateDialog = Dialog & { $?: { overlay: DialogOverlay } };