@merittdev/horus-lens 0.4.0 → 0.5.1

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.
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../../browser/src/index.ts","../../browser/src/gate.ts","../../browser/src/overlay/env.ts","../../browser/src/overlay/dom.ts","../../browser/src/overlay/draggable.ts","../../browser/src/overlay/geometry.ts","../../browser/src/overlay/icons.ts","../../browser/src/overlay/annotation-editor.ts","../../browser/src/overlay/panel.ts","../../browser/src/overlay/picker.ts","../../browser/src/overlay/styles.ts","../../browser/src/overlay/overlay.ts","../../browser/src/queue.ts","../../browser/src/snippet.ts"],"sourcesContent":["import { LensClient, type LensConfig } from '@horus-lens/core';\nimport { clearGate, DEFAULT_PARAM_NAME, evaluateGate, isGateActive } from './gate.js';\nimport { detectBrowser, detectOs, currentRoute, viewport } from './overlay/env.js';\nimport { mountOverlay, type OverlayHandle, type OverlayStats } from './overlay/index.js';\nimport { applyContext, installGlobal, processQueue, type QueuedCommands } from './queue.js';\n\nexport interface BootOptions extends Partial<Omit<LensConfig, 'accessId'>> {\n /** Falls back to a `<script data-lens-id>` attribute or a queued `init` call. */\n accessId?: string;\n /** Query param that gates activation. Default `'lens'` → `?lens=true`. */\n paramName?: string;\n /** Bypass the query-param gate (preview envs / the React provider). */\n force?: boolean;\n}\n\nexport interface LensBrowser {\n client: LensClient;\n /** Open the report panel. */\n open(): void;\n /** Close the report panel (overlay stays mounted). */\n close(): void;\n /** Remove the overlay, stop the client, and clear gate persistence. */\n destroy(): void;\n}\n\nexport { isGateActive } from './gate.js';\nexport { loaderSnippet, LOADER_SNIPPET, DEFAULT_CDN_URL } from './snippet.js';\nexport type { SnippetOptions } from './snippet.js';\nexport { processQueue, installGlobal } from './queue.js';\nexport type { QueuedCommands, LensCommand, LensGlobal } from './queue.js';\nexport type { OverlayStats } from './overlay/index.js';\n\nfunction hasDom(): boolean {\n return typeof window !== 'undefined' && typeof document !== 'undefined';\n}\n\nfunction scriptAccessId(): string | undefined {\n const tag = document.querySelector('script[data-lens-id]');\n return tag?.getAttribute('data-lens-id') ?? undefined;\n}\n\n/** Resolve access id + base config from options, script tag, and queued init. */\nfunction resolveConfig(\n options: BootOptions,\n commands: QueuedCommands,\n): { accessId: string; config: LensConfig } | null {\n const { accessId: optAccessId, paramName: _p, force: _f, ...rest } = options;\n\n let queuedConfig: Record<string, unknown> = {};\n let queuedAccessId: string | undefined;\n if (typeof commands.init === 'string') {\n queuedAccessId = commands.init;\n } else if (commands.init && typeof commands.init === 'object') {\n queuedConfig = commands.init;\n if (typeof commands.init.accessId === 'string') queuedAccessId = commands.init.accessId;\n }\n\n const accessId = optAccessId ?? scriptAccessId() ?? queuedAccessId;\n if (!accessId) return null;\n\n const config = { ...queuedConfig, ...rest, accessId } as unknown as LensConfig;\n return { accessId, config };\n}\n\n/**\n * Boot the overlay: gate check → resolve access id → start a LensClient →\n * mount the overlay → wire the global command dispatcher. Returns `null` on the\n * server, when the gate is inactive, or when no access id can be resolved.\n */\nexport function boot(options: BootOptions = {}): LensBrowser | null {\n if (!hasDom()) return null;\n\n const commands = processQueue();\n const paramName = options.paramName ?? DEFAULT_PARAM_NAME;\n\n const active = options.force === true || evaluateGate(paramName);\n if (!active) {\n installGlobal(null);\n return null;\n }\n\n const resolved = resolveConfig(options, commands);\n if (!resolved) {\n if (options.debug) console.warn('[lens] no accessId — overlay not booted');\n installGlobal(null);\n return null;\n }\n\n const client = new LensClient(resolved.config);\n client.start();\n\n const snapshotStats = (): OverlayStats => ({\n url: window.location.href,\n route: currentRoute(),\n browser: detectBrowser(),\n os: detectOs(),\n viewport: viewport(),\n replay: resolved.config.replay !== false,\n // Console / network / error counts are not exposed by the public core API.\n console: null,\n network: null,\n errors: null,\n });\n\n let overlay: OverlayHandle | null = null;\n const browser: LensBrowser = {\n client,\n open: () => overlay?.open(),\n close: () => overlay?.close(),\n destroy: () => {\n overlay?.destroy();\n overlay = null;\n client.stop();\n clearGate();\n installGlobal(null);\n },\n };\n\n overlay = mountOverlay({\n client,\n snapshotStats,\n onDismiss: () => {\n client.stop();\n clearGate();\n installGlobal(null);\n },\n });\n\n installGlobal(browser);\n applyContext(browser, commands);\n\n return browser;\n}\n\n/**\n * Auto-boot on bundle load when a queued `init` command or a\n * `<script data-lens-id>` attribute supplies an access id and the gate is\n * active. No-op during SSR. Exposed so the entry can self-initialize when\n * loaded via the CDN snippet, while ESM consumers call `boot()` directly.\n */\nexport function autoBoot(): LensBrowser | null {\n if (!hasDom()) return null;\n const hasQueuedInit = Array.from(window.Lens?.q ?? []).some(\n (entry) => (entry as ArrayLike<unknown>)[0] === 'init',\n );\n const hasScriptId = !!document.querySelector('script[data-lens-id]');\n if (!hasQueuedInit && !hasScriptId) return null;\n if (!isGateActive()) return null;\n return boot();\n}\n\n// Self-initialize when loaded via the CDN snippet: a queued `init` command or a\n// `<script data-lens-id>` attribute plus an active gate is enough to boot. This\n// is a no-op for bundler/ESM consumers (React provider, composition package),\n// which have neither and drive `boot({ force })` themselves.\nif (hasDom()) autoBoot();\n","/**\n * Activation gate — decides whether the overlay should mount on this page.\n *\n * The overlay is opt-in per session: it activates when the URL carries\n * `?lens=true` (param name configurable). Once seen we persist a flag in\n * sessionStorage so client-side navigations that drop the query param keep the\n * overlay alive for the rest of the tab session. Passing `?lens=false` (or\n * `off` / `0`) clears the flag and deactivates.\n */\n\nexport const DEFAULT_PARAM_NAME = 'lens';\nexport const GATE_STORAGE_KEY = 'lens:active';\n\n// Deprecated pre-rename (\"Lense\") identifiers, still honoured read-only so\n// existing links/sessions minted before the Lens rename keep working.\nconst LEGACY_PARAM_NAME = 'lense';\nconst LEGACY_STORAGE_KEY = 'lense:active';\n\nconst TRUTHY = new Set(['', 'true', '1', 'on', 'yes']);\nconst FALSY = new Set(['false', '0', 'off', 'no']);\n\nfunction hasWindow(): boolean {\n return typeof window !== 'undefined' && typeof document !== 'undefined';\n}\n\nfunction readParam(paramName: string): string | null {\n try {\n const params = new URLSearchParams(window.location.search);\n // Prefer the new param; fall back to the deprecated `?lense=` for back-compat.\n const value = params.get(paramName);\n if (value !== null) return value;\n if (paramName === DEFAULT_PARAM_NAME) return params.get(LEGACY_PARAM_NAME);\n return null;\n } catch {\n return null;\n }\n}\n\nfunction readStorage(): boolean {\n try {\n const s = window.sessionStorage;\n // Deprecated `lense:active` key is read-only back-compat for old sessions.\n return s.getItem(GATE_STORAGE_KEY) === '1' || s.getItem(LEGACY_STORAGE_KEY) === '1';\n } catch {\n return false;\n }\n}\n\nfunction writeStorage(active: boolean): void {\n try {\n if (active) window.sessionStorage.setItem(GATE_STORAGE_KEY, '1');\n else window.sessionStorage.removeItem(GATE_STORAGE_KEY);\n } catch {\n /* storage may be unavailable (private mode, sandbox) — degrade gracefully */\n }\n}\n\n/**\n * Evaluate the gate against the URL param and persisted session flag, applying\n * any side effects (persist on activate, clear on explicit deactivate).\n */\nexport function evaluateGate(paramName: string = DEFAULT_PARAM_NAME): boolean {\n if (!hasWindow()) return false;\n\n const raw = readParam(paramName);\n if (raw !== null) {\n const value = raw.trim().toLowerCase();\n if (FALSY.has(value)) {\n writeStorage(false);\n return false;\n }\n if (TRUTHY.has(value)) {\n writeStorage(true);\n return true;\n }\n // Unrecognised value — fall through to persisted state.\n }\n\n return readStorage();\n}\n\n/** Read-only gate check (param OR persisted flag). Never mutates storage. */\nexport function isGateActive(paramName: string = DEFAULT_PARAM_NAME): boolean {\n if (!hasWindow()) return false;\n\n const raw = readParam(paramName);\n if (raw !== null) {\n const value = raw.trim().toLowerCase();\n if (FALSY.has(value)) return false;\n if (TRUTHY.has(value)) return true;\n }\n return readStorage();\n}\n\n/** Clear the persisted session flag (used when the user closes the overlay). */\nexport function clearGate(): void {\n if (!hasWindow()) return;\n writeStorage(false);\n}\n","/**\n * Best-effort browser/OS detection from the user agent, plus viewport/route\n * readers. These feed the read-only context chips shown in the report panel;\n * the authoritative capture lives in @horus-lens/core.\n */\n\nexport function detectBrowser(ua: string = navigator.userAgent): string {\n if (/Edg\\//.test(ua)) return 'Edge';\n if (/OPR\\/|Opera/.test(ua)) return 'Opera';\n if (/Firefox\\//.test(ua)) return 'Firefox';\n if (/Chrome\\//.test(ua) && !/Chromium/.test(ua)) return 'Chrome';\n if (/Chromium\\//.test(ua)) return 'Chromium';\n if (/Safari\\//.test(ua) && /Version\\//.test(ua)) return 'Safari';\n return 'Browser';\n}\n\nexport function detectOs(ua: string = navigator.userAgent): string {\n if (/Windows NT/.test(ua)) return 'Windows';\n if (/Mac OS X|Macintosh/.test(ua)) return 'macOS';\n if (/Android/.test(ua)) return 'Android';\n if (/iPhone|iPad|iPod/.test(ua)) return 'iOS';\n if (/Linux/.test(ua)) return 'Linux';\n return 'Unknown';\n}\n\nexport function viewport(): { width: number; height: number } {\n return {\n width: window.innerWidth || document.documentElement.clientWidth || 0,\n height: window.innerHeight || document.documentElement.clientHeight || 0,\n };\n}\n\nexport function currentRoute(): string {\n return (window.location.pathname || '/') + (window.location.search || '');\n}\n","/** Tiny framework-free DOM helpers used to build the overlay tree. */\n\ntype Child = Node | string | null | undefined | false;\n\nexport interface ElProps {\n class?: string;\n text?: string;\n html?: string;\n title?: string;\n type?: string;\n placeholder?: string;\n ariaLabel?: string;\n attrs?: Record<string, string>;\n style?: Partial<CSSStyleDeclaration>;\n on?: Partial<Record<keyof HTMLElementEventMap, (e: Event) => void>>;\n}\n\nexport function el<K extends keyof HTMLElementTagNameMap>(\n tag: K,\n props: ElProps = {},\n children: Child[] = [],\n): HTMLElementTagNameMap[K] {\n const node = document.createElement(tag);\n if (props.class) node.className = props.class;\n if (props.text !== undefined) node.textContent = props.text;\n if (props.html !== undefined) node.innerHTML = props.html;\n if (props.title) node.title = props.title;\n if (props.ariaLabel) node.setAttribute('aria-label', props.ariaLabel);\n if (props.type && 'type' in node) (node as unknown as { type: string }).type = props.type;\n if (props.placeholder && 'placeholder' in node) {\n (node as unknown as { placeholder: string }).placeholder = props.placeholder;\n }\n if (props.attrs) {\n for (const [k, v] of Object.entries(props.attrs)) node.setAttribute(k, v);\n }\n if (props.style) Object.assign(node.style, props.style);\n if (props.on) {\n for (const [event, handler] of Object.entries(props.on)) {\n if (handler) node.addEventListener(event, handler as EventListener);\n }\n }\n for (const child of children) {\n if (child === null || child === undefined || child === false) continue;\n node.append(child);\n }\n return node;\n}\n\nexport function clear(node: Node): void {\n while (node.firstChild) node.removeChild(node.firstChild);\n}\n","/**\n * Make a fixed-position overlay surface draggable by a handle, so the user can\n * move it off page content it covers. Framework-free and pointer-based, so one\n * code path serves mouse, pen and touch.\n *\n * On the first drag the element is pinned to explicit `left`/`top` pixels — its\n * stylesheet anchor (`transform`/`right`/`bottom`) is overridden inline — and it\n * then follows the pointer, clamped to stay inside the viewport. A press that\n * moves less than {@link DRAG_THRESHOLD} is left alone so taps on the surface\n * still register as clicks.\n *\n * Positions persist per `key` for the page session in a module-level store, so a\n * surface that is destroyed and recreated (like the report panel) reappears\n * where the user left it, and every placed surface is re-clamped on viewport\n * resize / orientation change.\n */\n\n/** Keep at least this many px of the surface inside the viewport on every edge. */\nconst MARGIN = 6;\n/** Pointer travel (px, Manhattan) before a press is treated as a drag not a tap. */\nconst DRAG_THRESHOLD = 3;\n\ninterface Pos {\n left: number;\n top: number;\n}\n\n/** Session-lived, per-surface last position. Survives element re-creation. */\nconst savedPositions = new Map<string, Pos>();\n\n/** Default \"don't start a drag from here\" test: real interactive controls. */\nexport function isInteractiveTarget(target: EventTarget | null): boolean {\n return (\n target instanceof Element &&\n target.closest(\n 'button, a, input, textarea, select, [role=\"switch\"], [role=\"button\"], [contenteditable=\"true\"]',\n ) !== null\n );\n}\n\nexport interface DraggableOptions {\n /** The grab region. Presses starting here (and not on `ignore`) begin a drag. */\n handle: HTMLElement;\n /** Stable id under which this surface's position persists across re-creation. */\n key: string;\n /** Targets for which a drag must NOT start. Defaults to interactive controls. */\n ignore?: (target: EventTarget | null) => boolean;\n /** Invoked after each move (e.g. to reposition a dependent surface). */\n onMove?: () => void;\n}\n\nexport interface DraggableHandle {\n /** Re-apply viewport clamping (call if the surface changed size). */\n reclamp(): void;\n /** Forget the stored position and fall back to the stylesheet anchor. */\n reset(): void;\n destroy(): void;\n}\n\nfunction clampToViewport(element: HTMLElement, left: number, top: number): Pos {\n const rect = element.getBoundingClientRect();\n const vw = window.innerWidth;\n const vh = window.innerHeight;\n // If the surface is wider/taller than the viewport, pin it to the margin\n // rather than pushing it off-screen.\n const maxLeft = Math.max(MARGIN, vw - rect.width - MARGIN);\n const maxTop = Math.max(MARGIN, vh - rect.height - MARGIN);\n return {\n left: Math.min(Math.max(left, MARGIN), maxLeft),\n top: Math.min(Math.max(top, MARGIN), maxTop),\n };\n}\n\nexport function makeDraggable(element: HTMLElement, opts: DraggableOptions): DraggableHandle {\n const { handle, key } = opts;\n const ignore = opts.ignore ?? isInteractiveTarget;\n\n let startX = 0;\n let startY = 0;\n let originLeft = 0;\n let originTop = 0;\n let dragging = false;\n let armed = false;\n let pointerId: number | null = null;\n\n const apply = (left: number, top: number): void => {\n const p = clampToViewport(element, left, top);\n element.style.left = `${p.left}px`;\n element.style.top = `${p.top}px`;\n element.style.right = 'auto';\n element.style.bottom = 'auto';\n element.style.transform = 'none';\n savedPositions.set(key, p);\n opts.onMove?.();\n };\n\n const onPointerDown = (e: PointerEvent): void => {\n if (e.button !== 0 && e.pointerType === 'mouse') return; // primary button only\n if (ignore(e.target)) return;\n armed = true;\n dragging = false;\n pointerId = e.pointerId;\n startX = e.clientX;\n startY = e.clientY;\n const rect = element.getBoundingClientRect();\n originLeft = rect.left;\n originTop = rect.top;\n // Track on window so a fast drag that outruns the pointer still follows.\n window.addEventListener('pointermove', onPointerMove, true);\n window.addEventListener('pointerup', onPointerUp, true);\n window.addEventListener('pointercancel', onPointerUp, true);\n };\n\n const onPointerMove = (e: PointerEvent): void => {\n if (!armed || e.pointerId !== pointerId) return;\n const dx = e.clientX - startX;\n const dy = e.clientY - startY;\n if (!dragging) {\n if (Math.abs(dx) + Math.abs(dy) < DRAG_THRESHOLD) return;\n dragging = true;\n element.classList.add('is-dragging');\n }\n e.preventDefault();\n apply(originLeft + dx, originTop + dy);\n };\n\n const onPointerUp = (e: PointerEvent): void => {\n if (e.pointerId !== pointerId) return;\n armed = false;\n if (dragging) {\n dragging = false;\n element.classList.remove('is-dragging');\n }\n pointerId = null;\n window.removeEventListener('pointermove', onPointerMove, true);\n window.removeEventListener('pointerup', onPointerUp, true);\n window.removeEventListener('pointercancel', onPointerUp, true);\n };\n\n const onResize = (): void => {\n const p = savedPositions.get(key);\n if (p) apply(p.left, p.top);\n };\n\n handle.classList.add('lens-drag-handle');\n handle.addEventListener('pointerdown', onPointerDown);\n window.addEventListener('resize', onResize);\n\n // Restore a saved position once the element has been laid out (so clamping\n // sees its real size).\n const stored = savedPositions.get(key);\n if (stored) requestAnimationFrame(() => apply(stored.left, stored.top));\n\n return {\n reclamp: onResize,\n reset(): void {\n savedPositions.delete(key);\n element.style.left = '';\n element.style.top = '';\n element.style.right = '';\n element.style.bottom = '';\n element.style.transform = '';\n element.classList.remove('is-dragging');\n },\n destroy(): void {\n handle.removeEventListener('pointerdown', onPointerDown);\n window.removeEventListener('pointermove', onPointerMove, true);\n window.removeEventListener('pointerup', onPointerUp, true);\n window.removeEventListener('pointercancel', onPointerUp, true);\n window.removeEventListener('resize', onResize);\n },\n };\n}\n","/**\n * Pure geometry helpers for the SVG annotation editor. Kept free of DOM so the\n * math (point thinning / simplification, crop-bounds union, arrowhead polygon)\n * is unit-testable in isolation.\n *\n * ALL coordinates are DOCUMENT CSS pixels — the same space annotations are\n * emitted in.\n */\nimport type { Annotation } from '@horus-lens/shared';\n\nexport interface Point {\n x: number;\n y: number;\n}\n\nexport interface Bounds {\n x: number;\n y: number;\n width: number;\n height: number;\n}\n\n/** Minimum pointer travel (px) before a freehand point is kept. */\nexport const THIN_MIN_DIST = 3;\n/** Hard cap on points captured per freehand stroke. */\nexport const MAX_POINTS = 2000;\n/** Highlighter is always drawn at this stroke width (ignores S/M/L). */\nexport const HIGHLIGHTER_WIDTH = 14;\n/** Step badge circle radius. */\nexport const STEP_RADIUS = 12;\n\nexport function distance(a: Point, b: Point): number {\n return Math.hypot(a.x - b.x, a.y - b.y);\n}\n\n/**\n * True when `candidate` is far enough from `last` to be worth keeping while\n * capturing a freehand stroke (thins jitter at capture time).\n */\nexport function shouldKeepPoint(last: Point, candidate: Point, minDist = THIN_MIN_DIST): boolean {\n return distance(last, candidate) >= minDist;\n}\n\n/** Perpendicular distance from `p` to the segment `a`→`b`. */\nfunction perpendicularDistance(p: Point, a: Point, b: Point): number {\n const dx = b.x - a.x;\n const dy = b.y - a.y;\n const len2 = dx * dx + dy * dy;\n if (len2 === 0) return distance(p, a);\n let t = ((p.x - a.x) * dx + (p.y - a.y) * dy) / len2;\n t = Math.max(0, Math.min(1, t));\n return distance(p, { x: a.x + t * dx, y: a.y + t * dy });\n}\n\n/**\n * Ramer–Douglas–Peucker simplification. Drops points that sit within\n * `tolerance` px of the line between their neighbours — a light pass applied on\n * pointerup so freehand strokes stay smooth but cheap.\n */\nexport function simplifyPoints(points: Point[], tolerance = 1): Point[] {\n if (points.length <= 2 || tolerance <= 0) return points.map((p) => ({ ...p }));\n const first = points[0]!;\n const last = points[points.length - 1]!;\n\n let maxDist = 0;\n let index = 0;\n for (let i = 1; i < points.length - 1; i++) {\n const d = perpendicularDistance(points[i]!, first, last);\n if (d > maxDist) {\n maxDist = d;\n index = i;\n }\n }\n\n if (maxDist > tolerance) {\n const left = simplifyPoints(points.slice(0, index + 1), tolerance);\n const right = simplifyPoints(points.slice(index), tolerance);\n return left.slice(0, -1).concat(right);\n }\n return [{ ...first }, { ...last }];\n}\n\n/**\n * Three points of the filled arrowhead triangle for the segment tail→head.\n * Returned as `[tip, base1, base2]` in document coords. Drawn as an explicit\n * `<polygon>` because SVG `<marker>` does not rasterize reliably from a\n * serialized data-URL SVG.\n */\nexport function arrowheadPolygon(\n x1: number,\n y1: number,\n x2: number,\n y2: number,\n size = 14,\n): Point[] {\n const angle = Math.atan2(y2 - y1, x2 - x1);\n const spread = Math.PI / 7; // ~25.7° half-angle\n return [\n { x: x2, y: y2 },\n { x: x2 - size * Math.cos(angle - spread), y: y2 - size * Math.sin(angle - spread) },\n { x: x2 - size * Math.cos(angle + spread), y: y2 - size * Math.sin(angle + spread) },\n ];\n}\n\n/** Bounding box of an annotation in document coords, or `null` if degenerate. */\nexport function boundsOfAnnotation(a: Annotation): Bounds | null {\n switch (a.kind) {\n case 'rect':\n case 'ellipse':\n case 'blur': {\n const x = Math.min(a.x, a.x + a.width);\n const y = Math.min(a.y, a.y + a.height);\n return { x, y, width: Math.abs(a.width), height: Math.abs(a.height) };\n }\n case 'arrow':\n case 'line': {\n const x = Math.min(a.x1, a.x2);\n const y = Math.min(a.y1, a.y2);\n return { x, y, width: Math.abs(a.x2 - a.x1), height: Math.abs(a.y2 - a.y1) };\n }\n case 'pencil':\n case 'highlighter': {\n if (a.points.length === 0) return null;\n let minX = Infinity;\n let minY = Infinity;\n let maxX = -Infinity;\n let maxY = -Infinity;\n for (const p of a.points) {\n minX = Math.min(minX, p.x);\n minY = Math.min(minY, p.y);\n maxX = Math.max(maxX, p.x);\n maxY = Math.max(maxY, p.y);\n }\n return { x: minX, y: minY, width: maxX - minX, height: maxY - minY };\n }\n case 'text': {\n const fontSize = a.fontSize ?? 16;\n // Rough estimate; the editor prefers a live getBBox() when available.\n const width = Math.max(1, a.text.length * fontSize * 0.6);\n return { x: a.x, y: a.y, width, height: fontSize * 1.2 };\n }\n case 'step': {\n return {\n x: a.x - STEP_RADIUS,\n y: a.y - STEP_RADIUS,\n width: STEP_RADIUS * 2,\n height: STEP_RADIUS * 2,\n };\n }\n }\n}\n\n/** Union of a list of bounds, or `null` when the list is empty. */\nexport function unionBounds(list: Bounds[]): Bounds | null {\n if (list.length === 0) return null;\n let minX = Infinity;\n let minY = Infinity;\n let maxX = -Infinity;\n let maxY = -Infinity;\n for (const b of list) {\n minX = Math.min(minX, b.x);\n minY = Math.min(minY, b.y);\n maxX = Math.max(maxX, b.x + b.width);\n maxY = Math.max(maxY, b.y + b.height);\n }\n return { x: minX, y: minY, width: maxX - minX, height: maxY - minY };\n}\n\n/**\n * Expand `b` by `padding` on every side, then clamp to the document box\n * `[0..maxWidth] × [0..maxHeight]`.\n */\nexport function padAndClampBounds(\n b: Bounds,\n padding: number,\n maxWidth: number,\n maxHeight: number,\n): Bounds {\n const x = Math.max(0, b.x - padding);\n const y = Math.max(0, b.y - padding);\n const right = Math.min(maxWidth, b.x + b.width + padding);\n const bottom = Math.min(maxHeight, b.y + b.height + padding);\n return { x, y, width: Math.max(0, right - x), height: Math.max(0, bottom - y) };\n}\n","/** Inline SVG icon strings (16px, currentColor). Used via ElProps.html. */\n\nconst svg = (inner: string): string =>\n `<svg width=\"16\" height=\"16\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"2\" stroke-linecap=\"round\" stroke-linejoin=\"round\" aria-hidden=\"true\">${inner}</svg>`;\n\nexport const iconEye = svg(\n '<path d=\"M2 12s3.5-7 10-7 10 7 10 7-3.5 7-10 7-10-7-10-7Z\"/><circle cx=\"12\" cy=\"12\" r=\"3\"/>',\n);\n\nexport const iconCrosshair = svg(\n '<circle cx=\"12\" cy=\"12\" r=\"8\"/><line x1=\"12\" y1=\"2\" x2=\"12\" y2=\"6\"/><line x1=\"12\" y1=\"18\" x2=\"12\" y2=\"22\"/><line x1=\"2\" y1=\"12\" x2=\"6\" y2=\"12\"/><line x1=\"18\" y1=\"12\" x2=\"22\" y2=\"12\"/>',\n);\n\nexport const iconClose = svg('<line x1=\"6\" y1=\"6\" x2=\"18\" y2=\"18\"/><line x1=\"18\" y1=\"6\" x2=\"6\" y2=\"18\"/>');\n\nexport const iconMark = svg(\n '<rect x=\"3\" y=\"3\" width=\"18\" height=\"18\" rx=\"2\" stroke-dasharray=\"4 3\"/>',\n);\n\nexport const iconCopy = svg(\n '<rect x=\"9\" y=\"9\" width=\"11\" height=\"11\" rx=\"2\"/><path d=\"M5 15V5a2 2 0 0 1 2-2h10\"/>',\n);\n\nexport const iconCheck = svg('<polyline points=\"20 6 9 17 4 12\"/>');\n\nexport const iconSend = svg('<line x1=\"22\" y1=\"2\" x2=\"11\" y2=\"13\"/><polygon points=\"22 2 15 22 11 13 2 9 22 2\"/>');\n\n/** Filled red dot — \"record steps\". Uses a fixed fill so it reads as a record cue. */\nexport const iconRecord = `<svg width=\"16\" height=\"16\" viewBox=\"0 0 24 24\" fill=\"none\" aria-hidden=\"true\"><circle cx=\"12\" cy=\"12\" r=\"6\" fill=\"#ef4444\"/></svg>`;\n\n/** Square \"stop\" glyph. */\nexport const iconStop = `<svg width=\"16\" height=\"16\" viewBox=\"0 0 24 24\" fill=\"currentColor\" aria-hidden=\"true\"><rect x=\"6\" y=\"6\" width=\"12\" height=\"12\" rx=\"2\"/></svg>`;\n\n/* ---------------- Annotation tool glyphs ---------------- */\n\nexport const iconRectTool = svg('<rect x=\"4\" y=\"6\" width=\"16\" height=\"12\" rx=\"1\"/>');\n\nexport const iconEllipseTool = svg('<ellipse cx=\"12\" cy=\"12\" rx=\"8\" ry=\"6\"/>');\n\nexport const iconArrowTool = svg('<line x1=\"5\" y1=\"19\" x2=\"18\" y2=\"6\"/><polyline points=\"18 12 18 6 12 6\"/>');\n\nexport const iconLineTool = svg('<line x1=\"5\" y1=\"19\" x2=\"19\" y2=\"5\"/>');\n\nexport const iconPencil = svg('<path d=\"M12 20h9\"/><path d=\"M16.5 3.5a2.12 2.12 0 0 1 3 3L7 19l-4 1 1-4Z\"/>');\n\nexport const iconHighlighter = svg(\n '<path d=\"m9 11-6 6v3h9l3-3\"/><path d=\"m22 12-4.6 4.6a1 1 0 0 1-1.4 0l-5.6-5.6a1 1 0 0 1 0-1.4L14 4\"/>',\n);\n\nexport const iconText = svg(\n '<polyline points=\"4 7 4 4 20 4 20 7\"/><line x1=\"12\" y1=\"4\" x2=\"12\" y2=\"20\"/><line x1=\"9\" y1=\"20\" x2=\"15\" y2=\"20\"/>',\n);\n\nexport const iconStepTool = svg('<circle cx=\"12\" cy=\"12\" r=\"9\"/><path d=\"M11.2 9 13 8v8\"/>');\n\nexport const iconBlur = svg('<path d=\"M12 3s6 6.4 6 10a6 6 0 0 1-12 0c0-3.6 6-10 6-10Z\"/>');\n\nexport const iconUndo = svg('<path d=\"M9 14 4 9l5-5\"/><path d=\"M4 9h11a5 5 0 0 1 0 10h-1\"/>');\n\nexport const iconTrash = svg(\n '<polyline points=\"3 6 5 6 21 6\"/><path d=\"M19 6v14a2 2 0 0 1-2 2H7a2 2 0 0 1-2-2V6m3 0V4a2 2 0 0 1 2-2h4a2 2 0 0 1 2 2v2\"/>',\n);\n\n/** Panel action glyph — replaces the old dashed-rect \"Mark area\" icon. */\nexport const iconAnnotate = iconPencil;\n\n/** Drag grip — a 2×3 dot grid (\"⠿\"), the affordance on a draggable surface. */\nexport const iconGrip = `<svg width=\"16\" height=\"16\" viewBox=\"0 0 24 24\" fill=\"currentColor\" aria-hidden=\"true\"><circle cx=\"9\" cy=\"6\" r=\"1.6\"/><circle cx=\"15\" cy=\"6\" r=\"1.6\"/><circle cx=\"9\" cy=\"12\" r=\"1.6\"/><circle cx=\"15\" cy=\"12\" r=\"1.6\"/><circle cx=\"9\" cy=\"18\" r=\"1.6\"/><circle cx=\"15\" cy=\"18\" r=\"1.6\"/></svg>`;\n\n/** Report — a chat/feedback bubble. Fronts the \"Report issue\" pill action. */\nexport const iconReport = svg('<path d=\"M21 15a2 2 0 0 1-2 2H7l-4 4V5a2 2 0 0 1 2-2h14a2 2 0 0 1 2 2Z\"/>');\n","import type { Annotation } from '@horus-lens/shared';\nimport { el } from './dom.js';\nimport { makeDraggable, isInteractiveTarget, type DraggableHandle } from './draggable.js';\nimport {\n arrowheadPolygon,\n boundsOfAnnotation,\n distance,\n HIGHLIGHTER_WIDTH,\n MAX_POINTS,\n padAndClampBounds,\n shouldKeepPoint,\n simplifyPoints,\n STEP_RADIUS,\n unionBounds,\n type Bounds,\n type Point,\n} from './geometry.js';\nimport {\n iconArrowTool,\n iconBlur,\n iconClose,\n iconEllipseTool,\n iconHighlighter,\n iconLineTool,\n iconPencil,\n iconRectTool,\n iconGrip,\n iconStepTool,\n iconText,\n iconTrash,\n iconUndo,\n} from './icons.js';\n\nconst SVG_NS = 'http://www.w3.org/2000/svg';\nconst FONT = \"-apple-system, BlinkMacSystemFont, 'Segoe UI', sans-serif\";\n\n/** Minimum drag extent before a shape/segment is committed (vs. treated as a tap). */\nconst MIN_DRAG = 6;\n\ntype Tool =\n | 'rect'\n | 'ellipse'\n | 'arrow'\n | 'line'\n | 'pencil'\n | 'highlighter'\n | 'text'\n | 'step'\n | 'blur';\n\nconst TOOLS: ReadonlyArray<{ tool: Tool; icon: string; label: string }> = [\n { tool: 'rect', icon: iconRectTool, label: 'Rectangle' },\n { tool: 'ellipse', icon: iconEllipseTool, label: 'Ellipse' },\n { tool: 'arrow', icon: iconArrowTool, label: 'Arrow' },\n { tool: 'line', icon: iconLineTool, label: 'Line' },\n { tool: 'pencil', icon: iconPencil, label: 'Pencil' },\n { tool: 'highlighter', icon: iconHighlighter, label: 'Highlighter' },\n { tool: 'text', icon: iconText, label: 'Text' },\n { tool: 'step', icon: iconStepTool, label: 'Step number' },\n { tool: 'blur', icon: iconBlur, label: 'Blur / redact' },\n];\n\nconst COLORS = ['#ef4444', '#f59e0b', '#22c55e', '#3b82f6', '#8b5cf6', '#111827'] as const;\nconst WIDTHS: ReadonlyArray<{ label: string; value: number }> = [\n { label: 'S', value: 2 },\n { label: 'M', value: 3.5 },\n { label: 'L', value: 6 },\n];\n\n/** In-progress drag/draw state. */\ninterface DragState {\n tool: Tool;\n color: string;\n width: number;\n start: Point;\n node: SVGElement;\n points?: Point[];\n last?: Point;\n line?: SVGElement;\n head?: SVGElement;\n}\n\n/**\n * SVG annotation editor. Replaces the div-rect Annotator with a full-DOCUMENT\n * `<svg>` overlay whose marks anchor to page content (they survive scrolling)\n * and serialize to a standalone composite for server-side rasterization.\n *\n * Session semantics: `start(onExit)` arms drawing; the toolbar close (or Escape)\n * keeps the marks and exits. Discard is the trash button (clears all marks).\n */\nexport class AnnotationEditor {\n private svg: SVGSVGElement | null = null;\n private bg: SVGRectElement | null = null;\n private toolbar: HTMLElement | null = null;\n private toolbarDrag: DraggableHandle | null = null;\n private textInputEl: HTMLInputElement | null = null;\n private textAnchor: Point | null = null;\n private textColor: string = COLORS[0];\n\n private annotations: Annotation[] = [];\n private markNodes: SVGElement[] = [];\n private drag: DragState | null = null;\n\n private active = false;\n private sessionBase = 0;\n private stepCounter = 0;\n private idSeq = 0;\n private onExit: (() => void) | null = null;\n\n private tool: Tool = 'rect';\n private color: string = COLORS[0];\n private width = 3.5;\n\n private docW = 0;\n private docH = 0;\n private resizeObserver: ResizeObserver | null = null;\n\n private readonly toolBtns = new Map<Tool, HTMLButtonElement>();\n private readonly colorBtns = new Map<string, HTMLButtonElement>();\n private readonly widthBtns = new Map<number, HTMLButtonElement>();\n private undoBtn: HTMLButtonElement | null = null;\n private clearBtn: HTMLButtonElement | null = null;\n\n constructor(private readonly host: HTMLElement) {}\n\n get isActive(): boolean {\n return this.active;\n }\n\n get count(): number {\n return this.annotations.length;\n }\n\n /** Deep-copied document-coord annotations per the schema contract. */\n list(): Annotation[] {\n return this.annotations.map((a) => {\n const copy: Annotation = { ...a };\n if ('points' in copy && Array.isArray(copy.points)) {\n copy.points = copy.points.map((p) => ({ ...p }));\n }\n if (copy.kind === 'rect' && copy.viewport) copy.viewport = { ...copy.viewport };\n return copy;\n });\n }\n\n /** Remove every mark. Tears the layer down when not actively drawing. */\n clear(): void {\n for (const node of this.markNodes) node.remove();\n this.markNodes = [];\n this.annotations = [];\n this.stepCounter = 0;\n // Reconcile the session boundary: clearing removes every mark (including\n // ones kept from earlier sessions), so an active session's base can no\n // longer point past the now-empty list — otherwise a later Cancel would\n // splice past the end and fail to discard marks drawn after the clear.\n this.sessionBase = Math.min(this.sessionBase, this.annotations.length);\n if (!this.active) this.teardownLayer();\n this.syncActionButtons();\n }\n\n start(onExit: () => void): void {\n if (this.active) return;\n this.ensureLayer();\n const svg = this.svg!;\n this.active = true;\n this.onExit = onExit;\n this.sessionBase = this.annotations.length;\n this.stepCounter = 0;\n this.sizeLayer();\n this.updateTransform();\n svg.style.pointerEvents = 'auto';\n // Re-arm the transparent capture surface (exit() disables it so the persisted\n // marks layer never swallows page taps — e.g. the element picker).\n if (this.bg) this.bg.style.pointerEvents = 'all';\n svg.style.touchAction = 'none';\n svg.style.cursor = 'crosshair';\n svg.addEventListener('pointerdown', this.onPointerDown);\n this.buildToolbar();\n window.addEventListener('keydown', this.onKey, true);\n }\n\n /** Done — keep this session's marks, exit draw mode. */\n exit(): void {\n if (!this.active) return;\n this.active = false;\n this.commitTextInput(); // flush any in-progress text\n if (this.drag) {\n this.drag.node.remove();\n this.detachDragListeners();\n this.drag = null;\n }\n const svg = this.svg;\n if (svg) {\n svg.removeEventListener('pointerdown', this.onPointerDown);\n svg.style.pointerEvents = 'none';\n // CRITICAL: the transparent capture rect keeps pointer-events:'all' even\n // when its parent SVG is 'none' (a descendant re-enables hit-testing), so\n // the persisted marks layer would otherwise swallow every page tap after\n // Done — breaking the element picker and page interaction. Disable it.\n if (this.bg) this.bg.style.pointerEvents = 'none';\n svg.style.touchAction = '';\n svg.style.cursor = '';\n }\n window.removeEventListener('keydown', this.onKey, true);\n this.removeToolbar();\n const cb = this.onExit;\n this.onExit = null;\n cb?.();\n }\n\n private undo(): void {\n // Undo is bound to the current session: never pop below `sessionBase`, or a\n // Done+reopen followed by undo could destroy an annotation kept from an\n // earlier session (the marks below the base are already committed).\n if (this.markNodes.length <= this.sessionBase) return;\n const node = this.markNodes.pop();\n if (!node) return;\n node.remove();\n this.annotations.pop();\n this.syncActionButtons();\n }\n\n // --------------------------------------------------------------------------\n // Composite / crop\n // --------------------------------------------------------------------------\n\n /**\n * Complete standalone SVG of every NON-blur mark, plus blur regions returned\n * separately. `null` when there are no marks.\n */\n getComposite(): {\n svgMarkup: string;\n docWidth: number;\n docHeight: number;\n blurRegions: Bounds[];\n } | null {\n if (this.annotations.length === 0 || !this.svg) return null;\n this.sizeLayer();\n const docWidth = this.docW;\n const docHeight = this.docH;\n\n const clone = this.svg.cloneNode(true) as SVGSVGElement;\n clone.removeAttribute('style');\n clone.removeAttribute('class');\n // Strip editor chrome, in-progress drafts, and blur previews.\n clone\n .querySelectorAll('[data-lens-chrome],[data-lens-draft],[data-lens-blur]')\n .forEach((n) => n.remove());\n clone.querySelector('defs')?.remove();\n clone.setAttribute('xmlns', SVG_NS);\n clone.setAttribute('viewBox', `0 0 ${docWidth} ${docHeight}`);\n clone.setAttribute('width', String(docWidth));\n clone.setAttribute('height', String(docHeight));\n\n const svgMarkup = new XMLSerializer().serializeToString(clone);\n const blurRegions: Bounds[] = this.annotations\n .filter((a): a is Extract<Annotation, { kind: 'blur' }> => a.kind === 'blur')\n .map((a) => ({ x: a.x, y: a.y, width: a.width, height: a.height }));\n\n return { svgMarkup, docWidth, docHeight, blurRegions };\n }\n\n /** Union bbox of all marks + 24px padding, clamped to the document. */\n getCropBounds(): Bounds | undefined {\n if (this.annotations.length === 0) return undefined;\n const boxes: Bounds[] = [];\n for (let i = 0; i < this.annotations.length; i++) {\n const a = this.annotations[i]!;\n const b = a.kind === 'text' ? this.textBounds(i) : boundsOfAnnotation(a);\n if (b) boxes.push(b);\n }\n const u = unionBounds(boxes);\n if (!u) return undefined;\n this.sizeLayer();\n return padAndClampBounds(u, 24, this.docW, this.docH);\n }\n\n /** Prefer a live getBBox() for text; fall back to the geometric estimate. */\n private textBounds(index: number): Bounds | null {\n const node = this.markNodes[index];\n const annotation = this.annotations[index]!;\n if (node && typeof (node as SVGGraphicsElement).getBBox === 'function') {\n try {\n const box = (node as SVGGraphicsElement).getBBox();\n if (box.width > 0 && box.height > 0) {\n return { x: box.x, y: box.y, width: box.width, height: box.height };\n }\n } catch {\n /* getBBox throws for un-rendered nodes — fall through to the estimate */\n }\n }\n return boundsOfAnnotation(annotation);\n }\n\n // --------------------------------------------------------------------------\n // Layer lifecycle\n // --------------------------------------------------------------------------\n\n private ensureLayer(): void {\n if (this.svg) return;\n const svg = document.createElementNS(SVG_NS, 'svg') as SVGSVGElement;\n svg.setAttribute('class', 'lens-annotate-svg');\n svg.setAttribute('xmlns', SVG_NS);\n\n const defs = document.createElementNS(SVG_NS, 'defs');\n defs.setAttribute('data-lens-chrome', '1');\n // Diagonal hatch fill for blur/redaction previews (~35% opacity baked in).\n const pattern = document.createElementNS(SVG_NS, 'pattern');\n pattern.setAttribute('id', 'lens-blur-hatch');\n pattern.setAttribute('width', '8');\n pattern.setAttribute('height', '8');\n pattern.setAttribute('patternUnits', 'userSpaceOnUse');\n pattern.setAttribute('patternTransform', 'rotate(45)');\n const patternBase = document.createElementNS(SVG_NS, 'rect');\n patternBase.setAttribute('width', '8');\n patternBase.setAttribute('height', '8');\n patternBase.setAttribute('fill', 'rgba(17,24,39,0.12)');\n const patternLine = document.createElementNS(SVG_NS, 'line');\n patternLine.setAttribute('x1', '0');\n patternLine.setAttribute('y1', '0');\n patternLine.setAttribute('x2', '0');\n patternLine.setAttribute('y2', '8');\n patternLine.setAttribute('stroke', 'rgba(17,24,39,0.55)');\n patternLine.setAttribute('stroke-width', '4');\n pattern.append(patternBase, patternLine);\n defs.append(pattern);\n svg.append(defs);\n\n // Transparent capture surface so empty regions still start a draw.\n const bg = document.createElementNS(SVG_NS, 'rect') as SVGRectElement;\n bg.setAttribute('data-lens-chrome', '1');\n bg.setAttribute('x', '0');\n bg.setAttribute('y', '0');\n bg.setAttribute('fill', 'transparent');\n bg.style.pointerEvents = 'all';\n svg.append(bg);\n\n this.svg = svg;\n this.bg = bg;\n this.host.append(svg);\n\n // Re-anchor on scroll; resize the surface when the document grows.\n window.addEventListener('scroll', this.onScroll, { passive: true, capture: true });\n window.addEventListener('resize', this.onResize);\n if (typeof ResizeObserver !== 'undefined') {\n this.resizeObserver = new ResizeObserver(this.onResize);\n this.resizeObserver.observe(document.documentElement);\n }\n this.sizeLayer();\n this.updateTransform();\n }\n\n private teardownLayer(): void {\n window.removeEventListener('scroll', this.onScroll, true);\n window.removeEventListener('resize', this.onResize);\n this.resizeObserver?.disconnect();\n this.resizeObserver = null;\n this.svg?.remove();\n this.svg = null;\n this.bg = null;\n }\n\n private docSize(): { width: number; height: number } {\n const d = document.documentElement;\n const b = document.body;\n const width = Math.max(d.scrollWidth, b?.scrollWidth ?? 0, d.clientWidth);\n const height = Math.max(d.scrollHeight, b?.scrollHeight ?? 0, d.clientHeight);\n return { width, height };\n }\n\n private sizeLayer(): void {\n if (!this.svg) return;\n const { width, height } = this.docSize();\n this.docW = width;\n this.docH = height;\n this.svg.setAttribute('width', String(width));\n this.svg.setAttribute('height', String(height));\n this.svg.setAttribute('viewBox', `0 0 ${width} ${height}`);\n this.svg.style.width = `${width}px`;\n this.svg.style.height = `${height}px`;\n if (this.bg) {\n this.bg.setAttribute('width', String(width));\n this.bg.setAttribute('height', String(height));\n }\n }\n\n private updateTransform(): void {\n if (!this.svg) return;\n const scrollX = window.scrollX || window.pageXOffset || 0;\n const scrollY = window.scrollY || window.pageYOffset || 0;\n this.svg.style.left = `${-scrollX}px`;\n this.svg.style.top = `${-scrollY}px`;\n }\n\n private onScroll = (): void => this.updateTransform();\n private onResize = (): void => {\n this.sizeLayer();\n this.updateTransform();\n };\n\n // --------------------------------------------------------------------------\n // Toolbar\n // --------------------------------------------------------------------------\n\n private buildToolbar(): void {\n this.toolBtns.clear();\n this.colorBtns.clear();\n this.widthBtns.clear();\n\n const toolGroup = el('div', { class: 'lens-tool-group' });\n for (const { tool, icon, label } of TOOLS) {\n const btn = el('button', {\n class: 'lens-tool-btn',\n ariaLabel: label,\n title: label,\n html: icon,\n attrs: { type: 'button', 'aria-pressed': String(tool === this.tool) },\n on: { click: () => this.selectTool(tool) },\n });\n this.toolBtns.set(tool, btn);\n toolGroup.append(btn);\n }\n\n const colorGroup = el('div', { class: 'lens-tool-group lens-swatches' });\n for (const c of COLORS) {\n const btn = el('button', {\n class: 'lens-swatch',\n ariaLabel: `Color ${c}`,\n title: c,\n attrs: { type: 'button', 'aria-pressed': String(c === this.color) },\n style: { background: c },\n on: { click: () => this.selectColor(c) },\n });\n this.colorBtns.set(c, btn);\n colorGroup.append(btn);\n }\n\n const widthGroup = el('div', { class: 'lens-tool-group' });\n for (const { label, value } of WIDTHS) {\n const btn = el('button', {\n class: 'lens-width-btn',\n text: label,\n ariaLabel: `Stroke width ${label}`,\n title: `Stroke ${label} (${value}px)`,\n attrs: { type: 'button', 'aria-pressed': String(value === this.width) },\n on: { click: () => this.selectWidth(value) },\n });\n this.widthBtns.set(value, btn);\n widthGroup.append(btn);\n }\n\n this.undoBtn = el('button', {\n class: 'lens-tool-btn',\n ariaLabel: 'Undo',\n title: 'Undo',\n html: iconUndo,\n attrs: { type: 'button' },\n on: { click: () => this.undo() },\n });\n this.clearBtn = el('button', {\n class: 'lens-tool-btn',\n ariaLabel: 'Clear all',\n title: 'Clear all',\n html: iconTrash,\n attrs: { type: 'button' },\n on: { click: () => this.clear() },\n });\n const editGroup = el('div', { class: 'lens-tool-group' }, [this.undoBtn, this.clearBtn]);\n\n // A single close (✓/done) action: closing the toolbar KEEPS the marks — the\n // non-destructive default. Discarding is the trash button in editGroup.\n const closeBtn = el('button', {\n class: 'lens-tool-close',\n ariaLabel: 'Done',\n title: 'Done',\n html: iconClose,\n attrs: { type: 'button' },\n on: { click: () => this.exit() },\n });\n\n // Dedicated drag grip: it is the ONLY drag handle, so the tool row itself\n // stays free to scroll horizontally on narrow screens without the two\n // gestures fighting. The scrollable tools live in their own track.\n const grip = el('span', {\n class: 'lens-tool-grip',\n html: iconGrip,\n title: 'Drag to move toolbar',\n ariaLabel: 'Drag to move toolbar',\n });\n // Tools/colors/widths/edit scroll horizontally between the pinned grip\n // (left) and the pinned close (right), so it is always reachable without\n // scrolling on narrow screens.\n const track = el('div', { class: 'lens-tool-track' }, [\n toolGroup,\n el('span', { class: 'lens-tool-sep' }),\n colorGroup,\n el('span', { class: 'lens-tool-sep' }),\n widthGroup,\n el('span', { class: 'lens-tool-sep' }),\n editGroup,\n ]);\n\n this.toolbar = el(\n 'div',\n { class: 'lens-annotate-toolbar', attrs: { role: 'toolbar', 'aria-label': 'Annotation tools' } },\n [grip, track, closeBtn],\n );\n this.host.append(this.toolbar);\n this.toolbarDrag = makeDraggable(this.toolbar, {\n handle: grip,\n key: 'lens-annotate-toolbar',\n ignore: isInteractiveTarget,\n });\n this.syncActionButtons();\n }\n\n private removeToolbar(): void {\n this.toolbarDrag?.destroy();\n this.toolbarDrag = null;\n this.toolbar?.remove();\n this.toolbar = null;\n this.toolBtns.clear();\n this.colorBtns.clear();\n this.widthBtns.clear();\n this.undoBtn = null;\n this.clearBtn = null;\n }\n\n private selectTool(tool: Tool): void {\n this.commitTextInput();\n this.tool = tool;\n for (const [t, btn] of this.toolBtns) {\n const on = t === tool;\n btn.classList.toggle('is-active', on);\n btn.setAttribute('aria-pressed', String(on));\n }\n if (this.svg) this.svg.style.cursor = tool === 'text' ? 'text' : 'crosshair';\n }\n\n private selectColor(color: string): void {\n this.color = color;\n for (const [c, btn] of this.colorBtns) {\n const on = c === color;\n btn.classList.toggle('is-active', on);\n btn.setAttribute('aria-pressed', String(on));\n }\n }\n\n private selectWidth(value: number): void {\n this.width = value;\n for (const [v, btn] of this.widthBtns) {\n const on = v === value;\n btn.classList.toggle('is-active', on);\n btn.setAttribute('aria-pressed', String(on));\n }\n }\n\n private syncActionButtons(): void {\n const empty = this.markNodes.length === 0;\n // Undo only reaches marks drawn in the current session; disable it once the\n // stack is back down to the session base even if earlier marks remain.\n if (this.undoBtn) this.undoBtn.disabled = this.markNodes.length <= this.sessionBase;\n if (this.clearBtn) this.clearBtn.disabled = empty;\n }\n\n // --------------------------------------------------------------------------\n // Pointer / drawing\n // --------------------------------------------------------------------------\n\n private toDoc(e: PointerEvent): Point {\n return {\n x: e.clientX + (window.scrollX || window.pageXOffset || 0),\n y: e.clientY + (window.scrollY || window.pageYOffset || 0),\n };\n }\n\n private onPointerDown = (e: PointerEvent): void => {\n if (!this.active) return;\n // Guard re-entrancy: a second pointerdown while a drag is in flight (e.g. a\n // second finger, or a synthetic event) would orphan the current draft node\n // and leak its window listeners. Ignore it — the in-progress drag owns the\n // gesture until pointerup/pointercancel.\n if (this.drag) return;\n if (e.button !== undefined && e.button !== 0) return; // primary button only\n e.preventDefault();\n const p = this.toDoc(e);\n const tool = this.tool;\n\n if (tool === 'text') {\n this.openTextInput(e.clientX, e.clientY, p);\n return;\n }\n if (tool === 'step') {\n this.placeStep(p);\n return;\n }\n\n const color = this.color;\n const width = this.width;\n let drag: DragState;\n\n if (tool === 'pencil' || tool === 'highlighter') {\n const poly = this.svgEl('polyline', {\n 'data-lens-draft': '1',\n fill: 'none',\n stroke: color,\n 'stroke-width': tool === 'highlighter' ? HIGHLIGHTER_WIDTH : width,\n 'stroke-linecap': 'round',\n 'stroke-linejoin': 'round',\n ...(tool === 'highlighter' ? { 'stroke-opacity': '0.35' } : {}),\n points: `${p.x},${p.y}`,\n });\n this.svg!.append(poly);\n drag = { tool, color, width, start: p, node: poly, points: [p], last: p };\n } else if (tool === 'arrow') {\n const g = this.svgEl('g', { 'data-lens-draft': '1' });\n const line = this.svgEl('line', {\n stroke: color,\n 'stroke-width': width,\n 'stroke-linecap': 'round',\n });\n const head = this.svgEl('polygon', { fill: color });\n g.append(line, head);\n this.svg!.append(g);\n drag = { tool, color, width, start: p, node: g, line, head };\n this.updateArrow(drag, p);\n } else {\n const node = this.createShapeNode(tool, color, width);\n this.svg!.append(node);\n drag = { tool, color, width, start: p, node };\n this.updateShape(drag, p);\n }\n\n this.drag = drag;\n window.addEventListener('pointermove', this.onPointerMove, true);\n window.addEventListener('pointerup', this.onPointerUp, true);\n window.addEventListener('pointercancel', this.onPointerCancel, true);\n };\n\n private onPointerMove = (e: PointerEvent): void => {\n const d = this.drag;\n if (!d) return;\n const p = this.toDoc(e);\n if (d.tool === 'pencil' || d.tool === 'highlighter') {\n const pts = d.points!;\n if (d.last && shouldKeepPoint(d.last, p) && pts.length < MAX_POINTS) {\n pts.push(p);\n d.last = p;\n d.node.setAttribute('points', this.pointsAttr(pts));\n }\n } else if (d.tool === 'arrow') {\n this.updateArrow(d, p);\n } else {\n this.updateShape(d, p);\n }\n };\n\n private onPointerUp = (e: PointerEvent): void => {\n const d = this.drag;\n this.detachDragListeners();\n this.drag = null;\n if (!d) return;\n const p = this.toDoc(e);\n let annotation: Annotation | null = null;\n\n if (d.tool === 'pencil' || d.tool === 'highlighter') {\n let pts = d.points!;\n if (pts.length >= 2) pts = simplifyPoints(pts, 1);\n if (pts.length < 2) {\n d.node.remove();\n return;\n }\n d.node.setAttribute('points', this.pointsAttr(pts));\n annotation =\n d.tool === 'pencil'\n ? { kind: 'pencil', points: pts, color: d.color, strokeWidth: d.width, id: this.nextId() }\n : {\n kind: 'highlighter',\n points: pts,\n color: d.color,\n strokeWidth: HIGHLIGHTER_WIDTH,\n id: this.nextId(),\n };\n } else if (d.tool === 'arrow' || d.tool === 'line') {\n if (distance(d.start, p) < MIN_DRAG) {\n d.node.remove();\n return;\n }\n if (d.tool === 'arrow') {\n this.updateArrow(d, p);\n annotation = {\n kind: 'arrow',\n x1: d.start.x,\n y1: d.start.y,\n x2: p.x,\n y2: p.y,\n color: d.color,\n strokeWidth: d.width,\n id: this.nextId(),\n };\n } else {\n this.updateShape(d, p);\n annotation = {\n kind: 'line',\n x1: d.start.x,\n y1: d.start.y,\n x2: p.x,\n y2: p.y,\n color: d.color,\n strokeWidth: d.width,\n id: this.nextId(),\n };\n }\n } else {\n const x = Math.min(d.start.x, p.x);\n const y = Math.min(d.start.y, p.y);\n const width = Math.abs(p.x - d.start.x);\n const height = Math.abs(p.y - d.start.y);\n if (width < MIN_DRAG || height < MIN_DRAG) {\n d.node.remove();\n return;\n }\n this.updateShape(d, p);\n if (d.tool === 'rect') {\n annotation = {\n kind: 'rect',\n x,\n y,\n width,\n height,\n color: d.color,\n strokeWidth: d.width,\n id: this.nextId(),\n };\n } else if (d.tool === 'ellipse') {\n annotation = {\n kind: 'ellipse',\n x,\n y,\n width,\n height,\n color: d.color,\n strokeWidth: d.width,\n id: this.nextId(),\n };\n } else {\n // blur ignores color/width\n annotation = { kind: 'blur', x, y, width, height, id: this.nextId() };\n }\n }\n\n d.node.removeAttribute('data-lens-draft');\n this.commitMark(annotation, d.node);\n };\n\n /** Pointer capture was cancelled (OS gesture, page hidden, etc.): drop the\n * in-progress draft node and detach listeners so nothing leaks. */\n private onPointerCancel = (): void => {\n const d = this.drag;\n this.detachDragListeners();\n this.drag = null;\n d?.node.remove();\n };\n\n private detachDragListeners(): void {\n window.removeEventListener('pointermove', this.onPointerMove, true);\n window.removeEventListener('pointerup', this.onPointerUp, true);\n window.removeEventListener('pointercancel', this.onPointerCancel, true);\n }\n\n private commitMark(annotation: Annotation, node: SVGElement): void {\n this.annotations.push(annotation);\n this.markNodes.push(node);\n this.syncActionButtons();\n }\n\n private createShapeNode(tool: Tool, color: string, width: number): SVGElement {\n if (tool === 'ellipse') {\n return this.svgEl('ellipse', {\n 'data-lens-draft': '1',\n fill: 'none',\n stroke: color,\n 'stroke-width': width,\n });\n }\n if (tool === 'line') {\n return this.svgEl('line', {\n 'data-lens-draft': '1',\n stroke: color,\n 'stroke-width': width,\n 'stroke-linecap': 'round',\n });\n }\n if (tool === 'blur') {\n return this.svgEl('rect', {\n 'data-lens-draft': '1',\n 'data-lens-blur': '1',\n fill: 'url(#lens-blur-hatch)',\n stroke: '#111827',\n 'stroke-width': 1,\n 'stroke-dasharray': '4 3',\n });\n }\n // rect\n return this.svgEl('rect', {\n 'data-lens-draft': '1',\n fill: 'none',\n stroke: color,\n 'stroke-width': width,\n rx: 2,\n });\n }\n\n private updateShape(d: DragState, cur: Point): void {\n const x = Math.min(d.start.x, cur.x);\n const y = Math.min(d.start.y, cur.y);\n const w = Math.abs(cur.x - d.start.x);\n const h = Math.abs(cur.y - d.start.y);\n const node = d.node;\n if (d.tool === 'ellipse') {\n node.setAttribute('cx', String(x + w / 2));\n node.setAttribute('cy', String(y + h / 2));\n node.setAttribute('rx', String(w / 2));\n node.setAttribute('ry', String(h / 2));\n } else if (d.tool === 'line') {\n node.setAttribute('x1', String(d.start.x));\n node.setAttribute('y1', String(d.start.y));\n node.setAttribute('x2', String(cur.x));\n node.setAttribute('y2', String(cur.y));\n } else {\n // rect / blur\n node.setAttribute('x', String(x));\n node.setAttribute('y', String(y));\n node.setAttribute('width', String(w));\n node.setAttribute('height', String(h));\n }\n }\n\n private updateArrow(d: DragState, cur: Point): void {\n if (!d.line || !d.head) return;\n d.line.setAttribute('x1', String(d.start.x));\n d.line.setAttribute('y1', String(d.start.y));\n d.line.setAttribute('x2', String(cur.x));\n d.line.setAttribute('y2', String(cur.y));\n const size = Math.max(12, d.width * 3);\n const poly = arrowheadPolygon(d.start.x, d.start.y, cur.x, cur.y, size);\n d.head.setAttribute('points', this.pointsAttr(poly));\n }\n\n // --------------------------------------------------------------------------\n // Text tool\n // --------------------------------------------------------------------------\n\n private openTextInput(clientX: number, clientY: number, docPoint: Point): void {\n this.commitTextInput();\n const input = el('input', {\n class: 'lens-text-input',\n attrs: { type: 'text', 'aria-label': 'Annotation text' },\n style: { left: `${clientX}px`, top: `${clientY}px`, color: this.color },\n });\n input.addEventListener('blur', () => this.commitTextInput());\n this.host.append(input);\n this.textInputEl = input;\n this.textAnchor = docPoint;\n this.textColor = this.color;\n input.focus();\n }\n\n private commitTextInput(): void {\n const input = this.textInputEl;\n const anchor = this.textAnchor;\n if (!input || !anchor) return;\n const value = input.value.trim();\n this.textInputEl = null;\n this.textAnchor = null;\n input.remove();\n if (!value) return;\n const node = this.svgEl('text', {\n x: anchor.x,\n y: anchor.y,\n fill: this.textColor,\n 'font-size': 16,\n 'font-family': FONT,\n 'dominant-baseline': 'hanging',\n });\n node.textContent = value;\n this.svg!.append(node);\n this.commitMark(\n {\n kind: 'text',\n x: anchor.x,\n y: anchor.y,\n text: value,\n fontSize: 16,\n color: this.textColor,\n id: this.nextId(),\n },\n node,\n );\n }\n\n private cancelTextInput(): void {\n if (!this.textInputEl) return;\n this.textInputEl.remove();\n this.textInputEl = null;\n this.textAnchor = null;\n }\n\n // --------------------------------------------------------------------------\n // Step tool\n // --------------------------------------------------------------------------\n\n private placeStep(p: Point): void {\n const n = ++this.stepCounter;\n const g = this.svgEl('g', {});\n const circle = this.svgEl('circle', {\n cx: p.x,\n cy: p.y,\n r: STEP_RADIUS,\n fill: this.color,\n });\n const text = this.svgEl('text', {\n x: p.x,\n y: p.y,\n fill: '#ffffff',\n 'font-size': 13,\n 'font-weight': 700,\n 'font-family': FONT,\n 'text-anchor': 'middle',\n 'dominant-baseline': 'central',\n });\n text.textContent = String(n);\n g.append(circle, text);\n this.svg!.append(g);\n this.commitMark({ kind: 'step', x: p.x, y: p.y, n, color: this.color, id: this.nextId() }, g);\n }\n\n // --------------------------------------------------------------------------\n // Keyboard\n // --------------------------------------------------------------------------\n\n private onKey = (e: KeyboardEvent): void => {\n if (this.textInputEl) {\n if (e.key === 'Escape') {\n e.preventDefault();\n e.stopPropagation();\n this.cancelTextInput();\n } else if (e.key === 'Enter') {\n e.preventDefault();\n e.stopPropagation();\n this.commitTextInput();\n }\n return;\n }\n if (e.key === 'Escape') {\n e.preventDefault();\n e.stopPropagation();\n this.exit();\n }\n };\n\n // --------------------------------------------------------------------------\n // Small helpers\n // --------------------------------------------------------------------------\n\n private svgEl(tag: string, attrs: Record<string, string | number>): SVGElement {\n const node = document.createElementNS(SVG_NS, tag) as SVGElement;\n for (const [k, v] of Object.entries(attrs)) node.setAttribute(k, String(v));\n return node;\n }\n\n private pointsAttr(points: Point[]): string {\n return points.map((p) => `${p.x},${p.y}`).join(' ');\n }\n\n private nextId(): string {\n return `lens-${++this.idSeq}`;\n }\n}\n","import type { TargetElement } from '@horus-lens/shared';\nimport { clear, el } from './dom.js';\nimport { makeDraggable, type DraggableHandle } from './draggable.js';\nimport {\n iconAnnotate,\n iconCheck,\n iconClose,\n iconCopy,\n iconGrip,\n iconRecord,\n iconSend,\n} from './icons.js';\nimport type { IncludeState, OverlayStats, SubmitReportIncludes } from './types.js';\n\nexport interface PanelCallbacks {\n getStats: () => OverlayStats;\n getTarget: () => TargetElement | null;\n getAnnotationCount: () => number;\n /** Duration of a retained \"record steps\" recording, or `null` if none. */\n getRecording: () => { durationMs: number } | null;\n onRemoveTarget: () => void;\n onMarkArea: () => void;\n onRecordSteps: () => void;\n onDiscardRecording: () => void;\n onClose: () => void;\n onSubmit: (comment: string, include: SubmitReportIncludes) => Promise<{ reportId: string }>;\n}\n\n/** The bottom-right report card: compose, submit, success / error states. */\nexport class Panel {\n readonly root: HTMLElement;\n private body: HTMLElement;\n private textarea!: HTMLTextAreaElement;\n private submitBtn!: HTMLButtonElement;\n private drag: DraggableHandle | null = null;\n private autoCloseTimer: ReturnType<typeof setTimeout> | null = null;\n private submitting = false;\n /** Selected capture toggles; every flag starts ON. Persists across refresh. */\n private readonly include: IncludeState = {\n replay: true,\n console: true,\n network: true,\n errors: true,\n screenshot: true,\n };\n\n constructor(private readonly cb: PanelCallbacks) {\n this.body = el('div', { class: 'lens-panel__body' });\n const head = el('div', { class: 'lens-panel__head' }, [\n el('span', {\n class: 'lens-panel__grip',\n html: iconGrip,\n title: 'Drag to move',\n ariaLabel: 'Drag to move panel',\n }),\n el('div', { class: 'lens-panel__title', text: 'Report an issue' }),\n el('button', {\n class: 'lens-panel__x',\n ariaLabel: 'Close',\n html: iconClose,\n on: { click: () => this.cb.onClose() },\n }),\n ]);\n this.root = el(\n 'div',\n { class: 'lens-panel', attrs: { role: 'dialog', 'aria-label': 'Report an issue' } },\n [head, this.body],\n );\n // Draggable by the header so it can be moved off content it covers; the\n // close button is excluded from the grab. Position persists for the session\n // (the panel is recreated on each open, so this restores where it was left).\n this.drag = makeDraggable(this.root, { handle: head, key: 'lens-panel' });\n this.renderForm();\n }\n\n /** Re-render the compose view (chips reflect latest target / annotations). */\n refresh(): void {\n if (!this.submitting) this.renderForm();\n }\n\n focus(): void {\n this.textarea?.focus();\n }\n\n destroy(): void {\n if (this.autoCloseTimer) clearTimeout(this.autoCloseTimer);\n this.drag?.destroy();\n this.drag = null;\n this.root.remove();\n }\n\n private renderForm(): void {\n const prior = this.textarea?.value ?? '';\n clear(this.body);\n\n this.textarea = el('textarea', {\n class: 'lens-textarea',\n placeholder: \"What's wrong? Describe the issue…\",\n ariaLabel: 'Issue description',\n });\n this.textarea.value = prior;\n\n this.body.append(\n this.textarea,\n this.buildContext(),\n this.buildChips(),\n this.buildActions(),\n );\n }\n\n /** Static, non-interactive page context: route · browser · os · viewport. */\n private buildContext(): HTMLElement {\n const s = this.cb.getStats();\n const parts = [\n truncate(s.route || s.url, 40),\n `${s.browser} · ${s.os}`,\n `${s.viewport.width}×${s.viewport.height}`,\n ];\n const nodes: (HTMLElement | string)[] = [];\n parts.forEach((part, i) => {\n if (i > 0) nodes.push(el('span', { class: 'lens-context__dot', text: '·' }));\n nodes.push(el('span', { class: 'lens-context__item', text: part }));\n });\n return el('div', { class: 'lens-context', title: s.url }, nodes);\n }\n\n /** Removable context chips: annotations, retained recording, picked element. */\n private buildChips(): HTMLElement {\n const row = el('div', { class: 'lens-chips' });\n\n const annCount = this.cb.getAnnotationCount();\n if (annCount > 0) {\n row.append(chip(`${annCount} annotation${annCount === 1 ? '' : 's'}`));\n }\n\n const recording = this.cb.getRecording();\n if (recording) {\n const recChip = el('span', { class: 'lens-chip lens-chip--ok lens-chip--rec' }, [\n el('span', { text: `recording ✓ ${formatDuration(recording.durationMs)}` }),\n el('button', {\n class: 'lens-chip__x',\n ariaLabel: 'Discard recording',\n text: '×',\n on: { click: () => this.cb.onDiscardRecording() },\n }),\n ]);\n row.append(recChip);\n }\n\n const target = this.cb.getTarget();\n if (target) {\n const label = target.domPath || target.tagName || 'element';\n const targetChip = el('span', { class: 'lens-chip lens-chip--target', title: label }, [\n el('span', { class: 'lens-chip__code', text: truncate(label, 40) }),\n el('button', {\n class: 'lens-chip__x',\n ariaLabel: 'Remove element',\n text: '×',\n on: { click: () => this.cb.onRemoveTarget() },\n }),\n ]);\n row.append(targetChip);\n }\n\n // Collapse to nothing when empty so the section gap doesn't leave a void.\n row.style.display = row.childElementCount > 0 ? '' : 'none';\n return row;\n }\n\n private buildActions(): HTMLElement {\n const mark = el('button', {\n class: 'lens-abtn lens-abtn--ghost lens-abtn--compact',\n html: iconAnnotate + '<span>Annotate</span>',\n on: { click: () => this.cb.onMarkArea() },\n });\n const record = el('button', {\n class: 'lens-abtn lens-abtn--ghost lens-abtn--compact',\n html: iconRecord + '<span>Record steps</span>',\n on: { click: () => this.cb.onRecordSteps() },\n });\n const cancel = el('button', {\n class: 'lens-abtn lens-abtn--ghost',\n text: 'Cancel',\n on: { click: () => this.cb.onClose() },\n });\n this.submitBtn = el('button', {\n class: 'lens-abtn lens-abtn--primary lens-abtn--submit',\n html: iconSend + '<span>Submit</span>',\n on: { click: () => void this.submit() },\n });\n return el('div', { class: 'lens-actions' }, [\n el('div', { class: 'lens-actions__row lens-actions__secondary' }, [mark, record]),\n el('div', { class: 'lens-actions__row lens-actions__primary' }, [cancel, this.submitBtn]),\n ]);\n }\n\n private async submit(): Promise<void> {\n if (this.submitting) return;\n const comment = this.textarea.value.trim();\n this.submitting = true;\n this.submitBtn.disabled = true;\n this.submitBtn.innerHTML = '<span>Submitting…</span>';\n try {\n const { reportId } = await this.cb.onSubmit(comment, { ...this.include });\n this.renderSuccess(reportId);\n } catch (err) {\n this.renderError(err instanceof Error ? err.message : 'Something went wrong');\n } finally {\n this.submitting = false;\n }\n }\n\n private renderSuccess(reportId: string): void {\n clear(this.body);\n const idPill = el('div', { class: 'lens-idpill' }, [\n el('span', { text: reportId }),\n el('button', {\n ariaLabel: 'Copy report id',\n html: iconCopy,\n on: {\n click: (e) => {\n const btn = e.currentTarget as HTMLButtonElement;\n void copy(reportId).then(() => {\n btn.innerHTML = iconCheck;\n setTimeout(() => (btn.innerHTML = iconCopy), 1200);\n });\n },\n },\n }),\n ]);\n this.body.append(\n el('div', { class: 'lens-state' }, [\n el('div', { class: 'lens-state__badge lens-state__badge--ok', html: iconCheck }),\n el('div', { class: 'lens-state__title', text: 'Report submitted' }),\n el('div', { class: 'lens-state__msg', text: 'Thanks — the team can see the full context.' }),\n idPill,\n ]),\n );\n this.autoCloseTimer = setTimeout(() => this.cb.onClose(), 2500);\n }\n\n private renderError(message: string): void {\n clear(this.body);\n this.body.append(\n el('div', { class: 'lens-state' }, [\n el('div', { class: 'lens-state__badge lens-state__badge--err', html: iconClose }),\n el('div', { class: 'lens-state__title', text: 'Submission failed' }),\n el('div', { class: 'lens-state__msg', text: truncate(message, 120) }),\n el('div', { class: 'lens-actions' }, [\n el('button', {\n class: 'lens-abtn lens-abtn--ghost',\n text: 'Cancel',\n on: { click: () => this.cb.onClose() },\n }),\n el('button', {\n class: 'lens-abtn lens-abtn--primary',\n text: 'Retry',\n on: { click: () => this.renderForm() },\n }),\n ]),\n ]),\n );\n }\n}\n\nfunction chip(text: string, title?: string, extra?: string): HTMLElement {\n return el('span', { class: `lens-chip${extra ? ' ' + extra : ''}`, text, title: title ?? text });\n}\n\nfunction truncate(value: string, max: number): string {\n return value.length > max ? value.slice(0, max - 1) + '…' : value;\n}\n\n/** Format milliseconds as `m:ss` (e.g. 42000 → \"0:42\"). */\nexport function formatDuration(ms: number): string {\n const total = Math.max(0, Math.round(ms / 1000));\n const m = Math.floor(total / 60);\n const s = total % 60;\n return `${m}:${s.toString().padStart(2, '0')}`;\n}\n\nasync function copy(text: string): Promise<void> {\n try {\n await navigator.clipboard.writeText(text);\n } catch {\n /* clipboard blocked — silently ignore */\n }\n}\n","import { el } from './dom.js';\n\n/**\n * Element picker. Highlights an element with a fixed overlay box (never mutates\n * host element styles) and resolves the chosen element. Events originating\n * inside the overlay's own shadow tree are ignored so the pill / panel stay\n * interactive.\n *\n * Pointer-based so it works with mouse, pen and touch:\n * - Fine pointers (mouse/pen): hover highlights; a click confirms.\n * - Coarse pointers (touch): no hover, so the first tap highlights the element\n * under the finger, a second tap on the *same* element confirms, and a tap\n * elsewhere moves the highlight. A floating \"Tap an element — Cancel\" chip is\n * shown since mobile has no Escape key. Escape still cancels on desktop.\n */\nexport class ElementPicker {\n private highlight: HTMLElement;\n private tag: HTMLElement;\n private hint: HTMLElement;\n private current: Element | null = null;\n private active = false;\n private onPick: ((elem: Element) => void) | null = null;\n private onCancel: (() => void) | null = null;\n\n constructor(\n private readonly layer: HTMLElement,\n private readonly rootHost: HTMLElement,\n ) {\n this.tag = el('div', { class: 'lens-highlight__tag' });\n this.highlight = el('div', { class: 'lens-highlight' }, [this.tag]);\n this.hint = el('div', { class: 'lens-pick-chip' }, [\n el('span', { class: 'lens-pick-chip__label', text: 'Tap an element' }),\n el('button', {\n class: 'lens-pick-chip__btn',\n text: 'Cancel',\n on: { click: () => this.cancel() },\n }),\n ]);\n this.layer.append(this.highlight, this.hint);\n this.hide();\n }\n\n get isActive(): boolean {\n return this.active;\n }\n\n start(onPick: (elem: Element) => void, onCancel: () => void): void {\n if (this.active) return;\n this.active = true;\n this.onPick = onPick;\n this.onCancel = onCancel;\n this.current = null;\n this.hint.style.display = '';\n window.addEventListener('pointermove', this.onMove, true);\n window.addEventListener('pointerdown', this.onDown, true);\n window.addEventListener('pointerup', this.onUp, true);\n window.addEventListener('click', this.onClick, true);\n window.addEventListener('keydown', this.onKey, true);\n }\n\n stop(): void {\n if (!this.active) return;\n this.active = false;\n this.current = null;\n this.onPick = null;\n this.onCancel = null;\n this.hide();\n window.removeEventListener('pointermove', this.onMove, true);\n window.removeEventListener('pointerdown', this.onDown, true);\n window.removeEventListener('pointerup', this.onUp, true);\n window.removeEventListener('click', this.onClick, true);\n window.removeEventListener('keydown', this.onKey, true);\n }\n\n private cancel(): void {\n const cancel = this.onCancel;\n this.stop();\n cancel?.();\n }\n\n private hide(): void {\n this.highlight.style.display = 'none';\n this.hint.style.display = 'none';\n }\n\n private isOverlayEvent(e: Event): boolean {\n return e.composedPath().includes(this.rootHost);\n }\n\n private isCoarse(): boolean {\n return typeof window.matchMedia === 'function' && window.matchMedia('(pointer: coarse)').matches;\n }\n\n private elementAt(x: number, y: number): Element | null {\n const found = document.elementFromPoint(x, y);\n if (!found || found === this.rootHost) return null;\n return found;\n }\n\n private highlightElement(target: Element): void {\n this.current = target;\n const rect = target.getBoundingClientRect();\n Object.assign(this.highlight.style, {\n display: 'block',\n left: `${rect.left}px`,\n top: `${rect.top}px`,\n width: `${rect.width}px`,\n height: `${rect.height}px`,\n });\n this.tag.textContent = describe(target);\n }\n\n private confirm(target: Element): void {\n const pick = this.onPick;\n // The browser dispatches `click` AFTER pointerup — by then stop() has\n // removed our click suppressor, so a picked link/button would fire its own\n // action. Swallow exactly one trailing click before handing over.\n this.suppressNextClick();\n this.stop();\n pick?.(target);\n }\n\n private suppressNextClick(): void {\n const swallow = (e: MouseEvent): void => {\n e.preventDefault();\n e.stopImmediatePropagation();\n cleanup();\n };\n const cleanup = (): void => {\n window.removeEventListener('click', swallow, true);\n clearTimeout(timer);\n };\n window.addEventListener('click', swallow, { capture: true });\n // Safety: if no click arrives (e.g. keyboard-driven pick), don't leak the\n // suppressor into the next real interaction.\n const timer = setTimeout(cleanup, 500);\n }\n\n private onMove = (e: PointerEvent): void => {\n if (this.isOverlayEvent(e)) return;\n // On coarse pointers there is no hover; highlight is driven by taps instead.\n if (this.isCoarse()) return;\n const target = this.elementAt(e.clientX, e.clientY);\n if (!target || target === this.current) return;\n this.highlightElement(target);\n };\n\n private onDown = (e: PointerEvent): void => {\n if (this.isOverlayEvent(e)) return;\n // Block the underlying page from reacting to the press.\n e.preventDefault();\n e.stopImmediatePropagation();\n };\n\n private onUp = (e: PointerEvent): void => {\n if (this.isOverlayEvent(e)) return;\n e.preventDefault();\n e.stopImmediatePropagation();\n const target = this.elementAt(e.clientX, e.clientY);\n if (this.isCoarse()) {\n // Two-tap: first tap (or a tap on a different element) highlights; a\n // second tap on the same element confirms.\n if (target && target === this.current) {\n this.confirm(target);\n } else if (target) {\n this.highlightElement(target);\n }\n return;\n }\n const chosen = target ?? this.current;\n if (chosen) this.confirm(chosen);\n };\n\n private onClick = (e: MouseEvent): void => {\n if (this.isOverlayEvent(e)) return;\n // Swallow the synthetic click so links / buttons don't navigate.\n e.preventDefault();\n e.stopImmediatePropagation();\n };\n\n private onKey = (e: KeyboardEvent): void => {\n if (e.key !== 'Escape') return;\n e.preventDefault();\n e.stopPropagation();\n this.cancel();\n };\n}\n\nfunction describe(elem: Element): string {\n const tag = elem.tagName.toLowerCase();\n const id = elem.id ? `#${elem.id}` : '';\n const cls =\n typeof elem.className === 'string' && elem.className.trim()\n ? '.' + elem.className.trim().split(/\\s+/).slice(0, 2).join('.')\n : '';\n return `${tag}${id}${cls}`;\n}\n","/**\n * Overlay stylesheet, injected once into the shadow root. Scoped by `:host`\n * with `all: initial` so no host-page CSS can leak in and nothing here leaks\n * out. Dark, glassy pill; a light-aware panel that respects prefers-color-scheme;\n * an 8px radius/spacing grid and 150ms transitions throughout.\n */\nexport const OVERLAY_CSS = /* css */ `\n:host {\n all: initial;\n /* Black & white, mirroring the Horus Cloud dashboard: the accent is near-black\n in light and near-white in dark; the always-dark pill/toolbar use explicit\n light highlights (defined at their rules). Annotation swatch colors and\n status red/green are content, not brand, and keep their hues. */\n --lens-accent: #18181b;\n --lens-accent-strong: #000000;\n --lens-on-accent: #ffffff;\n --lens-focus: rgba(0, 0, 0, 0.16);\n --lens-radius: 8px;\n --lens-font: system-ui, -apple-system, \"Segoe UI\", Roboto, Helvetica, Arial, sans-serif;\n --lens-z: 2147483000;\n font-family: var(--lens-font);\n line-height: 1.4;\n}\n@media (prefers-color-scheme: dark) {\n :host {\n --lens-accent: #fafafa;\n --lens-accent-strong: #ffffff;\n --lens-on-accent: #18181b;\n --lens-focus: rgba(255, 255, 255, 0.22);\n }\n}\n\n*, *::before, *::after { box-sizing: border-box; }\n\n.lens-layer {\n position: fixed;\n inset: 0;\n z-index: var(--lens-z);\n pointer-events: none;\n font-family: var(--lens-font);\n}\n.lens-layer > * { pointer-events: auto; }\n\n/* ---------------- Pill ---------------- */\n.lens-pill {\n position: fixed;\n bottom: calc(12px + env(safe-area-inset-bottom));\n left: 50%;\n transform: translateX(-50%);\n max-width: calc(100vw - 16px);\n flex-wrap: nowrap;\n justify-content: center;\n display: inline-flex;\n align-items: center;\n gap: 4px;\n padding: 6px;\n border-radius: 999px;\n background: rgba(20, 20, 23, 0.82);\n -webkit-backdrop-filter: blur(12px) saturate(180%);\n backdrop-filter: blur(12px) saturate(180%);\n border: 1px solid rgba(255, 255, 255, 0.12);\n box-shadow: 0 8px 30px rgba(0, 0, 0, 0.35), inset 0 1px 0 rgba(255, 255, 255, 0.06);\n color: #f4f4f5;\n user-select: none;\n transition: opacity 150ms ease, transform 150ms ease;\n}\n.lens-pill__dot {\n display: inline-flex;\n align-items: center;\n justify-content: center;\n width: 26px;\n height: 26px;\n margin-left: 4px;\n border-radius: 999px;\n color: #f4f4f5;\n}\n.lens-btn {\n display: inline-flex;\n align-items: center;\n gap: 6px;\n height: 30px;\n padding: 0 12px;\n border: 0;\n border-radius: 999px;\n background: transparent;\n color: #e4e4e7;\n font-family: var(--lens-font);\n font-size: 13px;\n font-weight: 500;\n cursor: pointer;\n transition: background 150ms ease, color 150ms ease;\n}\n.lens-btn:hover { background: rgba(255, 255, 255, 0.1); }\n.lens-btn:focus-visible { outline: 2px solid rgba(255, 255, 255, 0.7); outline-offset: 1px; }\n.lens-btn--primary { background: #fff; color: #18181b; }\n.lens-btn--primary:hover { background: #e4e4e7; }\n.lens-btn--report svg { flex: none; }\n.lens-btn__label { white-space: nowrap; }\n.lens-btn--icon { width: 30px; padding: 0; justify-content: center; }\n/* Always-dark pill: an active control reads as a light (white) highlight. */\n.lens-btn--icon.is-active { background: #fff; color: #18181b; }\n.lens-pill__sep {\n width: 1px;\n height: 18px;\n background: rgba(255, 255, 255, 0.14);\n margin: 0 2px;\n}\n\n/* ---------------- Picker highlight ---------------- */\n.lens-highlight {\n position: fixed;\n z-index: calc(var(--lens-z) - 2);\n pointer-events: none;\n border: 2px solid var(--lens-accent);\n /* A light outer ring so the (black-in-light / white-in-dark) border stays\n visible over any page background. */\n box-shadow: 0 0 0 1px rgba(255, 255, 255, 0.6), 0 0 0 3px rgba(0, 0, 0, 0.15);\n background: rgba(127, 127, 127, 0.14);\n border-radius: 3px;\n transition: all 60ms linear;\n display: none;\n}\n.lens-highlight__tag {\n position: absolute;\n top: -22px;\n left: -2px;\n padding: 1px 6px;\n border-radius: 4px;\n background: var(--lens-accent);\n color: var(--lens-on-accent);\n font: 500 11px/1.5 var(--lens-font);\n white-space: nowrap;\n}\n.lens-hint {\n position: fixed;\n bottom: 64px;\n left: 50%;\n transform: translateX(-50%);\n padding: 6px 12px;\n border-radius: 999px;\n background: rgba(20, 20, 23, 0.9);\n color: #e4e4e7;\n font-size: 12px;\n font-weight: 500;\n border: 1px solid rgba(255, 255, 255, 0.12);\n box-shadow: 0 6px 20px rgba(0, 0, 0, 0.3);\n pointer-events: none;\n}\n\n/* ---------------- Annotation SVG layer ---------------- */\n/* One full-DOCUMENT SVG anchored to page content (translated by -scroll so\n marks survive scrolling). pointer-events flip to auto only while drawing. */\n.lens-annotate-svg {\n position: absolute;\n left: 0;\n top: 0;\n z-index: calc(var(--lens-z) - 1);\n pointer-events: none;\n overflow: visible;\n}\n\n/* Floating text-entry input for the Text tool (viewport-positioned). */\n.lens-text-input {\n position: fixed;\n z-index: var(--lens-z);\n min-width: 120px;\n padding: 2px 6px;\n border: 1px solid var(--lens-accent);\n border-radius: 4px;\n background: rgba(255, 255, 255, 0.96);\n color: #111827;\n font-family: var(--lens-font);\n font-size: 15px;\n line-height: 1.3;\n box-shadow: 0 4px 16px rgba(0, 0, 0, 0.25);\n outline: none;\n}\n\n/* ---------------- Panel ---------------- */\n.lens-panel {\n position: fixed;\n right: 20px;\n bottom: 64px;\n width: min(520px, calc(100vw - 40px));\n max-width: 520px;\n max-height: calc(100vh - 96px);\n display: flex;\n flex-direction: column;\n border-radius: 14px;\n background: #ffffff;\n color: #18181b;\n border: 1px solid rgba(0, 0, 0, 0.08);\n box-shadow: 0 12px 40px rgba(0, 0, 0, 0.22), 0 2px 8px rgba(0, 0, 0, 0.08);\n overflow: hidden;\n transform-origin: bottom right;\n animation: lens-in 150ms ease;\n}\n@keyframes lens-in {\n from { opacity: 0; transform: translateY(6px) scale(0.98); }\n to { opacity: 1; transform: none; }\n}\n.lens-panel__head {\n display: flex;\n align-items: center;\n justify-content: space-between;\n padding: 14px 16px;\n border-bottom: 1px solid rgba(0, 0, 0, 0.07);\n}\n.lens-panel__title { font-size: 14px; font-weight: 600; margin-right: auto; }\n.lens-panel__x {\n display: inline-flex;\n align-items: center;\n justify-content: center;\n width: 26px;\n height: 26px;\n border: 0;\n border-radius: 6px;\n background: transparent;\n color: #52525b;\n cursor: pointer;\n transition: background 150ms ease;\n}\n.lens-panel__x:hover { background: rgba(0, 0, 0, 0.06); }\n.lens-panel__body {\n padding: 14px 16px;\n overflow-y: auto;\n display: flex;\n flex-direction: column;\n gap: 12px;\n}\n.lens-textarea {\n width: 100%;\n min-height: 120px;\n resize: vertical;\n padding: 10px 12px;\n border-radius: var(--lens-radius);\n border: 1px solid rgba(0, 0, 0, 0.14);\n background: #fafafa;\n color: inherit;\n font-family: var(--lens-font);\n font-size: 13px;\n transition: border-color 150ms ease, box-shadow 150ms ease;\n}\n.lens-textarea:focus {\n outline: none;\n border-color: var(--lens-accent);\n box-shadow: 0 0 0 3px var(--lens-focus);\n}\n/* ---- Context row: static, non-interactive page facts (muted, dot-joined) ---- */\n.lens-context {\n display: flex;\n flex-wrap: wrap;\n align-items: center;\n gap: 6px;\n font-size: 11.5px;\n line-height: 1.4;\n color: #71717a;\n}\n.lens-context__item { white-space: nowrap; }\n.lens-context__dot { opacity: 0.55; }\n\n.lens-chips { display: flex; flex-wrap: wrap; gap: 6px; }\n.lens-chip {\n display: inline-flex;\n align-items: center;\n gap: 5px;\n max-width: 100%;\n padding: 3px 9px;\n border-radius: 999px;\n background: #f4f4f5;\n border: 1px solid rgba(0, 0, 0, 0.06);\n color: #3f3f46;\n font-size: 11.5px;\n font-weight: 500;\n white-space: nowrap;\n overflow: hidden;\n text-overflow: ellipsis;\n}\n.lens-chip--ok { color: #15803d; background: #f0fdf4; border-color: rgba(21, 128, 61, 0.18); }\n.lens-chip--target {\n max-width: 100%;\n background: rgba(0, 0, 0, 0.05);\n border-color: rgba(0, 0, 0, 0.16);\n color: #18181b;\n}\n.lens-chip__code {\n font-family: ui-monospace, SFMono-Regular, Menlo, monospace;\n font-size: 11px;\n overflow: hidden;\n text-overflow: ellipsis;\n}\n.lens-chip__x {\n display: inline-flex;\n border: 0;\n background: transparent;\n color: inherit;\n cursor: pointer;\n padding: 0;\n opacity: 0.7;\n font-size: 13px;\n line-height: 1;\n}\n.lens-chip__x:hover { opacity: 1; }\n/* ---- Actions: secondary row (mark / record) then primary row (cancel / submit) ---- */\n.lens-actions { display: flex; flex-direction: column; gap: 8px; }\n.lens-actions__row { display: flex; align-items: center; gap: 8px; }\n/* Mark area / Record steps split the row evenly, one line, never wrap. */\n.lens-actions__secondary .lens-abtn { flex: 1; min-width: 0; justify-content: center; }\n/* Submit always fills remaining width; Cancel stays intrinsic. */\n.lens-actions__primary .lens-abtn--submit { flex: 1; }\n.lens-abtn {\n display: inline-flex;\n align-items: center;\n justify-content: center;\n gap: 6px;\n height: 34px;\n padding: 0 14px;\n border-radius: var(--lens-radius);\n border: 1px solid transparent;\n font-family: var(--lens-font);\n font-size: 13px;\n font-weight: 600;\n white-space: nowrap;\n cursor: pointer;\n transition: background 150ms ease, border-color 150ms ease, opacity 150ms ease;\n}\n.lens-abtn span { white-space: nowrap; }\n.lens-abtn--compact { padding: 0 10px; font-size: 12px; }\n.lens-abtn svg { flex: none; }\n.lens-abtn--ghost { background: transparent; border-color: rgba(0, 0, 0, 0.14); color: #3f3f46; }\n.lens-abtn--ghost:hover { background: rgba(0, 0, 0, 0.04); }\n.lens-abtn--primary { background: var(--lens-accent); color: var(--lens-on-accent); }\n.lens-abtn--primary:hover { background: var(--lens-accent-strong); }\n.lens-abtn:disabled { opacity: 0.55; cursor: default; }\n.lens-abtn:focus-visible { outline: 2px solid var(--lens-accent); outline-offset: 1px; }\n\n.lens-state {\n display: flex;\n flex-direction: column;\n align-items: center;\n gap: 10px;\n padding: 26px 18px;\n text-align: center;\n}\n.lens-state__badge {\n display: inline-flex;\n align-items: center;\n justify-content: center;\n width: 44px;\n height: 44px;\n border-radius: 999px;\n}\n.lens-state__badge--ok { background: #dcfce7; color: #16a34a; }\n.lens-state__badge--err { background: #fee2e2; color: #dc2626; }\n.lens-state__title { font-size: 14px; font-weight: 600; }\n.lens-state__msg { font-size: 12.5px; color: #52525b; }\n.lens-idpill {\n display: inline-flex;\n align-items: center;\n gap: 6px;\n padding: 5px 10px;\n border-radius: 8px;\n background: #f4f4f5;\n border: 1px solid rgba(0, 0, 0, 0.08);\n font-family: ui-monospace, SFMono-Regular, Menlo, monospace;\n font-size: 12px;\n}\n.lens-idpill button {\n border: 0;\n background: transparent;\n color: #52525b;\n cursor: pointer;\n display: inline-flex;\n padding: 2px;\n border-radius: 4px;\n}\n.lens-idpill button:hover { background: rgba(0, 0, 0, 0.06); color: #18181b; }\n\n@media (prefers-color-scheme: dark) {\n .lens-panel { background: #1c1c1f; color: #f4f4f5; border-color: rgba(255, 255, 255, 0.1); }\n .lens-panel__head { border-bottom-color: rgba(255, 255, 255, 0.08); }\n .lens-panel__x { color: #a1a1aa; }\n .lens-panel__x:hover { background: rgba(255, 255, 255, 0.08); }\n .lens-textarea { background: #26262a; border-color: rgba(255, 255, 255, 0.14); color: #f4f4f5; }\n .lens-context { color: #a1a1aa; }\n .lens-chip { background: #26262a; border-color: rgba(255, 255, 255, 0.08); color: #d4d4d8; }\n .lens-chip--ok { color: #4ade80; background: rgba(34, 197, 94, 0.12); border-color: rgba(74, 222, 128, 0.22); }\n .lens-chip--target { background: rgba(255, 255, 255, 0.1); border-color: rgba(255, 255, 255, 0.18); color: #f4f4f5; }\n .lens-abtn--ghost { border-color: rgba(255, 255, 255, 0.16); color: #d4d4d8; }\n .lens-abtn--ghost:hover { background: rgba(255, 255, 255, 0.06); }\n .lens-state__msg { color: #a1a1aa; }\n .lens-idpill { background: #26262a; border-color: rgba(255, 255, 255, 0.1); }\n .lens-idpill button { color: #a1a1aa; }\n .lens-idpill button:hover { background: rgba(255, 255, 255, 0.08); color: #f4f4f5; }\n}\n\n/* ---------------- Floating action chips (picker / annotator) ---------------- */\n.lens-pick-chip, .lens-annotate-chips {\n position: fixed;\n top: calc(16px + env(safe-area-inset-top));\n left: 50%;\n transform: translateX(-50%);\n z-index: var(--lens-z);\n display: inline-flex;\n align-items: center;\n gap: 10px;\n max-width: calc(100vw - 24px);\n padding: 6px 6px 6px 14px;\n border-radius: 999px;\n background: rgba(20, 20, 23, 0.92);\n -webkit-backdrop-filter: blur(12px) saturate(180%);\n backdrop-filter: blur(12px) saturate(180%);\n border: 1px solid rgba(255, 255, 255, 0.12);\n box-shadow: 0 8px 30px rgba(0, 0, 0, 0.35);\n color: #f4f4f5;\n font-size: 13px;\n font-weight: 500;\n}\n.lens-annotate-chips { z-index: var(--lens-z); }\n\n/* ---------------- Annotation toolbar ---------------- */\n/* Floating top-center anchor. A fixed drag grip sits left of a tools \"track\":\n the track wraps on desktop and becomes a single horizontal-scroll row on\n narrow screens, so the bar stays one slim height instead of a bulky block. */\n.lens-annotate-toolbar {\n position: fixed;\n top: calc(16px + env(safe-area-inset-top));\n left: 50%;\n transform: translateX(-50%);\n z-index: var(--lens-z);\n display: inline-flex;\n flex-wrap: nowrap;\n align-items: center;\n gap: 6px;\n max-width: calc(100vw - 16px);\n padding: 6px 8px;\n border-radius: 14px;\n background: rgba(20, 20, 23, 0.92);\n -webkit-backdrop-filter: blur(12px) saturate(180%);\n backdrop-filter: blur(12px) saturate(180%);\n border: 1px solid rgba(255, 255, 255, 0.12);\n box-shadow: 0 8px 30px rgba(0, 0, 0, 0.35);\n color: #f4f4f5;\n}\n/* Tools lay out as ONE horizontal row that scrolls if it can't fit, so the bar\n is always a single slim height — never a wrapping (or, worse, min-content\n collapsed vertical) block. The grip sits outside this track. */\n.lens-tool-track {\n display: flex;\n align-items: center;\n flex-wrap: nowrap;\n justify-content: flex-start;\n gap: 6px;\n flex: 1 1 auto;\n min-width: 0;\n overflow-x: auto;\n overflow-y: hidden;\n scrollbar-width: none;\n -webkit-overflow-scrolling: touch;\n}\n.lens-tool-track::-webkit-scrollbar { display: none; }\n.lens-tool-group {\n display: inline-flex;\n align-items: center;\n gap: 4px;\n flex-wrap: nowrap;\n flex: none;\n}\n/* Single close (=Done, keeps marks) pinned at the right, always reachable\n while the tools scroll. Reads as a light control on the dark bar. */\n.lens-tool-close {\n display: inline-flex;\n align-items: center;\n justify-content: center;\n flex: none;\n width: 32px;\n height: 30px;\n padding: 0;\n border: 0;\n border-radius: 8px;\n background: rgba(255, 255, 255, 0.14);\n color: #f4f4f5;\n cursor: pointer;\n transition: background 150ms ease;\n}\n.lens-tool-close:hover { background: rgba(255, 255, 255, 0.26); }\n.lens-tool-close:focus-visible { outline: 2px solid rgba(255, 255, 255, 0.7); outline-offset: 1px; }\n.lens-tool-close svg { width: 18px; height: 18px; }\n.lens-tool-sep {\n width: 1px;\n align-self: stretch;\n min-height: 22px;\n background: rgba(255, 255, 255, 0.16);\n margin: 0 2px;\n}\n\n/* ---------------- Draggable surfaces ---------------- */\n/* Every drag handle: no page pan/scroll gesture starts here, and the cursor\n signals grabbability. Applied to the pill, panel header, toolbar grip, chips. */\n.lens-drag-handle { touch-action: none; cursor: grab; }\n.lens-drag-handle:active { cursor: grabbing; }\n.is-dragging, .is-dragging * { cursor: grabbing !important; }\n.is-dragging { user-select: none; }\n/* While dragging, drop the entry animation/transition so it tracks 1:1. */\n.lens-pill.is-dragging, .lens-panel.is-dragging,\n.lens-annotate-toolbar.is-dragging, .lens-rec-chip.is-dragging {\n animation: none;\n transition: none;\n}\n\n/* Toolbar drag grip — the only grab region, kept out of the scroll track. */\n.lens-tool-grip {\n display: inline-flex;\n align-items: center;\n justify-content: center;\n flex: none;\n width: 22px;\n height: 30px;\n margin-right: 2px;\n border-radius: 6px;\n color: #a1a1aa;\n}\n.lens-tool-grip:hover { color: #f4f4f5; background: rgba(255, 255, 255, 0.08); }\n.lens-tool-grip svg { width: 16px; height: 16px; }\n\n/* Pill grip (the eye dot) + panel header grip. */\n.lens-pill__grip { cursor: grab; }\n.lens-panel__grip {\n display: inline-flex;\n align-items: center;\n justify-content: center;\n flex: none;\n width: 22px;\n height: 22px;\n margin-right: 6px;\n color: #a1a1aa;\n}\n.lens-panel__grip svg { width: 16px; height: 16px; }\n.lens-panel__head { cursor: grab; }\n.lens-panel__head:active { cursor: grabbing; }\n.lens-tool-btn {\n display: inline-flex;\n align-items: center;\n justify-content: center;\n width: 30px;\n height: 30px;\n padding: 0;\n border: 1px solid transparent;\n border-radius: 8px;\n background: transparent;\n color: #d4d4d8;\n cursor: pointer;\n transition: background 150ms ease, color 150ms ease, border-color 150ms ease;\n}\n.lens-tool-btn:hover { background: rgba(255, 255, 255, 0.1); color: #fff; }\n.lens-tool-btn:focus-visible { outline: 2px solid rgba(255, 255, 255, 0.7); outline-offset: 1px; }\n.lens-tool-btn.is-active {\n background: #fff;\n border-color: #fff;\n color: #18181b;\n}\n.lens-tool-btn:disabled { opacity: 0.4; cursor: default; }\n.lens-tool-btn:disabled:hover { background: transparent; color: #d4d4d8; }\n\n.lens-swatch {\n width: 22px;\n height: 22px;\n padding: 0;\n border-radius: 999px;\n border: 2px solid transparent;\n box-shadow: 0 0 0 1px rgba(255, 255, 255, 0.25) inset;\n cursor: pointer;\n transition: transform 120ms ease, border-color 120ms ease;\n}\n.lens-swatch:hover { transform: scale(1.1); }\n.lens-swatch:focus-visible { outline: 2px solid #fff; outline-offset: 1px; }\n.lens-swatch.is-active {\n border-color: #fff;\n box-shadow: 0 0 0 2px rgba(0, 0, 0, 0.4);\n}\n\n.lens-width-btn {\n display: inline-flex;\n align-items: center;\n justify-content: center;\n min-width: 26px;\n height: 30px;\n padding: 0 6px;\n border: 1px solid transparent;\n border-radius: 8px;\n background: transparent;\n color: #d4d4d8;\n font-family: var(--lens-font);\n font-size: 12px;\n font-weight: 700;\n cursor: pointer;\n transition: background 150ms ease, color 150ms ease, border-color 150ms ease;\n}\n.lens-width-btn:hover { background: rgba(255, 255, 255, 0.1); color: #fff; }\n.lens-width-btn:focus-visible { outline: 2px solid rgba(255, 255, 255, 0.7); outline-offset: 1px; }\n.lens-width-btn.is-active {\n background: #fff;\n border-color: #fff;\n color: #18181b;\n}\n\n/* Coarse pointers: bump the tool targets toward 40px. */\n@media (pointer: coarse) {\n .lens-tool-btn, .lens-width-btn { width: 38px; height: 38px; }\n .lens-swatch { width: 30px; height: 30px; }\n .lens-tool-grip { width: 30px; height: 38px; }\n}\n\n/* Stacking inside the shadow layer: the panel, pill and floating chips always\n sit above the annotation layer/rects and picker highlight, so marked areas\n never paint over interactive UI. */\n.lens-panel, .lens-pill, .lens-recchip { z-index: var(--lens-z); }\n.lens-pick-chip__label, .lens-annotate-chips__label { white-space: nowrap; }\n.lens-pick-chip__btn {\n display: inline-flex;\n align-items: center;\n justify-content: center;\n height: 30px;\n padding: 0 14px;\n border: 0;\n border-radius: 999px;\n background: rgba(255, 255, 255, 0.12);\n color: #f4f4f5;\n font-family: var(--lens-font);\n font-size: 13px;\n font-weight: 600;\n cursor: pointer;\n transition: background 150ms ease;\n}\n.lens-pick-chip__btn:hover { background: rgba(255, 255, 255, 0.2); }\n.lens-pick-chip__btn--primary { background: #fff; color: #18181b; }\n.lens-pick-chip__btn--primary:hover { background: #e4e4e7; }\n\n/* ---------------- Recording chip ---------------- */\n.lens-rec-chip {\n position: fixed;\n top: calc(16px + env(safe-area-inset-top));\n left: 50%;\n transform: translateX(-50%);\n z-index: var(--lens-z);\n display: inline-flex;\n align-items: center;\n gap: 10px;\n max-width: calc(100vw - 24px);\n padding: 6px 6px 6px 14px;\n border-radius: 999px;\n background: rgba(20, 20, 23, 0.92);\n -webkit-backdrop-filter: blur(12px) saturate(180%);\n backdrop-filter: blur(12px) saturate(180%);\n border: 1px solid rgba(239, 68, 68, 0.4);\n box-shadow: 0 8px 30px rgba(0, 0, 0, 0.35);\n color: #f4f4f5;\n font-size: 13px;\n font-weight: 600;\n}\n.lens-rec-chip__dot {\n width: 10px;\n height: 10px;\n border-radius: 999px;\n background: #ef4444;\n animation: lens-pulse 1.2s ease-in-out infinite;\n}\n@keyframes lens-pulse {\n 0%, 100% { opacity: 1; transform: scale(1); }\n 50% { opacity: 0.4; transform: scale(0.7); }\n}\n.lens-rec-chip__time { font-variant-numeric: tabular-nums; min-width: 34px; }\n.lens-rec-chip__stop {\n display: inline-flex;\n align-items: center;\n gap: 6px;\n height: 30px;\n padding: 0 14px;\n border: 0;\n border-radius: 999px;\n background: #ef4444;\n color: #fff;\n font-family: var(--lens-font);\n font-size: 13px;\n font-weight: 600;\n cursor: pointer;\n transition: background 150ms ease;\n}\n.lens-rec-chip__stop:hover { background: #dc2626; }\n.lens-chip--rec { gap: 6px; }\n\n/* Very narrow screens: collapse the pill's \"Report issue\" label to its icon so\n the pill stays a single slim row (never wraps into a 2-row blob). */\n@media (max-width: 400px) {\n .lens-btn__label { display: none; }\n .lens-btn--report { width: 44px; padding: 0; justify-content: center; }\n}\n\n/* ---------------- Coarse pointers (touch): ≥44px targets ---------------- */\n@media (pointer: coarse) {\n .lens-btn { height: 44px; padding: 0 16px; }\n .lens-btn--icon { width: 44px; }\n .lens-tool-close { width: 44px; height: 38px; }\n .lens-pill__dot { width: 40px; height: 40px; }\n .lens-abtn { height: 44px; }\n .lens-panel__x { width: 44px; height: 44px; }\n .lens-chip__x { min-width: 32px; min-height: 32px; align-items: center; justify-content: center; }\n .lens-pick-chip__btn, .lens-rec-chip__stop { height: 40px; padding: 0 18px; }\n}\n\n/* ---------------- Narrow screens (≤640px) ---------------- */\n@media (max-width: 640px) {\n /* Report panel as a bottom sheet (unless the user has dragged it loose). */\n .lens-panel:not(.is-dragging) {\n left: 0;\n right: 0;\n bottom: 0;\n width: 100%;\n max-width: 100%;\n max-height: 85dvh;\n border-radius: 16px 16px 0 0;\n overflow-y: auto;\n padding-bottom: env(safe-area-inset-bottom);\n animation: lens-sheet-in 180ms ease;\n }\n @keyframes lens-sheet-in {\n from { opacity: 0; transform: translateY(16px); }\n to { opacity: 1; transform: none; }\n }\n .lens-textarea { font-size: 16px; }\n\n /* On narrow screens the single-row tool track usually overflows: fade its\n trailing edge so it reads as \"more tools this way\" (the grip sits outside\n the track and stays fully opaque). */\n .lens-tool-track {\n -webkit-mask-image: linear-gradient(90deg, #000 calc(100% - 20px), transparent 100%);\n mask-image: linear-gradient(90deg, #000 calc(100% - 20px), transparent 100%);\n }\n}\n`;\n","import type { Annotation, TargetElement } from '@horus-lens/shared';\nimport { AnnotationEditor } from './annotation-editor.js';\nimport { el } from './dom.js';\nimport { makeDraggable, isInteractiveTarget, type DraggableHandle } from './draggable.js';\nimport { iconClose, iconCrosshair, iconEye, iconReport, iconStop } from './icons.js';\nimport { formatDuration, Panel } from './panel.js';\nimport { ElementPicker } from './picker.js';\nimport { OVERLAY_CSS } from './styles.js';\nimport type { OverlayDeps, SubmitReportIncludes } from './types.js';\n\nimport { LENS_OVERLAY_HOST_ID } from '@horus-lens/core';\n\n/** Canonical host id — the core recorder/screenshot exclusions key off it. */\nexport const ROOT_ID = LENS_OVERLAY_HOST_ID;\n\n/** Auto-stop a manual recording at this ceiling (mirrors the core hard cap). */\nconst RECORDING_MAX_MS = 120000;\n\nexport interface OverlayHandle {\n open(): void;\n close(): void;\n destroy(): void;\n}\n\n/**\n * Root overlay controller. Owns the Shadow DOM host, the floating pill, and the\n * three interaction surfaces (element picker, annotator, report panel). Pure\n * DOM — no framework — so it can be dropped into any page.\n */\nclass Overlay implements OverlayHandle {\n private host: HTMLElement;\n private shadow: ShadowRoot;\n private layer: HTMLElement;\n private pickBtn!: HTMLButtonElement;\n private picker: ElementPicker;\n private annotator: AnnotationEditor;\n private panel: Panel | null = null;\n private target: TargetElement | null = null;\n private destroyed = false;\n\n private pillDrag: DraggableHandle | null = null;\n private recordingChip: HTMLElement | null = null;\n private recordingDrag: DraggableHandle | null = null;\n private recordingTimerEl: HTMLElement | null = null;\n private recordingInterval: ReturnType<typeof setInterval> | null = null;\n private recordingStartTs = 0;\n /** Duration of a retained (stopped, not yet submitted/discarded) recording. */\n private recordedDurationMs: number | null = null;\n\n constructor(private readonly deps: OverlayDeps) {\n this.host = el('div', { attrs: { id: ROOT_ID } });\n this.shadow = this.host.attachShadow({ mode: 'open' });\n\n const style = document.createElement('style');\n style.textContent = OVERLAY_CSS;\n this.shadow.append(style);\n\n this.layer = el('div', { class: 'lens-layer' });\n this.shadow.append(this.layer);\n\n this.picker = new ElementPicker(this.layer, this.host);\n this.annotator = new AnnotationEditor(this.layer);\n\n const pill = this.buildPill();\n this.layer.append(pill);\n document.documentElement.append(this.host);\n\n // The pill floats over content; let the user drag it clear by any non-button\n // spot (the eye grip, separators, padding). Position persists for the session.\n this.pillDrag = makeDraggable(pill, {\n handle: pill,\n key: 'lens-pill',\n ignore: isInteractiveTarget,\n });\n\n window.addEventListener('keydown', this.onGlobalKey, true);\n }\n\n private buildPill(): HTMLElement {\n this.pickBtn = el('button', {\n class: 'lens-btn lens-btn--icon',\n ariaLabel: 'Pick an element',\n title: 'Pick an element',\n html: iconCrosshair,\n on: { click: () => this.togglePicker() },\n });\n return el('div', { class: 'lens-pill', attrs: { role: 'toolbar', 'aria-label': 'Lens' } }, [\n el('span', {\n class: 'lens-pill__dot lens-pill__grip',\n html: iconEye,\n title: 'Drag to move',\n ariaLabel: 'Drag to move Lens',\n }),\n el('button', {\n class: 'lens-btn lens-btn--report',\n html: iconReport + '<span class=\"lens-btn__label\">Report issue</span>',\n ariaLabel: 'Report issue',\n on: { click: () => this.open() },\n }),\n this.pickBtn,\n el('span', { class: 'lens-pill__sep' }),\n el('button', {\n class: 'lens-btn lens-btn--icon',\n ariaLabel: 'Close Lens',\n title: 'Close Lens',\n html: iconClose,\n on: { click: () => this.dismiss() },\n }),\n ]);\n }\n\n open(): void {\n if (this.destroyed) return;\n this.stopPicker();\n if (!this.panel) {\n this.panel = new Panel({\n getStats: () => this.deps.snapshotStats(),\n getTarget: () => this.target,\n getAnnotationCount: () => this.annotator.count,\n getRecording: () =>\n this.recordedDurationMs !== null ? { durationMs: this.recordedDurationMs } : null,\n onRemoveTarget: () => {\n this.target = null;\n this.panel?.refresh();\n },\n onMarkArea: () => this.startAnnotating(),\n onRecordSteps: () => this.startRecording(),\n onDiscardRecording: () => this.discardRecording(),\n onClose: () => this.close(),\n onSubmit: (comment, include) => this.submit(comment, include),\n });\n this.layer.append(this.panel.root);\n }\n this.panel.root.style.display = '';\n this.panel.refresh();\n this.panel.focus();\n }\n\n close(): void {\n if (this.panel) {\n this.panel.destroy();\n this.panel = null;\n }\n }\n\n private toggle(): void {\n if (this.panel && this.panel.root.style.display !== 'none') this.close();\n else this.open();\n }\n\n private togglePicker(): void {\n if (this.picker.isActive) {\n this.stopPicker();\n return;\n }\n // Picking and annotating are mutually exclusive pointer modes. If the\n // annotator is still active its transparent capture surface swallows every\n // page tap, so leave annotation first (keeping any marks drawn) before the\n // picker arms — otherwise \"tap an element\" does nothing.\n if (this.annotator.isActive) this.annotator.exit();\n this.close();\n this.pickBtn.classList.add('is-active');\n this.picker.start(\n (elem) => {\n this.pickBtn.classList.remove('is-active');\n this.target = this.deps.client.captureTarget(elem);\n this.open();\n },\n () => this.pickBtn.classList.remove('is-active'),\n );\n }\n\n private stopPicker(): void {\n if (this.picker.isActive) this.picker.stop();\n this.pickBtn.classList.remove('is-active');\n }\n\n private startAnnotating(): void {\n if (this.panel) this.panel.root.style.display = 'none';\n this.annotator.start(() => {\n if (this.panel) {\n this.panel.root.style.display = '';\n this.panel.refresh();\n }\n });\n }\n\n private startRecording(): void {\n if (this.deps.client.isRecording()) return;\n // A fresh recording supersedes any retained one.\n this.recordedDurationMs = null;\n this.deps.client.startRecording();\n this.recordingStartTs = Date.now();\n if (this.panel) this.panel.root.style.display = 'none';\n this.showRecordingChip();\n }\n\n private stopRecording(): void {\n const result = this.deps.client.stopRecording();\n this.recordedDurationMs = result?.durationMs ?? Date.now() - this.recordingStartTs;\n this.hideRecordingChip();\n // Reopen the panel; the retained recording surfaces as a context chip.\n if (this.panel) {\n this.panel.root.style.display = '';\n this.panel.refresh();\n } else {\n this.open();\n }\n }\n\n private discardRecording(): void {\n this.deps.client.discardRecording();\n this.recordedDurationMs = null;\n this.panel?.refresh();\n }\n\n private showRecordingChip(): void {\n this.recordingTimerEl = el('span', { class: 'lens-rec-chip__time', text: '0:00' });\n this.recordingChip = el('div', { class: 'lens-rec-chip' }, [\n el('span', { class: 'lens-rec-chip__dot' }),\n el('span', { class: 'lens-rec-chip__label', text: 'Recording' }),\n this.recordingTimerEl,\n el('button', {\n class: 'lens-rec-chip__stop',\n html: iconStop + '<span>Stop</span>',\n on: { click: () => this.stopRecording() },\n }),\n ]);\n this.layer.append(this.recordingChip);\n this.recordingDrag = makeDraggable(this.recordingChip, {\n handle: this.recordingChip,\n key: 'lens-rec-chip',\n ignore: isInteractiveTarget,\n });\n this.recordingInterval = setInterval(() => this.tickRecording(), 250);\n }\n\n private tickRecording(): void {\n const elapsed = Date.now() - this.recordingStartTs;\n if (this.recordingTimerEl) this.recordingTimerEl.textContent = formatDuration(elapsed);\n if (elapsed >= RECORDING_MAX_MS) this.stopRecording();\n }\n\n private hideRecordingChip(): void {\n if (this.recordingInterval) {\n clearInterval(this.recordingInterval);\n this.recordingInterval = null;\n }\n if (this.recordingDrag) {\n this.recordingDrag.destroy();\n this.recordingDrag = null;\n }\n if (this.recordingChip) {\n this.recordingChip.remove();\n this.recordingChip = null;\n }\n this.recordingTimerEl = null;\n }\n\n private async submit(\n comment: string,\n include: SubmitReportIncludes,\n ): Promise<{ reportId: string }> {\n const annotations: Annotation[] = this.annotator.list();\n // The SVG editor owns all annotation geometry (document coords). It bakes\n // the marks into the screenshot (blur redaction + rasterized overlay) via\n // the composite, and derives the crop bbox from the same mark data — no\n // DOM math here. Both are `undefined`/`null` when nothing is marked.\n const composite = this.annotator.getComposite() ?? undefined;\n const screenshotCrop = this.annotator.getCropBounds();\n const result = await this.deps.client.submitReport({\n comment: comment || undefined,\n annotations,\n target: this.target ?? undefined,\n excludeFromScreenshot: this.host,\n screenshotCrop,\n annotationComposite: composite,\n include,\n trigger: 'user',\n });\n // Reset transient capture state after a successful submission.\n this.target = null;\n this.annotator.clear();\n this.recordedDurationMs = null;\n this.deps.client.discardRecording();\n return result;\n }\n\n private dismiss(): void {\n this.deps.onDismiss();\n this.destroy();\n }\n\n private onGlobalKey = (e: KeyboardEvent): void => {\n // Cmd/Ctrl+Shift+L toggles the panel.\n if ((e.metaKey || e.ctrlKey) && e.shiftKey && (e.key === 'l' || e.key === 'L')) {\n e.preventDefault();\n this.toggle();\n }\n };\n\n destroy(): void {\n if (this.destroyed) return;\n this.destroyed = true;\n window.removeEventListener('keydown', this.onGlobalKey, true);\n this.pillDrag?.destroy();\n this.pillDrag = null;\n this.stopPicker();\n if (this.deps.client.isRecording()) this.deps.client.stopRecording();\n this.hideRecordingChip();\n if (this.annotator.isActive) this.annotator.exit();\n this.annotator.clear();\n this.close();\n this.host.remove();\n }\n}\n\nexport function mountOverlay(deps: OverlayDeps): OverlayHandle {\n return new Overlay(deps);\n}\n","import type { AppContext } from '@horus-lens/shared';\nimport type { LensBrowser } from './index.js';\n\n/**\n * GTM-style command stub. The loader snippet defines:\n * window.Lens = function(){(window.Lens.q = window.Lens.q||[]).push(arguments)}\n * so pages can call `Lens('init', ...)`, `Lens('identify', user)` etc. before\n * the bundle downloads. On load we drain that queue, then replace the global\n * with a live dispatcher that forwards subsequent calls to the running client.\n */\n\nexport type LensCommand = 'init' | 'identify' | 'app' | 'open';\n\nexport interface LensGlobal {\n (...args: unknown[]): void;\n q?: Array<ArrayLike<unknown>>;\n}\n\ndeclare global {\n interface Window {\n Lens?: LensGlobal;\n }\n}\n\n/** Structured result of replaying the pre-boot command queue. */\nexport interface QueuedCommands {\n /** `init` argument: an access id string or a partial config object. */\n init?: string | Record<string, unknown>;\n identify?: NonNullable<AppContext['user']>;\n app?: Partial<AppContext>;\n open: boolean;\n}\n\n/** Drain `window.Lens.q` into a structured shape consumed by boot(). */\nexport function processQueue(): QueuedCommands {\n const result: QueuedCommands = { open: false };\n if (typeof window === 'undefined') return result;\n\n const queue = window.Lens?.q;\n if (!queue) return result;\n\n for (const entry of queue) {\n const args = Array.from(entry as ArrayLike<unknown>);\n const command = args[0] as LensCommand | undefined;\n const payload = args[1];\n switch (command) {\n case 'init':\n if (typeof payload === 'string' || (payload && typeof payload === 'object')) {\n result.init = payload as string | Record<string, unknown>;\n }\n break;\n case 'identify':\n if (payload && typeof payload === 'object') {\n result.identify = payload as NonNullable<AppContext['user']>;\n }\n break;\n case 'app':\n if (payload && typeof payload === 'object') {\n result.app = payload as Partial<AppContext>;\n }\n break;\n case 'open':\n result.open = true;\n break;\n }\n }\n\n // Clear so a freshly installed live dispatcher never re-processes them.\n if (window.Lens) window.Lens.q = [];\n return result;\n}\n\n/**\n * Replace `window.Lens` with a live function that forwards commands to the\n * mounted overlay. Safe to call with `null` (gate inactive) — it installs a\n * no-op-ish dispatcher that only handles future `init`-less commands.\n */\nexport function installGlobal(browser: LensBrowser | null): void {\n if (typeof window === 'undefined') return;\n\n const dispatch: LensGlobal = (...args: unknown[]): void => {\n if (!browser) return;\n const command = args[0] as LensCommand | undefined;\n const payload = args[1];\n switch (command) {\n case 'identify':\n if (payload && typeof payload === 'object') {\n browser.client.setApp({ user: payload as NonNullable<AppContext['user']> });\n }\n break;\n case 'app':\n if (payload && typeof payload === 'object') {\n browser.client.setApp(payload as Partial<AppContext>);\n }\n break;\n case 'open':\n browser.open();\n break;\n case 'init':\n // Already booted — ignore duplicate init calls.\n break;\n }\n };\n\n window.Lens = dispatch;\n}\n\n/** Apply queued identify / app context to a started client. */\nexport function applyContext(browser: LensBrowser, commands: QueuedCommands): void {\n if (commands.identify) browser.client.setApp({ user: commands.identify });\n if (commands.app) browser.client.setApp(commands.app);\n if (commands.open) browser.open();\n}\n","/**\n * The documented loader snippet — a GTM-style inline stub that queues commands\n * until the async bundle loads and replays them. Ship this in docs / install\n * flows so a page can call `Lens('init', ...)` before the SDK is downloaded.\n */\n\nexport interface SnippetOptions {\n accessId: string;\n /** URL of the browser bundle (defaults to the public CDN latest build). */\n cdnUrl?: string;\n}\n\nexport const DEFAULT_CDN_URL = 'https://cdn.lens.dev/browser.js';\n\nexport function loaderSnippet(options: SnippetOptions): string {\n const cdn = options.cdnUrl ?? DEFAULT_CDN_URL;\n return `<script>\n(function(w,d,s,u,i){\n w.Lens=w.Lens||function(){(w.Lens.q=w.Lens.q||[]).push(arguments)};\n w.Lens('init', i);\n var g=d.createElement(s); g.async=1; g.src=u;\n var f=d.getElementsByTagName(s)[0]; f.parentNode.insertBefore(g,f);\n})(window,document,'script','${cdn}','${options.accessId}');\n</script>`;\n}\n\n/** Example snippet string for documentation (placeholder access id + CDN). */\nexport const LOADER_SNIPPET = loaderSnippet({ accessId: 'lai_YOUR_ACCESS_ID' });\n"],"mappings":"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","names":["copy","svg"]}
package/dist/cli.cjs CHANGED
@@ -97,6 +97,7 @@ function discoverSourcemaps(dirs, opts = {}) {
97
97
  const warnings = [];
98
98
  const seen = /* @__PURE__ */ new Map();
99
99
  const files = [];
100
+ let duplicatesDropped = 0;
100
101
  const walk = (dir) => {
101
102
  let entries;
102
103
  try {
@@ -117,8 +118,9 @@ function discoverSourcemaps(dirs, opts = {}) {
117
118
  const name = entry.name;
118
119
  const existing = seen.get(name);
119
120
  if (existing !== void 0) {
121
+ duplicatesDropped++;
120
122
  warnings.push(
121
- `duplicate sourcemap basename "${name}": keeping ${existing}, skipping ${full}`
123
+ `DUPLICATE sourcemap basename "${name}" \u2014 the server identifies maps by basename, so only ${existing} will be uploaded; ${full} is SKIPPED and its bundle will have NO sourcemap. Rename the bundle/map to disambiguate.`
122
124
  );
123
125
  continue;
124
126
  }
@@ -134,6 +136,11 @@ function discoverSourcemaps(dirs, opts = {}) {
134
136
  }
135
137
  };
136
138
  for (const dir of dirs) walk((0, import_node_path.resolve)(dir));
139
+ if (duplicatesDropped > 0) {
140
+ warnings.push(
141
+ `${duplicatesDropped} sourcemap(s) SKIPPED due to duplicate basenames \u2014 those bundles will have no sourcemap on the server. See the warnings above.`
142
+ );
143
+ }
137
144
  let truncated = false;
138
145
  let result = files;
139
146
  if (files.length > maxFiles) {
@@ -143,7 +150,7 @@ function discoverSourcemaps(dirs, opts = {}) {
143
150
  );
144
151
  result = files.slice(0, maxFiles);
145
152
  }
146
- return { files: result, warnings, truncated };
153
+ return { files: result, warnings, truncated, duplicatesDropped };
147
154
  }
148
155
  function formatBytes(bytes) {
149
156
  if (!Number.isFinite(bytes) || bytes < 0) return "0 B";
@@ -178,13 +185,14 @@ async function postJson(url, key, body) {
178
185
  async function putFile(file, target) {
179
186
  const bytes = (0, import_node_fs2.readFileSync)(file.absolutePath);
180
187
  const method = target.method ?? "PUT";
181
- const headers = target.headers ?? { "content-type": "application/json" };
188
+ const headers = target.headers ?? {};
182
189
  let lastError = "";
183
190
  for (let attempt = 0; attempt < 2; attempt++) {
184
191
  try {
185
192
  const res = await fetch(target.url, { method, headers, body: bytes });
186
193
  if (res.ok) return;
187
194
  lastError = `HTTP ${res.status}`;
195
+ if (res.status < 500) break;
188
196
  } catch (err) {
189
197
  lastError = err.message;
190
198
  }
@@ -224,7 +232,7 @@ ${USAGE}
224
232
  return 1;
225
233
  }
226
234
  const { release, key, endpoint, dryRun, dirs } = parsed.args;
227
- const { files, warnings } = discoverSourcemaps(dirs);
235
+ const { files, warnings, duplicatesDropped } = discoverSourcemaps(dirs);
228
236
  for (const w of warnings) process.stderr.write(`warning: ${w}
229
237
  `);
230
238
  if (files.length === 0) {
@@ -288,8 +296,13 @@ ${initiate.body}
288
296
  }
289
297
  jobs.push({ file, target });
290
298
  }
291
- if (jobs.length === 0) {
292
- process.stderr.write("error: initiate returned no upload targets.\n");
299
+ const targeted = new Set(jobs.map((j) => j.file.name));
300
+ const undelivered = files.filter((f) => !targeted.has(f.name));
301
+ if (undelivered.length > 0) {
302
+ process.stderr.write(
303
+ `error: server returned upload targets for ${targeted.size} of ${files.length} file(s); no target for: ${undelivered.map((f) => f.name).join(", ")}
304
+ `
305
+ );
293
306
  return 1;
294
307
  }
295
308
  const failures = await runPool(jobs, PUT_CONCURRENCY, async ({ file, target }) => {
@@ -322,6 +335,12 @@ ${finalize.body}
322
335
  `\u2713 uploaded ${uploaded.length} sourcemaps for release ${release} (${formatBytes(uploadedBytes)})
323
336
  `
324
337
  );
338
+ if (duplicatesDropped > 0) {
339
+ process.stdout.write(
340
+ ` note: ${duplicatesDropped} sourcemap(s) were skipped due to duplicate basenames (see warnings above).
341
+ `
342
+ );
343
+ }
325
344
  return 0;
326
345
  }
327
346
  main(process.argv.slice(2)).then((code) => {