helldots 0.3.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/LICENSE +21 -0
- package/README.md +227 -0
- package/dist/helldots.esm.js +1019 -0
- package/dist/helldots.esm.js.map +7 -0
- package/dist/helldots.umd.js +1032 -0
- package/dist/index.d.ts +199 -0
- package/package.json +75 -0
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
{
|
|
2
|
+
"version": 3,
|
|
3
|
+
"sources": ["../src/capture.js", "../src/root-element.js", "../src/metadata.js", "../src/constants.js", "../src/styles.js", "../src/locales/en.js", "../src/locales/es.js", "../src/i18n.js", "../src/anchor.js", "../src/storage.js", "../src/comment-actions.js", "../src/components.js", "../src/agent-context.js", "../src/inbox.js", "../src/overlay.js", "../src/index.js"],
|
|
4
|
+
"sourcesContent": ["// Screenshot primitives. The page render is the expensive part, so it's\n// split out from the cropping: a drag capture and the automatic context\n// capture of the same comment share ONE render instead of paying for two.\n//\n// WE own the crop in page coordinates \u2014 html2canvas used to own it and\n// silently shifted it by the window scroll (double-counting: the hero\n// showed up in captures taken further down the page). Owning the crop\n// makes that whole bug class impossible.\n\nimport { domToCanvas } from \"modern-screenshot\";\nimport { TAG_NAME } from \"./root-element.js\";\n\n/** Automatic captures render and encode small \u2014 they live in localStorage. */\nexport const AUTO_SCALE = 0.5;\nexport const AUTO_QUALITY = 0.7;\n\nconst isUnpainted = (color) =>\n !color || color === \"transparent\" || color === \"rgba(0, 0, 0, 0)\";\n\n// What the user visually perceives as the page background: the html/body\n// CSS color when one is painted, else white \u2014 browsers paint their own\n// white canvas under a transparent document, but that canvas is not part\n// of the DOM, so a DOM-based render would come out as a transparent PNG\n// (invisible against the dark inbox UI).\nconst effectiveBackgroundColor = () => {\n const htmlBg = getComputedStyle(document.documentElement).backgroundColor;\n if (!isUnpainted(htmlBg)) return htmlBg;\n const bodyBg = getComputedStyle(document.body).backgroundColor;\n if (!isUnpainted(bodyBg)) return bodyBg;\n return \"#ffffff\";\n};\n\n/**\n * Renders the whole page to a canvas. This is the expensive call \u2014 callers\n * that need more than one image should render once and crop repeatedly.\n * @param {{ scale?: number }} [options] scale 1 keeps the canvas in CSS\n * pixels so crop rects map 1:1 to page coordinates.\n * @returns {Promise<any>}\n */\nexport async function renderPage({ scale = 1 } = {}) {\n return domToCanvas(document.body, {\n scale,\n backgroundColor: effectiveBackgroundColor(),\n });\n}\n\n/**\n * Runs `fn` with the HellDots UI hidden, so the widget never renders into\n * its own screenshot. Restores the host even if `fn` throws \u2014 a failed\n * render must not leave the widget invisible.\n * @template T\n * @param {() => Promise<T>} fn\n * @returns {Promise<T>}\n */\nexport async function withHiddenOverlay(fn) {\n const host = /** @type {HTMLElement} */ (document.querySelector(TAG_NAME));\n const previousDisplay = host?.style.display;\n if (host) host.style.display = \"none\";\n try {\n return await fn();\n } finally {\n if (host) host.style.display = previousDisplay || \"\";\n }\n}\n\n/**\n * Crops a viewport-relative region out of a scale-1 page render.\n * @param {any} canvas full-page render from renderPage({ scale: 1 })\n * @param {{ left: number, top: number, width: number, height: number }} region\n * Viewport (client) coordinates of the drag selection.\n * @returns {string | null} PNG data-URL, or null with no 2d context.\n */\nexport function cropRegion(canvas, { left, top, width, height }) {\n const out = document.createElement(\"canvas\");\n out.width = width;\n out.height = height;\n const ctx = out.getContext(\"2d\");\n if (!ctx) return null;\n\n ctx.drawImage(\n canvas,\n left + window.scrollX,\n top + window.scrollY,\n width,\n height,\n 0,\n 0,\n width,\n height\n );\n return out.toDataURL(\"image/png\");\n}\n\n/**\n * Crops the current viewport out of a page render and encodes it small.\n * @param {any} canvas full-page render\n * @param {{ sourceScale?: number, outputScale?: number, quality?: number }} [options]\n * `sourceScale` is the scale `canvas` was rendered at \u2014 the source rect is\n * mapped through it. `outputScale` is the final size in CSS pixels.\n * @returns {string | null} JPEG data-URL, or null with no 2d context.\n */\nexport function cropViewport(\n canvas,\n { sourceScale = 1, outputScale = AUTO_SCALE, quality = AUTO_QUALITY } = {}\n) {\n const out = document.createElement(\"canvas\");\n out.width = Math.round(window.innerWidth * outputScale);\n out.height = Math.round(window.innerHeight * outputScale);\n const ctx = out.getContext(\"2d\");\n if (!ctx) return null;\n\n ctx.drawImage(\n canvas,\n window.scrollX * sourceScale,\n window.scrollY * sourceScale,\n window.innerWidth * sourceScale,\n window.innerHeight * sourceScale,\n 0,\n 0,\n out.width,\n out.height\n );\n return out.toDataURL(\"image/jpeg\", quality);\n}\n\n/**\n * Captures a viewport-relative region of the current page.\n * Kept for API compatibility \u2014 renders and crops in one call.\n * @param {{ left: number, top: number, width: number, height: number }} region\n * @returns {Promise<string | null>} PNG data-URL. Render failures reject.\n */\nexport async function captureRegion(region) {\n return cropRegion(await renderPage({ scale: 1 }), region);\n}\n", "const TAG_NAME = \"helldots-root\";\n\n// Defined lazily rather than at module scope: `extends HTMLElement` is\n// evaluated when the class expression runs, so a top-level declaration makes\n// a bare `import \"helldots\"` throw on any server renderer (Next.js, Remix,\n// Astro) long before the app calls anything. Deferring it keeps the module\n// import-safe everywhere and only touches the DOM when we actually mount.\nconst ensureDefined = () => {\n if (customElements.get(TAG_NAME)) return;\n\n customElements.define(\n TAG_NAME,\n class HelldotsRoot extends HTMLElement {\n constructor() {\n super();\n this.attachShadow({ mode: \"open\" });\n }\n }\n );\n};\n\n/**\n * Returns the shared shadow root used to render all HellDots UI, creating\n * the host element and mounting it on document.body on first call.\n * @returns {ShadowRoot}\n */\nexport function getShadowRoot() {\n ensureDefined();\n\n let host = document.querySelector(TAG_NAME);\n if (!host) {\n host = document.createElement(TAG_NAME);\n document.body.appendChild(host);\n }\n\n return host.shadowRoot;\n}\n\nexport { TAG_NAME };\n", "// RF2 \u2014 environment snapshot attached to every comment at creation time.\n// Kept as a pure function over an injectable `window` so the UA parsing\n// paths are testable without touching jsdom's real navigator.\n\n// Order is load-bearing: Edge's UA contains \"Chrome\", and Chrome's UA\n// contains \"Safari\". First match wins, so the more specific entries lead.\nconst BROWSERS = [\n { name: \"Edge\", re: /Edg\\/([\\d.]+)/ },\n { name: \"Chrome\", re: /Chrome\\/([\\d.]+)/ },\n { name: \"Firefox\", re: /Firefox\\/([\\d.]+)/ },\n { name: \"Safari\", re: /Version\\/([\\d.]+).*Safari/ },\n];\n\n// iOS before macOS: an iPhone UA also carries \"Mac OS X\".\nconst OPERATING_SYSTEMS = [\n { name: \"iOS\", re: /(?:iPhone|iPad).*OS ([\\d_]+) like Mac OS X/ },\n { name: \"Android\", re: /Android ([\\d.]+)/ },\n { name: \"Windows\", re: /Windows NT ([\\d.]+)/ },\n { name: \"macOS\", re: /Mac OS X ([\\d_.]+)/ },\n { name: \"Linux\", re: /Linux/ },\n];\n\nconst UNKNOWN = { name: \"unknown\", version: \"\" };\n\n// Chromium pads its brand list with a randomised \"GREASE\" entry to stop\n// consumers hardcoding brand positions. It is never the real browser.\nconst isGreaseBrand = (brand) => /not[\\W_]*a[\\W_]*brand/i.test(brand);\n\nconst matchFirst = (table, ua) => {\n for (const { name, re } of table) {\n const match = ua.match(re);\n if (match) {\n return { name, version: (match[1] || \"\").replace(/_/g, \".\") };\n }\n }\n return { ...UNKNOWN };\n};\n\n/**\n * Snapshots the browsing environment of the current page.\n * @param {any} [win] Injectable window \u2014 defaults to the real one.\n * @returns {import('./index.d.ts').CommentContext}\n */\nexport function captureContext(win = window) {\n const nav = win.navigator || {};\n const ua = nav.userAgent || \"\";\n const uaData = nav.userAgentData;\n\n let browser = matchFirst(BROWSERS, ua);\n const brand = uaData?.brands?.find((b) => !isGreaseBrand(b.brand));\n if (brand) {\n browser = { name: brand.brand, version: brand.version || \"\" };\n }\n\n const os = matchFirst(OPERATING_SYSTEMS, ua);\n if (uaData?.platform) os.name = uaData.platform;\n\n return {\n version: 1,\n url: win.location?.href || \"\",\n viewport: { width: win.innerWidth, height: win.innerHeight },\n screen: {\n width: win.screen?.width ?? 0,\n height: win.screen?.height ?? 0,\n },\n devicePixelRatio: win.devicePixelRatio ?? 1,\n userAgent: ua,\n browser,\n os,\n language: nav.language || \"\",\n };\n}\n", "export const CLASSES = {\n CIRCLE: \"comment-circle\",\n CIRCLE_WRAPPER: \"comment-circle-wrapper\",\n TOOLTIP: \"comment-tooltip\",\n TOOLBAR_TEXT: \"toolbar-text\",\n SHORTCUT_HINT: \"shortcut-hint\",\n COMMENT_INPUT_AREA: \"comment-input-area\",\n CLOSE_TOOLTIP: \"close-tooltip\",\n ACTIVE: \"active\",\n COMMENT_CURSOR: \"comment-cursor\",\n COMMENT_OVERLAY: \"comment-overlay\",\n THREAD_POPOVER: \"comment-thread-popover\",\n THREAD_HEADER: \"thread-header\",\n THREAD_BODY: \"thread-body\",\n THREAD_REPLIES: \"thread-replies\",\n THREAD_REPLY: \"thread-reply\",\n THREAD_INPUT_AREA: \"thread-input-area\",\n THREAD_INPUT: \"thread-input\",\n THREAD_SUBMIT: \"thread-submit\",\n THREAD_META: \"thread-meta\",\n THREAD_AUTHOR: \"thread-author\",\n THREAD_TIME: \"thread-time\",\n PREVIEW_CIRCLE: \"preview-circle\",\n SELECTION_RECT: \"selection-rect\",\n SCREENSHOT_IMG: \"screenshot-img\",\n SCREENSHOT_REMOVE: \"screenshot-remove\",\n SCREENSHOTS_CONTAINER: \"screenshots-container\",\n SCREENSHOT_ITEM: \"screenshot-item\",\n LIGHTBOX: \"helldots-lightbox\",\n LIGHTBOX_IMG: \"helldots-lightbox-img\",\n LIGHTBOX_CLOSE: \"helldots-lightbox-close\",\n COMMENT_ACTIONS_BAR: \"comment-actions-bar\",\n ATTACH_IMAGE_BTN: \"attach-image-btn\",\n TOOLBAR_ACTIONS: \"toolbar-actions\",\n TOOLBAR_ACTION_BTN: \"toolbar-action-btn\",\n TOOLBAR_ACTION_WRAPPER: \"toolbar-action-wrapper\",\n TOOLBAR_ACTION_TOOLTIP: \"toolbar-action-tooltip\",\n TOOLBAR_COMMENT_BTN: \"toolbar-comment-btn\",\n TOOLBAR_MENU_BTN: \"toolbar-menu-btn\",\n INBOX_PANEL: \"inbox-panel\",\n INBOX_HEADER: \"inbox-header\",\n INBOX_FILTER: \"inbox-filter\",\n INBOX_FILTER_MENU: \"inbox-filter-menu\",\n INBOX_FILTER_OPTION: \"inbox-filter-option\",\n INBOX_FILTER_SECTION: \"inbox-filter-section\",\n INBOX_CLOSE: \"inbox-close\",\n INBOX_LIST: \"inbox-list\",\n INBOX_CARD: \"inbox-card\",\n INBOX_CARD_HEADER: \"inbox-card-header\",\n INBOX_CARD_ACTIONS: \"inbox-card-actions\",\n INBOX_CARD_TEXT: \"inbox-card-text\",\n INBOX_CARD_TAG: \"inbox-card-tag\",\n INBOX_CARD_REPLY_LINK: \"inbox-card-reply-link\",\n INBOX_ACTION_BTN: \"inbox-action-btn\",\n INBOX_ACTION_BTN_LABELED: \"inbox-action-btn--labeled\",\n INBOX_ACTION_LABEL: \"inbox-action-label\",\n INBOX_STATUS_DOT: \"inbox-status-dot\",\n INBOX_MENU: \"inbox-menu\",\n INBOX_MENU_ITEM: \"inbox-menu-item\",\n INBOX_DETAIL: \"inbox-detail\",\n INBOX_DETAIL_HEADER: \"inbox-detail-header\",\n INBOX_BACK: \"inbox-back\",\n INBOX_NAV_BTN: \"inbox-nav-btn\",\n INBOX_REPLIES: \"inbox-replies\",\n INBOX_EMPTY: \"inbox-empty\",\n CLASSIFY_ROW: \"classify-row\",\n TAGS_INPUT: \"tags-input\",\n TAG_CHIP: \"tag-chip\",\n TAG_CHIP_REMOVE: \"tag-chip-remove\",\n INBOX_BADGES: \"inbox-badges\",\n BADGE: \"helldots-badge\",\n BADGE_TYPE: \"helldots-badge--type\",\n BADGE_PRIORITY: \"helldots-badge--priority\",\n BADGE_TAG: \"helldots-badge--tag\",\n BADGE_DURATION: \"helldots-badge--duration\",\n CONTEXT_BLOCK: \"inbox-context\",\n CONTEXT_ROW: \"inbox-context-row\",\n CONTEXT_SCREENSHOT_CAPTION: \"inbox-context-screenshot-caption\",\n HIGHLIGHT: \"helldots-highlight\",\n};\n\nexport const IDS = {\n TOOLBAR: \"comment-toolbar\",\n COMMENT_BOX: \"comment-box\",\n COMMENT_INPUT: \"comment-input\",\n SUBMIT_COMMENT: \"submit-comment\",\n STYLES: \"comment-overlay-styles\",\n GLOBAL_STYLES: \"comment-overlay-global-styles\",\n ATTACH_IMAGE_INPUT: \"attach-image-input\",\n};\n\n// RF09 \u2014 comment lifecycle. Order matters: it's the order shown in the\n// status picker menu.\nexport const STATUSES = [\"open\", \"in_progress\", \"resolved\"];\n\nexport const STATUS_COLORS = {\n open: \"#2E90FA\",\n in_progress: \"#FF9F0A\",\n resolved: \"#30D158\",\n};\n\n// RF3 \u2014 comment category. Order matters: it's the order shown in the picker.\nexport const COMMENT_TYPES = [\"bug\", \"suggestion\", \"question\", \"improvement\"];\n\nexport const TYPE_COLORS = {\n bug: \"#FF453A\",\n suggestion: \"#BF5AF2\",\n question: \"#64D2FF\",\n improvement: \"#5E5CE6\",\n};\n\n// RF4 \u2014 priority, ordered high\u2192low so the picker reads as a scale.\nexport const PRIORITIES = [\"high\", \"medium\", \"low\"];\n\n// Deliberate red/orange/grey ramp: it reads as urgency at a glance. `high`\n// sharing red with `bug` (and `medium` sharing orange with `in_progress`) is\n// fine \u2014 they're different dimensions in different UI slots, and no badge\n// ever conveys meaning by colour alone (WCAG 1.4.1).\nexport const PRIORITY_COLORS = {\n high: \"#FF453A\",\n medium: \"#FF9F0A\",\n low: \"#8E8E93\",\n};\n\nexport const SELECTORS = {\n CONTAINER: 'section, div[class*=\"container\"], div[class*=\"content\"]',\n};\n\nexport const Z_INDEX = {\n CIRCLE: 9997,\n TOOLTIP: 10000,\n TOOLBAR: 9998,\n COMMENT_BOX: 9999,\n LIGHTBOX: 10001,\n};\n\nexport const CURSOR_SVG = `data:image/svg+xml;utf8,<svg width=\"48\" height=\"48\" viewBox=\"0 0 48 48\" fill=\"none\" xmlns=\"http://www.w3.org/2000/svg\"><g filter=\"url(%23filter0_d_4_97)\"><path d=\"M6 8C6 6.89543 6.89543 6 8 6H20C27.732 6 34 12.268 34 20V20C34 27.732 27.732 34 20 34V34C12.268 34 6 27.732 6 20V8Z\" fill=\"%232E90FA\"/><path d=\"M8 7H20C27.1797 7 33 12.8203 33 20C33 27.1797 27.1797 33 20 33C12.8203 33 7 27.1797 7 20V8C7 7.44772 7.44772 7 8 7Z\" stroke=\"white\" stroke-width=\"2\"/></g><filter id=\"filter0_d_4_97\" x=\"0\" y=\"0\" width=\"48\" height=\"48\" filterUnits=\"userSpaceOnUse\" color-interpolation-filters=\"sRGB\"><feFlood flood-opacity=\"0\" result=\"BackgroundImageFix\"/><feColorMatrix in=\"SourceAlpha\" type=\"matrix\" values=\"0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 127 0\" result=\"hardAlpha\"/><feOffset dx=\"4\" dy=\"4\"/><feGaussianBlur stdDeviation=\"5\"/><feComposite in2=\"hardAlpha\" operator=\"out\"/><feColorMatrix type=\"matrix\" values=\"0 0 0 0 0.180392 0 0 0 0 0.564706 0 0 0 0 0.980392 0 0 0 0.16 0\"/><feBlend mode=\"normal\" in2=\"BackgroundImageFix\" result=\"effect1_dropShadow_4_97\"/><feBlend mode=\"normal\" in=\"SourceGraphic\" in2=\"effect1_dropShadow_4_97\" result=\"shape\"/></filter></svg>`;\n", "import { CLASSES, IDS, Z_INDEX, CURSOR_SVG } from \"./constants.js\";\n\nexport const getStyles = () => `\n\n :host {\n all: initial;\n display: block;\n font-family: -apple-system, BlinkMacSystemFont, \"Segoe UI\", Roboto, Helvetica, Arial, sans-serif;\n line-height: 1.5;\n color-scheme: light;\n }\n\n :host *,\n :host *::before,\n :host *::after {\n box-sizing: border-box;\n font-family: inherit;\n }\n\n button {\n padding: 0;\n font: inherit;\n color: inherit;\n }\n\n #${IDS.TOOLBAR} {\n position: fixed;\n bottom: 20px;\n left: 50%;\n transform: translateX(-50%);\n z-index: ${Z_INDEX.TOOLBAR};\n }\n\n .${CLASSES.TOOLBAR_ACTION_WRAPPER} {\n position: relative;\n }\n\n .${CLASSES.TOOLBAR_ACTION_TOOLTIP} {\n position: absolute;\n bottom: calc(100% + 10px);\n left: 50%;\n transform: translateX(-50%) translateY(4px);\n display: flex;\n align-items: center;\n gap: 8px;\n background: rgba(20, 20, 23, 0.95);\n backdrop-filter: blur(16px);\n -webkit-backdrop-filter: blur(16px);\n padding: 8px 12px;\n border-radius: 10px;\n border: 1px solid rgba(255, 255, 255, 0.08);\n box-shadow: 0 4px 24px rgba(0, 0, 0, 0.35);\n color: white;\n white-space: nowrap;\n opacity: 0;\n pointer-events: none;\n transition: opacity 0.15s ease, transform 0.15s ease;\n }\n\n .${CLASSES.TOOLBAR_ACTION_WRAPPER}:hover .${\n CLASSES.TOOLBAR_ACTION_TOOLTIP\n } {\n opacity: 1;\n pointer-events: auto;\n transform: translateX(-50%) translateY(0);\n }\n\n .${CLASSES.TOOLBAR_TEXT} {\n font-size: 13px;\n font-weight: 500;\n letter-spacing: -0.01em;\n }\n\n .${CLASSES.SHORTCUT_HINT} {\n font-size: 11px;\n font-weight: 500;\n color: rgba(255, 255, 255, 0.5);\n background: rgba(255, 255, 255, 0.06);\n border: 1px solid rgba(255, 255, 255, 0.1);\n padding: 2px 6px;\n border-radius: 5px;\n line-height: 1;\n white-space: nowrap;\n }\n\n .${CLASSES.TOOLBAR_ACTIONS} {\n display: flex;\n flex-direction: row;\n background: rgba(20, 20, 23, 0.95);\n backdrop-filter: blur(16px);\n -webkit-backdrop-filter: blur(16px);\n border-radius: 12px;\n box-shadow: 0 4px 24px rgba(0, 0, 0, 0.35);\n }\n\n .${CLASSES.TOOLBAR_ACTION_BTN} {\n width: 42px;\n height: 42px;\n display: flex;\n align-items: center;\n justify-content: center;\n background: none;\n border: none;\n outline: none;\n color: rgba(255, 255, 255, 0.65);\n cursor: pointer;\n transition: background 0.2s, color 0.2s;\n padding: 0;\n }\n\n .${CLASSES.TOOLBAR_ACTION_WRAPPER}:first-child .${\n CLASSES.TOOLBAR_ACTION_BTN\n } {\n border-radius: 12px 0 0 12px;\n }\n\n .${CLASSES.TOOLBAR_ACTION_WRAPPER}:last-child .${\n CLASSES.TOOLBAR_ACTION_BTN\n } {\n border-radius: 0 12px 12px 0;\n }\n\n .${CLASSES.TOOLBAR_ACTION_BTN}:hover {\n background: rgba(255, 255, 255, 0.08);\n color: white;\n }\n\n .${CLASSES.TOOLBAR_COMMENT_BTN}.${CLASSES.ACTIVE} {\n color: #2E90FA;\n background: rgba(46, 144, 250, 0.1);\n }\n\n \n #${IDS.COMMENT_BOX} {\n position: fixed;\n background: #1C1C1E;\n border-radius: 12px;\n box-shadow: 0 4px 20px rgba(0,0,0,0.4);\n padding: 16px;\n z-index: ${Z_INDEX.COMMENT_BOX};\n width: 400px;\n display: none;\n box-sizing: border-box;\n }\n \n #${IDS.COMMENT_BOX} .${CLASSES.COMMENT_INPUT_AREA} {\n display: flex;\n flex-direction: column;\n gap: 0;\n }\n\n .${CLASSES.CLASSIFY_ROW} {\n display: flex;\n align-items: center;\n flex-wrap: wrap;\n gap: 6px;\n padding: 8px 10px 0;\n }\n .${CLASSES.TAGS_INPUT} {\n flex: 1 1 90px;\n min-width: 90px;\n background: transparent;\n border: none;\n outline: none;\n color: inherit;\n font-size: 12px;\n padding: 2px 0;\n }\n .${CLASSES.TAG_CHIP} {\n display: inline-flex;\n align-items: center;\n gap: 4px;\n padding: 2px 6px;\n border-radius: 10px;\n background: rgba(255, 255, 255, 0.1);\n font-size: 11px;\n line-height: 1.4;\n }\n .${CLASSES.TAG_CHIP_REMOVE} {\n background: none;\n border: none;\n color: inherit;\n cursor: pointer;\n padding: 0;\n font-size: 13px;\n line-height: 1;\n opacity: 0.6;\n }\n .${CLASSES.TAG_CHIP_REMOVE}:hover {\n opacity: 1;\n }\n\n #${IDS.COMMENT_INPUT} {\n flex: 1;\n min-height: 20px;\n background: #1C1C1E;\n border: none;\n resize: none;\n font-family: inherit;\n color: white;\n font-size: 14px;\n line-height: 1.4;\n box-sizing: border-box;\n field-sizing: content;\n padding-top: 4px;\n padding-bottom: 8px;\n }\n\n #${IDS.COMMENT_INPUT}::placeholder {\n color: rgba(255, 255, 255, 0.5);\n }\n \n #${IDS.COMMENT_INPUT}:focus {\n outline: none;\n box-shadow: none;\n }\n\n .${CLASSES.COMMENT_ACTIONS_BAR} {\n display: flex;\n align-items: center;\n justify-content: space-between;\n padding-top: 12px;\n }\n\n .${CLASSES.ATTACH_IMAGE_BTN} {\n background: none;\n border: none;\n color: rgba(255, 255, 255, 0.5);\n cursor: pointer;\n display: flex;\n align-items: center;\n justify-content: center;\n border-radius: 6px;\n transition: background 0.2s, color 0.2s;\n }\n\n .${CLASSES.ATTACH_IMAGE_BTN}:hover {\n background: rgba(255, 255, 255, 0.1);\n color: rgba(255, 255, 255, 0.8);\n }\n\n .${CLASSES.CIRCLE} {\n position: absolute;\n width: 28px;\n height: 28px;\n background: #2E90FA;\n border-radius: 0% 100% 100% 100%;\n border: 2px solid #FFF;\n cursor: pointer;\n box-shadow: 0 1px 5px rgba(0,0,0,0.2);\n transition: transform 0.2s, background 0.2s;\n z-index: ${Z_INDEX.CIRCLE};\n transform: translate(-50%, -50%);\n }\n\n .${CLASSES.CIRCLE}:hover {\n transform: translate(-50%, -50%) scale(1.2) !important;\n background: rgb(0, 123, 255);\n }\n\n .${CLASSES.CIRCLE}.${CLASSES.HIGHLIGHT} {\n transform: translate(-50%, -50%) scale(1.2) !important;\n background: rgb(0, 123, 255);\n box-shadow: 0 0 0 4px rgba(46, 144, 250, 0.35), 0 1px 5px rgba(0,0,0,0.2);\n }\n\n .${CLASSES.CIRCLE_WRAPPER} {\n position: absolute;\n left: 0;\n top: 0;\n width: 100%;\n height: 100%;\n pointer-events: none;\n z-index: ${Z_INDEX.CIRCLE};\n }\n\n .${CLASSES.TOOLTIP} {\n position: fixed;\n background: #1C1C1E;\n border-radius: 12px;\n padding: 16px;\n box-shadow: 0 4px 20px rgba(0,0,0,0.4);\n width: 400px;\n z-index: ${Z_INDEX.TOOLTIP};\n color: white;\n font-size: 14px;\n line-height: 1.5;\n box-sizing: border-box;\n }\n\n .${CLASSES.TOOLTIP} .${CLASSES.THREAD_HEADER} {\n padding: 0 0 0;\n }\n\n .${CLASSES.TOOLTIP} .${CLASSES.THREAD_BODY} {\n padding: 8px 0;\n }\n\n .${CLASSES.THREAD_POPOVER} {\n position: fixed;\n background: #1C1C1E;\n border-radius: 12px;\n padding: 16px;\n box-shadow: 0 4px 20px rgba(0,0,0,0.4);\n width: 400px;\n z-index: ${Z_INDEX.TOOLTIP};\n color: white;\n font-size: 14px;\n line-height: 1.5;\n box-sizing: border-box;\n }\n\n .${CLASSES.INBOX_PANEL} {\n position: fixed;\n top: 16px;\n right: 16px;\n bottom: 16px;\n width: 380px;\n display: flex;\n flex-direction: column;\n background: #1C1C1E;\n border: 1px solid rgba(255,255,255,0.08);\n border-radius: 14px;\n box-shadow: 0 8px 32px rgba(0,0,0,0.5);\n z-index: ${Z_INDEX.COMMENT_BOX};\n color: white;\n font-size: 14px;\n line-height: 1.5;\n box-sizing: border-box;\n overflow: hidden;\n }\n\n @media (max-width: 420px) {\n .${CLASSES.INBOX_PANEL} {\n left: 16px;\n width: auto;\n }\n }\n\n .${CLASSES.INBOX_HEADER},\n .${CLASSES.INBOX_DETAIL_HEADER} {\n display: flex;\n align-items: center;\n justify-content: space-between;\n gap: 8px;\n padding: 12px 14px;\n border-bottom: 1px solid rgba(255,255,255,0.08);\n flex: none;\n }\n\n .${CLASSES.INBOX_FILTER}-wrapper {\n position: relative;\n }\n\n .${CLASSES.INBOX_FILTER} {\n display: flex;\n align-items: center;\n gap: 6px;\n background: transparent;\n border: none;\n color: white;\n font-size: 13px;\n font-weight: 600;\n cursor: pointer;\n padding: 4px 6px;\n border-radius: 6px;\n }\n\n .${CLASSES.INBOX_FILTER}:hover {\n background: rgba(255,255,255,0.08);\n }\n\n .${CLASSES.INBOX_FILTER_MENU} {\n position: absolute;\n top: calc(100% + 4px);\n left: 0;\n background: #2C2C2E;\n border: 1px solid rgba(255,255,255,0.1);\n border-radius: 8px;\n padding: 4px;\n min-width: 190px;\n z-index: 1;\n box-shadow: 0 4px 16px rgba(0,0,0,0.4);\n }\n\n .${CLASSES.INBOX_FILTER_SECTION} {\n padding: 8px 10px 4px;\n font-size: 11px;\n font-weight: 600;\n color: rgba(255,255,255,0.45);\n text-transform: none;\n }\n\n .${CLASSES.INBOX_FILTER_SECTION}:not(:first-child) {\n margin-top: 4px;\n border-top: 1px solid rgba(255,255,255,0.1);\n padding-top: 10px;\n }\n\n .${CLASSES.INBOX_FILTER_OPTION} {\n display: flex;\n justify-content: space-between;\n align-items: center;\n gap: 12px;\n }\n\n .${CLASSES.INBOX_FILTER_OPTION},\n .${CLASSES.INBOX_MENU_ITEM} {\n display: block;\n width: 100%;\n text-align: left;\n background: transparent;\n border: none;\n color: white;\n font-size: 13px;\n padding: 7px 10px;\n border-radius: 6px;\n cursor: pointer;\n }\n\n .${CLASSES.INBOX_FILTER_OPTION}:hover,\n .${CLASSES.INBOX_MENU_ITEM}:hover {\n background: rgba(255,255,255,0.08);\n }\n\n .${CLASSES.INBOX_CLOSE},\n .${CLASSES.INBOX_NAV_BTN},\n .${CLASSES.INBOX_BACK} {\n display: flex;\n align-items: center;\n gap: 4px;\n background: transparent;\n border: none;\n color: rgba(255,255,255,0.75);\n cursor: pointer;\n padding: 4px 6px;\n border-radius: 6px;\n font-size: 14px;\n }\n\n .${CLASSES.INBOX_CLOSE} {\n font-size: 20px;\n line-height: 1;\n }\n\n .${CLASSES.INBOX_CLOSE}:hover,\n .${CLASSES.INBOX_NAV_BTN}:not(:disabled):hover,\n .${CLASSES.INBOX_BACK}:hover {\n background: rgba(255,255,255,0.08);\n color: white;\n }\n\n .${CLASSES.INBOX_NAV_BTN}:disabled {\n opacity: 0.35;\n cursor: default;\n }\n\n .${CLASSES.INBOX_LIST},\n .${CLASSES.INBOX_DETAIL} {\n flex: 1;\n overflow-y: auto;\n padding: 12px;\n display: flex;\n flex-direction: column;\n gap: 12px;\n }\n\n .${CLASSES.INBOX_CARD} {\n border: 1px solid rgba(255,255,255,0.1);\n border-radius: 10px;\n padding: 12px;\n display: flex;\n flex-direction: column;\n gap: 8px;\n }\n\n .${CLASSES.INBOX_LIST} .${CLASSES.INBOX_CARD} {\n cursor: pointer;\n }\n\n .${CLASSES.INBOX_LIST} .${CLASSES.INBOX_CARD}:hover {\n border-color: rgba(255,255,255,0.22);\n }\n\n .${CLASSES.INBOX_CARD}--resolved {\n border-color: rgba(48, 209, 88, 0.4);\n opacity: 0.75;\n }\n\n .${CLASSES.INBOX_LIST} .${CLASSES.INBOX_CARD}--resolved:hover {\n border-color: rgba(48, 209, 88, 0.7);\n opacity: 1;\n }\n\n .${CLASSES.INBOX_CARD_HEADER} {\n display: flex;\n align-items: center;\n justify-content: space-between;\n gap: 8px;\n }\n\n .${CLASSES.INBOX_CARD_ACTIONS} {\n display: flex;\n align-items: center;\n gap: 6px;\n }\n\n .${CLASSES.INBOX_ACTION_BTN} {\n display: flex;\n align-items: center;\n justify-content: center;\n width: 24px;\n height: 24px;\n background: transparent;\n border: none;\n border-radius: 6px;\n color: rgba(255,255,255,0.65);\n cursor: pointer;\n }\n\n .${CLASSES.INBOX_ACTION_BTN}:hover {\n background: rgba(255,255,255,0.08);\n color: white;\n }\n\n /* Type/priority pickers show their current value as text next to the\n dot (colour alone can't tell bug/high apart \u2014 same hex, and there's\n no hover on touch). Grow from the square icon-button width but stay\n bounded so the strip doesn't crowd out copy/status/\u22EF next to it. */\n .${CLASSES.INBOX_ACTION_BTN_LABELED} {\n width: auto;\n max-width: 72px;\n padding: 0 8px 0 6px;\n gap: 5px;\n justify-content: flex-start;\n }\n\n .${CLASSES.INBOX_ACTION_LABEL} {\n font-size: 11px;\n line-height: 1;\n white-space: nowrap;\n overflow: hidden;\n text-overflow: ellipsis;\n }\n\n .${CLASSES.INBOX_STATUS_DOT} {\n width: 12px;\n height: 12px;\n border-radius: 50%;\n border: 1.5px solid rgba(255,255,255,0.45);\n display: inline-block;\n flex: none;\n }\n\n .${CLASSES.INBOX_MENU_ITEM} .${CLASSES.INBOX_STATUS_DOT} {\n width: 9px;\n height: 9px;\n border: none;\n margin-right: 8px;\n vertical-align: baseline;\n }\n\n .${CLASSES.INBOX_MENU_ITEM}[aria-checked=\"true\"] {\n background: rgba(255,255,255,0.08);\n }\n\n .${CLASSES.THREAD_HEADER} .${CLASSES.INBOX_CARD_ACTIONS} {\n margin-left: auto;\n margin-right: 8px;\n }\n\n /* Generic hover tooltip, same look as .thread-time[data-full-date] */\n [data-hd-tooltip] {\n position: relative;\n }\n\n [data-hd-tooltip]::after {\n content: attr(data-hd-tooltip);\n position: absolute;\n bottom: calc(100% + 6px);\n left: 50%;\n transform: translateX(-50%);\n background: #000;\n color: white;\n padding: 4px 8px;\n border-radius: 6px;\n font-size: 11px;\n white-space: nowrap;\n opacity: 0;\n pointer-events: none;\n transition: opacity 0.12s ease;\n z-index: 2;\n }\n\n [data-hd-tooltip]:hover::after {\n opacity: 1;\n }\n\n .${CLASSES.INBOX_MENU} {\n position: absolute;\n top: calc(100% + 4px);\n right: 0;\n background: #2C2C2E;\n border: 1px solid rgba(255,255,255,0.1);\n border-radius: 8px;\n padding: 4px;\n min-width: 130px;\n z-index: 1;\n box-shadow: 0 4px 16px rgba(0,0,0,0.4);\n }\n\n .${CLASSES.INBOX_CARD_TEXT} {\n white-space: pre-wrap;\n word-break: break-word;\n }\n\n .${CLASSES.INBOX_CARD_TAG} {\n align-self: flex-start;\n padding: 1px 8px;\n border-radius: 999px;\n background: rgba(255, 159, 10, 0.2);\n color: #FF9F0A;\n font-size: 11px;\n font-weight: 600;\n }\n\n .${CLASSES.INBOX_BADGES} {\n display: flex;\n flex-wrap: wrap;\n gap: 4px;\n }\n /* Vertical separation from the card text above only applies to the\n badge row on inbox cards -- inside the comment-box classify row,\n .inbox-badges is one flex item among the type/priority pickers and\n the tags input, and the classify row's own gap already spaces it\n from its siblings, so an extra margin here would nudge it out of\n alignment with them. */\n .${CLASSES.INBOX_CARD} .${CLASSES.INBOX_BADGES} {\n margin-top: 6px;\n }\n .${CLASSES.BADGE} {\n display: inline-flex;\n align-items: center;\n padding: 1px 6px;\n border: 1px solid rgba(255, 255, 255, 0.18);\n border-radius: 10px;\n font-size: 10px;\n line-height: 1.6;\n letter-spacing: 0.01em;\n white-space: nowrap;\n }\n .${CLASSES.BADGE_TYPE},\n .${CLASSES.BADGE_PRIORITY} {\n font-weight: 600;\n }\n .${CLASSES.BADGE_TAG} {\n opacity: 0.75;\n }\n .${CLASSES.BADGE_DURATION} {\n opacity: 0.75;\n border-style: dashed;\n }\n\n .${CLASSES.CONTEXT_BLOCK} {\n display: flex;\n flex-direction: column;\n gap: 4px;\n padding: 10px 12px;\n border-top: 1px solid rgba(255, 255, 255, 0.08);\n font-size: 11px;\n }\n .${CLASSES.CONTEXT_BLOCK} img {\n width: 100%;\n border-radius: 6px;\n margin-bottom: 6px;\n cursor: zoom-in;\n }\n .${CLASSES.CONTEXT_SCREENSHOT_CAPTION} {\n opacity: 0.75;\n }\n .${CLASSES.CONTEXT_ROW} {\n display: flex;\n justify-content: space-between;\n gap: 12px;\n opacity: 0.75;\n }\n /* URLs and user agents have no spaces to break on, so the value column\n would otherwise push the row wider than the panel. */\n .${CLASSES.CONTEXT_ROW} span:last-child {\n text-align: right;\n word-break: break-all;\n }\n\n .${CLASSES.INBOX_CARD_REPLY_LINK} {\n align-self: flex-start;\n background: transparent;\n border: none;\n color: rgba(255,255,255,0.55);\n font-size: 13px;\n cursor: pointer;\n padding: 0;\n }\n\n .${CLASSES.INBOX_CARD_REPLY_LINK}:hover {\n color: white;\n }\n\n .${CLASSES.INBOX_REPLIES} {\n display: flex;\n flex-direction: column;\n gap: 10px;\n padding: 0 4px;\n }\n\n .${CLASSES.INBOX_EMPTY} {\n padding: 24px 12px;\n color: rgba(255,255,255,0.55);\n text-align: center;\n }\n\n .${CLASSES.THREAD_HEADER} {\n display: flex;\n justify-content: space-between;\n align-items: center;\n padding: 0 0 0;\n }\n\n .${CLASSES.THREAD_META} {\n display: flex;\n align-items: center;\n gap: 6px;\n }\n\n .${CLASSES.THREAD_AUTHOR} {\n font-weight: 600;\n font-size: 13px;\n }\n\n .${CLASSES.THREAD_TIME} {\n font-size: 12px;\n color: rgba(255,255,255,0.5);\n cursor: default;\n position: relative;\n }\n\n .${CLASSES.THREAD_TIME}::after {\n content: attr(data-full-date);\n position: absolute;\n bottom: calc(100% + 6px);\n left: 50%;\n transform: translateX(-50%);\n background: #000;\n color: white;\n padding: 4px 8px;\n border-radius: 6px;\n font-size: 11px;\n white-space: nowrap;\n opacity: 0;\n pointer-events: none;\n transition: opacity 0.15s ease;\n z-index: 1;\n }\n\n .${CLASSES.THREAD_TIME}:hover::after {\n opacity: 1;\n }\n\n .${CLASSES.THREAD_BODY} {\n padding: 8px 0;\n white-space: pre-wrap;\n word-break: break-word;\n }\n\n .${CLASSES.THREAD_REPLIES} {\n padding: 0;\n }\n\n .${CLASSES.THREAD_REPLIES}:empty {\n display: none;\n }\n\n .${CLASSES.THREAD_REPLY} {\n padding: 16px 0 0 0;\n border-top: 1px solid rgba(255,255,255,0.1);\n white-space: pre-wrap;\n word-break: break-word;\n font-size: 13px;\n color: rgba(255,255,255,0.85);\n }\n\n .${CLASSES.THREAD_REPLY} .${CLASSES.THREAD_META} {\n margin-bottom: 2px;\n }\n\n .${CLASSES.THREAD_REPLY} .${CLASSES.SCREENSHOT_IMG} {\n width: 144px;\n height: 100px;\n object-fit: cover;\n border-radius: 8px;\n margin-top: 4px;\n cursor: pointer;\n display: block;\n }\n\n .${CLASSES.THREAD_INPUT_AREA} {\n display: flex;\n flex-direction: column;\n gap: 0;\n padding: 12px 0 0;\n border-top: 1px solid rgba(255,255,255,0.1);\n }\n\n .${CLASSES.THREAD_INPUT} {\n width: 100%;\n background: transparent;\n border: none;\n padding: 0;\n color: white;\n font-size: 14px;\n font-family: inherit;\n outline: none;\n box-sizing: border-box;\n }\n\n .${CLASSES.THREAD_INPUT}::placeholder {\n color: rgba(255,255,255,0.5);\n }\n\n .${CLASSES.THREAD_INPUT}:focus {\n outline: none;\n box-shadow: none;\n }\n\n .${CLASSES.THREAD_SUBMIT} {\n background: none;\n border: none;\n color: #2E90FA;\n cursor: pointer;\n display: flex;\n align-items: center;\n justify-content: center;\n border-radius: 6px;\n transition: background 0.2s;\n }\n\n .${CLASSES.THREAD_SUBMIT}:hover {\n background: rgba(46, 144, 250, 0.15);\n color: #1570D6;\n }\n\n .${CLASSES.CLOSE_TOOLTIP} {\n background: none;\n border: none;\n font-size: 18px;\n cursor: pointer;\n color: rgba(255,255,255,0.5);\n line-height: 1;\n }\n \n .${CLASSES.CLOSE_TOOLTIP}:hover {\n color: white;\n }\n\n .${CLASSES.PREVIEW_CIRCLE} {\n animation: helldots-pulse 1.5s ease-in-out infinite;\n }\n\n @keyframes helldots-pulse {\n 0%, 100% { box-shadow: 0 0 0 0 rgba(46, 144, 250, 0.4), 0 1px 5px rgba(0,0,0,0.2); }\n 50% { box-shadow: 0 0 0 8px rgba(46, 144, 250, 0), 0 1px 5px rgba(0,0,0,0.2); }\n }\n\n .${CLASSES.COMMENT_OVERLAY} {\n position: fixed;\n top: 0;\n left: 0;\n right: 0;\n bottom: 0;\n background: transparent;\n pointer-events: none;\n z-index: ${Z_INDEX.TOOLBAR - 1};\n }\n\n .${CLASSES.COMMENT_OVERLAY}.${CLASSES.ACTIVE} {\n pointer-events: auto;\n background: rgba(0, 0, 0, 0.1);\n }\n\n .${CLASSES.SELECTION_RECT} {\n position: fixed;\n border: 2px solid #2E90FA;\n background: rgba(46, 144, 250, 0.1);\n pointer-events: none;\n z-index: ${Z_INDEX.TOOLTIP};\n box-sizing: border-box;\n }\n\n .${CLASSES.SCREENSHOTS_CONTAINER} {\n display: none;\n overflow-x: auto;\n gap: 8px;\n margin-top: 4px;\n padding: 4px 0;\n scrollbar-width: none;\n -ms-overflow-style: none;\n margin-bottom: 16px;\n }\n\n .${CLASSES.SCREENSHOTS_CONTAINER}::-webkit-scrollbar {\n display: none;\n }\n\n .${CLASSES.SCREENSHOTS_CONTAINER}.${CLASSES.ACTIVE} {\n display: flex;\n }\n\n .${CLASSES.SCREENSHOT_ITEM} {\n position: relative;\n flex-shrink: 0;\n }\n\n .${CLASSES.SCREENSHOT_ITEM} .${CLASSES.SCREENSHOT_IMG} {\n width: 50px;\n height: 50px;\n object-fit: cover;\n border-radius: 8px;\n cursor: pointer;\n display: block;\n margin: 0;\n }\n\n .${CLASSES.SCREENSHOT_ITEM} .${CLASSES.SCREENSHOT_IMG}:hover {\n opacity: 0.85;\n }\n\n .${CLASSES.SCREENSHOT_ITEM} .${CLASSES.SCREENSHOT_REMOVE} {\n position: absolute;\n top: -5px;\n right: -5px;\n width: 18px;\n height: 18px;\n background: rgba(0,0,0,0.7);\n border: none;\n border-radius: 50%;\n color: white;\n font-size: 12px;\n line-height: 1;\n cursor: pointer;\n display: none;\n align-items: center;\n justify-content: center;\n z-index: 1;\n }\n\n .${CLASSES.SCREENSHOT_ITEM}:hover .${CLASSES.SCREENSHOT_REMOVE} {\n display: flex;\n }\n\n .${CLASSES.SCREENSHOT_ITEM} .${CLASSES.SCREENSHOT_REMOVE}:hover {\n background: rgba(0,0,0,0.9);\n }\n\n .${CLASSES.TOOLTIP} > .${CLASSES.SCREENSHOTS_CONTAINER} .${\n CLASSES.SCREENSHOT_ITEM\n } .${CLASSES.SCREENSHOT_IMG},\n .${CLASSES.THREAD_POPOVER} > .${CLASSES.SCREENSHOTS_CONTAINER} .${\n CLASSES.SCREENSHOT_ITEM\n } .${CLASSES.SCREENSHOT_IMG},\n .${CLASSES.THREAD_REPLY} .${CLASSES.SCREENSHOT_ITEM} .${\n CLASSES.SCREENSHOT_IMG\n } {\n width: 144px;\n height: 100px;\n }\n\n .${CLASSES.LIGHTBOX} {\n position: fixed;\n top: 0;\n left: 0;\n right: 0;\n bottom: 0;\n background: rgba(0,0,0,0.92);\n z-index: ${Z_INDEX.LIGHTBOX};\n display: flex;\n align-items: center;\n justify-content: center;\n animation: helldots-fade-in 0.2s ease;\n }\n\n @keyframes helldots-fade-in {\n from { opacity: 0; }\n to { opacity: 1; }\n }\n\n .${CLASSES.LIGHTBOX_IMG} {\n max-width: 90vw;\n max-height: 90vh;\n object-fit: contain;\n border-radius: 8px;\n }\n\n .${CLASSES.LIGHTBOX_CLOSE} {\n position: absolute;\n top: 16px;\n right: 16px;\n background: rgba(255,255,255,0.15);\n border: none;\n color: white;\n font-size: 24px;\n width: 40px;\n height: 40px;\n border-radius: 50%;\n cursor: pointer;\n display: flex;\n align-items: center;\n justify-content: center;\n transition: background 0.2s;\n }\n\n .${CLASSES.LIGHTBOX_CLOSE}:hover {\n background: rgba(255,255,255,0.3);\n }\n`;\n\n/**\n * Styles that must apply to the host page itself (outside the shadow root),\n * because they target elements HellDots doesn't own \u2014 e.g. `document.body`\n * while in comment mode. A shadow root's stylesheet never reaches outside\n * it, so these can't live in `getStyles()`; they're injected separately\n * into `document.head` instead (see `CommentOverlay.injectStyles`).\n */\nexport const getGlobalStyles = () => `\n .${CLASSES.COMMENT_CURSOR},\n .${CLASSES.COMMENT_CURSOR} * {\n cursor: url('${CURSOR_SVG}') 6 6, auto !important;\n }\n`;\n", "export default {\n commentAriaLabelPrefix: \"Comment: \",\n anonymous: \"Anonymous\",\n justNow: \"Just now\",\n minutesAgoTemplate: \"{n}m\",\n hoursAgoTemplate: \"{n}h\",\n daysAgoTemplate: \"{n}d\",\n toolbarComment: \"Comment\",\n toolbarInbox: \"Inbox\",\n modifierAlt: \"Alt\",\n modifierCtrl: \"Ctrl\",\n commentBoxAriaLabel: \"New comment\",\n commentPlaceholder: \"Type your comment...\",\n attachImage: \"Attach image\",\n send: \"Send\",\n tooltipAriaLabel: \"Comment preview\",\n close: \"Close\",\n popoverAriaLabel: \"Comment thread\",\n replyPlaceholder: \"Reply...\",\n attachedScreenshot: \"Attached screenshot\",\n screenshotPreview: \"Screenshot preview\",\n removeScreenshot: \"Remove screenshot\",\n inboxAriaLabel: \"Comments inbox\",\n inboxEmpty: \"No comments yet\",\n orphanedBadge: \"Unanchored\",\n hiddenBadge: \"Hidden\",\n filterAll: \"All comments\",\n filterCurrentPage: \"Current page\",\n filterByPage: \"Filter by Page\",\n filterByStatus: \"Filter by Status\",\n filterStatusAll: \"All\",\n filterUnresolved: \"Unresolved\",\n filterResolved: \"Resolved\",\n back: \"Back\",\n deleteComment: \"Delete\",\n copyAgentContext: \"Copy agent context\",\n copied: \"Copied\",\n statusLabel: \"Status\",\n prevComment: \"Previous comment\",\n nextComment: \"Next comment\",\n replyLink: \"Reply\",\n commentOptions: \"Comment options\",\n moreOptions: \"More\",\n statusOpen: \"Open\",\n statusInProgress: \"In progress\",\n statusResolved: \"Resolved\",\n durationLessThanMinute: \"<1m\",\n resolvedInTemplate: \"Resolved in {n}\",\n typeLabel: \"Type\",\n priorityLabel: \"Priority\",\n unset: \"Unset\",\n typeBug: \"Bug\",\n typeSuggestion: \"Suggestion\",\n typeQuestion: \"Question\",\n typeImprovement: \"Improvement\",\n priorityHigh: \"High\",\n priorityMedium: \"Medium\",\n priorityLow: \"Low\",\n tagsPlaceholder: \"Add tags...\",\n removeTag: \"Remove tag\",\n filterByType: \"Filter by Type\",\n filterByPriority: \"Filter by Priority\",\n contextSection: \"Context\",\n autoScreenshotLabel: \"Automatic context\",\n contextUrl: \"URL\",\n contextViewport: \"Viewport\",\n contextScreen: \"Screen\",\n contextBrowser: \"Browser\",\n contextOs: \"OS\",\n};\n", "export default {\n commentAriaLabelPrefix: \"Comentario: \",\n anonymous: \"An\u00F3nimo\",\n justNow: \"Justo ahora\",\n minutesAgoTemplate: \"{n}m\",\n hoursAgoTemplate: \"{n}h\",\n daysAgoTemplate: \"{n}d\",\n toolbarComment: \"Comentar\",\n toolbarInbox: \"Bandeja\",\n modifierAlt: \"Alt\",\n modifierCtrl: \"Ctrl\",\n commentBoxAriaLabel: \"Nuevo comentario\",\n commentPlaceholder: \"Escribe tu comentario...\",\n attachImage: \"Adjuntar imagen\",\n send: \"Enviar\",\n tooltipAriaLabel: \"Vista previa del comentario\",\n close: \"Cerrar\",\n popoverAriaLabel: \"Hilo de comentarios\",\n replyPlaceholder: \"Responder...\",\n attachedScreenshot: \"Captura de pantalla adjunta\",\n screenshotPreview: \"Vista previa de la captura\",\n removeScreenshot: \"Quitar captura de pantalla\",\n inboxAriaLabel: \"Bandeja de comentarios\",\n inboxEmpty: \"A\u00FAn no hay comentarios\",\n orphanedBadge: \"Desanclado\",\n hiddenBadge: \"Oculto\",\n filterAll: \"Todos los comentarios\",\n filterCurrentPage: \"P\u00E1gina actual\",\n filterByPage: \"Filtrar por p\u00E1gina\",\n filterByStatus: \"Filtrar por estado\",\n filterStatusAll: \"Todos\",\n filterUnresolved: \"Sin resolver\",\n filterResolved: \"Resueltos\",\n back: \"Volver\",\n deleteComment: \"Eliminar\",\n copyAgentContext: \"Copiar contexto de agente\",\n copied: \"Copiado\",\n statusLabel: \"Estado\",\n prevComment: \"Comentario anterior\",\n nextComment: \"Comentario siguiente\",\n replyLink: \"Responder\",\n commentOptions: \"Opciones del comentario\",\n moreOptions: \"M\u00E1s\",\n statusOpen: \"Abierto\",\n statusInProgress: \"En progreso\",\n statusResolved: \"Resuelto\",\n durationLessThanMinute: \"<1m\",\n resolvedInTemplate: \"Resuelto en {n}\",\n typeLabel: \"Tipo\",\n priorityLabel: \"Prioridad\",\n unset: \"Sin definir\",\n typeBug: \"Bug\",\n typeSuggestion: \"Sugerencia\",\n typeQuestion: \"Pregunta\",\n typeImprovement: \"Mejora\",\n priorityHigh: \"Alta\",\n priorityMedium: \"Media\",\n priorityLow: \"Baja\",\n tagsPlaceholder: \"A\u00F1adir etiquetas...\",\n removeTag: \"Quitar etiqueta\",\n filterByType: \"Filtrar por tipo\",\n filterByPriority: \"Filtrar por prioridad\",\n contextSection: \"Contexto\",\n autoScreenshotLabel: \"Contexto autom\u00E1tico\",\n contextUrl: \"URL\",\n contextViewport: \"Viewport\",\n contextScreen: \"Pantalla\",\n contextBrowser: \"Navegador\",\n contextOs: \"SO\",\n};\n", "import en from \"./locales/en.js\";\nimport es from \"./locales/es.js\";\n\nconst LOCALES = { en, es };\nconst DEFAULT_LOCALE = \"en\";\n\n/**\n * Picks a supported locale code from the browser's language, falling back\n * to English for anything HellDots doesn't ship a translation for.\n * @returns {\"en\" | \"es\"}\n */\nexport function detectLocale() {\n const lang = (navigator.language || DEFAULT_LOCALE).slice(0, 2).toLowerCase();\n return lang in LOCALES ? /** @type {\"en\" | \"es\"} */ (lang) : DEFAULT_LOCALE;\n}\n\n/**\n * Resolves the UI strings dictionary for a given locale code, falling back\n * to English if the code isn't one HellDots ships.\n * @param {string} [localeCode]\n * @returns {typeof en}\n */\nexport function getStrings(localeCode) {\n return LOCALES[localeCode] || LOCALES[DEFAULT_LOCALE];\n}\n\n/**\n * Substitutes `{n}` in a template string, used for relative time labels and\n * resolution-duration badges (where the substitution is already a string,\n * e.g. \"2d 4h\" or the \"\u2014\" fallback).\n * @param {string} template\n * @param {number | string} n\n */\nexport function formatTemplate(template, n) {\n return template.replace(\"{n}\", String(n));\n}\n\nconst MINUTE_MS = 60_000;\n\n/**\n * RF5 \u2014 human-readable elapsed time (\"<1m\", \"45m\", \"3h 12m\", \"2d 4h\").\n * Reuses the same {n}-templates the relative timestamps already use.\n * @param {number} ms\n * @param {ReturnType<typeof getStrings>} strings\n * @returns {string} empty string when `ms` isn't a usable duration\n */\nexport function formatDuration(ms, strings) {\n if (!Number.isFinite(ms) || ms < 0) return \"\";\n\n const totalMinutes = Math.floor(ms / MINUTE_MS);\n if (totalMinutes < 1) return strings.durationLessThanMinute;\n if (totalMinutes < 60) {\n return formatTemplate(strings.minutesAgoTemplate, totalMinutes);\n }\n\n const totalHours = Math.floor(totalMinutes / 60);\n if (totalHours < 24) {\n const minutes = totalMinutes % 60;\n const hours = formatTemplate(strings.hoursAgoTemplate, totalHours);\n return minutes\n ? `${hours} ${formatTemplate(strings.minutesAgoTemplate, minutes)}`\n : hours;\n }\n\n const totalDays = Math.floor(totalHours / 24);\n const hours = totalHours % 24;\n const days = formatTemplate(strings.daysAgoTemplate, totalDays);\n return hours\n ? `${days} ${formatTemplate(strings.hoursAgoTemplate, hours)}`\n : days;\n}\n", "// Serializable comment anchors. An anchor pairs a best-effort CSS selector\n// (fast path) with a content fingerprint (verification + rescue path) so a\n// comment can be re-attached to its element after a page reload. Design:\n// docs/superpowers/specs/2026-07-02-comment-anchoring-design.md\n\nconst TEXT_SNIPPET_MAX = 64;\nconst MAX_CLASS_PATH_DEPTH = 3;\nconst MAX_STRUCTURAL_DEPTH = 5;\n\n// A selector match is verified against the fingerprint before being trusted;\n// the rescue path (fingerprint-only, no structural signal) demands more.\nconst SELECTOR_THRESHOLD = 0.6;\nconst RESCUE_THRESHOLD = 0.7;\n\nconst GENERATED_CLASS_PREFIX_RE = /^(css|sc|jsx|emotion)-/i;\nconst FRAMEWORK_DATA_ATTR_RE = /^data-(reactid|react-|v-|svelte-)/;\nconst STABLE_ATTR_NAMES = [\"id\", \"name\", \"role\", \"aria-label\"];\nconst SELECTOR_ATTR_NAMES = [\"data-testid\", \"name\", \"aria-label\"];\n\nconst escapeCss = (value) => {\n if (typeof CSS !== \"undefined\" && CSS.escape) return CSS.escape(value);\n return String(value).replace(/[^a-zA-Z0-9_-]/g, \"\\\\$&\");\n};\n\nconst escapeAttrValue = (value) => String(value).replace(/[\"\\\\]/g, \"\\\\$&\");\n\nconst isUnique = (selector, doc) => {\n try {\n return doc.querySelectorAll(selector).length === 1;\n } catch {\n return false;\n }\n};\n\nconst normalizeText = (text) =>\n (text || \"\").replace(/\\s+/g, \" \").trim().slice(0, TEXT_SNIPPET_MAX);\n\n// Heuristic: tooling-generated class names (CSS-in-JS, scoped-CSS hashes)\n// either carry a known prefix or contain a long token with digits in it.\nconst isStableClass = (cls) => {\n if (GENERATED_CLASS_PREFIX_RE.test(cls)) return false;\n return !cls.split(/[-_]/).some((part) => part.length >= 5 && /\\d/.test(part));\n};\n\nconst stableClassesOf = (element) =>\n [...element.classList].filter(isStableClass);\n\nconst stableAttributes = (element) => {\n /** @type {Record<string, string>} */\n const attrs = {};\n for (const { name, value } of element.attributes) {\n const isStable =\n STABLE_ATTR_NAMES.includes(name) ||\n (name.startsWith(\"data-\") && !FRAMEWORK_DATA_ATTR_RE.test(name));\n if (isStable && value) attrs[name] = value.slice(0, TEXT_SNIPPET_MAX);\n }\n return attrs;\n};\n\nconst siblingPosition = (element) => {\n const parent = element.parentElement;\n if (!parent) return { index: 0, count: 1 };\n const sameTag = [...parent.children].filter(\n (child) => child.tagName === element.tagName\n );\n return { index: sameTag.indexOf(element), count: sameTag.length };\n};\n\nconst idSelector = (element, doc) => {\n if (!element.id) return null;\n const selector = `#${escapeCss(element.id)}`;\n return isUnique(selector, doc) ? selector : null;\n};\n\nconst attributeSelector = (element, doc) => {\n const tag = element.tagName.toLowerCase();\n for (const name of SELECTOR_ATTR_NAMES) {\n const value = element.getAttribute(name);\n if (!value) continue;\n const selector = `${tag}[${name}=\"${escapeAttrValue(value)}\"]`;\n if (isUnique(selector, doc)) return selector;\n }\n return null;\n};\n\nconst classPathSelector = (element, doc) => {\n const segments = [];\n let current = element;\n for (let depth = 0; depth < MAX_CLASS_PATH_DEPTH && current; depth++) {\n const classes = stableClassesOf(current);\n const tag = current.tagName.toLowerCase();\n segments.unshift(\n classes.length ? `${tag}.${classes.map(escapeCss).join(\".\")}` : tag\n );\n // The element's own segment must carry at least one stable class for\n // this strategy to say anything a structural path wouldn't.\n if (depth === 0 && !classes.length) return null;\n const selector = segments.join(\" > \");\n if (isUnique(selector, doc)) return selector;\n current = current.parentElement;\n }\n return null;\n};\n\nconst structuralSelector = (element, doc) => {\n if (element === doc.body) return \"body\";\n const segments = [];\n let current = element;\n for (let depth = 0; depth < MAX_STRUCTURAL_DEPTH && current; depth++) {\n if (current === doc.body) {\n segments.unshift(\"body\");\n break;\n }\n if (current.id) {\n const rooted = [`#${escapeCss(current.id)}`, ...segments].join(\" > \");\n if (isUnique(rooted, doc)) return rooted;\n }\n const { index } = siblingPosition(current);\n segments.unshift(\n `${current.tagName.toLowerCase()}:nth-of-type(${index + 1})`\n );\n current = current.parentElement;\n }\n const selector = segments.join(\" > \");\n return isUnique(selector, doc) ? selector : null;\n};\n\nconst generateSelector = (element, doc) =>\n idSelector(element, doc) ||\n attributeSelector(element, doc) ||\n classPathSelector(element, doc) ||\n structuralSelector(element, doc);\n\n/**\n * Best-effort unique CSS selector for any element (or null). Exposed for\n * the overlay's target-visibility tracking; same cascade used by anchors.\n * @param {HTMLElement} element\n * @returns {string | null}\n */\nexport function generateElementSelector(element) {\n return generateSelector(element, element.ownerDocument);\n}\n\n/**\n * Captures a serializable anchor for `element` at creation time.\n * @param {HTMLElement} element\n * @param {number} relativeX\n * @param {number} relativeY\n * @returns {import('./index.d.ts').CommentAnchor}\n */\nexport function createAnchor(element, relativeX, relativeY) {\n const doc = element.ownerDocument;\n const { index, count } = siblingPosition(element);\n return {\n version: 1,\n selector: generateSelector(element, doc),\n fingerprint: {\n tagName: element.tagName,\n textSnippet: normalizeText(element.textContent),\n attributes: stableAttributes(element),\n siblingIndex: index,\n siblingCount: count,\n },\n relativeX,\n relativeY,\n };\n}\n\nconst textSimilarity = (a, b) => {\n if (!a && !b) return 1;\n if (!a || !b) return 0;\n if (a === b) return 1;\n if (a.startsWith(b) || b.startsWith(a)) return 0.8;\n const tokensA = new Set(a.split(\" \"));\n const tokensB = new Set(b.split(\" \"));\n let common = 0;\n for (const token of tokensA) if (tokensB.has(token)) common++;\n return (2 * common) / (tokensA.size + tokensB.size);\n};\n\nconst attributeSimilarity = (element, attrs) => {\n const names = Object.keys(attrs);\n if (!names.length) return 1;\n let matched = 0;\n for (const name of names) {\n if (\n (element.getAttribute(name) || \"\").slice(0, TEXT_SNIPPET_MAX) ===\n attrs[name]\n ) {\n matched++;\n }\n }\n return matched / names.length;\n};\n\nconst positionSimilarity = (element, fingerprint) => {\n const { index, count } = siblingPosition(element);\n const delta = Math.abs(index - fingerprint.siblingIndex);\n const span = Math.max(fingerprint.siblingCount, count, 1);\n return Math.max(0, 1 - delta / span);\n};\n\nconst scoreElement = (element, fingerprint) => {\n if (element.tagName !== fingerprint.tagName) return 0;\n\n const hasText = Boolean(fingerprint.textSnippet);\n const hasAttrs = Object.keys(fingerprint.attributes || {}).length > 0;\n\n // Base weights (text 0.5 / attrs 0.3 / position 0.2); a missing signal's\n // weight shifts to the other content signal so the scale stays 0\u20131.\n let textWeight = 0.5;\n let attrWeight = 0.3;\n const posWeight = 0.2;\n if (!hasAttrs) {\n textWeight += attrWeight;\n attrWeight = 0;\n } else if (!hasText) {\n attrWeight += textWeight;\n textWeight = 0;\n }\n\n // Degenerate fingerprint: only structural signal remains.\n if (!hasText && !hasAttrs) {\n return positionSimilarity(element, fingerprint);\n }\n\n return (\n textWeight *\n textSimilarity(\n normalizeText(element.textContent),\n fingerprint.textSnippet\n ) +\n attrWeight * attributeSimilarity(element, fingerprint.attributes || {}) +\n posWeight * positionSimilarity(element, fingerprint)\n );\n};\n\nconst bestMatch = (candidates, fingerprint) => {\n let best = null;\n for (const element of candidates) {\n const confidence = scoreElement(element, fingerprint);\n if (!best || confidence > best.confidence) best = { element, confidence };\n }\n return best;\n};\n\n/**\n * Re-locates the element an anchor points at, or null if no candidate is\n * trustworthy (orphaned comment). Never throws.\n * @param {import('./index.d.ts').CommentAnchor} anchor\n * @param {Document} [doc]\n * @returns {{ element: HTMLElement, confidence: number } | null}\n */\nexport function resolveAnchor(anchor, doc = document) {\n const fingerprint = anchor?.fingerprint;\n if (!fingerprint || !fingerprint.tagName) return null;\n\n if (anchor.selector) {\n let candidates = [];\n try {\n candidates = [...doc.querySelectorAll(anchor.selector)];\n } catch {\n // Corrupt selector \u2014 the rescue search below still applies.\n }\n const best = bestMatch(candidates, fingerprint);\n if (best && best.confidence >= SELECTOR_THRESHOLD) return best;\n }\n\n // Rescue search: only meaningful when the fingerprint carries content\n // signal \u2014 anonymous elements would make any tag-wide match a guess.\n const hasSignal =\n Boolean(fingerprint.textSnippet) ||\n Object.keys(fingerprint.attributes || {}).length > 0;\n if (!hasSignal) return null;\n\n let candidates;\n try {\n candidates = [...doc.querySelectorAll(fingerprint.tagName)];\n } catch {\n return null;\n }\n const best = bestMatch(candidates, fingerprint);\n return best && best.confidence >= RESCUE_THRESHOLD ? best : null;\n}\n", "// localStorage adapter for the optional `persistence: \"localStorage\"` mode.\n// One key holds the serialized comments of EVERY page (the inbox \"all\n// comments\" filter needs them); merge logic keeps other pages' entries\n// intact while treating in-memory state as the source of truth for ids it\n// knows about. Storage failures (quota, disabled, corrupt JSON) never\n// throw \u2014 the widget just runs without persistence.\n\nexport const STORAGE_KEY = \"helldots-comments\";\n\n// sessionStorage handoff: set right before navigating to another page so\n// the overlay there opens the inbox directly on that comment's detail.\nexport const PENDING_DETAIL_KEY = \"helldots-pending-detail\";\n\n/**\n * @returns {import('./index.d.ts').SerializedComment[]}\n */\nexport function readStoredComments() {\n try {\n const raw = localStorage.getItem(STORAGE_KEY);\n if (!raw) return [];\n const parsed = JSON.parse(raw);\n return Array.isArray(parsed) ? parsed : [];\n } catch (err) {\n console.warn(\"HellDots: could not read stored comments\", err);\n return [];\n }\n}\n\nfunction tryWriteStoredComments(comments) {\n try {\n localStorage.setItem(STORAGE_KEY, JSON.stringify(comments));\n return true;\n } catch {\n return false;\n }\n}\n\n/**\n * Writes the full cross-page corpus. Each comment can carry a base64 JPEG\n * `contextScreenshot` (~33KB) captured automatically (RF1/RF2); a growing\n * corpus of those eventually blows through the ~5MB localStorage quota. On\n * a failed write, the automatic screenshots are the only thing sacrificed \u2014\n * dropped one at a time starting with the oldest comment \u2014 so the comments\n * themselves (and any deliberate, user-attached `screenshots[]`) survive.\n * Never throws: a hostile or disabled localStorage just means no\n * persistence, not a broken widget.\n * @param {import('./index.d.ts').SerializedComment[]} comments\n * @returns {boolean} true once the write succeeded, possibly after shedding\n * automatic screenshots; false if it still failed with nothing left to shed\n */\nexport function writeStoredComments(comments) {\n if (tryWriteStoredComments(comments)) return true;\n\n // Oldest first (by createdAt; ties/missing dates fall back to array\n // order), and only entries that actually have something to shed.\n const shedOrder = comments\n .map((comment, index) => ({ comment, index }))\n .filter(({ comment }) => comment?.contextScreenshot)\n .sort((a, b) => {\n const timeA = Date.parse(a.comment.createdAt);\n const timeB = Date.parse(b.comment.createdAt);\n if (Number.isFinite(timeA) && Number.isFinite(timeB) && timeA !== timeB) {\n return timeA - timeB;\n }\n return a.index - b.index;\n });\n\n if (shedOrder.length === 0) {\n console.warn(\n \"HellDots: could not persist comments (storage quota exceeded, nothing left to shed)\"\n );\n return false;\n }\n\n const working = [...comments];\n let shed = 0;\n for (const { index } of shedOrder) {\n working[index] = { ...working[index], contextScreenshot: null };\n shed++;\n if (tryWriteStoredComments(working)) {\n console.warn(\n `HellDots: localStorage quota exceeded \u2014 dropped the automatic ` +\n `context screenshot from the ${shed} oldest comment(s) to keep ` +\n `all comments persisted. Comment text, replies and user-attached ` +\n `screenshots were not touched.`\n );\n return true;\n }\n }\n\n console.warn(\n `HellDots: could not persist comments even after dropping all ${shed} ` +\n `automatic context screenshot(s); storage quota exceeded`\n );\n return false;\n}\n\n/**\n * Merges the in-memory snapshot into what's already stored: entries the\n * memory knows about (by id) and entries of the current page are replaced\n * by the snapshot; entries from other pages are preserved.\n * @param {import('./index.d.ts').SerializedComment[]} stored\n * @param {import('./index.d.ts').SerializedComment[]} current\n * @param {string} currentPage\n * @returns {import('./index.d.ts').SerializedComment[]}\n */\nexport function mergeForStorage(stored, current, currentPage) {\n const currentIds = new Set(current.map((c) => c.id));\n const kept = stored.filter(\n (c) => !currentIds.has(c.id) && c.page !== currentPage\n );\n return [...kept, ...current];\n}\n", "// Shared per-comment action strip (copy agent context / lifecycle status /\n// more menu) used by both the inbox cards and the thread popover header.\n// Pure view: every mutation goes through the callbacks; the component only\n// keeps its own dot color and tooltips in sync after a selection.\n\nimport {\n CLASSES,\n STATUSES,\n STATUS_COLORS,\n COMMENT_TYPES,\n TYPE_COLORS,\n PRIORITIES,\n PRIORITY_COLORS,\n} from \"./constants.js\";\n\nconst COPY_ICON_SVG = `<svg width=\"14\" height=\"14\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"2\" stroke-linecap=\"round\" stroke-linejoin=\"round\"><rect x=\"9\" y=\"9\" width=\"13\" height=\"13\" rx=\"2\" ry=\"2\"/><path d=\"M5 15H4a2 2 0 0 1-2-2V4a2 2 0 0 1 2-2h9a2 2 0 0 1 2 2v1\"/></svg>`;\nconst CHECK_ICON_SVG = `<svg width=\"14\" height=\"14\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"2\" stroke-linecap=\"round\" stroke-linejoin=\"round\"><polyline points=\"20 6 9 17 4 12\"/></svg>`;\nconst DOTS_ICON_SVG = `<svg width=\"14\" height=\"14\" viewBox=\"0 0 24 24\" fill=\"currentColor\"><circle cx=\"5\" cy=\"12\" r=\"1.6\"/><circle cx=\"12\" cy=\"12\" r=\"1.6\"/><circle cx=\"19\" cy=\"12\" r=\"1.6\"/></svg>`;\n\nexport const copyToClipboard = (text) => {\n if (navigator.clipboard?.writeText) {\n return navigator.clipboard.writeText(text).catch(() => {});\n }\n const textarea = document.createElement(\"textarea\");\n textarea.value = text;\n textarea.style.position = \"fixed\";\n textarea.style.opacity = \"0\";\n document.body.appendChild(textarea);\n textarea.select();\n try {\n document.execCommand(\"copy\");\n } catch {}\n textarea.remove();\n return Promise.resolve();\n};\n\nexport const statusLabelOf = (status, strings) =>\n ({\n open: strings.statusOpen,\n in_progress: strings.statusInProgress,\n resolved: strings.statusResolved,\n })[status] || strings.statusOpen;\n\nexport const typeLabelOf = (type, strings) =>\n ({\n bug: strings.typeBug,\n suggestion: strings.typeSuggestion,\n question: strings.typeQuestion,\n improvement: strings.typeImprovement,\n })[type] || strings.unset;\n\nexport const priorityLabelOf = (priority, strings) =>\n ({\n high: strings.priorityHigh,\n medium: strings.priorityMedium,\n low: strings.priorityLow,\n })[priority] || strings.unset;\n\n/**\n * Dot-and-menu picker shared by the status, type and priority controls.\n * Keeps its own copy of the selection so the UI stays correct even when the\n * consumer's onSelect is async or doesn't mutate the comment in place.\n * @param {{\n * action: string,\n * options: Array<string|null>,\n * value: string|null,\n * colorOf: (option: string|null) => string,\n * labelOf: (option: string|null) => string,\n * tooltipLabel: string,\n * onSelect: (option: string|null) => void,\n * showLabel?: boolean,\n * }} config\n * @returns {HTMLElement}\n */\nexport const createPicker = ({\n action,\n options,\n value,\n colorOf,\n labelOf,\n tooltipLabel,\n onSelect,\n showLabel = false,\n}) => {\n const wrapper = document.createElement(\"div\");\n wrapper.style.position = \"relative\";\n\n const btn = document.createElement(\"button\");\n btn.type = \"button\";\n btn.className = CLASSES.INBOX_ACTION_BTN;\n if (showLabel) btn.classList.add(CLASSES.INBOX_ACTION_BTN_LABELED);\n btn.dataset.action = action;\n btn.setAttribute(\"aria-haspopup\", \"true\");\n\n const dot = document.createElement(\"span\");\n dot.className = CLASSES.INBOX_STATUS_DOT;\n btn.appendChild(dot);\n\n // Type and priority share exact colours (bug === high === #FF453A), and\n // unset shares \"no colour\" with unset \u2014 the dot alone can't tell them\n // apart, and hover-only disambiguation doesn't exist on touch. A short\n // text label next to the dot makes the current value legible without it.\n let labelEl = null;\n if (showLabel) {\n labelEl = document.createElement(\"span\");\n labelEl.className = CLASSES.INBOX_ACTION_LABEL;\n btn.appendChild(labelEl);\n }\n\n const menu = document.createElement(\"div\");\n menu.className = CLASSES.INBOX_MENU;\n menu.style.display = \"none\";\n menu.setAttribute(\"role\", \"menu\");\n\n let current = value;\n\n const syncUi = () => {\n const label = `${tooltipLabel}: ${labelOf(current)}`;\n dot.style.backgroundColor = colorOf(current);\n btn.dataset.hdTooltip = label;\n btn.setAttribute(\"aria-label\", label);\n if (labelEl) labelEl.textContent = labelOf(current);\n menu\n .querySelectorAll(\"[data-picker-option]\")\n .forEach((/** @type {HTMLElement} */ item) => {\n const raw = item.dataset.pickerOption;\n const option = raw === \"\" ? null : raw;\n item.setAttribute(\"aria-checked\", String(option === current));\n });\n };\n\n for (const option of options) {\n const item = document.createElement(\"button\");\n item.type = \"button\";\n item.className = CLASSES.INBOX_MENU_ITEM;\n // \"\" is how a null option round-trips through a dataset string.\n item.dataset.pickerOption = option === null ? \"\" : option;\n item.setAttribute(\"role\", \"menuitemradio\");\n\n const itemDot = document.createElement(\"span\");\n itemDot.className = CLASSES.INBOX_STATUS_DOT;\n itemDot.style.backgroundColor = colorOf(option);\n item.appendChild(itemDot);\n item.appendChild(document.createTextNode(labelOf(option)));\n\n item.addEventListener(\"click\", (e) => {\n e.stopPropagation();\n menu.style.display = \"none\";\n // No-op: re-picking the option that's already selected must not fire\n // onSelect \u2014 for the status picker that would re-stamp resolvedAt on\n // every redundant \"Resolved\" click, destroying RF5's elapsed time.\n if (option === current) return;\n current = option;\n onSelect(option);\n syncUi();\n });\n menu.appendChild(item);\n }\n\n btn.addEventListener(\"click\", (e) => {\n e.stopPropagation();\n menu.style.display = menu.style.display === \"none\" ? \"block\" : \"none\";\n });\n\n wrapper.appendChild(btn);\n wrapper.appendChild(menu);\n syncUi();\n return wrapper;\n};\n\n/**\n * @param {Object} comment\n * @param {{ strings: Object, onCopy: Function, onSetStatus: Function, onSetType: Function, onSetPriority: Function, onDelete: Function }} deps\n * @returns {HTMLElement}\n */\nexport const createCommentActions = (\n comment,\n { strings, onCopy, onSetStatus, onSetType, onSetPriority, onDelete }\n) => {\n const actions = document.createElement(\"div\");\n actions.className = CLASSES.INBOX_CARD_ACTIONS;\n\n // --- copy agent context ---\n const copyBtn = document.createElement(\"button\");\n copyBtn.type = \"button\";\n copyBtn.className = CLASSES.INBOX_ACTION_BTN;\n copyBtn.dataset.action = \"copy\";\n copyBtn.dataset.hdTooltip = strings.copyAgentContext;\n copyBtn.setAttribute(\"aria-label\", strings.copyAgentContext);\n copyBtn.innerHTML = COPY_ICON_SVG;\n copyBtn.addEventListener(\"click\", (e) => {\n e.stopPropagation();\n onCopy(comment);\n copyBtn.innerHTML = CHECK_ICON_SVG;\n copyBtn.dataset.hdTooltip = strings.copied;\n setTimeout(() => {\n copyBtn.innerHTML = COPY_ICON_SVG;\n copyBtn.dataset.hdTooltip = strings.copyAgentContext;\n }, 1500);\n });\n actions.appendChild(copyBtn);\n\n // --- lifecycle status picker (RF09) ---\n actions.appendChild(\n createPicker({\n action: \"status\",\n options: STATUSES,\n value: comment.status || \"open\",\n colorOf: (status) => STATUS_COLORS[status] || \"\",\n labelOf: (status) => statusLabelOf(status, strings),\n tooltipLabel: strings.statusLabel,\n onSelect: (status) => onSetStatus(comment, status),\n })\n );\n\n // --- category picker (RF3) ---\n actions.appendChild(\n createPicker({\n action: \"type\",\n // `null` first: returning to the neutral state must be reachable.\n options: [null, ...COMMENT_TYPES],\n value: comment.type || null,\n colorOf: (type) => TYPE_COLORS[type] || \"transparent\",\n labelOf: (type) => typeLabelOf(type, strings),\n tooltipLabel: strings.typeLabel,\n onSelect: (type) => onSetType?.(comment, type),\n showLabel: true,\n })\n );\n\n // --- priority picker (RF4) ---\n actions.appendChild(\n createPicker({\n action: \"priority\",\n options: [null, ...PRIORITIES],\n value: comment.priority || null,\n colorOf: (priority) => PRIORITY_COLORS[priority] || \"transparent\",\n labelOf: (priority) => priorityLabelOf(priority, strings),\n tooltipLabel: strings.priorityLabel,\n onSelect: (priority) => onSetPriority?.(comment, priority),\n showLabel: true,\n })\n );\n\n // --- more (\u22EF) menu ---\n const menuWrapper = document.createElement(\"div\");\n menuWrapper.style.position = \"relative\";\n\n const menuBtn = document.createElement(\"button\");\n menuBtn.type = \"button\";\n menuBtn.className = CLASSES.INBOX_ACTION_BTN;\n menuBtn.dataset.action = \"menu\";\n menuBtn.dataset.hdTooltip = strings.moreOptions;\n menuBtn.setAttribute(\"aria-label\", strings.commentOptions);\n menuBtn.innerHTML = DOTS_ICON_SVG;\n\n const menu = document.createElement(\"div\");\n menu.className = CLASSES.INBOX_MENU;\n menu.style.display = \"none\";\n\n const deleteItem = document.createElement(\"button\");\n deleteItem.type = \"button\";\n deleteItem.className = CLASSES.INBOX_MENU_ITEM;\n deleteItem.textContent = strings.deleteComment;\n deleteItem.addEventListener(\"click\", (e) => {\n e.stopPropagation();\n menu.style.display = \"none\";\n onDelete(comment);\n });\n menu.appendChild(deleteItem);\n\n menuBtn.addEventListener(\"click\", (e) => {\n e.stopPropagation();\n menu.style.display = menu.style.display === \"none\" ? \"block\" : \"none\";\n });\n\n menuWrapper.appendChild(menuBtn);\n menuWrapper.appendChild(menu);\n actions.appendChild(menuWrapper);\n\n return actions;\n};\n", "import {\n CLASSES,\n IDS,\n COMMENT_TYPES,\n TYPE_COLORS,\n PRIORITIES,\n PRIORITY_COLORS,\n} from \"./constants.js\";\nimport { formatTemplate } from \"./i18n.js\";\nimport defaultStrings from \"./locales/en.js\";\nimport {\n createPicker,\n typeLabelOf,\n priorityLabelOf,\n} from \"./comment-actions.js\";\n\nconst formatRelativeTime = (date, strings) => {\n const diff = Date.now() - new Date(date).getTime();\n const minutes = Math.floor(diff / 60000);\n const hours = Math.floor(diff / 3600000);\n const days = Math.floor(diff / 86400000);\n\n if (minutes < 1) return strings.justNow;\n if (minutes < 60) return formatTemplate(strings.minutesAgoTemplate, minutes);\n if (hours < 24) return formatTemplate(strings.hoursAgoTemplate, hours);\n return formatTemplate(strings.daysAgoTemplate, days);\n};\n\nconst formatFullDate = (date, locale) => {\n return new Intl.DateTimeFormat(locale, {\n month: \"short\",\n day: \"numeric\",\n hour: \"numeric\",\n minute: \"2-digit\",\n }).format(new Date(date));\n};\n\nexport const createMetaElement = (author, createdAt, strings, locale) => {\n const meta = document.createElement(\"div\");\n meta.className = CLASSES.THREAD_META;\n\n const authorEl = document.createElement(\"span\");\n authorEl.className = CLASSES.THREAD_AUTHOR;\n authorEl.textContent = author || strings.anonymous;\n\n const timeEl = document.createElement(\"span\");\n timeEl.className = CLASSES.THREAD_TIME;\n timeEl.textContent = formatRelativeTime(createdAt, strings);\n timeEl.dataset.fullDate = formatFullDate(createdAt, locale);\n\n meta.appendChild(authorEl);\n meta.appendChild(timeEl);\n\n return meta;\n};\n\nconst getShortcutText = (options, strings) => {\n const isMac = /Mac|iPod|iPhone|iPad/.test(navigator.userAgent);\n const modifierMap = {\n alt: isMac ? \"\u2325\" : strings.modifierAlt,\n ctrl: isMac ? \"\u2318\" : strings.modifierCtrl,\n shift: \"\u21E7\",\n };\n\n const modifier = modifierMap[options.shortcutModifier] || modifierMap.alt;\n const key = options.shortcutKey?.toUpperCase() || \"C\";\n\n return `${modifier} + ${key}`;\n};\n\nconst ATTACH_ICON_SVG = `<svg width=\"16\" height=\"16\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"2\" stroke-linecap=\"round\" stroke-linejoin=\"round\"><rect x=\"3\" y=\"3\" width=\"18\" height=\"18\" rx=\"2\" ry=\"2\"/><circle cx=\"8.5\" cy=\"8.5\" r=\"1.5\"/><polyline points=\"21 15 16 10 5 21\"/></svg>`;\n\nconst SEND_ICON_SVG = `<svg width=\"16\" height=\"16\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"2\"><path d=\"M22 2L11 13M22 2L15 22L11 13M11 13L2 9L22 2\"/></svg>`;\n\nconst COMMENT_BUBBLE_SVG = `<svg width=\"16\" height=\"16\" viewBox=\"0 0 16 16\" stroke-linejoin=\"round\" fill=\"currentColor\"><path fill-rule=\"evenodd\" clip-rule=\"evenodd\" d=\"M2.8914 10.4028L2.98327 10.6318C3.22909 11.2445 3.5 12.1045 3.5 13C3.5 13.3588 3.4564 13.7131 3.38773 14.0495C3.69637 13.9446 4.01409 13.8159 4.32918 13.6584C4.87888 13.3835 5.33961 13.0611 5.70994 12.7521L6.22471 12.3226L6.88809 12.4196C7.24851 12.4724 7.61994 12.5 8 12.5C11.7843 12.5 14.5 9.85569 14.5 7C14.5 4.14431 11.7843 1.5 8 1.5C4.21574 1.5 1.5 4.14431 1.5 7C1.5 8.18175 1.94229 9.29322 2.73103 10.2153L2.8914 10.4028ZM2.8135 15.7653C1.76096 16 1 16 1 16C1 16 1.43322 15.3097 1.72937 14.4367C1.88317 13.9834 2 13.4808 2 13C2 12.3826 1.80733 11.7292 1.59114 11.1903C0.591845 10.0221 0 8.57152 0 7C0 3.13401 3.58172 0 8 0C12.4183 0 16 3.13401 16 7C16 10.866 12.4183 14 8 14C7.54721 14 7.10321 13.9671 6.67094 13.9038C6.22579 14.2753 5.66881 14.6656 5 15C4.23366 15.3832 3.46733 15.6195 2.8135 15.7653Z\"/></svg>`;\n\nconst MENU_ICON_SVG = `<svg width=\"16\" height=\"16\" viewBox=\"0 0 16 16\" stroke-linejoin=\"round\" fill=\"currentColor\"><path fill-rule=\"evenodd\" clip-rule=\"evenodd\" d=\"M1.67705 7.5L3.92705 3H12.0729L14.3229 7.5H10H9.25V8.25C9.25 8.94036 8.69036 9.5 8 9.5C7.30964 9.5 6.75 8.94036 6.75 8.25V7.5H6H1.67705ZM1.5 9V12C1.5 12.5523 1.94772 13 2.5 13H13.5C14.0523 13 14.5 12.5523 14.5 12V9H10.6465C10.32 10.1543 9.25878 11 8 11C6.74122 11 5.67998 10.1543 5.35352 9H1.5ZM3 1.5H13L15.8944 7.28885C15.9639 7.42771 16 7.58082 16 7.73607V12C16 13.3807 14.8807 14.5 13.5 14.5H2.5C1.11929 14.5 0 13.3807 0 12V7.73607C0 7.58082 0.0361451 7.42771 0.105573 7.28885L3 1.5Z\"/></svg>`;\n\n/**\n * Shared input area component used by both the comment box and the thread popover.\n * Returns the container element and references to key child elements.\n * @param {Object} options\n * @param {string} options.areaClassName\n * @param {\"textarea\" | \"input\"} [options.inputTag]\n * @param {string} [options.inputClassName]\n * @param {string} [options.inputId]\n * @param {string} options.inputPlaceholder\n * @param {string} [options.submitBtnId]\n * @param {string} [options.fileInputId]\n * @param {typeof defaultStrings} strings\n */\nexport const createInputArea = (\n {\n areaClassName,\n inputTag = \"textarea\",\n inputClassName,\n inputId,\n inputPlaceholder,\n submitBtnId,\n fileInputId,\n },\n strings\n) => {\n const container = document.createElement(\"div\");\n container.className = areaClassName;\n\n /** @type {HTMLInputElement | HTMLTextAreaElement} */\n const inputEl = document.createElement(inputTag);\n if (inputId) inputEl.id = inputId;\n if (inputClassName) inputEl.className = inputClassName;\n inputEl.placeholder = inputPlaceholder;\n inputEl.setAttribute(\"aria-label\", inputPlaceholder);\n if (inputTag === \"input\")\n /** @type {HTMLInputElement} */ (inputEl).type = \"text\";\n\n const screenshotsContainer = document.createElement(\"div\");\n screenshotsContainer.className = CLASSES.SCREENSHOTS_CONTAINER;\n\n const actionsBar = document.createElement(\"div\");\n actionsBar.className = CLASSES.COMMENT_ACTIONS_BAR;\n\n const attachBtn = document.createElement(\"button\");\n attachBtn.className = CLASSES.ATTACH_IMAGE_BTN;\n attachBtn.type = \"button\";\n attachBtn.setAttribute(\"aria-label\", strings.attachImage);\n attachBtn.innerHTML = ATTACH_ICON_SVG;\n\n const fileInput = document.createElement(\"input\");\n fileInput.type = \"file\";\n if (fileInputId) fileInput.id = fileInputId;\n fileInput.accept = \"image/*\";\n fileInput.style.display = \"none\";\n\n const submitBtn = document.createElement(\"button\");\n if (submitBtnId) submitBtn.id = submitBtnId;\n submitBtn.className = CLASSES.THREAD_SUBMIT;\n submitBtn.type = \"button\";\n submitBtn.setAttribute(\"aria-label\", strings.send);\n submitBtn.innerHTML = SEND_ICON_SVG;\n\n actionsBar.appendChild(attachBtn);\n actionsBar.appendChild(fileInput);\n actionsBar.appendChild(submitBtn);\n\n container.appendChild(inputEl);\n container.appendChild(screenshotsContainer);\n container.appendChild(actionsBar);\n\n return {\n container,\n inputEl,\n screenshotsContainer,\n attachBtn,\n fileInput,\n submitBtn,\n };\n};\n\nconst createActionWithTooltip = (btnClass, btnSvg, tooltipContent, label) => {\n const wrapper = document.createElement(\"div\");\n wrapper.className = CLASSES.TOOLBAR_ACTION_WRAPPER;\n\n const tooltip = document.createElement(\"div\");\n tooltip.className = CLASSES.TOOLBAR_ACTION_TOOLTIP;\n tooltipContent.forEach((el) => tooltip.appendChild(el));\n\n const btn = document.createElement(\"button\");\n btn.type = \"button\";\n btn.className = `${CLASSES.TOOLBAR_ACTION_BTN} ${btnClass}`;\n btn.setAttribute(\"aria-label\", label);\n btn.innerHTML = btnSvg;\n\n wrapper.appendChild(tooltip);\n wrapper.appendChild(btn);\n return wrapper;\n};\n\nexport const createToolbar = (options = {}, strings = defaultStrings) => {\n const toolbar = document.createElement(\"div\");\n toolbar.id = IDS.TOOLBAR;\n\n const actions = document.createElement(\"div\");\n actions.className = CLASSES.TOOLBAR_ACTIONS;\n\n const commentLabel = document.createElement(\"span\");\n commentLabel.className = CLASSES.TOOLBAR_TEXT;\n commentLabel.textContent = strings.toolbarComment;\n\n const shortcutKey = document.createElement(\"span\");\n shortcutKey.className = CLASSES.SHORTCUT_HINT;\n shortcutKey.textContent = getShortcutText(options, strings);\n\n const commentWrapper = createActionWithTooltip(\n CLASSES.TOOLBAR_COMMENT_BTN,\n COMMENT_BUBBLE_SVG,\n [commentLabel, shortcutKey],\n strings.toolbarComment\n );\n commentWrapper\n .querySelector(`.${CLASSES.TOOLBAR_COMMENT_BTN}`)\n ?.setAttribute(\"aria-pressed\", \"false\");\n\n const inboxLabel = document.createElement(\"span\");\n inboxLabel.className = CLASSES.TOOLBAR_TEXT;\n inboxLabel.textContent = strings.toolbarInbox;\n\n const inboxWrapper = createActionWithTooltip(\n CLASSES.TOOLBAR_MENU_BTN,\n MENU_ICON_SVG,\n [inboxLabel],\n strings.toolbarInbox\n );\n\n actions.appendChild(commentWrapper);\n actions.appendChild(inboxWrapper);\n toolbar.appendChild(actions);\n\n return toolbar;\n};\n\n/**\n * RF3 + RF4 \u2014 the classification strip inside the new-comment box: type,\n * priority and free-form tags, all starting neutral.\n *\n * The comment box is built once and reused for every comment, so this\n * exposes reset(): without it the previous comment's selections would leak\n * into the next one.\n *\n * @param {object} strings\n * @returns {{ container: HTMLElement, getType: () => string|null,\n * getPriority: () => string|null, getTags: () => string[],\n * reset: () => void }}\n */\nexport const createClassifyRow = (strings) => {\n const container = document.createElement(\"div\");\n container.className = CLASSES.CLASSIFY_ROW;\n\n let type = null;\n let priority = null;\n /** @type {string[]} */\n const tags = [];\n\n const chips = document.createElement(\"div\");\n chips.className = CLASSES.INBOX_BADGES;\n\n const input = document.createElement(\"input\");\n input.type = \"text\";\n input.className = CLASSES.TAGS_INPUT;\n input.placeholder = strings.tagsPlaceholder;\n input.setAttribute(\"aria-label\", strings.tagsPlaceholder);\n\n const renderChips = () => {\n chips.innerHTML = \"\";\n tags.forEach((tag, index) => {\n const chip = document.createElement(\"span\");\n chip.className = CLASSES.TAG_CHIP;\n chip.appendChild(document.createTextNode(tag));\n\n const remove = document.createElement(\"button\");\n remove.type = \"button\";\n remove.className = CLASSES.TAG_CHIP_REMOVE;\n remove.setAttribute(\"aria-label\", `${strings.removeTag}: ${tag}`);\n remove.innerHTML = \"×\";\n remove.addEventListener(\"click\", (e) => {\n e.stopPropagation();\n tags.splice(index, 1);\n renderChips();\n });\n\n chip.appendChild(remove);\n chips.appendChild(chip);\n });\n };\n\n // Commits whatever is currently typed (if anything) as a tag. Shared by\n // the Enter/comma keydown handler and getTags(), so text left in the\n // input when the user clicks Send isn't silently discarded.\n const commitPendingTag = () => {\n const tag = input.value.trim().toLowerCase();\n // Blanks and duplicates are silently ignored \u2014 nothing to tell the user.\n if (tag && !tags.includes(tag)) {\n tags.push(tag);\n renderChips();\n }\n input.value = \"\";\n };\n\n input.addEventListener(\"keydown\", (e) => {\n if (e.key !== \"Enter\" && e.key !== \",\") return;\n e.preventDefault();\n commitPendingTag();\n });\n\n // Pickers keep their selection internally, so returning them to neutral\n // means rebuilding them \u2014 hence mount() rather than a one-shot append.\n const mount = () => {\n container.replaceChildren();\n container.appendChild(\n createPicker({\n action: \"type\",\n options: [null, ...COMMENT_TYPES],\n value: null,\n colorOf: (value) => TYPE_COLORS[value] || \"transparent\",\n labelOf: (value) => typeLabelOf(value, strings),\n tooltipLabel: strings.typeLabel,\n onSelect: (value) => (type = value),\n showLabel: true,\n })\n );\n container.appendChild(\n createPicker({\n action: \"priority\",\n options: [null, ...PRIORITIES],\n value: null,\n colorOf: (value) => PRIORITY_COLORS[value] || \"transparent\",\n labelOf: (value) => priorityLabelOf(value, strings),\n tooltipLabel: strings.priorityLabel,\n onSelect: (value) => (priority = value),\n showLabel: true,\n })\n );\n container.appendChild(input);\n container.appendChild(chips);\n };\n\n mount();\n\n return {\n container,\n getType: () => type,\n getPriority: () => priority,\n getTags: () => {\n commitPendingTag();\n return [...tags];\n },\n reset: () => {\n type = null;\n priority = null;\n tags.length = 0;\n input.value = \"\";\n renderChips();\n mount();\n },\n };\n};\n\nexport const createCommentBox = (strings = defaultStrings) => {\n const commentBox = document.createElement(\"div\");\n commentBox.id = IDS.COMMENT_BOX;\n commentBox.setAttribute(\"role\", \"dialog\");\n commentBox.setAttribute(\"aria-label\", strings.commentBoxAriaLabel);\n\n const { container: inputArea } = createInputArea(\n {\n areaClassName: CLASSES.COMMENT_INPUT_AREA,\n inputTag: \"textarea\",\n inputId: IDS.COMMENT_INPUT,\n inputPlaceholder: strings.commentPlaceholder,\n submitBtnId: IDS.SUBMIT_COMMENT,\n fileInputId: IDS.ATTACH_IMAGE_INPUT,\n },\n strings\n );\n\n const classify = createClassifyRow(strings);\n\n commentBox.appendChild(classify.container);\n commentBox.appendChild(inputArea);\n commentBox.style.display = \"none\";\n // Exposed so the overlay can read the selections at save time without\n // re-querying the DOM.\n /** @type {any} */ (commentBox).classify = classify;\n return commentBox;\n};\n\nexport const createCommentCircle = (comment, strings = defaultStrings) => {\n const circle = document.createElement(\"div\");\n circle.className = CLASSES.CIRCLE;\n circle.dataset.commentId = comment.id;\n circle.dataset.commentText = comment.text;\n circle.setAttribute(\"role\", \"button\");\n circle.setAttribute(\"tabindex\", \"0\");\n circle.setAttribute(\n \"aria-label\",\n `${strings.commentAriaLabelPrefix}${comment.text}`\n );\n\n // Basic positioning - will be updated by position validation system\n circle.style.cssText = `\n position: absolute;\n pointer-events: auto;\n `;\n\n return circle;\n};\n\nexport const createScreenshotsDisplay = (screenshots, strings) => {\n const container = document.createElement(\"div\");\n container.className = CLASSES.SCREENSHOTS_CONTAINER;\n container.classList.add(CLASSES.ACTIVE);\n\n screenshots.forEach((src) => {\n const item = document.createElement(\"div\");\n item.className = CLASSES.SCREENSHOT_ITEM;\n\n const img = document.createElement(\"img\");\n img.className = CLASSES.SCREENSHOT_IMG;\n img.src = src;\n img.alt = strings.attachedScreenshot;\n\n item.appendChild(img);\n container.appendChild(item);\n });\n\n return container;\n};\n\nexport const createTooltip = (comment, strings = defaultStrings, locale) => {\n const tooltip = document.createElement(\"div\");\n tooltip.className = CLASSES.TOOLTIP;\n tooltip.dataset.for = comment.id;\n tooltip.setAttribute(\"role\", \"dialog\");\n tooltip.setAttribute(\"aria-label\", strings.tooltipAriaLabel);\n\n const header = document.createElement(\"div\");\n header.className = CLASSES.THREAD_HEADER;\n\n const meta = createMetaElement(\n comment.author,\n comment.createdAt,\n strings,\n locale\n );\n const closeButton = document.createElement(\"button\");\n closeButton.type = \"button\";\n closeButton.className = CLASSES.CLOSE_TOOLTIP;\n closeButton.setAttribute(\"aria-label\", strings.close);\n closeButton.innerHTML = \"×\";\n\n header.appendChild(meta);\n header.appendChild(closeButton);\n\n const body = document.createElement(\"div\");\n body.className = CLASSES.THREAD_BODY;\n body.textContent = comment.text;\n\n tooltip.appendChild(header);\n tooltip.appendChild(body);\n const tooltipScreenshots =\n comment.screenshots || (comment.screenshot ? [comment.screenshot] : []);\n if (tooltipScreenshots.length > 0) {\n tooltip.appendChild(createScreenshotsDisplay(tooltipScreenshots, strings));\n }\n return tooltip;\n};\n\nexport const createReplyElement = (reply, strings = defaultStrings, locale) => {\n const replyEl = document.createElement(\"div\");\n replyEl.className = CLASSES.THREAD_REPLY;\n\n const meta = createMetaElement(\n reply.author,\n reply.timestamp,\n strings,\n locale\n );\n const text = document.createElement(\"div\");\n text.className = CLASSES.THREAD_BODY;\n text.textContent = reply.text;\n\n replyEl.appendChild(meta);\n replyEl.appendChild(text);\n const replyScreenshots =\n reply.screenshots || (reply.screenshot ? [reply.screenshot] : []);\n if (replyScreenshots.length > 0) {\n replyEl.appendChild(createScreenshotsDisplay(replyScreenshots, strings));\n }\n return replyEl;\n};\n\nexport const createThreadPopover = (\n comment,\n strings = defaultStrings,\n locale\n) => {\n const popover = document.createElement(\"div\");\n popover.className = CLASSES.THREAD_POPOVER;\n popover.dataset.for = comment.id;\n popover.setAttribute(\"role\", \"dialog\");\n popover.setAttribute(\"aria-label\", strings.popoverAriaLabel);\n\n const header = document.createElement(\"div\");\n header.className = CLASSES.THREAD_HEADER;\n\n const meta = createMetaElement(\n comment.author,\n comment.createdAt,\n strings,\n locale\n );\n const closeButton = document.createElement(\"button\");\n closeButton.type = \"button\";\n closeButton.className = CLASSES.CLOSE_TOOLTIP;\n closeButton.setAttribute(\"aria-label\", strings.close);\n closeButton.innerHTML = \"×\";\n\n header.appendChild(meta);\n header.appendChild(closeButton);\n\n const body = document.createElement(\"div\");\n body.className = CLASSES.THREAD_BODY;\n body.textContent = comment.text;\n\n const replies = document.createElement(\"div\");\n replies.className = CLASSES.THREAD_REPLIES;\n if (comment.replies) {\n comment.replies.forEach((reply) => {\n replies.appendChild(createReplyElement(reply, strings, locale));\n });\n }\n\n const { container: inputArea } = createInputArea(\n {\n areaClassName: CLASSES.THREAD_INPUT_AREA,\n inputTag: \"input\",\n inputClassName: CLASSES.THREAD_INPUT,\n inputPlaceholder: strings.replyPlaceholder,\n },\n strings\n );\n\n popover.appendChild(header);\n popover.appendChild(body);\n const popoverScreenshots =\n comment.screenshots || (comment.screenshot ? [comment.screenshot] : []);\n if (popoverScreenshots.length > 0) {\n popover.appendChild(createScreenshotsDisplay(popoverScreenshots, strings));\n }\n popover.appendChild(replies);\n popover.appendChild(inputArea);\n\n return popover;\n};\n", "// Builds the plain-text context block the inbox \"copy\" action puts on the\n// clipboard \u2014 enough for a coding agent to locate the element and understand\n// the reported issue (page, viewport, selector, DOM path, thread).\n\nimport { formatDuration } from \"./i18n.js\";\n\nconst openingTagOf = (element) => {\n const attrs = [...element.attributes]\n .map(({ name, value }) => `${name}=\"${value}\"`)\n .join(\" \");\n return `<${element.tagName.toLowerCase()}${attrs ? ` ${attrs}` : \"\"}>`;\n};\n\nconst openingTagFromFingerprint = (fingerprint) => {\n if (!fingerprint?.tagName) return \"(unknown)\";\n const attrs = Object.entries(fingerprint.attributes || {})\n .map(([name, value]) => `${name}=\"${value}\"`)\n .join(\" \");\n return `<${fingerprint.tagName.toLowerCase()}${attrs ? ` ${attrs}` : \"\"}>`;\n};\n\n// body > main.flex.layout > section#pricing.plans \u2014 tag + id + up to two\n// classes per level, from body down to the element.\nconst domPathOf = (element) => {\n const segments = [];\n let current = element;\n while (current && current !== document.documentElement) {\n const tag = current.tagName.toLowerCase();\n const id = current.id ? `#${current.id}` : \"\";\n const classes = [...current.classList]\n .slice(0, 2)\n .map((cls) => `.${cls}`)\n .join(\"\");\n segments.unshift(`${tag}${id}${classes}`);\n if (current === document.body) break;\n current = current.parentElement;\n }\n return segments.join(\" > \");\n};\n\n/**\n * @param {import('./index.d.ts').Comment} comment\n * @param {{ viewportWidth: number, viewportHeight: number, strings?: object }} env\n * @returns {string}\n */\nexport function buildAgentContext(\n comment,\n { viewportWidth, viewportHeight, strings }\n) {\n const anchor = comment.anchor;\n const fingerprint = anchor?.fingerprint;\n const live = comment.container?.isConnected ? comment.container : null;\n\n const state = comment.hidden ? \"hidden\" : comment.anchorState;\n const element = live\n ? openingTagOf(live)\n : openingTagFromFingerprint(fingerprint);\n const path = live ? domPathOf(live) : \"(unavailable)\";\n\n // The reporter's viewport, not the reader's: `comment.context.viewport`\n // was captured at report time (RF2) and travels with the comment. Live\n // `viewportWidth`/`viewportHeight` (the copying browser's window) is only\n // a fallback for legacy records persisted before RF1/RF2 had no context.\n const capturedViewport = comment.context?.viewport;\n const reportedViewportWidth = capturedViewport?.width ?? viewportWidth;\n const reportedViewportHeight = capturedViewport?.height ?? viewportHeight;\n\n const lines = [\n `Page: ${comment.page}`,\n `Viewport: ${reportedViewportWidth}x${reportedViewportHeight}`,\n `Anchor state: ${state}`,\n `Status: ${comment.status || \"open\"}`,\n `Selector: ${anchor?.selector || \"(none)\"}`,\n `Element: ${element}`,\n `DOM path: ${path}`,\n `Nearby text: \"${fingerprint?.textSnippet ?? \"\"}\"`,\n `Comment by ${comment.author} (${comment.createdAt}):`,\n `\"${comment.text}\"`,\n ];\n\n // Neutral classification fields are omitted rather than printed as\n // \"(none)\" \u2014 the agent shouldn't read noise for data nobody filled in.\n if (comment.type) lines.push(`Type: ${comment.type}`);\n if (comment.priority) lines.push(`Priority: ${comment.priority}`);\n if (comment.tags?.length) lines.push(`Tags: ${comment.tags.join(\", \")}`);\n\n const context = comment.context;\n if (context) {\n if (context.url) lines.push(`URL: ${context.url}`);\n if (context.screen) {\n lines.push(`Screen: ${context.screen.width}x${context.screen.height}`);\n }\n if (context.browser?.name) {\n lines.push(\n `Browser: ${`${context.browser.name} ${context.browser.version || \"\"}`.trim()}`\n );\n }\n if (context.os?.name) {\n lines.push(\n `OS: ${`${context.os.name} ${context.os.version || \"\"}`.trim()}`\n );\n }\n }\n\n if (strings && comment.status === \"resolved\" && comment.resolvedAt) {\n const elapsed = formatDuration(\n new Date(comment.resolvedAt).getTime() -\n new Date(comment.createdAt).getTime(),\n strings\n );\n if (elapsed) lines.push(`Resolution time: ${elapsed}`);\n }\n\n const replies = comment.replies || [];\n if (replies.length > 0) {\n lines.push(`Replies (${replies.length}):`);\n for (const reply of replies) {\n lines.push(`- ${reply.author}: \"${reply.text}\"`);\n }\n }\n\n return lines.join(\"\\n\");\n}\n", "// Right-side inbox sidebar: a filterable list of every comment and a detail\n// view with the full thread. Pure view layer \u2014 all data mutations flow back\n// to CommentOverlay through the callbacks contract passed to the\n// constructor, so this module never touches storage or the page markers.\n\nimport {\n CLASSES,\n TYPE_COLORS,\n PRIORITY_COLORS,\n COMMENT_TYPES,\n PRIORITIES,\n} from \"./constants.js\";\nimport { buildAgentContext } from \"./agent-context.js\";\nimport { formatDuration, formatTemplate } from \"./i18n.js\";\nimport {\n createCommentActions,\n copyToClipboard,\n typeLabelOf,\n priorityLabelOf,\n} from \"./comment-actions.js\";\nimport {\n createMetaElement,\n createScreenshotsDisplay,\n createInputArea,\n createReplyElement,\n} from \"./components.js\";\n\nconst CARET_ICON_SVG = `<svg width=\"12\" height=\"12\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"2\" stroke-linecap=\"round\" stroke-linejoin=\"round\"><polyline points=\"6 9 12 15 18 9\"/></svg>`;\nconst CHEVRON_LEFT_SVG = `<svg width=\"14\" height=\"14\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"2\" stroke-linecap=\"round\" stroke-linejoin=\"round\"><polyline points=\"15 18 9 12 15 6\"/></svg>`;\nconst ARROW_UP_SVG = `<svg width=\"14\" height=\"14\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"2\" stroke-linecap=\"round\" stroke-linejoin=\"round\"><polyline points=\"18 15 12 9 6 15\"/></svg>`;\nconst ARROW_DOWN_SVG = `<svg width=\"14\" height=\"14\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"2\" stroke-linecap=\"round\" stroke-linejoin=\"round\"><polyline points=\"6 9 12 15 18 9\"/></svg>`;\n\nexport class InboxView {\n /**\n * @param {Object} deps\n * @param {ShadowRoot} deps.shadowRoot\n * @param {Object} deps.strings\n * @param {string} deps.locale\n * @param {string} deps.currentPage\n * @param {() => Array<Object>} deps.getComments\n * @param {{ onOpenDetailScroll: Function, onReply: Function, onDelete: Function, onSetStatus: Function, onSetType: Function, onSetPriority: Function, onNavigateToPage: Function, onShowLightbox: Function, onClose: Function }} deps.callbacks\n */\n constructor({\n shadowRoot,\n strings,\n locale,\n currentPage,\n getComments,\n callbacks,\n }) {\n this.shadowRoot = shadowRoot;\n this.strings = strings;\n this.locale = locale;\n this.currentPage = currentPage;\n this.getComments = getComments;\n this.callbacks = callbacks;\n this.pageFilter = \"page\"; // \"all\" | \"page\"\n this.statusFilter = \"all\"; // \"all\" | \"unresolved\" | \"resolved\"\n this.typeFilter = \"all\"; // \"all\" | COMMENT_TYPES\n this.priorityFilter = \"all\"; // \"all\" | PRIORITIES\n this.detailId = null;\n /** @type {HTMLElement | null} */\n this.el = null;\n }\n\n isOpen() {\n return Boolean(this.el);\n }\n\n open() {\n if (this.el) return;\n this.el = document.createElement(\"div\");\n this.el.className = CLASSES.INBOX_PANEL;\n this.el.setAttribute(\"role\", \"dialog\");\n this.el.setAttribute(\"aria-label\", this.strings.inboxAriaLabel);\n this.shadowRoot.appendChild(this.el);\n this.render();\n }\n\n close() {\n this._clearHighlight();\n this.el?.remove();\n this.el = null;\n this.detailId = null;\n }\n\n refresh() {\n if (this.el) this.render();\n }\n\n _highlight(comment) {\n this._clearHighlight();\n if (\n comment.anchorState !== \"anchored\" ||\n comment.hidden ||\n comment.status === \"resolved\"\n ) {\n return;\n }\n const circle = this.shadowRoot.querySelector(\n `[data-comment-id=\"${comment.id}\"]`\n );\n if (!circle) return;\n circle.classList.add(CLASSES.HIGHLIGHT);\n this._highlightedEl = circle;\n }\n\n _clearHighlight() {\n this._highlightedEl?.classList.remove(CLASSES.HIGHLIGHT);\n this._highlightedEl = null;\n }\n\n filteredComments() {\n let comments = this.getComments();\n if (this.pageFilter === \"page\") {\n comments = comments.filter(\n (comment) => comment.page === this.currentPage\n );\n }\n if (this.statusFilter === \"resolved\") {\n comments = comments.filter((comment) => comment.status === \"resolved\");\n } else if (this.statusFilter === \"unresolved\") {\n comments = comments.filter((comment) => comment.status !== \"resolved\");\n }\n if (this.typeFilter !== \"all\") {\n comments = comments.filter((comment) => comment.type === this.typeFilter);\n }\n if (this.priorityFilter !== \"all\") {\n comments = comments.filter(\n (comment) => comment.priority === this.priorityFilter\n );\n }\n // Resolved sink to the bottom; both partitions keep their original order.\n return [\n ...comments.filter((comment) => comment.status !== \"resolved\"),\n ...comments.filter((comment) => comment.status === \"resolved\"),\n ];\n }\n\n render() {\n if (!this.el) return;\n this._clearHighlight();\n this.el.innerHTML = \"\";\n const comments = this.filteredComments();\n const detail =\n this.detailId != null\n ? comments.find((comment) => comment.id === this.detailId)\n : null;\n if (detail) {\n this._renderDetail(detail, comments);\n } else {\n this.detailId = null;\n this._renderList(comments);\n }\n }\n\n /**\n * Opens the panel (if needed) directly on a comment's detail. Used by\n * the overlay for the cross-page handoff on startup.\n * @param {number} id\n */\n openDetail(id) {\n if (!this.el) this.open();\n const comment = this.getComments().find((c) => c.id === id);\n if (comment) this._openDetail(comment);\n }\n\n _openDetail(comment) {\n this.detailId = comment.id;\n if (comment.anchorState === \"anchored\" && !comment.hidden) {\n this.callbacks.onOpenDetailScroll(comment);\n }\n this.render();\n }\n\n _closeButton() {\n const btn = document.createElement(\"button\");\n btn.type = \"button\";\n btn.className = CLASSES.INBOX_CLOSE;\n btn.setAttribute(\"aria-label\", this.strings.close);\n btn.innerHTML = \"×\";\n btn.addEventListener(\"click\", () => this.callbacks.onClose());\n return btn;\n }\n\n _renderList(comments) {\n const header = document.createElement(\"div\");\n header.className = CLASSES.INBOX_HEADER;\n header.appendChild(this._buildFilter());\n header.appendChild(this._closeButton());\n this.el.appendChild(header);\n\n const list = document.createElement(\"div\");\n list.className = CLASSES.INBOX_LIST;\n this.el.appendChild(list);\n\n if (comments.length === 0) {\n const empty = document.createElement(\"div\");\n empty.className = CLASSES.INBOX_EMPTY;\n empty.textContent = this.strings.inboxEmpty;\n list.appendChild(empty);\n return;\n }\n\n for (const comment of comments) {\n list.appendChild(this._buildCard(comment, { interactive: true }));\n }\n }\n\n _pageFilterLabel(value) {\n return value === \"all\"\n ? this.strings.filterAll\n : this.strings.filterCurrentPage;\n }\n\n _statusFilterLabel(value) {\n if (value === \"unresolved\") return this.strings.filterUnresolved;\n if (value === \"resolved\") return this.strings.filterResolved;\n return this.strings.filterStatusAll;\n }\n\n /**\n * Summary label for the collapsed filter button. The page filter always\n * contributes (it's either \"All\" or \"Current page\"); status, type, and\n * priority only join in when active, so an active filter is never hidden\n * from a user who hasn't opened the menu.\n */\n _filterSummaryLabel() {\n const parts = [this._pageFilterLabel(this.pageFilter)];\n if (this.statusFilter !== \"all\") {\n parts.push(this._statusFilterLabel(this.statusFilter));\n }\n if (this.typeFilter !== \"all\") {\n parts.push(typeLabelOf(this.typeFilter, this.strings));\n }\n if (this.priorityFilter !== \"all\") {\n parts.push(priorityLabelOf(this.priorityFilter, this.strings));\n }\n return parts.join(\" \u00B7 \");\n }\n\n _buildFilter() {\n const wrapper = document.createElement(\"div\");\n wrapper.className = CLASSES.INBOX_FILTER + \"-wrapper\";\n\n const label = this._filterSummaryLabel();\n\n const btn = document.createElement(\"button\");\n btn.type = \"button\";\n btn.className = CLASSES.INBOX_FILTER;\n btn.setAttribute(\"aria-haspopup\", \"true\");\n btn.setAttribute(\"aria-expanded\", \"false\");\n btn.innerHTML = `<span>${label}</span>${CARET_ICON_SVG}`;\n\n const menu = document.createElement(\"div\");\n menu.className = CLASSES.INBOX_FILTER_MENU;\n menu.style.display = \"none\";\n\n const addSection = (title) => {\n const section = document.createElement(\"div\");\n section.className = CLASSES.INBOX_FILTER_SECTION;\n section.textContent = title;\n menu.appendChild(section);\n };\n\n const addOption = (text, checked, dataAttr, value, onSelect) => {\n const option = document.createElement(\"button\");\n option.type = \"button\";\n option.className = CLASSES.INBOX_FILTER_OPTION;\n option.dataset[dataAttr] = value;\n option.setAttribute(\"role\", \"menuitemradio\");\n option.setAttribute(\"aria-checked\", String(checked));\n option.innerHTML = `<span>${text}</span>${checked ? \"\u2713\" : \"\"}`;\n option.addEventListener(\"click\", (e) => {\n e.stopPropagation();\n onSelect();\n this.render();\n });\n menu.appendChild(option);\n };\n\n addSection(this.strings.filterByPage);\n for (const value of [\"all\", \"page\"]) {\n addOption(\n this._pageFilterLabel(value),\n this.pageFilter === value,\n \"filterPage\",\n value,\n () => (this.pageFilter = value)\n );\n }\n\n addSection(this.strings.filterByStatus);\n for (const value of [\"all\", \"unresolved\", \"resolved\"]) {\n addOption(\n this._statusFilterLabel(value),\n this.statusFilter === value,\n \"filterStatus\",\n value,\n () => (this.statusFilter = value)\n );\n }\n\n addSection(this.strings.filterByType);\n for (const value of [\"all\", ...COMMENT_TYPES]) {\n addOption(\n value === \"all\"\n ? this.strings.filterStatusAll\n : typeLabelOf(value, this.strings),\n this.typeFilter === value,\n \"filterType\",\n value,\n () => (this.typeFilter = value)\n );\n }\n\n addSection(this.strings.filterByPriority);\n for (const value of [\"all\", ...PRIORITIES]) {\n addOption(\n value === \"all\"\n ? this.strings.filterStatusAll\n : priorityLabelOf(value, this.strings),\n this.priorityFilter === value,\n \"filterPriority\",\n value,\n () => (this.priorityFilter = value)\n );\n }\n\n btn.addEventListener(\"click\", (e) => {\n e.stopPropagation();\n const open = menu.style.display !== \"none\";\n menu.style.display = open ? \"none\" : \"block\";\n btn.setAttribute(\"aria-expanded\", String(!open));\n });\n\n wrapper.appendChild(btn);\n wrapper.appendChild(menu);\n return wrapper;\n }\n\n _buildCard(comment, { interactive }) {\n const card = document.createElement(\"div\");\n card.className = CLASSES.INBOX_CARD;\n if (comment.status === \"resolved\") {\n card.classList.add(`${CLASSES.INBOX_CARD}--resolved`);\n }\n card.dataset.commentId = comment.id;\n\n const header = document.createElement(\"div\");\n header.className = CLASSES.INBOX_CARD_HEADER;\n header.appendChild(\n createMetaElement(\n comment.author,\n comment.createdAt,\n this.strings,\n this.locale\n )\n );\n header.appendChild(this._buildCardActions(comment));\n card.appendChild(header);\n\n const text = document.createElement(\"div\");\n text.className = CLASSES.INBOX_CARD_TEXT;\n text.textContent = comment.text;\n card.appendChild(text);\n\n if (comment.screenshots?.length) {\n const shots = createScreenshotsDisplay(comment.screenshots, this.strings);\n shots\n .querySelectorAll(`.${CLASSES.SCREENSHOT_IMG}`)\n .forEach((/** @type {HTMLImageElement} */ img) => {\n img.addEventListener(\"click\", (e) => {\n e.stopPropagation();\n this.callbacks.onShowLightbox(img.src);\n });\n });\n card.appendChild(shots);\n }\n\n const badges = this._buildBadges(comment);\n if (badges) card.appendChild(badges);\n\n const tag = this._buildTag(comment);\n if (tag) card.appendChild(tag);\n\n if (interactive) {\n card.setAttribute(\"role\", \"button\");\n card.setAttribute(\"tabindex\", \"0\");\n\n // Inactive comments belong to another page: activating them hands\n // off to that page (the detail opens there after the redirect).\n const activate = () =>\n comment.anchorState === \"inactive\"\n ? this.callbacks.onNavigateToPage(comment)\n : this._openDetail(comment);\n\n const replyLink = document.createElement(\"button\");\n replyLink.type = \"button\";\n replyLink.className = CLASSES.INBOX_CARD_REPLY_LINK;\n replyLink.textContent = this.strings.replyLink;\n replyLink.addEventListener(\"click\", (e) => {\n e.stopPropagation();\n activate();\n });\n card.appendChild(replyLink);\n\n card.addEventListener(\"click\", activate);\n card.addEventListener(\"keydown\", (/** @type {KeyboardEvent} */ e) => {\n if (e.key === \"Enter\" || e.key === \" \") {\n e.preventDefault();\n activate();\n }\n });\n\n // Hovering a card spotlights its marker on the page \u2014 only when the\n // marker is actually there (anchored, visible, not resolved).\n card.addEventListener(\"mouseenter\", () => this._highlight(comment));\n card.addEventListener(\"mouseleave\", () => this._clearHighlight());\n }\n\n return card;\n }\n\n _buildTag(comment) {\n let label = null;\n if (comment.anchorState === \"orphaned\") label = this.strings.orphanedBadge;\n else if (comment.hidden) label = this.strings.hiddenBadge;\n else if (comment.anchorState === \"inactive\") label = comment.page;\n if (!label) return null;\n\n const tag = document.createElement(\"span\");\n tag.className = CLASSES.INBOX_CARD_TAG;\n tag.textContent = label;\n return tag;\n }\n\n /**\n * RF3/RF4/RF5 \u2014 classification and resolution-time badges. Every badge\n * carries text: colour alone must never be the only signal (WCAG 1.4.1).\n * @param {any} comment\n * @returns {HTMLElement | null} null when there's nothing to show\n */\n _buildBadges(comment) {\n const row = document.createElement(\"div\");\n row.className = CLASSES.INBOX_BADGES;\n\n const addBadge = (text, modifier, color) => {\n const badge = document.createElement(\"span\");\n badge.className = `${CLASSES.BADGE} ${modifier}`;\n badge.textContent = text;\n if (color) badge.style.borderColor = color;\n row.appendChild(badge);\n };\n\n if (comment.type) {\n addBadge(\n typeLabelOf(comment.type, this.strings),\n CLASSES.BADGE_TYPE,\n TYPE_COLORS[comment.type]\n );\n }\n if (comment.priority) {\n addBadge(\n priorityLabelOf(comment.priority, this.strings),\n CLASSES.BADGE_PRIORITY,\n PRIORITY_COLORS[comment.priority]\n );\n }\n for (const tag of comment.tags || []) {\n addBadge(tag, CLASSES.BADGE_TAG, null);\n }\n\n if (comment.status === \"resolved\") {\n // Comments resolved before RF5 shipped have no timestamp \u2014 show a\n // dash rather than a duration computed from data we don't have.\n const elapsed = comment.resolvedAt\n ? formatDuration(\n new Date(comment.resolvedAt).getTime() -\n new Date(comment.createdAt).getTime(),\n this.strings\n )\n : \"\";\n addBadge(\n formatTemplate(this.strings.resolvedInTemplate, elapsed || \"\u2014\"),\n CLASSES.BADGE_DURATION,\n null\n );\n }\n\n return row.children.length ? row : null;\n }\n\n /**\n * RF2 \u2014 the environment the comment was reported from, plus the\n * automatic capture. Returns null for comments created before RF1/RF2.\n * @param {any} comment\n * @returns {HTMLElement | null}\n */\n _buildContextBlock(comment) {\n const { context, contextScreenshot } = comment;\n if (!context && !contextScreenshot) return null;\n\n const block = document.createElement(\"div\");\n block.className = CLASSES.CONTEXT_BLOCK;\n\n const title = document.createElement(\"div\");\n title.className = CLASSES.INBOX_FILTER_SECTION;\n title.textContent = this.strings.contextSection;\n block.appendChild(title);\n\n if (contextScreenshot) {\n const caption = document.createElement(\"div\");\n caption.className = CLASSES.CONTEXT_SCREENSHOT_CAPTION;\n caption.textContent = this.strings.autoScreenshotLabel;\n block.appendChild(caption);\n\n const img = document.createElement(\"img\");\n img.className = CLASSES.SCREENSHOT_IMG;\n img.src = contextScreenshot;\n img.alt = this.strings.autoScreenshotLabel;\n img.addEventListener(\"click\", (e) => {\n e.stopPropagation();\n this.callbacks.onShowLightbox(contextScreenshot);\n });\n block.appendChild(img);\n }\n\n if (context) {\n const addRow = (label, value) => {\n if (!value) return;\n const row = document.createElement(\"div\");\n row.className = CLASSES.CONTEXT_ROW;\n const key = document.createElement(\"span\");\n key.textContent = label;\n const val = document.createElement(\"span\");\n val.textContent = value;\n row.appendChild(key);\n row.appendChild(val);\n block.appendChild(row);\n };\n\n const size = (dimensions) =>\n dimensions ? `${dimensions.width}\u00D7${dimensions.height}` : \"\";\n const named = (entry) =>\n entry?.name ? `${entry.name} ${entry.version || \"\"}`.trim() : \"\";\n\n addRow(this.strings.contextUrl, context.url);\n addRow(this.strings.contextViewport, size(context.viewport));\n addRow(this.strings.contextScreen, size(context.screen));\n addRow(this.strings.contextBrowser, named(context.browser));\n addRow(this.strings.contextOs, named(context.os));\n }\n\n return block;\n }\n\n _buildCardActions(comment) {\n return createCommentActions(comment, {\n strings: this.strings,\n onCopy: (c) =>\n copyToClipboard(\n buildAgentContext(c, {\n viewportWidth: window.innerWidth,\n viewportHeight: window.innerHeight,\n strings: this.strings,\n })\n ),\n onSetStatus: (c, status) => this.callbacks.onSetStatus(c.id, status),\n onSetType: (c, type) => this.callbacks.onSetType(c.id, type),\n onSetPriority: (c, priority) =>\n this.callbacks.onSetPriority(c.id, priority),\n onDelete: (c) => {\n if (this.detailId === c.id) this.detailId = null;\n this.callbacks.onDelete(c.id);\n this.render();\n },\n });\n }\n\n _renderDetail(comment, comments) {\n const index = comments.indexOf(comment);\n\n const header = document.createElement(\"div\");\n header.className = CLASSES.INBOX_DETAIL_HEADER;\n\n const backBtn = document.createElement(\"button\");\n backBtn.type = \"button\";\n backBtn.className = CLASSES.INBOX_BACK;\n backBtn.innerHTML = `${CHEVRON_LEFT_SVG}<span>${this.strings.back}</span>`;\n backBtn.addEventListener(\"click\", () => {\n this.detailId = null;\n this.render();\n });\n header.appendChild(backBtn);\n\n const nav = document.createElement(\"div\");\n nav.className = CLASSES.INBOX_CARD_ACTIONS;\n\n const navBtn = (svg, label, targetIndex) => {\n const btn = document.createElement(\"button\");\n btn.type = \"button\";\n btn.className = CLASSES.INBOX_NAV_BTN;\n btn.setAttribute(\"aria-label\", label);\n btn.title = label;\n btn.innerHTML = svg;\n const target = comments[targetIndex];\n btn.disabled = !target;\n if (target) {\n btn.addEventListener(\"click\", () => this._openDetail(target));\n }\n return btn;\n };\n\n nav.appendChild(navBtn(ARROW_UP_SVG, this.strings.prevComment, index - 1));\n nav.appendChild(\n navBtn(ARROW_DOWN_SVG, this.strings.nextComment, index + 1)\n );\n nav.appendChild(this._closeButton());\n header.appendChild(nav);\n\n this.el.appendChild(header);\n\n const detail = document.createElement(\"div\");\n detail.className = CLASSES.INBOX_DETAIL;\n\n detail.appendChild(this._buildCard(comment, { interactive: false }));\n\n const context = this._buildContextBlock(comment);\n if (context) detail.appendChild(context);\n\n const replies = document.createElement(\"div\");\n replies.className = CLASSES.INBOX_REPLIES;\n for (const reply of comment.replies || []) {\n const replyEl = createReplyElement(reply, this.strings, this.locale);\n replyEl\n .querySelectorAll(`.${CLASSES.SCREENSHOT_IMG}`)\n .forEach((/** @type {HTMLImageElement} */ img) => {\n img.addEventListener(\"click\", (e) => {\n e.stopPropagation();\n this.callbacks.onShowLightbox(img.src);\n });\n });\n replies.appendChild(replyEl);\n }\n detail.appendChild(replies);\n\n detail.appendChild(this._buildReplyInput(comment));\n this.el.appendChild(detail);\n }\n\n _buildReplyInput(comment) {\n const {\n container,\n inputEl,\n screenshotsContainer,\n attachBtn,\n fileInput,\n submitBtn,\n } = createInputArea(\n {\n areaClassName: CLASSES.THREAD_INPUT_AREA,\n inputTag: \"input\",\n inputClassName: CLASSES.THREAD_INPUT,\n inputPlaceholder: this.strings.replyPlaceholder,\n },\n this.strings\n );\n\n let pendingScreenshots = [];\n\n const updatePreview = () => {\n screenshotsContainer.innerHTML = \"\";\n screenshotsContainer.classList.toggle(\n CLASSES.ACTIVE,\n pendingScreenshots.length > 0\n );\n pendingScreenshots.forEach((dataUrl, i) => {\n const item = document.createElement(\"div\");\n item.className = CLASSES.SCREENSHOT_ITEM;\n const img = document.createElement(\"img\");\n img.className = CLASSES.SCREENSHOT_IMG;\n img.src = dataUrl;\n img.alt = this.strings.attachedScreenshot;\n img.onclick = () => this.callbacks.onShowLightbox(dataUrl);\n const removeBtn = document.createElement(\"button\");\n removeBtn.type = \"button\";\n removeBtn.className = CLASSES.SCREENSHOT_REMOVE;\n removeBtn.setAttribute(\"aria-label\", this.strings.removeScreenshot);\n removeBtn.innerHTML = \"×\";\n removeBtn.onclick = (e) => {\n e.stopPropagation();\n pendingScreenshots.splice(i, 1);\n updatePreview();\n };\n item.appendChild(img);\n item.appendChild(removeBtn);\n screenshotsContainer.appendChild(item);\n });\n };\n\n attachBtn.addEventListener(\"click\", () => fileInput.click());\n fileInput.addEventListener(\"change\", (e) => {\n const file = /** @type {HTMLInputElement} */ (e.target).files[0];\n if (!file || pendingScreenshots.length >= 5) return;\n const reader = new FileReader();\n reader.onload = (ev) => {\n pendingScreenshots.push(ev.target.result);\n updatePreview();\n };\n reader.readAsDataURL(file);\n fileInput.value = \"\";\n });\n\n const submit = () => {\n const text = inputEl.value.trim();\n if (!text && pendingScreenshots.length === 0) return;\n this.callbacks.onReply(comment, text, [...pendingScreenshots]);\n pendingScreenshots = [];\n this.render();\n };\n\n submitBtn.addEventListener(\"click\", submit);\n inputEl.addEventListener(\"keydown\", (/** @type {KeyboardEvent} */ e) => {\n if (e.key === \"Enter\" && !e.shiftKey) {\n e.preventDefault();\n submit();\n }\n });\n\n return container;\n }\n}\n", "import {\n renderPage,\n cropRegion,\n cropViewport,\n withHiddenOverlay,\n AUTO_SCALE,\n} from \"./capture.js\";\nimport { captureContext } from \"./metadata.js\";\nimport {\n CLASSES,\n IDS,\n SELECTORS,\n STATUSES,\n COMMENT_TYPES,\n PRIORITIES,\n} from \"./constants.js\";\nimport { getStyles, getGlobalStyles } from \"./styles.js\";\nimport { getShadowRoot, TAG_NAME } from \"./root-element.js\";\nimport { getStrings, detectLocale } from \"./i18n.js\";\nimport {\n createAnchor,\n resolveAnchor,\n generateElementSelector,\n} from \"./anchor.js\";\nimport {\n readStoredComments,\n writeStoredComments,\n mergeForStorage,\n PENDING_DETAIL_KEY,\n} from \"./storage.js\";\nimport {\n createToolbar,\n createCommentBox,\n createCommentCircle,\n createTooltip,\n createThreadPopover,\n createReplyElement,\n} from \"./components.js\";\nimport { InboxView } from \"./inbox.js\";\nimport { createCommentActions, copyToClipboard } from \"./comment-actions.js\";\nimport { buildAgentContext } from \"./agent-context.js\";\n\n// Tags are user-typed, so they arrive with stray case and whitespace.\n// Normalising here (rather than at each entry point) is what makes\n// \"Checkout\" and \"checkout \" the same tag for filtering.\nconst normalizeTags = (tags) => {\n const seen = new Set();\n for (const tag of tags) {\n const clean = String(tag).trim().toLowerCase();\n if (clean) seen.add(clean);\n }\n return [...seen];\n};\n\nclass CommentOverlay {\n /**\n * @param {import('./index.d.ts').CommentOverlayOptions} [options]\n */\n constructor(options = {}) {\n this.comments = [];\n this.commentMode = false;\n this.isMac = /Mac|iPod|iPhone|iPad/.test(navigator.userAgent);\n this.options = {\n shortcutKey: options.shortcutKey || (this.isMac ? \"c\" : \"C\"),\n shortcutModifier: options.shortcutModifier || \"alt\",\n autoScreenshot: options.autoScreenshot !== false,\n ...options,\n };\n this.locale = this.options.locale || detectLocale();\n this.strings = getStrings(this.locale);\n\n // Initialize resize observers and position validation\n this.resizeObservers = new Map();\n // Track mutation observers per comment\n this.mutationObservers = new Map();\n this.positionValidationEnabled = true;\n\n // rAF scheduling flag for bulk updates\n this._pendingRaf = null;\n this._pendingContextScreenshot = null;\n\n if (document.readyState === \"loading\") {\n document.addEventListener(\"DOMContentLoaded\", () => this.initOverlay());\n } else {\n this.initOverlay();\n }\n }\n\n initOverlay() {\n // Mount inside a dedicated shadow root so widget styles/markup stay\n // isolated from the host page in both directions.\n this.shadowRoot = getShadowRoot();\n\n // Create and append UI elements\n this.toolbar = createToolbar(this.options, this.strings);\n this.commentBox = createCommentBox(this.strings);\n this.overlay = document.createElement(\"div\");\n this.overlay.className = CLASSES.COMMENT_OVERLAY;\n\n this.shadowRoot.appendChild(this.overlay);\n this.shadowRoot.appendChild(this.toolbar);\n this.shadowRoot.appendChild(this.commentBox);\n\n this.commentBtn = this.toolbar.querySelector(\n `.${CLASSES.TOOLBAR_COMMENT_BTN}`\n );\n this.inboxBtn = this.toolbar.querySelector(`.${CLASSES.TOOLBAR_MENU_BTN}`);\n /** @type {HTMLButtonElement} */\n this.submitButton = /** @type {any} */ (\n this.shadowRoot.getElementById(IDS.SUBMIT_COMMENT)\n );\n /** @type {HTMLTextAreaElement} */\n this.commentInput = /** @type {any} */ (\n this.shadowRoot.getElementById(IDS.COMMENT_INPUT)\n );\n this.attachImageBtn = this.commentBox.querySelector(\n `.${CLASSES.ATTACH_IMAGE_BTN}`\n );\n /** @type {HTMLInputElement} */\n this.attachImageInput = /** @type {any} */ (\n this.shadowRoot.getElementById(IDS.ATTACH_IMAGE_INPUT)\n );\n\n // Bind event listeners\n this.bindEventListeners();\n this.setupKeyboardShortcut();\n this.setupResizeHandlers();\n this.injectStyles();\n\n if (this.options.persistence === \"localStorage\") {\n this.loadComments(readStoredComments());\n this._openPendingDetail();\n }\n }\n\n _navigateTo(url) {\n location.assign(url);\n }\n\n // Cross-page handoff: an inactive card click on the previous page left a\n // comment id in sessionStorage; open the inbox on its detail here.\n _openPendingDetail() {\n let id = null;\n try {\n id = sessionStorage.getItem(PENDING_DETAIL_KEY);\n if (id != null) sessionStorage.removeItem(PENDING_DETAIL_KEY);\n } catch {\n return;\n }\n if (!id) return;\n const comment = this.comments.find((c) => String(c.id) === id);\n if (!comment) return;\n this.showInbox();\n this.inboxView.openDetail(comment.id);\n }\n\n _syncStorage() {\n if (this.options.persistence !== \"localStorage\") return;\n writeStoredComments(\n mergeForStorage(\n readStoredComments(),\n this.serializeComments(),\n location.pathname\n )\n );\n }\n\n bindEventListeners() {\n this.commentBtn.addEventListener(\"click\", () => this.toggleCommentMode());\n this.inboxBtn.addEventListener(\"click\", () => this.toggleInbox());\n this.submitButton.addEventListener(\"click\", () => this.saveComment());\n\n this.commentInput.addEventListener(\"keydown\", (e) => {\n if (e.key === \"Enter\" && !e.shiftKey) {\n e.preventDefault();\n this.saveComment();\n }\n });\n\n this.attachImageBtn.addEventListener(\"click\", () => {\n this.attachImageInput.click();\n });\n\n this.attachImageInput.addEventListener(\"change\", (e) => {\n const file = /** @type {HTMLInputElement} */ (e.target).files[0];\n if (!file) return;\n if (!this._pendingScreenshots) this._pendingScreenshots = [];\n if (this._pendingScreenshots.length >= 5) return;\n\n const reader = new FileReader();\n reader.onload = (ev) => {\n this._pendingScreenshots.push(ev.target.result);\n this._updateScreenshotsPreview();\n };\n reader.readAsDataURL(file);\n this.attachImageInput.value = \"\";\n });\n\n this._handleDocumentClickBound = (e) => this.handleDocumentClick(e);\n document.addEventListener(\"mousedown\", this._handleDocumentClickBound);\n }\n\n setupKeyboardShortcut() {\n // Remove any existing event listeners\n if (this.keydownHandler) {\n document.removeEventListener(\"keydown\", this.keydownHandler);\n }\n\n // Create a new handler with proper binding\n this.keydownHandler = (e) => {\n if (e.key === \"Escape\") {\n if (this._activeLightbox) {\n this.closeLightbox();\n } else if (this.activeThreadPopover) {\n this.closeThreadPopover();\n } else if (this.inboxView?.isOpen()) {\n this.closeInbox();\n } else if (this.commentBox.style.display !== \"none\") {\n this.hideCommentBox();\n this.toggleCommentMode();\n } else if (this.commentMode) {\n this.toggleCommentMode();\n }\n return;\n }\n\n const isMacOptionC =\n this.isMac && e.altKey && (e.key === \"\u00E7\" || e.key === \"\u00C7\");\n const isWindowsAltC =\n !this.isMac && e.altKey && e.key.toLowerCase() === \"c\";\n const isCustomShortcut =\n e.key.toLowerCase() === this.options.shortcutKey.toLowerCase() &&\n ((this.options.shortcutModifier === \"alt\" && e.altKey) ||\n (this.options.shortcutModifier === \"ctrl\" &&\n (e.ctrlKey || e.metaKey)) ||\n (this.options.shortcutModifier === \"shift\" && e.shiftKey));\n\n if (isMacOptionC || isWindowsAltC || isCustomShortcut) {\n e.preventDefault();\n e.stopPropagation();\n this.toggleCommentMode();\n return false;\n }\n };\n\n // Add the event listener\n document.addEventListener(\"keydown\", this.keydownHandler);\n }\n\n handleDocumentClick(e) {\n if (!this.commentMode) return;\n\n // Listener is attached on `document`, outside the shadow boundary, so\n // `e.target` gets retargeted to the shadow host. Use composedPath() to\n // recover the real, deepest target inside the shadow tree.\n const target = e.composedPath()[0] || e.target;\n\n if (\n this.toolbar.contains(target) ||\n target?.closest?.(`.${CLASSES.CIRCLE}`) ||\n target?.closest?.(`.${CLASSES.TOOLTIP}`) ||\n target?.closest?.(`.${CLASSES.THREAD_POPOVER}`) ||\n target?.closest?.(`.${CLASSES.INBOX_PANEL}`) ||\n target?.closest?.(`.${CLASSES.LIGHTBOX}`)\n ) {\n return;\n }\n\n if (this.commentBox.contains(target)) {\n return;\n }\n\n if (this.commentBox.style.display !== \"none\") {\n this.hideCommentBox();\n this.toggleCommentMode();\n return;\n }\n\n if (e.button !== 0) return;\n e.preventDefault();\n\n this._dragStart = { x: e.clientX, y: e.clientY };\n this._isDragging = false;\n\n this._boundDragMove = (ev) => this._onDragMove(ev);\n this._boundDragEnd = (ev) => this._onDragEnd(ev);\n document.addEventListener(\"mousemove\", this._boundDragMove);\n document.addEventListener(\"mouseup\", this._boundDragEnd);\n }\n\n _onDragMove(e) {\n const dx = e.clientX - this._dragStart.x;\n const dy = e.clientY - this._dragStart.y;\n\n if (!this._isDragging && Math.hypot(dx, dy) < 5) return;\n\n this._isDragging = true;\n\n const left = Math.min(this._dragStart.x, e.clientX);\n const top = Math.min(this._dragStart.y, e.clientY);\n const width = Math.abs(dx);\n const height = Math.abs(dy);\n\n if (!this._selectionRect) {\n this._selectionRect = document.createElement(\"div\");\n this._selectionRect.className = CLASSES.SELECTION_RECT;\n this.shadowRoot.appendChild(this._selectionRect);\n }\n\n this._selectionRect.style.left = `${left}px`;\n this._selectionRect.style.top = `${top}px`;\n this._selectionRect.style.width = `${width}px`;\n this._selectionRect.style.height = `${height}px`;\n }\n\n async _onDragEnd(e) {\n document.removeEventListener(\"mousemove\", this._boundDragMove);\n document.removeEventListener(\"mouseup\", this._boundDragEnd);\n\n if (this._isDragging) {\n const left = Math.min(this._dragStart.x, e.clientX);\n const top = Math.min(this._dragStart.y, e.clientY);\n const width = Math.abs(e.clientX - this._dragStart.x);\n const height = Math.abs(e.clientY - this._dragStart.y);\n\n this._selectionRect?.remove();\n this._selectionRect = null;\n\n if (width > 10 && height > 10) {\n try {\n if (!this._pendingScreenshots) this._pendingScreenshots = [];\n // One render feeds both images: the PNG region the user selected\n // and the automatic JPEG context shot.\n const full = await withHiddenOverlay(() => renderPage({ scale: 1 }));\n const dataUrl = cropRegion(full, { left, top, width, height });\n if (dataUrl && this._pendingScreenshots.length < 5) {\n this._pendingScreenshots.push(dataUrl);\n }\n if (this.options.autoScreenshot) {\n this._pendingContextScreenshot = cropViewport(full, {\n sourceScale: 1,\n });\n }\n } catch (err) {\n console.warn(\"Screenshot capture failed:\", err);\n }\n }\n\n await this._placeCommentAtPoint(e.clientX, e.clientY);\n } else {\n await this._placeCommentAtPoint(this._dragStart.x, this._dragStart.y);\n }\n\n this._isDragging = false;\n this._dragStart = null;\n }\n\n async _placeCommentAtPoint(clientX, clientY) {\n // The no-drag path has no render yet. Half scale because the output is\n // half scale anyway \u2014 the render is the expensive part, and it costs\n // ~4x less here than at scale 1.\n if (this.options.autoScreenshot && !this._pendingContextScreenshot) {\n try {\n const full = await withHiddenOverlay(() =>\n renderPage({ scale: AUTO_SCALE })\n );\n this._pendingContextScreenshot = cropViewport(full, {\n sourceScale: AUTO_SCALE,\n });\n } catch (err) {\n console.warn(\"HellDots: automatic screenshot failed\", err);\n this._pendingContextScreenshot = null;\n }\n }\n\n const prevPointerEvents = this.overlay.style.pointerEvents;\n this.overlay.style.pointerEvents = \"none\";\n const underlying = document.elementFromPoint(clientX, clientY);\n this.overlay.style.pointerEvents = prevPointerEvents || \"\";\n\n const container =\n underlying?.closest?.(SELECTORS.CONTAINER) || document.body;\n const containerRect = container.getBoundingClientRect();\n\n // Zero-size containers (display:none, not yet laid out) would make the\n // division blow up to Infinity \u2014 which isn't JSON-serializable either.\n const relativeX =\n containerRect.width > 0\n ? (clientX - containerRect.left) / containerRect.width\n : 0;\n const relativeY =\n containerRect.height > 0\n ? (clientY - containerRect.top) / containerRect.height\n : 0;\n\n const anchor = createAnchor(\n /** @type {HTMLElement} */ (container),\n relativeX,\n relativeY\n );\n // The clicked element can disappear (responsive display:none) while the\n // coarse anchor container stays visible \u2014 track it separately so the\n // marker hides with what the user actually commented on.\n anchor.targetSelector =\n underlying && underlying !== container\n ? generateElementSelector(/** @type {HTMLElement} */ (underlying))\n : null;\n\n this.currentPosition = {\n container,\n relativeX,\n relativeY,\n anchor,\n target: /** @type {HTMLElement} */ (underlying || container),\n };\n\n this.createPreviewCircle(clientX, clientY);\n document.body.classList.remove(CLASSES.COMMENT_CURSOR);\n\n if (this._pendingScreenshots && this._pendingScreenshots.length > 0) {\n this._updateScreenshotsPreview();\n }\n\n this.showCommentBox(clientX, clientY);\n }\n\n _updateScreenshotsPreview() {\n const container = this.commentBox.querySelector(\n `.${CLASSES.SCREENSHOTS_CONTAINER}`\n );\n if (!container) return;\n container.innerHTML = \"\";\n\n if (!this._pendingScreenshots || this._pendingScreenshots.length === 0) {\n container.classList.remove(CLASSES.ACTIVE);\n return;\n }\n\n container.classList.add(CLASSES.ACTIVE);\n\n this._pendingScreenshots.forEach((dataUrl, i) => {\n const item = document.createElement(\"div\");\n item.className = CLASSES.SCREENSHOT_ITEM;\n\n const img = document.createElement(\"img\");\n img.className = CLASSES.SCREENSHOT_IMG;\n img.src = dataUrl;\n img.alt = this.strings.attachedScreenshot;\n img.onclick = () => this.showLightbox(dataUrl);\n\n const removeBtn = document.createElement(\"button\");\n removeBtn.type = \"button\";\n removeBtn.className = CLASSES.SCREENSHOT_REMOVE;\n removeBtn.setAttribute(\"aria-label\", this.strings.removeScreenshot);\n removeBtn.innerHTML = \"×\";\n removeBtn.onclick = (e) => {\n e.stopPropagation();\n this._pendingScreenshots.splice(i, 1);\n this._updateScreenshotsPreview();\n };\n\n item.appendChild(img);\n item.appendChild(removeBtn);\n container.appendChild(item);\n });\n }\n\n _clearScreenshotPreview() {\n this._pendingScreenshots = [];\n const container = this.commentBox.querySelector(\n `.${CLASSES.SCREENSHOTS_CONTAINER}`\n );\n if (container) {\n container.innerHTML = \"\";\n container.classList.remove(CLASSES.ACTIVE);\n }\n }\n\n showCommentBox(x, y) {\n this.commentBox.style.display = \"block\";\n\n const boxWidth = 300;\n const circleBaseSize = 28;\n const circleRadius = circleBaseSize / 2;\n const offset = circleRadius + 10;\n const windowWidth = window.innerWidth;\n const windowHeight = window.innerHeight;\n\n const centerX = x + circleRadius;\n const centerY = y + circleRadius;\n\n let adjustedX = centerX + offset;\n let adjustedY = centerY - circleRadius;\n\n if (adjustedX + boxWidth > windowWidth) {\n adjustedX = centerX - offset - boxWidth;\n }\n adjustedX = Math.max(10, adjustedX);\n\n const boxRect = this.commentBox.getBoundingClientRect();\n if (adjustedY + boxRect.height > windowHeight) {\n adjustedY = windowHeight - boxRect.height - 10;\n }\n adjustedY = Math.max(10, adjustedY);\n\n this.commentBox.style.left = `${adjustedX}px`;\n this.commentBox.style.top = `${adjustedY}px`;\n\n this.commentInput.value = \"\";\n setTimeout(() => this.commentInput.focus(), 50);\n }\n\n hideCommentBox() {\n this.commentBox.style.display = \"none\";\n this.commentInput.style.height = \"auto\";\n this.currentPosition = null;\n this.removePreviewCircle();\n this._clearScreenshotPreview();\n this._pendingContextScreenshot = null;\n /** @type {any} */ (this.commentBox).classify?.reset();\n\n if (this.commentMode) {\n document.body.classList.add(CLASSES.COMMENT_CURSOR);\n }\n }\n\n toggleCommentMode() {\n this.commentMode = !this.commentMode;\n this.commentBtn?.classList.toggle(CLASSES.ACTIVE, this.commentMode);\n this.commentBtn?.setAttribute(\"aria-pressed\", String(this.commentMode));\n this.overlay.classList.toggle(CLASSES.ACTIVE, this.commentMode);\n document.body.classList.toggle(CLASSES.COMMENT_CURSOR, this.commentMode);\n\n if (!this.commentMode) {\n this.hideCommentBox();\n }\n }\n\n saveComment() {\n if (!this.commentInput.value.trim() || !this.currentPosition) return;\n\n const comment = {\n text: this.commentInput.value,\n container: this.currentPosition.container,\n relativeX: this.currentPosition.relativeX,\n relativeY: this.currentPosition.relativeY,\n anchor: this.currentPosition.anchor,\n anchorState: \"anchored\",\n target: this.currentPosition.target,\n hidden: false,\n status: \"open\",\n page: location.pathname,\n id: Date.now(),\n replies: [],\n author: this.options.user?.name || this.strings.anonymous,\n createdAt: new Date().toISOString(),\n screenshots: this._pendingScreenshots\n ? [...this._pendingScreenshots]\n : [],\n type: /** @type {any} */ (this.commentBox).classify?.getType() ?? null,\n priority:\n /** @type {any} */ (this.commentBox).classify?.getPriority() ?? null,\n tags: /** @type {any} */ (this.commentBox).classify?.getTags() ?? [],\n resolvedAt: null,\n context: captureContext(),\n contextScreenshot: this._pendingContextScreenshot,\n };\n\n this.comments.push(comment);\n this._syncStorage();\n this.options.onCommentCreated?.(this._serializeComment(comment));\n this.renderCommentCircle(comment);\n this.hideCommentBox();\n this.toggleCommentMode();\n\n const circle = this.shadowRoot.querySelector(\n `[data-comment-id=\"${comment.id}\"]`\n );\n if (circle) {\n this.showThreadPopover(circle, comment);\n }\n }\n\n renderCommentCircle(comment) {\n const circle = createCommentCircle(comment, this.strings);\n\n circle.addEventListener(\"mouseenter\", () =>\n this.showCommentTooltip(circle, comment)\n );\n circle.addEventListener(\"mouseleave\", () => {\n setTimeout(() => {\n const tooltip = this.shadowRoot.querySelector(\n `.${CLASSES.TOOLTIP}[data-for=\"${comment.id}\"]`\n );\n if (tooltip && !tooltip.matches(\":hover\")) {\n tooltip.remove();\n }\n }, 250);\n });\n\n circle.addEventListener(\"click\", (e) => {\n e.stopPropagation();\n const tooltip = this.shadowRoot.querySelector(\n `.${CLASSES.TOOLTIP}[data-for=\"${comment.id}\"]`\n );\n if (tooltip) tooltip.remove();\n this.showThreadPopover(circle, comment);\n });\n\n // The circle is a <div role=\"button\">, so unlike a real <button> it\n // doesn't get Enter/Space-activates-click for free.\n circle.addEventListener(\"keydown\", (e) => {\n if (e.key === \"Enter\" || e.key === \" \") {\n e.preventDefault();\n circle.click();\n }\n });\n\n this.overlay.appendChild(circle);\n this.updateCommentPosition(comment, circle);\n\n this.createResizeObserver(comment, circle);\n this.createMutationObserver(comment);\n }\n\n showCommentTooltip(circle, comment) {\n const existingPopover = this.shadowRoot.querySelector(\n `.${CLASSES.THREAD_POPOVER}[data-for=\"${comment.id}\"]`\n );\n if (existingPopover) return;\n\n const existingTooltip = this.shadowRoot.querySelector(\n `.${CLASSES.TOOLTIP}[data-for=\"${comment.id}\"]`\n );\n if (existingTooltip) return;\n\n const tooltip = createTooltip(comment, this.strings, this.locale);\n this.shadowRoot.appendChild(tooltip);\n\n tooltip\n .querySelectorAll(`.${CLASSES.SCREENSHOT_IMG}`)\n .forEach((/** @type {HTMLImageElement} */ img) => {\n img.addEventListener(\"click\", (e) => {\n e.stopPropagation();\n this.showLightbox(img.src);\n });\n });\n\n setTimeout(() => {\n this.positionPopoverAtCircle(tooltip, circle);\n }, 10);\n\n tooltip\n .querySelector(`.${CLASSES.CLOSE_TOOLTIP}`)\n .addEventListener(\"click\", (e) => {\n e.stopPropagation();\n tooltip.remove();\n });\n\n tooltip.addEventListener(\"mouseleave\", () => tooltip.remove());\n }\n\n toggleInbox() {\n if (this.inboxView?.isOpen()) {\n this.closeInbox();\n } else {\n this.showInbox();\n }\n }\n\n showInbox() {\n this.closeThreadPopover();\n\n if (!this.inboxView) {\n this.inboxView = new InboxView({\n shadowRoot: this.shadowRoot,\n strings: this.strings,\n locale: this.locale,\n currentPage: location.pathname,\n getComments: () => this.comments,\n callbacks: {\n onOpenDetailScroll: (comment) =>\n comment.container?.scrollIntoView?.({ block: \"center\" }),\n onReply: (comment, text, screenshots) =>\n this.addReply(comment, text, screenshots),\n onDelete: (id) => this.deleteComment(id),\n onSetStatus: (id, status) => this.setCommentStatus(id, status),\n onSetType: (id, type) => this.setCommentType(id, type),\n onSetPriority: (id, priority) =>\n this.setCommentPriority(id, priority),\n onNavigateToPage: (comment) => {\n try {\n sessionStorage.setItem(PENDING_DETAIL_KEY, String(comment.id));\n } catch {}\n this._navigateTo(comment.page);\n },\n onShowLightbox: (src) => this.showLightbox(src),\n onClose: () => this.closeInbox(),\n },\n });\n }\n this.inboxView.open();\n\n setTimeout(() => {\n this._inboxClickHandler = (e) => {\n const target = e.composedPath()[0] || e.target;\n if (\n !this.inboxView.el?.contains(target) &&\n !this.inboxBtn.contains(target)\n ) {\n this.closeInbox();\n }\n };\n document.addEventListener(\"mousedown\", this._inboxClickHandler);\n }, 0);\n }\n\n closeInbox() {\n this.inboxView?.close();\n if (this._inboxClickHandler) {\n document.removeEventListener(\"mousedown\", this._inboxClickHandler);\n this._inboxClickHandler = null;\n }\n }\n\n // `circle` may be null for orphaned comments (opened from the inbox):\n // the popover is centered in the viewport instead of pinned to a marker.\n showThreadPopover(circle, comment) {\n this.closeThreadPopover();\n\n const existingTooltip = this.shadowRoot.querySelector(\n `.${CLASSES.TOOLTIP}[data-for=\"${comment.id}\"]`\n );\n if (existingTooltip) existingTooltip.remove();\n\n const popover = createThreadPopover(comment, this.strings, this.locale);\n this.shadowRoot.appendChild(popover);\n\n // Same action strip as the inbox cards: copy agent context, lifecycle\n // status picker (RF09) and the \u22EF menu.\n const headerEl = popover.querySelector(`.${CLASSES.THREAD_HEADER}`);\n const actionsEl = createCommentActions(comment, {\n strings: this.strings,\n onCopy: (c) =>\n copyToClipboard(\n buildAgentContext(c, {\n viewportWidth: window.innerWidth,\n viewportHeight: window.innerHeight,\n strings: this.strings,\n })\n ),\n onSetStatus: (c, status) => this.setCommentStatus(c.id, status),\n onSetType: (c, type) => this.setCommentType(c.id, type),\n onSetPriority: (c, priority) => this.setCommentPriority(c.id, priority),\n onDelete: (c) => {\n this.closeThreadPopover();\n this.deleteComment(c.id);\n if (this.inboxView?.isOpen()) this.inboxView.refresh();\n },\n });\n headerEl.insertBefore(\n actionsEl,\n headerEl.querySelector(`.${CLASSES.CLOSE_TOOLTIP}`)\n );\n\n const mainScreenshotsContainer = Array.from(popover.children).find(\n (child) => child.classList.contains(CLASSES.SCREENSHOTS_CONTAINER)\n );\n if (mainScreenshotsContainer) {\n mainScreenshotsContainer\n .querySelectorAll(`.${CLASSES.SCREENSHOT_IMG}`)\n .forEach((/** @type {HTMLImageElement} */ img) => {\n img.addEventListener(\"click\", (e) => {\n e.stopPropagation();\n this.showLightbox(img.src);\n });\n });\n }\n\n setTimeout(() => {\n if (circle) {\n this.positionPopoverAtCircle(popover, circle);\n } else {\n this.centerPopover(popover);\n }\n }, 10);\n\n popover\n .querySelector(`.${CLASSES.CLOSE_TOOLTIP}`)\n .addEventListener(\"click\", (e) => {\n e.stopPropagation();\n this.closeThreadPopover();\n });\n\n /** @type {HTMLInputElement} */\n const input = /** @type {any} */ (\n popover.querySelector(`.${CLASSES.THREAD_INPUT}`)\n );\n const submitBtn = popover.querySelector(`.${CLASSES.THREAD_SUBMIT}`);\n const threadAttachBtn = popover.querySelector(\n `.${CLASSES.THREAD_INPUT_AREA} .${CLASSES.ATTACH_IMAGE_BTN}`\n );\n /** @type {HTMLInputElement} */\n const threadFileInput = /** @type {any} */ (\n popover.querySelector(`.${CLASSES.THREAD_INPUT_AREA} input[type=\"file\"]`)\n );\n const threadScreenshotsContainer = popover.querySelector(\n `.${CLASSES.THREAD_INPUT_AREA} .${CLASSES.SCREENSHOTS_CONTAINER}`\n );\n\n let pendingReplyScreenshots = [];\n\n const updateReplyScreenshotsPreview = () => {\n threadScreenshotsContainer.innerHTML = \"\";\n if (pendingReplyScreenshots.length === 0) {\n threadScreenshotsContainer.classList.remove(CLASSES.ACTIVE);\n return;\n }\n threadScreenshotsContainer.classList.add(CLASSES.ACTIVE);\n pendingReplyScreenshots.forEach((dataUrl, i) => {\n const item = document.createElement(\"div\");\n item.className = CLASSES.SCREENSHOT_ITEM;\n\n const img = document.createElement(\"img\");\n img.className = CLASSES.SCREENSHOT_IMG;\n img.src = dataUrl;\n img.alt = this.strings.attachedScreenshot;\n img.onclick = () => this.showLightbox(dataUrl);\n\n const removeBtn = document.createElement(\"button\");\n removeBtn.className = CLASSES.SCREENSHOT_REMOVE;\n removeBtn.innerHTML = \"×\";\n removeBtn.onclick = (e) => {\n e.stopPropagation();\n pendingReplyScreenshots.splice(i, 1);\n updateReplyScreenshotsPreview();\n };\n\n item.appendChild(img);\n item.appendChild(removeBtn);\n threadScreenshotsContainer.appendChild(item);\n });\n };\n\n threadAttachBtn.addEventListener(\"click\", () => {\n threadFileInput.click();\n });\n\n threadFileInput.addEventListener(\"change\", (e) => {\n const file = /** @type {HTMLInputElement} */ (e.target).files[0];\n if (!file) return;\n if (pendingReplyScreenshots.length >= 5) return;\n\n const reader = new FileReader();\n reader.onload = (ev) => {\n pendingReplyScreenshots.push(ev.target.result);\n updateReplyScreenshotsPreview();\n };\n reader.readAsDataURL(file);\n threadFileInput.value = \"\";\n });\n\n const submitReply = () => {\n const text = input.value.trim();\n if (!text && pendingReplyScreenshots.length === 0) return;\n\n const reply = this.addReply(\n comment,\n text,\n pendingReplyScreenshots.length > 0 ? [...pendingReplyScreenshots] : []\n );\n\n const repliesContainer = popover.querySelector(\n `.${CLASSES.THREAD_REPLIES}`\n );\n const replyEl = createReplyElement(reply, this.strings, this.locale);\n repliesContainer.appendChild(replyEl);\n\n replyEl\n .querySelectorAll(`.${CLASSES.SCREENSHOT_IMG}`)\n .forEach((/** @type {HTMLImageElement} */ img) => {\n img.addEventListener(\"click\", (e) => {\n e.stopPropagation();\n this.showLightbox(img.src);\n });\n });\n\n input.value = \"\";\n pendingReplyScreenshots = [];\n updateReplyScreenshotsPreview();\n input.focus();\n };\n\n submitBtn.addEventListener(\"click\", submitReply);\n input.addEventListener(\"keydown\", (e) => {\n if (e.key === \"Enter\" && !e.shiftKey) {\n e.preventDefault();\n submitReply();\n }\n });\n\n this.activeThreadPopover = popover;\n\n setTimeout(() => input.focus(), 50);\n\n setTimeout(() => {\n this._threadClickHandler = (e) => {\n const target = e.composedPath()[0] || e.target;\n if (!popover.contains(target) && !circle?.contains(target)) {\n this.closeThreadPopover();\n }\n };\n document.addEventListener(\"mousedown\", this._threadClickHandler);\n }, 0);\n }\n\n closeThreadPopover() {\n if (this.activeThreadPopover) {\n this.activeThreadPopover.remove();\n this.activeThreadPopover = null;\n }\n if (this._threadClickHandler) {\n document.removeEventListener(\"mousedown\", this._threadClickHandler);\n this._threadClickHandler = null;\n }\n }\n\n showLightbox(imageSrc) {\n this.closeLightbox();\n\n const lightbox = document.createElement(\"div\");\n lightbox.className = CLASSES.LIGHTBOX;\n\n const img = document.createElement(\"img\");\n img.className = CLASSES.LIGHTBOX_IMG;\n img.src = imageSrc;\n img.alt = this.strings.screenshotPreview;\n\n const closeBtn = document.createElement(\"button\");\n closeBtn.type = \"button\";\n closeBtn.className = CLASSES.LIGHTBOX_CLOSE;\n closeBtn.setAttribute(\"aria-label\", this.strings.close);\n closeBtn.innerHTML = \"×\";\n closeBtn.addEventListener(\"click\", () => this.closeLightbox());\n\n lightbox.appendChild(img);\n lightbox.appendChild(closeBtn);\n\n lightbox.addEventListener(\"click\", (e) => {\n if (e.target === lightbox) this.closeLightbox();\n });\n\n this.shadowRoot.appendChild(lightbox);\n this._activeLightbox = lightbox;\n }\n\n closeLightbox() {\n this._activeLightbox?.remove();\n this._activeLightbox = null;\n }\n\n addReply(comment, text, screenshots = []) {\n if (!comment.replies) comment.replies = [];\n const reply = {\n id: Date.now(),\n text,\n author: this.options.user?.name || this.strings.anonymous,\n timestamp: new Date().toISOString(),\n screenshots,\n };\n comment.replies.push(reply);\n this._syncStorage();\n this.options.onReplyAdded?.(\n this._serializeComment(comment),\n this._serializeReply(reply)\n );\n return reply;\n }\n\n _serializeReply({ id, text, author, timestamp, screenshots }) {\n return { id, text, author, timestamp, screenshots: screenshots || [] };\n }\n\n /**\n * Serializable snapshot of one comment: the live `container` element is\n * replaced by its `anchor`. Screenshots (data-URLs) are included \u2014 the\n * localStorage mode and the inbox cards need them.\n */\n _serializeComment(comment) {\n return {\n id: comment.id,\n text: comment.text,\n anchor: comment.anchor || null,\n page: comment.page || location.pathname,\n replies: (comment.replies || []).map((reply) =>\n this._serializeReply(reply)\n ),\n author: comment.author,\n createdAt: comment.createdAt,\n screenshots: comment.screenshots || [],\n status: comment.status || \"open\",\n type: comment.type || null,\n priority: comment.priority || null,\n // Copied rather than referenced: a host mutating serializeComments()\n // output must not be able to reach back into overlay internals.\n tags: comment.tags ? [...comment.tags] : [],\n resolvedAt: comment.resolvedAt || null,\n context: comment.context ? { ...comment.context } : null,\n contextScreenshot: comment.contextScreenshot || null,\n };\n }\n\n /**\n * RF09 \u2014 moves a comment through its lifecycle\n * (open \u2192 in_progress \u2192 resolved \u2192 closed, in any order).\n * @param {number} id\n * @param {import('./index.d.ts').CommentStatus} status\n * @returns {boolean} false when the id or status is unknown\n */\n setCommentStatus(id, status) {\n if (!STATUSES.includes(status)) return false;\n const comment = this.comments.find((c) => c.id === id);\n if (!comment) return false;\n // No-op: picking the status the comment is already in must not re-stamp\n // resolvedAt (that would reset RF5's elapsed time to \"<1m\") or trigger a\n // storage write / inbox refresh / callback for nothing having changed.\n if (comment.status === status) return true;\n comment.status = status;\n // RF5 \u2014 the timestamp always describes the CURRENT resolution: a\n // reopened comment loses it, and resolving again re-stamps it.\n comment.resolvedAt =\n status === \"resolved\" ? new Date().toISOString() : null;\n // Resolving removes the on-page marker; reopening restores it.\n const circle = /** @type {HTMLElement} */ (\n this.shadowRoot?.querySelector(`[data-comment-id=\"${id}\"]`)\n );\n if (circle) this.updateCommentPosition(comment, circle);\n this._syncStorage();\n // Re-render the inbox so the card picks up the new status right away\n // (resolved styling + sink-to-bottom sorting) no matter where the\n // change came from \u2014 card, detail or thread popover.\n if (this.inboxView?.isOpen()) this.inboxView.refresh();\n this.options.onCommentStatusChanged?.(this._serializeComment(comment));\n return true;\n }\n\n /**\n * Shared tail of the classification setters: persist, re-render the\n * inbox if it's showing, and notify the host app.\n * @param {any} comment\n * @returns {true}\n */\n _commitUpdate(comment) {\n this._syncStorage();\n if (this.inboxView?.isOpen()) this.inboxView.refresh();\n this.options.onCommentUpdated?.(this._serializeComment(comment));\n return true;\n }\n\n /**\n * RF3 \u2014 categorises a comment. `null` returns it to the neutral state.\n * @param {number} id\n * @param {import('./index.d.ts').CommentType | null} type\n * @returns {boolean} false when the id or type is unknown\n */\n setCommentType(id, type) {\n if (type !== null && !COMMENT_TYPES.includes(type)) return false;\n const comment = this.comments.find((c) => c.id === id);\n if (!comment) return false;\n comment.type = type;\n return this._commitUpdate(comment);\n }\n\n /**\n * RF4 \u2014 prioritises a comment. `null` returns it to the neutral state.\n * @param {number} id\n * @param {import('./index.d.ts').CommentPriority | null} priority\n * @returns {boolean} false when the id or priority is unknown\n */\n setCommentPriority(id, priority) {\n if (priority !== null && !PRIORITIES.includes(priority)) return false;\n const comment = this.comments.find((c) => c.id === id);\n if (!comment) return false;\n comment.priority = priority;\n return this._commitUpdate(comment);\n }\n\n /**\n * RF3 \u2014 replaces a comment's free-form labels. Values are trimmed,\n * lowercased and de-duplicated.\n * @param {number} id\n * @param {string[]} tags\n * @returns {boolean} false when the id is unknown or tags isn't an array\n */\n setCommentTags(id, tags) {\n if (!Array.isArray(tags)) return false;\n const comment = this.comments.find((c) => c.id === id);\n if (!comment) return false;\n comment.tags = normalizeTags(tags);\n return this._commitUpdate(comment);\n }\n\n /**\n * @returns {import('./index.d.ts').SerializedComment[]}\n */\n serializeComments() {\n return this.comments.map((comment) => this._serializeComment(comment));\n }\n\n /**\n * Removes a comment everywhere: page marker, memory and (when the\n * localStorage mode is on) persisted storage.\n * @param {number} id\n * @returns {boolean} false when the id is unknown\n */\n deleteComment(id) {\n if (!this.comments.some((comment) => comment.id === id)) return false;\n this._removeComment(id);\n if (this.options.persistence === \"localStorage\") {\n // The merge preserves other-page entries missing from memory, which\n // would resurrect a deleted inactive comment \u2014 drop the id explicitly.\n writeStoredComments(\n mergeForStorage(\n readStoredComments().filter((comment) => comment.id !== id),\n this.serializeComments(),\n location.pathname\n )\n );\n }\n this.options.onCommentDeleted?.(id);\n return true;\n }\n\n _removeComment(id) {\n this.cleanupResizeObserver(id);\n if (this.mutationObservers.has(id)) {\n try {\n this.mutationObservers.get(id).disconnect();\n } catch {}\n this.mutationObservers.delete(id);\n }\n this.shadowRoot.querySelector(`[data-comment-id=\"${id}\"]`)?.remove();\n this.comments = this.comments.filter((comment) => comment.id !== id);\n }\n\n /**\n * Restores serialized comments: each anchor is resolved back to a live\n * element (circle re-rendered) or the comment is kept as an orphan \u2014\n * present in the list/inbox but never positioned over the wrong element.\n * Loading the same id again replaces the previous copy (idempotent).\n * @param {import('./index.d.ts').SerializedComment[]} data\n * @returns {{ anchored: number, orphaned: number, inactive: number }}\n */\n loadComments(data) {\n let anchored = 0;\n let orphaned = 0;\n let inactive = 0;\n if (!Array.isArray(data)) return { anchored, orphaned, inactive };\n\n for (const item of data) {\n if (!item || item.id == null || typeof item.text !== \"string\") {\n console.warn(\"HellDots: skipping malformed serialized comment\", item);\n continue;\n }\n this._removeComment(item.id);\n\n const comment = {\n id: item.id,\n text: item.text,\n anchor: item.anchor || null,\n anchorState: \"orphaned\",\n target: null,\n hidden: false,\n page: item.page || location.pathname,\n container: null,\n relativeX: 0,\n relativeY: 0,\n replies: Array.isArray(item.replies) ? [...item.replies] : [],\n author: item.author || this.strings.anonymous,\n createdAt: item.createdAt || new Date().toISOString(),\n screenshots: Array.isArray(item.screenshots)\n ? [...item.screenshots]\n : [],\n // \"closed\" existed briefly and was folded into \"resolved\".\n status:\n /** @type {string} */ (item.status) === \"closed\"\n ? \"resolved\"\n : STATUSES.includes(item.status)\n ? item.status\n : \"open\",\n // Records persisted before RF1-RF5 have none of these \u2014 every\n // reader downstream may assume they exist after this point.\n type: COMMENT_TYPES.includes(item.type) ? item.type : null,\n priority: PRIORITIES.includes(item.priority) ? item.priority : null,\n tags: Array.isArray(item.tags) ? [...item.tags] : [],\n resolvedAt: item.resolvedAt || null,\n context: item.context || null,\n contextScreenshot: item.contextScreenshot || null,\n };\n\n // Comments from other pages aren't broken \u2014 their elements just\n // don't exist here. They stay listed (inbox \"all\" filter) without a\n // marker and without an onAnchorLost false alarm.\n if (item.page && item.page !== location.pathname) {\n comment.anchorState = \"inactive\";\n this.comments.push(comment);\n inactive++;\n continue;\n }\n\n const resolved = item.anchor ? resolveAnchor(item.anchor) : null;\n if (resolved) {\n comment.container = resolved.element;\n comment.relativeX = item.anchor.relativeX;\n comment.relativeY = item.anchor.relativeY;\n comment.anchorState = \"anchored\";\n this.comments.push(comment);\n this.renderCommentCircle(comment);\n anchored++;\n } else {\n this.comments.push(comment);\n orphaned++;\n this.options.onAnchorLost?.(this._serializeComment(comment));\n }\n }\n\n return { anchored, orphaned, inactive };\n }\n\n centerPopover(el) {\n const elRect = el.getBoundingClientRect();\n const x = Math.max(10, (window.innerWidth - (elRect.width || 400)) / 2);\n const y = Math.max(10, (window.innerHeight - elRect.height) / 2);\n el.style.left = `${x}px`;\n el.style.top = `${y}px`;\n }\n\n positionPopoverAtCircle(el, circle) {\n const circleRect = circle.getBoundingClientRect();\n const centerX = circleRect.left + circleRect.width / 2;\n const centerY = circleRect.top + circleRect.height / 2;\n const circleBaseSize = 28;\n const offset = circleBaseSize / 2 + 10;\n\n let x = centerX + offset;\n let y = centerY - circleBaseSize / 2;\n\n if (x + 400 > window.innerWidth) {\n x = centerX - offset - 400;\n }\n x = Math.max(10, x);\n\n const elRect = el.getBoundingClientRect();\n if (y + elRect.height > window.innerHeight) {\n y = window.innerHeight - elRect.height - 10;\n }\n y = Math.max(10, y);\n\n el.style.left = `${x}px`;\n el.style.top = `${y}px`;\n }\n\n createPreviewCircle(x, y) {\n this.removePreviewCircle();\n\n const circle = document.createElement(\"div\");\n circle.className = `${CLASSES.CIRCLE} ${CLASSES.PREVIEW_CIRCLE}`;\n circle.style.position = \"absolute\";\n const circleRadius = 14;\n circle.style.left = `${x + circleRadius}px`;\n circle.style.top = `${y + circleRadius}px`;\n circle.style.transform = \"translate(-50%, -50%)\";\n circle.style.pointerEvents = \"none\";\n\n this.overlay.appendChild(circle);\n this.previewCircle = circle;\n }\n\n removePreviewCircle() {\n this.previewCircle?.remove();\n this.previewCircle = null;\n }\n\n cleanupResizeObserver(commentId) {\n if (this.resizeObservers && this.resizeObservers.has(commentId)) {\n const { circle, observer } = this.resizeObservers.get(commentId);\n if (observer) {\n observer.disconnect();\n }\n if (circle && circle.parentNode) {\n circle.parentNode.removeChild(circle);\n }\n this.resizeObservers.delete(commentId);\n }\n }\n\n /**\n * Validates and recalculates comment position based on container dimensions\n * @param {Object} comment - The comment object with position data\n * @param {HTMLElement} circle - The comment circle element\n * @returns {Object} - Validated position data\n */\n validateAndCalculatePosition(comment, circle) {\n if (!comment.container || !circle) return null;\n\n const containerRect = comment.container.getBoundingClientRect();\n const containerWidth = containerRect.width;\n const containerHeight = containerRect.height;\n\n // Zero size isn't an anomaly: it's what display:none (e.g. responsive\n // media queries) looks like. The caller hides the marker until the\n // element gets its size back.\n if (containerWidth <= 0 || containerHeight <= 0) {\n return null;\n }\n\n // Use simple relative positioning for consistent results\n const absoluteX = comment.relativeX * containerWidth;\n const absoluteY = comment.relativeY * containerHeight;\n\n const circleSize = 28;\n const validatedX = Math.max(\n 0,\n Math.min(absoluteX, containerWidth - circleSize)\n );\n const validatedY = Math.max(\n 0,\n Math.min(absoluteY, containerHeight - circleSize)\n );\n\n // Recalculate relative position for future calculations\n const validatedRelativeX = validatedX / containerWidth;\n const validatedRelativeY = validatedY / containerHeight;\n\n return {\n absoluteX: validatedX,\n absoluteY: validatedY,\n relativeX: validatedRelativeX,\n relativeY: validatedRelativeY,\n containerWidth,\n containerHeight,\n containerLeft: containerRect.left,\n containerTop: containerRect.top,\n };\n }\n\n /**\n * Updates comment circle position based on validated calculations\n * @param {Object} comment - The comment object\n * @param {HTMLElement} circle - The comment circle element\n */\n /**\n * The exact element the user clicked on can vanish (responsive\n * display:none) while its coarse anchor container stays visible. When we\n * have a live target \u2014 or can re-derive one from the serialized\n * targetSelector \u2014 the marker follows ITS visibility too.\n */\n _isAnchorTargetVisible(comment) {\n let target = comment.target;\n if ((!target || !target.isConnected) && comment.anchor?.targetSelector) {\n try {\n target = document.querySelector(comment.anchor.targetSelector);\n } catch {\n target = null;\n }\n comment.target = target || null;\n }\n if (!target || !target.isConnected) return true; // no signal \u2014 assume visible\n const rect = target.getBoundingClientRect();\n return rect.width > 0 && rect.height > 0;\n }\n\n /**\n * A marker floats above the whole page (own shadow host, high z-index),\n * so a host-page modal overlay can never cover it with CSS alone. Hit-test\n * the marker's point instead: if the topmost page element there is\n * unrelated to the comment's anchor (neither ancestor nor descendant),\n * something like a modal backdrop is covering it and the marker should\n * hide with it.\n */\n _isMarkerOccluded(comment, x, y) {\n if (typeof document.elementsFromPoint !== \"function\") return false;\n // Off-viewport points can't be hit-tested; the marker isn't visible\n // there anyway, so keep the current (visible) state.\n if (x < 0 || y < 0 || x >= window.innerWidth || y >= window.innerHeight) {\n return false;\n }\n const stack = document.elementsFromPoint(x, y);\n // Our own shadow host shows up first (the marker itself, toolbar, \u2026).\n const top = stack.find(\n (el) => el.tagName.toLowerCase() !== TAG_NAME.toLowerCase()\n );\n if (!top) return false;\n\n const target = comment.target?.isConnected ? comment.target : null;\n // The precise element the comment was left on (or its subtree /\n // ancestors) is what should be under the marker \u2014 never an occluder.\n if (target && (target.contains(top) || top.contains(target))) {\n return false;\n }\n\n const container = comment.container;\n if (!container?.isConnected) return false;\n // Something entirely unrelated to the anchor sits on top of it.\n if (!container.contains(top) && !top.contains(container)) return true;\n\n // `top` lives inside the anchor container \u2014 usually normal content of\n // the anchored subtree. But broad containers (body, page wrappers) also\n // contain the page's modals, so walk the chain up to the container: if\n // it crosses a modal-looking layer the anchor doesn't belong to, the\n // marker is covered after all.\n if (container.contains(top) && top !== container) {\n for (let el = top; el && el !== container; el = el.parentElement) {\n if (this._looksLikeModalLayer(el, target)) return true;\n }\n }\n return false;\n }\n\n /**\n * Heuristic for \"this element is a modal/backdrop layer\": explicit dialog\n * semantics, or a hit-testable fixed element covering most of the\n * viewport. Elements that contain the comment's own target are the layer\n * the comment lives in, never an occluder.\n */\n _looksLikeModalLayer(el, target) {\n if (target && el.contains(target)) return false;\n if (el.matches?.('dialog, [aria-modal=\"true\"], [role=\"dialog\"]')) {\n return true;\n }\n if (getComputedStyle(el).position !== \"fixed\") return false;\n const rect = el.getBoundingClientRect();\n return (\n rect.width >= window.innerWidth * 0.5 &&\n rect.height >= window.innerHeight * 0.5\n );\n }\n\n // A marker that just went away must not leave its hover tooltip or its\n // open thread popover floating on the page (e.g. above the modal that\n // now covers the marker).\n _dismissMarkerUi(comment) {\n this.shadowRoot\n .querySelector(`.${CLASSES.TOOLTIP}[data-for=\"${comment.id}\"]`)\n ?.remove();\n if (this.activeThreadPopover?.dataset.for === String(comment.id)) {\n this.closeThreadPopover();\n }\n }\n\n updateCommentPosition(comment, circle) {\n // Resolved comments have no on-page marker (RF09). This is not the\n // \"hidden\" state \u2014 the anchor is fine, the issue is just done.\n if (comment.status === \"resolved\") {\n if (circle) circle.style.display = \"none\";\n return;\n }\n\n let positionData = this.validateAndCalculatePosition(comment, circle);\n if (positionData && !this._isAnchorTargetVisible(comment)) {\n positionData = null;\n }\n const wasHidden = comment.hidden === true;\n\n if (!positionData) {\n // Anchor element currently invisible (zero-size container): hide the\n // marker; it comes back automatically when the observers fire again.\n if (circle && comment.container) {\n comment.hidden = true;\n circle.style.display = \"none\";\n this._dismissMarkerUi(comment);\n if (!wasHidden && this.inboxView?.isOpen()) this.inboxView.refresh();\n }\n return;\n }\n\n // Offset so the circle's top-left tip (sharp corner) aligns with the stored position\n const circleRadius = 14;\n const viewportX =\n positionData.containerLeft + positionData.absoluteX + circleRadius;\n const viewportY =\n positionData.containerTop + positionData.absoluteY + circleRadius;\n\n // A host-page modal (or any unrelated overlay) covering the anchor also\n // hides the marker \u2014 it must not float above the modal's backdrop.\n if (this._isMarkerOccluded(comment, viewportX, viewportY)) {\n comment.hidden = true;\n circle.style.display = \"none\";\n this._dismissMarkerUi(comment);\n if (!wasHidden && this.inboxView?.isOpen()) this.inboxView.refresh();\n return;\n }\n\n comment.hidden = false;\n circle.style.display = \"\";\n if (wasHidden && this.inboxView?.isOpen()) this.inboxView.refresh();\n\n circle.style.left = `${viewportX}px`;\n circle.style.top = `${viewportY}px`;\n circle.style.transform = \"translate(-50%, -50%)\";\n circle.style.position = \"absolute\";\n\n comment.relativeX = positionData.relativeX;\n comment.relativeY = positionData.relativeY;\n }\n\n /**\n * Sets up resize observers and window resize handlers\n */\n setupResizeHandlers() {\n // Throttled updater\n this.scheduleUpdatePositions = () => {\n if (this._pendingRaf) return;\n this._pendingRaf = requestAnimationFrame(() => {\n this._pendingRaf = null;\n if (!this.positionValidationEnabled) return;\n this.comments.forEach((comment) => {\n /** @type {HTMLElement} */\n const circle = /** @type {any} */ (\n this.shadowRoot.querySelector(`[data-comment-id=\"${comment.id}\"]`)\n );\n if (circle) this.updateCommentPosition(comment, circle);\n });\n });\n };\n\n // Window resize handler for viewport changes\n this.windowResizeHandler = () => {\n this.scheduleUpdatePositions();\n };\n window.addEventListener(\"resize\", this.windowResizeHandler, {\n passive: true,\n });\n\n // Capture scroll on any scrolling ancestor\n this.scrollHandler = () => {\n this.scheduleUpdatePositions();\n };\n window.addEventListener(\"scroll\", this.scrollHandler, {\n capture: true,\n passive: true,\n });\n\n // Update after resources load (images, fonts)\n this.loadHandler = () => {\n this.scheduleUpdatePositions();\n };\n window.addEventListener(\"load\", this.loadHandler);\n\n // Modals open/close outside any comment's container (backdrops are\n // usually appended to <body> or toggled via style/class), so the\n // per-comment observers never see them. One page-wide observer keeps\n // the occlusion check honest; shadow-root internals don't bubble into\n // it, so our own marker updates can't retrigger it.\n if (window.MutationObserver) {\n this._globalMutationObserver = new MutationObserver(() => {\n this.scheduleUpdatePositions();\n });\n this._globalMutationObserver.observe(document.body, {\n childList: true,\n subtree: true,\n attributes: true,\n attributeFilter: [\"style\", \"class\", \"hidden\", \"open\"],\n });\n }\n }\n\n /**\n * Debug function to log position information\n * @param {Object} comment - The comment object\n * @param {HTMLElement} circle - The comment circle element\n */\n debugPosition(comment, circle) {\n if (!comment || !circle) return;\n\n const containerRect = comment.container.getBoundingClientRect();\n const circleRect = circle.getBoundingClientRect();\n\n // Calculate expected position from relative coordinates\n const expectedX = comment.relativeX * containerRect.width;\n const expectedY = comment.relativeY * containerRect.height;\n\n console.log(\"Position Debug:\", {\n commentId: comment.id,\n relativePosition: { x: comment.relativeX, y: comment.relativeY },\n containerRect: {\n left: containerRect.left,\n top: containerRect.top,\n width: containerRect.width,\n height: containerRect.height,\n },\n circlePosition: {\n left: circleRect.left,\n top: circleRect.top,\n centerX: circleRect.left + circleRect.width / 2,\n centerY: circleRect.top + circleRect.height / 2,\n },\n expectedPosition: {\n x: expectedX,\n y: expectedY,\n },\n offset: {\n x:\n circleRect.left +\n circleRect.width / 2 -\n (containerRect.left + expectedX),\n y:\n circleRect.top +\n circleRect.height / 2 -\n (containerRect.top + expectedY),\n },\n });\n }\n\n /**\n * Creates a ResizeObserver for a specific comment container\n * @param {Object} comment - The comment object\n * @param {HTMLElement} circle - The comment circle element\n */\n createResizeObserver(comment, circle) {\n if (!window.ResizeObserver) {\n console.warn(\n \"ResizeObserver not supported, position validation will be limited\"\n );\n return;\n }\n\n const observer = new ResizeObserver((entries) => {\n if (!this.positionValidationEnabled) return;\n\n for (const entry of entries) {\n // Only update if the container size actually changed\n if (entry.target === comment.container) {\n this.updateCommentPosition(comment, circle);\n }\n }\n });\n\n // Start observing the container\n observer.observe(comment.container);\n\n // Store the observer for cleanup\n this.resizeObservers.set(comment.id, {\n circle,\n observer,\n container: comment.container,\n });\n }\n\n /**\n * Creates a MutationObserver to react to layout-affecting DOM changes\n * @param {Object} comment\n */\n createMutationObserver(comment) {\n if (!window.MutationObserver) return;\n\n // Disconnect existing for this comment if any\n if (this.mutationObservers.has(comment.id)) {\n try {\n this.mutationObservers.get(comment.id).disconnect();\n } catch {}\n this.mutationObservers.delete(comment.id);\n }\n\n const observer = new MutationObserver(() => {\n this.scheduleUpdatePositions();\n });\n\n observer.observe(comment.container, {\n attributes: true,\n attributeFilter: undefined,\n childList: true,\n subtree: true,\n });\n\n this.mutationObservers.set(comment.id, observer);\n }\n\n /**\n * Cleanup method to remove all event listeners and observers\n */\n cleanup() {\n this.closeThreadPopover();\n this.closeInbox();\n this.closeLightbox();\n this.removePreviewCircle();\n this._selectionRect?.remove();\n this._pendingScreenshots = [];\n\n if (this._handleDocumentClickBound) {\n document.removeEventListener(\"mousedown\", this._handleDocumentClickBound);\n }\n\n if (this.windowResizeHandler) {\n window.removeEventListener(\"resize\", this.windowResizeHandler);\n }\n\n if (this.scrollHandler) {\n window.removeEventListener(\"scroll\", this.scrollHandler, {\n capture: true,\n });\n }\n\n if (this.loadHandler) {\n window.removeEventListener(\"load\", this.loadHandler);\n }\n\n if (this._globalMutationObserver) {\n this._globalMutationObserver.disconnect();\n this._globalMutationObserver = null;\n }\n\n // Cleanup all resize observers\n if (this.resizeObservers) {\n this.resizeObservers.forEach(({ observer }) => {\n if (observer) {\n observer.disconnect();\n }\n });\n this.resizeObservers.clear();\n }\n\n // Cleanup mutation observers\n if (this.mutationObservers) {\n this.mutationObservers.forEach((observer) => {\n try {\n observer.disconnect();\n } catch {}\n });\n this.mutationObservers.clear();\n }\n\n // Remove keyboard shortcut handler\n if (this.keydownHandler) {\n document.removeEventListener(\"keydown\", this.keydownHandler);\n }\n\n // Remove DOM elements\n if (this.toolbar && this.toolbar.parentNode) {\n this.toolbar.parentNode.removeChild(this.toolbar);\n }\n if (this.commentBox && this.commentBox.parentNode) {\n this.commentBox.parentNode.removeChild(this.commentBox);\n }\n if (this.overlay && this.overlay.parentNode) {\n this.overlay.parentNode.removeChild(this.overlay);\n }\n\n document.body.classList.remove(CLASSES.COMMENT_CURSOR);\n document.getElementById(IDS.GLOBAL_STYLES)?.remove();\n\n // Remove all comment circles\n this.comments.forEach((comment) => {\n const circle = this.shadowRoot.querySelector(\n `[data-comment-id=\"${comment.id}\"]`\n );\n if (circle && circle.parentNode) {\n circle.parentNode.removeChild(circle);\n }\n });\n }\n\n injectStyles() {\n const existingStyle = this.shadowRoot.getElementById(IDS.STYLES);\n if (existingStyle) {\n existingStyle.remove();\n }\n\n const style = document.createElement(\"style\");\n style.id = IDS.STYLES;\n style.textContent = getStyles();\n this.shadowRoot.appendChild(style);\n\n // A few rules (e.g. the comment-mode cursor on document.body) target\n // the host page itself, which a shadow root's stylesheet can't reach \u2014\n // those live in a separate <style> in document.head instead.\n const existingGlobalStyle = document.getElementById(IDS.GLOBAL_STYLES);\n if (existingGlobalStyle) {\n existingGlobalStyle.remove();\n }\n\n const globalStyle = document.createElement(\"style\");\n globalStyle.id = IDS.GLOBAL_STYLES;\n globalStyle.textContent = getGlobalStyles();\n document.head.appendChild(globalStyle);\n }\n}\n\nexport default CommentOverlay;\n", "import CommentOverlay from \"./overlay.js\";\n\n/**\n * Creates a CommentOverlay.\n *\n * Safe to call before the document is ready: `CommentOverlay`'s constructor\n * already defers its own DOM work to `DOMContentLoaded`, so callers always\n * get a real instance back and never have to branch on `readyState`. An\n * earlier version duplicated that same check here and, while the document\n * was loading, both registered a listener AND returned the uninvoked\n * initializer \u2014 so a caller who invoked it (reasonably, since the type said\n * it might be a function) ended up with two overlays, and the one the\n * listener built had no handle to call `cleanup()` on.\n *\n * @overload\n * @param {import('./index.d.ts').CommentOverlayOptions & { autoInit?: true }} [options]\n * @returns {CommentOverlay}\n */\n/**\n * @overload\n * @param {import('./index.d.ts').CommentOverlayOptions & { autoInit: false }} options\n * @returns {() => CommentOverlay}\n */\n/**\n * @param {import('./index.d.ts').CommentOverlayOptions} [options]\n * @returns {CommentOverlay | (() => CommentOverlay)}\n */\nexport function createCommentOverlay(options = {}) {\n const { autoInit = true, ...overlayOptions } = options;\n const initialize = () => new CommentOverlay(overlayOptions);\n return autoInit ? initialize() : initialize;\n}\n\n// Export the class for advanced usage\nexport { CommentOverlay };\n\n// Export a default instance creator for simple usage\nexport default createCommentOverlay;\n"],
|
|
5
|
+
"mappings": "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",
|
|
6
|
+
"names": ["domToCanvas", "TAG_NAME", "ensureDefined", "getShadowRoot", "host", "AUTO_SCALE", "AUTO_QUALITY", "isUnpainted", "color", "effectiveBackgroundColor", "htmlBg", "bodyBg", "renderPage", "scale", "domToCanvas", "withHiddenOverlay", "fn", "host", "TAG_NAME", "previousDisplay", "cropRegion", "canvas", "left", "top", "width", "height", "out", "ctx", "cropViewport", "sourceScale", "outputScale", "quality", "BROWSERS", "OPERATING_SYSTEMS", "UNKNOWN", "isGreaseBrand", "brand", "matchFirst", "table", "ua", "name", "re", "match", "captureContext", "win", "nav", "uaData", "browser", "b", "os", "CLASSES", "IDS", "STATUSES", "STATUS_COLORS", "COMMENT_TYPES", "TYPE_COLORS", "PRIORITIES", "PRIORITY_COLORS", "SELECTORS", "Z_INDEX", "CURSOR_SVG", "getStyles", "IDS", "Z_INDEX", "CLASSES", "getGlobalStyles", "CURSOR_SVG", "en_default", "es_default", "LOCALES", "en_default", "es_default", "DEFAULT_LOCALE", "detectLocale", "lang", "getStrings", "localeCode", "formatTemplate", "template", "n", "MINUTE_MS", "formatDuration", "ms", "strings", "totalMinutes", "totalHours", "minutes", "hours", "totalDays", "days", "GENERATED_CLASS_PREFIX_RE", "FRAMEWORK_DATA_ATTR_RE", "STABLE_ATTR_NAMES", "SELECTOR_ATTR_NAMES", "escapeCss", "value", "escapeAttrValue", "isUnique", "selector", "doc", "normalizeText", "text", "isStableClass", "cls", "part", "stableClassesOf", "element", "stableAttributes", "attrs", "name", "siblingPosition", "parent", "sameTag", "child", "idSelector", "attributeSelector", "tag", "classPathSelector", "segments", "current", "depth", "classes", "structuralSelector", "rooted", "index", "generateSelector", "generateElementSelector", "createAnchor", "relativeX", "relativeY", "count", "textSimilarity", "a", "b", "tokensA", "tokensB", "common", "token", "attributeSimilarity", "names", "matched", "positionSimilarity", "fingerprint", "delta", "span", "scoreElement", "hasText", "hasAttrs", "textWeight", "attrWeight", "posWeight", "bestMatch", "candidates", "best", "confidence", "resolveAnchor", "anchor", "STORAGE_KEY", "PENDING_DETAIL_KEY", "readStoredComments", "raw", "parsed", "err", "tryWriteStoredComments", "comments", "writeStoredComments", "shedOrder", "comment", "index", "a", "b", "timeA", "timeB", "working", "shed", "mergeForStorage", "stored", "current", "currentPage", "currentIds", "c", "COPY_ICON_SVG", "CHECK_ICON_SVG", "DOTS_ICON_SVG", "copyToClipboard", "text", "textarea", "statusLabelOf", "status", "strings", "typeLabelOf", "type", "priorityLabelOf", "priority", "createPicker", "action", "options", "value", "colorOf", "labelOf", "tooltipLabel", "onSelect", "showLabel", "wrapper", "btn", "CLASSES", "dot", "labelEl", "menu", "current", "syncUi", "label", "item", "raw", "option", "itemDot", "e", "createCommentActions", "comment", "onCopy", "onSetStatus", "onSetType", "onSetPriority", "onDelete", "actions", "copyBtn", "STATUSES", "STATUS_COLORS", "COMMENT_TYPES", "TYPE_COLORS", "PRIORITIES", "PRIORITY_COLORS", "menuWrapper", "menuBtn", "deleteItem", "formatRelativeTime", "date", "strings", "diff", "minutes", "hours", "days", "formatTemplate", "formatFullDate", "locale", "createMetaElement", "author", "createdAt", "meta", "CLASSES", "authorEl", "timeEl", "getShortcutText", "options", "isMac", "modifierMap", "modifier", "key", "ATTACH_ICON_SVG", "SEND_ICON_SVG", "COMMENT_BUBBLE_SVG", "MENU_ICON_SVG", "createInputArea", "areaClassName", "inputTag", "inputClassName", "inputId", "inputPlaceholder", "submitBtnId", "fileInputId", "container", "inputEl", "screenshotsContainer", "actionsBar", "attachBtn", "fileInput", "submitBtn", "createActionWithTooltip", "btnClass", "btnSvg", "tooltipContent", "label", "wrapper", "tooltip", "el", "btn", "createToolbar", "en_default", "toolbar", "IDS", "actions", "commentLabel", "shortcutKey", "commentWrapper", "inboxLabel", "inboxWrapper", "createClassifyRow", "type", "priority", "tags", "chips", "input", "renderChips", "tag", "index", "chip", "remove", "e", "commitPendingTag", "mount", "createPicker", "COMMENT_TYPES", "value", "TYPE_COLORS", "typeLabelOf", "PRIORITIES", "PRIORITY_COLORS", "priorityLabelOf", "createCommentBox", "commentBox", "inputArea", "classify", "createCommentCircle", "comment", "circle", "createScreenshotsDisplay", "screenshots", "src", "item", "img", "createTooltip", "header", "closeButton", "body", "tooltipScreenshots", "createReplyElement", "reply", "replyEl", "text", "replyScreenshots", "createThreadPopover", "popover", "replies", "popoverScreenshots", "openingTagOf", "element", "attrs", "name", "value", "openingTagFromFingerprint", "fingerprint", "domPathOf", "segments", "current", "tag", "id", "classes", "cls", "buildAgentContext", "comment", "viewportWidth", "viewportHeight", "strings", "anchor", "live", "state", "path", "capturedViewport", "reportedViewportWidth", "reportedViewportHeight", "lines", "context", "elapsed", "formatDuration", "replies", "reply", "CARET_ICON_SVG", "CHEVRON_LEFT_SVG", "ARROW_UP_SVG", "ARROW_DOWN_SVG", "InboxView", "shadowRoot", "strings", "locale", "currentPage", "getComments", "callbacks", "CLASSES", "comment", "circle", "comments", "detail", "id", "c", "btn", "header", "list", "empty", "value", "parts", "typeLabelOf", "priorityLabelOf", "wrapper", "label", "menu", "addSection", "title", "section", "addOption", "text", "checked", "dataAttr", "onSelect", "option", "e", "COMMENT_TYPES", "PRIORITIES", "open", "interactive", "card", "createMetaElement", "shots", "createScreenshotsDisplay", "img", "badges", "tag", "activate", "replyLink", "row", "addBadge", "modifier", "color", "badge", "TYPE_COLORS", "PRIORITY_COLORS", "elapsed", "formatDuration", "formatTemplate", "context", "contextScreenshot", "block", "caption", "addRow", "key", "val", "size", "dimensions", "named", "entry", "createCommentActions", "copyToClipboard", "buildAgentContext", "status", "type", "priority", "index", "backBtn", "nav", "navBtn", "svg", "targetIndex", "target", "replies", "reply", "replyEl", "createReplyElement", "container", "inputEl", "screenshotsContainer", "attachBtn", "fileInput", "submitBtn", "createInputArea", "pendingScreenshots", "updatePreview", "dataUrl", "i", "item", "removeBtn", "file", "reader", "ev", "submit", "normalizeTags", "tags", "seen", "tag", "clean", "CommentOverlay", "options", "detectLocale", "getStrings", "getShadowRoot", "createToolbar", "createCommentBox", "CLASSES", "IDS", "readStoredComments", "url", "id", "PENDING_DETAIL_KEY", "comment", "c", "writeStoredComments", "mergeForStorage", "file", "reader", "ev", "isMacOptionC", "isWindowsAltC", "isCustomShortcut", "target", "dx", "dy", "left", "top", "width", "height", "full", "withHiddenOverlay", "renderPage", "dataUrl", "cropRegion", "cropViewport", "err", "clientX", "clientY", "AUTO_SCALE", "prevPointerEvents", "underlying", "container", "SELECTORS", "containerRect", "relativeX", "relativeY", "anchor", "createAnchor", "generateElementSelector", "i", "item", "img", "removeBtn", "e", "x", "y", "boxWidth", "circleRadius", "offset", "windowWidth", "windowHeight", "centerX", "centerY", "adjustedX", "adjustedY", "boxRect", "captureContext", "circle", "createCommentCircle", "tooltip", "createTooltip", "InboxView", "text", "screenshots", "status", "type", "priority", "src", "existingTooltip", "popover", "createThreadPopover", "headerEl", "actionsEl", "createCommentActions", "copyToClipboard", "buildAgentContext", "mainScreenshotsContainer", "child", "input", "submitBtn", "threadAttachBtn", "threadFileInput", "threadScreenshotsContainer", "pendingReplyScreenshots", "updateReplyScreenshotsPreview", "submitReply", "reply", "repliesContainer", "replyEl", "createReplyElement", "imageSrc", "lightbox", "closeBtn", "author", "timestamp", "STATUSES", "COMMENT_TYPES", "PRIORITIES", "data", "anchored", "orphaned", "inactive", "resolved", "resolveAnchor", "el", "elRect", "circleRect", "circleBaseSize", "commentId", "observer", "containerWidth", "containerHeight", "absoluteX", "absoluteY", "circleSize", "validatedX", "validatedY", "validatedRelativeX", "validatedRelativeY", "rect", "TAG_NAME", "positionData", "wasHidden", "viewportX", "viewportY", "expectedX", "expectedY", "entries", "entry", "existingStyle", "style", "getStyles", "existingGlobalStyle", "globalStyle", "getGlobalStyles", "overlay_default", "createCommentOverlay", "options", "autoInit", "overlayOptions", "initialize", "overlay_default", "index_default", "createCommentOverlay"]
|
|
7
|
+
}
|