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.
@@ -1 +1 @@
1
- {"version":3,"sources":["../src/index.ts","../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":["export { WebRemarq } from './web-remarq'\nexport type { Annotation, AnnotationStore, ElementFingerprint, WebRemarqOptions, ImportResult } from './core/types'\n","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":"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","names":["options","parent","buildDomPath","options","e","popup"]}
1
+ {"version":3,"sources":["../src/index.ts","../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":["export { WebRemarq } from './web-remarq'\nexport type { Annotation, AnnotationStore, ElementFingerprint, WebRemarqOptions, ImportResult } from './core/types'\n","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"]}
package/dist/index.js CHANGED
@@ -164,8 +164,17 @@ function getStableId(el) {
164
164
  return id;
165
165
  }
166
166
  function getTextContent(el) {
167
- var _a, _b;
168
- const text = (_b = (_a = el.textContent) == null ? void 0 : _a.trim()) != null ? _b : null;
167
+ var _a, _b, _c;
168
+ let text = "";
169
+ for (const node of Array.from(el.childNodes)) {
170
+ if (node.nodeType === Node.TEXT_NODE) {
171
+ text += (_a = node.textContent) != null ? _a : "";
172
+ }
173
+ }
174
+ text = text.trim();
175
+ if (!text && el.children.length <= 3) {
176
+ text = (_c = (_b = el.textContent) == null ? void 0 : _b.trim()) != null ? _c : "";
177
+ }
169
178
  if (!text) return null;
170
179
  return text.length > TEXT_MAX_LENGTH ? text.slice(0, TEXT_MAX_LENGTH) : text;
171
180
  }
@@ -454,7 +463,7 @@ var CSS = `
454
463
  .remarq-marker[data-status="resolved"] { background: var(--remarq-resolved); opacity: 0.7; }
455
464
 
456
465
  .remarq-popup {
457
- position: fixed;
466
+ position: absolute;
458
467
  z-index: 2147483647;
459
468
  width: 300px;
460
469
  background: var(--remarq-bg);
@@ -796,7 +805,6 @@ var Overlay = class {
796
805
  container.appendChild(this.tooltipEl);
797
806
  }
798
807
  show(target) {
799
- var _a;
800
808
  try {
801
809
  const rect = target.getBoundingClientRect();
802
810
  this.overlayEl.style.display = "block";
@@ -804,13 +812,7 @@ var Overlay = class {
804
812
  this.overlayEl.style.left = `${rect.left}px`;
805
813
  this.overlayEl.style.width = `${rect.width}px`;
806
814
  this.overlayEl.style.height = `${rect.height}px`;
807
- const tag = target.tagName.toLowerCase();
808
- const text = ((_a = target.textContent) == null ? void 0 : _a.trim().slice(0, 30)) || "";
809
- const dataAnnotate = target.getAttribute("data-annotate");
810
- let label = `<${tag}>`;
811
- if (text) label += ` "${text}"`;
812
- if (dataAnnotate) label += ` [${dataAnnotate}]`;
813
- this.tooltipEl.textContent = label;
815
+ this.tooltipEl.textContent = describeElement(target);
814
816
  this.tooltipEl.style.display = "block";
815
817
  this.tooltipEl.style.top = `${rect.top - 28}px`;
816
818
  this.tooltipEl.style.left = `${rect.left}px`;
@@ -831,6 +833,43 @@ var Overlay = class {
831
833
  this.tooltipEl.remove();
832
834
  }
833
835
  };
836
+ function describeElement(el) {
837
+ const tag = el.tagName.toLowerCase();
838
+ const parts = [`<${tag}>`];
839
+ const dataAnnotate = el.getAttribute("data-annotate");
840
+ const dataTestId = el.getAttribute("data-testid") || el.getAttribute("data-test") || el.getAttribute("data-cy");
841
+ if (dataAnnotate) {
842
+ parts.push(`[${dataAnnotate}]`);
843
+ } else if (dataTestId) {
844
+ parts.push(`[${dataTestId}]`);
845
+ }
846
+ if (el.id) {
847
+ parts.push(`#${el.id}`);
848
+ }
849
+ 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);
850
+ if (classes.length) {
851
+ parts.push(`.${classes.join(".")}`);
852
+ }
853
+ const directText = getDirectText(el);
854
+ if (directText) {
855
+ parts.push(`"${directText}"`);
856
+ }
857
+ return parts.join(" ");
858
+ }
859
+ function getDirectText(el) {
860
+ var _a, _b, _c;
861
+ let text = "";
862
+ for (const node of Array.from(el.childNodes)) {
863
+ if (node.nodeType === Node.TEXT_NODE) {
864
+ text += (_a = node.textContent) != null ? _a : "";
865
+ }
866
+ }
867
+ text = text.trim();
868
+ if (!text && el.children.length <= 2) {
869
+ text = (_c = (_b = el.textContent) == null ? void 0 : _b.trim()) != null ? _c : "";
870
+ }
871
+ return text.slice(0, 30);
872
+ }
834
873
 
