weml-monaco 0.5.2 → 0.7.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +56 -3
- package/README.md +161 -47
- package/dist/index.cjs +25587 -24926
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.mts +204 -11
- package/dist/index.d.ts +204 -11
- package/dist/index.global.js +142 -132
- package/dist/index.mjs +25591 -24930
- package/dist/index.mjs.map +1 -1
- package/dist/panel.cjs +1314 -0
- package/dist/panel.cjs.map +1 -0
- package/dist/panel.css +261 -0
- package/dist/panel.d.mts +106 -0
- package/dist/panel.d.ts +106 -0
- package/dist/panel.mjs +1291 -0
- package/dist/panel.mjs.map +1 -0
- package/dist/preview.cjs +324 -0
- package/dist/preview.cjs.map +1 -0
- package/dist/preview.d.mts +63 -0
- package/dist/preview.d.ts +63 -0
- package/dist/preview.mjs +301 -0
- package/dist/preview.mjs.map +1 -0
- package/dist/weml.worker.d.mts +2 -0
- package/dist/weml.worker.mjs +25164 -0
- package/dist/weml.worker.mjs.map +1 -0
- package/dist/worker.cjs +8596 -0
- package/dist/worker.cjs.map +1 -0
- package/dist/worker.d.mts +21 -0
- package/dist/worker.d.ts +21 -0
- package/dist/worker.mjs +8597 -0
- package/dist/worker.mjs.map +1 -0
- package/package.json +57 -12
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/panel/index.ts","../src/panel/panes.ts","../src/panel/dom.ts","../src/panel/searchPane.ts","../src/panel/styles.ts","../../weml-language-core/src/generated/schema.ts","../../weml-language-core/src/toolbar/toolModel.ts","../src/panel/toolPicker.ts","../src/panel/toolsPane.ts","../src/panel/panel.ts"],"sourcesContent":["// `weml-monaco/panel`: the WEML panel (Tools + Search Suggestions) — framework-free, the same in\n// VS Code and on the web.\n//\n// import { createMonacoPanelHost } from 'weml-monaco';\n// import { createWemlPanel } from 'weml-monaco/panel';\n// createWemlPanel(createMonacoPanelHost(editor, { search: { apiUrl, getAccessToken } }), { container });\n//\n// The panel itself is only UI (light); `createMonacoPanelHost`, which edits a Monaco editor, is in\n// the main entry: its Renumber needs the HTML parser the main bundle already carries, which would\n// otherwise be bundled a second time here. A VS Code webview uses the panel without it.\n//\n// The stylesheet is injected by default; it is also published as `weml-monaco/panel.css`.\n\nexport { createWemlPanel } from './panel';\nexport { injectPanelStyles, PANEL_CLASS, PANEL_CSS } from './styles';\nexport type {\n WemlPanel,\n WemlPanelHost,\n WemlPanelOptions,\n WemlPanelSearch,\n WemlPanelStorage,\n WemlPanelTools,\n WemlSearchResult,\n WemlSearchState,\n} from './types';\n","// Panes like the Explorer's (Outline, Timeline): each collapses from its header, each open one\n// scrolls on its own, and the sash on a pane's top edge resizes it against the open pane above.\n// Collapsed panes and sizes are remembered in the panel's state. (Ported from weml-tools'\n// media/view.js; the state keeps that file's shape, so a VS Code user's layout survives.)\n\n/** The panel state as stored: collapsed pane ids, pane weights, and each pane's own values. */\nexport interface PanelState {\n collapsed?: string[];\n weights?: Record<string, number>;\n modules?: Record<string, unknown>;\n}\n\nexport interface PaneSpec {\n /** Stable id: the state key, and `data-group` on the pane. */\n id: string;\n title: string;\n body: HTMLElement;\n /** The pane lays itself out: nothing scrolls but the element marked `.scroll`. */\n fill?: boolean;\n}\n\nexport interface Panes {\n element: HTMLElement;\n dispose(): void;\n}\n\n/** Smallest body height of an open pane while resizing, in px. */\nconst MIN_BODY = 48;\nconst HEADER = 22;\n\nexport function createPanes(specs: PaneSpec[], state: PanelState, save: () => void): Panes {\n const root = document.createElement('div');\n root.className = 'weml-panes';\n const collapsed = new Set(state.collapsed ?? []);\n /** Flex weights of the open panes; a pane's weight is its share of the free height. */\n const weights: Record<string, number> = { ...state.weights };\n const cleanups: (() => void)[] = [];\n\n const panes = specs.map((spec) => {\n const pane = document.createElement('section');\n pane.className = 'pane';\n pane.setAttribute('data-group', spec.id);\n const sash = document.createElement('div');\n sash.className = 'sash';\n sash.setAttribute('aria-hidden', 'true');\n const header = document.createElement('div');\n header.className = 'pane-header';\n header.setAttribute('role', 'button');\n header.tabIndex = 0;\n header.textContent = spec.title;\n const body = document.createElement('div');\n body.className = spec.fill ? 'pane-body fill' : 'pane-body';\n body.append(spec.body);\n pane.append(sash, header, body);\n root.append(pane);\n return { spec, pane, sash, header };\n });\n\n const isOpen = (id: string) => !collapsed.has(id);\n\n const layout = () => {\n // A pane with no remembered size (never resized, or just added) gets the average of the\n // open ones — weights become pixel heights after a drag, so a plain 1 would be a sliver.\n const known = panes.filter((p) => isOpen(p.spec.id)).map((p) => weights[p.spec.id]).filter((w) => w !== undefined);\n const fallback = known.length > 0 ? known.reduce((sum, w) => sum + w, 0) / known.length : 1;\n let openAbove = false;\n for (const { spec, pane, header } of panes) {\n const open = isOpen(spec.id);\n pane.classList.toggle('collapsed', !open);\n header.setAttribute('aria-expanded', String(open));\n pane.style.flex = open ? `${weights[spec.id] ?? fallback} 1 0px` : '0 0 auto';\n // A sash only between two open panes: this one and one somewhere above it.\n pane.classList.toggle('resizable', open && openAbove);\n openAbove ||= open;\n }\n };\n\n const persist = () => {\n state.collapsed = [...collapsed];\n state.weights = { ...weights };\n save();\n };\n\n panes.forEach(({ spec, pane, sash, header }, index) => {\n const toggle = () => {\n if (collapsed.has(spec.id)) collapsed.delete(spec.id);\n else collapsed.add(spec.id);\n persist();\n layout();\n };\n header.addEventListener('click', toggle);\n header.addEventListener('keydown', (event) => {\n if (event.key === 'Enter' || event.key === ' ') {\n event.preventDefault();\n toggle();\n }\n });\n\n sash.addEventListener('pointerdown', (event) => {\n if (!pane.classList.contains('resizable')) return;\n const above = panes.slice(0, index).reverse().find((p) => isOpen(p.spec.id));\n if (!above) return;\n event.preventDefault();\n sash.setPointerCapture?.(event.pointerId);\n sash.classList.add('active');\n\n // Freeze every open pane at its current height, so only these two change.\n for (const open of panes.filter((p) => isOpen(p.spec.id))) {\n weights[open.spec.id] = open.pane.getBoundingClientRect().height;\n }\n const startY = event.clientY;\n const aboveStart = weights[above.spec.id];\n const paneStart = weights[spec.id];\n const min = HEADER + MIN_BODY;\n\n const move = (moveEvent: PointerEvent) => {\n const total = aboveStart + paneStart;\n const aboveHeight = Math.min(Math.max(aboveStart + moveEvent.clientY - startY, min), total - min);\n weights[above.spec.id] = aboveHeight;\n weights[spec.id] = total - aboveHeight;\n layout();\n };\n const end = () => {\n sash.classList.remove('active');\n sash.removeEventListener('pointermove', move);\n persist();\n };\n sash.addEventListener('pointermove', move);\n sash.addEventListener('pointerup', end, { once: true });\n sash.addEventListener('pointercancel', end, { once: true });\n });\n // Double-click on a sash: share the height evenly again, as the Explorer does.\n sash.addEventListener('dblclick', () => {\n for (const key of Object.keys(weights)) delete weights[key];\n persist();\n layout();\n });\n });\n layout();\n\n // A shadow under the top edge of whatever is scrolled down, as in the workbench's lists.\n const onScroll = (event: Event) => {\n const target = event.target;\n if (target instanceof HTMLElement && target.matches('.pane-body, .scroll')) {\n target.classList.toggle('scrolled', target.scrollTop > 0);\n }\n };\n root.addEventListener('scroll', onScroll, true);\n cleanups.push(() => root.removeEventListener('scroll', onScroll, true));\n\n return {\n element: root,\n dispose: () => cleanups.forEach((cleanup) => cleanup()),\n };\n}\n","// Small DOM helpers of the WEML panel. Text is always set with textContent, never parsed as HTML\n// (search results come from a remote service).\n\nexport function element<K extends keyof HTMLElementTagNameMap>(\n tag: K,\n options: { className?: string; text?: string; title?: string } = {},\n children: Node[] = [],\n): HTMLElementTagNameMap[K] {\n const node = document.createElement(tag);\n if (options.className) node.className = options.className;\n if (options.text !== undefined) node.textContent = options.text;\n if (options.title) node.title = options.title;\n node.append(...children);\n return node;\n}\n\n/** Icons drawn inline (16px, currentColor): the narrow panel needs no icon font. */\nconst ICONS = {\n search: '<circle cx=\"7\" cy=\"7\" r=\"4.5\"/><path d=\"M10.3 10.3L14 14\"/>',\n copy: '<rect x=\"5.5\" y=\"5.5\" width=\"8\" height=\"8\" rx=\"1\"/><path d=\"M3.5 10.5h-1v-8h8v1\"/>',\n insert: '<path d=\"M13 3v5.5a2 2 0 0 1-2 2H4\"/><path d=\"M6.5 8L4 10.5 6.5 13\"/>',\n wrap: '<path d=\"M5.5 3H3.5v10h2\"/><path d=\"M10.5 3h2v10h-2\"/><path d=\"M6.5 8h3\"/>',\n add: '<path d=\"M8 3.5v9M3.5 8h9\"/>',\n} as const;\n\nexport type IconName = keyof typeof ICONS;\n\nexport function icon(name: IconName): SVGSVGElement {\n const svg = document.createElementNS('http://www.w3.org/2000/svg', 'svg');\n svg.setAttribute('viewBox', '0 0 16 16');\n svg.setAttribute('aria-hidden', 'true');\n // Our own constant markup, not data.\n svg.innerHTML = ICONS[name];\n return svg;\n}\n\n/** A button. Every icon button carries its name as title and aria-label. */\nexport function button(\n options: { text?: string; icon?: IconName; title?: string; className?: string; type?: 'button' | 'submit' },\n onClick?: () => void,\n): HTMLButtonElement {\n const node = element('button', { className: options.className, text: options.text, title: options.title });\n node.type = options.type ?? 'button';\n if (options.icon) {\n node.append(icon(options.icon));\n if (options.title) node.setAttribute('aria-label', options.title);\n }\n if (onClick) node.addEventListener('click', onClick);\n return node;\n}\n","// The Search Suggestions pane: EGW search, with ParaId / BookCode to copy and an `egw://` link to\n// copy or insert in place of the selection. Presentation only — the request, the token and the\n// edit are the host's (see WemlPanelSearch).\n\nimport { button, element } from './dom';\nimport type { WemlPanelSearch, WemlSearchResult, WemlSearchState } from './types';\n\n/** What the pane remembers: the language (the query starts empty every time). */\ninterface SearchPaneState {\n lang?: string;\n}\n\nexport interface SearchPane {\n element: HTMLElement;\n dispose(): void;\n}\n\nexport function createSearchPane(\n search: WemlPanelSearch,\n memory: { get(): SearchPaneState | undefined; set(value: SearchPaneState): void },\n): SearchPane {\n const account = element('div', { className: 'account' });\n const query = element('input', { className: 'grow' });\n query.type = 'text';\n query.placeholder = 'Search…';\n query.setAttribute('aria-label', 'Search suggestions');\n const lang = element('input', { className: 'weml-lang', title: 'Language code, e.g. en' });\n lang.type = 'text';\n lang.placeholder = 'lang';\n lang.setAttribute('aria-label', 'Language');\n const searchButton = button({ icon: 'search', title: 'Search', className: 'icon', type: 'submit' });\n const form = element('form', {}, [element('div', { className: 'row' }, [query, lang, searchButton])]);\n form.hidden = true;\n const status = element('div', { className: 'status' });\n status.setAttribute('aria-live', 'polite');\n const results = element('ol', { className: 'results scroll' });\n const root = element('section', {}, [account, form, status, results]);\n\n lang.value = memory.get()?.lang ?? '';\n lang.addEventListener('input', () => memory.set({ lang: lang.value }));\n\n /** Bumped by every search and every reset: an answer for an older one is dropped. */\n let generation = 0;\n let disposed = false;\n\n const renderResults = (state: { query: string | null; loading?: boolean; error?: string; results?: WemlSearchResult[] }) => {\n searchButton.disabled = !!state.loading;\n status.className = state.error ? 'status error' : 'status';\n status.textContent = state.loading\n ? 'Searching…'\n : state.error ?? (state.query && state.results?.length === 0 ? `Nothing found for “${state.query}”` : '');\n results.replaceChildren();\n (state.results ?? []).forEach((suggestion, index) => {\n const item = element('li');\n item.append(element('span', { className: 'number', text: String(index + 1) }));\n\n const meta = element('div', { className: 'meta' });\n const paraId = element('span', { className: 'field' }, [\n element('span', { className: 'label', text: 'ParaId ' }),\n element('span', { className: 'value', text: suggestion.paraId || '—' }),\n ]);\n if (suggestion.paraId) {\n paraId.append(button({ icon: 'copy', title: 'Copy ParaId', className: 'icon flat' }, () => search.copy(suggestion.paraId)));\n }\n meta.append(paraId, element('span', { className: 'field' }, [\n element('span', { className: 'label', text: 'BookCode ' }),\n element('span', { className: 'value', text: suggestion.bookCode || '—' }),\n ]));\n item.append(meta, element('div', { className: 'title', text: suggestion.title }));\n\n if (suggestion.link) {\n const link = suggestion.link;\n item.append(element('div', { className: 'link' }, [\n element('code', { text: link }),\n element('div', { className: 'actions' }, [\n button({ icon: 'copy', title: 'Copy link', className: 'icon flat' }, () => search.copy(link)),\n button(\n {\n icon: 'insert',\n title: 'Insert the link in place of the selection (the selection becomes its label)',\n className: 'icon flat primary',\n },\n () => search.insertLink(index),\n ),\n ]),\n ]));\n }\n results.append(item);\n });\n };\n\n const clearResults = () => {\n generation++;\n renderResults({ query: null, results: [] });\n };\n\n form.addEventListener('submit', (event) => {\n event.preventDefault();\n const text = query.value.trim();\n if (!text) {\n clearResults();\n return;\n }\n const current = ++generation;\n renderResults({ query: text, loading: true });\n search.search(text, lang.value.trim()).then(\n (found) => {\n if (!disposed && current === generation) renderResults({ query: text, results: found });\n },\n (error: unknown) => {\n if (!disposed && current === generation) {\n renderResults({ query: text, error: error instanceof Error ? error.message : 'Search failed' });\n }\n },\n );\n });\n\n /**\n * Sign-in shows here only when it is missing — not configured, or signed out. Signed in, the\n * account belongs to the host (VS Code's title bar, a web app's own header), and this is just\n * the search.\n */\n const renderState = (state: WemlSearchState) => {\n account.replaceChildren();\n // The host's default language fills an empty field; `en` only once search can run, so a\n // default that arrives with the sign-in is not shadowed by an earlier guess.\n const fallback = state.kind === 'not-configured' ? undefined : state.defaultLanguage || (state.kind === 'signed-in' ? 'en' : undefined);\n if (!lang.value && fallback) lang.value = fallback;\n const signedIn = state.kind === 'signed-in';\n account.hidden = signedIn;\n form.hidden = !signedIn;\n if (!signedIn) clearResults();\n if (state.kind === 'not-configured') {\n account.append(element('span', { text: state.message }));\n if (state.canOpenSettings && search.openSettings) {\n account.append(button({ text: 'Open Settings', className: 'link' }, () => search.openSettings?.()));\n }\n } else if (state.kind === 'signed-out') {\n const failure = element('span', { className: 'status error' });\n const signIn = () => {\n failure.textContent = '';\n Promise.resolve(search.signIn()).catch((error: unknown) => {\n if (!disposed) failure.textContent = error instanceof Error ? error.message : 'Sign-in failed';\n });\n };\n account.append(button({ text: 'Sign in', className: 'full', title: 'Sign in to EGW Writings' }, signIn), failure);\n }\n };\n\n const refresh = () => {\n Promise.resolve(search.getState()).then(\n (state) => {\n if (!disposed) renderState(state);\n },\n () => {\n if (!disposed) renderState({ kind: 'not-configured', message: 'Search is not available.' });\n },\n );\n };\n const unsubscribe = search.onDidChangeState(refresh);\n refresh();\n\n return {\n element: root,\n dispose: () => {\n disposed = true;\n unsubscribe();\n },\n };\n}\n","// The WEML panel's stylesheet: the look of VS Code's side bar (the WEML Tools view), on the\n// `--vscode-*` theme variables only — a VS Code webview defines them on <html>, Monaco on\n// `.monaco-component` — and scoped to `.weml-panel`, so it can sit in any container of any page.\n// Kept as a string so it can be injected; the build also writes it out as `dist/panel.css`.\n\nexport const PANEL_CLASS = 'weml-panel';\n\nconst STYLE_ID = 'weml-panel-styles';\n\nexport const PANEL_CSS = `\n.weml-panel {\n display: flex;\n flex-direction: column;\n height: 100%;\n min-height: 0;\n box-sizing: border-box;\n overflow: hidden;\n font-family: var(--vscode-font-family, system-ui, sans-serif);\n font-size: var(--vscode-font-size, 13px);\n /* A webview's own; a host page's (Mantine: 1.55) would make every row taller than in VS Code. */\n line-height: normal;\n color: var(--vscode-foreground);\n}\n\n/* Panes, like the Explorer's (Outline, Timeline): the panel's height is shared by the open panes,\n each scrolls on its own, a collapsed one is just its 22px header; the sash on a pane's top edge\n resizes it against the open pane above. */\n.weml-panel .weml-panes { display: flex; flex-direction: column; flex: 1 1 auto; min-height: 0; }\n.weml-panel .pane { position: relative; display: flex; flex-direction: column; min-height: 22px; overflow: hidden; }\n.weml-panel .pane:not(.collapsed) { min-height: 70px; }\n/* The border colours fall back to editorWidget.border: Monaco defines no sideBar*, panel or widget\n colours, only the editor's own, and without it the panes and results run into each other. */\n.weml-panel .pane + .pane { border-top: 1px solid var(--vscode-sideBarSectionHeader-border, var(--vscode-panel-border, var(--vscode-editorWidget-border, transparent))); }\n.weml-panel .pane-header {\n display: flex;\n align-items: center;\n gap: 2px;\n flex: none;\n height: 22px;\n padding: 0 8px 0 2px;\n cursor: pointer;\n user-select: none;\n font-size: 11px;\n font-weight: 700;\n text-transform: uppercase;\n color: var(--vscode-sideBarSectionHeader-foreground, var(--vscode-foreground));\n background: var(--vscode-sideBarSectionHeader-background, transparent);\n}\n.weml-panel .pane-header::before {\n content: '';\n width: 16px;\n height: 16px;\n flex: none;\n /* chevron-right, turned down when open */\n background: currentColor;\n -webkit-mask: url(\"data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 16 16'%3E%3Cpath d='M6 4l4 4-4 4' fill='none' stroke='black' stroke-width='1.3'/%3E%3C/svg%3E\") center / 16px no-repeat;\n mask: url(\"data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 16 16'%3E%3Cpath d='M6 4l4 4-4 4' fill='none' stroke='black' stroke-width='1.3'/%3E%3C/svg%3E\") center / 16px no-repeat;\n transform: rotate(90deg);\n transition: transform .1s;\n}\n.weml-panel .pane.collapsed .pane-header::before { transform: none; }\n.weml-panel .pane-header:focus-visible { outline: 1px solid var(--vscode-focusBorder); outline-offset: -1px; }\n.weml-panel .pane-body { flex: 1 1 auto; min-height: 0; overflow: auto; padding: 6px 12px 12px 20px; }\n.weml-panel .pane.collapsed .pane-body { display: none; }\n/* A pane that lays itself out (the search): nothing scrolls but its .scroll part. */\n.weml-panel .pane-body.fill { display: flex; flex-direction: column; overflow: hidden; padding-bottom: 0; }\n.weml-panel .pane-body.fill > section { display: flex; flex-direction: column; flex: 1 1 auto; min-height: 0; margin: 0; }\n.weml-panel .pane-body.fill > section > * { flex: none; }\n.weml-panel .pane-body.fill .scroll { flex: 1 1 auto; min-height: 0; overflow: auto; padding-bottom: 12px; }\n\n.weml-panel .sash { position: absolute; top: -2px; left: 0; right: 0; height: 4px; z-index: 10; display: none; }\n.weml-panel .pane.resizable .sash { display: block; cursor: ns-resize; }\n.weml-panel .sash:hover, .weml-panel .sash.active {\n background: var(--vscode-sash-hoverBorder, var(--vscode-focusBorder));\n transition: background .1s .2s;\n}\n\n.weml-panel .pane-body section { margin-bottom: 14px; }\n.weml-panel .pane-body section:last-child { margin-bottom: 0; }\n.weml-panel h2 {\n margin: 0 0 6px;\n font-size: 11px;\n font-weight: 600;\n text-transform: uppercase;\n letter-spacing: .04em;\n color: var(--vscode-sideBarSectionHeader-foreground, var(--vscode-foreground));\n opacity: .8;\n}\n.weml-panel [hidden] { display: none !important; }\n.weml-panel .row { display: flex; gap: 6px; margin-bottom: 6px; }\n.weml-panel input, .weml-panel select, .weml-panel button {\n box-sizing: border-box;\n min-width: 0;\n font-family: inherit;\n font-size: inherit;\n color: var(--vscode-input-foreground);\n background: var(--vscode-input-background);\n border: 1px solid var(--vscode-input-border, transparent);\n border-radius: 2px;\n padding: 4px 6px;\n /* 26px with the padding and border, VS Code's input and button height (the icon buttons too). */\n line-height: 16px;\n}\n.weml-panel select { height: 26px; padding-block: 0; }\n.weml-panel select {\n color: var(--vscode-dropdown-foreground);\n background: var(--vscode-dropdown-background);\n border-color: var(--vscode-dropdown-border, transparent);\n}\n.weml-panel input:focus, .weml-panel select:focus, .weml-panel button:focus-visible { outline: 1px solid var(--vscode-focusBorder); outline-offset: -1px; }\n.weml-panel .full { width: 100%; }\n.weml-panel .grow { flex: 1 1 auto; }\n.weml-panel .weml-lang { flex: 0 0 44px; }\n\n/* Icon buttons: a square with a 16px inline SVG; the name is in title / aria-label. */\n.weml-panel button.icon {\n display: inline-flex;\n align-items: center;\n justify-content: center;\n flex: none;\n width: 26px;\n height: 26px;\n padding: 0;\n}\n.weml-panel button.icon svg { width: 16px; height: 16px; fill: none; stroke: currentColor; stroke-width: 1.2; stroke-linecap: round; stroke-linejoin: round; }\n.weml-panel button.icon.flat {\n width: 20px;\n height: 20px;\n border: none;\n background: none;\n color: var(--vscode-icon-foreground, var(--vscode-foreground));\n border-radius: 3px;\n}\n.weml-panel button.icon.flat:hover { background: var(--vscode-toolbar-hoverBackground, rgba(128, 128, 128, .2)); }\n/* The main action of a row: the same small square, filled like a primary button. */\n.weml-panel button.icon.flat.primary { color: var(--vscode-button-foreground); background: var(--vscode-button-background); }\n.weml-panel button.icon.flat.primary:hover { background: var(--vscode-button-hoverBackground); }\n\n/* The tag picker: an input with its action inside (as the find widget's toggles), and a list drawn\n as the quick pick — rows, matched characters, group separators — on the quick input's colours,\n which VS Code and Monaco (its own command palette) both define. */\n.weml-panel .tool-field {\n display: flex;\n align-items: center;\n gap: 2px;\n box-sizing: border-box;\n height: 26px;\n padding-right: 2px;\n background: var(--vscode-input-background);\n border: 1px solid var(--vscode-input-border, transparent);\n border-radius: 2px;\n}\n.weml-panel .tool-field:focus-within { outline: 1px solid var(--vscode-focusBorder); outline-offset: -1px; }\n.weml-panel .tool-field input { flex: 1 1 auto; height: 24px; border: none; background: none; }\n.weml-panel .tool-field input:focus { outline: none; }\n.weml-panel .tool-field input::placeholder, .weml-panel input::placeholder { color: var(--vscode-input-placeholderForeground); }\n.weml-panel button[aria-disabled=\"true\"] { opacity: .5; cursor: default; }\n.weml-panel button.icon.flat.primary[aria-disabled=\"true\"]:hover { background: var(--vscode-button-background); }\n.weml-panel .tool-list {\n position: fixed;\n z-index: 1000;\n box-sizing: border-box;\n overflow-y: auto;\n padding: 4px 0;\n color: var(--vscode-quickInput-foreground, var(--vscode-foreground));\n background: var(--vscode-quickInput-background, var(--vscode-editorWidget-background));\n border: 1px solid var(--vscode-widget-border, var(--vscode-editorWidget-border, transparent));\n border-radius: 3px;\n box-shadow: 0 0 8px 2px var(--vscode-widget-shadow, rgba(0, 0, 0, .36));\n}\n.weml-panel .tool-group + .tool-group { margin-top: 4px; border-top: 1px solid var(--vscode-pickerGroup-border, transparent); }\n.weml-panel .tool-group-label {\n padding: 2px 8px 0;\n text-align: right;\n font-size: 11px;\n line-height: 16px;\n color: var(--vscode-pickerGroup-foreground, var(--vscode-descriptionForeground));\n}\n.weml-panel .tool-option {\n display: flex;\n align-items: center;\n gap: 12px;\n height: 22px;\n padding: 0 8px;\n white-space: nowrap;\n cursor: pointer;\n}\n.weml-panel .tool-option:hover { background: var(--vscode-list-hoverBackground); }\n.weml-panel .tool-option.active {\n color: var(--vscode-quickInputList-focusForeground, var(--vscode-list-activeSelectionForeground));\n background: var(--vscode-quickInputList-focusBackground, var(--vscode-list-activeSelectionBackground));\n}\n.weml-panel .tool-option .highlight { font-weight: 600; color: var(--vscode-list-highlightForeground); }\n.weml-panel .tool-option.active .highlight { color: var(--vscode-list-focusHighlightForeground, var(--vscode-list-highlightForeground)); }\n.weml-panel .tool-kind { margin-left: auto; font-size: 11px; color: var(--vscode-descriptionForeground); }\n.weml-panel .tool-option.active .tool-kind { color: inherit; opacity: .8; }\n.weml-panel .tool-empty { padding: 2px 8px; color: var(--vscode-descriptionForeground); }\n\n/* Scrollbars like the workbench's lists: thin, theme-coloured, shown while the pointer is over the\n scrolling area; a shadow under the top edge once the content is scrolled. */\n.weml-panel .pane-body, .weml-panel .scroll { scrollbar-gutter: stable; }\n/* Chromium ignores every ::-webkit-scrollbar rule on an element whose scrollbar-color or\n scrollbar-width is set - and scrollbar-color inherits - drawing its standard scrollbar with arrow\n buttons instead. Reset both, whoever set them, so the rules below apply. */\n.weml-panel, .weml-panel *, .weml-panel *::before, .weml-panel *::after { scrollbar-color: auto !important; scrollbar-width: auto !important; }\n.weml-panel ::-webkit-scrollbar { width: 10px; height: 10px; }\n.weml-panel ::-webkit-scrollbar-button { display: none; width: 0; height: 0; }\n.weml-panel ::-webkit-scrollbar-track, .weml-panel ::-webkit-scrollbar-corner { background: transparent; }\n.weml-panel ::-webkit-scrollbar-thumb { background: transparent; }\n.weml-panel .pane-body:hover::-webkit-scrollbar-thumb, .weml-panel .scroll:hover::-webkit-scrollbar-thumb { background: var(--vscode-scrollbarSlider-background); }\n.weml-panel ::-webkit-scrollbar-thumb:hover { background: var(--vscode-scrollbarSlider-hoverBackground) !important; }\n.weml-panel ::-webkit-scrollbar-thumb:active { background: var(--vscode-scrollbarSlider-activeBackground) !important; }\n.weml-panel .pane-body.scrolled, .weml-panel .scroll.scrolled { box-shadow: var(--vscode-scrollbar-shadow, rgba(0, 0, 0, .4)) 0 6px 6px -6px inset; }\n.weml-panel button {\n cursor: pointer;\n color: var(--vscode-button-foreground);\n background: var(--vscode-button-background);\n border: 1px solid var(--vscode-button-border, transparent);\n}\n.weml-panel button:hover { background: var(--vscode-button-hoverBackground); }\n.weml-panel button:disabled { opacity: .6; cursor: default; }\n.weml-panel button.secondary {\n color: var(--vscode-button-secondaryForeground);\n background: var(--vscode-button-secondaryBackground);\n}\n.weml-panel button.secondary:hover { background: var(--vscode-button-secondaryHoverBackground); }\n.weml-panel button.link {\n padding: 0;\n border: none;\n background: none;\n color: var(--vscode-textLink-foreground);\n}\n.weml-panel button.link:hover { background: none; color: var(--vscode-textLink-activeForeground); text-decoration: underline; }\n\n/* Search suggestions */\n.weml-panel .account { display: flex; flex-wrap: wrap; gap: 6px; align-items: baseline; margin-bottom: 8px; color: var(--vscode-descriptionForeground); }\n.weml-panel .status { color: var(--vscode-descriptionForeground); margin: 4px 0; }\n.weml-panel .status.error { color: var(--vscode-errorForeground); }\n.weml-panel .results { list-style: none; margin: 0; padding: 0; }\n.weml-panel .results li {\n display: grid;\n grid-template-columns: auto 1fr;\n column-gap: 8px;\n padding: 6px 0;\n border-top: 1px solid var(--vscode-widget-border, var(--vscode-panel-border, var(--vscode-editorWidget-border)));\n}\n.weml-panel .results li:last-child { border-bottom: 1px solid var(--vscode-widget-border, var(--vscode-panel-border, var(--vscode-editorWidget-border))); }\n.weml-panel .results .number { grid-row: span 3; color: var(--vscode-descriptionForeground); font-variant-numeric: tabular-nums; }\n.weml-panel .results .meta { display: flex; flex-wrap: wrap; gap: 4px 10px; align-items: center; }\n.weml-panel .results .label { color: var(--vscode-descriptionForeground); font-size: 11px; }\n.weml-panel .results .value { font-family: var(--vscode-editor-font-family); }\n.weml-panel .results .title { margin: 2px 0; overflow-wrap: anywhere; }\n.weml-panel .results .field { display: inline-flex; align-items: center; gap: 2px; white-space: nowrap; }\n/* The link and its actions share one box: the code, then Copy and Insert in a row under it. */\n.weml-panel .results .link {\n margin-top: 2px;\n padding: 4px 6px 2px;\n border-radius: 3px;\n background: var(--vscode-textPreformat-background, var(--vscode-textCodeBlock-background));\n}\n.weml-panel .results .link code {\n display: block;\n padding: 0;\n background: none;\n font-family: var(--vscode-editor-font-family);\n font-size: 11px;\n overflow-wrap: anywhere;\n color: var(--vscode-textPreformat-foreground);\n}\n.weml-panel .results .link .actions { display: flex; justify-content: flex-end; gap: 2px; margin-top: 2px; }\n.weml-panel .dim { color: var(--vscode-descriptionForeground); }\n`;\n\n/** Adds the stylesheet to `document.head` once per page. */\nexport function injectPanelStyles(doc: Document = document): void {\n if (doc.getElementById(STYLE_ID)) return;\n const style = doc.createElement('style');\n style.id = STYLE_ID;\n style.textContent = PANEL_CSS;\n doc.head.appendChild(style);\n}\n","// AUTO-GENERATED by tools/generate-schema.mjs from docs/*.md.\n// Do not edit by hand — run `npm run generate-schema` to regenerate.\n\nexport interface EnumValue {\n value: string;\n name: string;\n description: string;\n}\n\nexport interface EnumSchema {\n id: string;\n title: string;\n values: EnumValue[];\n}\n\nexport interface AttributeSchema {\n name: string;\n required: boolean;\n default?: string;\n description: string;\n enumRef?: string;\n}\n\nexport interface TagSchema {\n tag: string;\n description: string;\n attributes: AttributeSchema[];\n notes: string;\n source: string;\n}\n\nexport interface MetaFieldSchema {\n name: string;\n description: string;\n enumRef?: string;\n}\n\nexport const ENUMS: Record<string, EnumSchema> = {\n \"entity-type\": {\n \"id\": \"entity-type\",\n \"title\": \"Entity type\",\n \"values\": [\n {\n \"value\": \"addressee\",\n \"name\": \"Addressee\",\n \"description\": \"For Letter it means person whom this letter is addressed to.\"\n },\n {\n \"value\": \"date\",\n \"name\": \"Date\",\n \"description\": \"Date entity. For LT/MS it means date when document was written. Optional value contains single date, range of dates (two date via `...`) or two different date via `,` — all of dates must be in ISO 8601 format.\"\n },\n {\n \"value\": \"place\",\n \"name\": \"Place\",\n \"description\": \"Place. For Lt/Ms it means place where manuscript was written\"\n },\n {\n \"value\": \"topic\",\n \"name\": \"Topic\",\n \"description\": \"Topic entity. For topical index it marks whole topic. For dictionary it marks topic in the header.\"\n },\n {\n \"value\": \"topic-word\",\n \"name\": \"Topic word\",\n \"description\": \"Topic word entity. For topical index it marks the main term of a topic. For dictionary it marks topic in the regular paragraph.\"\n }\n ]\n },\n \"horizontal-alignment\": {\n \"id\": \"horizontal-alignment\",\n \"title\": \"Horizontal Alignment\",\n \"values\": [\n {\n \"value\": \"left\",\n \"name\": \"Left\",\n \"description\": \"Align text to the left\"\n },\n {\n \"value\": \"center\",\n \"name\": \"Center\",\n \"description\": \"Align text to the center\"\n },\n {\n \"value\": \"right\",\n \"name\": \"Right\",\n \"description\": \"Align text to the right\"\n }\n ]\n },\n \"figure-alignment\": {\n \"id\": \"figure-alignment\",\n \"title\": \"Figure Alignment\",\n \"values\": [\n {\n \"value\": \"left\",\n \"name\": \"Left\",\n \"description\": \"Align to the left\"\n },\n {\n \"value\": \"center\",\n \"name\": \"Center\",\n \"description\": \"Align to the center\"\n },\n {\n \"value\": \"right\",\n \"name\": \"Right\",\n \"description\": \"Align to the right\"\n },\n {\n \"value\": \"justify\",\n \"name\": \"Justify\",\n \"description\": \"Full-width alignment\"\n }\n ]\n },\n \"list-type\": {\n \"id\": \"list-type\",\n \"title\": \"List Type\",\n \"values\": [\n {\n \"value\": \"unordered\",\n \"name\": \"Unordered\",\n \"description\": \"Unordered list. Each item is marked with a bullet.\"\n },\n {\n \"value\": \"ordered\",\n \"name\": \"Ordered\",\n \"description\": \"Ordered list. Each item is marked with a number.\"\n }\n ]\n },\n \"non-egw-type\": {\n \"id\": \"non-egw-type\",\n \"title\": \"Non-EGW Type\",\n \"values\": [\n {\n \"value\": \"appendix\",\n \"name\": \"Appendix\",\n \"description\": \"Non-EGW Appendix\"\n },\n {\n \"value\": \"comment\",\n \"name\": \"Comment\",\n \"description\": \"Non-EGW Commentary\"\n },\n {\n \"value\": \"foreword\",\n \"name\": \"Foreword\",\n \"description\": \"Non-EGW Foreword\"\n },\n {\n \"value\": \"intro\",\n \"name\": \"Intro\",\n \"description\": \"Non-EGW Introduction\"\n },\n {\n \"value\": \"note\",\n \"name\": \"Note\",\n \"description\": \"Non-EGW Note\"\n },\n {\n \"value\": \"preface\",\n \"name\": \"Preface\",\n \"description\": \"Non-EGW Preface\"\n },\n {\n \"value\": \"text\",\n \"name\": \"Text\",\n \"description\": \"Non-EGW Text\"\n }\n ]\n },\n \"note-types\": {\n \"id\": \"note-types\",\n \"title\": \"Note types\",\n \"values\": [\n {\n \"value\": \"footnote\",\n \"name\": \"Footnote\",\n \"description\": \"Placed at the bottom of the page.\"\n },\n {\n \"value\": \"chapter-endnote\",\n \"name\": \"Chapter End Note\",\n \"description\": \"Placed at the end of the chapter.\"\n },\n {\n \"value\": \"book-endnote\",\n \"name\": \"Book End Note\",\n \"description\": \"Placed at the end of the book\"\n }\n ]\n },\n \"paragraph-role\": {\n \"id\": \"paragraph-role\",\n \"title\": \"Paragraph role\",\n \"values\": [\n {\n \"value\": \"address\",\n \"name\": \"Address\",\n \"description\": \"Paragraph contains address. For letter it means address of the addressee\"\n },\n {\n \"value\": \"addressee\",\n \"name\": \"Addressee\",\n \"description\": \"Paragraph contains addressee. For letter it means addressee name\"\n },\n {\n \"value\": \"author\",\n \"name\": \"Author\",\n \"description\": \"Paragraph contains author name.\"\n },\n {\n \"value\": \"date\",\n \"name\": \"Date\",\n \"description\": \"Paragraph contains date.\"\n },\n {\n \"value\": \"place\",\n \"name\": \"Place\",\n \"description\": \"Paragraph contains place.\"\n },\n {\n \"value\": \"introduction\",\n \"name\": \"Introduction\",\n \"description\": \"Paragraph contains introduction text.\"\n },\n {\n \"value\": \"letterhead\",\n \"name\": \"Letterhead\",\n \"description\": \"Paragraph contains letter header.\"\n },\n {\n \"value\": \"salutation\",\n \"name\": \"Salutation\",\n \"description\": \"Paragraph contains salutation.\"\n },\n {\n \"value\": \"signature-date\",\n \"name\": \"Signature Date\",\n \"description\": \"Paragraph contains signature date.\"\n },\n {\n \"value\": \"signature-line\",\n \"name\": \"Signature Line\",\n \"description\": \"Paragraph contains signature line.\"\n },\n {\n \"value\": \"signature-source\",\n \"name\": \"Signature Source\",\n \"description\": \"Paragraph contains signature source.\"\n },\n {\n \"value\": \"bible-text\",\n \"name\": \"Bible Text\",\n \"description\": \"Paragraph contains Bible text.\"\n },\n {\n \"value\": \"devotional-text\",\n \"name\": \"Devotional Text\",\n \"description\": \"Paragraph contains devotional text.\"\n },\n {\n \"value\": \"poem-source\",\n \"name\": \"Poem Source\",\n \"description\": \"Paragraph contains poem source.\"\n },\n {\n \"value\": \"publication-info\",\n \"name\": \"Publication Info\",\n \"description\": \"Paragraph contains publication info.\"\n },\n {\n \"value\": \"title\",\n \"name\": \"Title\",\n \"description\": \"Paragraph contains title.\"\n }\n ]\n },\n \"paragraph-type\": {\n \"id\": \"paragraph-type\",\n \"title\": \"Paragraph type\",\n \"values\": [\n {\n \"value\": \"blockquote\",\n \"name\": \"Blockquote\",\n \"description\": \"Blockquote\"\n },\n {\n \"value\": \"paragraph\",\n \"name\": \"Paragraph\",\n \"description\": \"Paragraph\"\n },\n {\n \"value\": \"poem\",\n \"name\": \"Poem\",\n \"description\": \"Poem. Lines are separated with <br/>\"\n }\n ]\n },\n \"paragraphs-group-type\": {\n \"id\": \"paragraphs-group-type\",\n \"title\": \"Paragraphs group type\",\n \"values\": [\n {\n \"value\": \"frame\",\n \"name\": \"Frame\",\n \"description\": \"Blockquote with several paragraphs\"\n }\n ]\n },\n \"publication-type\": {\n \"id\": \"publication-type\",\n \"title\": \"Publication Type\",\n \"values\": [\n {\n \"value\": \"bible\",\n \"name\": \"Bible\",\n \"description\": \"Bible translation\"\n },\n {\n \"value\": \"bible-commentary\",\n \"name\": \"Bible Commentary\",\n \"description\": \"Bible commentaries\"\n },\n {\n \"value\": \"book\",\n \"name\": \"Book\",\n \"description\": \"Paginated book\"\n },\n {\n \"value\": \"devotional\",\n \"name\": \"Devotional\",\n \"description\": \"Daily devotional\"\n },\n {\n \"value\": \"dictionary\",\n \"name\": \"Dictionary\",\n \"description\": \"Dictionary\"\n },\n {\n \"value\": \"manuscript-volume\",\n \"name\": \"Manuscript Volume\",\n \"description\": \"One of EGW Lt&Ms bound volumes\"\n },\n {\n \"value\": \"periodical/page-break\",\n \"name\": \"Periodical\",\n \"description\": \"Periodical with page markers\"\n },\n {\n \"value\": \"periodical/no-page-break\",\n \"name\": \"Periodical\",\n \"description\": \"Periodical without page markers\"\n },\n {\n \"value\": \"topical-index\",\n \"name\": \"Topical Index\",\n \"description\": \"Topical index\"\n },\n {\n \"value\": \"scripture-index\",\n \"name\": \"Scripture Index\",\n \"description\": \"Scripture index\"\n }\n ]\n },\n \"text-direction\": {\n \"id\": \"text-direction\",\n \"title\": \"Text Direction\",\n \"values\": [\n {\n \"value\": \"ltr\",\n \"name\": \"Left to right\",\n \"description\": \"Text is written from left to right\"\n },\n {\n \"value\": \"rtl\",\n \"name\": \"Right to left\",\n \"description\": \"Text is written from right to left\"\n }\n ]\n },\n \"text-formatting\": {\n \"id\": \"text-formatting\",\n \"title\": \"Text formatting\",\n \"values\": [\n {\n \"value\": \"bold\",\n \"name\": \"Bold\",\n \"description\": \"Bold text\"\n },\n {\n \"value\": \"italic\",\n \"name\": \"Italic\",\n \"description\": \"Italic text\"\n },\n {\n \"value\": \"underline\",\n \"name\": \"Underline\",\n \"description\": \"Underlined text\"\n },\n {\n \"value\": \"superscript\",\n \"name\": \"Superscript\",\n \"description\": \"Superscript text\"\n },\n {\n \"value\": \"subscript\",\n \"name\": \"Subscript\",\n \"description\": \"Subscript text\"\n },\n {\n \"value\": \"small-caps\",\n \"name\": \"Small Caps\",\n \"description\": \"Small caps text\"\n },\n {\n \"value\": \"all-caps\",\n \"name\": \"All Caps\",\n \"description\": \"All caps text\"\n },\n {\n \"value\": \"overline\",\n \"name\": \"Overline\",\n \"description\": \"Overlined text\"\n }\n ]\n },\n \"vertical-alignment\": {\n \"id\": \"vertical-alignment\",\n \"title\": \"Vertical Alignment\",\n \"values\": [\n {\n \"value\": \"top\",\n \"name\": \"Top alignment\",\n \"description\": \"Align text to the top\"\n },\n {\n \"value\": \"center\",\n \"name\": \"Center alignment\",\n \"description\": \"Align text to the center\"\n },\n {\n \"value\": \"bottom\",\n \"name\": \"Bottom alignment\",\n \"description\": \"Align text to the bottom\"\n }\n ]\n }\n};\n\nexport const TAGS: Record<string, TagSchema> = {\n \"figure\": {\n \"tag\": \"figure\",\n \"description\": \"Represents an image with an optional caption.\",\n \"attributes\": [\n {\n \"name\": \"align\",\n \"required\": false,\n \"description\": \"Horizontal alignment. See corresponding page for allowed values. Default `left`\",\n \"enumRef\": \"figure-alignment\"\n },\n {\n \"name\": \"wrap\",\n \"required\": false,\n \"description\": \"Default `1`: text continues to flow beside the image, otherwise `0`\"\n }\n ],\n \"notes\": \"Contains a required `img` tag and an optional `figcaption` tag.\\n\\n`img` tag must contain `src` attribute with a valid image url and an optional `alt`, `width` and `height` and attributes.\\n\\nFigcaption may contain a single Paragraph.\\n\\nIs displayed as a full-width or centered image with caption underneath\",\n \"source\": \"blocks/figure.md\"\n },\n \"hr\": {\n \"tag\": \"hr\",\n \"description\": \"Represents a horizontal ruler with optional foreground and background colors.\",\n \"attributes\": [\n {\n \"name\": \"background\",\n \"required\": false,\n \"description\": \"Background color. See Colors.\"\n },\n {\n \"name\": \"foreground\",\n \"required\": false,\n \"description\": \"Foreground color. See Colors.\"\n }\n ],\n \"notes\": \"Usually displayed as an ornament or three centered asterisks.\",\n \"source\": \"blocks/hr.md\"\n },\n \"w-list\": {\n \"tag\": \"w-list\",\n \"description\": \"Represents a list of text items.\",\n \"attributes\": [\n {\n \"name\": \"type\",\n \"required\": false,\n \"default\": \"unordered\",\n \"description\": \"Type of the list. See corresponding page for possible values\",\n \"enumRef\": \"list-type\"\n },\n {\n \"name\": \"marker\",\n \"required\": false,\n \"default\": \"•\",\n \"description\": \"Based on list type. See extended info\"\n },\n {\n \"name\": \"start\",\n \"required\": false,\n \"default\": \"null\",\n \"description\": \"Based on marker. See extended info\"\n }\n ],\n \"notes\": \"List contains zero or more `w-li` elements, each of them containing one or\\nmore block elements. `w-li` has no attributes.\\n\\n### Valid attribute values\\n\\n**Ordered List**\\n\\n| Marker | Description | Start | Values for first `w-li` |\\n|--------|---------------------------|-------|----------------------------|\\n| `1` | Arabic numerals (default) | 1 | Start from `1` |\\n| `a` | Lowercase letters | 2 | Start from lower `b` |\\n| `A` | Uppercase letters | 3 | Start from upper `C` |\\n| `i` | Lowercase Roman numerals | 5 | Start from lower Roman `v` |\\n| `I` | Uppercase Roman numerals | 10 | Start from upper Roman `X` |\\n\\n**Unordered list**\\n\\nThe `marker` attribute specifies the marker type. Marker must be a unicode string.\\nIf not specified, the default value is `•`. The `start` attribute is not considered.\",\n \"source\": \"blocks/w-list.md\"\n },\n \"w-text-block\": {\n \"tag\": \"w-text-block\",\n \"description\": \"Represents a block of text.\\n\\nMay contain inline elements only.\",\n \"attributes\": [\n {\n \"name\": \"type\",\n \"required\": false,\n \"default\": \"paragraph\",\n \"description\": \"Type of the paragraph. See corresponding page for values\",\n \"enumRef\": \"paragraph-type\"\n },\n {\n \"name\": \"align\",\n \"required\": false,\n \"default\": \"`left` for LTR, `right` for RTL\",\n \"description\": \"Horizontal alignment. See corresponding page for allowed values\",\n \"enumRef\": \"horizontal-alignment\"\n }\n ],\n \"notes\": \"\",\n \"source\": \"blocks/w-text-block.md\"\n },\n \"br\": {\n \"tag\": \"br\",\n \"description\": \"Line breaks are represented by the `br` element. They are used to force a line break\\nin the output.\",\n \"attributes\": [],\n \"notes\": \"Current line is broken and the next line is started. Next line has the same alignment\\nas the current line, and the same indentation level as any line other than the first.\",\n \"source\": \"inlines/br.md\"\n },\n \"w-color\": {\n \"tag\": \"w-color\",\n \"description\": \"Represents an inline span with a foreground color, a background color, or both.\",\n \"attributes\": [\n {\n \"name\": \"background\",\n \"required\": false,\n \"description\": \"Background color. See Colors.\"\n },\n {\n \"name\": \"foreground\",\n \"required\": false,\n \"description\": \"Foreground color. See Colors.\"\n }\n ],\n \"notes\": \"Any inline elements.\",\n \"source\": \"inlines/w-color.md\"\n },\n \"w-entity\": {\n \"tag\": \"w-entity\",\n \"description\": \"An entity is a reference to a person, place, or thing. Entities are used to\",\n \"attributes\": [\n {\n \"name\": \"type\",\n \"required\": true,\n \"description\": \"The type of the entity. See Entity Types for a list of valid values.\",\n \"enumRef\": \"entity-type\"\n },\n {\n \"name\": \"value\",\n \"required\": false,\n \"description\": \"Value of the entity. This is a string that is the real value of the entity, if actual text differs from what it represents.<br><br> For Entity Type `date` value may contains <ul><li>single date</li><li>range of dates (two date via `...`)</li><li>two different date via `,`</li></ul>\"\n }\n ],\n \"notes\": \"Any inline elements.\",\n \"source\": \"inlines/w-entity.md\"\n },\n \"w-format\": {\n \"tag\": \"w-format\",\n \"description\": \"Represents a block of text that is formatted in a special way (bold, italic, etc.).\",\n \"attributes\": [\n {\n \"name\": \"type\",\n \"required\": true,\n \"description\": \"Type of the formatting. See Formatting types for a list of possible values.\",\n \"enumRef\": \"text-formatting\"\n }\n ],\n \"notes\": \"Text is displayed with a different style depending on the formatting type.\",\n \"source\": \"inlines/w-format.md\"\n },\n \"w-lang\": {\n \"tag\": \"w-lang\",\n \"description\": \"Represents a span written in different language.\",\n \"attributes\": [\n {\n \"name\": \"lang\",\n \"required\": false,\n \"description\": \"The language of the text. See BCP 47 for a list of possible values.\"\n },\n {\n \"name\": \"dir\",\n \"required\": false,\n \"description\": \"The direction of the text. See Text directions for a list of possible values.\",\n \"enumRef\": \"text-direction\"\n }\n ],\n \"notes\": \"Any inline elements.\",\n \"source\": \"inlines/w-lang.md\"\n },\n \"w-non-egw\": {\n \"tag\": \"w-non-egw\",\n \"description\": \"Represents a block of text that is not written by EGW herself. This is used to represent\\nquotes from other authors, or other text that is not written by EGW.\",\n \"attributes\": [\n {\n \"name\": \"type\",\n \"required\": true,\n \"description\": \"The type of the non-egw text. See Non-EGW types for a list of valid values.\",\n \"enumRef\": \"non-egw-type\"\n }\n ],\n \"notes\": \"Non-EGW text is drawn as a blue text.\",\n \"source\": \"inlines/w-non-egw.md\"\n },\n \"w-page\": {\n \"tag\": \"w-page\",\n \"description\": \"Page break element represents a page break in the publication.\",\n \"attributes\": [\n {\n \"name\": \"number\",\n \"required\": true,\n \"description\": \"Page number. Usually contains an arabic or roman number.\"\n }\n ],\n \"notes\": \"This element is usually hidden\",\n \"source\": \"inlines/w-page.md\"\n },\n \"w-sent\": {\n \"tag\": \"w-sent\",\n \"description\": \"Sentence element represents a sentence in the publication.\",\n \"attributes\": [],\n \"notes\": \"\",\n \"source\": \"inlines/w-sent.md\"\n },\n \"a\": {\n \"tag\": \"a\",\n \"description\": \"Either a link to another document/resource (`href` attribute) or a named anchor in the text (`id` attribute).\",\n \"attributes\": [\n {\n \"name\": \"href\",\n \"required\": true,\n \"description\": \"The URL of the link. Link must be an absolute URI and have one of the following formats\"\n },\n {\n \"name\": \"title\",\n \"required\": false,\n \"description\": \"The title of the link.\"\n },\n {\n \"name\": \"id\",\n \"required\": true,\n \"description\": \"The identifier of the anchor.\"\n }\n ],\n \"notes\": \"**As a link** (`href` attribute): Represents a link to another document or resource.\\n\\nLink may have any inline elements as children.\\n\\nLink is displayed as a text with a different style depending on the type of the resource\\nto which it points. On mouse over, the title of the link is displayed.\\n\\n**As a named anchor** (`id` attribute): Represents a named anchor in the text.\\n\\nAnchor may not have any children.\\n\\nAnchor is not displayed in the text.\",\n \"source\": \"inlines/a-href.md, inlines/w-anchor.md\"\n },\n \"w-heading\": {\n \"tag\": \"w-heading\",\n \"description\": \"Represents a header of a document.\",\n \"attributes\": [\n {\n \"name\": \"skip\",\n \"required\": false,\n \"description\": \"Non-empty value means that heading is for non-meaningful chapter (preface, epilogue, annotations etc\"\n },\n {\n \"name\": \"level\",\n \"required\": true,\n \"description\": \"Header level. Must be in range 1-6\"\n },\n {\n \"name\": \"alt-text\",\n \"required\": false,\n \"description\": \"Alternative heading text (HTML-encoded text)\"\n },\n {\n \"name\": \"override-chapter-number\",\n \"required\": false,\n \"description\": \"Chapter number for manual set\"\n },\n {\n \"name\": \"background\",\n \"required\": false,\n \"description\": \"Background color. See Colors\"\n },\n {\n \"name\": \"foreground\",\n \"required\": false,\n \"description\": \"Foreground color. See Colors\"\n }\n ],\n \"notes\": \"Must contain a single text block element.\",\n \"source\": \"containers.md\"\n },\n \"w-para\": {\n \"tag\": \"w-para\",\n \"description\": \"Represents a single paragraph of a document\",\n \"attributes\": [\n {\n \"name\": \"skip\",\n \"required\": false,\n \"description\": \"Non-empty value means that paragraph does not affect paragraph numeration\"\n },\n {\n \"name\": \"indent\",\n \"required\": false,\n \"description\": \"Indentation level (from `-4` to `0`+). Default value is `1` (single indentation)\"\n },\n {\n \"name\": \"role\",\n \"required\": false,\n \"description\": \"Paragraph role. See corresponding page for allowed values.\",\n \"enumRef\": \"paragraph-role\"\n },\n {\n \"name\": \"align\",\n \"required\": false,\n \"description\": \"Horizontal alignment. See corresponding page for allowed values. Defaults to `left` for left-to-right languages and `right` to right-to-left\",\n \"enumRef\": \"horizontal-alignment\"\n },\n {\n \"name\": \"background\",\n \"required\": false,\n \"description\": \"Background color. See Colors\"\n },\n {\n \"name\": \"foreground\",\n \"required\": false,\n \"description\": \"Foreground color. See Colors\"\n }\n ],\n \"notes\": \"Must contain a single block element.\",\n \"source\": \"containers.md\"\n },\n \"w-para-group\": {\n \"tag\": \"w-para-group\",\n \"description\": \"Represents a group of paragraphs, formatted as a same entity\",\n \"attributes\": [\n {\n \"name\": \"skip\",\n \"required\": false,\n \"description\": \"Non-empty value means that container does not affect paragraph numeration\"\n },\n {\n \"name\": \"type\",\n \"required\": false,\n \"description\": \"Paragraphs group type. See corresponding page for allowed values.\",\n \"enumRef\": \"paragraphs-group-type\"\n }\n ],\n \"notes\": \"Must contain 1 or more paragraph containers element.\",\n \"source\": \"containers.md\"\n },\n \"w-toc\": {\n \"tag\": \"w-toc\",\n \"description\": \"TOC position marker.\",\n \"attributes\": [],\n \"notes\": \"Must contain a single text block element.\",\n \"source\": \"containers.md\"\n },\n \"table\": {\n \"tag\": \"table\",\n \"description\": \"\",\n \"attributes\": [\n {\n \"name\": \"align\",\n \"required\": false,\n \"description\": \"Horizontal alignment of the table. See corresponding page for possible values\",\n \"enumRef\": \"horizontal-alignment\"\n }\n ],\n \"notes\": \"Contains optional `<thead>` and `<tbody>` sections. Both of them, if specfied, must\\nhave at least one table row.\\n\\n`THEAD` element includes cells from the table header and `TBODY` represents actual\\ntabular data.\\n\\nIs displayed as a table. Borderless or bordered, is determined by the client\",\n \"source\": \"blocks/table.md\"\n },\n \"tr\": {\n \"tag\": \"tr\",\n \"description\": \"Represents a table row\",\n \"attributes\": [],\n \"notes\": \"Contains zero or more table cells\",\n \"source\": \"blocks/table.md\"\n },\n \"th\": {\n \"tag\": \"th\",\n \"description\": \"Table header cell. Represents a table cell\",\n \"attributes\": [\n {\n \"name\": \"align\",\n \"required\": false,\n \"default\": \"`left` for left-to-right languages,<br/>`right` for right-to-left\",\n \"description\": \"Horizontal alignment of the cell content. See corresponding page for possible values\",\n \"enumRef\": \"horizontal-alignment\"\n },\n {\n \"name\": \"valign\",\n \"required\": false,\n \"default\": \"top\",\n \"description\": \"Vertical alignment of the cell content. See corresponding page for possible values. If not specified, defaults to `top`\",\n \"enumRef\": \"vertical-alignment\"\n },\n {\n \"name\": \"indent\",\n \"required\": false,\n \"description\": \"Indentation level (from `-4` to `0`+). Default value is `0` (no indentation)\"\n },\n {\n \"name\": \"colspan\",\n \"required\": false,\n \"default\": \"1\",\n \"description\": \"number of columns this cell spans. If not specified, defaults to `1`\"\n },\n {\n \"name\": \"rowspan\",\n \"required\": false,\n \"default\": \"1\",\n \"description\": \"number of rows this cell spans. If not specified, defaults to `1`\"\n }\n ],\n \"notes\": \"Contains zero or more block nodes\",\n \"source\": \"blocks/table.md\"\n },\n \"td\": {\n \"tag\": \"td\",\n \"description\": \"Table data cell. Represents a table cell\",\n \"attributes\": [\n {\n \"name\": \"align\",\n \"required\": false,\n \"default\": \"`left` for left-to-right languages,<br/>`right` for right-to-left\",\n \"description\": \"Horizontal alignment of the cell content. See corresponding page for possible values\",\n \"enumRef\": \"horizontal-alignment\"\n },\n {\n \"name\": \"valign\",\n \"required\": false,\n \"default\": \"top\",\n \"description\": \"Vertical alignment of the cell content. See corresponding page for possible values. If not specified, defaults to `top`\",\n \"enumRef\": \"vertical-alignment\"\n },\n {\n \"name\": \"indent\",\n \"required\": false,\n \"description\": \"Indentation level (from `-4` to `0`+). Default value is `0` (no indentation)\"\n },\n {\n \"name\": \"colspan\",\n \"required\": false,\n \"default\": \"1\",\n \"description\": \"number of columns this cell spans. If not specified, defaults to `1`\"\n },\n {\n \"name\": \"rowspan\",\n \"required\": false,\n \"default\": \"1\",\n \"description\": \"number of rows this cell spans. If not specified, defaults to `1`\"\n }\n ],\n \"notes\": \"Contains zero or more block nodes\",\n \"source\": \"blocks/table.md\"\n },\n \"w-note\": {\n \"tag\": \"w-note\",\n \"description\": \"A note is a block of text that is not part of the main text flow. It is usually placed at the end of a chapter or book,\\nbut can also be placed inline in the text. Notes are usually numbered sequentially, but can also be given a custom\\nnumber.\",\n \"attributes\": [\n {\n \"name\": \"type\",\n \"required\": false,\n \"default\": \"footnote\",\n \"description\": \"Note type. See corresponding Note Type page\",\n \"enumRef\": \"note-types\"\n }\n ],\n \"notes\": \"Note contains a single `w-note-header` and a single `w-note-body` element. Both of them are required.\\n\\n`w-note-header` contain any number of inline elements. Usually it contains only a single reference to the note body,\\n\\n`w-note-body` contains any number of `w-note-para` elements.\",\n \"source\": \"inlines/w-note.md\"\n },\n \"w-note-para\": {\n \"tag\": \"w-note-para\",\n \"description\": \"Represents a single paragraph of a note\",\n \"attributes\": [\n {\n \"name\": \"indent\",\n \"required\": false,\n \"description\": \"Indentation level (`0`+). Default value is `1` (single indentation)\"\n },\n {\n \"name\": \"align\",\n \"required\": false,\n \"description\": \"Text align (default: `left`)\"\n }\n ],\n \"notes\": \"\",\n \"source\": \"inlines/w-note.md\"\n },\n \"img\": {\n \"tag\": \"img\",\n \"description\": \"Image to display, child of `figure`.\",\n \"attributes\": [\n {\n \"name\": \"src\",\n \"required\": true,\n \"description\": \"A valid image URL.\"\n },\n {\n \"name\": \"alt\",\n \"required\": false,\n \"description\": \"Alternative text for the image.\"\n },\n {\n \"name\": \"width\",\n \"required\": false,\n \"description\": \"Image width.\"\n },\n {\n \"name\": \"height\",\n \"required\": false,\n \"description\": \"Image height.\"\n }\n ],\n \"notes\": \"\",\n \"source\": \"blocks/figure.md\"\n },\n \"figcaption\": {\n \"tag\": \"figcaption\",\n \"description\": \"Optional caption of a `figure`. May contain a single text block.\",\n \"attributes\": [],\n \"notes\": \"\",\n \"source\": \"blocks/figure.md\"\n },\n \"w-li\": {\n \"tag\": \"w-li\",\n \"description\": \"A single item of a `w-list`. Contains one or more block elements.\",\n \"attributes\": [],\n \"notes\": \"\",\n \"source\": \"blocks/w-list.md\"\n },\n \"thead\": {\n \"tag\": \"thead\",\n \"description\": \"Table header section of a `table`. Contains cells from the table header.\",\n \"attributes\": [],\n \"notes\": \"Must contain at least one `tr`, if specified.\",\n \"source\": \"blocks/table.md\"\n },\n \"tbody\": {\n \"tag\": \"tbody\",\n \"description\": \"Table body section of a `table`. Represents the actual tabular data.\",\n \"attributes\": [],\n \"notes\": \"Must contain at least one `tr`, if specified.\",\n \"source\": \"blocks/table.md\"\n },\n \"w-note-header\": {\n \"tag\": \"w-note-header\",\n \"description\": \"Header of a `w-note`. Contains any number of inline elements, usually a single reference to the note body.\",\n \"attributes\": [],\n \"notes\": \"\",\n \"source\": \"inlines/w-note.md\"\n },\n \"w-note-body\": {\n \"tag\": \"w-note-body\",\n \"description\": \"Body of a `w-note`. Contains one or more `w-note-para` elements.\",\n \"attributes\": [],\n \"notes\": \"\",\n \"source\": \"inlines/w-note.md\"\n },\n \"html\": {\n \"tag\": \"html\",\n \"description\": \"Root element of a WEML document. Must be a valid html5 document with a head and a body.\",\n \"attributes\": [\n {\n \"name\": \"lang\",\n \"required\": true,\n \"description\": \"Document language. Must be one of the existing EGW languages (BCP 47 format).\"\n },\n {\n \"name\": \"dir\",\n \"required\": false,\n \"description\": \"Text direction of the document.\",\n \"enumRef\": \"text-direction\",\n \"default\": \"ltr\"\n }\n ],\n \"notes\": \"\",\n \"source\": \"intermediary-format.md\"\n },\n \"head\": {\n \"tag\": \"head\",\n \"description\": \"Document header. Must contain a charset declaration, a title and several meta tags.\",\n \"attributes\": [],\n \"notes\": \"\",\n \"source\": \"intermediary-format.md\"\n },\n \"title\": {\n \"tag\": \"title\",\n \"description\": \"Publication title.\",\n \"attributes\": [],\n \"notes\": \"\",\n \"source\": \"intermediary-format.md\"\n },\n \"meta\": {\n \"tag\": \"meta\",\n \"description\": \"Document metadata. See `name` attribute for supported fields (`pubid`, `code`, `type`, `author`, ...).\",\n \"attributes\": [\n {\n \"name\": \"charset\",\n \"required\": false,\n \"description\": \"Document character set. Must be `UTF-8`.\"\n },\n {\n \"name\": \"name\",\n \"required\": false,\n \"description\": \"Name of the metadata field.\"\n },\n {\n \"name\": \"content\",\n \"required\": false,\n \"description\": \"Value of the metadata field.\"\n }\n ],\n \"notes\": \"\",\n \"source\": \"intermediary-format.md\"\n },\n \"body\": {\n \"tag\": \"body\",\n \"description\": \"Document body. Contains one or more `div` elements, each representing a paragraph.\",\n \"attributes\": [],\n \"notes\": \"\",\n \"source\": \"intermediary-format.md\"\n },\n \"div\": {\n \"tag\": \"div\",\n \"description\": \"Represents a single paragraph of the document. Must contain a single container element or a page break element.\",\n \"attributes\": [\n {\n \"name\": \"id\",\n \"required\": true,\n \"description\": \"Positive 32-bit integer ID (1–2147483647), unique within the document. Should be preserved between imports.\"\n },\n {\n \"name\": \"hash\",\n \"required\": false,\n \"description\": \"Paragraph hash. Preserved without calculation or verification.\"\n },\n {\n \"name\": \"refcode-short\",\n \"required\": false,\n \"description\": \"Short reference code.\"\n },\n {\n \"name\": \"refcode-long\",\n \"required\": false,\n \"description\": \"Long reference code.\"\n },\n {\n \"name\": \"data-skip\",\n \"required\": false,\n \"description\": \"If present, this paragraph is skipped in page numbering (and, for headings, excluded from the TOC).\"\n }\n ],\n \"notes\": \"\",\n \"source\": \"intermediary-format.md\"\n }\n};\n\nexport const META_FIELDS: MetaFieldSchema[] = [\n {\n \"name\": \"pubid\",\n \"description\": \"Publication id. Must be unique for each publication.\"\n },\n {\n \"name\": \"original-id\",\n \"description\": \"Original publication ID for a translation. Optional 32-bit integer, represented by `WemlDocumentHeader.OriginalId` (`int?`). Missing or unparseable WEML values are read as `null`.\"\n },\n {\n \"name\": \"code\",\n \"description\": \"Publication short code.\"\n },\n {\n \"name\": \"type\",\n \"description\": \"Publication type.\",\n \"enumRef\": \"publication-type\"\n },\n {\n \"name\": \"author\",\n \"description\": \"Publication author.\"\n },\n {\n \"name\": \"publication-year\",\n \"description\": \"Publication year.\"\n },\n {\n \"name\": \"publication-start-year\",\n \"description\": \"Publication start year.\"\n },\n {\n \"name\": \"publication-end-year\",\n \"description\": \"Publication end year.\"\n },\n {\n \"name\": \"total-pages\",\n \"description\": \"Total pages.\"\n },\n {\n \"name\": \"publisher\",\n \"description\": \"Publisher\"\n },\n {\n \"name\": \"isbn\",\n \"description\": \"ISBN\"\n },\n {\n \"name\": \"description\",\n \"description\": \"Publication description.\"\n },\n {\n \"name\": \"purchase-link\",\n \"description\": \"Absolute purchase URI.\"\n },\n {\n \"name\": \"version-id\",\n \"description\": \"Publication version GUID.\"\n },\n {\n \"name\": \"hash\",\n \"description\": \"Publication version hash.\"\n }\n];\n\nexport const TEXT_NODE_DESCRIPTION: string = \"Represents html text. Any set of characters.\\n\\nHTML escaping follows standard rules, but on import the only escaped characters are \\n`<` (`<`), `>` (`>`) and `&` (`&`).\";\n","// What the WEML Tools offer: the inlines the \"wrap selection\" control can wrap in, the snippet\n// buttons, and both as one grouped list for the tool picker. One list for every toolbar —\n// weml-tools (VS Code side bar), weml-monaco's DOM toolbar and the web editor's Tools panel — so a\n// new tag is added here once.\n\nimport { ENUMS, TAGS } from '../generated/schema';\nimport { buildAnchorIdSnippet, buildElementSnippet, COMPOSITE_SNIPPETS } from '../schema/snippets';\n\nexport interface WrapOption {\n /** Encoded option value, e.g. \"w-format:italic\" or \"w-lang\". */\n value: string;\n label: string;\n tag: string;\n /** The `type` of `w-format`; absent for the other inlines. */\n type?: string;\n}\n\n/** The inlines other than `w-format` that the wrap control offers, in order. */\nexport const WRAP_INLINE_TAGS = ['w-color', 'w-lang', 'w-non-egw', 'w-entity', 'w-sent', 'a'] as const;\n\n/** Wrap options: `w-format` expanded per text-formatting value, then the other inlines. */\nexport const WRAP_OPTIONS: WrapOption[] = [\n ...(ENUMS['text-formatting']?.values ?? []).map((v) => ({\n value: `w-format:${v.value}`,\n label: `w-format.${v.value}`,\n tag: 'w-format',\n type: v.value,\n })),\n ...WRAP_INLINE_TAGS.map((t) => ({ value: t, label: t, tag: t })),\n];\n\nexport interface SnippetButton {\n /** Shown on the button. */\n label: string;\n /** The snippet: a tag name or a `COMPOSITE_SNIPPETS` label. */\n id: string;\n /** The element the snippet inserts (its documentation category: `categoryOf(tag)`). */\n tag: string;\n}\n\n/** Snippet buttons, in order. */\nexport const SNIPPET_BUTTONS: SnippetButton[] = [\n { label: 'w-para', id: 'w-para', tag: 'w-para' },\n { label: 'w-heading', id: 'w-heading', tag: 'w-heading' },\n { label: 'w-note', id: 'w-note', tag: 'w-note' },\n { label: 'table', id: 'table (with row)', tag: 'table' },\n { label: 'list', id: 'w-list (with item)', tag: 'w-list' },\n { label: 'figure', id: 'figure (with caption)', tag: 'figure' },\n];\n\n/** The documentation's sections the tool picker groups its items by, in order. */\nexport const TOOL_GROUPS = ['Containers', 'Blocks', 'Inlines'] as const;\nexport type ToolGroup = (typeof TOOL_GROUPS)[number];\n\n/** What a tool item does: wrap the selection, or insert a snippet at the cursor. */\nexport type ToolAction = { kind: 'wrap'; option: WrapOption } | { kind: 'insert'; snippetId: string };\n\nexport interface ToolItem {\n /** Unique: the wrap option's value, or the snippet's tag. */\n value: string;\n /** What the picker shows and searches: the tag (`w-format.bold` for a format). */\n label: string;\n group: ToolGroup;\n action: ToolAction;\n /**\n * A new section of `<body>` (a `<div id>` with its container): only for a whole document, not\n * for an editor of one paragraph, whose model is a single `<div>` already.\n */\n documentOnly?: boolean;\n}\n\n/** What is edited: a whole WEML document, or one paragraph (the content of one `<div>`). */\nexport type ToolMode = 'file' | 'paragraph';\n\n/** The id of the named-anchor snippet (`<a id=\"…\"></a>`), named as tag completion names it. */\nexport const ANCHOR_SNIPPET_ID = 'a (anchor)';\n\n/**\n * The snippet body of an insert id: a `COMPOSITE_SNIPPETS` label, the named anchor, or a tag (its\n * element with the required attributes and children). Undefined for an unknown id.\n */\nexport function snippetBodyFor(id: string): string | undefined {\n if (id === ANCHOR_SNIPPET_ID) return buildAnchorIdSnippet();\n const composite = COMPOSITE_SNIPPETS.find((snippet) => snippet.label === id);\n if (composite) return composite.body;\n return TAGS[id] ? buildElementSnippet(id) : undefined;\n}\n\n/** What the picker inserts, by group, in order: every container, block and empty inline of the docs. */\nconst INSERT_TOOLS: { label: string; id: string; group: ToolGroup; documentOnly?: boolean }[] = [\n ...['w-para', 'w-heading', 'w-para-group', 'w-toc'].map((tag) => ({ label: tag, id: tag, group: 'Containers' as const })),\n // A new section of <body>: a <div id> with its container, or with a page break (the docs list\n // `w-page` among the containers too: a <div> holds one container or one `w-page`).\n ...['div + w-para', 'div + w-heading', 'div + w-para-group', 'div + w-toc', 'div + w-page'].map((id) => ({\n label: id,\n id,\n group: 'Containers' as const,\n documentOnly: true,\n })),\n { label: 'w-text-block', id: 'w-text-block', group: 'Blocks' },\n { label: 'table', id: 'table (with row)', group: 'Blocks' },\n { label: 'w-list', id: 'w-list (with item)', group: 'Blocks' },\n { label: 'figure', id: 'figure (with caption)', group: 'Blocks' },\n { label: 'hr', id: 'hr', group: 'Blocks' },\n ...['w-note', 'w-page', 'br'].map((tag) => ({ label: tag, id: tag, group: 'Inlines' as const })),\n { label: ANCHOR_SNIPPET_ID, id: ANCHOR_SNIPPET_ID, group: 'Inlines' },\n];\n\n/**\n * One list of everything the Tools offer — the snippets to insert, then the inlines to wrap the\n * selection in — grouped as the WEML documentation is (containers, blocks, inlines).\n */\nexport const TOOL_ITEMS: ToolItem[] = (() => {\n const items: ToolItem[] = [\n ...INSERT_TOOLS.map((tool): ToolItem => ({\n value: tool.label,\n label: tool.label,\n group: tool.group,\n action: { kind: 'insert', snippetId: tool.id },\n ...(tool.documentOnly ? { documentOnly: true } : {}),\n })),\n ...WRAP_OPTIONS.map((option): ToolItem => ({\n value: option.value,\n // `a` wraps as a link; the anchor is an insert of its own.\n label: option.tag === 'a' ? 'a (link)' : option.label,\n group: 'Inlines',\n action: { kind: 'wrap', option },\n })),\n ];\n return TOOL_GROUPS.flatMap((group) => items.filter((item) => item.group === group));\n})();\n\n/** The tool items for what is edited: a paragraph has no sections to add. */\nexport function toolItemsFor(mode: ToolMode = 'file'): ToolItem[] {\n return mode === 'paragraph' ? TOOL_ITEMS.filter((item) => !item.documentOnly) : TOOL_ITEMS;\n}\n\n/** A tool item that matches a query, with the matched ranges of its label (`[start, end)`). */\nexport interface ToolMatch {\n item: ToolItem;\n matches: [number, number][];\n}\n\n/**\n * The items whose label contains `query` (case-insensitive; an empty query matches all), in\n * `TOOL_ITEMS` order, with the match to highlight.\n */\nexport function filterToolItems(query: string, items: readonly ToolItem[] = TOOL_ITEMS): ToolMatch[] {\n const needle = query.trim().toLowerCase();\n if (!needle) return items.map((item) => ({ item, matches: [] }));\n const found: ToolMatch[] = [];\n for (const item of items) {\n const at = item.label.toLowerCase().indexOf(needle);\n if (at >= 0) found.push({ item, matches: [[at, at + needle.length]] });\n }\n return found;\n}\n","// The Tools pane's tag picker: one searchable list of everything the Tools offer (the core's\n// TOOL_ITEMS — snippets to insert, inlines to wrap the selection in), grouped as the WEML docs are,\n// drawn as VS Code's quick pick. Choosing (Enter, click) only chooses: the button in the field wraps\n// or inserts, so the same tag can be applied again and again.\n\nimport { filterToolItems, TOOL_GROUPS, type ToolItem, type ToolMatch, type ToolMode, toolItemsFor } from 'weml-language-core';\nimport { button, element, icon } from './dom';\nimport type { WemlPanelTools } from './types';\n\n/** What the picker remembers: the chosen tag (its `ToolItem.value`). */\nexport interface ToolPickerState {\n get(): { tool?: string } | undefined;\n set(value: { tool?: string }): void;\n}\n\nconst PAGE = 8;\nconst MAX_LIST_HEIGHT = 320;\nlet pickers = 0;\n\nexport function createToolPicker(\n tools: WemlPanelTools,\n state: ToolPickerState,\n mode: ToolMode = 'file',\n): { element: HTMLElement; dispose(): void } {\n const items = toolItemsFor(mode);\n const id = `weml-tool-picker-${++pickers}`;\n const input = element('input', { className: 'tool-input' });\n input.type = 'text';\n input.placeholder = 'Tag to wrap or insert';\n input.spellcheck = false;\n input.autocomplete = 'off';\n input.setAttribute('role', 'combobox');\n input.setAttribute('aria-label', 'Tag to wrap or insert');\n input.setAttribute('aria-autocomplete', 'list');\n input.setAttribute('aria-expanded', 'false');\n input.setAttribute('aria-controls', `${id}-list`);\n\n const action = button({ className: 'icon flat primary' }, () => apply());\n const field = element('div', { className: 'tool-field' }, [input, action]);\n const list = element('div', { className: 'tool-list' });\n list.id = `${id}-list`;\n list.setAttribute('role', 'listbox');\n list.hidden = true;\n // The list must not take the focus: a click on it would blur the input and close it first.\n list.addEventListener('mousedown', (event) => event.preventDefault());\n\n /** The window the panel is in (a webview's, an iframe's), for its size and its events. */\n const view = () => input.ownerDocument.defaultView;\n\n // A tag remembered from a document is not offered in a paragraph (a `div + …` section).\n let chosen: ToolItem | undefined = items.find((item) => item.value === state.get()?.tool);\n let shown: ToolMatch[] = [];\n let active = -1;\n\n const updateAction = () => {\n const label = !chosen\n ? 'Choose a tag first'\n : chosen.action.kind === 'wrap'\n ? `Wrap selection in ${chosen.label}`\n : `Insert ${chosen.label}`;\n action.replaceChildren(icon(chosen?.action.kind === 'insert' ? 'add' : 'wrap'));\n action.title = label;\n action.setAttribute('aria-label', label);\n // aria-disabled, not disabled: a disabled button gets no pointer events, and its tooltip —\n // which says why — would never show.\n action.setAttribute('aria-disabled', String(!chosen));\n };\n\n const apply = () => {\n if (!chosen) return;\n if (chosen.action.kind === 'wrap') tools.wrap(chosen.action.option);\n else tools.insertSnippet(chosen.action.snippetId);\n };\n\n const choose = (item: ToolItem) => {\n chosen = item;\n input.value = item.label;\n state.set({ tool: item.value });\n updateAction();\n close();\n };\n\n /** The query: what is typed — but the chosen tag's own label shows everything, as a fresh list. */\n const query = () => (chosen && input.value === chosen.label ? '' : input.value);\n\n const optionId = (index: number) => `${id}-option-${index}`;\n\n const setActive = (index: number) => {\n list.querySelector('.tool-option.active')?.classList.remove('active');\n active = shown.length ? Math.max(0, Math.min(shown.length - 1, index)) : -1;\n const node = active >= 0 ? list.querySelector<HTMLElement>(`#${optionId(active)}`) : null;\n node?.classList.add('active');\n node?.scrollIntoView?.({ block: 'nearest' });\n if (node) input.setAttribute('aria-activedescendant', node.id);\n else input.removeAttribute('aria-activedescendant');\n };\n\n const render = () => {\n shown = filterToolItems(query(), items);\n list.replaceChildren();\n if (!shown.length) {\n list.append(element('div', { className: 'tool-empty', text: 'No such tag' }));\n }\n let index = 0;\n for (const group of TOOL_GROUPS) {\n const inGroup = shown.filter((match) => match.item.group === group);\n if (!inGroup.length) continue;\n const node = element('div', { className: 'tool-group' });\n node.setAttribute('role', 'group');\n node.setAttribute('aria-label', group);\n node.append(element('div', { className: 'tool-group-label', text: group }));\n for (const match of inGroup) {\n const at = index++;\n const option = element('div', { className: 'tool-option' }, [\n highlighted(match),\n element('span', { className: 'tool-kind', text: match.item.action.kind }),\n ]);\n option.id = optionId(at);\n option.setAttribute('role', 'option');\n option.setAttribute('aria-selected', String(match.item === chosen));\n option.addEventListener('click', () => choose(match.item));\n node.append(option);\n }\n list.append(node);\n }\n const current = shown.findIndex((match) => match.item === chosen);\n setActive(current >= 0 ? current : 0);\n };\n\n /** Under the field, `position: fixed`: the pane's overflow would clip it otherwise. */\n const place = () => {\n const rect = field.getBoundingClientRect();\n const below = (view()?.innerHeight ?? 0) - rect.bottom - 8;\n list.style.left = `${rect.left}px`;\n list.style.top = `${rect.bottom}px`;\n list.style.width = `${rect.width}px`;\n list.style.maxHeight = `${Math.max(88, Math.min(MAX_LIST_HEIGHT, below))}px`;\n };\n\n const open = () => {\n if (list.hidden) {\n list.hidden = false;\n input.setAttribute('aria-expanded', 'true');\n view()?.addEventListener('resize', close);\n view()?.addEventListener('scroll', onScroll, true);\n }\n render();\n place();\n };\n\n function close() {\n if (list.hidden) return;\n list.hidden = true;\n input.setAttribute('aria-expanded', 'false');\n input.removeAttribute('aria-activedescendant');\n view()?.removeEventListener('resize', close);\n view()?.removeEventListener('scroll', onScroll, true);\n }\n\n // A scroll of the page or the pane moves the field away from the list; the list's own does not.\n function onScroll(event: Event) {\n if (event.target !== list) close();\n }\n\n // Focus selects the chosen tag's name, so typing replaces it (as the quick pick's value); the\n // mouseup of the click that focused would put a caret there instead, so it is skipped once.\n let keepSelection = false;\n input.addEventListener('focus', () => {\n if (chosen && input.value === chosen.label) {\n input.select();\n keepSelection = true;\n }\n open();\n });\n input.addEventListener('mouseup', (event) => {\n if (keepSelection) event.preventDefault();\n keepSelection = false;\n });\n input.addEventListener('click', () => {\n if (list.hidden) open();\n });\n input.addEventListener('input', () => {\n // Text cleared: no choice (else the field would show the old tag again on blur).\n if (!input.value && chosen) {\n chosen = undefined;\n state.set({});\n updateAction();\n }\n open();\n });\n input.addEventListener('blur', () => {\n close();\n input.value = chosen?.label ?? '';\n });\n input.addEventListener('keydown', (event) => {\n const moves: Record<string, number> = { ArrowDown: 1, ArrowUp: -1, PageDown: PAGE, PageUp: -PAGE };\n if (event.key in moves) {\n event.preventDefault();\n if (list.hidden) open();\n else setActive(active + moves[event.key]);\n } else if (event.key === 'Enter') {\n event.preventDefault();\n const match = list.hidden ? undefined : shown[active];\n if (match) choose(match.item);\n } else if (event.key === 'Escape') {\n if (list.hidden) return;\n // Ours: neither the editor nor VS Code should see it.\n event.preventDefault();\n event.stopPropagation();\n close();\n input.value = chosen?.label ?? '';\n } else if (event.key === 'Tab') {\n close();\n }\n });\n\n input.value = chosen?.label ?? '';\n updateAction();\n\n return {\n element: element('div', { className: 'tool-picker' }, [field, list]),\n dispose: close,\n };\n}\n\n/** The label with its matched ranges in `.highlight` spans. */\nfunction highlighted({ item, matches }: ToolMatch): HTMLElement {\n const label = element('span', { className: 'tool-label' });\n let at = 0;\n for (const [start, end] of matches) {\n if (start > at) label.append(item.label.slice(at, start));\n label.append(element('span', { className: 'highlight', text: item.label.slice(start, end) }));\n at = end;\n }\n if (at < item.label.length) label.append(item.label.slice(at));\n return label;\n}\n","// The Tools pane: the tag picker (wrap the selection or insert a snippet), renumber div ids. The\n// items are weml-language-core's tool model — the same list everywhere.\n\nimport type { ToolMode } from 'weml-language-core';\nimport { button, element } from './dom';\nimport { createToolPicker, type ToolPickerState } from './toolPicker';\nimport type { WemlPanelTools } from './types';\n\nexport function createToolsPane(\n tools: WemlPanelTools,\n options: { mode: ToolMode; state: ToolPickerState },\n): { element: HTMLElement; dispose(): void } {\n const root = element('div');\n const picker = createToolPicker(tools, options.state, options.mode);\n root.append(element('section', {}, [element('h2', { text: 'Wrap or insert' }), picker.element]));\n\n // A paragraph is one <div id>: nothing to number.\n if (options.mode === 'file') {\n root.append(element('section', {}, [\n element('h2', { text: 'Document' }),\n button({ text: 'Renumber div ids (1…n)', className: 'full' }, () => tools.renumber()),\n ]));\n }\n return { element: root, dispose: picker.dispose };\n}\n","// The WEML panel: the Tools and Search Suggestions panes of the WEML Tools VS Code view, as a\n// framework-free DOM component — the same panel in VS Code (weml-tools bundles it into its\n// webview) and on a web page next to a Monaco editor. The host does the work (types.ts).\n\nimport { createPanes, type PaneSpec, type PanelState } from './panes';\nimport { createSearchPane } from './searchPane';\nimport { injectPanelStyles, PANEL_CLASS } from './styles';\nimport { createToolsPane } from './toolsPane';\nimport type { WemlPanel, WemlPanelHost, WemlPanelOptions } from './types';\n\n/** Pane ids: the keys of the remembered state (the same as weml-tools' before the panel). */\nconst TOOLS = 'tools';\nconst SEARCH = 'suggestions';\n\nexport function createWemlPanel(host: WemlPanelHost, options: WemlPanelOptions = {}): WemlPanel {\n if (options.injectStyles !== false) injectPanelStyles();\n\n let memory: PanelState = {};\n try {\n const stored = host.storage?.get();\n if (stored && typeof stored === 'object') memory = { ...(stored as PanelState) };\n } catch {\n // An unreadable state is a fresh panel, not a broken one.\n }\n const save = () => {\n try {\n host.storage?.set(memory);\n } catch {\n // Remembering is a convenience.\n }\n };\n\n const toolsPane = createToolsPane(host.tools, {\n mode: options.mode ?? 'file',\n state: {\n get: () => memory.modules?.[TOOLS] as { tool?: string } | undefined,\n set: (value) => {\n memory.modules = { ...memory.modules, [TOOLS]: value };\n save();\n },\n },\n });\n const specs: PaneSpec[] = [{ id: TOOLS, title: 'Tools', body: toolsPane.element }];\n const search = host.search\n ? createSearchPane(host.search, {\n get: () => memory.modules?.[SEARCH] as { lang?: string } | undefined,\n set: (value) => {\n memory.modules = { ...memory.modules, [SEARCH]: value };\n save();\n },\n })\n : undefined;\n if (search) {\n // The search box stays put; only the results scroll.\n specs.push({ id: SEARCH, title: 'Search Suggestions', body: search.element, fill: true });\n }\n\n const panes = createPanes(specs, memory, save);\n const element = document.createElement('div');\n element.className = options.monacoTheme === false ? PANEL_CLASS : `${PANEL_CLASS} monaco-component`;\n element.append(panes.element);\n options.container?.append(element);\n\n return {\n element,\n dispose: () => {\n toolsPane.dispose();\n search?.dispose();\n panes.dispose();\n element.remove();\n },\n };\n}\n"],"mappings":"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","names":["element"]}
|
package/dist/panel.css
ADDED
|
@@ -0,0 +1,261 @@
|
|
|
1
|
+
.weml-panel {
|
|
2
|
+
display: flex;
|
|
3
|
+
flex-direction: column;
|
|
4
|
+
height: 100%;
|
|
5
|
+
min-height: 0;
|
|
6
|
+
box-sizing: border-box;
|
|
7
|
+
overflow: hidden;
|
|
8
|
+
font-family: var(--vscode-font-family, system-ui, sans-serif);
|
|
9
|
+
font-size: var(--vscode-font-size, 13px);
|
|
10
|
+
/* A webview's own; a host page's (Mantine: 1.55) would make every row taller than in VS Code. */
|
|
11
|
+
line-height: normal;
|
|
12
|
+
color: var(--vscode-foreground);
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
/* Panes, like the Explorer's (Outline, Timeline): the panel's height is shared by the open panes,
|
|
16
|
+
each scrolls on its own, a collapsed one is just its 22px header; the sash on a pane's top edge
|
|
17
|
+
resizes it against the open pane above. */
|
|
18
|
+
.weml-panel .weml-panes { display: flex; flex-direction: column; flex: 1 1 auto; min-height: 0; }
|
|
19
|
+
.weml-panel .pane { position: relative; display: flex; flex-direction: column; min-height: 22px; overflow: hidden; }
|
|
20
|
+
.weml-panel .pane:not(.collapsed) { min-height: 70px; }
|
|
21
|
+
/* The border colours fall back to editorWidget.border: Monaco defines no sideBar*, panel or widget
|
|
22
|
+
colours, only the editor's own, and without it the panes and results run into each other. */
|
|
23
|
+
.weml-panel .pane + .pane { border-top: 1px solid var(--vscode-sideBarSectionHeader-border, var(--vscode-panel-border, var(--vscode-editorWidget-border, transparent))); }
|
|
24
|
+
.weml-panel .pane-header {
|
|
25
|
+
display: flex;
|
|
26
|
+
align-items: center;
|
|
27
|
+
gap: 2px;
|
|
28
|
+
flex: none;
|
|
29
|
+
height: 22px;
|
|
30
|
+
padding: 0 8px 0 2px;
|
|
31
|
+
cursor: pointer;
|
|
32
|
+
user-select: none;
|
|
33
|
+
font-size: 11px;
|
|
34
|
+
font-weight: 700;
|
|
35
|
+
text-transform: uppercase;
|
|
36
|
+
color: var(--vscode-sideBarSectionHeader-foreground, var(--vscode-foreground));
|
|
37
|
+
background: var(--vscode-sideBarSectionHeader-background, transparent);
|
|
38
|
+
}
|
|
39
|
+
.weml-panel .pane-header::before {
|
|
40
|
+
content: '';
|
|
41
|
+
width: 16px;
|
|
42
|
+
height: 16px;
|
|
43
|
+
flex: none;
|
|
44
|
+
/* chevron-right, turned down when open */
|
|
45
|
+
background: currentColor;
|
|
46
|
+
-webkit-mask: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 16 16'%3E%3Cpath d='M6 4l4 4-4 4' fill='none' stroke='black' stroke-width='1.3'/%3E%3C/svg%3E") center / 16px no-repeat;
|
|
47
|
+
mask: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 16 16'%3E%3Cpath d='M6 4l4 4-4 4' fill='none' stroke='black' stroke-width='1.3'/%3E%3C/svg%3E") center / 16px no-repeat;
|
|
48
|
+
transform: rotate(90deg);
|
|
49
|
+
transition: transform .1s;
|
|
50
|
+
}
|
|
51
|
+
.weml-panel .pane.collapsed .pane-header::before { transform: none; }
|
|
52
|
+
.weml-panel .pane-header:focus-visible { outline: 1px solid var(--vscode-focusBorder); outline-offset: -1px; }
|
|
53
|
+
.weml-panel .pane-body { flex: 1 1 auto; min-height: 0; overflow: auto; padding: 6px 12px 12px 20px; }
|
|
54
|
+
.weml-panel .pane.collapsed .pane-body { display: none; }
|
|
55
|
+
/* A pane that lays itself out (the search): nothing scrolls but its .scroll part. */
|
|
56
|
+
.weml-panel .pane-body.fill { display: flex; flex-direction: column; overflow: hidden; padding-bottom: 0; }
|
|
57
|
+
.weml-panel .pane-body.fill > section { display: flex; flex-direction: column; flex: 1 1 auto; min-height: 0; margin: 0; }
|
|
58
|
+
.weml-panel .pane-body.fill > section > * { flex: none; }
|
|
59
|
+
.weml-panel .pane-body.fill .scroll { flex: 1 1 auto; min-height: 0; overflow: auto; padding-bottom: 12px; }
|
|
60
|
+
|
|
61
|
+
.weml-panel .sash { position: absolute; top: -2px; left: 0; right: 0; height: 4px; z-index: 10; display: none; }
|
|
62
|
+
.weml-panel .pane.resizable .sash { display: block; cursor: ns-resize; }
|
|
63
|
+
.weml-panel .sash:hover, .weml-panel .sash.active {
|
|
64
|
+
background: var(--vscode-sash-hoverBorder, var(--vscode-focusBorder));
|
|
65
|
+
transition: background .1s .2s;
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
.weml-panel .pane-body section { margin-bottom: 14px; }
|
|
69
|
+
.weml-panel .pane-body section:last-child { margin-bottom: 0; }
|
|
70
|
+
.weml-panel h2 {
|
|
71
|
+
margin: 0 0 6px;
|
|
72
|
+
font-size: 11px;
|
|
73
|
+
font-weight: 600;
|
|
74
|
+
text-transform: uppercase;
|
|
75
|
+
letter-spacing: .04em;
|
|
76
|
+
color: var(--vscode-sideBarSectionHeader-foreground, var(--vscode-foreground));
|
|
77
|
+
opacity: .8;
|
|
78
|
+
}
|
|
79
|
+
.weml-panel [hidden] { display: none !important; }
|
|
80
|
+
.weml-panel .row { display: flex; gap: 6px; margin-bottom: 6px; }
|
|
81
|
+
.weml-panel input, .weml-panel select, .weml-panel button {
|
|
82
|
+
box-sizing: border-box;
|
|
83
|
+
min-width: 0;
|
|
84
|
+
font-family: inherit;
|
|
85
|
+
font-size: inherit;
|
|
86
|
+
color: var(--vscode-input-foreground);
|
|
87
|
+
background: var(--vscode-input-background);
|
|
88
|
+
border: 1px solid var(--vscode-input-border, transparent);
|
|
89
|
+
border-radius: 2px;
|
|
90
|
+
padding: 4px 6px;
|
|
91
|
+
/* 26px with the padding and border, VS Code's input and button height (the icon buttons too). */
|
|
92
|
+
line-height: 16px;
|
|
93
|
+
}
|
|
94
|
+
.weml-panel select { height: 26px; padding-block: 0; }
|
|
95
|
+
.weml-panel select {
|
|
96
|
+
color: var(--vscode-dropdown-foreground);
|
|
97
|
+
background: var(--vscode-dropdown-background);
|
|
98
|
+
border-color: var(--vscode-dropdown-border, transparent);
|
|
99
|
+
}
|
|
100
|
+
.weml-panel input:focus, .weml-panel select:focus, .weml-panel button:focus-visible { outline: 1px solid var(--vscode-focusBorder); outline-offset: -1px; }
|
|
101
|
+
.weml-panel .full { width: 100%; }
|
|
102
|
+
.weml-panel .grow { flex: 1 1 auto; }
|
|
103
|
+
.weml-panel .weml-lang { flex: 0 0 44px; }
|
|
104
|
+
|
|
105
|
+
/* Icon buttons: a square with a 16px inline SVG; the name is in title / aria-label. */
|
|
106
|
+
.weml-panel button.icon {
|
|
107
|
+
display: inline-flex;
|
|
108
|
+
align-items: center;
|
|
109
|
+
justify-content: center;
|
|
110
|
+
flex: none;
|
|
111
|
+
width: 26px;
|
|
112
|
+
height: 26px;
|
|
113
|
+
padding: 0;
|
|
114
|
+
}
|
|
115
|
+
.weml-panel button.icon svg { width: 16px; height: 16px; fill: none; stroke: currentColor; stroke-width: 1.2; stroke-linecap: round; stroke-linejoin: round; }
|
|
116
|
+
.weml-panel button.icon.flat {
|
|
117
|
+
width: 20px;
|
|
118
|
+
height: 20px;
|
|
119
|
+
border: none;
|
|
120
|
+
background: none;
|
|
121
|
+
color: var(--vscode-icon-foreground, var(--vscode-foreground));
|
|
122
|
+
border-radius: 3px;
|
|
123
|
+
}
|
|
124
|
+
.weml-panel button.icon.flat:hover { background: var(--vscode-toolbar-hoverBackground, rgba(128, 128, 128, .2)); }
|
|
125
|
+
/* The main action of a row: the same small square, filled like a primary button. */
|
|
126
|
+
.weml-panel button.icon.flat.primary { color: var(--vscode-button-foreground); background: var(--vscode-button-background); }
|
|
127
|
+
.weml-panel button.icon.flat.primary:hover { background: var(--vscode-button-hoverBackground); }
|
|
128
|
+
|
|
129
|
+
/* The tag picker: an input with its action inside (as the find widget's toggles), and a list drawn
|
|
130
|
+
as the quick pick — rows, matched characters, group separators — on the quick input's colours,
|
|
131
|
+
which VS Code and Monaco (its own command palette) both define. */
|
|
132
|
+
.weml-panel .tool-field {
|
|
133
|
+
display: flex;
|
|
134
|
+
align-items: center;
|
|
135
|
+
gap: 2px;
|
|
136
|
+
box-sizing: border-box;
|
|
137
|
+
height: 26px;
|
|
138
|
+
padding-right: 2px;
|
|
139
|
+
background: var(--vscode-input-background);
|
|
140
|
+
border: 1px solid var(--vscode-input-border, transparent);
|
|
141
|
+
border-radius: 2px;
|
|
142
|
+
}
|
|
143
|
+
.weml-panel .tool-field:focus-within { outline: 1px solid var(--vscode-focusBorder); outline-offset: -1px; }
|
|
144
|
+
.weml-panel .tool-field input { flex: 1 1 auto; height: 24px; border: none; background: none; }
|
|
145
|
+
.weml-panel .tool-field input:focus { outline: none; }
|
|
146
|
+
.weml-panel .tool-field input::placeholder, .weml-panel input::placeholder { color: var(--vscode-input-placeholderForeground); }
|
|
147
|
+
.weml-panel button[aria-disabled="true"] { opacity: .5; cursor: default; }
|
|
148
|
+
.weml-panel button.icon.flat.primary[aria-disabled="true"]:hover { background: var(--vscode-button-background); }
|
|
149
|
+
.weml-panel .tool-list {
|
|
150
|
+
position: fixed;
|
|
151
|
+
z-index: 1000;
|
|
152
|
+
box-sizing: border-box;
|
|
153
|
+
overflow-y: auto;
|
|
154
|
+
padding: 4px 0;
|
|
155
|
+
color: var(--vscode-quickInput-foreground, var(--vscode-foreground));
|
|
156
|
+
background: var(--vscode-quickInput-background, var(--vscode-editorWidget-background));
|
|
157
|
+
border: 1px solid var(--vscode-widget-border, var(--vscode-editorWidget-border, transparent));
|
|
158
|
+
border-radius: 3px;
|
|
159
|
+
box-shadow: 0 0 8px 2px var(--vscode-widget-shadow, rgba(0, 0, 0, .36));
|
|
160
|
+
}
|
|
161
|
+
.weml-panel .tool-group + .tool-group { margin-top: 4px; border-top: 1px solid var(--vscode-pickerGroup-border, transparent); }
|
|
162
|
+
.weml-panel .tool-group-label {
|
|
163
|
+
padding: 2px 8px 0;
|
|
164
|
+
text-align: right;
|
|
165
|
+
font-size: 11px;
|
|
166
|
+
line-height: 16px;
|
|
167
|
+
color: var(--vscode-pickerGroup-foreground, var(--vscode-descriptionForeground));
|
|
168
|
+
}
|
|
169
|
+
.weml-panel .tool-option {
|
|
170
|
+
display: flex;
|
|
171
|
+
align-items: center;
|
|
172
|
+
gap: 12px;
|
|
173
|
+
height: 22px;
|
|
174
|
+
padding: 0 8px;
|
|
175
|
+
white-space: nowrap;
|
|
176
|
+
cursor: pointer;
|
|
177
|
+
}
|
|
178
|
+
.weml-panel .tool-option:hover { background: var(--vscode-list-hoverBackground); }
|
|
179
|
+
.weml-panel .tool-option.active {
|
|
180
|
+
color: var(--vscode-quickInputList-focusForeground, var(--vscode-list-activeSelectionForeground));
|
|
181
|
+
background: var(--vscode-quickInputList-focusBackground, var(--vscode-list-activeSelectionBackground));
|
|
182
|
+
}
|
|
183
|
+
.weml-panel .tool-option .highlight { font-weight: 600; color: var(--vscode-list-highlightForeground); }
|
|
184
|
+
.weml-panel .tool-option.active .highlight { color: var(--vscode-list-focusHighlightForeground, var(--vscode-list-highlightForeground)); }
|
|
185
|
+
.weml-panel .tool-kind { margin-left: auto; font-size: 11px; color: var(--vscode-descriptionForeground); }
|
|
186
|
+
.weml-panel .tool-option.active .tool-kind { color: inherit; opacity: .8; }
|
|
187
|
+
.weml-panel .tool-empty { padding: 2px 8px; color: var(--vscode-descriptionForeground); }
|
|
188
|
+
|
|
189
|
+
/* Scrollbars like the workbench's lists: thin, theme-coloured, shown while the pointer is over the
|
|
190
|
+
scrolling area; a shadow under the top edge once the content is scrolled. */
|
|
191
|
+
.weml-panel .pane-body, .weml-panel .scroll { scrollbar-gutter: stable; }
|
|
192
|
+
/* Chromium ignores every ::-webkit-scrollbar rule on an element whose scrollbar-color or
|
|
193
|
+
scrollbar-width is set - and scrollbar-color inherits - drawing its standard scrollbar with arrow
|
|
194
|
+
buttons instead. Reset both, whoever set them, so the rules below apply. */
|
|
195
|
+
.weml-panel, .weml-panel *, .weml-panel *::before, .weml-panel *::after { scrollbar-color: auto !important; scrollbar-width: auto !important; }
|
|
196
|
+
.weml-panel ::-webkit-scrollbar { width: 10px; height: 10px; }
|
|
197
|
+
.weml-panel ::-webkit-scrollbar-button { display: none; width: 0; height: 0; }
|
|
198
|
+
.weml-panel ::-webkit-scrollbar-track, .weml-panel ::-webkit-scrollbar-corner { background: transparent; }
|
|
199
|
+
.weml-panel ::-webkit-scrollbar-thumb { background: transparent; }
|
|
200
|
+
.weml-panel .pane-body:hover::-webkit-scrollbar-thumb, .weml-panel .scroll:hover::-webkit-scrollbar-thumb { background: var(--vscode-scrollbarSlider-background); }
|
|
201
|
+
.weml-panel ::-webkit-scrollbar-thumb:hover { background: var(--vscode-scrollbarSlider-hoverBackground) !important; }
|
|
202
|
+
.weml-panel ::-webkit-scrollbar-thumb:active { background: var(--vscode-scrollbarSlider-activeBackground) !important; }
|
|
203
|
+
.weml-panel .pane-body.scrolled, .weml-panel .scroll.scrolled { box-shadow: var(--vscode-scrollbar-shadow, rgba(0, 0, 0, .4)) 0 6px 6px -6px inset; }
|
|
204
|
+
.weml-panel button {
|
|
205
|
+
cursor: pointer;
|
|
206
|
+
color: var(--vscode-button-foreground);
|
|
207
|
+
background: var(--vscode-button-background);
|
|
208
|
+
border: 1px solid var(--vscode-button-border, transparent);
|
|
209
|
+
}
|
|
210
|
+
.weml-panel button:hover { background: var(--vscode-button-hoverBackground); }
|
|
211
|
+
.weml-panel button:disabled { opacity: .6; cursor: default; }
|
|
212
|
+
.weml-panel button.secondary {
|
|
213
|
+
color: var(--vscode-button-secondaryForeground);
|
|
214
|
+
background: var(--vscode-button-secondaryBackground);
|
|
215
|
+
}
|
|
216
|
+
.weml-panel button.secondary:hover { background: var(--vscode-button-secondaryHoverBackground); }
|
|
217
|
+
.weml-panel button.link {
|
|
218
|
+
padding: 0;
|
|
219
|
+
border: none;
|
|
220
|
+
background: none;
|
|
221
|
+
color: var(--vscode-textLink-foreground);
|
|
222
|
+
}
|
|
223
|
+
.weml-panel button.link:hover { background: none; color: var(--vscode-textLink-activeForeground); text-decoration: underline; }
|
|
224
|
+
|
|
225
|
+
/* Search suggestions */
|
|
226
|
+
.weml-panel .account { display: flex; flex-wrap: wrap; gap: 6px; align-items: baseline; margin-bottom: 8px; color: var(--vscode-descriptionForeground); }
|
|
227
|
+
.weml-panel .status { color: var(--vscode-descriptionForeground); margin: 4px 0; }
|
|
228
|
+
.weml-panel .status.error { color: var(--vscode-errorForeground); }
|
|
229
|
+
.weml-panel .results { list-style: none; margin: 0; padding: 0; }
|
|
230
|
+
.weml-panel .results li {
|
|
231
|
+
display: grid;
|
|
232
|
+
grid-template-columns: auto 1fr;
|
|
233
|
+
column-gap: 8px;
|
|
234
|
+
padding: 6px 0;
|
|
235
|
+
border-top: 1px solid var(--vscode-widget-border, var(--vscode-panel-border, var(--vscode-editorWidget-border)));
|
|
236
|
+
}
|
|
237
|
+
.weml-panel .results li:last-child { border-bottom: 1px solid var(--vscode-widget-border, var(--vscode-panel-border, var(--vscode-editorWidget-border))); }
|
|
238
|
+
.weml-panel .results .number { grid-row: span 3; color: var(--vscode-descriptionForeground); font-variant-numeric: tabular-nums; }
|
|
239
|
+
.weml-panel .results .meta { display: flex; flex-wrap: wrap; gap: 4px 10px; align-items: center; }
|
|
240
|
+
.weml-panel .results .label { color: var(--vscode-descriptionForeground); font-size: 11px; }
|
|
241
|
+
.weml-panel .results .value { font-family: var(--vscode-editor-font-family); }
|
|
242
|
+
.weml-panel .results .title { margin: 2px 0; overflow-wrap: anywhere; }
|
|
243
|
+
.weml-panel .results .field { display: inline-flex; align-items: center; gap: 2px; white-space: nowrap; }
|
|
244
|
+
/* The link and its actions share one box: the code, then Copy and Insert in a row under it. */
|
|
245
|
+
.weml-panel .results .link {
|
|
246
|
+
margin-top: 2px;
|
|
247
|
+
padding: 4px 6px 2px;
|
|
248
|
+
border-radius: 3px;
|
|
249
|
+
background: var(--vscode-textPreformat-background, var(--vscode-textCodeBlock-background));
|
|
250
|
+
}
|
|
251
|
+
.weml-panel .results .link code {
|
|
252
|
+
display: block;
|
|
253
|
+
padding: 0;
|
|
254
|
+
background: none;
|
|
255
|
+
font-family: var(--vscode-editor-font-family);
|
|
256
|
+
font-size: 11px;
|
|
257
|
+
overflow-wrap: anywhere;
|
|
258
|
+
color: var(--vscode-textPreformat-foreground);
|
|
259
|
+
}
|
|
260
|
+
.weml-panel .results .link .actions { display: flex; justify-content: flex-end; gap: 2px; margin-top: 2px; }
|
|
261
|
+
.weml-panel .dim { color: var(--vscode-descriptionForeground); }
|