import { html, css, TemplateResult, CSSResultArray } from 'lit'; import { customElement, property, state } from 'lit/decorators.js'; import NileElement from '../../internal/nile-element'; import '../../nile-button-toggle-group/index'; import '../../nile-button-toggle/index'; interface CharCategory { key: string; label: string; /** Representative glyph shown as the (iconified) tab label. */ icon: string; chars: string[]; } const CATEGORIES: CharCategory[] = [ { key: 'punctuation', label: 'Punctuation', icon: '¶', chars: [ '–', '—', '…', '‘', '’', '“', '”', '‚', '„', '«', '»', '‹', '›', '§', '¶', '†', '‡', '•', '·', '¡', '¿', '′', '″', '‰', ], }, { key: 'currency', label: 'Currency', icon: '$', chars: [ '$', '€', '£', '¥', '₹', '¢', '₩', '₽', '₺', '₪', '₫', '₦', '₴', '₱', '฿', '₿', ], }, { key: 'math', label: 'Math', icon: '∑', chars: [ '±', '×', '÷', '≠', '≈', '≤', '≥', '¬', '∞', '∑', '∏', '√', '∫', '∂', '∆', '∇', '∈', '∉', '∩', '∪', '⊂', '⊃', '°', 'µ', '‰', '½', '⅓', '¼', '¾', '⅛', ], }, { key: 'arrows', label: 'Arrows', icon: '→', chars: [ '←', '→', '↑', '↓', '↔', '↕', '⇐', '⇒', '⇑', '⇓', '⇔', '↩', '↪', '↖', '↗', '↘', '↙', '⟵', '⟶', ], }, { key: 'latin', label: 'Latin', icon: 'Á', chars: [ 'À', 'Á', 'Â', 'Ã', 'Ä', 'Å', 'Æ', 'Ç', 'È', 'É', 'Ê', 'Ë', 'Ì', 'Í', 'Î', 'Ï', 'Ñ', 'Ò', 'Ó', 'Ô', 'Õ', 'Ö', 'Ø', 'Ù', 'Ú', 'Û', 'Ü', 'ß', 'à', 'á', 'â', 'ã', 'ä', 'å', 'æ', 'ç', 'è', 'é', 'ê', 'ë', 'ì', 'í', 'î', 'ï', 'ñ', 'ò', 'ó', 'ô', 'õ', 'ö', 'ø', 'ù', 'ú', 'û', 'ü', 'ÿ', ], }, { key: 'symbols', label: 'Symbols', icon: '★', chars: [ '©', '®', '™', '℠', '№', '℮', '✓', '✗', '★', '☆', '♠', '♣', '♥', '♦', '☀', '☁', '☂', '♻', '⚠', '⌘', '⌥', '⇧', '⏎', '⌫', ], }, ]; /** * Special characters picker (the Ω toolbar item). Emits * `wysiwyg-char-select` detail: { char } and `wysiwyg-char-cancel`. */ @customElement('nile-wysiwyg-special-chars') export class NileWysiwygSpecialChars extends NileElement { @property({ type: Boolean, reflect: true }) open = false; @state() private category = CATEGORIES[0].key; public static get styles(): CSSResultArray { return [ css` :host { font-family: var( --nile-font-family-sans-serif, var(--ng-font-family-body, system-ui, -apple-system, sans-serif) ); position: absolute; z-index: 20; display: none; } :host([open]) { display: block; } .panel { width: 316px; padding: 8px; background: var(--nile-wysiwyg-popover-bg, #ffffff); border: 1px solid var(--nile-colors-neutral-400, #d0d5dd); border-radius: 8px; box-shadow: var(--nile-wysiwyg-popover-shadow, 0 4px 12px rgba(16, 24, 40, 0.12)); } .tabs { flex-wrap: wrap; margin-bottom: 8px; max-width: 100%; } .cat-icon { display: inline-block; min-width: 16px; font-size: 15px; line-height: 1; text-align: center; } .grid { display: grid; grid-template-columns: repeat(10, 1fr); gap: 2px; max-height: 180px; overflow-y: auto; overscroll-behavior: contain; } .char { font: inherit; font-size: 15px; height: 28px; border: none; border-radius: 5px; background: transparent; cursor: pointer; color: var(--nile-colors-dark-900, #101828); } .char:hover { background: var(--nile-colors-neutral-100, #f2f4f7); } `, ]; } private handleKeydown(event: KeyboardEvent): void { if (event.key === 'Escape') { event.stopPropagation(); this.emit('wysiwyg-char-cancel'); } } public render(): TemplateResult { const current = CATEGORIES.find(c => c.key === this.category) ?? CATEGORIES[0]; return html`