835
874
  // src/ui/popup.ts
836
875
  var POPUP_WIDTH = 300;
@@ -877,7 +916,10 @@ var Popup = class {
877
916
  popup2.appendChild(actions);
878
917
  this.container.appendChild(popup2);
879
918
  this.popupEl = popup2;
880
- this.adjustPosition(popup2, position);
919
+ requestAnimationFrame(() => {
920
+ this.adjustPosition(popup2, position);
921
+ textarea.focus();
922
+ });
881
923
  this.keyHandler = (e) => {
882
924
  if (e.key === "Enter" && (e.metaKey || e.ctrlKey)) {
883
925
  const comment = textarea.value.trim();
@@ -891,7 +933,6 @@ var Popup = class {
891
933
  }
892
934
  };
893
935
  document.addEventListener("keydown", this.keyHandler);
894
- requestAnimationFrame(() => textarea.focus());
895
936
  }
896
937
  showDetail(info, position, callbacks) {
897
938
  this.hide();
@@ -934,7 +975,9 @@ var Popup = class {
934
975
  popup2.appendChild(actions);
935
976
  this.container.appendChild(popup2);
936
977
  this.popupEl = popup2;
937
- this.adjustPosition(popup2, position);
978
+ requestAnimationFrame(() => {
979
+ this.adjustPosition(popup2, position);
980
+ });
938
981
  this.keyHandler = (e) => {
939
982
  if (e.key === "Escape") {
940
983
  this.hide();
@@ -957,22 +1000,22 @@ var Popup = class {
957
1000
  this.hide();
958
1001
  }
959
1002
  adjustPosition(popup2, position) {
960
- const popupRect = popup2.getBoundingClientRect();
961
- const viewH = window.innerHeight;
962
- const viewW = window.innerWidth;
1003
+ const popupHeight = popup2.offsetHeight;
1004
+ const viewportBottom = window.scrollY + window.innerHeight;
1005
+ const viewportRight = window.scrollX + window.innerWidth;
963
1006
  let top = position.top;
964
1007
  let left = position.left;
965
- if (top + popupRect.height > viewH - POPUP_MARGIN) {
966
- top = position.top - popupRect.height - 16;
1008
+ if (top + popupHeight > viewportBottom - POPUP_MARGIN) {
1009
+ top = position.anchorBottom - popupHeight;
967
1010
  }
968
- if (top < POPUP_MARGIN) {
969
- top = POPUP_MARGIN;
1011
+ if (top < window.scrollY + POPUP_MARGIN) {
1012
+ top = window.scrollY + POPUP_MARGIN;
970
1013
  }
971
- if (left + POPUP_WIDTH > viewW - POPUP_MARGIN) {
972
- left = viewW - POPUP_WIDTH - POPUP_MARGIN;
1014
+ if (left + POPUP_WIDTH > viewportRight - POPUP_MARGIN) {
1015
+ left = viewportRight - POPUP_WIDTH - POPUP_MARGIN;
973
1016
  }
974
- if (left < POPUP_MARGIN) {
975
- left = POPUP_MARGIN;
1017
+ if (left < window.scrollX + POPUP_MARGIN) {
1018
+ left = window.scrollX + POPUP_MARGIN;
976
1019
  }
977
1020
  popup2.style.top = `${top}px`;
978
1021
  popup2.style.left = `${left}px`;
@@ -1175,6 +1218,25 @@ var mutationObserver = null;
1175
1218
  var unsubRoute = null;
1176
1219
  var refreshScheduled = false;
1177
1220
  var elementCache = /* @__PURE__ */ new Map();
1221
+ function describeTarget(el) {
1222
+ var _a, _b, _c, _d;
1223
+ const parts = [];
1224
+ if (el.id) parts.push(`#${el.id}`);
1225
+ const dataAnnotate = el.getAttribute((_a = options.dataAttribute) != null ? _a : "data-annotate");
1226
+ const dataTestId = el.getAttribute("data-testid") || el.getAttribute("data-test") || el.getAttribute("data-cy");
1227
+ if (dataAnnotate) parts.push(`[${dataAnnotate}]`);
1228
+ else if (dataTestId) parts.push(`[${dataTestId}]`);
1229
+ 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);
1230
+ if (classes.length) parts.push(`.${classes.join(".")}`);
1231
+ let text = "";
1232
+ for (const node of Array.from(el.childNodes)) {
1233
+ if (node.nodeType === Node.TEXT_NODE) text += (_b = node.textContent) != null ? _b : "";
1234
+ }
1235
+ text = text.trim();
1236
+ if (!text && el.children.length <= 2) text = (_d = (_c = el.textContent) == null ? void 0 : _c.trim()) != null ? _d : "";
1237
+ if (text) parts.push(`"${text.slice(0, 30)}"`);
1238
+ return parts.join(" ") || "";
1239
+ }
1178
1240
  function currentRoute() {
1179
1241
  return location.pathname + location.hash;
1180
1242
  }
@@ -1232,7 +1294,6 @@ function scheduleRefresh() {
1232
1294
  });
1233
1295
  }
1234
1296
  function handleInspectClick(e) {
1235
- var _a, _b;
1236
1297
  if (!inspecting) return;
1237
1298
  const target = e.target;
1238
1299
  if (!target || target.closest("[data-remarq-theme]")) return;
@@ -1244,11 +1305,12 @@ function handleInspectClick(e) {
1244
1305
  popup.show(
1245
1306
  {
1246
1307
  tag: target.tagName.toLowerCase(),
1247
- text: (_b = (_a = target.textContent) == null ? void 0 : _a.trim().slice(0, 30)) != null ? _b : ""
1308
+ text: describeTarget(target)
1248
1309
  },
1249
1310
  {
1250
- top: rect.bottom + 8,
1251
- left: rect.left
1311
+ top: window.scrollY + rect.bottom + 8,
1312
+ left: window.scrollX + rect.left,
1313
+ anchorBottom: window.scrollY + rect.top - 8
1252
1314
  },
1253
1315
  (comment) => {
1254
1316
  const fp = createFingerprint(target, {
@@ -1303,7 +1365,11 @@ function handleMarkerClick(annotationId) {
1303
1365
  comment: ann.comment,
1304
1366
  status: ann.status
1305
1367
  },
1306
- { top: rect.bottom + 8, left: rect.left },
1368
+ {
1369
+ top: window.scrollY + rect.bottom + 8,
1370
+ left: window.scrollX + rect.left,
1371
+ anchorBottom: window.scrollY + rect.top - 8
1372
+ },
1307
1373
  {
1308
1374
  onResolve: () => {
1309
1375
  storage.update(ann.id, { status: "resolved" });