web-remarq 0.1.2 → 0.1.3

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/dist/index.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"sources":["../src/core/storage.ts","../src/core/hash-detect.ts","../src/core/fingerprint.ts","../src/core/matcher.ts","../src/ui/styles.ts","../src/ui/theme.ts","../src/ui/toolbar.ts","../src/ui/overlay.ts","../src/ui/popup.ts","../src/ui/markers.ts","../src/ui/detached-panel.ts","../src/spa.ts","../src/web-remarq.ts"],"sourcesContent":["import type { Annotation, AnnotationStore } from './types'\n\nconst STORAGE_KEY = 'remarq:annotations'\n\nexport class AnnotationStorage {\n private annotations: Annotation[] = []\n private extraFields: Record<string, unknown> = {}\n isMemoryOnly = false\n\n constructor() {\n this.load()\n }\n\n getAll(): Annotation[] {\n return [...this.annotations]\n }\n\n getByRoute(route: string): Annotation[] {\n return this.annotations.filter((a) => a.route === route)\n }\n\n add(annotation: Annotation): void {\n this.annotations.push(annotation)\n this.save()\n }\n\n remove(id: string): void {\n this.annotations = this.annotations.filter((a) => a.id !== id)\n this.save()\n }\n\n update(id: string, changes: Partial<Annotation>): void {\n const idx = this.annotations.findIndex((a) => a.id === id)\n if (idx !== -1) {\n this.annotations[idx] = { ...this.annotations[idx], ...changes }\n this.save()\n }\n }\n\n clearAll(): void {\n this.annotations = []\n this.save()\n }\n\n exportJSON(): AnnotationStore {\n return {\n version: 1,\n annotations: [...this.annotations],\n }\n }\n\n importJSON(data: AnnotationStore): void {\n this.annotations = [...data.annotations]\n this.save()\n }\n\n private load(): void {\n try {\n const raw = localStorage.getItem(STORAGE_KEY)\n if (raw) {\n const parsed = JSON.parse(raw)\n const { version, annotations, ...rest } = parsed\n this.annotations = annotations ?? []\n this.extraFields = rest\n }\n } catch {\n this.isMemoryOnly = true\n }\n }\n\n private save(): void {\n if (this.isMemoryOnly) return\n try {\n const data = {\n version: 1,\n ...this.extraFields,\n annotations: this.annotations,\n }\n localStorage.setItem(STORAGE_KEY, JSON.stringify(data))\n } catch {\n this.isMemoryOnly = true\n }\n }\n}\n","const CSS_MODULES_RE = /^(.+)__([a-zA-Z0-9]{3,})$/\nconst STYLED_COMPONENTS_RE = /^sc-/\nconst EMOTION_RE = /^css-[a-zA-Z0-9]+$/\nconst PURE_HASH_RE = /^(?=.*[a-zA-Z])(?=.*\\d)[a-zA-Z0-9]{8,}$/\n\nexport function isHashedClass(className: string): boolean {\n if (STYLED_COMPONENTS_RE.test(className)) return true\n if (EMOTION_RE.test(className)) return true\n if (CSS_MODULES_RE.test(className)) return true\n if (PURE_HASH_RE.test(className)) return true\n return false\n}\n\nexport function stripHash(className: string): string {\n const match = className.match(CSS_MODULES_RE)\n if (match) {\n const prefix = className.slice(0, className.lastIndexOf('__'))\n return prefix\n }\n return className\n}\n\nexport function filterClasses(\n classes: string[],\n classFilter?: (className: string) => boolean,\n): string[] {\n const result: string[] = []\n\n for (const cls of classes) {\n if (STYLED_COMPONENTS_RE.test(cls)) continue\n if (EMOTION_RE.test(cls)) continue\n if (PURE_HASH_RE.test(cls)) continue\n\n let stable = stripHash(cls)\n\n if (classFilter && !classFilter(stable)) continue\n\n result.push(stable)\n }\n\n return result\n}\n","import type { ElementFingerprint, WebRemarqOptions } from './types'\nimport { filterClasses, isHashedClass } from './hash-detect'\n\nconst TEXT_MAX_LENGTH = 50\n\nexport function createFingerprint(\n el: HTMLElement,\n options?: Pick<WebRemarqOptions, 'classFilter' | 'dataAttribute'>,\n): ElementFingerprint {\n const dataAttr = options?.dataAttribute ?? 'data-annotate'\n\n return {\n dataAnnotate: el.getAttribute(dataAttr) ?? null,\n dataTestId: el.getAttribute('data-testid')\n ?? el.getAttribute('data-test')\n ?? el.getAttribute('data-cy')\n ?? null,\n id: getStableId(el),\n tagName: el.tagName.toLowerCase(),\n textContent: getTextContent(el),\n role: el.getAttribute('role') ?? null,\n ariaLabel: el.getAttribute('aria-label') ?? null,\n stableClasses: filterClasses(\n Array.from(el.classList),\n options?.classFilter,\n ),\n domPath: buildDomPath(el),\n siblingIndex: getSiblingIndex(el),\n parentAnchor: findParentAnchor(el, dataAttr),\n }\n}\n\nfunction getStableId(el: HTMLElement): string | null {\n const id = el.id\n if (!id) return null\n if (isHashedClass(id)) return null\n return id\n}\n\nfunction getTextContent(el: HTMLElement): string | null {\n const text = el.textContent?.trim() ?? null\n if (!text) return null\n return text.length > TEXT_MAX_LENGTH ? text.slice(0, TEXT_MAX_LENGTH) : text\n}\n\nfunction buildDomPath(el: HTMLElement): string {\n const parts: string[] = []\n let current: HTMLElement | null = el\n\n while (current && current !== document.body && parts.length < 5) {\n parts.unshift(current.tagName.toLowerCase())\n current = current.parentElement\n }\n\n return parts.join(' > ')\n}\n\nfunction getSiblingIndex(el: HTMLElement): number {\n const parent = el.parentElement\n if (!parent) return 0\n const children = Array.from(parent.children)\n return children.indexOf(el)\n}\n\nfunction findParentAnchor(el: HTMLElement, dataAttr: string): string | null {\n let current = el.parentElement\n while (current && current !== document.body) {\n const value = current.getAttribute(dataAttr)\n if (value) return value\n current = current.parentElement\n }\n return null\n}\n","import type { ElementFingerprint, WebRemarqOptions } from './types'\n\nconst MATCH_THRESHOLD = 50\n\nexport function levenshteinSimilarity(a: string, b: string): number {\n if (a === b) return 1\n if (!a.length || !b.length) return 0\n\n const matrix: number[][] = []\n for (let i = 0; i <= a.length; i++) {\n matrix[i] = [i]\n }\n for (let j = 0; j <= b.length; j++) {\n matrix[0][j] = j\n }\n\n for (let i = 1; i <= a.length; i++) {\n for (let j = 1; j <= b.length; j++) {\n const cost = a[i - 1] === b[j - 1] ? 0 : 1\n matrix[i][j] = Math.min(\n matrix[i - 1][j] + 1,\n matrix[i][j - 1] + 1,\n matrix[i - 1][j - 1] + cost,\n )\n }\n }\n\n const distance = matrix[a.length][b.length]\n return 1 - distance / Math.max(a.length, b.length)\n}\n\nfunction textSimilarity(a: string | null, b: string | null): number {\n if (!a || !b) return 0\n const na = a.trim().toLowerCase()\n const nb = b.trim().toLowerCase()\n if (na === nb) return 1\n if (na.includes(nb) || nb.includes(na)) return 1\n return levenshteinSimilarity(na, nb)\n}\n\nfunction jaccardSimilarity(a: string[], b: string[]): number {\n if (!a.length && !b.length) return 0\n const setA = new Set(a)\n const setB = new Set(b)\n let intersection = 0\n for (const item of setA) {\n if (setB.has(item)) intersection++\n }\n const union = new Set([...a, ...b]).size\n return union === 0 ? 0 : intersection / union\n}\n\nfunction scoreCandidate(el: HTMLElement, fp: ElementFingerprint, dataAttr: string): number {\n let score = 0\n\n // dataAnnotate match (+100)\n const elAnnotate = el.getAttribute(dataAttr)\n if (fp.dataAnnotate && elAnnotate === fp.dataAnnotate) {\n score += 100\n }\n\n // textContent match (+35 scaled)\n const elText = el.textContent?.trim().slice(0, 50) ?? null\n const textSim = textSimilarity(fp.textContent, elText)\n if (textSim > 0.7) {\n score += textSim * 35\n }\n\n // role + ariaLabel match (+30)\n if (fp.role && el.getAttribute('role') === fp.role &&\n fp.ariaLabel && el.getAttribute('aria-label') === fp.ariaLabel) {\n score += 30\n }\n\n // parentAnchor match (+15)\n if (fp.parentAnchor) {\n let parent = el.parentElement\n while (parent && parent !== document.body) {\n if (parent.getAttribute(dataAttr) === fp.parentAnchor) {\n score += 15\n break\n }\n parent = parent.parentElement\n }\n }\n\n // stableClasses overlap (+15 scaled)\n if (fp.stableClasses.length > 0) {\n const elClasses = Array.from(el.classList)\n const jaccard = jaccardSimilarity(fp.stableClasses, elClasses)\n score += jaccard * 15\n }\n\n // domPath match (+15 scaled)\n if (fp.domPath) {\n const elPath = buildDomPath(el)\n const pathSim = levenshteinSimilarity(fp.domPath, elPath)\n score += pathSim * 15\n }\n\n // siblingIndex match (+5)\n const parent = el.parentElement\n if (parent) {\n const idx = Array.from(parent.children).indexOf(el)\n if (idx === fp.siblingIndex) {\n score += 5\n }\n }\n\n return score\n}\n\nfunction buildDomPath(el: HTMLElement): string {\n const parts: string[] = []\n let current: HTMLElement | null = el\n while (current && current !== document.body && parts.length < 5) {\n parts.unshift(current.tagName.toLowerCase())\n current = current.parentElement\n }\n return parts.join(' > ')\n}\n\nexport function matchElement(\n fp: ElementFingerprint,\n options?: Pick<WebRemarqOptions, 'dataAttribute'>,\n): HTMLElement | null {\n const dataAttr = options?.dataAttribute ?? 'data-annotate'\n\n // 1. Exact match by data-annotate\n if (fp.dataAnnotate) {\n const el = document.querySelector<HTMLElement>(`[${dataAttr}=\"${fp.dataAnnotate}\"]`)\n if (el) return el\n }\n\n // 2. Exact match by data-testid\n if (fp.dataTestId) {\n const el = document.querySelector<HTMLElement>(\n `[data-testid=\"${fp.dataTestId}\"], [data-test=\"${fp.dataTestId}\"], [data-cy=\"${fp.dataTestId}\"]`,\n )\n if (el) return el\n }\n\n // 3. Exact match by id\n if (fp.id) {\n const el = document.getElementById(fp.id) as HTMLElement | null\n if (el) return el\n }\n\n // 4. Fuzzy match by tagName + weighted scoring\n const candidates = document.querySelectorAll<HTMLElement>(fp.tagName)\n let bestEl: HTMLElement | null = null\n let bestScore = 0\n\n for (const candidate of candidates) {\n const score = scoreCandidate(candidate, fp, dataAttr)\n if (score > bestScore) {\n bestScore = score\n bestEl = candidate\n }\n }\n\n return bestScore >= MATCH_THRESHOLD ? bestEl : null\n}\n","const STYLES_ID = 'data-remarq-styles'\n\nconst CSS = `\n[data-remarq-theme=\"light\"] {\n --remarq-bg: #ffffff;\n --remarq-bg-secondary: #f5f5f5;\n --remarq-text: #1a1a1a;\n --remarq-text-secondary: #666666;\n --remarq-border: #e2e8f0;\n --remarq-accent: #3b82f6;\n --remarq-pending: #f97316;\n --remarq-resolved: #22c55e;\n --remarq-overlay: rgba(59, 130, 246, 0.15);\n --remarq-shadow: 0 4px 12px rgba(0,0,0,0.15);\n}\n\n[data-remarq-theme=\"dark\"] {\n --remarq-bg: #1e1e1e;\n --remarq-bg-secondary: #2a2a2a;\n --remarq-text: #e5e5e5;\n --remarq-text-secondary: #999999;\n --remarq-border: #333333;\n --remarq-accent: #60a5fa;\n --remarq-pending: #fb923c;\n --remarq-resolved: #4ade80;\n --remarq-overlay: rgba(96, 165, 250, 0.15);\n --remarq-shadow: 0 4px 12px rgba(0,0,0,0.4);\n}\n\n.remarq-toolbar {\n position: fixed;\n bottom: 16px;\n right: 16px;\n z-index: 2147483647;\n display: flex;\n gap: 4px;\n padding: 8px;\n background: var(--remarq-bg);\n border: 1px solid var(--remarq-border);\n border-radius: 8px;\n box-shadow: var(--remarq-shadow);\n font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, sans-serif;\n font-size: 13px;\n color: var(--remarq-text);\n}\n\n.remarq-toolbar.remarq-minimized { padding: 4px; }\n\n.remarq-toolbar-btn {\n display: flex;\n align-items: center;\n justify-content: center;\n width: 32px;\n height: 32px;\n border: none;\n border-radius: 6px;\n background: transparent;\n color: var(--remarq-text);\n cursor: pointer;\n position: relative;\n}\n\n.remarq-toolbar-btn:hover { background: var(--remarq-bg-secondary); }\n.remarq-toolbar-btn.remarq-active { background: var(--remarq-accent); color: #ffffff; }\n\n.remarq-badge {\n position: absolute;\n top: -4px;\n right: -4px;\n min-width: 16px;\n height: 16px;\n padding: 0 4px;\n border-radius: 8px;\n background: var(--remarq-pending);\n color: #ffffff;\n font-size: 10px;\n font-weight: 600;\n display: flex;\n align-items: center;\n justify-content: center;\n}\n\n.remarq-overlay {\n position: fixed;\n pointer-events: none;\n background: var(--remarq-overlay);\n border: 2px solid var(--remarq-accent);\n border-radius: 2px;\n z-index: 2147483646;\n transition: all 0.05s ease-out;\n}\n\n.remarq-tooltip {\n position: fixed;\n z-index: 2147483647;\n padding: 4px 8px;\n background: var(--remarq-bg);\n border: 1px solid var(--remarq-border);\n border-radius: 4px;\n font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, sans-serif;\n font-size: 12px;\n color: var(--remarq-text);\n box-shadow: var(--remarq-shadow);\n pointer-events: none;\n white-space: nowrap;\n max-width: 300px;\n overflow: hidden;\n text-overflow: ellipsis;\n}\n\n.remarq-marker {\n position: absolute;\n z-index: 2147483645;\n width: 24px;\n height: 24px;\n border-radius: 50%;\n display: flex;\n align-items: center;\n justify-content: center;\n font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, sans-serif;\n font-size: 11px;\n font-weight: 700;\n color: #ffffff;\n cursor: pointer;\n box-shadow: 0 2px 4px rgba(0,0,0,0.2);\n transition: transform 0.1s ease;\n}\n\n.remarq-marker:hover { transform: scale(1.2); }\n.remarq-marker[data-status=\"pending\"] { background: var(--remarq-pending); }\n.remarq-marker[data-status=\"resolved\"] { background: var(--remarq-resolved); opacity: 0.7; }\n\n.remarq-popup {\n position: fixed;\n z-index: 2147483647;\n width: 300px;\n background: var(--remarq-bg);\n border: 1px solid var(--remarq-border);\n border-radius: 8px;\n box-shadow: var(--remarq-shadow);\n font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, sans-serif;\n font-size: 13px;\n color: var(--remarq-text);\n}\n\n.remarq-popup-header {\n padding: 8px 12px;\n border-bottom: 1px solid var(--remarq-border);\n font-size: 12px;\n color: var(--remarq-text-secondary);\n overflow: hidden;\n text-overflow: ellipsis;\n white-space: nowrap;\n}\n\n.remarq-popup-body { padding: 12px; }\n\n.remarq-popup textarea {\n width: 100%;\n min-height: 60px;\n padding: 8px;\n border: 1px solid var(--remarq-border);\n border-radius: 4px;\n background: var(--remarq-bg-secondary);\n color: var(--remarq-text);\n font-family: inherit;\n font-size: 13px;\n resize: vertical;\n box-sizing: border-box;\n}\n\n.remarq-popup textarea:focus { outline: none; border-color: var(--remarq-accent); }\n\n.remarq-popup-actions {\n display: flex;\n justify-content: flex-end;\n gap: 8px;\n padding: 8px 12px;\n border-top: 1px solid var(--remarq-border);\n}\n\n.remarq-popup-actions button {\n padding: 4px 12px;\n border: 1px solid var(--remarq-border);\n border-radius: 4px;\n background: var(--remarq-bg);\n color: var(--remarq-text);\n cursor: pointer;\n font-size: 12px;\n}\n\n.remarq-popup-actions button.remarq-primary {\n background: var(--remarq-accent);\n border-color: var(--remarq-accent);\n color: #ffffff;\n}\n\n.remarq-detached-panel {\n position: fixed;\n bottom: 60px;\n right: 16px;\n z-index: 2147483646;\n width: 280px;\n max-height: 300px;\n overflow-y: auto;\n background: var(--remarq-bg);\n border: 1px solid var(--remarq-border);\n border-radius: 8px;\n box-shadow: var(--remarq-shadow);\n font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, sans-serif;\n font-size: 13px;\n color: var(--remarq-text);\n}\n\n.remarq-detached-header {\n padding: 8px 12px;\n border-bottom: 1px solid var(--remarq-border);\n font-weight: 600;\n font-size: 12px;\n color: var(--remarq-text-secondary);\n}\n\n.remarq-detached-item {\n padding: 8px 12px;\n border-bottom: 1px solid var(--remarq-border);\n display: flex;\n justify-content: space-between;\n align-items: flex-start;\n gap: 8px;\n}\n\n.remarq-detached-item:last-child { border-bottom: none; }\n.remarq-detached-info { flex: 1; min-width: 0; }\n.remarq-detached-comment { margin-bottom: 4px; }\n\n.remarq-detached-element {\n font-size: 11px;\n color: var(--remarq-text-secondary);\n overflow: hidden;\n text-overflow: ellipsis;\n white-space: nowrap;\n}\n\n.remarq-detached-delete {\n border: none;\n background: none;\n color: var(--remarq-text-secondary);\n cursor: pointer;\n padding: 2px;\n font-size: 14px;\n line-height: 1;\n flex-shrink: 0;\n}\n\n.remarq-detached-delete:hover { color: #ef4444; }\n\n.remarq-export-menu {\n position: absolute;\n bottom: 100%;\n right: 0;\n margin-bottom: 4px;\n background: var(--remarq-bg);\n border: 1px solid var(--remarq-border);\n border-radius: 6px;\n box-shadow: var(--remarq-shadow);\n overflow: hidden;\n}\n\n.remarq-export-menu button {\n display: block;\n width: 100%;\n padding: 8px 16px;\n border: none;\n background: transparent;\n color: var(--remarq-text);\n cursor: pointer;\n font-size: 12px;\n text-align: left;\n white-space: nowrap;\n}\n\n.remarq-export-menu button:hover { background: var(--remarq-bg-secondary); }\n`\n\nexport function injectStyles(): void {\n if (document.querySelector(`style[${STYLES_ID}]`)) return\n\n try {\n const style = document.createElement('style')\n style.setAttribute(STYLES_ID, '')\n style.textContent = CSS\n document.head.appendChild(style)\n } catch {\n // CSP fallback: try blob URL via <link>\n try {\n const blob = new Blob([CSS], { type: 'text/css' })\n const link = document.createElement('link')\n link.rel = 'stylesheet'\n link.href = URL.createObjectURL(blob)\n link.setAttribute(STYLES_ID, '')\n document.head.appendChild(link)\n } catch {\n console.warn('[web-remarq] Could not inject styles')\n }\n }\n}\n\nexport function removeStyles(): void {\n const el = document.querySelector(`[${STYLES_ID}]`)\n el?.remove()\n}\n","const THEME_KEY = 'remarq:theme'\n\nexport type Theme = 'light' | 'dark'\n\nexport class ThemeManager {\n container: HTMLElement\n private theme: Theme\n\n constructor(parent: HTMLElement, initialTheme?: Theme) {\n const persisted = this.loadTheme()\n this.theme = initialTheme ?? persisted ?? 'light'\n\n this.container = document.createElement('div')\n this.container.setAttribute('data-remarq-theme', this.theme)\n parent.appendChild(this.container)\n\n this.persist()\n }\n\n getTheme(): Theme {\n return this.theme\n }\n\n setTheme(theme: Theme): void {\n this.theme = theme\n this.container.setAttribute('data-remarq-theme', theme)\n this.persist()\n }\n\n toggle(): void {\n this.setTheme(this.theme === 'light' ? 'dark' : 'light')\n }\n\n destroy(): void {\n this.container.remove()\n }\n\n private persist(): void {\n try {\n localStorage.setItem(THEME_KEY, this.theme)\n } catch {\n // ignore\n }\n }\n\n private loadTheme(): Theme | null {\n try {\n const value = localStorage.getItem(THEME_KEY)\n if (value === 'light' || value === 'dark') return value\n } catch {\n // ignore\n }\n return null\n }\n}\n","export interface ToolbarCallbacks {\n onInspect: () => void\n onExportMd: () => void\n onExportJson: () => void\n onImport: () => void\n onClear: () => void\n onThemeToggle: () => void\n}\n\nconst ICONS = {\n inspect: '<svg width=\"16\" height=\"16\" viewBox=\"0 0 16 16\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"1.5\"><circle cx=\"7\" cy=\"7\" r=\"4\"/><line x1=\"10\" y1=\"10\" x2=\"14\" y2=\"14\"/></svg>',\n export: '<svg width=\"16\" height=\"16\" viewBox=\"0 0 16 16\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"1.5\"><path d=\"M8 2v8M4 6l4-4 4 4M2 12h12\"/></svg>',\n import: '<svg width=\"16\" height=\"16\" viewBox=\"0 0 16 16\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"1.5\"><path d=\"M8 10V2M4 6l4 4 4-4M2 12h12\"/></svg>',\n clear: '<svg width=\"16\" height=\"16\" viewBox=\"0 0 16 16\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"1.5\"><path d=\"M3 4h10M6 4V3h4v1M5 4v9h6V4\"/></svg>',\n theme: '<svg width=\"16\" height=\"16\" viewBox=\"0 0 16 16\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"1.5\"><circle cx=\"8\" cy=\"8\" r=\"3\"/><path d=\"M8 1v2M8 13v2M1 8h2M13 8h2\"/></svg>',\n minimize: '<svg width=\"16\" height=\"16\" viewBox=\"0 0 16 16\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"1.5\"><path d=\"M4 8h8\"/></svg>',\n}\n\nexport class Toolbar {\n private toolbarEl: HTMLElement\n private badgeEl: HTMLElement\n private inspectBtn: HTMLElement\n private exportMenu: HTMLElement | null = null\n private fileInput: HTMLInputElement\n private minimized = false\n private buttons: HTMLElement[] = []\n\n constructor(\n private container: HTMLElement,\n private callbacks: ToolbarCallbacks,\n ) {\n this.toolbarEl = document.createElement('div')\n this.toolbarEl.className = 'remarq-toolbar'\n\n this.inspectBtn = this.createButton('inspect', ICONS.inspect, () => callbacks.onInspect())\n this.badgeEl = document.createElement('span')\n this.badgeEl.className = 'remarq-badge'\n this.badgeEl.style.display = 'none'\n this.inspectBtn.appendChild(this.badgeEl)\n\n const exportBtn = this.createButton('export', ICONS.export, (e) => this.toggleExportMenu(e))\n\n this.fileInput = document.createElement('input')\n this.fileInput.type = 'file'\n this.fileInput.accept = '.json'\n this.fileInput.style.display = 'none'\n this.fileInput.addEventListener('change', () => {\n callbacks.onImport()\n this.fileInput.value = ''\n })\n const importBtn = this.createButton('import', ICONS.import, () => this.fileInput.click())\n\n const clearBtn = this.createButton('clear', ICONS.clear, () => callbacks.onClear())\n const themeBtn = this.createButton('theme', ICONS.theme, () => callbacks.onThemeToggle())\n const minimizeBtn = this.createButton('minimize', ICONS.minimize, () => this.toggleMinimize())\n\n this.buttons = [this.inspectBtn, exportBtn, importBtn, clearBtn, themeBtn]\n\n this.toolbarEl.appendChild(this.inspectBtn)\n this.toolbarEl.appendChild(exportBtn)\n this.toolbarEl.appendChild(importBtn)\n this.toolbarEl.appendChild(clearBtn)\n this.toolbarEl.appendChild(themeBtn)\n this.toolbarEl.appendChild(minimizeBtn)\n this.toolbarEl.appendChild(this.fileInput)\n\n container.appendChild(this.toolbarEl)\n }\n\n setInspectActive(active: boolean): void {\n this.inspectBtn.classList.toggle('remarq-active', active)\n }\n\n setBadgeCount(count: number): void {\n this.badgeEl.textContent = String(count)\n this.badgeEl.style.display = count > 0 ? 'flex' : 'none'\n }\n\n getFileInput(): HTMLInputElement {\n return this.fileInput\n }\n\n setMemoryWarning(show: boolean): void {\n this.toolbarEl.title = show ? 'localStorage unavailable — annotations stored in memory only' : ''\n }\n\n destroy(): void {\n this.closeExportMenu()\n this.toolbarEl.remove()\n }\n\n private createButton(action: string, icon: string, handler: (e: Event) => void): HTMLElement {\n const btn = document.createElement('button')\n btn.className = 'remarq-toolbar-btn'\n btn.setAttribute('data-remarq-action', action)\n btn.innerHTML = icon\n btn.addEventListener('click', handler)\n return btn\n }\n\n private toggleMinimize(): void {\n this.minimized = !this.minimized\n this.toolbarEl.classList.toggle('remarq-minimized', this.minimized)\n for (const btn of this.buttons) {\n btn.style.display = this.minimized ? 'none' : ''\n }\n }\n\n private toggleExportMenu(e: Event): void {\n if (this.exportMenu) {\n this.closeExportMenu()\n return\n }\n\n this.exportMenu = document.createElement('div')\n this.exportMenu.className = 'remarq-export-menu'\n\n const mdBtn = document.createElement('button')\n mdBtn.textContent = 'Markdown (clipboard)'\n mdBtn.addEventListener('click', () => {\n this.callbacks.onExportMd()\n this.closeExportMenu()\n })\n\n const jsonBtn = document.createElement('button')\n jsonBtn.textContent = 'JSON (file)'\n jsonBtn.addEventListener('click', () => {\n this.callbacks.onExportJson()\n this.closeExportMenu()\n })\n\n this.exportMenu.appendChild(mdBtn)\n this.exportMenu.appendChild(jsonBtn)\n\n const exportBtn = (e.currentTarget as HTMLElement)\n exportBtn.style.position = 'relative'\n exportBtn.appendChild(this.exportMenu)\n }\n\n private closeExportMenu(): void {\n if (this.exportMenu) {\n this.exportMenu.remove()\n this.exportMenu = null\n }\n }\n}\n","export class Overlay {\n private overlayEl: HTMLElement\n private tooltipEl: HTMLElement\n\n constructor(private container: HTMLElement) {\n this.overlayEl = document.createElement('div')\n this.overlayEl.className = 'remarq-overlay'\n this.overlayEl.style.display = 'none'\n\n this.tooltipEl = document.createElement('div')\n this.tooltipEl.className = 'remarq-tooltip'\n this.tooltipEl.style.display = 'none'\n\n container.appendChild(this.overlayEl)\n container.appendChild(this.tooltipEl)\n }\n\n show(target: HTMLElement): void {\n try {\n const rect = target.getBoundingClientRect()\n\n this.overlayEl.style.display = 'block'\n this.overlayEl.style.top = `${rect.top}px`\n this.overlayEl.style.left = `${rect.left}px`\n this.overlayEl.style.width = `${rect.width}px`\n this.overlayEl.style.height = `${rect.height}px`\n\n const tag = target.tagName.toLowerCase()\n const text = target.textContent?.trim().slice(0, 30) || ''\n const dataAnnotate = target.getAttribute('data-annotate')\n let label = `<${tag}>`\n if (text) label += ` \"${text}\"`\n if (dataAnnotate) label += ` [${dataAnnotate}]`\n\n this.tooltipEl.textContent = label\n this.tooltipEl.style.display = 'block'\n this.tooltipEl.style.top = `${rect.top - 28}px`\n this.tooltipEl.style.left = `${rect.left}px`\n } catch {\n this.hide()\n }\n }\n\n updateTooltipPosition(x: number, y: number): void {\n this.tooltipEl.style.left = `${x + 12}px`\n this.tooltipEl.style.top = `${y - 28}px`\n }\n\n hide(): void {\n this.overlayEl.style.display = 'none'\n this.tooltipEl.style.display = 'none'\n }\n\n destroy(): void {\n this.overlayEl.remove()\n this.tooltipEl.remove()\n }\n}\n","interface ElementInfo {\n tag: string\n text: string\n}\n\ninterface DetailInfo extends ElementInfo {\n comment: string\n status: 'pending' | 'resolved'\n}\n\ninterface DetailCallbacks {\n onResolve: () => void\n onDelete: () => void\n onClose: () => void\n}\n\ninterface Position {\n top: number\n left: number\n}\n\nconst POPUP_WIDTH = 300\nconst POPUP_MARGIN = 8\n\nexport class Popup {\n private popupEl: HTMLElement | null = null\n private keyHandler: ((e: KeyboardEvent) => void) | null = null\n\n constructor(private container: HTMLElement) {}\n\n show(\n info: ElementInfo,\n position: Position,\n onSubmit: (comment: string) => void,\n onCancel: () => void,\n ): void {\n this.hide()\n\n const popup = document.createElement('div')\n popup.className = 'remarq-popup'\n\n const header = document.createElement('div')\n header.className = 'remarq-popup-header'\n header.textContent = `<${info.tag}>${info.text ? ` \"${info.text}\"` : ''}`\n\n const body = document.createElement('div')\n body.className = 'remarq-popup-body'\n\n const textarea = document.createElement('textarea')\n textarea.placeholder = 'Add your comment...'\n\n body.appendChild(textarea)\n\n const actions = document.createElement('div')\n actions.className = 'remarq-popup-actions'\n\n const cancelBtn = document.createElement('button')\n cancelBtn.textContent = 'Cancel'\n cancelBtn.addEventListener('click', () => {\n this.hide()\n onCancel()\n })\n\n const addBtn = document.createElement('button')\n addBtn.className = 'remarq-primary'\n addBtn.textContent = 'Add'\n addBtn.addEventListener('click', () => {\n const comment = textarea.value.trim()\n if (!comment) return\n this.hide()\n onSubmit(comment)\n })\n\n actions.appendChild(cancelBtn)\n actions.appendChild(addBtn)\n\n popup.appendChild(header)\n popup.appendChild(body)\n popup.appendChild(actions)\n\n this.container.appendChild(popup)\n this.popupEl = popup\n\n this.adjustPosition(popup, position)\n\n // Cmd/Ctrl+Enter to submit\n this.keyHandler = (e: KeyboardEvent) => {\n if (e.key === 'Enter' && (e.metaKey || e.ctrlKey)) {\n const comment = textarea.value.trim()\n if (!comment) return\n this.hide()\n onSubmit(comment)\n }\n if (e.key === 'Escape') {\n this.hide()\n onCancel()\n }\n }\n document.addEventListener('keydown', this.keyHandler)\n\n // Focus textarea after render\n requestAnimationFrame(() => textarea.focus())\n }\n\n showDetail(\n info: DetailInfo,\n position: Position,\n callbacks: DetailCallbacks,\n ): void {\n this.hide()\n\n const popup = document.createElement('div')\n popup.className = 'remarq-popup'\n\n const header = document.createElement('div')\n header.className = 'remarq-popup-header'\n header.textContent = `<${info.tag}>${info.text ? ` \"${info.text}\"` : ''} [${info.status}]`\n\n const body = document.createElement('div')\n body.className = 'remarq-popup-body'\n body.textContent = info.comment\n\n const actions = document.createElement('div')\n actions.className = 'remarq-popup-actions'\n\n if (info.status === 'pending') {\n const resolveBtn = document.createElement('button')\n resolveBtn.className = 'remarq-primary'\n resolveBtn.textContent = 'Resolve'\n resolveBtn.addEventListener('click', () => {\n this.hide()\n callbacks.onResolve()\n })\n actions.appendChild(resolveBtn)\n }\n\n const deleteBtn = document.createElement('button')\n deleteBtn.textContent = 'Delete'\n deleteBtn.addEventListener('click', () => {\n this.hide()\n callbacks.onDelete()\n })\n actions.appendChild(deleteBtn)\n\n const closeBtn = document.createElement('button')\n closeBtn.textContent = 'Close'\n closeBtn.addEventListener('click', () => {\n this.hide()\n callbacks.onClose()\n })\n actions.appendChild(closeBtn)\n\n popup.appendChild(header)\n popup.appendChild(body)\n popup.appendChild(actions)\n\n this.container.appendChild(popup)\n this.popupEl = popup\n\n this.adjustPosition(popup, position)\n\n this.keyHandler = (e: KeyboardEvent) => {\n if (e.key === 'Escape') {\n this.hide()\n callbacks.onClose()\n }\n }\n document.addEventListener('keydown', this.keyHandler)\n }\n\n hide(): void {\n if (this.popupEl) {\n this.popupEl.remove()\n this.popupEl = null\n }\n if (this.keyHandler) {\n document.removeEventListener('keydown', this.keyHandler)\n this.keyHandler = null\n }\n }\n\n destroy(): void {\n this.hide()\n }\n\n private adjustPosition(popup: HTMLElement, position: Position): void {\n const popupRect = popup.getBoundingClientRect()\n const viewH = window.innerHeight\n const viewW = window.innerWidth\n\n let top = position.top\n let left = position.left\n\n // Flip above if overflows bottom\n if (top + popupRect.height > viewH - POPUP_MARGIN) {\n top = position.top - popupRect.height - 16\n }\n\n // Clamp to top edge\n if (top < POPUP_MARGIN) {\n top = POPUP_MARGIN\n }\n\n // Clamp to right edge\n if (left + POPUP_WIDTH > viewW - POPUP_MARGIN) {\n left = viewW - POPUP_WIDTH - POPUP_MARGIN\n }\n\n // Clamp to left edge\n if (left < POPUP_MARGIN) {\n left = POPUP_MARGIN\n }\n\n popup.style.top = `${top}px`\n popup.style.left = `${left}px`\n }\n}\n","import type { Annotation } from '../core/types'\n\ninterface MarkerEntry {\n annotation: Annotation\n target: HTMLElement\n markerEl: HTMLElement\n}\n\nexport class MarkerManager {\n private markers = new Map<string, MarkerEntry>()\n private rafId: number | null = null\n private counter = 0\n\n constructor(\n private container: HTMLElement,\n private onClick?: (annotationId: string) => void,\n ) {\n this.startPositionLoop()\n }\n\n addMarker(annotation: Annotation, target: HTMLElement): void {\n this.counter++\n const markerEl = document.createElement('div')\n markerEl.className = 'remarq-marker'\n markerEl.setAttribute('data-status', annotation.status)\n markerEl.setAttribute('data-annotation-id', annotation.id)\n markerEl.textContent = String(this.counter)\n markerEl.title = annotation.comment\n\n markerEl.addEventListener('click', () => {\n this.onClick?.(annotation.id)\n })\n\n this.container.appendChild(markerEl)\n this.markers.set(annotation.id, { annotation, target, markerEl })\n this.updatePosition(annotation.id)\n }\n\n removeMarker(id: string): void {\n const entry = this.markers.get(id)\n if (entry) {\n entry.markerEl.remove()\n this.markers.delete(id)\n }\n }\n\n updateStatus(id: string, status: 'pending' | 'resolved'): void {\n const entry = this.markers.get(id)\n if (entry) {\n entry.annotation.status = status\n entry.markerEl.setAttribute('data-status', status)\n }\n }\n\n clear(): void {\n for (const entry of this.markers.values()) {\n entry.markerEl.remove()\n }\n this.markers.clear()\n this.counter = 0\n }\n\n destroy(): void {\n if (this.rafId !== null) {\n cancelAnimationFrame(this.rafId)\n this.rafId = null\n }\n this.clear()\n }\n\n private updatePosition(id: string): void {\n const entry = this.markers.get(id)\n if (!entry) return\n try {\n const rect = entry.target.getBoundingClientRect()\n entry.markerEl.style.top = `${window.scrollY + rect.top - 12}px`\n entry.markerEl.style.left = `${window.scrollX + rect.right - 12}px`\n } catch {\n // element may have been removed\n }\n }\n\n private startPositionLoop(): void {\n const update = () => {\n for (const id of this.markers.keys()) {\n this.updatePosition(id)\n }\n this.rafId = requestAnimationFrame(update)\n }\n this.rafId = requestAnimationFrame(update)\n }\n}\n","import type { Annotation } from '../core/types'\n\nexport class DetachedPanel {\n private panelEl: HTMLElement | null = null\n\n constructor(\n private container: HTMLElement,\n private onDelete?: (id: string) => void,\n ) {}\n\n update(annotations: Annotation[]): void {\n this.remove()\n if (annotations.length === 0) return\n\n const panel = document.createElement('div')\n panel.className = 'remarq-detached-panel'\n\n const header = document.createElement('div')\n header.className = 'remarq-detached-header'\n header.textContent = `Detached (${annotations.length})`\n panel.appendChild(header)\n\n for (const ann of annotations) {\n const item = document.createElement('div')\n item.className = 'remarq-detached-item'\n\n const info = document.createElement('div')\n info.className = 'remarq-detached-info'\n\n const comment = document.createElement('div')\n comment.className = 'remarq-detached-comment'\n comment.textContent = ann.comment\n\n const elDesc = document.createElement('div')\n elDesc.className = 'remarq-detached-element'\n const fp = ann.fingerprint\n let desc = `<${fp.tagName}>`\n if (fp.textContent) desc += ` \"${fp.textContent}\"`\n if (fp.dataAnnotate) desc += ` [${fp.dataAnnotate}]`\n elDesc.textContent = desc\n\n info.appendChild(comment)\n info.appendChild(elDesc)\n\n const deleteBtn = document.createElement('button')\n deleteBtn.className = 'remarq-detached-delete'\n deleteBtn.textContent = '\\u00d7'\n deleteBtn.addEventListener('click', () => {\n this.onDelete?.(ann.id)\n })\n\n item.appendChild(info)\n item.appendChild(deleteBtn)\n panel.appendChild(item)\n }\n\n this.container.appendChild(panel)\n this.panelEl = panel\n }\n\n destroy(): void {\n this.remove()\n }\n\n private remove(): void {\n if (this.panelEl) {\n this.panelEl.remove()\n this.panelEl = null\n }\n }\n}\n","type RouteChangeListener = (route: string) => void\n\nexport class RouteObserver {\n private listeners: Set<RouteChangeListener> = new Set()\n private originalPushState: typeof history.pushState\n private originalReplaceState: typeof history.replaceState\n private boundOnPopState: () => void\n private boundOnHashChange: () => void\n\n constructor() {\n this.originalPushState = history.pushState.bind(history)\n this.originalReplaceState = history.replaceState.bind(history)\n this.boundOnPopState = () => this.notify()\n this.boundOnHashChange = () => this.notify()\n\n this.patchHistory()\n\n window.addEventListener('popstate', this.boundOnPopState)\n window.addEventListener('hashchange', this.boundOnHashChange)\n }\n\n currentRoute(): string {\n return location.pathname + location.hash\n }\n\n onChange(listener: RouteChangeListener): () => void {\n this.listeners.add(listener)\n return () => {\n this.listeners.delete(listener)\n }\n }\n\n destroy(): void {\n window.removeEventListener('popstate', this.boundOnPopState)\n window.removeEventListener('hashchange', this.boundOnHashChange)\n history.pushState = this.originalPushState\n history.replaceState = this.originalReplaceState\n this.listeners.clear()\n }\n\n private notify(): void {\n const route = this.currentRoute()\n for (const listener of this.listeners) {\n listener(route)\n }\n }\n\n private patchHistory(): void {\n const self = this\n\n history.pushState = function (...args: Parameters<typeof history.pushState>) {\n self.originalPushState.apply(this, args)\n self.notify()\n }\n\n history.replaceState = function (...args: Parameters<typeof history.replaceState>) {\n self.originalReplaceState.apply(this, args)\n self.notify()\n }\n }\n}\n","import type { Annotation, ImportResult, WebRemarqOptions } from './core/types'\nimport { AnnotationStorage } from './core/storage'\nimport { createFingerprint } from './core/fingerprint'\nimport { matchElement } from './core/matcher'\nimport { injectStyles, removeStyles } from './ui/styles'\nimport { ThemeManager } from './ui/theme'\nimport { Toolbar } from './ui/toolbar'\nimport { Overlay } from './ui/overlay'\nimport { Popup } from './ui/popup'\nimport { MarkerManager } from './ui/markers'\nimport { DetachedPanel } from './ui/detached-panel'\nimport { RouteObserver } from './spa'\n\nlet initialized = false\nlet options: WebRemarqOptions = {}\nlet storage: AnnotationStorage\nlet themeManager: ThemeManager\nlet toolbar: Toolbar\nlet overlay: Overlay\nlet popup: Popup\nlet markers: MarkerManager\nlet detachedPanel: DetachedPanel\nlet routeObserver: RouteObserver\nlet inspecting = false\nlet mutationObserver: MutationObserver | null = null\nlet unsubRoute: (() => void) | null = null\nlet refreshScheduled = false\n\n// WeakRef cache: annotation id → element (survives GC of element)\nconst elementCache = new Map<string, WeakRef<HTMLElement>>()\n\nfunction currentRoute(): string {\n return location.pathname + location.hash\n}\n\nfunction generateId(): string {\n return `ann-${Date.now()}-${Math.random().toString(36).slice(2, 8)}`\n}\n\nfunction cacheElement(annotationId: string, el: HTMLElement): void {\n elementCache.set(annotationId, new WeakRef(el))\n}\n\nfunction getCachedElement(annotationId: string): HTMLElement | null {\n const ref = elementCache.get(annotationId)\n if (!ref) return null\n const el = ref.deref()\n if (!el || !el.isConnected) {\n elementCache.delete(annotationId)\n return null\n }\n return el\n}\n\nfunction resolveElement(ann: Annotation): HTMLElement | null {\n // 1. Check cache first\n const cached = getCachedElement(ann.id)\n if (cached) return cached\n\n // 2. Fall back to fingerprint matching\n const el = matchElement(ann.fingerprint, { dataAttribute: options.dataAttribute })\n if (el) {\n cacheElement(ann.id, el)\n console.debug(`[web-remarq] Matched \"${ann.comment}\" via fingerprint on <${el.tagName.toLowerCase()}>`)\n } else {\n console.debug(`[web-remarq] Could not match \"${ann.comment}\"`, ann.fingerprint)\n }\n return el\n}\n\nfunction refreshMarkers(): void {\n markers.clear()\n const detached: Annotation[] = []\n const route = currentRoute()\n const anns = storage.getByRoute(route)\n\n for (const ann of anns) {\n const el = resolveElement(ann)\n if (el) {\n markers.addMarker(ann, el)\n } else {\n detached.push(ann)\n }\n }\n\n detachedPanel.update(detached)\n\n const pendingCount = anns.filter((a) => a.status === 'pending').length\n toolbar.setBadgeCount(pendingCount)\n}\n\n// Debounced refresh — MutationObserver can fire rapidly\nfunction scheduleRefresh(): void {\n if (refreshScheduled) return\n refreshScheduled = true\n requestAnimationFrame(() => {\n refreshScheduled = false\n refreshMarkers()\n })\n}\n\nfunction handleInspectClick(e: MouseEvent): void {\n if (!inspecting) return\n\n const target = e.target as HTMLElement\n if (!target || target.closest('[data-remarq-theme]')) return\n\n e.preventDefault()\n e.stopPropagation()\n\n overlay.hide()\n setInspecting(false)\n\n const rect = target.getBoundingClientRect()\n popup.show(\n {\n tag: target.tagName.toLowerCase(),\n text: target.textContent?.trim().slice(0, 30) ?? '',\n },\n {\n top: rect.bottom + 8,\n left: rect.left,\n },\n (comment) => {\n const fp = createFingerprint(target, {\n classFilter: options.classFilter,\n dataAttribute: options.dataAttribute,\n })\n const ann: Annotation = {\n id: generateId(),\n comment,\n fingerprint: fp,\n route: currentRoute(),\n timestamp: Date.now(),\n status: 'pending',\n }\n // Cache the element immediately — no need to re-match\n cacheElement(ann.id, target)\n storage.add(ann)\n refreshMarkers()\n },\n () => {\n // cancel\n },\n )\n}\n\nfunction handleInspectHover(e: MouseEvent): void {\n if (!inspecting) return\n const target = e.target as HTMLElement\n if (!target || target.closest('[data-remarq-theme]')) return\n overlay.show(target)\n overlay.updateTooltipPosition(e.clientX, e.clientY)\n}\n\nfunction handleInspectKeydown(e: KeyboardEvent): void {\n if (e.key === 'Escape' && inspecting) {\n setInspecting(false)\n overlay.hide()\n }\n}\n\nfunction setInspecting(value: boolean): void {\n inspecting = value\n toolbar.setInspectActive(value)\n if (!value) overlay.hide()\n}\n\nfunction handleMarkerClick(annotationId: string): void {\n const ann = storage.getAll().find((a) => a.id === annotationId)\n if (!ann) return\n\n const el = resolveElement(ann)\n if (!el) return\n\n const rect = el.getBoundingClientRect()\n\n popup.showDetail(\n {\n tag: ann.fingerprint.tagName,\n text: ann.fingerprint.textContent ?? '',\n comment: ann.comment,\n status: ann.status,\n },\n { top: rect.bottom + 8, left: rect.left },\n {\n onResolve: () => {\n storage.update(ann.id, { status: 'resolved' })\n refreshMarkers()\n },\n onDelete: () => {\n elementCache.delete(ann.id)\n storage.remove(ann.id)\n refreshMarkers()\n },\n onClose: () => {},\n },\n )\n}\n\nfunction exportMarkdown(): void {\n const route = currentRoute()\n const anns = storage.getByRoute(route)\n if (!anns.length) return\n\n const lines = [`## Annotations — ${route} (${anns.length})`, '']\n anns.forEach((ann, i) => {\n const fp = ann.fingerprint\n let desc = `<${fp.tagName}>`\n if (fp.textContent) desc += ` \"${fp.textContent}\"`\n if (fp.parentAnchor) desc += ` (${fp.parentAnchor})`\n if (fp.dataAnnotate) desc += fp.parentAnchor ? ` > ${fp.dataAnnotate}` : ` (${fp.dataAnnotate})`\n lines.push(`${i + 1}. [${ann.status}] ${desc}: \"${ann.comment}\"`)\n })\n\n const text = lines.join('\\n')\n try {\n navigator.clipboard.writeText(text)\n } catch {\n console.warn('[web-remarq] Clipboard write failed')\n }\n}\n\nfunction exportJSON(): void {\n const data = storage.exportJSON()\n const json = JSON.stringify(data, null, 2)\n const blob = new Blob([json], { type: 'application/json' })\n const url = URL.createObjectURL(blob)\n const a = document.createElement('a')\n a.href = url\n a.download = `remarq-annotations-${Date.now()}.json`\n a.click()\n URL.revokeObjectURL(url)\n}\n\nfunction setupMutationObserver(): void {\n mutationObserver = new MutationObserver((mutations) => {\n for (const m of mutations) {\n if (m.target instanceof HTMLElement && m.target.closest('[data-remarq-theme]')) return\n }\n scheduleRefresh()\n })\n\n mutationObserver.observe(document.body, {\n childList: true,\n subtree: true,\n attributes: true,\n attributeFilter: ['id', 'class', 'data-annotate', 'data-testid', 'data-test', 'data-cy'],\n })\n}\n\nexport const WebRemarq = {\n init(opts?: WebRemarqOptions): void {\n if (initialized) return\n options = opts ?? {}\n\n try {\n injectStyles()\n storage = new AnnotationStorage()\n themeManager = new ThemeManager(document.body, options.theme)\n overlay = new Overlay(themeManager.container)\n popup = new Popup(themeManager.container)\n markers = new MarkerManager(themeManager.container, handleMarkerClick)\n detachedPanel = new DetachedPanel(themeManager.container, (id) => {\n elementCache.delete(id)\n storage.remove(id)\n refreshMarkers()\n })\n\n toolbar = new Toolbar(themeManager.container, {\n onInspect: () => setInspecting(!inspecting),\n onExportMd: exportMarkdown,\n onExportJson: exportJSON,\n onImport: () => {\n const file = toolbar.getFileInput().files?.[0]\n if (file) {\n WebRemarq.import(file)\n }\n },\n onClear: () => {\n elementCache.clear()\n storage.clearAll()\n refreshMarkers()\n },\n onThemeToggle: () => themeManager.toggle(),\n })\n\n if (storage.isMemoryOnly) {\n toolbar.setMemoryWarning(true)\n }\n\n routeObserver = new RouteObserver()\n unsubRoute = routeObserver.onChange(() => refreshMarkers())\n\n document.addEventListener('click', handleInspectClick, true)\n document.addEventListener('mousemove', handleInspectHover)\n document.addEventListener('keydown', handleInspectKeydown)\n\n setupMutationObserver()\n\n console.debug(`[web-remarq] Initialized on route: ${currentRoute()}`)\n refreshMarkers()\n initialized = true\n } catch (err) {\n console.error('[web-remarq] Init failed:', err)\n }\n },\n\n destroy(): void {\n if (!initialized) return\n try {\n document.removeEventListener('click', handleInspectClick, true)\n document.removeEventListener('mousemove', handleInspectHover)\n document.removeEventListener('keydown', handleInspectKeydown)\n mutationObserver?.disconnect()\n mutationObserver = null\n unsubRoute?.()\n routeObserver?.destroy()\n markers?.destroy()\n detachedPanel?.destroy()\n popup?.destroy()\n overlay?.destroy()\n toolbar?.destroy()\n themeManager?.destroy()\n removeStyles()\n elementCache.clear()\n inspecting = false\n initialized = false\n } catch (err) {\n console.error('[web-remarq] Destroy failed:', err)\n }\n },\n\n setTheme(theme: 'light' | 'dark'): void {\n themeManager?.setTheme(theme)\n },\n\n export(format: 'md' | 'json'): void {\n if (format === 'md') exportMarkdown()\n else exportJSON()\n },\n\n async import(file: File): Promise<ImportResult> {\n const text = await file.text()\n const data = JSON.parse(text)\n storage.importJSON(data)\n refreshMarkers()\n\n const allAnns = storage.getAll()\n let matched = 0\n let detached = 0\n for (const ann of allAnns) {\n if (resolveElement(ann)) {\n matched++\n } else {\n detached++\n }\n }\n return { total: allAnns.length, matched, detached }\n },\n\n getAnnotations(route?: string): Annotation[] {\n if (!storage) return []\n return route ? storage.getByRoute(route) : storage.getAll()\n },\n\n clearAll(): void {\n elementCache.clear()\n storage?.clearAll()\n if (initialized) refreshMarkers()\n },\n}\n"],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AAEA,IAAM,cAAc;AAEb,IAAM,oBAAN,MAAwB;AAAA,EAK7B,cAAc;AAJd,SAAQ,cAA4B,CAAC;AACrC,SAAQ,cAAuC,CAAC;AAChD,wBAAe;AAGb,SAAK,KAAK;AAAA,EACZ;AAAA,EAEA,SAAuB;AACrB,WAAO,CAAC,GAAG,KAAK,WAAW;AAAA,EAC7B;AAAA,EAEA,WAAW,OAA6B;AACtC,WAAO,KAAK,YAAY,OAAO,CAAC,MAAM,EAAE,UAAU,KAAK;AAAA,EACzD;AAAA,EAEA,IAAI,YAA8B;AAChC,SAAK,YAAY,KAAK,UAAU;AAChC,SAAK,KAAK;AAAA,EACZ;AAAA,EAEA,OAAO,IAAkB;AACvB,SAAK,cAAc,KAAK,YAAY,OAAO,CAAC,MAAM,EAAE,OAAO,EAAE;AAC7D,SAAK,KAAK;AAAA,EACZ;AAAA,EAEA,OAAO,IAAY,SAAoC;AACrD,UAAM,MAAM,KAAK,YAAY,UAAU,CAAC,MAAM,EAAE,OAAO,EAAE;AACzD,QAAI,QAAQ,IAAI;AACd,WAAK,YAAY,GAAG,IAAI,kCAAK,KAAK,YAAY,GAAG,IAAM;AACvD,WAAK,KAAK;AAAA,IACZ;AAAA,EACF;AAAA,EAEA,WAAiB;AACf,SAAK,cAAc,CAAC;AACpB,SAAK,KAAK;AAAA,EACZ;AAAA,EAEA,aAA8B;AAC5B,WAAO;AAAA,MACL,SAAS;AAAA,MACT,aAAa,CAAC,GAAG,KAAK,WAAW;AAAA,IACnC;AAAA,EACF;AAAA,EAEA,WAAW,MAA6B;AACtC,SAAK,cAAc,CAAC,GAAG,KAAK,WAAW;AACvC,SAAK,KAAK;AAAA,EACZ;AAAA,EAEQ,OAAa;AACnB,QAAI;AACF,YAAM,MAAM,aAAa,QAAQ,WAAW;AAC5C,UAAI,KAAK;AACP,cAAM,SAAS,KAAK,MAAM,GAAG;AAC7B,cAA0C,aAAlC,WAAS,YA7DzB,IA6DkD,IAAT,iBAAS,IAAT,CAAzB,WAAS;AACjB,aAAK,cAAc,oCAAe,CAAC;AACnC,aAAK,cAAc;AAAA,MACrB;AAAA,IACF,SAAQ;AACN,WAAK,eAAe;AAAA,IACtB;AAAA,EACF;AAAA,EAEQ,OAAa;AACnB,QAAI,KAAK,aAAc;AACvB,QAAI;AACF,YAAM,OAAO;AAAA,QACX,SAAS;AAAA,SACN,KAAK,cAFG;AAAA,QAGX,aAAa,KAAK;AAAA,MACpB;AACA,mBAAa,QAAQ,aAAa,KAAK,UAAU,IAAI,CAAC;AAAA,IACxD,SAAQ;AACN,WAAK,eAAe;AAAA,IACtB;AAAA,EACF;AACF;;;ACnFA,IAAM,iBAAiB;AACvB,IAAM,uBAAuB;AAC7B,IAAM,aAAa;AACnB,IAAM,eAAe;AAEd,SAAS,cAAc,WAA4B;AACxD,MAAI,qBAAqB,KAAK,SAAS,EAAG,QAAO;AACjD,MAAI,WAAW,KAAK,SAAS,EAAG,QAAO;AACvC,MAAI,eAAe,KAAK,SAAS,EAAG,QAAO;AAC3C,MAAI,aAAa,KAAK,SAAS,EAAG,QAAO;AACzC,SAAO;AACT;AAEO,SAAS,UAAU,WAA2B;AACnD,QAAM,QAAQ,UAAU,MAAM,cAAc;AAC5C,MAAI,OAAO;AACT,UAAM,SAAS,UAAU,MAAM,GAAG,UAAU,YAAY,IAAI,CAAC;AAC7D,WAAO;AAAA,EACT;AACA,SAAO;AACT;AAEO,SAAS,cACd,SACA,aACU;AACV,QAAM,SAAmB,CAAC;AAE1B,aAAW,OAAO,SAAS;AACzB,QAAI,qBAAqB,KAAK,GAAG,EAAG;AACpC,QAAI,WAAW,KAAK,GAAG,EAAG;AAC1B,QAAI,aAAa,KAAK,GAAG,EAAG;AAE5B,QAAI,SAAS,UAAU,GAAG;AAE1B,QAAI,eAAe,CAAC,YAAY,MAAM,EAAG;AAEzC,WAAO,KAAK,MAAM;AAAA,EACpB;AAEA,SAAO;AACT;;;ACtCA,IAAM,kBAAkB;AAEjB,SAAS,kBACd,IACAA,UACoB;AARtB;AASE,QAAM,YAAW,KAAAA,YAAA,gBAAAA,SAAS,kBAAT,YAA0B;AAE3C,SAAO;AAAA,IACL,eAAc,QAAG,aAAa,QAAQ,MAAxB,YAA6B;AAAA,IAC3C,aAAY,oBAAG,aAAa,aAAa,MAA7B,YACP,GAAG,aAAa,WAAW,MADpB,YAEP,GAAG,aAAa,SAAS,MAFlB,YAGP;AAAA,IACL,IAAI,YAAY,EAAE;AAAA,IAClB,SAAS,GAAG,QAAQ,YAAY;AAAA,IAChC,aAAa,eAAe,EAAE;AAAA,IAC9B,OAAM,QAAG,aAAa,MAAM,MAAtB,YAA2B;AAAA,IACjC,YAAW,QAAG,aAAa,YAAY,MAA5B,YAAiC;AAAA,IAC5C,eAAe;AAAA,MACb,MAAM,KAAK,GAAG,SAAS;AAAA,MACvBA,YAAA,gBAAAA,SAAS;AAAA,IACX;AAAA,IACA,SAAS,aAAa,EAAE;AAAA,IACxB,cAAc,gBAAgB,EAAE;AAAA,IAChC,cAAc,iBAAiB,IAAI,QAAQ;AAAA,EAC7C;AACF;AAEA,SAAS,YAAY,IAAgC;AACnD,QAAM,KAAK,GAAG;AACd,MAAI,CAAC,GAAI,QAAO;AAChB,MAAI,cAAc,EAAE,EAAG,QAAO;AAC9B,SAAO;AACT;AAEA,SAAS,eAAe,IAAgC;AAvCxD;AAwCE,QAAM,QAAO,cAAG,gBAAH,mBAAgB,WAAhB,YAA0B;AACvC,MAAI,CAAC,KAAM,QAAO;AAClB,SAAO,KAAK,SAAS,kBAAkB,KAAK,MAAM,GAAG,eAAe,IAAI;AAC1E;AAEA,SAAS,aAAa,IAAyB;AAC7C,QAAM,QAAkB,CAAC;AACzB,MAAI,UAA8B;AAElC,SAAO,WAAW,YAAY,SAAS,QAAQ,MAAM,SAAS,GAAG;AAC/D,UAAM,QAAQ,QAAQ,QAAQ,YAAY,CAAC;AAC3C,cAAU,QAAQ;AAAA,EACpB;AAEA,SAAO,MAAM,KAAK,KAAK;AACzB;AAEA,SAAS,gBAAgB,IAAyB;AAChD,QAAM,SAAS,GAAG;AAClB,MAAI,CAAC,OAAQ,QAAO;AACpB,QAAM,WAAW,MAAM,KAAK,OAAO,QAAQ;AAC3C,SAAO,SAAS,QAAQ,EAAE;AAC5B;AAEA,SAAS,iBAAiB,IAAiB,UAAiC;AAC1E,MAAI,UAAU,GAAG;AACjB,SAAO,WAAW,YAAY,SAAS,MAAM;AAC3C,UAAM,QAAQ,QAAQ,aAAa,QAAQ;AAC3C,QAAI,MAAO,QAAO;AAClB,cAAU,QAAQ;AAAA,EACpB;AACA,SAAO;AACT;;;ACtEA,IAAM,kBAAkB;AAEjB,SAAS,sBAAsB,GAAW,GAAmB;AAClE,MAAI,MAAM,EAAG,QAAO;AACpB,MAAI,CAAC,EAAE,UAAU,CAAC,EAAE,OAAQ,QAAO;AAEnC,QAAM,SAAqB,CAAC;AAC5B,WAAS,IAAI,GAAG,KAAK,EAAE,QAAQ,KAAK;AAClC,WAAO,CAAC,IAAI,CAAC,CAAC;AAAA,EAChB;AACA,WAAS,IAAI,GAAG,KAAK,EAAE,QAAQ,KAAK;AAClC,WAAO,CAAC,EAAE,CAAC,IAAI;AAAA,EACjB;AAEA,WAAS,IAAI,GAAG,KAAK,EAAE,QAAQ,KAAK;AAClC,aAAS,IAAI,GAAG,KAAK,EAAE,QAAQ,KAAK;AAClC,YAAM,OAAO,EAAE,IAAI,CAAC,MAAM,EAAE,IAAI,CAAC,IAAI,IAAI;AACzC,aAAO,CAAC,EAAE,CAAC,IAAI,KAAK;AAAA,QAClB,OAAO,IAAI,CAAC,EAAE,CAAC,IAAI;AAAA,QACnB,OAAO,CAAC,EAAE,IAAI,CAAC,IAAI;AAAA,QACnB,OAAO,IAAI,CAAC,EAAE,IAAI,CAAC,IAAI;AAAA,MACzB;AAAA,IACF;AAAA,EACF;AAEA,QAAM,WAAW,OAAO,EAAE,MAAM,EAAE,EAAE,MAAM;AAC1C,SAAO,IAAI,WAAW,KAAK,IAAI,EAAE,QAAQ,EAAE,MAAM;AACnD;AAEA,SAAS,eAAe,GAAkB,GAA0B;AAClE,MAAI,CAAC,KAAK,CAAC,EAAG,QAAO;AACrB,QAAM,KAAK,EAAE,KAAK,EAAE,YAAY;AAChC,QAAM,KAAK,EAAE,KAAK,EAAE,YAAY;AAChC,MAAI,OAAO,GAAI,QAAO;AACtB,MAAI,GAAG,SAAS,EAAE,KAAK,GAAG,SAAS,EAAE,EAAG,QAAO;AAC/C,SAAO,sBAAsB,IAAI,EAAE;AACrC;AAEA,SAAS,kBAAkB,GAAa,GAAqB;AAC3D,MAAI,CAAC,EAAE,UAAU,CAAC,EAAE,OAAQ,QAAO;AACnC,QAAM,OAAO,IAAI,IAAI,CAAC;AACtB,QAAM,OAAO,IAAI,IAAI,CAAC;AACtB,MAAI,eAAe;AACnB,aAAW,QAAQ,MAAM;AACvB,QAAI,KAAK,IAAI,IAAI,EAAG;AAAA,EACtB;AACA,QAAM,SAAQ,oBAAI,IAAI,CAAC,GAAG,GAAG,GAAG,CAAC,CAAC,GAAE;AACpC,SAAO,UAAU,IAAI,IAAI,eAAe;AAC1C;AAEA,SAAS,eAAe,IAAiB,IAAwB,UAA0B;AApD3F;AAqDE,MAAI,QAAQ;AAGZ,QAAM,aAAa,GAAG,aAAa,QAAQ;AAC3C,MAAI,GAAG,gBAAgB,eAAe,GAAG,cAAc;AACrD,aAAS;AAAA,EACX;AAGA,QAAM,UAAS,cAAG,gBAAH,mBAAgB,OAAO,MAAM,GAAG,QAAhC,YAAuC;AACtD,QAAM,UAAU,eAAe,GAAG,aAAa,MAAM;AACrD,MAAI,UAAU,KAAK;AACjB,aAAS,UAAU;AAAA,EACrB;AAGA,MAAI,GAAG,QAAQ,GAAG,aAAa,MAAM,MAAM,GAAG,QAC5C,GAAG,aAAa,GAAG,aAAa,YAAY,MAAM,GAAG,WAAW;AAChE,aAAS;AAAA,EACX;AAGA,MAAI,GAAG,cAAc;AACnB,QAAIC,UAAS,GAAG;AAChB,WAAOA,WAAUA,YAAW,SAAS,MAAM;AACzC,UAAIA,QAAO,aAAa,QAAQ,MAAM,GAAG,cAAc;AACrD,iBAAS;AACT;AAAA,MACF;AACA,MAAAA,UAASA,QAAO;AAAA,IAClB;AAAA,EACF;AAGA,MAAI,GAAG,cAAc,SAAS,GAAG;AAC/B,UAAM,YAAY,MAAM,KAAK,GAAG,SAAS;AACzC,UAAM,UAAU,kBAAkB,GAAG,eAAe,SAAS;AAC7D,aAAS,UAAU;AAAA,EACrB;AAGA,MAAI,GAAG,SAAS;AACd,UAAM,SAASC,cAAa,EAAE;AAC9B,UAAM,UAAU,sBAAsB,GAAG,SAAS,MAAM;AACxD,aAAS,UAAU;AAAA,EACrB;AAGA,QAAM,SAAS,GAAG;AAClB,MAAI,QAAQ;AACV,UAAM,MAAM,MAAM,KAAK,OAAO,QAAQ,EAAE,QAAQ,EAAE;AAClD,QAAI,QAAQ,GAAG,cAAc;AAC3B,eAAS;AAAA,IACX;AAAA,EACF;AAEA,SAAO;AACT;AAEA,SAASA,cAAa,IAAyB;AAC7C,QAAM,QAAkB,CAAC;AACzB,MAAI,UAA8B;AAClC,SAAO,WAAW,YAAY,SAAS,QAAQ,MAAM,SAAS,GAAG;AAC/D,UAAM,QAAQ,QAAQ,QAAQ,YAAY,CAAC;AAC3C,cAAU,QAAQ;AAAA,EACpB;AACA,SAAO,MAAM,KAAK,KAAK;AACzB;AAEO,SAAS,aACd,IACAC,UACoB;AA7HtB;AA8HE,QAAM,YAAW,KAAAA,YAAA,gBAAAA,SAAS,kBAAT,YAA0B;AAG3C,MAAI,GAAG,cAAc;AACnB,UAAM,KAAK,SAAS,cAA2B,IAAI,QAAQ,KAAK,GAAG,YAAY,IAAI;AACnF,QAAI,GAAI,QAAO;AAAA,EACjB;AAGA,MAAI,GAAG,YAAY;AACjB,UAAM,KAAK,SAAS;AAAA,MAClB,iBAAiB,GAAG,UAAU,mBAAmB,GAAG,UAAU,iBAAiB,GAAG,UAAU;AAAA,IAC9F;AACA,QAAI,GAAI,QAAO;AAAA,EACjB;AAGA,MAAI,GAAG,IAAI;AACT,UAAM,KAAK,SAAS,eAAe,GAAG,EAAE;AACxC,QAAI,GAAI,QAAO;AAAA,EACjB;AAGA,QAAM,aAAa,SAAS,iBAA8B,GAAG,OAAO;AACpE,MAAI,SAA6B;AACjC,MAAI,YAAY;AAEhB,aAAW,aAAa,YAAY;AAClC,UAAM,QAAQ,eAAe,WAAW,IAAI,QAAQ;AACpD,QAAI,QAAQ,WAAW;AACrB,kBAAY;AACZ,eAAS;AAAA,IACX;AAAA,EACF;AAEA,SAAO,aAAa,kBAAkB,SAAS;AACjD;;;AClKA,IAAM,YAAY;AAElB,IAAM,MAAM;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AA0RL,SAAS,eAAqB;AACnC,MAAI,SAAS,cAAc,SAAS,SAAS,GAAG,EAAG;AAEnD,MAAI;AACF,UAAM,QAAQ,SAAS,cAAc,OAAO;AAC5C,UAAM,aAAa,WAAW,EAAE;AAChC,UAAM,cAAc;AACpB,aAAS,KAAK,YAAY,KAAK;AAAA,EACjC,SAAQ;AAEN,QAAI;AACF,YAAM,OAAO,IAAI,KAAK,CAAC,GAAG,GAAG,EAAE,MAAM,WAAW,CAAC;AACjD,YAAM,OAAO,SAAS,cAAc,MAAM;AAC1C,WAAK,MAAM;AACX,WAAK,OAAO,IAAI,gBAAgB,IAAI;AACpC,WAAK,aAAa,WAAW,EAAE;AAC/B,eAAS,KAAK,YAAY,IAAI;AAAA,IAChC,SAAQC,IAAA;AACN,cAAQ,KAAK,sCAAsC;AAAA,IACrD;AAAA,EACF;AACF;AAEO,SAAS,eAAqB;AACnC,QAAM,KAAK,SAAS,cAAc,IAAI,SAAS,GAAG;AAClD,2BAAI;AACN;;;ACtTA,IAAM,YAAY;AAIX,IAAM,eAAN,MAAmB;AAAA,EAIxB,YAAY,QAAqB,cAAsB;AARzD;AASI,UAAM,YAAY,KAAK,UAAU;AACjC,SAAK,SAAQ,2CAAgB,cAAhB,YAA6B;AAE1C,SAAK,YAAY,SAAS,cAAc,KAAK;AAC7C,SAAK,UAAU,aAAa,qBAAqB,KAAK,KAAK;AAC3D,WAAO,YAAY,KAAK,SAAS;AAEjC,SAAK,QAAQ;AAAA,EACf;AAAA,EAEA,WAAkB;AAChB,WAAO,KAAK;AAAA,EACd;AAAA,EAEA,SAAS,OAAoB;AAC3B,SAAK,QAAQ;AACb,SAAK,UAAU,aAAa,qBAAqB,KAAK;AACtD,SAAK,QAAQ;AAAA,EACf;AAAA,EAEA,SAAe;AACb,SAAK,SAAS,KAAK,UAAU,UAAU,SAAS,OAAO;AAAA,EACzD;AAAA,EAEA,UAAgB;AACd,SAAK,UAAU,OAAO;AAAA,EACxB;AAAA,EAEQ,UAAgB;AACtB,QAAI;AACF,mBAAa,QAAQ,WAAW,KAAK,KAAK;AAAA,IAC5C,SAAQ;AAAA,IAER;AAAA,EACF;AAAA,EAEQ,YAA0B;AAChC,QAAI;AACF,YAAM,QAAQ,aAAa,QAAQ,SAAS;AAC5C,UAAI,UAAU,WAAW,UAAU,OAAQ,QAAO;AAAA,IACpD,SAAQ;AAAA,IAER;AACA,WAAO;AAAA,EACT;AACF;;;AC7CA,IAAM,QAAQ;AAAA,EACZ,SAAS;AAAA,EACT,QAAQ;AAAA,EACR,QAAQ;AAAA,EACR,OAAO;AAAA,EACP,OAAO;AAAA,EACP,UAAU;AACZ;AAEO,IAAM,UAAN,MAAc;AAAA,EASnB,YACU,WACA,WACR;AAFQ;AACA;AAPV,SAAQ,aAAiC;AAEzC,SAAQ,YAAY;AACpB,SAAQ,UAAyB,CAAC;AAMhC,SAAK,YAAY,SAAS,cAAc,KAAK;AAC7C,SAAK,UAAU,YAAY;AAE3B,SAAK,aAAa,KAAK,aAAa,WAAW,MAAM,SAAS,MAAM,UAAU,UAAU,CAAC;AACzF,SAAK,UAAU,SAAS,cAAc,MAAM;AAC5C,SAAK,QAAQ,YAAY;AACzB,SAAK,QAAQ,MAAM,UAAU;AAC7B,SAAK,WAAW,YAAY,KAAK,OAAO;AAExC,UAAM,YAAY,KAAK,aAAa,UAAU,MAAM,QAAQ,CAAC,MAAM,KAAK,iBAAiB,CAAC,CAAC;AAE3F,SAAK,YAAY,SAAS,cAAc,OAAO;AAC/C,SAAK,UAAU,OAAO;AACtB,SAAK,UAAU,SAAS;AACxB,SAAK,UAAU,MAAM,UAAU;AAC/B,SAAK,UAAU,iBAAiB,UAAU,MAAM;AAC9C,gBAAU,SAAS;AACnB,WAAK,UAAU,QAAQ;AAAA,IACzB,CAAC;AACD,UAAM,YAAY,KAAK,aAAa,UAAU,MAAM,QAAQ,MAAM,KAAK,UAAU,MAAM,CAAC;AAExF,UAAM,WAAW,KAAK,aAAa,SAAS,MAAM,OAAO,MAAM,UAAU,QAAQ,CAAC;AAClF,UAAM,WAAW,KAAK,aAAa,SAAS,MAAM,OAAO,MAAM,UAAU,cAAc,CAAC;AACxF,UAAM,cAAc,KAAK,aAAa,YAAY,MAAM,UAAU,MAAM,KAAK,eAAe,CAAC;AAE7F,SAAK,UAAU,CAAC,KAAK,YAAY,WAAW,WAAW,UAAU,QAAQ;AAEzE,SAAK,UAAU,YAAY,KAAK,UAAU;AAC1C,SAAK,UAAU,YAAY,SAAS;AACpC,SAAK,UAAU,YAAY,SAAS;AACpC,SAAK,UAAU,YAAY,QAAQ;AACnC,SAAK,UAAU,YAAY,QAAQ;AACnC,SAAK,UAAU,YAAY,WAAW;AACtC,SAAK,UAAU,YAAY,KAAK,SAAS;AAEzC,cAAU,YAAY,KAAK,SAAS;AAAA,EACtC;AAAA,EAEA,iBAAiB,QAAuB;AACtC,SAAK,WAAW,UAAU,OAAO,iBAAiB,MAAM;AAAA,EAC1D;AAAA,EAEA,cAAc,OAAqB;AACjC,SAAK,QAAQ,cAAc,OAAO,KAAK;AACvC,SAAK,QAAQ,MAAM,UAAU,QAAQ,IAAI,SAAS;AAAA,EACpD;AAAA,EAEA,eAAiC;AAC/B,WAAO,KAAK;AAAA,EACd;AAAA,EAEA,iBAAiB,MAAqB;AACpC,SAAK,UAAU,QAAQ,OAAO,sEAAiE;AAAA,EACjG;AAAA,EAEA,UAAgB;AACd,SAAK,gBAAgB;AACrB,SAAK,UAAU,OAAO;AAAA,EACxB;AAAA,EAEQ,aAAa,QAAgB,MAAc,SAA0C;AAC3F,UAAM,MAAM,SAAS,cAAc,QAAQ;AAC3C,QAAI,YAAY;AAChB,QAAI,aAAa,sBAAsB,MAAM;AAC7C,QAAI,YAAY;AAChB,QAAI,iBAAiB,SAAS,OAAO;AACrC,WAAO;AAAA,EACT;AAAA,EAEQ,iBAAuB;AAC7B,SAAK,YAAY,CAAC,KAAK;AACvB,SAAK,UAAU,UAAU,OAAO,oBAAoB,KAAK,SAAS;AAClE,eAAW,OAAO,KAAK,SAAS;AAC9B,UAAI,MAAM,UAAU,KAAK,YAAY,SAAS;AAAA,IAChD;AAAA,EACF;AAAA,EAEQ,iBAAiB,GAAgB;AACvC,QAAI,KAAK,YAAY;AACnB,WAAK,gBAAgB;AACrB;AAAA,IACF;AAEA,SAAK,aAAa,SAAS,cAAc,KAAK;AAC9C,SAAK,WAAW,YAAY;AAE5B,UAAM,QAAQ,SAAS,cAAc,QAAQ;AAC7C,UAAM,cAAc;AACpB,UAAM,iBAAiB,SAAS,MAAM;AACpC,WAAK,UAAU,WAAW;AAC1B,WAAK,gBAAgB;AAAA,IACvB,CAAC;AAED,UAAM,UAAU,SAAS,cAAc,QAAQ;AAC/C,YAAQ,cAAc;AACtB,YAAQ,iBAAiB,SAAS,MAAM;AACtC,WAAK,UAAU,aAAa;AAC5B,WAAK,gBAAgB;AAAA,IACvB,CAAC;AAED,SAAK,WAAW,YAAY,KAAK;AACjC,SAAK,WAAW,YAAY,OAAO;AAEnC,UAAM,YAAa,EAAE;AACrB,cAAU,MAAM,WAAW;AAC3B,cAAU,YAAY,KAAK,UAAU;AAAA,EACvC;AAAA,EAEQ,kBAAwB;AAC9B,QAAI,KAAK,YAAY;AACnB,WAAK,WAAW,OAAO;AACvB,WAAK,aAAa;AAAA,IACpB;AAAA,EACF;AACF;;;ACjJO,IAAM,UAAN,MAAc;AAAA,EAInB,YAAoB,WAAwB;AAAxB;AAClB,SAAK,YAAY,SAAS,cAAc,KAAK;AAC7C,SAAK,UAAU,YAAY;AAC3B,SAAK,UAAU,MAAM,UAAU;AAE/B,SAAK,YAAY,SAAS,cAAc,KAAK;AAC7C,SAAK,UAAU,YAAY;AAC3B,SAAK,UAAU,MAAM,UAAU;AAE/B,cAAU,YAAY,KAAK,SAAS;AACpC,cAAU,YAAY,KAAK,SAAS;AAAA,EACtC;AAAA,EAEA,KAAK,QAA2B;AAjBlC;AAkBI,QAAI;AACF,YAAM,OAAO,OAAO,sBAAsB;AAE1C,WAAK,UAAU,MAAM,UAAU;AAC/B,WAAK,UAAU,MAAM,MAAM,GAAG,KAAK,GAAG;AACtC,WAAK,UAAU,MAAM,OAAO,GAAG,KAAK,IAAI;AACxC,WAAK,UAAU,MAAM,QAAQ,GAAG,KAAK,KAAK;AAC1C,WAAK,UAAU,MAAM,SAAS,GAAG,KAAK,MAAM;AAE5C,YAAM,MAAM,OAAO,QAAQ,YAAY;AACvC,YAAM,SAAO,YAAO,gBAAP,mBAAoB,OAAO,MAAM,GAAG,QAAO;AACxD,YAAM,eAAe,OAAO,aAAa,eAAe;AACxD,UAAI,QAAQ,IAAI,GAAG;AACnB,UAAI,KAAM,UAAS,KAAK,IAAI;AAC5B,UAAI,aAAc,UAAS,KAAK,YAAY;AAE5C,WAAK,UAAU,cAAc;AAC7B,WAAK,UAAU,MAAM,UAAU;AAC/B,WAAK,UAAU,MAAM,MAAM,GAAG,KAAK,MAAM,EAAE;AAC3C,WAAK,UAAU,MAAM,OAAO,GAAG,KAAK,IAAI;AAAA,IAC1C,SAAQ;AACN,WAAK,KAAK;AAAA,IACZ;AAAA,EACF;AAAA,EAEA,sBAAsB,GAAW,GAAiB;AAChD,SAAK,UAAU,MAAM,OAAO,GAAG,IAAI,EAAE;AACrC,SAAK,UAAU,MAAM,MAAM,GAAG,IAAI,EAAE;AAAA,EACtC;AAAA,EAEA,OAAa;AACX,SAAK,UAAU,MAAM,UAAU;AAC/B,SAAK,UAAU,MAAM,UAAU;AAAA,EACjC;AAAA,EAEA,UAAgB;AACd,SAAK,UAAU,OAAO;AACtB,SAAK,UAAU,OAAO;AAAA,EACxB;AACF;;;ACpCA,IAAM,cAAc;AACpB,IAAM,eAAe;AAEd,IAAM,QAAN,MAAY;AAAA,EAIjB,YAAoB,WAAwB;AAAxB;AAHpB,SAAQ,UAA8B;AACtC,SAAQ,aAAkD;AAAA,EAEb;AAAA,EAE7C,KACE,MACA,UACA,UACA,UACM;AACN,SAAK,KAAK;AAEV,UAAMC,SAAQ,SAAS,cAAc,KAAK;AAC1C,IAAAA,OAAM,YAAY;AAElB,UAAM,SAAS,SAAS,cAAc,KAAK;AAC3C,WAAO,YAAY;AACnB,WAAO,cAAc,IAAI,KAAK,GAAG,IAAI,KAAK,OAAO,KAAK,KAAK,IAAI,MAAM,EAAE;AAEvE,UAAM,OAAO,SAAS,cAAc,KAAK;AACzC,SAAK,YAAY;AAEjB,UAAM,WAAW,SAAS,cAAc,UAAU;AAClD,aAAS,cAAc;AAEvB,SAAK,YAAY,QAAQ;AAEzB,UAAM,UAAU,SAAS,cAAc,KAAK;AAC5C,YAAQ,YAAY;AAEpB,UAAM,YAAY,SAAS,cAAc,QAAQ;AACjD,cAAU,cAAc;AACxB,cAAU,iBAAiB,SAAS,MAAM;AACxC,WAAK,KAAK;AACV,eAAS;AAAA,IACX,CAAC;AAED,UAAM,SAAS,SAAS,cAAc,QAAQ;AAC9C,WAAO,YAAY;AACnB,WAAO,cAAc;AACrB,WAAO,iBAAiB,SAAS,MAAM;AACrC,YAAM,UAAU,SAAS,MAAM,KAAK;AACpC,UAAI,CAAC,QAAS;AACd,WAAK,KAAK;AACV,eAAS,OAAO;AAAA,IAClB,CAAC;AAED,YAAQ,YAAY,SAAS;AAC7B,YAAQ,YAAY,MAAM;AAE1B,IAAAA,OAAM,YAAY,MAAM;AACxB,IAAAA,OAAM,YAAY,IAAI;AACtB,IAAAA,OAAM,YAAY,OAAO;AAEzB,SAAK,UAAU,YAAYA,MAAK;AAChC,SAAK,UAAUA;AAEf,SAAK,eAAeA,QAAO,QAAQ;AAGnC,SAAK,aAAa,CAAC,MAAqB;AACtC,UAAI,EAAE,QAAQ,YAAY,EAAE,WAAW,EAAE,UAAU;AACjD,cAAM,UAAU,SAAS,MAAM,KAAK;AACpC,YAAI,CAAC,QAAS;AACd,aAAK,KAAK;AACV,iBAAS,OAAO;AAAA,MAClB;AACA,UAAI,EAAE,QAAQ,UAAU;AACtB,aAAK,KAAK;AACV,iBAAS;AAAA,MACX;AAAA,IACF;AACA,aAAS,iBAAiB,WAAW,KAAK,UAAU;AAGpD,0BAAsB,MAAM,SAAS,MAAM,CAAC;AAAA,EAC9C;AAAA,EAEA,WACE,MACA,UACA,WACM;AACN,SAAK,KAAK;AAEV,UAAMA,SAAQ,SAAS,cAAc,KAAK;AAC1C,IAAAA,OAAM,YAAY;AAElB,UAAM,SAAS,SAAS,cAAc,KAAK;AAC3C,WAAO,YAAY;AACnB,WAAO,cAAc,IAAI,KAAK,GAAG,IAAI,KAAK,OAAO,KAAK,KAAK,IAAI,MAAM,EAAE,KAAK,KAAK,MAAM;AAEvF,UAAM,OAAO,SAAS,cAAc,KAAK;AACzC,SAAK,YAAY;AACjB,SAAK,cAAc,KAAK;AAExB,UAAM,UAAU,SAAS,cAAc,KAAK;AAC5C,YAAQ,YAAY;AAEpB,QAAI,KAAK,WAAW,WAAW;AAC7B,YAAM,aAAa,SAAS,cAAc,QAAQ;AAClD,iBAAW,YAAY;AACvB,iBAAW,cAAc;AACzB,iBAAW,iBAAiB,SAAS,MAAM;AACzC,aAAK,KAAK;AACV,kBAAU,UAAU;AAAA,MACtB,CAAC;AACD,cAAQ,YAAY,UAAU;AAAA,IAChC;AAEA,UAAM,YAAY,SAAS,cAAc,QAAQ;AACjD,cAAU,cAAc;AACxB,cAAU,iBAAiB,SAAS,MAAM;AACxC,WAAK,KAAK;AACV,gBAAU,SAAS;AAAA,IACrB,CAAC;AACD,YAAQ,YAAY,SAAS;AAE7B,UAAM,WAAW,SAAS,cAAc,QAAQ;AAChD,aAAS,cAAc;AACvB,aAAS,iBAAiB,SAAS,MAAM;AACvC,WAAK,KAAK;AACV,gBAAU,QAAQ;AAAA,IACpB,CAAC;AACD,YAAQ,YAAY,QAAQ;AAE5B,IAAAA,OAAM,YAAY,MAAM;AACxB,IAAAA,OAAM,YAAY,IAAI;AACtB,IAAAA,OAAM,YAAY,OAAO;AAEzB,SAAK,UAAU,YAAYA,MAAK;AAChC,SAAK,UAAUA;AAEf,SAAK,eAAeA,QAAO,QAAQ;AAEnC,SAAK,aAAa,CAAC,MAAqB;AACtC,UAAI,EAAE,QAAQ,UAAU;AACtB,aAAK,KAAK;AACV,kBAAU,QAAQ;AAAA,MACpB;AAAA,IACF;AACA,aAAS,iBAAiB,WAAW,KAAK,UAAU;AAAA,EACtD;AAAA,EAEA,OAAa;AACX,QAAI,KAAK,SAAS;AAChB,WAAK,QAAQ,OAAO;AACpB,WAAK,UAAU;AAAA,IACjB;AACA,QAAI,KAAK,YAAY;AACnB,eAAS,oBAAoB,WAAW,KAAK,UAAU;AACvD,WAAK,aAAa;AAAA,IACpB;AAAA,EACF;AAAA,EAEA,UAAgB;AACd,SAAK,KAAK;AAAA,EACZ;AAAA,EAEQ,eAAeA,QAAoB,UAA0B;AACnE,UAAM,YAAYA,OAAM,sBAAsB;AAC9C,UAAM,QAAQ,OAAO;AACrB,UAAM,QAAQ,OAAO;AAErB,QAAI,MAAM,SAAS;AACnB,QAAI,OAAO,SAAS;AAGpB,QAAI,MAAM,UAAU,SAAS,QAAQ,cAAc;AACjD,YAAM,SAAS,MAAM,UAAU,SAAS;AAAA,IAC1C;AAGA,QAAI,MAAM,cAAc;AACtB,YAAM;AAAA,IACR;AAGA,QAAI,OAAO,cAAc,QAAQ,cAAc;AAC7C,aAAO,QAAQ,cAAc;AAAA,IAC/B;AAGA,QAAI,OAAO,cAAc;AACvB,aAAO;AAAA,IACT;AAEA,IAAAA,OAAM,MAAM,MAAM,GAAG,GAAG;AACxB,IAAAA,OAAM,MAAM,OAAO,GAAG,IAAI;AAAA,EAC5B;AACF;;;AChNO,IAAM,gBAAN,MAAoB;AAAA,EAKzB,YACU,WACA,SACR;AAFQ;AACA;AANV,SAAQ,UAAU,oBAAI,IAAyB;AAC/C,SAAQ,QAAuB;AAC/B,SAAQ,UAAU;AAMhB,SAAK,kBAAkB;AAAA,EACzB;AAAA,EAEA,UAAU,YAAwB,QAA2B;AAC3D,SAAK;AACL,UAAM,WAAW,SAAS,cAAc,KAAK;AAC7C,aAAS,YAAY;AACrB,aAAS,aAAa,eAAe,WAAW,MAAM;AACtD,aAAS,aAAa,sBAAsB,WAAW,EAAE;AACzD,aAAS,cAAc,OAAO,KAAK,OAAO;AAC1C,aAAS,QAAQ,WAAW;AAE5B,aAAS,iBAAiB,SAAS,MAAM;AA7B7C;AA8BM,iBAAK,YAAL,8BAAe,WAAW;AAAA,IAC5B,CAAC;AAED,SAAK,UAAU,YAAY,QAAQ;AACnC,SAAK,QAAQ,IAAI,WAAW,IAAI,EAAE,YAAY,QAAQ,SAAS,CAAC;AAChE,SAAK,eAAe,WAAW,EAAE;AAAA,EACnC;AAAA,EAEA,aAAa,IAAkB;AAC7B,UAAM,QAAQ,KAAK,QAAQ,IAAI,EAAE;AACjC,QAAI,OAAO;AACT,YAAM,SAAS,OAAO;AACtB,WAAK,QAAQ,OAAO,EAAE;AAAA,IACxB;AAAA,EACF;AAAA,EAEA,aAAa,IAAY,QAAsC;AAC7D,UAAM,QAAQ,KAAK,QAAQ,IAAI,EAAE;AACjC,QAAI,OAAO;AACT,YAAM,WAAW,SAAS;AAC1B,YAAM,SAAS,aAAa,eAAe,MAAM;AAAA,IACnD;AAAA,EACF;AAAA,EAEA,QAAc;AACZ,eAAW,SAAS,KAAK,QAAQ,OAAO,GAAG;AACzC,YAAM,SAAS,OAAO;AAAA,IACxB;AACA,SAAK,QAAQ,MAAM;AACnB,SAAK,UAAU;AAAA,EACjB;AAAA,EAEA,UAAgB;AACd,QAAI,KAAK,UAAU,MAAM;AACvB,2BAAqB,KAAK,KAAK;AAC/B,WAAK,QAAQ;AAAA,IACf;AACA,SAAK,MAAM;AAAA,EACb;AAAA,EAEQ,eAAe,IAAkB;AACvC,UAAM,QAAQ,KAAK,QAAQ,IAAI,EAAE;AACjC,QAAI,CAAC,MAAO;AACZ,QAAI;AACF,YAAM,OAAO,MAAM,OAAO,sBAAsB;AAChD,YAAM,SAAS,MAAM,MAAM,GAAG,OAAO,UAAU,KAAK,MAAM,EAAE;AAC5D,YAAM,SAAS,MAAM,OAAO,GAAG,OAAO,UAAU,KAAK,QAAQ,EAAE;AAAA,IACjE,SAAQ;AAAA,IAER;AAAA,EACF;AAAA,EAEQ,oBAA0B;AAChC,UAAM,SAAS,MAAM;AACnB,iBAAW,MAAM,KAAK,QAAQ,KAAK,GAAG;AACpC,aAAK,eAAe,EAAE;AAAA,MACxB;AACA,WAAK,QAAQ,sBAAsB,MAAM;AAAA,IAC3C;AACA,SAAK,QAAQ,sBAAsB,MAAM;AAAA,EAC3C;AACF;;;ACzFO,IAAM,gBAAN,MAAoB;AAAA,EAGzB,YACU,WACA,UACR;AAFQ;AACA;AAJV,SAAQ,UAA8B;AAAA,EAKnC;AAAA,EAEH,OAAO,aAAiC;AACtC,SAAK,OAAO;AACZ,QAAI,YAAY,WAAW,EAAG;AAE9B,UAAM,QAAQ,SAAS,cAAc,KAAK;AAC1C,UAAM,YAAY;AAElB,UAAM,SAAS,SAAS,cAAc,KAAK;AAC3C,WAAO,YAAY;AACnB,WAAO,cAAc,aAAa,YAAY,MAAM;AACpD,UAAM,YAAY,MAAM;AAExB,eAAW,OAAO,aAAa;AAC7B,YAAM,OAAO,SAAS,cAAc,KAAK;AACzC,WAAK,YAAY;AAEjB,YAAM,OAAO,SAAS,cAAc,KAAK;AACzC,WAAK,YAAY;AAEjB,YAAM,UAAU,SAAS,cAAc,KAAK;AAC5C,cAAQ,YAAY;AACpB,cAAQ,cAAc,IAAI;AAE1B,YAAM,SAAS,SAAS,cAAc,KAAK;AAC3C,aAAO,YAAY;AACnB,YAAM,KAAK,IAAI;AACf,UAAI,OAAO,IAAI,GAAG,OAAO;AACzB,UAAI,GAAG,YAAa,SAAQ,KAAK,GAAG,WAAW;AAC/C,UAAI,GAAG,aAAc,SAAQ,KAAK,GAAG,YAAY;AACjD,aAAO,cAAc;AAErB,WAAK,YAAY,OAAO;AACxB,WAAK,YAAY,MAAM;AAEvB,YAAM,YAAY,SAAS,cAAc,QAAQ;AACjD,gBAAU,YAAY;AACtB,gBAAU,cAAc;AACxB,gBAAU,iBAAiB,SAAS,MAAM;AA/ChD;AAgDQ,mBAAK,aAAL,8BAAgB,IAAI;AAAA,MACtB,CAAC;AAED,WAAK,YAAY,IAAI;AACrB,WAAK,YAAY,SAAS;AAC1B,YAAM,YAAY,IAAI;AAAA,IACxB;AAEA,SAAK,UAAU,YAAY,KAAK;AAChC,SAAK,UAAU;AAAA,EACjB;AAAA,EAEA,UAAgB;AACd,SAAK,OAAO;AAAA,EACd;AAAA,EAEQ,SAAe;AACrB,QAAI,KAAK,SAAS;AAChB,WAAK,QAAQ,OAAO;AACpB,WAAK,UAAU;AAAA,IACjB;AAAA,EACF;AACF;;;ACpEO,IAAM,gBAAN,MAAoB;AAAA,EAOzB,cAAc;AANd,SAAQ,YAAsC,oBAAI,IAAI;AAOpD,SAAK,oBAAoB,QAAQ,UAAU,KAAK,OAAO;AACvD,SAAK,uBAAuB,QAAQ,aAAa,KAAK,OAAO;AAC7D,SAAK,kBAAkB,MAAM,KAAK,OAAO;AACzC,SAAK,oBAAoB,MAAM,KAAK,OAAO;AAE3C,SAAK,aAAa;AAElB,WAAO,iBAAiB,YAAY,KAAK,eAAe;AACxD,WAAO,iBAAiB,cAAc,KAAK,iBAAiB;AAAA,EAC9D;AAAA,EAEA,eAAuB;AACrB,WAAO,SAAS,WAAW,SAAS;AAAA,EACtC;AAAA,EAEA,SAAS,UAA2C;AAClD,SAAK,UAAU,IAAI,QAAQ;AAC3B,WAAO,MAAM;AACX,WAAK,UAAU,OAAO,QAAQ;AAAA,IAChC;AAAA,EACF;AAAA,EAEA,UAAgB;AACd,WAAO,oBAAoB,YAAY,KAAK,eAAe;AAC3D,WAAO,oBAAoB,cAAc,KAAK,iBAAiB;AAC/D,YAAQ,YAAY,KAAK;AACzB,YAAQ,eAAe,KAAK;AAC5B,SAAK,UAAU,MAAM;AAAA,EACvB;AAAA,EAEQ,SAAe;AACrB,UAAM,QAAQ,KAAK,aAAa;AAChC,eAAW,YAAY,KAAK,WAAW;AACrC,eAAS,KAAK;AAAA,IAChB;AAAA,EACF;AAAA,EAEQ,eAAqB;AAC3B,UAAM,OAAO;AAEb,YAAQ,YAAY,YAAa,MAA4C;AAC3E,WAAK,kBAAkB,MAAM,MAAM,IAAI;AACvC,WAAK,OAAO;AAAA,IACd;AAEA,YAAQ,eAAe,YAAa,MAA+C;AACjF,WAAK,qBAAqB,MAAM,MAAM,IAAI;AAC1C,WAAK,OAAO;AAAA,IACd;AAAA,EACF;AACF;;;AC/CA,IAAI,cAAc;AAClB,IAAI,UAA4B,CAAC;AACjC,IAAI;AACJ,IAAI;AACJ,IAAI;AACJ,IAAI;AACJ,IAAI;AACJ,IAAI;AACJ,IAAI;AACJ,IAAI;AACJ,IAAI,aAAa;AACjB,IAAI,mBAA4C;AAChD,IAAI,aAAkC;AACtC,IAAI,mBAAmB;AAGvB,IAAM,eAAe,oBAAI,IAAkC;AAE3D,SAAS,eAAuB;AAC9B,SAAO,SAAS,WAAW,SAAS;AACtC;AAEA,SAAS,aAAqB;AAC5B,SAAO,OAAO,KAAK,IAAI,CAAC,IAAI,KAAK,OAAO,EAAE,SAAS,EAAE,EAAE,MAAM,GAAG,CAAC,CAAC;AACpE;AAEA,SAAS,aAAa,cAAsB,IAAuB;AACjE,eAAa,IAAI,cAAc,IAAI,QAAQ,EAAE,CAAC;AAChD;AAEA,SAAS,iBAAiB,cAA0C;AAClE,QAAM,MAAM,aAAa,IAAI,YAAY;AACzC,MAAI,CAAC,IAAK,QAAO;AACjB,QAAM,KAAK,IAAI,MAAM;AACrB,MAAI,CAAC,MAAM,CAAC,GAAG,aAAa;AAC1B,iBAAa,OAAO,YAAY;AAChC,WAAO;AAAA,EACT;AACA,SAAO;AACT;AAEA,SAAS,eAAe,KAAqC;AAE3D,QAAM,SAAS,iBAAiB,IAAI,EAAE;AACtC,MAAI,OAAQ,QAAO;AAGnB,QAAM,KAAK,aAAa,IAAI,aAAa,EAAE,eAAe,QAAQ,cAAc,CAAC;AACjF,MAAI,IAAI;AACN,iBAAa,IAAI,IAAI,EAAE;AACvB,YAAQ,MAAM,yBAAyB,IAAI,OAAO,yBAAyB,GAAG,QAAQ,YAAY,CAAC,GAAG;AAAA,EACxG,OAAO;AACL,YAAQ,MAAM,iCAAiC,IAAI,OAAO,KAAK,IAAI,WAAW;AAAA,EAChF;AACA,SAAO;AACT;AAEA,SAAS,iBAAuB;AAC9B,UAAQ,MAAM;AACd,QAAM,WAAyB,CAAC;AAChC,QAAM,QAAQ,aAAa;AAC3B,QAAM,OAAO,QAAQ,WAAW,KAAK;AAErC,aAAW,OAAO,MAAM;AACtB,UAAM,KAAK,eAAe,GAAG;AAC7B,QAAI,IAAI;AACN,cAAQ,UAAU,KAAK,EAAE;AAAA,IAC3B,OAAO;AACL,eAAS,KAAK,GAAG;AAAA,IACnB;AAAA,EACF;AAEA,gBAAc,OAAO,QAAQ;AAE7B,QAAM,eAAe,KAAK,OAAO,CAAC,MAAM,EAAE,WAAW,SAAS,EAAE;AAChE,UAAQ,cAAc,YAAY;AACpC;AAGA,SAAS,kBAAwB;AAC/B,MAAI,iBAAkB;AACtB,qBAAmB;AACnB,wBAAsB,MAAM;AAC1B,uBAAmB;AACnB,mBAAe;AAAA,EACjB,CAAC;AACH;AAEA,SAAS,mBAAmB,GAAqB;AArGjD;AAsGE,MAAI,CAAC,WAAY;AAEjB,QAAM,SAAS,EAAE;AACjB,MAAI,CAAC,UAAU,OAAO,QAAQ,qBAAqB,EAAG;AAEtD,IAAE,eAAe;AACjB,IAAE,gBAAgB;AAElB,UAAQ,KAAK;AACb,gBAAc,KAAK;AAEnB,QAAM,OAAO,OAAO,sBAAsB;AAC1C,QAAM;AAAA,IACJ;AAAA,MACE,KAAK,OAAO,QAAQ,YAAY;AAAA,MAChC,OAAM,kBAAO,gBAAP,mBAAoB,OAAO,MAAM,GAAG,QAApC,YAA2C;AAAA,IACnD;AAAA,IACA;AAAA,MACE,KAAK,KAAK,SAAS;AAAA,MACnB,MAAM,KAAK;AAAA,IACb;AAAA,IACA,CAAC,YAAY;AACX,YAAM,KAAK,kBAAkB,QAAQ;AAAA,QACnC,aAAa,QAAQ;AAAA,QACrB,eAAe,QAAQ;AAAA,MACzB,CAAC;AACD,YAAM,MAAkB;AAAA,QACtB,IAAI,WAAW;AAAA,QACf;AAAA,QACA,aAAa;AAAA,QACb,OAAO,aAAa;AAAA,QACpB,WAAW,KAAK,IAAI;AAAA,QACpB,QAAQ;AAAA,MACV;AAEA,mBAAa,IAAI,IAAI,MAAM;AAC3B,cAAQ,IAAI,GAAG;AACf,qBAAe;AAAA,IACjB;AAAA,IACA,MAAM;AAAA,IAEN;AAAA,EACF;AACF;AAEA,SAAS,mBAAmB,GAAqB;AAC/C,MAAI,CAAC,WAAY;AACjB,QAAM,SAAS,EAAE;AACjB,MAAI,CAAC,UAAU,OAAO,QAAQ,qBAAqB,EAAG;AACtD,UAAQ,KAAK,MAAM;AACnB,UAAQ,sBAAsB,EAAE,SAAS,EAAE,OAAO;AACpD;AAEA,SAAS,qBAAqB,GAAwB;AACpD,MAAI,EAAE,QAAQ,YAAY,YAAY;AACpC,kBAAc,KAAK;AACnB,YAAQ,KAAK;AAAA,EACf;AACF;AAEA,SAAS,cAAc,OAAsB;AAC3C,eAAa;AACb,UAAQ,iBAAiB,KAAK;AAC9B,MAAI,CAAC,MAAO,SAAQ,KAAK;AAC3B;AAEA,SAAS,kBAAkB,cAA4B;AAxKvD;AAyKE,QAAM,MAAM,QAAQ,OAAO,EAAE,KAAK,CAAC,MAAM,EAAE,OAAO,YAAY;AAC9D,MAAI,CAAC,IAAK;AAEV,QAAM,KAAK,eAAe,GAAG;AAC7B,MAAI,CAAC,GAAI;AAET,QAAM,OAAO,GAAG,sBAAsB;AAEtC,QAAM;AAAA,IACJ;AAAA,MACE,KAAK,IAAI,YAAY;AAAA,MACrB,OAAM,SAAI,YAAY,gBAAhB,YAA+B;AAAA,MACrC,SAAS,IAAI;AAAA,MACb,QAAQ,IAAI;AAAA,IACd;AAAA,IACA,EAAE,KAAK,KAAK,SAAS,GAAG,MAAM,KAAK,KAAK;AAAA,IACxC;AAAA,MACE,WAAW,MAAM;AACf,gBAAQ,OAAO,IAAI,IAAI,EAAE,QAAQ,WAAW,CAAC;AAC7C,uBAAe;AAAA,MACjB;AAAA,MACA,UAAU,MAAM;AACd,qBAAa,OAAO,IAAI,EAAE;AAC1B,gBAAQ,OAAO,IAAI,EAAE;AACrB,uBAAe;AAAA,MACjB;AAAA,MACA,SAAS,MAAM;AAAA,MAAC;AAAA,IAClB;AAAA,EACF;AACF;AAEA,SAAS,iBAAuB;AAC9B,QAAM,QAAQ,aAAa;AAC3B,QAAM,OAAO,QAAQ,WAAW,KAAK;AACrC,MAAI,CAAC,KAAK,OAAQ;AAElB,QAAM,QAAQ,CAAC,yBAAoB,KAAK,KAAK,KAAK,MAAM,KAAK,EAAE;AAC/D,OAAK,QAAQ,CAAC,KAAK,MAAM;AACvB,UAAM,KAAK,IAAI;AACf,QAAI,OAAO,IAAI,GAAG,OAAO;AACzB,QAAI,GAAG,YAAa,SAAQ,KAAK,GAAG,WAAW;AAC/C,QAAI,GAAG,aAAc,SAAQ,KAAK,GAAG,YAAY;AACjD,QAAI,GAAG,aAAc,SAAQ,GAAG,eAAe,MAAM,GAAG,YAAY,KAAK,KAAK,GAAG,YAAY;AAC7F,UAAM,KAAK,GAAG,IAAI,CAAC,MAAM,IAAI,MAAM,KAAK,IAAI,MAAM,IAAI,OAAO,GAAG;AAAA,EAClE,CAAC;AAED,QAAM,OAAO,MAAM,KAAK,IAAI;AAC5B,MAAI;AACF,cAAU,UAAU,UAAU,IAAI;AAAA,EACpC,SAAQ;AACN,YAAQ,KAAK,qCAAqC;AAAA,EACpD;AACF;AAEA,SAAS,aAAmB;AAC1B,QAAM,OAAO,QAAQ,WAAW;AAChC,QAAM,OAAO,KAAK,UAAU,MAAM,MAAM,CAAC;AACzC,QAAM,OAAO,IAAI,KAAK,CAAC,IAAI,GAAG,EAAE,MAAM,mBAAmB,CAAC;AAC1D,QAAM,MAAM,IAAI,gBAAgB,IAAI;AACpC,QAAM,IAAI,SAAS,cAAc,GAAG;AACpC,IAAE,OAAO;AACT,IAAE,WAAW,sBAAsB,KAAK,IAAI,CAAC;AAC7C,IAAE,MAAM;AACR,MAAI,gBAAgB,GAAG;AACzB;AAEA,SAAS,wBAA8B;AACrC,qBAAmB,IAAI,iBAAiB,CAAC,cAAc;AACrD,eAAW,KAAK,WAAW;AACzB,UAAI,EAAE,kBAAkB,eAAe,EAAE,OAAO,QAAQ,qBAAqB,EAAG;AAAA,IAClF;AACA,oBAAgB;AAAA,EAClB,CAAC;AAED,mBAAiB,QAAQ,SAAS,MAAM;AAAA,IACtC,WAAW;AAAA,IACX,SAAS;AAAA,IACT,YAAY;AAAA,IACZ,iBAAiB,CAAC,MAAM,SAAS,iBAAiB,eAAe,aAAa,SAAS;AAAA,EACzF,CAAC;AACH;AAEO,IAAM,YAAY;AAAA,EACvB,KAAK,MAA+B;AAClC,QAAI,YAAa;AACjB,cAAU,sBAAQ,CAAC;AAEnB,QAAI;AACF,mBAAa;AACb,gBAAU,IAAI,kBAAkB;AAChC,qBAAe,IAAI,aAAa,SAAS,MAAM,QAAQ,KAAK;AAC5D,gBAAU,IAAI,QAAQ,aAAa,SAAS;AAC5C,cAAQ,IAAI,MAAM,aAAa,SAAS;AACxC,gBAAU,IAAI,cAAc,aAAa,WAAW,iBAAiB;AACrE,sBAAgB,IAAI,cAAc,aAAa,WAAW,CAAC,OAAO;AAChE,qBAAa,OAAO,EAAE;AACtB,gBAAQ,OAAO,EAAE;AACjB,uBAAe;AAAA,MACjB,CAAC;AAED,gBAAU,IAAI,QAAQ,aAAa,WAAW;AAAA,QAC5C,WAAW,MAAM,cAAc,CAAC,UAAU;AAAA,QAC1C,YAAY;AAAA,QACZ,cAAc;AAAA,QACd,UAAU,MAAM;AAjRxB;AAkRU,gBAAM,QAAO,aAAQ,aAAa,EAAE,UAAvB,mBAA+B;AAC5C,cAAI,MAAM;AACR,sBAAU,OAAO,IAAI;AAAA,UACvB;AAAA,QACF;AAAA,QACA,SAAS,MAAM;AACb,uBAAa,MAAM;AACnB,kBAAQ,SAAS;AACjB,yBAAe;AAAA,QACjB;AAAA,QACA,eAAe,MAAM,aAAa,OAAO;AAAA,MAC3C,CAAC;AAED,UAAI,QAAQ,cAAc;AACxB,gBAAQ,iBAAiB,IAAI;AAAA,MAC/B;AAEA,sBAAgB,IAAI,cAAc;AAClC,mBAAa,cAAc,SAAS,MAAM,eAAe,CAAC;AAE1D,eAAS,iBAAiB,SAAS,oBAAoB,IAAI;AAC3D,eAAS,iBAAiB,aAAa,kBAAkB;AACzD,eAAS,iBAAiB,WAAW,oBAAoB;AAEzD,4BAAsB;AAEtB,cAAQ,MAAM,sCAAsC,aAAa,CAAC,EAAE;AACpE,qBAAe;AACf,oBAAc;AAAA,IAChB,SAAS,KAAK;AACZ,cAAQ,MAAM,6BAA6B,GAAG;AAAA,IAChD;AAAA,EACF;AAAA,EAEA,UAAgB;AACd,QAAI,CAAC,YAAa;AAClB,QAAI;AACF,eAAS,oBAAoB,SAAS,oBAAoB,IAAI;AAC9D,eAAS,oBAAoB,aAAa,kBAAkB;AAC5D,eAAS,oBAAoB,WAAW,oBAAoB;AAC5D,2DAAkB;AAClB,yBAAmB;AACnB;AACA,qDAAe;AACf,yCAAS;AACT,qDAAe;AACf,qCAAO;AACP,yCAAS;AACT,yCAAS;AACT,mDAAc;AACd,mBAAa;AACb,mBAAa,MAAM;AACnB,mBAAa;AACb,oBAAc;AAAA,IAChB,SAAS,KAAK;AACZ,cAAQ,MAAM,gCAAgC,GAAG;AAAA,IACnD;AAAA,EACF;AAAA,EAEA,SAAS,OAA+B;AACtC,iDAAc,SAAS;AAAA,EACzB;AAAA,EAEA,OAAO,QAA6B;AAClC,QAAI,WAAW,KAAM,gBAAe;AAAA,QAC/B,YAAW;AAAA,EAClB;AAAA,EAEA,MAAM,OAAO,MAAmC;AAC9C,UAAM,OAAO,MAAM,KAAK,KAAK;AAC7B,UAAM,OAAO,KAAK,MAAM,IAAI;AAC5B,YAAQ,WAAW,IAAI;AACvB,mBAAe;AAEf,UAAM,UAAU,QAAQ,OAAO;AAC/B,QAAI,UAAU;AACd,QAAI,WAAW;AACf,eAAW,OAAO,SAAS;AACzB,UAAI,eAAe,GAAG,GAAG;AACvB;AAAA,MACF,OAAO;AACL;AAAA,MACF;AAAA,IACF;AACA,WAAO,EAAE,OAAO,QAAQ,QAAQ,SAAS,SAAS;AAAA,EACpD;AAAA,EAEA,eAAe,OAA8B;AAC3C,QAAI,CAAC,QAAS,QAAO,CAAC;AACtB,WAAO,QAAQ,QAAQ,WAAW,KAAK,IAAI,QAAQ,OAAO;AAAA,EAC5D;AAAA,EAEA,WAAiB;AACf,iBAAa,MAAM;AACnB,uCAAS;AACT,QAAI,YAAa,gBAAe;AAAA,EAClC;AACF;","names":["options","parent","buildDomPath","options","e","popup"]}
1
+ {"version":3,"sources":["../src/core/storage.ts","../src/core/hash-detect.ts","../src/core/fingerprint.ts","../src/core/matcher.ts","../src/ui/styles.ts","../src/ui/theme.ts","../src/ui/toolbar.ts","../src/ui/overlay.ts","../src/ui/popup.ts","../src/ui/markers.ts","../src/ui/detached-panel.ts","../src/spa.ts","../src/web-remarq.ts"],"sourcesContent":["import type { Annotation, AnnotationStore } from './types'\n\nconst STORAGE_KEY = 'remarq:annotations'\n\nexport class AnnotationStorage {\n private annotations: Annotation[] = []\n private extraFields: Record<string, unknown> = {}\n isMemoryOnly = false\n\n constructor() {\n this.load()\n }\n\n getAll(): Annotation[] {\n return [...this.annotations]\n }\n\n getByRoute(route: string): Annotation[] {\n return this.annotations.filter((a) => a.route === route)\n }\n\n add(annotation: Annotation): void {\n this.annotations.push(annotation)\n this.save()\n }\n\n remove(id: string): void {\n this.annotations = this.annotations.filter((a) => a.id !== id)\n this.save()\n }\n\n update(id: string, changes: Partial<Annotation>): void {\n const idx = this.annotations.findIndex((a) => a.id === id)\n if (idx !== -1) {\n this.annotations[idx] = { ...this.annotations[idx], ...changes }\n this.save()\n }\n }\n\n clearAll(): void {\n this.annotations = []\n this.save()\n }\n\n exportJSON(): AnnotationStore {\n return {\n version: 1,\n annotations: [...this.annotations],\n }\n }\n\n importJSON(data: AnnotationStore): void {\n this.annotations = [...data.annotations]\n this.save()\n }\n\n private load(): void {\n try {\n const raw = localStorage.getItem(STORAGE_KEY)\n if (raw) {\n const parsed = JSON.parse(raw)\n const { version, annotations, ...rest } = parsed\n this.annotations = annotations ?? []\n this.extraFields = rest\n }\n } catch {\n this.isMemoryOnly = true\n }\n }\n\n private save(): void {\n if (this.isMemoryOnly) return\n try {\n const data = {\n version: 1,\n ...this.extraFields,\n annotations: this.annotations,\n }\n localStorage.setItem(STORAGE_KEY, JSON.stringify(data))\n } catch {\n this.isMemoryOnly = true\n }\n }\n}\n","const CSS_MODULES_RE = /^(.+)__([a-zA-Z0-9]{3,})$/\nconst STYLED_COMPONENTS_RE = /^sc-/\nconst EMOTION_RE = /^css-[a-zA-Z0-9]+$/\nconst PURE_HASH_RE = /^(?=.*[a-zA-Z])(?=.*\\d)[a-zA-Z0-9]{8,}$/\n\nexport function isHashedClass(className: string): boolean {\n if (STYLED_COMPONENTS_RE.test(className)) return true\n if (EMOTION_RE.test(className)) return true\n if (CSS_MODULES_RE.test(className)) return true\n if (PURE_HASH_RE.test(className)) return true\n return false\n}\n\nexport function stripHash(className: string): string {\n const match = className.match(CSS_MODULES_RE)\n if (match) {\n const prefix = className.slice(0, className.lastIndexOf('__'))\n return prefix\n }\n return className\n}\n\nexport function filterClasses(\n classes: string[],\n classFilter?: (className: string) => boolean,\n): string[] {\n const result: string[] = []\n\n for (const cls of classes) {\n if (STYLED_COMPONENTS_RE.test(cls)) continue\n if (EMOTION_RE.test(cls)) continue\n if (PURE_HASH_RE.test(cls)) continue\n\n let stable = stripHash(cls)\n\n if (classFilter && !classFilter(stable)) continue\n\n result.push(stable)\n }\n\n return result\n}\n","import type { ElementFingerprint, WebRemarqOptions } from './types'\nimport { filterClasses, isHashedClass } from './hash-detect'\n\nconst TEXT_MAX_LENGTH = 50\n\nexport function createFingerprint(\n el: HTMLElement,\n options?: Pick<WebRemarqOptions, 'classFilter' | 'dataAttribute'>,\n): ElementFingerprint {\n const dataAttr = options?.dataAttribute ?? 'data-annotate'\n\n return {\n dataAnnotate: el.getAttribute(dataAttr) ?? null,\n dataTestId: el.getAttribute('data-testid')\n ?? el.getAttribute('data-test')\n ?? el.getAttribute('data-cy')\n ?? null,\n id: getStableId(el),\n tagName: el.tagName.toLowerCase(),\n textContent: getTextContent(el),\n role: el.getAttribute('role') ?? null,\n ariaLabel: el.getAttribute('aria-label') ?? null,\n stableClasses: filterClasses(\n Array.from(el.classList),\n options?.classFilter,\n ),\n domPath: buildDomPath(el),\n siblingIndex: getSiblingIndex(el),\n parentAnchor: findParentAnchor(el, dataAttr),\n }\n}\n\nfunction getStableId(el: HTMLElement): string | null {\n const id = el.id\n if (!id) return null\n if (isHashedClass(id)) return null\n return id\n}\n\nfunction getTextContent(el: HTMLElement): string | null {\n // Use only direct text nodes, not nested children's text\n let text = ''\n for (const node of Array.from(el.childNodes)) {\n if (node.nodeType === Node.TEXT_NODE) {\n text += node.textContent ?? ''\n }\n }\n text = text.trim()\n\n // If no direct text, try first meaningful child's text (for wrappers like <span><b>Text</b></span>)\n if (!text && el.children.length <= 3) {\n text = el.textContent?.trim() ?? ''\n }\n\n if (!text) return null\n return text.length > TEXT_MAX_LENGTH ? text.slice(0, TEXT_MAX_LENGTH) : text\n}\n\nfunction buildDomPath(el: HTMLElement): string {\n const parts: string[] = []\n let current: HTMLElement | null = el\n\n while (current && current !== document.body && parts.length < 5) {\n parts.unshift(current.tagName.toLowerCase())\n current = current.parentElement\n }\n\n return parts.join(' > ')\n}\n\nfunction getSiblingIndex(el: HTMLElement): number {\n const parent = el.parentElement\n if (!parent) return 0\n const children = Array.from(parent.children)\n return children.indexOf(el)\n}\n\nfunction findParentAnchor(el: HTMLElement, dataAttr: string): string | null {\n let current = el.parentElement\n while (current && current !== document.body) {\n const value = current.getAttribute(dataAttr)\n if (value) return value\n current = current.parentElement\n }\n return null\n}\n","import type { ElementFingerprint, WebRemarqOptions } from './types'\n\nconst MATCH_THRESHOLD = 50\n\nexport function levenshteinSimilarity(a: string, b: string): number {\n if (a === b) return 1\n if (!a.length || !b.length) return 0\n\n const matrix: number[][] = []\n for (let i = 0; i <= a.length; i++) {\n matrix[i] = [i]\n }\n for (let j = 0; j <= b.length; j++) {\n matrix[0][j] = j\n }\n\n for (let i = 1; i <= a.length; i++) {\n for (let j = 1; j <= b.length; j++) {\n const cost = a[i - 1] === b[j - 1] ? 0 : 1\n matrix[i][j] = Math.min(\n matrix[i - 1][j] + 1,\n matrix[i][j - 1] + 1,\n matrix[i - 1][j - 1] + cost,\n )\n }\n }\n\n const distance = matrix[a.length][b.length]\n return 1 - distance / Math.max(a.length, b.length)\n}\n\nfunction textSimilarity(a: string | null, b: string | null): number {\n if (!a || !b) return 0\n const na = a.trim().toLowerCase()\n const nb = b.trim().toLowerCase()\n if (na === nb) return 1\n if (na.includes(nb) || nb.includes(na)) return 1\n return levenshteinSimilarity(na, nb)\n}\n\nfunction jaccardSimilarity(a: string[], b: string[]): number {\n if (!a.length && !b.length) return 0\n const setA = new Set(a)\n const setB = new Set(b)\n let intersection = 0\n for (const item of setA) {\n if (setB.has(item)) intersection++\n }\n const union = new Set([...a, ...b]).size\n return union === 0 ? 0 : intersection / union\n}\n\nfunction scoreCandidate(el: HTMLElement, fp: ElementFingerprint, dataAttr: string): number {\n let score = 0\n\n // dataAnnotate match (+100)\n const elAnnotate = el.getAttribute(dataAttr)\n if (fp.dataAnnotate && elAnnotate === fp.dataAnnotate) {\n score += 100\n }\n\n // textContent match (+35 scaled)\n const elText = el.textContent?.trim().slice(0, 50) ?? null\n const textSim = textSimilarity(fp.textContent, elText)\n if (textSim > 0.7) {\n score += textSim * 35\n }\n\n // role + ariaLabel match (+30)\n if (fp.role && el.getAttribute('role') === fp.role &&\n fp.ariaLabel && el.getAttribute('aria-label') === fp.ariaLabel) {\n score += 30\n }\n\n // parentAnchor match (+15)\n if (fp.parentAnchor) {\n let parent = el.parentElement\n while (parent && parent !== document.body) {\n if (parent.getAttribute(dataAttr) === fp.parentAnchor) {\n score += 15\n break\n }\n parent = parent.parentElement\n }\n }\n\n // stableClasses overlap (+15 scaled)\n if (fp.stableClasses.length > 0) {\n const elClasses = Array.from(el.classList)\n const jaccard = jaccardSimilarity(fp.stableClasses, elClasses)\n score += jaccard * 15\n }\n\n // domPath match (+15 scaled)\n if (fp.domPath) {\n const elPath = buildDomPath(el)\n const pathSim = levenshteinSimilarity(fp.domPath, elPath)\n score += pathSim * 15\n }\n\n // siblingIndex match (+5)\n const parent = el.parentElement\n if (parent) {\n const idx = Array.from(parent.children).indexOf(el)\n if (idx === fp.siblingIndex) {\n score += 5\n }\n }\n\n return score\n}\n\nfunction buildDomPath(el: HTMLElement): string {\n const parts: string[] = []\n let current: HTMLElement | null = el\n while (current && current !== document.body && parts.length < 5) {\n parts.unshift(current.tagName.toLowerCase())\n current = current.parentElement\n }\n return parts.join(' > ')\n}\n\nexport function matchElement(\n fp: ElementFingerprint,\n options?: Pick<WebRemarqOptions, 'dataAttribute'>,\n): HTMLElement | null {\n const dataAttr = options?.dataAttribute ?? 'data-annotate'\n\n // 1. Exact match by data-annotate\n if (fp.dataAnnotate) {\n const el = document.querySelector<HTMLElement>(`[${dataAttr}=\"${fp.dataAnnotate}\"]`)\n if (el) return el\n }\n\n // 2. Exact match by data-testid\n if (fp.dataTestId) {\n const el = document.querySelector<HTMLElement>(\n `[data-testid=\"${fp.dataTestId}\"], [data-test=\"${fp.dataTestId}\"], [data-cy=\"${fp.dataTestId}\"]`,\n )\n if (el) return el\n }\n\n // 3. Exact match by id\n if (fp.id) {\n const el = document.getElementById(fp.id) as HTMLElement | null\n if (el) return el\n }\n\n // 4. Fuzzy match by tagName + weighted scoring\n const candidates = document.querySelectorAll<HTMLElement>(fp.tagName)\n let bestEl: HTMLElement | null = null\n let bestScore = 0\n\n for (const candidate of candidates) {\n const score = scoreCandidate(candidate, fp, dataAttr)\n if (score > bestScore) {\n bestScore = score\n bestEl = candidate\n }\n }\n\n return bestScore >= MATCH_THRESHOLD ? bestEl : null\n}\n","const STYLES_ID = 'data-remarq-styles'\n\nconst CSS = `\n[data-remarq-theme=\"light\"] {\n --remarq-bg: #ffffff;\n --remarq-bg-secondary: #f5f5f5;\n --remarq-text: #1a1a1a;\n --remarq-text-secondary: #666666;\n --remarq-border: #e2e8f0;\n --remarq-accent: #3b82f6;\n --remarq-pending: #f97316;\n --remarq-resolved: #22c55e;\n --remarq-overlay: rgba(59, 130, 246, 0.15);\n --remarq-shadow: 0 4px 12px rgba(0,0,0,0.15);\n}\n\n[data-remarq-theme=\"dark\"] {\n --remarq-bg: #1e1e1e;\n --remarq-bg-secondary: #2a2a2a;\n --remarq-text: #e5e5e5;\n --remarq-text-secondary: #999999;\n --remarq-border: #333333;\n --remarq-accent: #60a5fa;\n --remarq-pending: #fb923c;\n --remarq-resolved: #4ade80;\n --remarq-overlay: rgba(96, 165, 250, 0.15);\n --remarq-shadow: 0 4px 12px rgba(0,0,0,0.4);\n}\n\n.remarq-toolbar {\n position: fixed;\n bottom: 16px;\n right: 16px;\n z-index: 2147483647;\n display: flex;\n gap: 4px;\n padding: 8px;\n background: var(--remarq-bg);\n border: 1px solid var(--remarq-border);\n border-radius: 8px;\n box-shadow: var(--remarq-shadow);\n font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, sans-serif;\n font-size: 13px;\n color: var(--remarq-text);\n}\n\n.remarq-toolbar.remarq-minimized { padding: 4px; }\n\n.remarq-toolbar-btn {\n display: flex;\n align-items: center;\n justify-content: center;\n width: 32px;\n height: 32px;\n border: none;\n border-radius: 6px;\n background: transparent;\n color: var(--remarq-text);\n cursor: pointer;\n position: relative;\n}\n\n.remarq-toolbar-btn:hover { background: var(--remarq-bg-secondary); }\n.remarq-toolbar-btn.remarq-active { background: var(--remarq-accent); color: #ffffff; }\n\n.remarq-badge {\n position: absolute;\n top: -4px;\n right: -4px;\n min-width: 16px;\n height: 16px;\n padding: 0 4px;\n border-radius: 8px;\n background: var(--remarq-pending);\n color: #ffffff;\n font-size: 10px;\n font-weight: 600;\n display: flex;\n align-items: center;\n justify-content: center;\n}\n\n.remarq-overlay {\n position: fixed;\n pointer-events: none;\n background: var(--remarq-overlay);\n border: 2px solid var(--remarq-accent);\n border-radius: 2px;\n z-index: 2147483646;\n transition: all 0.05s ease-out;\n}\n\n.remarq-tooltip {\n position: fixed;\n z-index: 2147483647;\n padding: 4px 8px;\n background: var(--remarq-bg);\n border: 1px solid var(--remarq-border);\n border-radius: 4px;\n font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, sans-serif;\n font-size: 12px;\n color: var(--remarq-text);\n box-shadow: var(--remarq-shadow);\n pointer-events: none;\n white-space: nowrap;\n max-width: 300px;\n overflow: hidden;\n text-overflow: ellipsis;\n}\n\n.remarq-marker {\n position: absolute;\n z-index: 2147483645;\n width: 24px;\n height: 24px;\n border-radius: 50%;\n display: flex;\n align-items: center;\n justify-content: center;\n font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, sans-serif;\n font-size: 11px;\n font-weight: 700;\n color: #ffffff;\n cursor: pointer;\n box-shadow: 0 2px 4px rgba(0,0,0,0.2);\n transition: transform 0.1s ease;\n}\n\n.remarq-marker:hover { transform: scale(1.2); }\n.remarq-marker[data-status=\"pending\"] { background: var(--remarq-pending); }\n.remarq-marker[data-status=\"resolved\"] { background: var(--remarq-resolved); opacity: 0.7; }\n\n.remarq-popup {\n position: absolute;\n z-index: 2147483647;\n width: 300px;\n background: var(--remarq-bg);\n border: 1px solid var(--remarq-border);\n border-radius: 8px;\n box-shadow: var(--remarq-shadow);\n font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, sans-serif;\n font-size: 13px;\n color: var(--remarq-text);\n}\n\n.remarq-popup-header {\n padding: 8px 12px;\n border-bottom: 1px solid var(--remarq-border);\n font-size: 12px;\n color: var(--remarq-text-secondary);\n overflow: hidden;\n text-overflow: ellipsis;\n white-space: nowrap;\n}\n\n.remarq-popup-body { padding: 12px; }\n\n.remarq-popup textarea {\n width: 100%;\n min-height: 60px;\n padding: 8px;\n border: 1px solid var(--remarq-border);\n border-radius: 4px;\n background: var(--remarq-bg-secondary);\n color: var(--remarq-text);\n font-family: inherit;\n font-size: 13px;\n resize: vertical;\n box-sizing: border-box;\n}\n\n.remarq-popup textarea:focus { outline: none; border-color: var(--remarq-accent); }\n\n.remarq-popup-actions {\n display: flex;\n justify-content: flex-end;\n gap: 8px;\n padding: 8px 12px;\n border-top: 1px solid var(--remarq-border);\n}\n\n.remarq-popup-actions button {\n padding: 4px 12px;\n border: 1px solid var(--remarq-border);\n border-radius: 4px;\n background: var(--remarq-bg);\n color: var(--remarq-text);\n cursor: pointer;\n font-size: 12px;\n}\n\n.remarq-popup-actions button.remarq-primary {\n background: var(--remarq-accent);\n border-color: var(--remarq-accent);\n color: #ffffff;\n}\n\n.remarq-detached-panel {\n position: fixed;\n bottom: 60px;\n right: 16px;\n z-index: 2147483646;\n width: 280px;\n max-height: 300px;\n overflow-y: auto;\n background: var(--remarq-bg);\n border: 1px solid var(--remarq-border);\n border-radius: 8px;\n box-shadow: var(--remarq-shadow);\n font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, sans-serif;\n font-size: 13px;\n color: var(--remarq-text);\n}\n\n.remarq-detached-header {\n padding: 8px 12px;\n border-bottom: 1px solid var(--remarq-border);\n font-weight: 600;\n font-size: 12px;\n color: var(--remarq-text-secondary);\n}\n\n.remarq-detached-item {\n padding: 8px 12px;\n border-bottom: 1px solid var(--remarq-border);\n display: flex;\n justify-content: space-between;\n align-items: flex-start;\n gap: 8px;\n}\n\n.remarq-detached-item:last-child { border-bottom: none; }\n.remarq-detached-info { flex: 1; min-width: 0; }\n.remarq-detached-comment { margin-bottom: 4px; }\n\n.remarq-detached-element {\n font-size: 11px;\n color: var(--remarq-text-secondary);\n overflow: hidden;\n text-overflow: ellipsis;\n white-space: nowrap;\n}\n\n.remarq-detached-delete {\n border: none;\n background: none;\n color: var(--remarq-text-secondary);\n cursor: pointer;\n padding: 2px;\n font-size: 14px;\n line-height: 1;\n flex-shrink: 0;\n}\n\n.remarq-detached-delete:hover { color: #ef4444; }\n\n.remarq-export-menu {\n position: absolute;\n bottom: 100%;\n right: 0;\n margin-bottom: 4px;\n background: var(--remarq-bg);\n border: 1px solid var(--remarq-border);\n border-radius: 6px;\n box-shadow: var(--remarq-shadow);\n overflow: hidden;\n}\n\n.remarq-export-menu button {\n display: block;\n width: 100%;\n padding: 8px 16px;\n border: none;\n background: transparent;\n color: var(--remarq-text);\n cursor: pointer;\n font-size: 12px;\n text-align: left;\n white-space: nowrap;\n}\n\n.remarq-export-menu button:hover { background: var(--remarq-bg-secondary); }\n`\n\nexport function injectStyles(): void {\n if (document.querySelector(`style[${STYLES_ID}]`)) return\n\n try {\n const style = document.createElement('style')\n style.setAttribute(STYLES_ID, '')\n style.textContent = CSS\n document.head.appendChild(style)\n } catch {\n // CSP fallback: try blob URL via <link>\n try {\n const blob = new Blob([CSS], { type: 'text/css' })\n const link = document.createElement('link')\n link.rel = 'stylesheet'\n link.href = URL.createObjectURL(blob)\n link.setAttribute(STYLES_ID, '')\n document.head.appendChild(link)\n } catch {\n console.warn('[web-remarq] Could not inject styles')\n }\n }\n}\n\nexport function removeStyles(): void {\n const el = document.querySelector(`[${STYLES_ID}]`)\n el?.remove()\n}\n","const THEME_KEY = 'remarq:theme'\n\nexport type Theme = 'light' | 'dark'\n\nexport class ThemeManager {\n container: HTMLElement\n private theme: Theme\n\n constructor(parent: HTMLElement, initialTheme?: Theme) {\n const persisted = this.loadTheme()\n this.theme = initialTheme ?? persisted ?? 'light'\n\n this.container = document.createElement('div')\n this.container.setAttribute('data-remarq-theme', this.theme)\n parent.appendChild(this.container)\n\n this.persist()\n }\n\n getTheme(): Theme {\n return this.theme\n }\n\n setTheme(theme: Theme): void {\n this.theme = theme\n this.container.setAttribute('data-remarq-theme', theme)\n this.persist()\n }\n\n toggle(): void {\n this.setTheme(this.theme === 'light' ? 'dark' : 'light')\n }\n\n destroy(): void {\n this.container.remove()\n }\n\n private persist(): void {\n try {\n localStorage.setItem(THEME_KEY, this.theme)\n } catch {\n // ignore\n }\n }\n\n private loadTheme(): Theme | null {\n try {\n const value = localStorage.getItem(THEME_KEY)\n if (value === 'light' || value === 'dark') return value\n } catch {\n // ignore\n }\n return null\n }\n}\n","export interface ToolbarCallbacks {\n onInspect: () => void\n onExportMd: () => void\n onExportJson: () => void\n onImport: () => void\n onClear: () => void\n onThemeToggle: () => void\n}\n\nconst ICONS = {\n inspect: '<svg width=\"16\" height=\"16\" viewBox=\"0 0 16 16\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"1.5\"><circle cx=\"7\" cy=\"7\" r=\"4\"/><line x1=\"10\" y1=\"10\" x2=\"14\" y2=\"14\"/></svg>',\n export: '<svg width=\"16\" height=\"16\" viewBox=\"0 0 16 16\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"1.5\"><path d=\"M8 2v8M4 6l4-4 4 4M2 12h12\"/></svg>',\n import: '<svg width=\"16\" height=\"16\" viewBox=\"0 0 16 16\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"1.5\"><path d=\"M8 10V2M4 6l4 4 4-4M2 12h12\"/></svg>',\n clear: '<svg width=\"16\" height=\"16\" viewBox=\"0 0 16 16\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"1.5\"><path d=\"M3 4h10M6 4V3h4v1M5 4v9h6V4\"/></svg>',\n theme: '<svg width=\"16\" height=\"16\" viewBox=\"0 0 16 16\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"1.5\"><circle cx=\"8\" cy=\"8\" r=\"3\"/><path d=\"M8 1v2M8 13v2M1 8h2M13 8h2\"/></svg>',\n minimize: '<svg width=\"16\" height=\"16\" viewBox=\"0 0 16 16\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"1.5\"><path d=\"M4 8h8\"/></svg>',\n}\n\nexport class Toolbar {\n private toolbarEl: HTMLElement\n private badgeEl: HTMLElement\n private inspectBtn: HTMLElement\n private exportMenu: HTMLElement | null = null\n private fileInput: HTMLInputElement\n private minimized = false\n private buttons: HTMLElement[] = []\n\n constructor(\n private container: HTMLElement,\n private callbacks: ToolbarCallbacks,\n ) {\n this.toolbarEl = document.createElement('div')\n this.toolbarEl.className = 'remarq-toolbar'\n\n this.inspectBtn = this.createButton('inspect', ICONS.inspect, () => callbacks.onInspect())\n this.badgeEl = document.createElement('span')\n this.badgeEl.className = 'remarq-badge'\n this.badgeEl.style.display = 'none'\n this.inspectBtn.appendChild(this.badgeEl)\n\n const exportBtn = this.createButton('export', ICONS.export, (e) => this.toggleExportMenu(e))\n\n this.fileInput = document.createElement('input')\n this.fileInput.type = 'file'\n this.fileInput.accept = '.json'\n this.fileInput.style.display = 'none'\n this.fileInput.addEventListener('change', () => {\n callbacks.onImport()\n this.fileInput.value = ''\n })\n const importBtn = this.createButton('import', ICONS.import, () => this.fileInput.click())\n\n const clearBtn = this.createButton('clear', ICONS.clear, () => callbacks.onClear())\n const themeBtn = this.createButton('theme', ICONS.theme, () => callbacks.onThemeToggle())\n const minimizeBtn = this.createButton('minimize', ICONS.minimize, () => this.toggleMinimize())\n\n this.buttons = [this.inspectBtn, exportBtn, importBtn, clearBtn, themeBtn]\n\n this.toolbarEl.appendChild(this.inspectBtn)\n this.toolbarEl.appendChild(exportBtn)\n this.toolbarEl.appendChild(importBtn)\n this.toolbarEl.appendChild(clearBtn)\n this.toolbarEl.appendChild(themeBtn)\n this.toolbarEl.appendChild(minimizeBtn)\n this.toolbarEl.appendChild(this.fileInput)\n\n container.appendChild(this.toolbarEl)\n }\n\n setInspectActive(active: boolean): void {\n this.inspectBtn.classList.toggle('remarq-active', active)\n }\n\n setBadgeCount(count: number): void {\n this.badgeEl.textContent = String(count)\n this.badgeEl.style.display = count > 0 ? 'flex' : 'none'\n }\n\n getFileInput(): HTMLInputElement {\n return this.fileInput\n }\n\n setMemoryWarning(show: boolean): void {\n this.toolbarEl.title = show ? 'localStorage unavailable — annotations stored in memory only' : ''\n }\n\n destroy(): void {\n this.closeExportMenu()\n this.toolbarEl.remove()\n }\n\n private createButton(action: string, icon: string, handler: (e: Event) => void): HTMLElement {\n const btn = document.createElement('button')\n btn.className = 'remarq-toolbar-btn'\n btn.setAttribute('data-remarq-action', action)\n btn.innerHTML = icon\n btn.addEventListener('click', handler)\n return btn\n }\n\n private toggleMinimize(): void {\n this.minimized = !this.minimized\n this.toolbarEl.classList.toggle('remarq-minimized', this.minimized)\n for (const btn of this.buttons) {\n btn.style.display = this.minimized ? 'none' : ''\n }\n }\n\n private toggleExportMenu(e: Event): void {\n if (this.exportMenu) {\n this.closeExportMenu()\n return\n }\n\n this.exportMenu = document.createElement('div')\n this.exportMenu.className = 'remarq-export-menu'\n\n const mdBtn = document.createElement('button')\n mdBtn.textContent = 'Markdown (clipboard)'\n mdBtn.addEventListener('click', () => {\n this.callbacks.onExportMd()\n this.closeExportMenu()\n })\n\n const jsonBtn = document.createElement('button')\n jsonBtn.textContent = 'JSON (file)'\n jsonBtn.addEventListener('click', () => {\n this.callbacks.onExportJson()\n this.closeExportMenu()\n })\n\n this.exportMenu.appendChild(mdBtn)\n this.exportMenu.appendChild(jsonBtn)\n\n const exportBtn = (e.currentTarget as HTMLElement)\n exportBtn.style.position = 'relative'\n exportBtn.appendChild(this.exportMenu)\n }\n\n private closeExportMenu(): void {\n if (this.exportMenu) {\n this.exportMenu.remove()\n this.exportMenu = null\n }\n }\n}\n","export class Overlay {\n private overlayEl: HTMLElement\n private tooltipEl: HTMLElement\n\n constructor(private container: HTMLElement) {\n this.overlayEl = document.createElement('div')\n this.overlayEl.className = 'remarq-overlay'\n this.overlayEl.style.display = 'none'\n\n this.tooltipEl = document.createElement('div')\n this.tooltipEl.className = 'remarq-tooltip'\n this.tooltipEl.style.display = 'none'\n\n container.appendChild(this.overlayEl)\n container.appendChild(this.tooltipEl)\n }\n\n show(target: HTMLElement): void {\n try {\n const rect = target.getBoundingClientRect()\n\n this.overlayEl.style.display = 'block'\n this.overlayEl.style.top = `${rect.top}px`\n this.overlayEl.style.left = `${rect.left}px`\n this.overlayEl.style.width = `${rect.width}px`\n this.overlayEl.style.height = `${rect.height}px`\n\n this.tooltipEl.textContent = describeElement(target)\n this.tooltipEl.style.display = 'block'\n this.tooltipEl.style.top = `${rect.top - 28}px`\n this.tooltipEl.style.left = `${rect.left}px`\n } catch {\n this.hide()\n }\n }\n\n updateTooltipPosition(x: number, y: number): void {\n this.tooltipEl.style.left = `${x + 12}px`\n this.tooltipEl.style.top = `${y - 28}px`\n }\n\n hide(): void {\n this.overlayEl.style.display = 'none'\n this.tooltipEl.style.display = 'none'\n }\n\n destroy(): void {\n this.overlayEl.remove()\n this.tooltipEl.remove()\n }\n}\n\nfunction describeElement(el: HTMLElement): string {\n const tag = el.tagName.toLowerCase()\n const parts: string[] = [`<${tag}>`]\n\n // data-annotate or data-testid\n const dataAnnotate = el.getAttribute('data-annotate')\n const dataTestId = el.getAttribute('data-testid') || el.getAttribute('data-test') || el.getAttribute('data-cy')\n if (dataAnnotate) {\n parts.push(`[${dataAnnotate}]`)\n } else if (dataTestId) {\n parts.push(`[${dataTestId}]`)\n }\n\n // id\n if (el.id) {\n parts.push(`#${el.id}`)\n }\n\n // Meaningful classes (skip hashed ones, max 2)\n const classes = Array.from(el.classList)\n .filter((c) => !c.match(/^(sc-|css-)/) && !c.match(/^[a-zA-Z0-9]{8,}$/) && !c.match(/__[a-zA-Z0-9]{3,}$/))\n .slice(0, 2)\n if (classes.length) {\n parts.push(`.${classes.join('.')}`)\n }\n\n // Direct text content only (not nested)\n const directText = getDirectText(el)\n if (directText) {\n parts.push(`\"${directText}\"`)\n }\n\n return parts.join(' ')\n}\n\nfunction getDirectText(el: HTMLElement): string {\n let text = ''\n for (const node of Array.from(el.childNodes)) {\n if (node.nodeType === Node.TEXT_NODE) {\n text += node.textContent ?? ''\n }\n }\n text = text.trim()\n\n // Fallback: if no direct text and few children, use shallow textContent\n if (!text && el.children.length <= 2) {\n text = el.textContent?.trim() ?? ''\n }\n\n return text.slice(0, 30)\n}\n","interface ElementInfo {\n tag: string\n text: string\n}\n\ninterface DetailInfo extends ElementInfo {\n comment: string\n status: 'pending' | 'resolved'\n}\n\ninterface DetailCallbacks {\n onResolve: () => void\n onDelete: () => void\n onClose: () => void\n}\n\ninterface Position {\n top: number // absolute page Y below the element\n left: number // absolute page X\n anchorBottom: number // absolute page Y above the element (for flipping)\n}\n\nconst POPUP_WIDTH = 300\nconst POPUP_MARGIN = 8\n\nexport class Popup {\n private popupEl: HTMLElement | null = null\n private keyHandler: ((e: KeyboardEvent) => void) | null = null\n\n constructor(private container: HTMLElement) {}\n\n show(\n info: ElementInfo,\n position: Position,\n onSubmit: (comment: string) => void,\n onCancel: () => void,\n ): void {\n this.hide()\n\n const popup = document.createElement('div')\n popup.className = 'remarq-popup'\n\n const header = document.createElement('div')\n header.className = 'remarq-popup-header'\n header.textContent = `<${info.tag}>${info.text ? ` \"${info.text}\"` : ''}`\n\n const body = document.createElement('div')\n body.className = 'remarq-popup-body'\n\n const textarea = document.createElement('textarea')\n textarea.placeholder = 'Add your comment...'\n\n body.appendChild(textarea)\n\n const actions = document.createElement('div')\n actions.className = 'remarq-popup-actions'\n\n const cancelBtn = document.createElement('button')\n cancelBtn.textContent = 'Cancel'\n cancelBtn.addEventListener('click', () => {\n this.hide()\n onCancel()\n })\n\n const addBtn = document.createElement('button')\n addBtn.className = 'remarq-primary'\n addBtn.textContent = 'Add'\n addBtn.addEventListener('click', () => {\n const comment = textarea.value.trim()\n if (!comment) return\n this.hide()\n onSubmit(comment)\n })\n\n actions.appendChild(cancelBtn)\n actions.appendChild(addBtn)\n\n popup.appendChild(header)\n popup.appendChild(body)\n popup.appendChild(actions)\n\n this.container.appendChild(popup)\n this.popupEl = popup\n\n // Measure after layout, then position\n requestAnimationFrame(() => {\n this.adjustPosition(popup, position)\n textarea.focus()\n })\n\n // Cmd/Ctrl+Enter to submit\n this.keyHandler = (e: KeyboardEvent) => {\n if (e.key === 'Enter' && (e.metaKey || e.ctrlKey)) {\n const comment = textarea.value.trim()\n if (!comment) return\n this.hide()\n onSubmit(comment)\n }\n if (e.key === 'Escape') {\n this.hide()\n onCancel()\n }\n }\n document.addEventListener('keydown', this.keyHandler)\n }\n\n showDetail(\n info: DetailInfo,\n position: Position,\n callbacks: DetailCallbacks,\n ): void {\n this.hide()\n\n const popup = document.createElement('div')\n popup.className = 'remarq-popup'\n\n const header = document.createElement('div')\n header.className = 'remarq-popup-header'\n header.textContent = `<${info.tag}>${info.text ? ` \"${info.text}\"` : ''} [${info.status}]`\n\n const body = document.createElement('div')\n body.className = 'remarq-popup-body'\n body.textContent = info.comment\n\n const actions = document.createElement('div')\n actions.className = 'remarq-popup-actions'\n\n if (info.status === 'pending') {\n const resolveBtn = document.createElement('button')\n resolveBtn.className = 'remarq-primary'\n resolveBtn.textContent = 'Resolve'\n resolveBtn.addEventListener('click', () => {\n this.hide()\n callbacks.onResolve()\n })\n actions.appendChild(resolveBtn)\n }\n\n const deleteBtn = document.createElement('button')\n deleteBtn.textContent = 'Delete'\n deleteBtn.addEventListener('click', () => {\n this.hide()\n callbacks.onDelete()\n })\n actions.appendChild(deleteBtn)\n\n const closeBtn = document.createElement('button')\n closeBtn.textContent = 'Close'\n closeBtn.addEventListener('click', () => {\n this.hide()\n callbacks.onClose()\n })\n actions.appendChild(closeBtn)\n\n popup.appendChild(header)\n popup.appendChild(body)\n popup.appendChild(actions)\n\n this.container.appendChild(popup)\n this.popupEl = popup\n\n // Measure after layout, then position\n requestAnimationFrame(() => {\n this.adjustPosition(popup, position)\n })\n\n this.keyHandler = (e: KeyboardEvent) => {\n if (e.key === 'Escape') {\n this.hide()\n callbacks.onClose()\n }\n }\n document.addEventListener('keydown', this.keyHandler)\n }\n\n hide(): void {\n if (this.popupEl) {\n this.popupEl.remove()\n this.popupEl = null\n }\n if (this.keyHandler) {\n document.removeEventListener('keydown', this.keyHandler)\n this.keyHandler = null\n }\n }\n\n destroy(): void {\n this.hide()\n }\n\n private adjustPosition(popup: HTMLElement, position: Position): void {\n const popupHeight = popup.offsetHeight\n const viewportBottom = window.scrollY + window.innerHeight\n const viewportRight = window.scrollX + window.innerWidth\n\n let top = position.top\n let left = position.left\n\n // Flip above element if overflows viewport bottom\n if (top + popupHeight > viewportBottom - POPUP_MARGIN) {\n top = position.anchorBottom - popupHeight\n }\n\n // Clamp: don't go above visible area\n if (top < window.scrollY + POPUP_MARGIN) {\n top = window.scrollY + POPUP_MARGIN\n }\n\n // Clamp right edge\n if (left + POPUP_WIDTH > viewportRight - POPUP_MARGIN) {\n left = viewportRight - POPUP_WIDTH - POPUP_MARGIN\n }\n\n // Clamp left edge\n if (left < window.scrollX + POPUP_MARGIN) {\n left = window.scrollX + POPUP_MARGIN\n }\n\n popup.style.top = `${top}px`\n popup.style.left = `${left}px`\n }\n}\n","import type { Annotation } from '../core/types'\n\ninterface MarkerEntry {\n annotation: Annotation\n target: HTMLElement\n markerEl: HTMLElement\n}\n\nexport class MarkerManager {\n private markers = new Map<string, MarkerEntry>()\n private rafId: number | null = null\n private counter = 0\n\n constructor(\n private container: HTMLElement,\n private onClick?: (annotationId: string) => void,\n ) {\n this.startPositionLoop()\n }\n\n addMarker(annotation: Annotation, target: HTMLElement): void {\n this.counter++\n const markerEl = document.createElement('div')\n markerEl.className = 'remarq-marker'\n markerEl.setAttribute('data-status', annotation.status)\n markerEl.setAttribute('data-annotation-id', annotation.id)\n markerEl.textContent = String(this.counter)\n markerEl.title = annotation.comment\n\n markerEl.addEventListener('click', () => {\n this.onClick?.(annotation.id)\n })\n\n this.container.appendChild(markerEl)\n this.markers.set(annotation.id, { annotation, target, markerEl })\n this.updatePosition(annotation.id)\n }\n\n removeMarker(id: string): void {\n const entry = this.markers.get(id)\n if (entry) {\n entry.markerEl.remove()\n this.markers.delete(id)\n }\n }\n\n updateStatus(id: string, status: 'pending' | 'resolved'): void {\n const entry = this.markers.get(id)\n if (entry) {\n entry.annotation.status = status\n entry.markerEl.setAttribute('data-status', status)\n }\n }\n\n clear(): void {\n for (const entry of this.markers.values()) {\n entry.markerEl.remove()\n }\n this.markers.clear()\n this.counter = 0\n }\n\n destroy(): void {\n if (this.rafId !== null) {\n cancelAnimationFrame(this.rafId)\n this.rafId = null\n }\n this.clear()\n }\n\n private updatePosition(id: string): void {\n const entry = this.markers.get(id)\n if (!entry) return\n try {\n const rect = entry.target.getBoundingClientRect()\n entry.markerEl.style.top = `${window.scrollY + rect.top - 12}px`\n entry.markerEl.style.left = `${window.scrollX + rect.right - 12}px`\n } catch {\n // element may have been removed\n }\n }\n\n private startPositionLoop(): void {\n const update = () => {\n for (const id of this.markers.keys()) {\n this.updatePosition(id)\n }\n this.rafId = requestAnimationFrame(update)\n }\n this.rafId = requestAnimationFrame(update)\n }\n}\n","import type { Annotation } from '../core/types'\n\nexport class DetachedPanel {\n private panelEl: HTMLElement | null = null\n\n constructor(\n private container: HTMLElement,\n private onDelete?: (id: string) => void,\n ) {}\n\n update(annotations: Annotation[]): void {\n this.remove()\n if (annotations.length === 0) return\n\n const panel = document.createElement('div')\n panel.className = 'remarq-detached-panel'\n\n const header = document.createElement('div')\n header.className = 'remarq-detached-header'\n header.textContent = `Detached (${annotations.length})`\n panel.appendChild(header)\n\n for (const ann of annotations) {\n const item = document.createElement('div')\n item.className = 'remarq-detached-item'\n\n const info = document.createElement('div')\n info.className = 'remarq-detached-info'\n\n const comment = document.createElement('div')\n comment.className = 'remarq-detached-comment'\n comment.textContent = ann.comment\n\n const elDesc = document.createElement('div')\n elDesc.className = 'remarq-detached-element'\n const fp = ann.fingerprint\n let desc = `<${fp.tagName}>`\n if (fp.textContent) desc += ` \"${fp.textContent}\"`\n if (fp.dataAnnotate) desc += ` [${fp.dataAnnotate}]`\n elDesc.textContent = desc\n\n info.appendChild(comment)\n info.appendChild(elDesc)\n\n const deleteBtn = document.createElement('button')\n deleteBtn.className = 'remarq-detached-delete'\n deleteBtn.textContent = '\\u00d7'\n deleteBtn.addEventListener('click', () => {\n this.onDelete?.(ann.id)\n })\n\n item.appendChild(info)\n item.appendChild(deleteBtn)\n panel.appendChild(item)\n }\n\n this.container.appendChild(panel)\n this.panelEl = panel\n }\n\n destroy(): void {\n this.remove()\n }\n\n private remove(): void {\n if (this.panelEl) {\n this.panelEl.remove()\n this.panelEl = null\n }\n }\n}\n","type RouteChangeListener = (route: string) => void\n\nexport class RouteObserver {\n private listeners: Set<RouteChangeListener> = new Set()\n private originalPushState: typeof history.pushState\n private originalReplaceState: typeof history.replaceState\n private boundOnPopState: () => void\n private boundOnHashChange: () => void\n\n constructor() {\n this.originalPushState = history.pushState.bind(history)\n this.originalReplaceState = history.replaceState.bind(history)\n this.boundOnPopState = () => this.notify()\n this.boundOnHashChange = () => this.notify()\n\n this.patchHistory()\n\n window.addEventListener('popstate', this.boundOnPopState)\n window.addEventListener('hashchange', this.boundOnHashChange)\n }\n\n currentRoute(): string {\n return location.pathname + location.hash\n }\n\n onChange(listener: RouteChangeListener): () => void {\n this.listeners.add(listener)\n return () => {\n this.listeners.delete(listener)\n }\n }\n\n destroy(): void {\n window.removeEventListener('popstate', this.boundOnPopState)\n window.removeEventListener('hashchange', this.boundOnHashChange)\n history.pushState = this.originalPushState\n history.replaceState = this.originalReplaceState\n this.listeners.clear()\n }\n\n private notify(): void {\n const route = this.currentRoute()\n for (const listener of this.listeners) {\n listener(route)\n }\n }\n\n private patchHistory(): void {\n const self = this\n\n history.pushState = function (...args: Parameters<typeof history.pushState>) {\n self.originalPushState.apply(this, args)\n self.notify()\n }\n\n history.replaceState = function (...args: Parameters<typeof history.replaceState>) {\n self.originalReplaceState.apply(this, args)\n self.notify()\n }\n }\n}\n","import type { Annotation, ImportResult, WebRemarqOptions } from './core/types'\nimport { AnnotationStorage } from './core/storage'\nimport { createFingerprint } from './core/fingerprint'\nimport { matchElement } from './core/matcher'\nimport { injectStyles, removeStyles } from './ui/styles'\nimport { ThemeManager } from './ui/theme'\nimport { Toolbar } from './ui/toolbar'\nimport { Overlay } from './ui/overlay'\nimport { Popup } from './ui/popup'\nimport { MarkerManager } from './ui/markers'\nimport { DetachedPanel } from './ui/detached-panel'\nimport { RouteObserver } from './spa'\n\nlet initialized = false\nlet options: WebRemarqOptions = {}\nlet storage: AnnotationStorage\nlet themeManager: ThemeManager\nlet toolbar: Toolbar\nlet overlay: Overlay\nlet popup: Popup\nlet markers: MarkerManager\nlet detachedPanel: DetachedPanel\nlet routeObserver: RouteObserver\nlet inspecting = false\nlet mutationObserver: MutationObserver | null = null\nlet unsubRoute: (() => void) | null = null\nlet refreshScheduled = false\n\n// WeakRef cache: annotation id → element (survives GC of element)\nconst elementCache = new Map<string, WeakRef<HTMLElement>>()\n\nfunction describeTarget(el: HTMLElement): string {\n const parts: string[] = []\n\n // id\n if (el.id) parts.push(`#${el.id}`)\n\n // data attributes\n const dataAnnotate = el.getAttribute(options.dataAttribute ?? 'data-annotate')\n const dataTestId = el.getAttribute('data-testid') || el.getAttribute('data-test') || el.getAttribute('data-cy')\n if (dataAnnotate) parts.push(`[${dataAnnotate}]`)\n else if (dataTestId) parts.push(`[${dataTestId}]`)\n\n // Meaningful classes (max 2)\n const classes = Array.from(el.classList)\n .filter((c) => !c.match(/^(sc-|css-)/) && !c.match(/^[a-zA-Z0-9]{8,}$/) && !c.match(/__[a-zA-Z0-9]{3,}$/))\n .slice(0, 2)\n if (classes.length) parts.push(`.${classes.join('.')}`)\n\n // Direct text only\n let text = ''\n for (const node of Array.from(el.childNodes)) {\n if (node.nodeType === Node.TEXT_NODE) text += node.textContent ?? ''\n }\n text = text.trim()\n if (!text && el.children.length <= 2) text = el.textContent?.trim() ?? ''\n if (text) parts.push(`\"${text.slice(0, 30)}\"`)\n\n return parts.join(' ') || ''\n}\n\nfunction currentRoute(): string {\n return location.pathname + location.hash\n}\n\nfunction generateId(): string {\n return `ann-${Date.now()}-${Math.random().toString(36).slice(2, 8)}`\n}\n\nfunction cacheElement(annotationId: string, el: HTMLElement): void {\n elementCache.set(annotationId, new WeakRef(el))\n}\n\nfunction getCachedElement(annotationId: string): HTMLElement | null {\n const ref = elementCache.get(annotationId)\n if (!ref) return null\n const el = ref.deref()\n if (!el || !el.isConnected) {\n elementCache.delete(annotationId)\n return null\n }\n return el\n}\n\nfunction resolveElement(ann: Annotation): HTMLElement | null {\n // 1. Check cache first\n const cached = getCachedElement(ann.id)\n if (cached) return cached\n\n // 2. Fall back to fingerprint matching\n const el = matchElement(ann.fingerprint, { dataAttribute: options.dataAttribute })\n if (el) {\n cacheElement(ann.id, el)\n console.debug(`[web-remarq] Matched \"${ann.comment}\" via fingerprint on <${el.tagName.toLowerCase()}>`)\n } else {\n console.debug(`[web-remarq] Could not match \"${ann.comment}\"`, ann.fingerprint)\n }\n return el\n}\n\nfunction refreshMarkers(): void {\n markers.clear()\n const detached: Annotation[] = []\n const route = currentRoute()\n const anns = storage.getByRoute(route)\n\n for (const ann of anns) {\n const el = resolveElement(ann)\n if (el) {\n markers.addMarker(ann, el)\n } else {\n detached.push(ann)\n }\n }\n\n detachedPanel.update(detached)\n\n const pendingCount = anns.filter((a) => a.status === 'pending').length\n toolbar.setBadgeCount(pendingCount)\n}\n\n// Debounced refresh — MutationObserver can fire rapidly\nfunction scheduleRefresh(): void {\n if (refreshScheduled) return\n refreshScheduled = true\n requestAnimationFrame(() => {\n refreshScheduled = false\n refreshMarkers()\n })\n}\n\nfunction handleInspectClick(e: MouseEvent): void {\n if (!inspecting) return\n\n const target = e.target as HTMLElement\n if (!target || target.closest('[data-remarq-theme]')) return\n\n e.preventDefault()\n e.stopPropagation()\n\n overlay.hide()\n setInspecting(false)\n\n const rect = target.getBoundingClientRect()\n popup.show(\n {\n tag: target.tagName.toLowerCase(),\n text: describeTarget(target),\n },\n {\n top: window.scrollY + rect.bottom + 8,\n left: window.scrollX + rect.left,\n anchorBottom: window.scrollY + rect.top - 8,\n },\n (comment) => {\n const fp = createFingerprint(target, {\n classFilter: options.classFilter,\n dataAttribute: options.dataAttribute,\n })\n const ann: Annotation = {\n id: generateId(),\n comment,\n fingerprint: fp,\n route: currentRoute(),\n timestamp: Date.now(),\n status: 'pending',\n }\n // Cache the element immediately — no need to re-match\n cacheElement(ann.id, target)\n storage.add(ann)\n refreshMarkers()\n },\n () => {\n // cancel\n },\n )\n}\n\nfunction handleInspectHover(e: MouseEvent): void {\n if (!inspecting) return\n const target = e.target as HTMLElement\n if (!target || target.closest('[data-remarq-theme]')) return\n overlay.show(target)\n overlay.updateTooltipPosition(e.clientX, e.clientY)\n}\n\nfunction handleInspectKeydown(e: KeyboardEvent): void {\n if (e.key === 'Escape' && inspecting) {\n setInspecting(false)\n overlay.hide()\n }\n}\n\nfunction setInspecting(value: boolean): void {\n inspecting = value\n toolbar.setInspectActive(value)\n if (!value) overlay.hide()\n}\n\nfunction handleMarkerClick(annotationId: string): void {\n const ann = storage.getAll().find((a) => a.id === annotationId)\n if (!ann) return\n\n const el = resolveElement(ann)\n if (!el) return\n\n const rect = el.getBoundingClientRect()\n\n popup.showDetail(\n {\n tag: ann.fingerprint.tagName,\n text: ann.fingerprint.textContent ?? '',\n comment: ann.comment,\n status: ann.status,\n },\n {\n top: window.scrollY + rect.bottom + 8,\n left: window.scrollX + rect.left,\n anchorBottom: window.scrollY + rect.top - 8,\n },\n {\n onResolve: () => {\n storage.update(ann.id, { status: 'resolved' })\n refreshMarkers()\n },\n onDelete: () => {\n elementCache.delete(ann.id)\n storage.remove(ann.id)\n refreshMarkers()\n },\n onClose: () => {},\n },\n )\n}\n\nfunction exportMarkdown(): void {\n const route = currentRoute()\n const anns = storage.getByRoute(route)\n if (!anns.length) return\n\n const lines = [`## Annotations — ${route} (${anns.length})`, '']\n anns.forEach((ann, i) => {\n const fp = ann.fingerprint\n let desc = `<${fp.tagName}>`\n if (fp.textContent) desc += ` \"${fp.textContent}\"`\n if (fp.parentAnchor) desc += ` (${fp.parentAnchor})`\n if (fp.dataAnnotate) desc += fp.parentAnchor ? ` > ${fp.dataAnnotate}` : ` (${fp.dataAnnotate})`\n lines.push(`${i + 1}. [${ann.status}] ${desc}: \"${ann.comment}\"`)\n })\n\n const text = lines.join('\\n')\n try {\n navigator.clipboard.writeText(text)\n } catch {\n console.warn('[web-remarq] Clipboard write failed')\n }\n}\n\nfunction exportJSON(): void {\n const data = storage.exportJSON()\n const json = JSON.stringify(data, null, 2)\n const blob = new Blob([json], { type: 'application/json' })\n const url = URL.createObjectURL(blob)\n const a = document.createElement('a')\n a.href = url\n a.download = `remarq-annotations-${Date.now()}.json`\n a.click()\n URL.revokeObjectURL(url)\n}\n\nfunction setupMutationObserver(): void {\n mutationObserver = new MutationObserver((mutations) => {\n for (const m of mutations) {\n if (m.target instanceof HTMLElement && m.target.closest('[data-remarq-theme]')) return\n }\n scheduleRefresh()\n })\n\n mutationObserver.observe(document.body, {\n childList: true,\n subtree: true,\n attributes: true,\n attributeFilter: ['id', 'class', 'data-annotate', 'data-testid', 'data-test', 'data-cy'],\n })\n}\n\nexport const WebRemarq = {\n init(opts?: WebRemarqOptions): void {\n if (initialized) return\n options = opts ?? {}\n\n try {\n injectStyles()\n storage = new AnnotationStorage()\n themeManager = new ThemeManager(document.body, options.theme)\n overlay = new Overlay(themeManager.container)\n popup = new Popup(themeManager.container)\n markers = new MarkerManager(themeManager.container, handleMarkerClick)\n detachedPanel = new DetachedPanel(themeManager.container, (id) => {\n elementCache.delete(id)\n storage.remove(id)\n refreshMarkers()\n })\n\n toolbar = new Toolbar(themeManager.container, {\n onInspect: () => setInspecting(!inspecting),\n onExportMd: exportMarkdown,\n onExportJson: exportJSON,\n onImport: () => {\n const file = toolbar.getFileInput().files?.[0]\n if (file) {\n WebRemarq.import(file)\n }\n },\n onClear: () => {\n elementCache.clear()\n storage.clearAll()\n refreshMarkers()\n },\n onThemeToggle: () => themeManager.toggle(),\n })\n\n if (storage.isMemoryOnly) {\n toolbar.setMemoryWarning(true)\n }\n\n routeObserver = new RouteObserver()\n unsubRoute = routeObserver.onChange(() => refreshMarkers())\n\n document.addEventListener('click', handleInspectClick, true)\n document.addEventListener('mousemove', handleInspectHover)\n document.addEventListener('keydown', handleInspectKeydown)\n\n setupMutationObserver()\n\n console.debug(`[web-remarq] Initialized on route: ${currentRoute()}`)\n refreshMarkers()\n initialized = true\n } catch (err) {\n console.error('[web-remarq] Init failed:', err)\n }\n },\n\n destroy(): void {\n if (!initialized) return\n try {\n document.removeEventListener('click', handleInspectClick, true)\n document.removeEventListener('mousemove', handleInspectHover)\n document.removeEventListener('keydown', handleInspectKeydown)\n mutationObserver?.disconnect()\n mutationObserver = null\n unsubRoute?.()\n routeObserver?.destroy()\n markers?.destroy()\n detachedPanel?.destroy()\n popup?.destroy()\n overlay?.destroy()\n toolbar?.destroy()\n themeManager?.destroy()\n removeStyles()\n elementCache.clear()\n inspecting = false\n initialized = false\n } catch (err) {\n console.error('[web-remarq] Destroy failed:', err)\n }\n },\n\n setTheme(theme: 'light' | 'dark'): void {\n themeManager?.setTheme(theme)\n },\n\n export(format: 'md' | 'json'): void {\n if (format === 'md') exportMarkdown()\n else exportJSON()\n },\n\n async import(file: File): Promise<ImportResult> {\n const text = await file.text()\n const data = JSON.parse(text)\n storage.importJSON(data)\n refreshMarkers()\n\n const allAnns = storage.getAll()\n let matched = 0\n let detached = 0\n for (const ann of allAnns) {\n if (resolveElement(ann)) {\n matched++\n } else {\n detached++\n }\n }\n return { total: allAnns.length, matched, detached }\n },\n\n getAnnotations(route?: string): Annotation[] {\n if (!storage) return []\n return route ? storage.getByRoute(route) : storage.getAll()\n },\n\n clearAll(): void {\n elementCache.clear()\n storage?.clearAll()\n if (initialized) refreshMarkers()\n },\n}\n"],"mappings":"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","names":["options","parent","buildDomPath","options","e","popup"]}
@@ -187,8 +187,17 @@ var WebRemarq = (() => {
187
187
  return id;
188
188
  }
189
189
  function getTextContent(el) {
190
- var _a, _b;
191
- const text = (_b = (_a = el.textContent) == null ? void 0 : _a.trim()) != null ? _b : null;
190
+ var _a, _b, _c;
191
+ let text = "";
192
+ for (const node of Array.from(el.childNodes)) {
193
+ if (node.nodeType === Node.TEXT_NODE) {
194
+ text += (_a = node.textContent) != null ? _a : "";
195
+ }
196
+ }
197
+ text = text.trim();
198
+ if (!text && el.children.length <= 3) {
199
+ text = (_c = (_b = el.textContent) == null ? void 0 : _b.trim()) != null ? _c : "";
200
+ }
192
201
  if (!text) return null;
193
202
  return text.length > TEXT_MAX_LENGTH ? text.slice(0, TEXT_MAX_LENGTH) : text;
194
203
  }
@@ -477,7 +486,7 @@ var WebRemarq = (() => {
477
486
  .remarq-marker[data-status="resolved"] { background: var(--remarq-resolved); opacity: 0.7; }
478
487
 
479
488
  .remarq-popup {
480
- position: fixed;
489
+ position: absolute;
481
490
  z-index: 2147483647;
482
491
  width: 300px;
483
492
  background: var(--remarq-bg);
@@ -819,7 +828,6 @@ var WebRemarq = (() => {
819
828
  container.appendChild(this.tooltipEl);
820
829
  }
821
830
  show(target) {
822
- var _a;
823
831
  try {
824
832
  const rect = target.getBoundingClientRect();
825
833
  this.overlayEl.style.display = "block";
@@ -827,13 +835,7 @@ var WebRemarq = (() => {
827
835
  this.overlayEl.style.left = `${rect.left}px`;
828
836
  this.overlayEl.style.width = `${rect.width}px`;
829
837
  this.overlayEl.style.height = `${rect.height}px`;
830
- const tag = target.tagName.toLowerCase();
831
- const text = ((_a = target.textContent) == null ? void 0 : _a.trim().slice(0, 30)) || "";
832
- const dataAnnotate = target.getAttribute("data-annotate");
833
- let label = `<${tag}>`;
834
- if (text) label += ` "${text}"`;
835
- if (dataAnnotate) label += ` [${dataAnnotate}]`;
836
- this.tooltipEl.textContent = label;
838
+ this.tooltipEl.textContent = describeElement(target);
837
839
  this.tooltipEl.style.display = "block";
838
840
  this.tooltipEl.style.top = `${rect.top - 28}px`;
839
841
  this.tooltipEl.style.left = `${rect.left}px`;
@@ -854,6 +856,43 @@ var WebRemarq = (() => {
854
856
  this.tooltipEl.remove();
855
857
  }
856
858
  };
859
+ function describeElement(el) {
860
+ const tag = el.tagName.toLowerCase();
861
+ const parts = [`<${tag}>`];
862
+ const dataAnnotate = el.getAttribute("data-annotate");
863
+ const dataTestId = el.getAttribute("data-testid") || el.getAttribute("data-test") || el.getAttribute("data-cy");
864
+ if (dataAnnotate) {
865
+ parts.push(`[${dataAnnotate}]`);
866
+ } else if (dataTestId) {
867
+ parts.push(`[${dataTestId}]`);
868
+ }
869
+ if (el.id) {
870
+ parts.push(`#${el.id}`);
871
+ }
872
+ const classes = Array.from(el.classList).filter((c) => !c.match(/^(sc-|css-)/) && !c.match(/^[a-zA-Z0-9]{8,}$/) && !c.match(/__[a-zA-Z0-9]{3,}$/)).slice(0, 2);
873
+ if (classes.length) {
874
+ parts.push(`.${classes.join(".")}`);
875
+ }
876
+ const directText = getDirectText(el);
877
+ if (directText) {
878
+ parts.push(`"${directText}"`);
879
+ }
880
+ return parts.join(" ");
881
+ }
882
+ function getDirectText(el) {
883
+ var _a, _b, _c;
884
+ let text = "";
885
+ for (const node of Array.from(el.childNodes)) {
886
+ if (node.nodeType === Node.TEXT_NODE) {
887
+ text += (_a = node.textContent) != null ? _a : "";
888
+ }
889
+ }
890
+ text = text.trim();
891
+ if (!text && el.children.length <= 2) {
892
+ text = (_c = (_b = el.textContent) == null ? void 0 : _b.trim()) != null ? _c : "";
893
+ }
894
+ return text.slice(0, 30);
895
+ }
857
896
 
858
897
  // src/ui/popup.ts
859
898
  var POPUP_WIDTH = 300;
@@ -900,7 +939,10 @@ var WebRemarq = (() => {
900
939
  popup2.appendChild(actions);
901
940
  this.container.appendChild(popup2);
902
941
  this.popupEl = popup2;
903
- this.adjustPosition(popup2, position);
942
+ requestAnimationFrame(() => {
943
+ this.adjustPosition(popup2, position);
944
+ textarea.focus();
945
+ });
904
946
  this.keyHandler = (e) => {
905
947
  if (e.key === "Enter" && (e.metaKey || e.ctrlKey)) {
906
948
  const comment = textarea.value.trim();
@@ -914,7 +956,6 @@ var WebRemarq = (() => {
914
956
  }
915
957
  };
916
958
  document.addEventListener("keydown", this.keyHandler);
917
- requestAnimationFrame(() => textarea.focus());
918
959
  }
919
960
  showDetail(info, position, callbacks) {
920
961
  this.hide();
@@ -957,7 +998,9 @@ var WebRemarq = (() => {
957
998
  popup2.appendChild(actions);
958
999
  this.container.appendChild(popup2);
959
1000
  this.popupEl = popup2;
960
- this.adjustPosition(popup2, position);
1001
+ requestAnimationFrame(() => {
1002
+ this.adjustPosition(popup2, position);
1003
+ });
961
1004
  this.keyHandler = (e) => {
962
1005
  if (e.key === "Escape") {
963
1006
  this.hide();
@@ -980,22 +1023,22 @@ var WebRemarq = (() => {
980
1023
  this.hide();
981
1024
  }
982
1025
  adjustPosition(popup2, position) {
983
- const popupRect = popup2.getBoundingClientRect();
984
- const viewH = window.innerHeight;
985
- const viewW = window.innerWidth;
1026
+ const popupHeight = popup2.offsetHeight;
1027
+ const viewportBottom = window.scrollY + window.innerHeight;
1028
+ const viewportRight = window.scrollX + window.innerWidth;
986
1029
  let top = position.top;
987
1030
  let left = position.left;
988
- if (top + popupRect.height > viewH - POPUP_MARGIN) {
989
- top = position.top - popupRect.height - 16;
1031
+ if (top + popupHeight > viewportBottom - POPUP_MARGIN) {
1032
+ top = position.anchorBottom - popupHeight;
990
1033
  }
991
- if (top < POPUP_MARGIN) {
992
- top = POPUP_MARGIN;
1034
+ if (top < window.scrollY + POPUP_MARGIN) {
1035
+ top = window.scrollY + POPUP_MARGIN;
993
1036
  }
994
- if (left + POPUP_WIDTH > viewW - POPUP_MARGIN) {
995
- left = viewW - POPUP_WIDTH - POPUP_MARGIN;
1037
+ if (left + POPUP_WIDTH > viewportRight - POPUP_MARGIN) {
1038
+ left = viewportRight - POPUP_WIDTH - POPUP_MARGIN;
996
1039
  }
997
- if (left < POPUP_MARGIN) {
998
- left = POPUP_MARGIN;
1040
+ if (left < window.scrollX + POPUP_MARGIN) {
1041
+ left = window.scrollX + POPUP_MARGIN;
999
1042
  }
1000
1043
  popup2.style.top = `${top}px`;
1001
1044
  popup2.style.left = `${left}px`;
@@ -1198,6 +1241,25 @@ var WebRemarq = (() => {
1198
1241
  var unsubRoute = null;
1199
1242
  var refreshScheduled = false;
1200
1243
  var elementCache = /* @__PURE__ */ new Map();
1244
+ function describeTarget(el) {
1245
+ var _a, _b, _c, _d;
1246
+ const parts = [];
1247
+ if (el.id) parts.push(`#${el.id}`);
1248
+ const dataAnnotate = el.getAttribute((_a = options.dataAttribute) != null ? _a : "data-annotate");
1249
+ const dataTestId = el.getAttribute("data-testid") || el.getAttribute("data-test") || el.getAttribute("data-cy");
1250
+ if (dataAnnotate) parts.push(`[${dataAnnotate}]`);
1251
+ else if (dataTestId) parts.push(`[${dataTestId}]`);
1252
+ const classes = Array.from(el.classList).filter((c) => !c.match(/^(sc-|css-)/) && !c.match(/^[a-zA-Z0-9]{8,}$/) && !c.match(/__[a-zA-Z0-9]{3,}$/)).slice(0, 2);
1253
+ if (classes.length) parts.push(`.${classes.join(".")}`);
1254
+ let text = "";
1255
+ for (const node of Array.from(el.childNodes)) {
1256
+ if (node.nodeType === Node.TEXT_NODE) text += (_b = node.textContent) != null ? _b : "";
1257
+ }
1258
+ text = text.trim();
1259
+ if (!text && el.children.length <= 2) text = (_d = (_c = el.textContent) == null ? void 0 : _c.trim()) != null ? _d : "";
1260
+ if (text) parts.push(`"${text.slice(0, 30)}"`);
1261
+ return parts.join(" ") || "";
1262
+ }
1201
1263
  function currentRoute() {
1202
1264
  return location.pathname + location.hash;
1203
1265
  }
@@ -1255,7 +1317,6 @@ var WebRemarq = (() => {
1255
1317
  });
1256
1318
  }
1257
1319
  function handleInspectClick(e) {
1258
- var _a, _b;
1259
1320
  if (!inspecting) return;
1260
1321
  const target = e.target;
1261
1322
  if (!target || target.closest("[data-remarq-theme]")) return;
@@ -1267,11 +1328,12 @@ var WebRemarq = (() => {
1267
1328
  popup.show(
1268
1329
  {
1269
1330
  tag: target.tagName.toLowerCase(),
1270
- text: (_b = (_a = target.textContent) == null ? void 0 : _a.trim().slice(0, 30)) != null ? _b : ""
1331
+ text: describeTarget(target)
1271
1332
  },
1272
1333
  {
1273
- top: rect.bottom + 8,
1274
- left: rect.left
1334
+ top: window.scrollY + rect.bottom + 8,
1335
+ left: window.scrollX + rect.left,
1336
+ anchorBottom: window.scrollY + rect.top - 8
1275
1337
  },
1276
1338
  (comment) => {
1277
1339
  const fp = createFingerprint(target, {
@@ -1326,7 +1388,11 @@ var WebRemarq = (() => {
1326
1388
  comment: ann.comment,
1327
1389
  status: ann.status
1328
1390
  },
1329
- { top: rect.bottom + 8, left: rect.left },
1391
+ {
1392
+ top: window.scrollY + rect.bottom + 8,
1393
+ left: window.scrollX + rect.left,
1394
+ anchorBottom: window.scrollY + rect.top - 8
1395
+ },
1330
1396
  {
1331
1397
  onResolve: () => {
1332
1398
  storage.update(ann.id, { status: "resolved" });