@mhosaic/feedback 0.6.1 → 0.6.2

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.
@@ -1065,10 +1065,13 @@ function Modal({ onDismiss, children, closeLabel = "Close" }) {
1065
1065
  useEffect3(() => {
1066
1066
  previouslyFocused.current = document.activeElement;
1067
1067
  const onKey = (e) => {
1068
- if (e.key === "Escape") {
1069
- e.stopPropagation();
1070
- onDismiss();
1068
+ if (e.key !== "Escape") return;
1069
+ const root = modalRef.current?.getRootNode();
1070
+ if (root instanceof ShadowRoot && root.querySelector(".annotator-backdrop")) {
1071
+ return;
1071
1072
  }
1073
+ e.stopPropagation();
1074
+ onDismiss();
1072
1075
  };
1073
1076
  window.addEventListener("keydown", onKey);
1074
1077
  const first = modalRef.current?.querySelector(
@@ -1677,4 +1680,4 @@ function createFeedback(config) {
1677
1680
  export {
1678
1681
  createFeedback
1679
1682
  };
1680
- //# sourceMappingURL=chunk-LGGKJPFH.mjs.map
1683
+ //# sourceMappingURL=chunk-KXLX4IGN.mjs.map
@@ -1 +1 @@
1
- {"version":3,"sources":["../src/api/client.ts","../src/capture/urlSanitizer.ts","../src/capture/device.ts","../src/capture/console.ts","../src/capture/network.ts","../src/capture/errors.ts","../src/capture/performance.ts","../src/capture/ringBuffer.ts","../src/capture/index.ts","../src/screenshot/index.ts","../src/widget/i18n.ts","../src/widget/mount.tsx","../src/widget/Fab.tsx","../src/widget/Form.tsx","../src/widget/Annotator.tsx","../src/widget/screenshot-utils.ts","../src/widget/Modal.tsx","../src/widget/styles.ts","../src/core.ts"],"sourcesContent":["import type { ReportPayload, SubmittedReport } from '../types'\n\nexport interface ApiClientOptions {\n apiKey: string\n endpoint: string\n fetch?: typeof fetch\n beforeSend?: (payload: ReportPayload) => ReportPayload | false | Promise<ReportPayload | false>\n}\n\nexport interface ApiClient {\n submitReport(payload: ReportPayload): Promise<SubmittedReport>\n}\n\nconst SCALAR_FIELDS: Array<keyof ReportPayload> = [\n 'description', 'feedback_type', 'severity', 'env', 'page_url', 'user_agent', 'capture_method',\n]\n\nexport function createApiClient(options: ApiClientOptions): ApiClient {\n // No silent fallback to a hardcoded host — a misconfigured deploy used\n // to leak reports to https://core.mhosaic.com (which doesn't even\n // resolve). Failing fast at construction makes the misconfig obvious.\n const endpoint = (options.endpoint ?? '').replace(/\\/+$/, '')\n if (!endpoint) {\n throw new Error(\n '[mhosaic-feedback] `endpoint` is required (e.g. \"https://feedback.example.com\").',\n )\n }\n const fetcher = options.fetch ?? globalThis.fetch\n\n async function submitReport(input: ReportPayload): Promise<SubmittedReport> {\n let payload: ReportPayload | false = input\n if (options.beforeSend) payload = await options.beforeSend(input)\n if (payload === false) throw new Error('Submission cancelled by beforeSend')\n\n const form = new FormData()\n for (const field of SCALAR_FIELDS) {\n form.append(field, String(payload[field]))\n }\n form.append('technical_context', JSON.stringify(payload.technical_context))\n if (payload.screenshot) form.append('screenshot', payload.screenshot, 'screenshot.png')\n // Only emit `synthetic` when truthy — a `false` value would still trigger\n // the BooleanField parser on the backend, which is fine, but omitting it\n // keeps the request shape byte-identical for existing curated submissions.\n if (payload.synthetic) form.append('synthetic', 'true')\n\n const response = await fetcher(`${endpoint}/api/feedback/v1/reports/`, {\n method: 'POST',\n headers: { Authorization: `Bearer ${options.apiKey}` },\n body: form,\n })\n if (!response.ok) {\n const text = await response.text().catch(() => '')\n throw new Error(`Feedback submit failed: ${response.status} ${text}`)\n }\n return response.json() as Promise<SubmittedReport>\n }\n\n return { submitReport }\n}\n","const SENSITIVE = /token|key|password|secret|auth|session|sig/i\n\nexport function sanitizeUrl(url: string): string {\n try {\n // Accept absolute URLs or root-relative paths; reject everything else\n const isAbsolute = /^https?:\\/\\//i.test(url)\n const isRootRelative = url.startsWith('/')\n if (!isAbsolute && !isRootRelative) return url\n\n const base = typeof window !== 'undefined' ? window.location.origin : 'http://localhost'\n const u = new URL(url, base)\n const clean = new URLSearchParams()\n u.searchParams.forEach((value, name) => {\n clean.set(name, SENSITIVE.test(name) ? '[redacted]' : value)\n })\n u.search = clean.toString()\n return u.toString()\n } catch {\n return url\n }\n}\n","import type { DeviceContext } from '../types'\n\nexport function collectDevice(): DeviceContext {\n const nav = navigator as Navigator & { connection?: { effectiveType?: string }; deviceMemory?: number }\n const connection = nav.connection?.effectiveType\n const deviceMemory = nav.deviceMemory\n const referrer = document.referrer || undefined\n return {\n viewport: { w: window.innerWidth, h: window.innerHeight, dpr: window.devicePixelRatio || 1 },\n screen: { w: window.screen.width, h: window.screen.height },\n platform: nav.platform,\n language: nav.language,\n timezone: Intl.DateTimeFormat().resolvedOptions().timeZone,\n timezoneOffset: new Date().getTimezoneOffset(),\n ...(connection !== undefined && { connection }),\n online: nav.onLine,\n ...(deviceMemory !== undefined && { deviceMemory }),\n hardwareConcurrency: nav.hardwareConcurrency,\n ...(referrer !== undefined && { referrer }),\n title: document.title,\n pathname: window.location.pathname,\n }\n}\n","import type { RingBuffer } from './ringBuffer'\nimport type { ConsoleEntry } from '../types'\n\ntype ConsoleLevel = 'log' | 'info' | 'warn' | 'error' | 'debug'\n\nfunction safeStringify(arg: unknown): string {\n if (arg == null) return String(arg)\n if (typeof arg === 'string') return arg\n if (typeof arg === 'number' || typeof arg === 'boolean') return String(arg)\n if (arg instanceof Error) return `${arg.name}: ${arg.message}`\n if (arg instanceof Element) return `<${arg.tagName.toLowerCase()}>`\n try {\n return JSON.stringify(arg, (_k, v) => (typeof v === 'bigint' ? v.toString() : v))\n } catch {\n try { return String(arg) } catch { return '[unserializable]' }\n }\n}\n\nexport function installConsolePatch(buffer: RingBuffer<ConsoleEntry>): () => void {\n const levels: ConsoleLevel[] = ['log', 'info', 'warn', 'error', 'debug']\n const originals: Partial<Record<ConsoleLevel, (...args: unknown[]) => void>> = {}\n for (const level of levels) {\n const original = console[level] as ((...args: unknown[]) => void) | undefined\n if (typeof original !== 'function') continue\n originals[level] = original\n console[level] = function patched(...args: unknown[]) {\n try {\n const message = args.map(safeStringify).join(' ').slice(0, 2000)\n const entry: ConsoleEntry = { level, message, ts: Date.now() }\n if (level === 'error') {\n const stack = new Error().stack\n if (stack) entry.stack = stack.split('\\n').slice(2, 8).join('\\n')\n }\n buffer.push(entry)\n } catch { /* never break console */ }\n original.apply(console, args)\n }\n }\n return () => {\n for (const [level, fn] of Object.entries(originals)) {\n (console as unknown as Record<string, (...args: unknown[]) => void>)[level] = fn\n }\n }\n}\n","import type { RingBuffer } from './ringBuffer'\nimport type { NetworkEntry } from '../types'\n\nexport function installFetchPatch(buffer: RingBuffer<NetworkEntry>, sanitize: (url: string) => string): () => void {\n if (typeof window === 'undefined' || typeof window.fetch !== 'function') return () => {}\n const original = window.fetch.bind(window)\n window.fetch = async function patched(input: RequestInfo | URL, init?: RequestInit) {\n const start = performance.now()\n const url = typeof input === 'string' ? input : input instanceof URL ? input.toString() : input.url\n const method = (init?.method || (input instanceof Request ? input.method : 'GET')).toUpperCase()\n try {\n const response = await original(input, init)\n buffer.push({ url: sanitize(url), method, status: response.status, durationMs: Math.round(performance.now() - start), ts: Date.now() })\n return response\n } catch (err) {\n buffer.push({\n url: sanitize(url), method, status: 0,\n durationMs: Math.round(performance.now() - start),\n ts: Date.now(),\n error: err instanceof Error ? err.message : String(err),\n })\n throw err\n }\n }\n return () => { window.fetch = original }\n}\n\nexport function installXhrPatch(buffer: RingBuffer<NetworkEntry>, sanitize: (url: string) => string): () => void {\n if (typeof window === 'undefined' || typeof window.XMLHttpRequest !== 'function') return () => {}\n const Original = window.XMLHttpRequest\n const originalOpen = Original.prototype.open\n const originalSend = Original.prototype.send\n\n Original.prototype.open = function patchedOpen(this: XMLHttpRequest & { __mfb?: { method: string; url: string; start: number } }, method: string, url: string | URL) {\n this.__mfb = { method: method.toUpperCase(), url: typeof url === 'string' ? url : url.toString(), start: performance.now() }\n return originalOpen.apply(this, arguments as unknown as Parameters<typeof originalOpen>)\n }\n\n Original.prototype.send = function patchedSend(this: XMLHttpRequest & { __mfb?: { method: string; url: string; start: number } }, body?: Document | XMLHttpRequestBodyInit | null) {\n this.addEventListener('loadend', () => {\n try {\n const ctx = this.__mfb\n if (!ctx) return\n buffer.push({\n url: sanitize(ctx.url),\n method: ctx.method,\n status: this.status,\n durationMs: Math.round(performance.now() - ctx.start),\n ts: Date.now(),\n })\n } catch { /* noop */ }\n })\n return originalSend.call(this, body ?? null)\n }\n\n return () => {\n Original.prototype.open = originalOpen\n Original.prototype.send = originalSend\n }\n}\n","import type { RingBuffer } from './ringBuffer'\nimport type { ErrorEntry } from '../types'\n\nexport function installErrorHandlers(buffer: RingBuffer<ErrorEntry>): () => void {\n if (typeof window === 'undefined') return () => {}\n const onError = (e: ErrorEvent) => {\n const stack = e.error instanceof Error ? e.error.stack : undefined\n buffer.push({\n message: e.message || 'Unknown error',\n ...(stack !== undefined && { stack }),\n ts: Date.now(),\n source: 'window.error',\n })\n }\n const onRejection = (e: PromiseRejectionEvent) => {\n const reason = e.reason\n const message =\n reason instanceof Error ? reason.message :\n typeof reason === 'string' ? reason :\n (() => { try { return JSON.stringify(reason) } catch { return String(reason) } })()\n const stack = reason instanceof Error ? reason.stack : undefined\n buffer.push({\n message,\n ...(stack !== undefined && { stack }),\n ts: Date.now(),\n source: 'unhandledrejection',\n })\n }\n window.addEventListener('error', onError)\n window.addEventListener('unhandledrejection', onRejection)\n return () => {\n window.removeEventListener('error', onError)\n window.removeEventListener('unhandledrejection', onRejection)\n }\n}\n","export interface PerformanceSnapshot {\n navigation?: { type: string; duration: number }\n longTasks: { duration: number; startTime: number }[]\n slowResources: { name: string; duration: number; initiatorType: string }[]\n}\n\nexport function createPerformanceCollector(slowResourceMs = 1000) {\n const longTasks: PerformanceSnapshot['longTasks'] = []\n const slowResources: PerformanceSnapshot['slowResources'] = []\n let observer: PerformanceObserver | null = null\n\n if (typeof PerformanceObserver !== 'undefined') {\n try {\n observer = new PerformanceObserver((list) => {\n for (const entry of list.getEntries()) {\n if (entry.entryType === 'longtask') {\n longTasks.push({ duration: entry.duration, startTime: entry.startTime })\n while (longTasks.length > 20) longTasks.shift()\n } else if (entry.entryType === 'resource') {\n const e = entry as PerformanceResourceTiming\n if (e.duration > slowResourceMs) {\n slowResources.push({ name: e.name, duration: e.duration, initiatorType: e.initiatorType })\n while (slowResources.length > 20) slowResources.shift()\n }\n }\n }\n })\n observer.observe({ entryTypes: ['longtask', 'resource'] })\n } catch { /* unsupported */ }\n }\n\n return {\n snapshot(): PerformanceSnapshot {\n const nav = typeof performance !== 'undefined' ? performance.getEntriesByType('navigation')[0] as PerformanceNavigationTiming | undefined : undefined\n const navigation = nav ? { type: nav.type, duration: nav.duration } : undefined\n return {\n ...(navigation !== undefined && { navigation }),\n longTasks: longTasks.slice(),\n slowResources: slowResources.slice(),\n }\n },\n dispose() { observer?.disconnect() },\n }\n}\n","export class RingBuffer<T> {\n private items: T[] = []\n constructor(private readonly max: number) {}\n\n push(item: T): void {\n this.items.push(item)\n while (this.items.length > this.max) this.items.shift()\n }\n\n snapshot(): T[] {\n return this.items.slice()\n }\n\n clear(): void {\n this.items.length = 0\n }\n}\n","import { sanitizeUrl } from './urlSanitizer'\nimport { collectDevice } from './device'\nimport { installConsolePatch } from './console'\nimport { installFetchPatch, installXhrPatch } from './network'\nimport { installErrorHandlers } from './errors'\nimport { createPerformanceCollector } from './performance'\nimport { RingBuffer } from './ringBuffer'\nimport type { CapturedContext, ConsoleEntry, ErrorEntry, NetworkEntry } from '../types'\n\nexport interface CaptureOptions {\n sanitizeUrl?: (url: string) => string\n maxConsole?: number\n maxNetwork?: number\n maxErrors?: number\n}\n\nexport interface CaptureHandle {\n snapshot(): CapturedContext\n clear(): void\n dispose(): void\n}\n\nexport function installCapture(options: CaptureOptions = {}): CaptureHandle {\n const { maxConsole = 50, maxNetwork = 50, maxErrors = 20 } = options\n const sanitize = options.sanitizeUrl ?? sanitizeUrl\n\n const consoleBuf = new RingBuffer<ConsoleEntry>(maxConsole)\n const networkBuf = new RingBuffer<NetworkEntry>(maxNetwork)\n const errorBuf = new RingBuffer<ErrorEntry>(maxErrors)\n\n const uninstallConsole = installConsolePatch(consoleBuf)\n const uninstallFetch = installFetchPatch(networkBuf, sanitize)\n const uninstallXhr = installXhrPatch(networkBuf, sanitize)\n const uninstallErrors = installErrorHandlers(errorBuf)\n const perf = createPerformanceCollector()\n\n return {\n snapshot(): CapturedContext {\n return {\n consoleLogs: consoleBuf.snapshot(),\n networkRequests: networkBuf.snapshot(),\n errors: errorBuf.snapshot(),\n device: collectDevice(),\n capturedAt: Date.now(),\n }\n },\n clear() {\n consoleBuf.clear(); networkBuf.clear(); errorBuf.clear()\n },\n dispose() {\n uninstallConsole(); uninstallFetch(); uninstallXhr(); uninstallErrors()\n perf.dispose()\n },\n }\n}\n","export function isMaskedElement(el: Element): boolean {\n return el.hasAttribute('data-mfb-mask') || el.classList.contains('mfb-mask')\n}\n\nexport function prepareMaskMatcher(selectors: string[]): (el: Element) => boolean {\n const joined = selectors.join(',').trim()\n if (!joined) return isMaskedElement\n return (el: Element) => isMaskedElement(el) || el.matches(joined)\n}\n\nexport interface ScreenshotOptions {\n mask?: string[]\n maxBytes?: number\n}\n\nexport async function takeScreenshot(target: Element, options: ScreenshotOptions = {}): Promise<Blob | null> {\n if (typeof document === 'undefined') return null\n try {\n const html2canvas = (await import('html2canvas-pro')).default\n const matcher = prepareMaskMatcher(options.mask ?? [])\n const canvas = await html2canvas(target as HTMLElement, {\n ignoreElements: (el) => matcher(el),\n useCORS: true,\n logging: false,\n backgroundColor: null,\n })\n return await new Promise<Blob | null>((resolve) => canvas.toBlob(resolve, 'image/png'))\n } catch {\n return null\n }\n}\n","export const DEFAULT_STRINGS = {\n 'fab.label': 'Send feedback',\n 'form.title': 'Send feedback',\n 'form.description.label': 'What happened?',\n 'form.description.placeholder': 'Describe the issue or idea in one or two sentences.',\n 'form.type.label': 'Type',\n 'form.severity.label': 'Severity',\n 'form.submit': 'Send',\n 'form.cancel': 'Cancel',\n 'form.close': 'Close',\n 'form.submitting': 'Sending…',\n 'form.success': 'Thanks — your feedback was sent.',\n 'form.error': 'Could not send. Please try again.',\n 'form.screenshot.label': 'Screenshot',\n 'form.screenshot.cta_click': 'Click',\n 'form.screenshot.cta_rest': 'drop, or paste an image',\n 'form.screenshot.formats': 'PNG, JPEG or WebP — up to 10 MB',\n 'form.screenshot.remove': 'Remove screenshot',\n 'form.screenshot.annotate': 'Annotate',\n 'form.screenshot.error_type': 'Unsupported file type. Use PNG, JPEG or WebP.',\n 'form.screenshot.error_size': 'File too large (max {max} MB).',\n 'form.context.label': 'Page',\n 'type.bug': 'Bug',\n 'type.feature': 'Feature request',\n 'type.question': 'Question',\n 'type.praise': 'Praise',\n 'type.typo': 'Typo',\n 'severity.blocker': 'Blocker',\n 'severity.high': 'High',\n 'severity.medium': 'Medium',\n 'severity.low': 'Low',\n 'annotator.title': 'Annotate screenshot',\n 'annotator.tool.rectangle': 'Rectangle',\n 'annotator.tool.arrow': 'Arrow',\n 'annotator.tool.freehand': 'Freehand',\n 'annotator.tool.text': 'Text',\n 'annotator.text_prompt': 'Enter text:',\n 'annotator.undo': 'Undo',\n 'annotator.clear': 'Clear all',\n 'annotator.count_suffix': 'annotations',\n 'annotator.loading': 'Loading…',\n 'annotator.apply': 'Apply',\n 'annotator.applying': 'Applying…',\n}\n\nexport type StringKey = keyof typeof DEFAULT_STRINGS\n\nconst FRENCH_STRINGS: Record<StringKey, string> = {\n 'fab.label': 'Envoyer un commentaire',\n 'form.title': 'Envoyer un commentaire',\n 'form.description.label': 'Qu’est-il arrivé ?',\n 'form.description.placeholder': 'Décrivez le problème ou l’idée en une ou deux phrases.',\n 'form.type.label': 'Type',\n 'form.severity.label': 'Sévérité',\n 'form.submit': 'Envoyer',\n 'form.cancel': 'Annuler',\n 'form.close': 'Fermer',\n 'form.submitting': 'Envoi…',\n 'form.success': 'Merci — votre commentaire a été envoyé.',\n 'form.error': 'Échec d’envoi. Veuillez réessayer.',\n 'form.screenshot.label': 'Capture d’écran',\n 'form.screenshot.cta_click': 'Cliquez',\n 'form.screenshot.cta_rest': 'déposez ou collez une image',\n 'form.screenshot.formats': 'PNG, JPEG ou WebP — jusqu’à 10 Mo',\n 'form.screenshot.remove': 'Retirer la capture',\n 'form.screenshot.annotate': 'Annoter',\n 'form.screenshot.error_type': 'Format non supporté. Utilisez PNG, JPEG ou WebP.',\n 'form.screenshot.error_size': 'Fichier trop volumineux (max {max} Mo).',\n 'form.context.label': 'Page',\n 'type.bug': 'Bogue',\n 'type.feature': 'Suggestion',\n 'type.question': 'Question',\n 'type.praise': 'Compliment',\n 'type.typo': 'Coquille',\n 'severity.blocker': 'Bloquant',\n 'severity.high': 'Élevée',\n 'severity.medium': 'Moyenne',\n 'severity.low': 'Faible',\n 'annotator.title': 'Annoter la capture',\n 'annotator.tool.rectangle': 'Rectangle',\n 'annotator.tool.arrow': 'Flèche',\n 'annotator.tool.freehand': 'Dessin libre',\n 'annotator.tool.text': 'Texte',\n 'annotator.text_prompt': 'Entrez le texte :',\n 'annotator.undo': 'Annuler',\n 'annotator.clear': 'Tout effacer',\n 'annotator.count_suffix': 'annotations',\n 'annotator.loading': 'Chargement…',\n 'annotator.apply': 'Appliquer',\n 'annotator.applying': 'Application…',\n}\n\nconst LOCALE_PACKS: Record<string, Record<StringKey, string>> = {\n fr: FRENCH_STRINGS,\n}\n\ninterface ResolveOptions {\n locale?: string\n}\n\nfunction packFor(locale: string | undefined): Record<StringKey, string> | null {\n if (!locale) return null\n // Match the language subtag only (fr-CA, fr-FR → fr).\n const tag = locale.toLowerCase().split(/[-_]/)[0]!\n return LOCALE_PACKS[tag] ?? null\n}\n\nexport function resolveStrings(\n overrides: Record<string, string>,\n options: ResolveOptions = {},\n): Record<StringKey, string> {\n const localePack = packFor(options.locale) ?? {}\n return {\n ...DEFAULT_STRINGS,\n ...localePack,\n ...overrides,\n } as Record<StringKey, string>\n}\n","import { h, render } from 'preact'\nimport { useCallback, useState } from 'preact/hooks'\n\nimport { Fab } from './Fab'\nimport { Form, type FormValues } from './Form'\nimport { Modal } from './Modal'\nimport { WIDGET_STYLES } from './styles'\nimport type { StringKey } from './i18n'\n\nexport interface MountOptions {\n host: HTMLElement\n strings: Record<StringKey, string>\n showFAB: boolean\n onSubmit: (values: FormValues) => Promise<void>\n}\n\nexport interface MountHandle {\n open(): void\n close(): void\n dispose(): void\n}\n\ntype State = { open: boolean; status: 'idle' | 'submitting' | 'error' | 'success'; error?: string }\n\nexport function mountWidget(options: MountOptions): MountHandle {\n const shadow = options.host.attachShadow({ mode: 'open' })\n const style = document.createElement('style')\n style.textContent = WIDGET_STYLES\n shadow.appendChild(style)\n const mountPoint = document.createElement('div')\n shadow.appendChild(mountPoint)\n\n let currentState: State = { open: false, status: 'idle' }\n\n function rerender(state: State) {\n currentState = state\n render(h(Root, { state }), mountPoint)\n }\n\n function Root({ state }: { state: State }) {\n const handleSubmit = useCallback(async (values: FormValues) => {\n rerender({ open: true, status: 'submitting' })\n try {\n await options.onSubmit(values)\n rerender({ open: true, status: 'success' })\n setTimeout(() => rerender({ open: false, status: 'idle' }), 1200)\n } catch (err) {\n rerender({ open: true, status: 'error', error: err instanceof Error ? err.message : String(err) })\n }\n }, [])\n\n return (\n <>\n {options.showFAB && (\n <Fab\n label={options.strings['fab.label']}\n onClick={() => rerender({ ...currentState, open: true })}\n />\n )}\n {state.open && (\n <Modal\n onDismiss={() => rerender({ open: false, status: 'idle' })}\n closeLabel={options.strings['form.close']}\n >\n <Form\n strings={options.strings}\n onSubmit={handleSubmit}\n onCancel={() => rerender({ open: false, status: 'idle' })}\n status={state.status}\n {...(state.error !== undefined && { errorMessage: state.error })}\n />\n </Modal>\n )}\n </>\n )\n }\n\n rerender(currentState)\n\n return {\n open() { rerender({ ...currentState, open: true }) },\n close() { rerender({ ...currentState, open: false, status: 'idle' }) },\n dispose() {\n render(null, mountPoint)\n options.host.innerHTML = ''\n },\n }\n}\n","import { h } from 'preact'\n\ninterface FabProps {\n label: string\n onClick: () => void\n}\n\nexport function Fab({ label, onClick }: FabProps) {\n return (\n <button type=\"button\" class=\"fab\" aria-label={label} onClick={onClick}>\n 💬\n </button>\n )\n}\n","import { h } from 'preact'\nimport { useEffect, useRef, useState } from 'preact/hooks'\n\nimport type { FeedbackSeverity, FeedbackType } from '../types'\nimport { Annotator } from './Annotator'\nimport type { StringKey } from './i18n'\nimport { truncateUrl, validateScreenshotFile } from './screenshot-utils'\n\nexport type FormStatus = 'idle' | 'submitting' | 'error' | 'success'\n\nexport interface FormValues {\n description: string\n feedback_type: FeedbackType\n severity: FeedbackSeverity\n /** When set, the host should send this blob instead of running html2canvas. */\n screenshot?: Blob\n}\n\ninterface FormProps {\n strings: Record<StringKey, string>\n onSubmit: (values: FormValues) => void\n onCancel: () => void\n status: FormStatus\n errorMessage?: string\n}\n\nconst TYPES: FeedbackType[] = ['bug', 'feature', 'question', 'praise', 'typo']\nconst SEVERITIES: FeedbackSeverity[] = ['blocker', 'high', 'medium', 'low']\n\nexport function Form({ strings, onSubmit, onCancel, status, errorMessage }: FormProps) {\n const [description, setDescription] = useState('')\n const [feedbackType, setFeedbackType] = useState<FeedbackType>('bug')\n const [severity, setSeverity] = useState<FeedbackSeverity>('medium')\n const [localError, setLocalError] = useState('')\n const [screenshotBlob, setScreenshotBlob] = useState<Blob | null>(null)\n const [screenshotPreview, setScreenshotPreview] = useState<string | null>(null)\n const [isDragOver, setIsDragOver] = useState(false)\n const [annotatorOpen, setAnnotatorOpen] = useState(false)\n const fileInputRef = useRef<HTMLInputElement | null>(null)\n const dropZoneRef = useRef<HTMLDivElement | null>(null)\n\n const submitting = status === 'submitting'\n const submitLabel = submitting ? strings['form.submitting'] : strings['form.submit']\n const pageUrl = typeof window !== 'undefined' ? window.location.href : ''\n\n // Revoke any object URL when the preview changes or the form unmounts.\n useEffect(() => {\n return () => {\n if (screenshotPreview) URL.revokeObjectURL(screenshotPreview)\n }\n }, [screenshotPreview])\n\n const acceptFile = (file: File | Blob) => {\n setLocalError('')\n if (file instanceof File) {\n const err = validateScreenshotFile(file)\n if (err) {\n setLocalError(\n err.kind === 'type'\n ? strings['form.screenshot.error_type']\n : strings['form.screenshot.error_size'].replace('{max}', String(err.maxMb)),\n )\n return\n }\n }\n if (screenshotPreview) URL.revokeObjectURL(screenshotPreview)\n setScreenshotBlob(file)\n setScreenshotPreview(URL.createObjectURL(file))\n }\n\n const clearScreenshot = () => {\n if (screenshotPreview) URL.revokeObjectURL(screenshotPreview)\n setScreenshotPreview(null)\n setScreenshotBlob(null)\n setLocalError('')\n if (fileInputRef.current) fileInputRef.current.value = ''\n }\n\n const handleFileInputChange = (e: Event) => {\n const file = (e.target as HTMLInputElement).files?.[0]\n if (file) acceptFile(file)\n }\n\n const handleDragOver = (e: DragEvent) => {\n e.preventDefault()\n e.stopPropagation()\n setIsDragOver(true)\n }\n const handleDragLeave = (e: DragEvent) => {\n e.preventDefault()\n e.stopPropagation()\n if (e.currentTarget === e.target) setIsDragOver(false)\n }\n const handleDrop = (e: DragEvent) => {\n e.preventDefault()\n e.stopPropagation()\n setIsDragOver(false)\n const file = e.dataTransfer?.files?.[0]\n if (file) acceptFile(file)\n }\n\n // Clipboard paste, scoped to the dropzone — so we don't hijack paste from\n // textareas elsewhere in the page or in our own description field.\n useEffect(() => {\n const zone = dropZoneRef.current\n if (!zone) return\n const onPaste = (e: ClipboardEvent) => {\n const items = e.clipboardData?.items\n if (!items) return\n for (const item of Array.from(items)) {\n if (item.kind === 'file' && item.type.startsWith('image/')) {\n const file = item.getAsFile()\n if (file) {\n e.preventDefault()\n acceptFile(file)\n return\n }\n }\n }\n }\n zone.addEventListener('paste', onPaste)\n return () => zone.removeEventListener('paste', onPaste)\n // eslint-disable-next-line react-hooks/exhaustive-deps\n }, [screenshotPreview])\n\n const handleAnnotated = (annotated: Blob) => {\n if (screenshotPreview) URL.revokeObjectURL(screenshotPreview)\n setScreenshotBlob(annotated)\n setScreenshotPreview(URL.createObjectURL(annotated))\n setAnnotatorOpen(false)\n }\n\n const handleSubmit = (e: Event) => {\n e.preventDefault()\n if (!description.trim()) {\n setLocalError(strings['form.description.placeholder'])\n return\n }\n setLocalError('')\n const values: FormValues = {\n description: description.trim(),\n feedback_type: feedbackType,\n severity,\n }\n if (screenshotBlob) values.screenshot = screenshotBlob\n onSubmit(values)\n }\n\n return (\n <form onSubmit={handleSubmit}>\n <h2>{strings['form.title']}</h2>\n\n <div class=\"field\">\n <label for=\"mfb-desc\">{strings['form.description.label']}</label>\n <textarea\n id=\"mfb-desc\"\n value={description}\n placeholder={strings['form.description.placeholder']}\n onInput={(e) => setDescription((e.target as HTMLTextAreaElement).value)}\n />\n </div>\n\n <div class=\"row\">\n <div class=\"field\">\n <label for=\"mfb-type\">{strings['form.type.label']}</label>\n <select\n id=\"mfb-type\"\n value={feedbackType}\n onChange={(e) => setFeedbackType((e.target as HTMLSelectElement).value as FeedbackType)}\n >\n {TYPES.map((t) => <option value={t}>{strings[`type.${t}` as StringKey]}</option>)}\n </select>\n </div>\n <div class=\"field\">\n <label for=\"mfb-sev\">{strings['form.severity.label']}</label>\n <select\n id=\"mfb-sev\"\n value={severity}\n onChange={(e) => setSeverity((e.target as HTMLSelectElement).value as FeedbackSeverity)}\n >\n {SEVERITIES.map((s) => <option value={s}>{strings[`severity.${s}` as StringKey]}</option>)}\n </select>\n </div>\n </div>\n\n <div class=\"field\">\n <label>{strings['form.screenshot.label']}</label>\n <input\n ref={fileInputRef}\n type=\"file\"\n accept=\"image/png,image/jpeg,image/webp\"\n class=\"mfb-sr-only\"\n onChange={handleFileInputChange}\n aria-hidden=\"true\"\n tabIndex={-1}\n />\n {screenshotPreview ? (\n <div class=\"screenshot-preview\">\n <img src={screenshotPreview} alt=\"\" />\n <button\n type=\"button\"\n class=\"screenshot-remove\"\n onClick={clearScreenshot}\n aria-label={strings['form.screenshot.remove']}\n >\n ×\n </button>\n <button\n type=\"button\"\n class=\"btn screenshot-annotate\"\n onClick={() => setAnnotatorOpen(true)}\n >\n {strings['form.screenshot.annotate']}\n </button>\n </div>\n ) : (\n <div\n ref={dropZoneRef}\n class={`screenshot-dropzone ${isDragOver ? 'is-dragover' : ''}`}\n tabIndex={0}\n role=\"button\"\n aria-label={strings['form.screenshot.label']}\n onClick={() => fileInputRef.current?.click()}\n onKeyDown={(e) => {\n if (e.key === 'Enter' || e.key === ' ') {\n e.preventDefault()\n fileInputRef.current?.click()\n }\n }}\n onDragOver={handleDragOver}\n onDragLeave={handleDragLeave}\n onDrop={handleDrop}\n >\n <div class=\"screenshot-cta\">\n <strong>{strings['form.screenshot.cta_click']}</strong>\n {', '}\n {strings['form.screenshot.cta_rest']}\n </div>\n <div class=\"screenshot-formats\">{strings['form.screenshot.formats']}</div>\n </div>\n )}\n </div>\n\n {pageUrl && (\n <div class=\"page-context\" title={pageUrl}>\n <span class=\"page-context-label\">{strings['form.context.label']}</span>\n <span class=\"page-context-url\">{truncateUrl(pageUrl, 90)}</span>\n </div>\n )}\n\n {localError && <div class=\"error\">{localError}</div>}\n {status === 'error' && errorMessage && <div class=\"error\">{errorMessage}</div>}\n {status === 'success' && <div class=\"success\">{strings['form.success']}</div>}\n\n <div class=\"actions\">\n <button type=\"button\" class=\"btn\" onClick={onCancel} disabled={submitting}>{strings['form.cancel']}</button>\n <button type=\"submit\" class=\"btn btn--primary\" disabled={submitting}>{submitLabel}</button>\n </div>\n\n {annotatorOpen && screenshotBlob && (\n <Annotator\n imageBlob={screenshotBlob}\n strings={strings}\n onCancel={() => setAnnotatorOpen(false)}\n onSave={handleAnnotated}\n />\n )}\n </form>\n )\n}\n","/**\n * Annotator — minimal screenshot annotation modal (v0.6.0).\n *\n * Ported from thepnr-platform's FeedbackAnnotator. Custom canvas, no\n * external lib. Supports rectangle, arrow, freehand and text shapes with\n * undo / clear-all / color-picker. The Save call rasterizes the original\n * image + every shape onto a fresh canvas and returns a PNG Blob.\n *\n * Inline SVG icons (no lucide) and inline CSS classes (the widget shadow\n * root sees the styles in styles.ts).\n */\n\nimport { h } from 'preact'\nimport { useEffect, useRef, useState } from 'preact/hooks'\n\nimport type { StringKey } from './i18n'\n\ntype Tool = 'rectangle' | 'arrow' | 'freehand' | 'text'\n\ninterface BaseShape {\n color: string\n lineWidth: number\n}\n\ninterface RectShape extends BaseShape {\n kind: 'rectangle'\n x: number\n y: number\n w: number\n h: number\n}\n\ninterface ArrowShape extends BaseShape {\n kind: 'arrow'\n x1: number\n y1: number\n x2: number\n y2: number\n}\n\ninterface FreehandShape extends BaseShape {\n kind: 'freehand'\n points: Array<{ x: number; y: number }>\n}\n\ninterface TextShape extends BaseShape {\n kind: 'text'\n x: number\n y: number\n text: string\n fontSize: number\n}\n\ntype Shape = RectShape | ArrowShape | FreehandShape | TextShape\n\nconst COLORS: string[] = ['#ef4444', '#f59e0b', '#10b981', '#3b82f6', '#ffffff']\n\n// ---------------------------------------------------------------------------\n// Drawing helpers\n// ---------------------------------------------------------------------------\n\nfunction drawShape(ctx: CanvasRenderingContext2D, shape: Shape) {\n ctx.save()\n ctx.strokeStyle = shape.color\n ctx.fillStyle = shape.color\n ctx.lineWidth = shape.lineWidth\n ctx.lineCap = 'round'\n ctx.lineJoin = 'round'\n\n if (shape.kind === 'rectangle') {\n ctx.strokeRect(shape.x, shape.y, shape.w, shape.h)\n } else if (shape.kind === 'arrow') {\n drawArrow(ctx, shape.x1, shape.y1, shape.x2, shape.y2)\n } else if (shape.kind === 'freehand') {\n if (shape.points.length < 2) {\n ctx.restore()\n return\n }\n ctx.beginPath()\n ctx.moveTo(shape.points[0]!.x, shape.points[0]!.y)\n for (let i = 1; i < shape.points.length; i++) {\n ctx.lineTo(shape.points[i]!.x, shape.points[i]!.y)\n }\n ctx.stroke()\n } else if (shape.kind === 'text') {\n ctx.font = `bold ${shape.fontSize}px -apple-system, BlinkMacSystemFont, sans-serif`\n ctx.textBaseline = 'top'\n const metrics = ctx.measureText(shape.text)\n const padding = 4\n const w = metrics.width + padding * 2\n const hh = shape.fontSize + padding * 2\n ctx.fillStyle = 'rgba(0, 0, 0, 0.6)'\n ctx.fillRect(shape.x - padding, shape.y - padding, w, hh)\n ctx.fillStyle = shape.color\n ctx.fillText(shape.text, shape.x, shape.y)\n }\n ctx.restore()\n}\n\nfunction drawArrow(\n ctx: CanvasRenderingContext2D,\n x1: number,\n y1: number,\n x2: number,\n y2: number,\n) {\n const headLen = 14\n const angle = Math.atan2(y2 - y1, x2 - x1)\n ctx.beginPath()\n ctx.moveTo(x1, y1)\n ctx.lineTo(x2, y2)\n ctx.stroke()\n ctx.beginPath()\n ctx.moveTo(x2, y2)\n ctx.lineTo(\n x2 - headLen * Math.cos(angle - Math.PI / 6),\n y2 - headLen * Math.sin(angle - Math.PI / 6),\n )\n ctx.lineTo(\n x2 - headLen * Math.cos(angle + Math.PI / 6),\n y2 - headLen * Math.sin(angle + Math.PI / 6),\n )\n ctx.closePath()\n ctx.fill()\n}\n\n// ---------------------------------------------------------------------------\n// Inline icons\n// ---------------------------------------------------------------------------\n\nconst Icon = {\n rect: (\n <svg width=\"16\" height=\"16\" viewBox=\"0 0 16 16\" aria-hidden=\"true\">\n <rect x=\"2\" y=\"3\" width=\"12\" height=\"10\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"1.5\" />\n </svg>\n ),\n arrow: (\n <svg width=\"16\" height=\"16\" viewBox=\"0 0 16 16\" aria-hidden=\"true\">\n <path d=\"M2 8h11M9 4l4 4-4 4\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"1.5\" stroke-linecap=\"round\" stroke-linejoin=\"round\" />\n </svg>\n ),\n pencil: (\n <svg width=\"16\" height=\"16\" viewBox=\"0 0 16 16\" aria-hidden=\"true\">\n <path d=\"M11.5 2.5l2 2L5 13H3v-2l8.5-8.5z\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"1.5\" stroke-linejoin=\"round\" />\n </svg>\n ),\n text: (\n <svg width=\"16\" height=\"16\" viewBox=\"0 0 16 16\" aria-hidden=\"true\">\n <path d=\"M3 3h10M8 3v10M5 13h6\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"1.5\" stroke-linecap=\"round\" />\n </svg>\n ),\n undo: (\n <svg width=\"14\" height=\"14\" viewBox=\"0 0 16 16\" aria-hidden=\"true\">\n <path d=\"M4 7l3-3M4 7l3 3M4 7h6a3 3 0 0 1 0 6H7\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"1.5\" stroke-linecap=\"round\" stroke-linejoin=\"round\" />\n </svg>\n ),\n trash: (\n <svg width=\"14\" height=\"14\" viewBox=\"0 0 16 16\" aria-hidden=\"true\">\n <path d=\"M3 4h10M6 4V2.5h4V4M5 4l.5 9h5L11 4\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"1.5\" stroke-linecap=\"round\" stroke-linejoin=\"round\" />\n </svg>\n ),\n close: (\n <svg width=\"16\" height=\"16\" viewBox=\"0 0 16 16\" aria-hidden=\"true\">\n <path d=\"M4 4l8 8M12 4l-8 8\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"1.5\" stroke-linecap=\"round\" />\n </svg>\n ),\n}\n\n// ---------------------------------------------------------------------------\n// Component\n// ---------------------------------------------------------------------------\n\nexport interface AnnotatorProps {\n imageBlob: Blob\n strings: Record<StringKey, string>\n onSave: (annotated: Blob) => void\n onCancel: () => void\n}\n\nexport function Annotator({ imageBlob, strings, onSave, onCancel }: AnnotatorProps) {\n const canvasRef = useRef<HTMLCanvasElement | null>(null)\n const containerRef = useRef<HTMLDivElement | null>(null)\n const imageRef = useRef<HTMLImageElement | null>(null)\n const [tool, setTool] = useState<Tool>('rectangle')\n const [color, setColor] = useState<string>(COLORS[0]!)\n const [shapes, setShapes] = useState<Shape[]>([])\n const isDrawingRef = useRef(false)\n const [draftShape, setDraftShape] = useState<Shape | null>(null)\n const [imageLoaded, setImageLoaded] = useState(false)\n const [saving, setSaving] = useState(false)\n const scaleRef = useRef(1)\n\n // Esc closes; mirrors Modal.tsx behaviour.\n useEffect(() => {\n const onKey = (e: KeyboardEvent) => {\n if (e.key === 'Escape') {\n e.stopPropagation()\n onCancel()\n }\n }\n window.addEventListener('keydown', onKey)\n return () => window.removeEventListener('keydown', onKey)\n }, [onCancel])\n\n // Decode the source image once, into an offscreen <img> we keep around for\n // every redraw.\n useEffect(() => {\n const url = URL.createObjectURL(imageBlob)\n const img = new Image()\n img.onload = () => {\n imageRef.current = img\n setImageLoaded(true)\n }\n img.src = url\n return () => URL.revokeObjectURL(url)\n }, [imageBlob])\n\n // Once the image loads, fit the canvas to whatever room the modal has.\n useEffect(() => {\n if (\n !imageLoaded ||\n !canvasRef.current ||\n !imageRef.current ||\n !containerRef.current\n ) {\n return\n }\n const img = imageRef.current\n const container = containerRef.current\n const maxW = container.clientWidth - 16\n const maxH = window.innerHeight * 0.6\n const fitScale = Math.min(maxW / img.width, maxH / img.height, 1)\n scaleRef.current = fitScale\n\n const canvas = canvasRef.current\n canvas.width = img.width\n canvas.height = img.height\n canvas.style.width = `${img.width * fitScale}px`\n canvas.style.height = `${img.height * fitScale}px`\n redraw()\n // eslint-disable-next-line react-hooks/exhaustive-deps\n }, [imageLoaded])\n\n // Redraw whenever the shape list or in-flight draft changes.\n useEffect(() => {\n redraw()\n // eslint-disable-next-line react-hooks/exhaustive-deps\n }, [shapes, draftShape])\n\n function redraw() {\n const canvas = canvasRef.current\n const img = imageRef.current\n if (!canvas || !img) return\n const ctx = canvas.getContext('2d')\n if (!ctx) return\n ctx.clearRect(0, 0, canvas.width, canvas.height)\n ctx.drawImage(img, 0, 0)\n for (const s of shapes) drawShape(ctx, s)\n if (draftShape) drawShape(ctx, draftShape)\n }\n\n function getCanvasCoords(e: MouseEvent) {\n const canvas = canvasRef.current!\n const rect = canvas.getBoundingClientRect()\n return {\n x: (e.clientX - rect.left) / scaleRef.current,\n y: (e.clientY - rect.top) / scaleRef.current,\n }\n }\n\n const handleMouseDown = (e: MouseEvent) => {\n if (!imageLoaded) return\n const { x, y } = getCanvasCoords(e)\n const lineWidth = Math.max(3, Math.round(canvasRef.current!.width / 400))\n\n if (tool === 'text') {\n const text = window.prompt(strings['annotator.text_prompt'])\n if (text && text.trim()) {\n setShapes((prev) => [\n ...prev,\n {\n kind: 'text',\n x,\n y,\n text: text.trim(),\n color,\n fontSize: Math.max(16, Math.round(canvasRef.current!.width / 50)),\n lineWidth: 1,\n },\n ])\n }\n return\n }\n\n isDrawingRef.current = true\n if (tool === 'rectangle') {\n setDraftShape({ kind: 'rectangle', x, y, w: 0, h: 0, color, lineWidth })\n } else if (tool === 'arrow') {\n setDraftShape({ kind: 'arrow', x1: x, y1: y, x2: x, y2: y, color, lineWidth })\n } else if (tool === 'freehand') {\n setDraftShape({ kind: 'freehand', points: [{ x, y }], color, lineWidth })\n }\n }\n\n const handleMouseMove = (e: MouseEvent) => {\n if (!isDrawingRef.current || !draftShape) return\n const { x, y } = getCanvasCoords(e)\n if (draftShape.kind === 'rectangle') {\n setDraftShape({ ...draftShape, w: x - draftShape.x, h: y - draftShape.y })\n } else if (draftShape.kind === 'arrow') {\n setDraftShape({ ...draftShape, x2: x, y2: y })\n } else if (draftShape.kind === 'freehand') {\n setDraftShape({ ...draftShape, points: [...draftShape.points, { x, y }] })\n }\n }\n\n const handleMouseUp = () => {\n if (isDrawingRef.current && draftShape) {\n // Discard tiny shapes (accidental clicks).\n const isTiny =\n (draftShape.kind === 'rectangle' &&\n Math.abs(draftShape.w) < 4 &&\n Math.abs(draftShape.h) < 4) ||\n (draftShape.kind === 'arrow' &&\n Math.hypot(\n draftShape.x2 - draftShape.x1,\n draftShape.y2 - draftShape.y1,\n ) < 4) ||\n (draftShape.kind === 'freehand' && draftShape.points.length < 3)\n if (!isTiny) {\n setShapes((prev) => [...prev, draftShape])\n }\n }\n isDrawingRef.current = false\n setDraftShape(null)\n }\n\n const handleSave = async () => {\n const canvas = canvasRef.current\n if (!canvas) return\n setSaving(true)\n try {\n const blob = await new Promise<Blob | null>((resolve) =>\n canvas.toBlob(resolve, 'image/png', 0.92),\n )\n if (blob) onSave(blob)\n } finally {\n setSaving(false)\n }\n }\n\n const tools: Array<{ id: Tool; icon: typeof Icon.rect; label: string }> = [\n { id: 'rectangle', icon: Icon.rect, label: strings['annotator.tool.rectangle'] },\n { id: 'arrow', icon: Icon.arrow, label: strings['annotator.tool.arrow'] },\n { id: 'freehand', icon: Icon.pencil, label: strings['annotator.tool.freehand'] },\n { id: 'text', icon: Icon.text, label: strings['annotator.tool.text'] },\n ]\n\n return (\n <div\n class=\"annotator-backdrop\"\n role=\"presentation\"\n onClick={(e) => {\n if (e.target === e.currentTarget) onCancel()\n }}\n >\n <div class=\"annotator\" role=\"dialog\" aria-modal=\"true\" aria-label={strings['annotator.title']}>\n <div class=\"annotator-header\">\n <span>{strings['annotator.title']}</span>\n <button\n type=\"button\"\n class=\"modal-close\"\n aria-label={strings['form.close']}\n onClick={onCancel}\n >\n {Icon.close}\n </button>\n </div>\n\n <div class=\"annotator-toolbar\">\n <div class=\"annotator-tools\">\n {tools.map((t) => (\n <button\n key={t.id}\n type=\"button\"\n onClick={() => setTool(t.id)}\n title={t.label}\n aria-label={t.label}\n aria-pressed={tool === t.id}\n class={`annotator-tool ${tool === t.id ? 'is-active' : ''}`}\n >\n {t.icon}\n </button>\n ))}\n </div>\n\n <span class=\"annotator-sep\" />\n\n <div class=\"annotator-colors\">\n {COLORS.map((c) => (\n <button\n key={c}\n type=\"button\"\n onClick={() => setColor(c)}\n aria-label={c}\n aria-pressed={color === c}\n class={`annotator-color ${color === c ? 'is-active' : ''}`}\n style={{ backgroundColor: c }}\n />\n ))}\n </div>\n\n <span class=\"annotator-sep\" />\n\n <button\n type=\"button\"\n class=\"annotator-btn\"\n onClick={() => setShapes((prev) => prev.slice(0, -1))}\n disabled={shapes.length === 0}\n >\n {Icon.undo}\n <span>{strings['annotator.undo']}</span>\n </button>\n <button\n type=\"button\"\n class=\"annotator-btn\"\n onClick={() => setShapes([])}\n disabled={shapes.length === 0}\n >\n {Icon.trash}\n <span>{strings['annotator.clear']}</span>\n </button>\n\n <span class=\"annotator-spacer\" />\n\n <span class=\"annotator-count\">\n {shapes.length} {strings['annotator.count_suffix']}\n </span>\n </div>\n\n <div ref={containerRef} class=\"annotator-canvas-wrap\">\n {!imageLoaded ? (\n <span class=\"annotator-loading\">{strings['annotator.loading']}</span>\n ) : (\n <canvas\n ref={canvasRef}\n onMouseDown={handleMouseDown}\n onMouseMove={handleMouseMove}\n onMouseUp={handleMouseUp}\n onMouseLeave={handleMouseUp}\n class=\"annotator-canvas\"\n />\n )}\n </div>\n\n <div class=\"annotator-footer\">\n <button type=\"button\" class=\"btn\" onClick={onCancel}>\n {strings['form.cancel']}\n </button>\n <button\n type=\"button\"\n class=\"btn btn--primary\"\n onClick={handleSave}\n disabled={saving || !imageLoaded}\n >\n {saving ? strings['annotator.applying'] : strings['annotator.apply']}\n </button>\n </div>\n </div>\n </div>\n )\n}\n","/**\n * Helpers for the manual-screenshot-upload UX (v0.6.0).\n *\n * Kept tiny and dependency-free so they can be unit-tested without DOM/jsdom\n * setup. The interesting work — drag/drop, paste, file picker — lives in\n * Form.tsx.\n */\n\nexport const ALLOWED_IMAGE_TYPES = [\n 'image/png',\n 'image/jpeg',\n 'image/webp',\n] as const\n\nexport const MAX_SCREENSHOT_BYTES = 10 * 1024 * 1024 // 10 MB\n\nexport type ScreenshotValidationError =\n | { kind: 'type' }\n | { kind: 'size'; maxMb: number }\n\nexport function validateScreenshotFile(file: File): ScreenshotValidationError | null {\n if (\n !ALLOWED_IMAGE_TYPES.includes(\n file.type as (typeof ALLOWED_IMAGE_TYPES)[number],\n )\n ) {\n return { kind: 'type' }\n }\n if (file.size > MAX_SCREENSHOT_BYTES) {\n return { kind: 'size', maxMb: MAX_SCREENSHOT_BYTES / (1024 * 1024) }\n }\n return null\n}\n\n/**\n * Truncate a URL while keeping the start and end visible. Used in the form's\n * \"Vous étiez ici\" footer so the user can verify the URL we'll send without\n * the long path overflowing the modal.\n *\n * \"https://app.example.com/very/long/deep/path?a=1&b=2\" (53 chars, max 30)\n * → \"https://app.examp…h?a=1&b=2\"\n */\nexport function truncateUrl(url: string, maxLength = 80): string {\n if (url.length <= maxLength) return url\n const keepStart = Math.floor((maxLength - 1) / 2)\n const keepEnd = maxLength - 1 - keepStart\n return `${url.slice(0, keepStart)}…${url.slice(url.length - keepEnd)}`\n}\n","import { h, type ComponentChildren } from 'preact'\nimport { useEffect, useRef } from 'preact/hooks'\n\ninterface ModalProps {\n onDismiss: () => void\n children: ComponentChildren\n closeLabel?: string\n}\n\nexport function Modal({ onDismiss, children, closeLabel = 'Close' }: ModalProps) {\n const modalRef = useRef<HTMLDivElement>(null)\n const previouslyFocused = useRef<Element | null>(null)\n\n // Esc-to-close + focus management. Without this, users couldn't dismiss\n // with the keyboard (a real-world UX expectation). Listener installed on\n // window so it works regardless of which element inside the modal has focus.\n useEffect(() => {\n previouslyFocused.current = document.activeElement\n const onKey = (e: KeyboardEvent) => {\n if (e.key === 'Escape') {\n e.stopPropagation()\n onDismiss()\n }\n }\n window.addEventListener('keydown', onKey)\n // Focus first focusable element inside the modal so the keyboard user\n // lands inside, not still on the FAB or whatever opened the modal.\n const first = modalRef.current?.querySelector<HTMLElement>(\n 'textarea, input, select, button',\n )\n first?.focus()\n return () => {\n window.removeEventListener('keydown', onKey)\n // Restore focus on dismiss so screen-readers don't lose place.\n const prev = previouslyFocused.current as HTMLElement | null\n if (prev && typeof prev.focus === 'function') prev.focus()\n }\n }, [onDismiss])\n\n return (\n <div\n class=\"backdrop\"\n role=\"presentation\"\n onClick={(e) => {\n if (e.target === e.currentTarget) onDismiss()\n }}\n >\n <div ref={modalRef} class=\"modal\" role=\"dialog\" aria-modal=\"true\">\n <button\n type=\"button\"\n class=\"modal-close\"\n aria-label={closeLabel}\n onClick={onDismiss}\n >\n ×\n </button>\n {children}\n </div>\n </div>\n )\n}\n","export const WIDGET_STYLES = `\n:host {\n --mfb-accent: #3b82f6;\n --mfb-accent-contrast: #ffffff;\n --mfb-bg: #ffffff;\n --mfb-surface: #f9fafb;\n --mfb-text: #0a0a0a;\n --mfb-text-muted: #6b7280;\n --mfb-border: #e5e7eb;\n --mfb-radius: 8px;\n --mfb-font: system-ui, -apple-system, sans-serif;\n --mfb-z-index: 2147483640;\n\n all: initial;\n font-family: var(--mfb-font);\n color: var(--mfb-text);\n position: fixed;\n z-index: var(--mfb-z-index);\n}\n\n@media (prefers-color-scheme: dark) {\n :host {\n --mfb-bg: #111827;\n --mfb-surface: #1f2937;\n --mfb-text: #f9fafb;\n --mfb-text-muted: #9ca3af;\n --mfb-border: #374151;\n }\n}\n\n.fab {\n position: fixed;\n bottom: 24px;\n right: 24px;\n width: 52px;\n height: 52px;\n border-radius: 999px;\n background: var(--mfb-accent);\n color: var(--mfb-accent-contrast);\n border: none;\n cursor: pointer;\n box-shadow: 0 4px 14px rgba(0, 0, 0, 0.18);\n font-size: 22px;\n display: grid;\n place-items: center;\n transition: transform 120ms ease, box-shadow 120ms ease;\n}\n\n.fab:hover { transform: translateY(-1px); box-shadow: 0 6px 18px rgba(0, 0, 0, 0.24); }\n.fab:active { transform: translateY(0) scale(0.96); box-shadow: 0 3px 10px rgba(0, 0, 0, 0.22); }\n.fab:focus-visible { outline: 2px solid #fff; outline-offset: 3px; box-shadow: 0 0 0 4px var(--mfb-accent), 0 4px 14px rgba(0, 0, 0, 0.18); }\n@media (prefers-reduced-motion: reduce) { .fab { transition: none; } .fab:hover, .fab:active { transform: none; } }\n\n.backdrop {\n position: fixed;\n inset: 0;\n background: rgba(0, 0, 0, 0.45);\n display: grid;\n place-items: center;\n}\n\n.modal {\n background: var(--mfb-bg);\n border-radius: calc(var(--mfb-radius) * 1.5);\n box-shadow: 0 20px 48px rgba(0, 0, 0, 0.25);\n width: min(420px, 92vw);\n padding: 20px;\n display: flex;\n flex-direction: column;\n gap: 12px;\n position: relative;\n /* Cap modal height on short viewports (mobile landscape, tiny laptops)\n so the form scrolls inside the modal rather than overflowing the\n viewport with no way to reach the actions row. */\n max-height: calc(100vh - 32px);\n overflow-y: auto;\n}\n\n.modal h2 { margin: 0 0 4px; font-size: 18px; font-weight: 600; padding-right: 28px; }\n\n.modal-close {\n position: absolute;\n top: 8px;\n right: 8px;\n width: 32px;\n height: 32px;\n display: grid;\n place-items: center;\n background: transparent;\n border: none;\n border-radius: var(--mfb-radius);\n color: var(--mfb-text-muted);\n font: inherit;\n font-size: 22px;\n line-height: 1;\n cursor: pointer;\n}\n.modal-close:hover { background: var(--mfb-surface); color: var(--mfb-text); }\n.modal-close:focus-visible { outline: 2px solid var(--mfb-accent); outline-offset: 2px; }\n\n.field { display: flex; flex-direction: column; gap: 4px; font-size: 13px; }\n\n.field label { color: var(--mfb-text-muted); }\n\n.field input, .field select, .field textarea {\n font-family: inherit;\n font-size: 14px;\n color: inherit;\n padding: 8px 10px;\n border: 1px solid var(--mfb-border);\n border-radius: var(--mfb-radius);\n background: var(--mfb-surface);\n transition: border-color 120ms ease, box-shadow 120ms ease;\n}\n\n.field input:hover, .field select:hover, .field textarea:hover { border-color: var(--mfb-text-muted); }\n.field input:focus, .field select:focus, .field textarea:focus {\n outline: none;\n border-color: var(--mfb-accent);\n box-shadow: 0 0 0 3px color-mix(in srgb, var(--mfb-accent) 22%, transparent);\n}\n\n.field select {\n -webkit-appearance: none;\n -moz-appearance: none;\n appearance: none;\n padding-right: 28px;\n background-image: url(\"data:image/svg+xml;utf8,<svg xmlns='http://www.w3.org/2000/svg' width='10' height='6' viewBox='0 0 10 6'><path fill='none' stroke='%236b7280' stroke-width='1.5' stroke-linecap='round' stroke-linejoin='round' d='M1 1l4 4 4-4'/></svg>\");\n background-repeat: no-repeat;\n background-position: right 10px center;\n}\n\n.field textarea { min-height: 88px; resize: vertical; }\n\n.row { display: flex; gap: 8px; }\n.row > * { flex: 1; }\n\n.actions { display: flex; gap: 8px; justify-content: flex-end; padding-top: 8px; }\n\n.btn {\n padding: 8px 14px;\n border-radius: var(--mfb-radius);\n border: 1px solid var(--mfb-border);\n background: var(--mfb-bg);\n color: var(--mfb-text);\n font: inherit;\n cursor: pointer;\n}\n\n.btn--primary {\n background: var(--mfb-accent);\n color: var(--mfb-accent-contrast);\n border-color: var(--mfb-accent);\n}\n\n.btn[disabled] { opacity: 0.6; cursor: not-allowed; }\n\n.error { color: #dc2626; font-size: 13px; }\n.success { color: #059669; font-size: 13px; }\n\n/* ---- v0.6.0: manual screenshot upload + annotator -------------------- */\n\n.mfb-sr-only {\n position: absolute;\n width: 1px;\n height: 1px;\n padding: 0;\n margin: -1px;\n overflow: hidden;\n clip: rect(0, 0, 0, 0);\n white-space: nowrap;\n border: 0;\n}\n\n.screenshot-dropzone {\n border: 1px dashed var(--mfb-border);\n border-radius: var(--mfb-radius);\n padding: 14px 12px;\n text-align: center;\n cursor: pointer;\n background: var(--mfb-surface);\n transition: border-color 120ms ease, background 120ms ease;\n}\n.screenshot-dropzone:hover { border-color: var(--mfb-text-muted); }\n.screenshot-dropzone.is-dragover {\n border-color: var(--mfb-accent);\n border-style: solid;\n background: color-mix(in srgb, var(--mfb-accent) 8%, var(--mfb-surface));\n}\n.screenshot-dropzone:focus-visible {\n outline: 2px solid var(--mfb-accent);\n outline-offset: 2px;\n}\n.screenshot-cta { font-size: 13px; color: var(--mfb-text); }\n.screenshot-cta strong { color: var(--mfb-accent); font-weight: 600; }\n.screenshot-formats { font-size: 11px; color: var(--mfb-text-muted); margin-top: 4px; }\n\n.screenshot-preview {\n position: relative;\n border: 1px solid var(--mfb-border);\n border-radius: var(--mfb-radius);\n overflow: hidden;\n background: var(--mfb-surface);\n display: flex;\n flex-direction: column;\n}\n.screenshot-preview img {\n display: block;\n width: 100%;\n height: auto;\n max-height: 180px;\n object-fit: contain;\n background: #1a1a1a;\n}\n.screenshot-remove {\n position: absolute;\n top: 6px;\n right: 6px;\n width: 26px;\n height: 26px;\n display: grid;\n place-items: center;\n background: rgba(255, 255, 255, 0.9);\n border: 1px solid var(--mfb-border);\n border-radius: 999px;\n font-size: 18px;\n line-height: 1;\n cursor: pointer;\n color: #111827;\n}\n.screenshot-remove:hover { background: #fff; }\n.screenshot-annotate {\n border-radius: 0;\n border-width: 0;\n border-top: 1px solid var(--mfb-border);\n background: var(--mfb-bg);\n}\n.screenshot-annotate:hover { background: var(--mfb-surface); }\n\n.page-context {\n display: flex;\n align-items: center;\n gap: 8px;\n font-size: 11px;\n color: var(--mfb-text-muted);\n}\n.page-context-label {\n text-transform: uppercase;\n font-weight: 600;\n letter-spacing: 0.04em;\n}\n.page-context-url {\n font-family: ui-monospace, SFMono-Regular, Menlo, monospace;\n background: var(--mfb-surface);\n padding: 4px 6px;\n border-radius: 4px;\n flex: 1;\n overflow: hidden;\n text-overflow: ellipsis;\n white-space: nowrap;\n}\n\n/* Annotator modal — sits above the feedback modal (z-index +1). */\n\n.annotator-backdrop {\n position: fixed;\n inset: 0;\n background: rgba(0, 0, 0, 0.78);\n display: grid;\n place-items: center;\n z-index: 1;\n padding: 12px;\n}\n.annotator {\n position: relative;\n background: var(--mfb-bg);\n color: var(--mfb-text);\n border-radius: calc(var(--mfb-radius) * 1.5);\n width: min(960px, 96vw);\n max-height: calc(100vh - 24px);\n display: flex;\n flex-direction: column;\n box-shadow: 0 24px 60px rgba(0, 0, 0, 0.4);\n}\n.annotator-header {\n display: flex;\n align-items: center;\n justify-content: space-between;\n padding: 10px 14px;\n border-bottom: 1px solid var(--mfb-border);\n font-size: 13px;\n font-weight: 600;\n}\n.annotator-toolbar {\n display: flex;\n flex-wrap: wrap;\n align-items: center;\n gap: 8px;\n padding: 8px 14px;\n border-bottom: 1px solid var(--mfb-border);\n}\n.annotator-tools, .annotator-colors { display: flex; gap: 4px; }\n.annotator-sep {\n display: inline-block;\n width: 1px;\n height: 18px;\n background: var(--mfb-border);\n margin: 0 4px;\n}\n.annotator-spacer { flex: 1; }\n.annotator-tool {\n width: 30px;\n height: 30px;\n display: grid;\n place-items: center;\n background: var(--mfb-bg);\n color: var(--mfb-text);\n border: 1px solid var(--mfb-border);\n border-radius: var(--mfb-radius);\n cursor: pointer;\n}\n.annotator-tool:hover { background: var(--mfb-surface); }\n.annotator-tool.is-active {\n background: var(--mfb-text);\n color: var(--mfb-bg);\n border-color: var(--mfb-text);\n}\n.annotator-color {\n width: 24px;\n height: 24px;\n border-radius: 999px;\n border: 2px solid var(--mfb-border);\n cursor: pointer;\n padding: 0;\n transition: transform 120ms ease;\n}\n.annotator-color.is-active {\n transform: scale(1.12);\n border-color: var(--mfb-text);\n}\n.annotator-btn {\n display: inline-flex;\n align-items: center;\n gap: 4px;\n height: 30px;\n padding: 0 10px;\n font: inherit;\n font-size: 12px;\n background: var(--mfb-bg);\n color: var(--mfb-text);\n border: 1px solid var(--mfb-border);\n border-radius: var(--mfb-radius);\n cursor: pointer;\n}\n.annotator-btn:hover { background: var(--mfb-surface); }\n.annotator-btn[disabled] { opacity: 0.5; cursor: not-allowed; }\n.annotator-count { font-size: 11px; color: var(--mfb-text-muted); }\n.annotator-canvas-wrap {\n flex: 1;\n overflow: auto;\n background: #1a1a1a;\n display: flex;\n align-items: center;\n justify-content: center;\n padding: 12px;\n min-height: 200px;\n}\n.annotator-canvas {\n cursor: crosshair;\n box-shadow: 0 8px 28px rgba(0, 0, 0, 0.45);\n background: #fff;\n}\n.annotator-loading {\n color: rgba(255, 255, 255, 0.7);\n font-size: 13px;\n}\n.annotator-footer {\n display: flex;\n align-items: center;\n justify-content: flex-end;\n gap: 8px;\n padding: 10px 14px;\n border-top: 1px solid var(--mfb-border);\n}\n`\n","import { createApiClient } from './api/client'\nimport { installCapture } from './capture'\nimport { takeScreenshot } from './screenshot'\nimport { resolveStrings } from './widget/i18n'\nimport { mountWidget } from './widget/mount'\nimport type { FeedbackApi, FeedbackConfig, ReportPayload, ReportTransformer, UserIdentity } from './types'\n\nexport interface InternalConfig extends FeedbackConfig {\n fetchImpl?: typeof fetch\n}\n\ninterface WindowWithGlobal extends Window {\n mhosaicFeedback?: FeedbackApi\n}\n\nexport function createFeedback(config: InternalConfig): FeedbackApi & { _registerTransformer(fn: ReportTransformer): void } {\n const env = config.env ?? 'prod'\n const locale =\n config.locale ?? (typeof navigator !== 'undefined' ? navigator.language : undefined)\n const strings = resolveStrings(\n config.translations ?? {},\n locale !== undefined ? { locale } : {},\n )\n const capture = installCapture({\n ...(config.sanitizeUrl !== undefined && { sanitizeUrl: config.sanitizeUrl }),\n })\n const api = createApiClient({\n apiKey: config.apiKey,\n endpoint: config.endpoint,\n ...(config.fetchImpl !== undefined && { fetch: config.fetchImpl }),\n ...(config.beforeSend !== undefined && { beforeSend: config.beforeSend }),\n })\n\n let user: UserIdentity | undefined = config.user\n let metadata: Record<string, unknown> = config.metadata ?? {}\n const transformers: ReportTransformer[] = []\n\n const host = document.createElement('div')\n host.className = 'mhosaic-feedback'\n if (config.attachTo) {\n const attach = typeof config.attachTo === 'string' ? document.querySelector(config.attachTo) : config.attachTo\n attach?.appendChild(host)\n } else {\n document.body.appendChild(host)\n }\n\n async function buildAndSubmit(values: {\n description: string\n feedback_type?: string\n severity?: string\n synthetic?: boolean\n /** When set, used as-is and html2canvas is skipped. v0.6.0 manual upload. */\n screenshot?: Blob\n }) {\n // Auto-error reports skip screenshot capture: html2canvas is async/slow,\n // and the DOM is often in an inconsistent state when a JS error fires.\n // The captured ring buffer (errors, console, network) carries the signal.\n // Manual uploads (user dropped/pasted/annotated their own image) take\n // precedence over the html2canvas auto-grab.\n const manualScreenshot = values.screenshot\n const screenshot = values.synthetic\n ? undefined\n : (manualScreenshot ??\n (await takeScreenshot(document.body, {\n mask: ['.mhosaic-feedback', '[data-mfb-mask]'],\n })))\n const technical_context = capture.snapshot()\n // Surface identify()/setMetadata() values on the report. Without this\n // the host-supplied user identity and metadata sit in closure forever\n // and never reach the operator — a stack trace from a logged-in user\n // looks anonymous on the dashboard.\n if (user) technical_context.user = user\n if (metadata && Object.keys(metadata).length > 0) {\n technical_context.metadata = { ...metadata }\n }\n const payload: ReportPayload = {\n description: values.description,\n feedback_type: (values.feedback_type ?? 'bug') as ReportPayload['feedback_type'],\n severity: (values.severity ?? 'medium') as ReportPayload['severity'],\n env,\n page_url: window.location.href,\n user_agent: navigator.userAgent,\n capture_method: screenshot\n ? manualScreenshot\n ? 'manual'\n : 'html2canvas'\n : 'none',\n technical_context,\n }\n if (screenshot) payload.screenshot = screenshot\n if (values.synthetic) payload.synthetic = true\n let finalPayload: ReportPayload = payload\n for (const t of transformers) finalPayload = await t(finalPayload)\n try {\n const result = await api.submitReport(finalPayload)\n config.onSubmitSuccess?.(result)\n capture.clear()\n return result\n } catch (err) {\n const error = err instanceof Error ? err : new Error(String(err))\n config.onError?.(error)\n throw error\n }\n }\n\n const handle = mountWidget({\n host,\n strings,\n showFAB: config.showFAB ?? true,\n onSubmit: async (values) => { await buildAndSubmit(values) },\n })\n\n const instance: FeedbackApi & { _registerTransformer(fn: ReportTransformer): void } = {\n show() { handle.open() },\n hide() { handle.close() },\n open(opts) { handle.open(); void opts },\n async submit(partial) {\n return buildAndSubmit({\n description: partial.description,\n ...(partial.feedback_type !== undefined && { feedback_type: partial.feedback_type }),\n ...(partial.severity !== undefined && { severity: partial.severity }),\n ...(partial.synthetic !== undefined && { synthetic: partial.synthetic }),\n ...(partial.screenshot !== undefined && { screenshot: partial.screenshot }),\n })\n },\n identify(u) { user = u },\n setMetadata(kv) { metadata = { ...metadata, ...kv } },\n shutdown() {\n handle.dispose()\n capture.dispose()\n host.remove()\n // Only release the global if it still points at *us* — otherwise a\n // newer instance has taken ownership and we mustn't blow it away.\n const w = window as unknown as WindowWithGlobal\n if (w.mhosaicFeedback === instance) {\n delete w.mhosaicFeedback\n }\n },\n _registerTransformer(fn: ReportTransformer) { transformers.push(fn) },\n }\n\n // Expose the instance globally for ad-hoc callers (DevTools, docs pages,\n // help-widget integrations). The most-recently-created instance wins.\n ;(window as unknown as WindowWithGlobal).mhosaicFeedback = instance\n\n return instance\n}\n"],"mappings":"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AA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;;ANoDvB,mBAEI,OAAAE,MAFJ,QAAAC,aAAA;AA5BC,SAAS,YAAY,SAAoC;AAC9D,QAAM,SAAS,QAAQ,KAAK,aAAa,EAAE,MAAM,OAAO,CAAC;AACzD,QAAM,QAAQ,SAAS,cAAc,OAAO;AAC5C,QAAM,cAAc;AACpB,SAAO,YAAY,KAAK;AACxB,QAAM,aAAa,SAAS,cAAc,KAAK;AAC/C,SAAO,YAAY,UAAU;AAE7B,MAAI,eAAsB,EAAE,MAAM,OAAO,QAAQ,OAAO;AAExD,WAAS,SAAS,OAAc;AAC9B,mBAAe;AACf,WAAO,EAAE,MAAM,EAAE,MAAM,CAAC,GAAG,UAAU;AAAA,EACvC;AAEA,WAAS,KAAK,EAAE,MAAM,GAAqB;AACzC,UAAM,eAAe,YAAY,OAAO,WAAuB;AAC7D,eAAS,EAAE,MAAM,MAAM,QAAQ,aAAa,CAAC;AAC7C,UAAI;AACF,cAAM,QAAQ,SAAS,MAAM;AAC7B,iBAAS,EAAE,MAAM,MAAM,QAAQ,UAAU,CAAC;AAC1C,mBAAW,MAAM,SAAS,EAAE,MAAM,OAAO,QAAQ,OAAO,CAAC,GAAG,IAAI;AAAA,MAClE,SAAS,KAAK;AACZ,iBAAS,EAAE,MAAM,MAAM,QAAQ,SAAS,OAAO,eAAe,QAAQ,IAAI,UAAU,OAAO,GAAG,EAAE,CAAC;AAAA,MACnG;AAAA,IACF,GAAG,CAAC,CAAC;AAEL,WACE,gBAAAA,MAAA,YACG;AAAA,cAAQ,WACP,gBAAAD;AAAA,QAAC;AAAA;AAAA,UACC,OAAO,QAAQ,QAAQ,WAAW;AAAA,UAClC,SAAS,MAAM,SAAS,EAAE,GAAG,cAAc,MAAM,KAAK,CAAC;AAAA;AAAA,MACzD;AAAA,MAED,MAAM,QACL,gBAAAA;AAAA,QAAC;AAAA;AAAA,UACC,WAAW,MAAM,SAAS,EAAE,MAAM,OAAO,QAAQ,OAAO,CAAC;AAAA,UACzD,YAAY,QAAQ,QAAQ,YAAY;AAAA,UAExC,0BAAAA;AAAA,YAAC;AAAA;AAAA,cACC,SAAS,QAAQ;AAAA,cACjB,UAAU;AAAA,cACV,UAAU,MAAM,SAAS,EAAE,MAAM,OAAO,QAAQ,OAAO,CAAC;AAAA,cACxD,QAAQ,MAAM;AAAA,cACb,GAAI,MAAM,UAAU,UAAa,EAAE,cAAc,MAAM,MAAM;AAAA;AAAA,UAChE;AAAA;AAAA,MACF;AAAA,OAEJ;AAAA,EAEJ;AAEA,WAAS,YAAY;AAErB,SAAO;AAAA,IACL,OAAO;AAAE,eAAS,EAAE,GAAG,cAAc,MAAM,KAAK,CAAC;AAAA,IAAE;AAAA,IACnD,QAAQ;AAAE,eAAS,EAAE,GAAG,cAAc,MAAM,OAAO,QAAQ,OAAO,CAAC;AAAA,IAAE;AAAA,IACrE,UAAU;AACR,aAAO,MAAM,UAAU;AACvB,cAAQ,KAAK,YAAY;AAAA,IAC3B;AAAA,EACF;AACF;;;AOxEO,SAAS,eAAe,QAA6F;AAC1H,QAAM,MAAM,OAAO,OAAO;AAC1B,QAAM,SACJ,OAAO,WAAW,OAAO,cAAc,cAAc,UAAU,WAAW;AAC5E,QAAM,UAAU;AAAA,IACd,OAAO,gBAAgB,CAAC;AAAA,IACxB,WAAW,SAAY,EAAE,OAAO,IAAI,CAAC;AAAA,EACvC;AACA,QAAM,UAAU,eAAe;AAAA,IAC7B,GAAI,OAAO,gBAAgB,UAAa,EAAE,aAAa,OAAO,YAAY;AAAA,EAC5E,CAAC;AACD,QAAM,MAAM,gBAAgB;AAAA,IAC1B,QAAQ,OAAO;AAAA,IACf,UAAU,OAAO;AAAA,IACjB,GAAI,OAAO,cAAc,UAAa,EAAE,OAAO,OAAO,UAAU;AAAA,IAChE,GAAI,OAAO,eAAe,UAAa,EAAE,YAAY,OAAO,WAAW;AAAA,EACzE,CAAC;AAED,MAAI,OAAiC,OAAO;AAC5C,MAAI,WAAoC,OAAO,YAAY,CAAC;AAC5D,QAAM,eAAoC,CAAC;AAE3C,QAAM,OAAO,SAAS,cAAc,KAAK;AACzC,OAAK,YAAY;AACjB,MAAI,OAAO,UAAU;AACnB,UAAM,SAAS,OAAO,OAAO,aAAa,WAAW,SAAS,cAAc,OAAO,QAAQ,IAAI,OAAO;AACtG,YAAQ,YAAY,IAAI;AAAA,EAC1B,OAAO;AACL,aAAS,KAAK,YAAY,IAAI;AAAA,EAChC;AAEA,iBAAe,eAAe,QAO3B;AAMD,UAAM,mBAAmB,OAAO;AAChC,UAAM,aAAa,OAAO,YACtB,SACC,oBACE,MAAM,eAAe,SAAS,MAAM;AAAA,MACnC,MAAM,CAAC,qBAAqB,iBAAiB;AAAA,IAC/C,CAAC;AACP,UAAM,oBAAoB,QAAQ,SAAS;AAK3C,QAAI,KAAM,mBAAkB,OAAO;AACnC,QAAI,YAAY,OAAO,KAAK,QAAQ,EAAE,SAAS,GAAG;AAChD,wBAAkB,WAAW,EAAE,GAAG,SAAS;AAAA,IAC7C;AACA,UAAM,UAAyB;AAAA,MAC7B,aAAa,OAAO;AAAA,MACpB,eAAgB,OAAO,iBAAiB;AAAA,MACxC,UAAW,OAAO,YAAY;AAAA,MAC9B;AAAA,MACA,UAAU,OAAO,SAAS;AAAA,MAC1B,YAAY,UAAU;AAAA,MACtB,gBAAgB,aACZ,mBACE,WACA,gBACF;AAAA,MACJ;AAAA,IACF;AACA,QAAI,WAAY,SAAQ,aAAa;AACrC,QAAI,OAAO,UAAW,SAAQ,YAAY;AAC1C,QAAI,eAA8B;AAClC,eAAW,KAAK,aAAc,gBAAe,MAAM,EAAE,YAAY;AACjE,QAAI;AACF,YAAM,SAAS,MAAM,IAAI,aAAa,YAAY;AAClD,aAAO,kBAAkB,MAAM;AAC/B,cAAQ,MAAM;AACd,aAAO;AAAA,IACT,SAAS,KAAK;AACZ,YAAM,QAAQ,eAAe,QAAQ,MAAM,IAAI,MAAM,OAAO,GAAG,CAAC;AAChE,aAAO,UAAU,KAAK;AACtB,YAAM;AAAA,IACR;AAAA,EACF;AAEA,QAAM,SAAS,YAAY;AAAA,IACzB;AAAA,IACA;AAAA,IACA,SAAS,OAAO,WAAW;AAAA,IAC3B,UAAU,OAAO,WAAW;AAAE,YAAM,eAAe,MAAM;AAAA,IAAE;AAAA,EAC7D,CAAC;AAED,QAAM,WAAgF;AAAA,IACpF,OAAO;AAAE,aAAO,KAAK;AAAA,IAAE;AAAA,IACvB,OAAO;AAAE,aAAO,MAAM;AAAA,IAAE;AAAA,IACxB,KAAK,MAAM;AAAE,aAAO,KAAK;AAAG,WAAK;AAAA,IAAK;AAAA,IACtC,MAAM,OAAO,SAAS;AACpB,aAAO,eAAe;AAAA,QACpB,aAAa,QAAQ;AAAA,QACrB,GAAI,QAAQ,kBAAkB,UAAa,EAAE,eAAe,QAAQ,cAAc;AAAA,QAClF,GAAI,QAAQ,aAAa,UAAa,EAAE,UAAU,QAAQ,SAAS;AAAA,QACnE,GAAI,QAAQ,cAAc,UAAa,EAAE,WAAW,QAAQ,UAAU;AAAA,QACtE,GAAI,QAAQ,eAAe,UAAa,EAAE,YAAY,QAAQ,WAAW;AAAA,MAC3E,CAAC;AAAA,IACH;AAAA,IACA,SAAS,GAAG;AAAE,aAAO;AAAA,IAAE;AAAA,IACvB,YAAY,IAAI;AAAE,iBAAW,EAAE,GAAG,UAAU,GAAG,GAAG;AAAA,IAAE;AAAA,IACpD,WAAW;AACT,aAAO,QAAQ;AACf,cAAQ,QAAQ;AAChB,WAAK,OAAO;AAGZ,YAAM,IAAI;AACV,UAAI,EAAE,oBAAoB,UAAU;AAClC,eAAO,EAAE;AAAA,MACX;AAAA,IACF;AAAA,IACA,qBAAqB,IAAuB;AAAE,mBAAa,KAAK,EAAE;AAAA,IAAE;AAAA,EACtE;AAIC,EAAC,OAAuC,kBAAkB;AAE3D,SAAO;AACT;","names":["useEffect","useRef","useState","jsx","jsx","jsxs","useState","useRef","useEffect","useEffect","useRef","jsx","jsxs","jsx","jsxs"]}
1
+ {"version":3,"sources":["../src/api/client.ts","../src/capture/urlSanitizer.ts","../src/capture/device.ts","../src/capture/console.ts","../src/capture/network.ts","../src/capture/errors.ts","../src/capture/performance.ts","../src/capture/ringBuffer.ts","../src/capture/index.ts","../src/screenshot/index.ts","../src/widget/i18n.ts","../src/widget/mount.tsx","../src/widget/Fab.tsx","../src/widget/Form.tsx","../src/widget/Annotator.tsx","../src/widget/screenshot-utils.ts","../src/widget/Modal.tsx","../src/widget/styles.ts","../src/core.ts"],"sourcesContent":["import type { ReportPayload, SubmittedReport } from '../types'\n\nexport interface ApiClientOptions {\n apiKey: string\n endpoint: string\n fetch?: typeof fetch\n beforeSend?: (payload: ReportPayload) => ReportPayload | false | Promise<ReportPayload | false>\n}\n\nexport interface ApiClient {\n submitReport(payload: ReportPayload): Promise<SubmittedReport>\n}\n\nconst SCALAR_FIELDS: Array<keyof ReportPayload> = [\n 'description', 'feedback_type', 'severity', 'env', 'page_url', 'user_agent', 'capture_method',\n]\n\nexport function createApiClient(options: ApiClientOptions): ApiClient {\n // No silent fallback to a hardcoded host — a misconfigured deploy used\n // to leak reports to https://core.mhosaic.com (which doesn't even\n // resolve). Failing fast at construction makes the misconfig obvious.\n const endpoint = (options.endpoint ?? '').replace(/\\/+$/, '')\n if (!endpoint) {\n throw new Error(\n '[mhosaic-feedback] `endpoint` is required (e.g. \"https://feedback.example.com\").',\n )\n }\n const fetcher = options.fetch ?? globalThis.fetch\n\n async function submitReport(input: ReportPayload): Promise<SubmittedReport> {\n let payload: ReportPayload | false = input\n if (options.beforeSend) payload = await options.beforeSend(input)\n if (payload === false) throw new Error('Submission cancelled by beforeSend')\n\n const form = new FormData()\n for (const field of SCALAR_FIELDS) {\n form.append(field, String(payload[field]))\n }\n form.append('technical_context', JSON.stringify(payload.technical_context))\n if (payload.screenshot) form.append('screenshot', payload.screenshot, 'screenshot.png')\n // Only emit `synthetic` when truthy — a `false` value would still trigger\n // the BooleanField parser on the backend, which is fine, but omitting it\n // keeps the request shape byte-identical for existing curated submissions.\n if (payload.synthetic) form.append('synthetic', 'true')\n\n const response = await fetcher(`${endpoint}/api/feedback/v1/reports/`, {\n method: 'POST',\n headers: { Authorization: `Bearer ${options.apiKey}` },\n body: form,\n })\n if (!response.ok) {\n const text = await response.text().catch(() => '')\n throw new Error(`Feedback submit failed: ${response.status} ${text}`)\n }\n return response.json() as Promise<SubmittedReport>\n }\n\n return { submitReport }\n}\n","const SENSITIVE = /token|key|password|secret|auth|session|sig/i\n\nexport function sanitizeUrl(url: string): string {\n try {\n // Accept absolute URLs or root-relative paths; reject everything else\n const isAbsolute = /^https?:\\/\\//i.test(url)\n const isRootRelative = url.startsWith('/')\n if (!isAbsolute && !isRootRelative) return url\n\n const base = typeof window !== 'undefined' ? window.location.origin : 'http://localhost'\n const u = new URL(url, base)\n const clean = new URLSearchParams()\n u.searchParams.forEach((value, name) => {\n clean.set(name, SENSITIVE.test(name) ? '[redacted]' : value)\n })\n u.search = clean.toString()\n return u.toString()\n } catch {\n return url\n }\n}\n","import type { DeviceContext } from '../types'\n\nexport function collectDevice(): DeviceContext {\n const nav = navigator as Navigator & { connection?: { effectiveType?: string }; deviceMemory?: number }\n const connection = nav.connection?.effectiveType\n const deviceMemory = nav.deviceMemory\n const referrer = document.referrer || undefined\n return {\n viewport: { w: window.innerWidth, h: window.innerHeight, dpr: window.devicePixelRatio || 1 },\n screen: { w: window.screen.width, h: window.screen.height },\n platform: nav.platform,\n language: nav.language,\n timezone: Intl.DateTimeFormat().resolvedOptions().timeZone,\n timezoneOffset: new Date().getTimezoneOffset(),\n ...(connection !== undefined && { connection }),\n online: nav.onLine,\n ...(deviceMemory !== undefined && { deviceMemory }),\n hardwareConcurrency: nav.hardwareConcurrency,\n ...(referrer !== undefined && { referrer }),\n title: document.title,\n pathname: window.location.pathname,\n }\n}\n","import type { RingBuffer } from './ringBuffer'\nimport type { ConsoleEntry } from '../types'\n\ntype ConsoleLevel = 'log' | 'info' | 'warn' | 'error' | 'debug'\n\nfunction safeStringify(arg: unknown): string {\n if (arg == null) return String(arg)\n if (typeof arg === 'string') return arg\n if (typeof arg === 'number' || typeof arg === 'boolean') return String(arg)\n if (arg instanceof Error) return `${arg.name}: ${arg.message}`\n if (arg instanceof Element) return `<${arg.tagName.toLowerCase()}>`\n try {\n return JSON.stringify(arg, (_k, v) => (typeof v === 'bigint' ? v.toString() : v))\n } catch {\n try { return String(arg) } catch { return '[unserializable]' }\n }\n}\n\nexport function installConsolePatch(buffer: RingBuffer<ConsoleEntry>): () => void {\n const levels: ConsoleLevel[] = ['log', 'info', 'warn', 'error', 'debug']\n const originals: Partial<Record<ConsoleLevel, (...args: unknown[]) => void>> = {}\n for (const level of levels) {\n const original = console[level] as ((...args: unknown[]) => void) | undefined\n if (typeof original !== 'function') continue\n originals[level] = original\n console[level] = function patched(...args: unknown[]) {\n try {\n const message = args.map(safeStringify).join(' ').slice(0, 2000)\n const entry: ConsoleEntry = { level, message, ts: Date.now() }\n if (level === 'error') {\n const stack = new Error().stack\n if (stack) entry.stack = stack.split('\\n').slice(2, 8).join('\\n')\n }\n buffer.push(entry)\n } catch { /* never break console */ }\n original.apply(console, args)\n }\n }\n return () => {\n for (const [level, fn] of Object.entries(originals)) {\n (console as unknown as Record<string, (...args: unknown[]) => void>)[level] = fn\n }\n }\n}\n","import type { RingBuffer } from './ringBuffer'\nimport type { NetworkEntry } from '../types'\n\nexport function installFetchPatch(buffer: RingBuffer<NetworkEntry>, sanitize: (url: string) => string): () => void {\n if (typeof window === 'undefined' || typeof window.fetch !== 'function') return () => {}\n const original = window.fetch.bind(window)\n window.fetch = async function patched(input: RequestInfo | URL, init?: RequestInit) {\n const start = performance.now()\n const url = typeof input === 'string' ? input : input instanceof URL ? input.toString() : input.url\n const method = (init?.method || (input instanceof Request ? input.method : 'GET')).toUpperCase()\n try {\n const response = await original(input, init)\n buffer.push({ url: sanitize(url), method, status: response.status, durationMs: Math.round(performance.now() - start), ts: Date.now() })\n return response\n } catch (err) {\n buffer.push({\n url: sanitize(url), method, status: 0,\n durationMs: Math.round(performance.now() - start),\n ts: Date.now(),\n error: err instanceof Error ? err.message : String(err),\n })\n throw err\n }\n }\n return () => { window.fetch = original }\n}\n\nexport function installXhrPatch(buffer: RingBuffer<NetworkEntry>, sanitize: (url: string) => string): () => void {\n if (typeof window === 'undefined' || typeof window.XMLHttpRequest !== 'function') return () => {}\n const Original = window.XMLHttpRequest\n const originalOpen = Original.prototype.open\n const originalSend = Original.prototype.send\n\n Original.prototype.open = function patchedOpen(this: XMLHttpRequest & { __mfb?: { method: string; url: string; start: number } }, method: string, url: string | URL) {\n this.__mfb = { method: method.toUpperCase(), url: typeof url === 'string' ? url : url.toString(), start: performance.now() }\n return originalOpen.apply(this, arguments as unknown as Parameters<typeof originalOpen>)\n }\n\n Original.prototype.send = function patchedSend(this: XMLHttpRequest & { __mfb?: { method: string; url: string; start: number } }, body?: Document | XMLHttpRequestBodyInit | null) {\n this.addEventListener('loadend', () => {\n try {\n const ctx = this.__mfb\n if (!ctx) return\n buffer.push({\n url: sanitize(ctx.url),\n method: ctx.method,\n status: this.status,\n durationMs: Math.round(performance.now() - ctx.start),\n ts: Date.now(),\n })\n } catch { /* noop */ }\n })\n return originalSend.call(this, body ?? null)\n }\n\n return () => {\n Original.prototype.open = originalOpen\n Original.prototype.send = originalSend\n }\n}\n","import type { RingBuffer } from './ringBuffer'\nimport type { ErrorEntry } from '../types'\n\nexport function installErrorHandlers(buffer: RingBuffer<ErrorEntry>): () => void {\n if (typeof window === 'undefined') return () => {}\n const onError = (e: ErrorEvent) => {\n const stack = e.error instanceof Error ? e.error.stack : undefined\n buffer.push({\n message: e.message || 'Unknown error',\n ...(stack !== undefined && { stack }),\n ts: Date.now(),\n source: 'window.error',\n })\n }\n const onRejection = (e: PromiseRejectionEvent) => {\n const reason = e.reason\n const message =\n reason instanceof Error ? reason.message :\n typeof reason === 'string' ? reason :\n (() => { try { return JSON.stringify(reason) } catch { return String(reason) } })()\n const stack = reason instanceof Error ? reason.stack : undefined\n buffer.push({\n message,\n ...(stack !== undefined && { stack }),\n ts: Date.now(),\n source: 'unhandledrejection',\n })\n }\n window.addEventListener('error', onError)\n window.addEventListener('unhandledrejection', onRejection)\n return () => {\n window.removeEventListener('error', onError)\n window.removeEventListener('unhandledrejection', onRejection)\n }\n}\n","export interface PerformanceSnapshot {\n navigation?: { type: string; duration: number }\n longTasks: { duration: number; startTime: number }[]\n slowResources: { name: string; duration: number; initiatorType: string }[]\n}\n\nexport function createPerformanceCollector(slowResourceMs = 1000) {\n const longTasks: PerformanceSnapshot['longTasks'] = []\n const slowResources: PerformanceSnapshot['slowResources'] = []\n let observer: PerformanceObserver | null = null\n\n if (typeof PerformanceObserver !== 'undefined') {\n try {\n observer = new PerformanceObserver((list) => {\n for (const entry of list.getEntries()) {\n if (entry.entryType === 'longtask') {\n longTasks.push({ duration: entry.duration, startTime: entry.startTime })\n while (longTasks.length > 20) longTasks.shift()\n } else if (entry.entryType === 'resource') {\n const e = entry as PerformanceResourceTiming\n if (e.duration > slowResourceMs) {\n slowResources.push({ name: e.name, duration: e.duration, initiatorType: e.initiatorType })\n while (slowResources.length > 20) slowResources.shift()\n }\n }\n }\n })\n observer.observe({ entryTypes: ['longtask', 'resource'] })\n } catch { /* unsupported */ }\n }\n\n return {\n snapshot(): PerformanceSnapshot {\n const nav = typeof performance !== 'undefined' ? performance.getEntriesByType('navigation')[0] as PerformanceNavigationTiming | undefined : undefined\n const navigation = nav ? { type: nav.type, duration: nav.duration } : undefined\n return {\n ...(navigation !== undefined && { navigation }),\n longTasks: longTasks.slice(),\n slowResources: slowResources.slice(),\n }\n },\n dispose() { observer?.disconnect() },\n }\n}\n","export class RingBuffer<T> {\n private items: T[] = []\n constructor(private readonly max: number) {}\n\n push(item: T): void {\n this.items.push(item)\n while (this.items.length > this.max) this.items.shift()\n }\n\n snapshot(): T[] {\n return this.items.slice()\n }\n\n clear(): void {\n this.items.length = 0\n }\n}\n","import { sanitizeUrl } from './urlSanitizer'\nimport { collectDevice } from './device'\nimport { installConsolePatch } from './console'\nimport { installFetchPatch, installXhrPatch } from './network'\nimport { installErrorHandlers } from './errors'\nimport { createPerformanceCollector } from './performance'\nimport { RingBuffer } from './ringBuffer'\nimport type { CapturedContext, ConsoleEntry, ErrorEntry, NetworkEntry } from '../types'\n\nexport interface CaptureOptions {\n sanitizeUrl?: (url: string) => string\n maxConsole?: number\n maxNetwork?: number\n maxErrors?: number\n}\n\nexport interface CaptureHandle {\n snapshot(): CapturedContext\n clear(): void\n dispose(): void\n}\n\nexport function installCapture(options: CaptureOptions = {}): CaptureHandle {\n const { maxConsole = 50, maxNetwork = 50, maxErrors = 20 } = options\n const sanitize = options.sanitizeUrl ?? sanitizeUrl\n\n const consoleBuf = new RingBuffer<ConsoleEntry>(maxConsole)\n const networkBuf = new RingBuffer<NetworkEntry>(maxNetwork)\n const errorBuf = new RingBuffer<ErrorEntry>(maxErrors)\n\n const uninstallConsole = installConsolePatch(consoleBuf)\n const uninstallFetch = installFetchPatch(networkBuf, sanitize)\n const uninstallXhr = installXhrPatch(networkBuf, sanitize)\n const uninstallErrors = installErrorHandlers(errorBuf)\n const perf = createPerformanceCollector()\n\n return {\n snapshot(): CapturedContext {\n return {\n consoleLogs: consoleBuf.snapshot(),\n networkRequests: networkBuf.snapshot(),\n errors: errorBuf.snapshot(),\n device: collectDevice(),\n capturedAt: Date.now(),\n }\n },\n clear() {\n consoleBuf.clear(); networkBuf.clear(); errorBuf.clear()\n },\n dispose() {\n uninstallConsole(); uninstallFetch(); uninstallXhr(); uninstallErrors()\n perf.dispose()\n },\n }\n}\n","export function isMaskedElement(el: Element): boolean {\n return el.hasAttribute('data-mfb-mask') || el.classList.contains('mfb-mask')\n}\n\nexport function prepareMaskMatcher(selectors: string[]): (el: Element) => boolean {\n const joined = selectors.join(',').trim()\n if (!joined) return isMaskedElement\n return (el: Element) => isMaskedElement(el) || el.matches(joined)\n}\n\nexport interface ScreenshotOptions {\n mask?: string[]\n maxBytes?: number\n}\n\nexport async function takeScreenshot(target: Element, options: ScreenshotOptions = {}): Promise<Blob | null> {\n if (typeof document === 'undefined') return null\n try {\n const html2canvas = (await import('html2canvas-pro')).default\n const matcher = prepareMaskMatcher(options.mask ?? [])\n const canvas = await html2canvas(target as HTMLElement, {\n ignoreElements: (el) => matcher(el),\n useCORS: true,\n logging: false,\n backgroundColor: null,\n })\n return await new Promise<Blob | null>((resolve) => canvas.toBlob(resolve, 'image/png'))\n } catch {\n return null\n }\n}\n","export const DEFAULT_STRINGS = {\n 'fab.label': 'Send feedback',\n 'form.title': 'Send feedback',\n 'form.description.label': 'What happened?',\n 'form.description.placeholder': 'Describe the issue or idea in one or two sentences.',\n 'form.type.label': 'Type',\n 'form.severity.label': 'Severity',\n 'form.submit': 'Send',\n 'form.cancel': 'Cancel',\n 'form.close': 'Close',\n 'form.submitting': 'Sending…',\n 'form.success': 'Thanks — your feedback was sent.',\n 'form.error': 'Could not send. Please try again.',\n 'form.screenshot.label': 'Screenshot',\n 'form.screenshot.cta_click': 'Click',\n 'form.screenshot.cta_rest': 'drop, or paste an image',\n 'form.screenshot.formats': 'PNG, JPEG or WebP — up to 10 MB',\n 'form.screenshot.remove': 'Remove screenshot',\n 'form.screenshot.annotate': 'Annotate',\n 'form.screenshot.error_type': 'Unsupported file type. Use PNG, JPEG or WebP.',\n 'form.screenshot.error_size': 'File too large (max {max} MB).',\n 'form.context.label': 'Page',\n 'type.bug': 'Bug',\n 'type.feature': 'Feature request',\n 'type.question': 'Question',\n 'type.praise': 'Praise',\n 'type.typo': 'Typo',\n 'severity.blocker': 'Blocker',\n 'severity.high': 'High',\n 'severity.medium': 'Medium',\n 'severity.low': 'Low',\n 'annotator.title': 'Annotate screenshot',\n 'annotator.tool.rectangle': 'Rectangle',\n 'annotator.tool.arrow': 'Arrow',\n 'annotator.tool.freehand': 'Freehand',\n 'annotator.tool.text': 'Text',\n 'annotator.text_prompt': 'Enter text:',\n 'annotator.undo': 'Undo',\n 'annotator.clear': 'Clear all',\n 'annotator.count_suffix': 'annotations',\n 'annotator.loading': 'Loading…',\n 'annotator.apply': 'Apply',\n 'annotator.applying': 'Applying…',\n}\n\nexport type StringKey = keyof typeof DEFAULT_STRINGS\n\nconst FRENCH_STRINGS: Record<StringKey, string> = {\n 'fab.label': 'Envoyer un commentaire',\n 'form.title': 'Envoyer un commentaire',\n 'form.description.label': 'Qu’est-il arrivé ?',\n 'form.description.placeholder': 'Décrivez le problème ou l’idée en une ou deux phrases.',\n 'form.type.label': 'Type',\n 'form.severity.label': 'Sévérité',\n 'form.submit': 'Envoyer',\n 'form.cancel': 'Annuler',\n 'form.close': 'Fermer',\n 'form.submitting': 'Envoi…',\n 'form.success': 'Merci — votre commentaire a été envoyé.',\n 'form.error': 'Échec d’envoi. Veuillez réessayer.',\n 'form.screenshot.label': 'Capture d’écran',\n 'form.screenshot.cta_click': 'Cliquez',\n 'form.screenshot.cta_rest': 'déposez ou collez une image',\n 'form.screenshot.formats': 'PNG, JPEG ou WebP — jusqu’à 10 Mo',\n 'form.screenshot.remove': 'Retirer la capture',\n 'form.screenshot.annotate': 'Annoter',\n 'form.screenshot.error_type': 'Format non supporté. Utilisez PNG, JPEG ou WebP.',\n 'form.screenshot.error_size': 'Fichier trop volumineux (max {max} Mo).',\n 'form.context.label': 'Page',\n 'type.bug': 'Bogue',\n 'type.feature': 'Suggestion',\n 'type.question': 'Question',\n 'type.praise': 'Compliment',\n 'type.typo': 'Coquille',\n 'severity.blocker': 'Bloquant',\n 'severity.high': 'Élevée',\n 'severity.medium': 'Moyenne',\n 'severity.low': 'Faible',\n 'annotator.title': 'Annoter la capture',\n 'annotator.tool.rectangle': 'Rectangle',\n 'annotator.tool.arrow': 'Flèche',\n 'annotator.tool.freehand': 'Dessin libre',\n 'annotator.tool.text': 'Texte',\n 'annotator.text_prompt': 'Entrez le texte :',\n 'annotator.undo': 'Annuler',\n 'annotator.clear': 'Tout effacer',\n 'annotator.count_suffix': 'annotations',\n 'annotator.loading': 'Chargement…',\n 'annotator.apply': 'Appliquer',\n 'annotator.applying': 'Application…',\n}\n\nconst LOCALE_PACKS: Record<string, Record<StringKey, string>> = {\n fr: FRENCH_STRINGS,\n}\n\ninterface ResolveOptions {\n locale?: string\n}\n\nfunction packFor(locale: string | undefined): Record<StringKey, string> | null {\n if (!locale) return null\n // Match the language subtag only (fr-CA, fr-FR → fr).\n const tag = locale.toLowerCase().split(/[-_]/)[0]!\n return LOCALE_PACKS[tag] ?? null\n}\n\nexport function resolveStrings(\n overrides: Record<string, string>,\n options: ResolveOptions = {},\n): Record<StringKey, string> {\n const localePack = packFor(options.locale) ?? {}\n return {\n ...DEFAULT_STRINGS,\n ...localePack,\n ...overrides,\n } as Record<StringKey, string>\n}\n","import { h, render } from 'preact'\nimport { useCallback, useState } from 'preact/hooks'\n\nimport { Fab } from './Fab'\nimport { Form, type FormValues } from './Form'\nimport { Modal } from './Modal'\nimport { WIDGET_STYLES } from './styles'\nimport type { StringKey } from './i18n'\n\nexport interface MountOptions {\n host: HTMLElement\n strings: Record<StringKey, string>\n showFAB: boolean\n onSubmit: (values: FormValues) => Promise<void>\n}\n\nexport interface MountHandle {\n open(): void\n close(): void\n dispose(): void\n}\n\ntype State = { open: boolean; status: 'idle' | 'submitting' | 'error' | 'success'; error?: string }\n\nexport function mountWidget(options: MountOptions): MountHandle {\n const shadow = options.host.attachShadow({ mode: 'open' })\n const style = document.createElement('style')\n style.textContent = WIDGET_STYLES\n shadow.appendChild(style)\n const mountPoint = document.createElement('div')\n shadow.appendChild(mountPoint)\n\n let currentState: State = { open: false, status: 'idle' }\n\n function rerender(state: State) {\n currentState = state\n render(h(Root, { state }), mountPoint)\n }\n\n function Root({ state }: { state: State }) {\n const handleSubmit = useCallback(async (values: FormValues) => {\n rerender({ open: true, status: 'submitting' })\n try {\n await options.onSubmit(values)\n rerender({ open: true, status: 'success' })\n setTimeout(() => rerender({ open: false, status: 'idle' }), 1200)\n } catch (err) {\n rerender({ open: true, status: 'error', error: err instanceof Error ? err.message : String(err) })\n }\n }, [])\n\n return (\n <>\n {options.showFAB && (\n <Fab\n label={options.strings['fab.label']}\n onClick={() => rerender({ ...currentState, open: true })}\n />\n )}\n {state.open && (\n <Modal\n onDismiss={() => rerender({ open: false, status: 'idle' })}\n closeLabel={options.strings['form.close']}\n >\n <Form\n strings={options.strings}\n onSubmit={handleSubmit}\n onCancel={() => rerender({ open: false, status: 'idle' })}\n status={state.status}\n {...(state.error !== undefined && { errorMessage: state.error })}\n />\n </Modal>\n )}\n </>\n )\n }\n\n rerender(currentState)\n\n return {\n open() { rerender({ ...currentState, open: true }) },\n close() { rerender({ ...currentState, open: false, status: 'idle' }) },\n dispose() {\n render(null, mountPoint)\n options.host.innerHTML = ''\n },\n }\n}\n","import { h } from 'preact'\n\ninterface FabProps {\n label: string\n onClick: () => void\n}\n\nexport function Fab({ label, onClick }: FabProps) {\n return (\n <button type=\"button\" class=\"fab\" aria-label={label} onClick={onClick}>\n 💬\n </button>\n )\n}\n","import { h } from 'preact'\nimport { useEffect, useRef, useState } from 'preact/hooks'\n\nimport type { FeedbackSeverity, FeedbackType } from '../types'\nimport { Annotator } from './Annotator'\nimport type { StringKey } from './i18n'\nimport { truncateUrl, validateScreenshotFile } from './screenshot-utils'\n\nexport type FormStatus = 'idle' | 'submitting' | 'error' | 'success'\n\nexport interface FormValues {\n description: string\n feedback_type: FeedbackType\n severity: FeedbackSeverity\n /** When set, the host should send this blob instead of running html2canvas. */\n screenshot?: Blob\n}\n\ninterface FormProps {\n strings: Record<StringKey, string>\n onSubmit: (values: FormValues) => void\n onCancel: () => void\n status: FormStatus\n errorMessage?: string\n}\n\nconst TYPES: FeedbackType[] = ['bug', 'feature', 'question', 'praise', 'typo']\nconst SEVERITIES: FeedbackSeverity[] = ['blocker', 'high', 'medium', 'low']\n\nexport function Form({ strings, onSubmit, onCancel, status, errorMessage }: FormProps) {\n const [description, setDescription] = useState('')\n const [feedbackType, setFeedbackType] = useState<FeedbackType>('bug')\n const [severity, setSeverity] = useState<FeedbackSeverity>('medium')\n const [localError, setLocalError] = useState('')\n const [screenshotBlob, setScreenshotBlob] = useState<Blob | null>(null)\n const [screenshotPreview, setScreenshotPreview] = useState<string | null>(null)\n const [isDragOver, setIsDragOver] = useState(false)\n const [annotatorOpen, setAnnotatorOpen] = useState(false)\n const fileInputRef = useRef<HTMLInputElement | null>(null)\n const dropZoneRef = useRef<HTMLDivElement | null>(null)\n\n const submitting = status === 'submitting'\n const submitLabel = submitting ? strings['form.submitting'] : strings['form.submit']\n const pageUrl = typeof window !== 'undefined' ? window.location.href : ''\n\n // Revoke any object URL when the preview changes or the form unmounts.\n useEffect(() => {\n return () => {\n if (screenshotPreview) URL.revokeObjectURL(screenshotPreview)\n }\n }, [screenshotPreview])\n\n const acceptFile = (file: File | Blob) => {\n setLocalError('')\n if (file instanceof File) {\n const err = validateScreenshotFile(file)\n if (err) {\n setLocalError(\n err.kind === 'type'\n ? strings['form.screenshot.error_type']\n : strings['form.screenshot.error_size'].replace('{max}', String(err.maxMb)),\n )\n return\n }\n }\n if (screenshotPreview) URL.revokeObjectURL(screenshotPreview)\n setScreenshotBlob(file)\n setScreenshotPreview(URL.createObjectURL(file))\n }\n\n const clearScreenshot = () => {\n if (screenshotPreview) URL.revokeObjectURL(screenshotPreview)\n setScreenshotPreview(null)\n setScreenshotBlob(null)\n setLocalError('')\n if (fileInputRef.current) fileInputRef.current.value = ''\n }\n\n const handleFileInputChange = (e: Event) => {\n const file = (e.target as HTMLInputElement).files?.[0]\n if (file) acceptFile(file)\n }\n\n const handleDragOver = (e: DragEvent) => {\n e.preventDefault()\n e.stopPropagation()\n setIsDragOver(true)\n }\n const handleDragLeave = (e: DragEvent) => {\n e.preventDefault()\n e.stopPropagation()\n if (e.currentTarget === e.target) setIsDragOver(false)\n }\n const handleDrop = (e: DragEvent) => {\n e.preventDefault()\n e.stopPropagation()\n setIsDragOver(false)\n const file = e.dataTransfer?.files?.[0]\n if (file) acceptFile(file)\n }\n\n // Clipboard paste, scoped to the dropzone — so we don't hijack paste from\n // textareas elsewhere in the page or in our own description field.\n useEffect(() => {\n const zone = dropZoneRef.current\n if (!zone) return\n const onPaste = (e: ClipboardEvent) => {\n const items = e.clipboardData?.items\n if (!items) return\n for (const item of Array.from(items)) {\n if (item.kind === 'file' && item.type.startsWith('image/')) {\n const file = item.getAsFile()\n if (file) {\n e.preventDefault()\n acceptFile(file)\n return\n }\n }\n }\n }\n zone.addEventListener('paste', onPaste)\n return () => zone.removeEventListener('paste', onPaste)\n // eslint-disable-next-line react-hooks/exhaustive-deps\n }, [screenshotPreview])\n\n const handleAnnotated = (annotated: Blob) => {\n if (screenshotPreview) URL.revokeObjectURL(screenshotPreview)\n setScreenshotBlob(annotated)\n setScreenshotPreview(URL.createObjectURL(annotated))\n setAnnotatorOpen(false)\n }\n\n const handleSubmit = (e: Event) => {\n e.preventDefault()\n if (!description.trim()) {\n setLocalError(strings['form.description.placeholder'])\n return\n }\n setLocalError('')\n const values: FormValues = {\n description: description.trim(),\n feedback_type: feedbackType,\n severity,\n }\n if (screenshotBlob) values.screenshot = screenshotBlob\n onSubmit(values)\n }\n\n return (\n <form onSubmit={handleSubmit}>\n <h2>{strings['form.title']}</h2>\n\n <div class=\"field\">\n <label for=\"mfb-desc\">{strings['form.description.label']}</label>\n <textarea\n id=\"mfb-desc\"\n value={description}\n placeholder={strings['form.description.placeholder']}\n onInput={(e) => setDescription((e.target as HTMLTextAreaElement).value)}\n />\n </div>\n\n <div class=\"row\">\n <div class=\"field\">\n <label for=\"mfb-type\">{strings['form.type.label']}</label>\n <select\n id=\"mfb-type\"\n value={feedbackType}\n onChange={(e) => setFeedbackType((e.target as HTMLSelectElement).value as FeedbackType)}\n >\n {TYPES.map((t) => <option value={t}>{strings[`type.${t}` as StringKey]}</option>)}\n </select>\n </div>\n <div class=\"field\">\n <label for=\"mfb-sev\">{strings['form.severity.label']}</label>\n <select\n id=\"mfb-sev\"\n value={severity}\n onChange={(e) => setSeverity((e.target as HTMLSelectElement).value as FeedbackSeverity)}\n >\n {SEVERITIES.map((s) => <option value={s}>{strings[`severity.${s}` as StringKey]}</option>)}\n </select>\n </div>\n </div>\n\n <div class=\"field\">\n <label>{strings['form.screenshot.label']}</label>\n <input\n ref={fileInputRef}\n type=\"file\"\n accept=\"image/png,image/jpeg,image/webp\"\n class=\"mfb-sr-only\"\n onChange={handleFileInputChange}\n aria-hidden=\"true\"\n tabIndex={-1}\n />\n {screenshotPreview ? (\n <div class=\"screenshot-preview\">\n <img src={screenshotPreview} alt=\"\" />\n <button\n type=\"button\"\n class=\"screenshot-remove\"\n onClick={clearScreenshot}\n aria-label={strings['form.screenshot.remove']}\n >\n ×\n </button>\n <button\n type=\"button\"\n class=\"btn screenshot-annotate\"\n onClick={() => setAnnotatorOpen(true)}\n >\n {strings['form.screenshot.annotate']}\n </button>\n </div>\n ) : (\n <div\n ref={dropZoneRef}\n class={`screenshot-dropzone ${isDragOver ? 'is-dragover' : ''}`}\n tabIndex={0}\n role=\"button\"\n aria-label={strings['form.screenshot.label']}\n onClick={() => fileInputRef.current?.click()}\n onKeyDown={(e) => {\n if (e.key === 'Enter' || e.key === ' ') {\n e.preventDefault()\n fileInputRef.current?.click()\n }\n }}\n onDragOver={handleDragOver}\n onDragLeave={handleDragLeave}\n onDrop={handleDrop}\n >\n <div class=\"screenshot-cta\">\n <strong>{strings['form.screenshot.cta_click']}</strong>\n {', '}\n {strings['form.screenshot.cta_rest']}\n </div>\n <div class=\"screenshot-formats\">{strings['form.screenshot.formats']}</div>\n </div>\n )}\n </div>\n\n {pageUrl && (\n <div class=\"page-context\" title={pageUrl}>\n <span class=\"page-context-label\">{strings['form.context.label']}</span>\n <span class=\"page-context-url\">{truncateUrl(pageUrl, 90)}</span>\n </div>\n )}\n\n {localError && <div class=\"error\">{localError}</div>}\n {status === 'error' && errorMessage && <div class=\"error\">{errorMessage}</div>}\n {status === 'success' && <div class=\"success\">{strings['form.success']}</div>}\n\n <div class=\"actions\">\n <button type=\"button\" class=\"btn\" onClick={onCancel} disabled={submitting}>{strings['form.cancel']}</button>\n <button type=\"submit\" class=\"btn btn--primary\" disabled={submitting}>{submitLabel}</button>\n </div>\n\n {annotatorOpen && screenshotBlob && (\n <Annotator\n imageBlob={screenshotBlob}\n strings={strings}\n onCancel={() => setAnnotatorOpen(false)}\n onSave={handleAnnotated}\n />\n )}\n </form>\n )\n}\n","/**\n * Annotator — minimal screenshot annotation modal (v0.6.0).\n *\n * Ported from thepnr-platform's FeedbackAnnotator. Custom canvas, no\n * external lib. Supports rectangle, arrow, freehand and text shapes with\n * undo / clear-all / color-picker. The Save call rasterizes the original\n * image + every shape onto a fresh canvas and returns a PNG Blob.\n *\n * Inline SVG icons (no lucide) and inline CSS classes (the widget shadow\n * root sees the styles in styles.ts).\n */\n\nimport { h } from 'preact'\nimport { useEffect, useRef, useState } from 'preact/hooks'\n\nimport type { StringKey } from './i18n'\n\ntype Tool = 'rectangle' | 'arrow' | 'freehand' | 'text'\n\ninterface BaseShape {\n color: string\n lineWidth: number\n}\n\ninterface RectShape extends BaseShape {\n kind: 'rectangle'\n x: number\n y: number\n w: number\n h: number\n}\n\ninterface ArrowShape extends BaseShape {\n kind: 'arrow'\n x1: number\n y1: number\n x2: number\n y2: number\n}\n\ninterface FreehandShape extends BaseShape {\n kind: 'freehand'\n points: Array<{ x: number; y: number }>\n}\n\ninterface TextShape extends BaseShape {\n kind: 'text'\n x: number\n y: number\n text: string\n fontSize: number\n}\n\ntype Shape = RectShape | ArrowShape | FreehandShape | TextShape\n\nconst COLORS: string[] = ['#ef4444', '#f59e0b', '#10b981', '#3b82f6', '#ffffff']\n\n// ---------------------------------------------------------------------------\n// Drawing helpers\n// ---------------------------------------------------------------------------\n\nfunction drawShape(ctx: CanvasRenderingContext2D, shape: Shape) {\n ctx.save()\n ctx.strokeStyle = shape.color\n ctx.fillStyle = shape.color\n ctx.lineWidth = shape.lineWidth\n ctx.lineCap = 'round'\n ctx.lineJoin = 'round'\n\n if (shape.kind === 'rectangle') {\n ctx.strokeRect(shape.x, shape.y, shape.w, shape.h)\n } else if (shape.kind === 'arrow') {\n drawArrow(ctx, shape.x1, shape.y1, shape.x2, shape.y2)\n } else if (shape.kind === 'freehand') {\n if (shape.points.length < 2) {\n ctx.restore()\n return\n }\n ctx.beginPath()\n ctx.moveTo(shape.points[0]!.x, shape.points[0]!.y)\n for (let i = 1; i < shape.points.length; i++) {\n ctx.lineTo(shape.points[i]!.x, shape.points[i]!.y)\n }\n ctx.stroke()\n } else if (shape.kind === 'text') {\n ctx.font = `bold ${shape.fontSize}px -apple-system, BlinkMacSystemFont, sans-serif`\n ctx.textBaseline = 'top'\n const metrics = ctx.measureText(shape.text)\n const padding = 4\n const w = metrics.width + padding * 2\n const hh = shape.fontSize + padding * 2\n ctx.fillStyle = 'rgba(0, 0, 0, 0.6)'\n ctx.fillRect(shape.x - padding, shape.y - padding, w, hh)\n ctx.fillStyle = shape.color\n ctx.fillText(shape.text, shape.x, shape.y)\n }\n ctx.restore()\n}\n\nfunction drawArrow(\n ctx: CanvasRenderingContext2D,\n x1: number,\n y1: number,\n x2: number,\n y2: number,\n) {\n const headLen = 14\n const angle = Math.atan2(y2 - y1, x2 - x1)\n ctx.beginPath()\n ctx.moveTo(x1, y1)\n ctx.lineTo(x2, y2)\n ctx.stroke()\n ctx.beginPath()\n ctx.moveTo(x2, y2)\n ctx.lineTo(\n x2 - headLen * Math.cos(angle - Math.PI / 6),\n y2 - headLen * Math.sin(angle - Math.PI / 6),\n )\n ctx.lineTo(\n x2 - headLen * Math.cos(angle + Math.PI / 6),\n y2 - headLen * Math.sin(angle + Math.PI / 6),\n )\n ctx.closePath()\n ctx.fill()\n}\n\n// ---------------------------------------------------------------------------\n// Inline icons\n// ---------------------------------------------------------------------------\n\nconst Icon = {\n rect: (\n <svg width=\"16\" height=\"16\" viewBox=\"0 0 16 16\" aria-hidden=\"true\">\n <rect x=\"2\" y=\"3\" width=\"12\" height=\"10\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"1.5\" />\n </svg>\n ),\n arrow: (\n <svg width=\"16\" height=\"16\" viewBox=\"0 0 16 16\" aria-hidden=\"true\">\n <path d=\"M2 8h11M9 4l4 4-4 4\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"1.5\" stroke-linecap=\"round\" stroke-linejoin=\"round\" />\n </svg>\n ),\n pencil: (\n <svg width=\"16\" height=\"16\" viewBox=\"0 0 16 16\" aria-hidden=\"true\">\n <path d=\"M11.5 2.5l2 2L5 13H3v-2l8.5-8.5z\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"1.5\" stroke-linejoin=\"round\" />\n </svg>\n ),\n text: (\n <svg width=\"16\" height=\"16\" viewBox=\"0 0 16 16\" aria-hidden=\"true\">\n <path d=\"M3 3h10M8 3v10M5 13h6\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"1.5\" stroke-linecap=\"round\" />\n </svg>\n ),\n undo: (\n <svg width=\"14\" height=\"14\" viewBox=\"0 0 16 16\" aria-hidden=\"true\">\n <path d=\"M4 7l3-3M4 7l3 3M4 7h6a3 3 0 0 1 0 6H7\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"1.5\" stroke-linecap=\"round\" stroke-linejoin=\"round\" />\n </svg>\n ),\n trash: (\n <svg width=\"14\" height=\"14\" viewBox=\"0 0 16 16\" aria-hidden=\"true\">\n <path d=\"M3 4h10M6 4V2.5h4V4M5 4l.5 9h5L11 4\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"1.5\" stroke-linecap=\"round\" stroke-linejoin=\"round\" />\n </svg>\n ),\n close: (\n <svg width=\"16\" height=\"16\" viewBox=\"0 0 16 16\" aria-hidden=\"true\">\n <path d=\"M4 4l8 8M12 4l-8 8\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"1.5\" stroke-linecap=\"round\" />\n </svg>\n ),\n}\n\n// ---------------------------------------------------------------------------\n// Component\n// ---------------------------------------------------------------------------\n\nexport interface AnnotatorProps {\n imageBlob: Blob\n strings: Record<StringKey, string>\n onSave: (annotated: Blob) => void\n onCancel: () => void\n}\n\nexport function Annotator({ imageBlob, strings, onSave, onCancel }: AnnotatorProps) {\n const canvasRef = useRef<HTMLCanvasElement | null>(null)\n const containerRef = useRef<HTMLDivElement | null>(null)\n const imageRef = useRef<HTMLImageElement | null>(null)\n const [tool, setTool] = useState<Tool>('rectangle')\n const [color, setColor] = useState<string>(COLORS[0]!)\n const [shapes, setShapes] = useState<Shape[]>([])\n const isDrawingRef = useRef(false)\n const [draftShape, setDraftShape] = useState<Shape | null>(null)\n const [imageLoaded, setImageLoaded] = useState(false)\n const [saving, setSaving] = useState(false)\n const scaleRef = useRef(1)\n\n // Esc closes the annotator. The parent Modal has its own Esc handler but\n // bails when it sees an .annotator-backdrop in the shadow root, so the\n // top-most dialog wins.\n useEffect(() => {\n const onKey = (e: KeyboardEvent) => {\n if (e.key === 'Escape') {\n e.stopPropagation()\n onCancel()\n }\n }\n window.addEventListener('keydown', onKey)\n return () => window.removeEventListener('keydown', onKey)\n }, [onCancel])\n\n // Decode the source image once, into an offscreen <img> we keep around for\n // every redraw.\n useEffect(() => {\n const url = URL.createObjectURL(imageBlob)\n const img = new Image()\n img.onload = () => {\n imageRef.current = img\n setImageLoaded(true)\n }\n img.src = url\n return () => URL.revokeObjectURL(url)\n }, [imageBlob])\n\n // Once the image loads, fit the canvas to whatever room the modal has.\n useEffect(() => {\n if (\n !imageLoaded ||\n !canvasRef.current ||\n !imageRef.current ||\n !containerRef.current\n ) {\n return\n }\n const img = imageRef.current\n const container = containerRef.current\n const maxW = container.clientWidth - 16\n const maxH = window.innerHeight * 0.6\n const fitScale = Math.min(maxW / img.width, maxH / img.height, 1)\n scaleRef.current = fitScale\n\n const canvas = canvasRef.current\n canvas.width = img.width\n canvas.height = img.height\n canvas.style.width = `${img.width * fitScale}px`\n canvas.style.height = `${img.height * fitScale}px`\n redraw()\n // eslint-disable-next-line react-hooks/exhaustive-deps\n }, [imageLoaded])\n\n // Redraw whenever the shape list or in-flight draft changes.\n useEffect(() => {\n redraw()\n // eslint-disable-next-line react-hooks/exhaustive-deps\n }, [shapes, draftShape])\n\n function redraw() {\n const canvas = canvasRef.current\n const img = imageRef.current\n if (!canvas || !img) return\n const ctx = canvas.getContext('2d')\n if (!ctx) return\n ctx.clearRect(0, 0, canvas.width, canvas.height)\n ctx.drawImage(img, 0, 0)\n for (const s of shapes) drawShape(ctx, s)\n if (draftShape) drawShape(ctx, draftShape)\n }\n\n function getCanvasCoords(e: MouseEvent) {\n const canvas = canvasRef.current!\n const rect = canvas.getBoundingClientRect()\n return {\n x: (e.clientX - rect.left) / scaleRef.current,\n y: (e.clientY - rect.top) / scaleRef.current,\n }\n }\n\n const handleMouseDown = (e: MouseEvent) => {\n if (!imageLoaded) return\n const { x, y } = getCanvasCoords(e)\n const lineWidth = Math.max(3, Math.round(canvasRef.current!.width / 400))\n\n if (tool === 'text') {\n const text = window.prompt(strings['annotator.text_prompt'])\n if (text && text.trim()) {\n setShapes((prev) => [\n ...prev,\n {\n kind: 'text',\n x,\n y,\n text: text.trim(),\n color,\n fontSize: Math.max(16, Math.round(canvasRef.current!.width / 50)),\n lineWidth: 1,\n },\n ])\n }\n return\n }\n\n isDrawingRef.current = true\n if (tool === 'rectangle') {\n setDraftShape({ kind: 'rectangle', x, y, w: 0, h: 0, color, lineWidth })\n } else if (tool === 'arrow') {\n setDraftShape({ kind: 'arrow', x1: x, y1: y, x2: x, y2: y, color, lineWidth })\n } else if (tool === 'freehand') {\n setDraftShape({ kind: 'freehand', points: [{ x, y }], color, lineWidth })\n }\n }\n\n const handleMouseMove = (e: MouseEvent) => {\n if (!isDrawingRef.current || !draftShape) return\n const { x, y } = getCanvasCoords(e)\n if (draftShape.kind === 'rectangle') {\n setDraftShape({ ...draftShape, w: x - draftShape.x, h: y - draftShape.y })\n } else if (draftShape.kind === 'arrow') {\n setDraftShape({ ...draftShape, x2: x, y2: y })\n } else if (draftShape.kind === 'freehand') {\n setDraftShape({ ...draftShape, points: [...draftShape.points, { x, y }] })\n }\n }\n\n const handleMouseUp = () => {\n if (isDrawingRef.current && draftShape) {\n // Discard tiny shapes (accidental clicks).\n const isTiny =\n (draftShape.kind === 'rectangle' &&\n Math.abs(draftShape.w) < 4 &&\n Math.abs(draftShape.h) < 4) ||\n (draftShape.kind === 'arrow' &&\n Math.hypot(\n draftShape.x2 - draftShape.x1,\n draftShape.y2 - draftShape.y1,\n ) < 4) ||\n (draftShape.kind === 'freehand' && draftShape.points.length < 3)\n if (!isTiny) {\n setShapes((prev) => [...prev, draftShape])\n }\n }\n isDrawingRef.current = false\n setDraftShape(null)\n }\n\n const handleSave = async () => {\n const canvas = canvasRef.current\n if (!canvas) return\n setSaving(true)\n try {\n const blob = await new Promise<Blob | null>((resolve) =>\n canvas.toBlob(resolve, 'image/png', 0.92),\n )\n if (blob) onSave(blob)\n } finally {\n setSaving(false)\n }\n }\n\n const tools: Array<{ id: Tool; icon: typeof Icon.rect; label: string }> = [\n { id: 'rectangle', icon: Icon.rect, label: strings['annotator.tool.rectangle'] },\n { id: 'arrow', icon: Icon.arrow, label: strings['annotator.tool.arrow'] },\n { id: 'freehand', icon: Icon.pencil, label: strings['annotator.tool.freehand'] },\n { id: 'text', icon: Icon.text, label: strings['annotator.tool.text'] },\n ]\n\n return (\n <div\n class=\"annotator-backdrop\"\n role=\"presentation\"\n onClick={(e) => {\n if (e.target === e.currentTarget) onCancel()\n }}\n >\n <div class=\"annotator\" role=\"dialog\" aria-modal=\"true\" aria-label={strings['annotator.title']}>\n <div class=\"annotator-header\">\n <span>{strings['annotator.title']}</span>\n <button\n type=\"button\"\n class=\"modal-close\"\n aria-label={strings['form.close']}\n onClick={onCancel}\n >\n {Icon.close}\n </button>\n </div>\n\n <div class=\"annotator-toolbar\">\n <div class=\"annotator-tools\">\n {tools.map((t) => (\n <button\n key={t.id}\n type=\"button\"\n onClick={() => setTool(t.id)}\n title={t.label}\n aria-label={t.label}\n aria-pressed={tool === t.id}\n class={`annotator-tool ${tool === t.id ? 'is-active' : ''}`}\n >\n {t.icon}\n </button>\n ))}\n </div>\n\n <span class=\"annotator-sep\" />\n\n <div class=\"annotator-colors\">\n {COLORS.map((c) => (\n <button\n key={c}\n type=\"button\"\n onClick={() => setColor(c)}\n aria-label={c}\n aria-pressed={color === c}\n class={`annotator-color ${color === c ? 'is-active' : ''}`}\n style={{ backgroundColor: c }}\n />\n ))}\n </div>\n\n <span class=\"annotator-sep\" />\n\n <button\n type=\"button\"\n class=\"annotator-btn\"\n onClick={() => setShapes((prev) => prev.slice(0, -1))}\n disabled={shapes.length === 0}\n >\n {Icon.undo}\n <span>{strings['annotator.undo']}</span>\n </button>\n <button\n type=\"button\"\n class=\"annotator-btn\"\n onClick={() => setShapes([])}\n disabled={shapes.length === 0}\n >\n {Icon.trash}\n <span>{strings['annotator.clear']}</span>\n </button>\n\n <span class=\"annotator-spacer\" />\n\n <span class=\"annotator-count\">\n {shapes.length} {strings['annotator.count_suffix']}\n </span>\n </div>\n\n <div ref={containerRef} class=\"annotator-canvas-wrap\">\n {!imageLoaded ? (\n <span class=\"annotator-loading\">{strings['annotator.loading']}</span>\n ) : (\n <canvas\n ref={canvasRef}\n onMouseDown={handleMouseDown}\n onMouseMove={handleMouseMove}\n onMouseUp={handleMouseUp}\n onMouseLeave={handleMouseUp}\n class=\"annotator-canvas\"\n />\n )}\n </div>\n\n <div class=\"annotator-footer\">\n <button type=\"button\" class=\"btn\" onClick={onCancel}>\n {strings['form.cancel']}\n </button>\n <button\n type=\"button\"\n class=\"btn btn--primary\"\n onClick={handleSave}\n disabled={saving || !imageLoaded}\n >\n {saving ? strings['annotator.applying'] : strings['annotator.apply']}\n </button>\n </div>\n </div>\n </div>\n )\n}\n","/**\n * Helpers for the manual-screenshot-upload UX (v0.6.0).\n *\n * Kept tiny and dependency-free so they can be unit-tested without DOM/jsdom\n * setup. The interesting work — drag/drop, paste, file picker — lives in\n * Form.tsx.\n */\n\nexport const ALLOWED_IMAGE_TYPES = [\n 'image/png',\n 'image/jpeg',\n 'image/webp',\n] as const\n\nexport const MAX_SCREENSHOT_BYTES = 10 * 1024 * 1024 // 10 MB\n\nexport type ScreenshotValidationError =\n | { kind: 'type' }\n | { kind: 'size'; maxMb: number }\n\nexport function validateScreenshotFile(file: File): ScreenshotValidationError | null {\n if (\n !ALLOWED_IMAGE_TYPES.includes(\n file.type as (typeof ALLOWED_IMAGE_TYPES)[number],\n )\n ) {\n return { kind: 'type' }\n }\n if (file.size > MAX_SCREENSHOT_BYTES) {\n return { kind: 'size', maxMb: MAX_SCREENSHOT_BYTES / (1024 * 1024) }\n }\n return null\n}\n\n/**\n * Truncate a URL while keeping the start and end visible. Used in the form's\n * \"Vous étiez ici\" footer so the user can verify the URL we'll send without\n * the long path overflowing the modal.\n *\n * \"https://app.example.com/very/long/deep/path?a=1&b=2\" (53 chars, max 30)\n * → \"https://app.examp…h?a=1&b=2\"\n */\nexport function truncateUrl(url: string, maxLength = 80): string {\n if (url.length <= maxLength) return url\n const keepStart = Math.floor((maxLength - 1) / 2)\n const keepEnd = maxLength - 1 - keepStart\n return `${url.slice(0, keepStart)}…${url.slice(url.length - keepEnd)}`\n}\n","import { h, type ComponentChildren } from 'preact'\nimport { useEffect, useRef } from 'preact/hooks'\n\ninterface ModalProps {\n onDismiss: () => void\n children: ComponentChildren\n closeLabel?: string\n}\n\nexport function Modal({ onDismiss, children, closeLabel = 'Close' }: ModalProps) {\n const modalRef = useRef<HTMLDivElement>(null)\n const previouslyFocused = useRef<Element | null>(null)\n\n // Esc-to-close + focus management. Without this, users couldn't dismiss\n // with the keyboard (a real-world UX expectation). Listener installed on\n // window so it works regardless of which element inside the modal has focus.\n useEffect(() => {\n previouslyFocused.current = document.activeElement\n const onKey = (e: KeyboardEvent) => {\n if (e.key !== 'Escape') return\n // Ignore Esc when a topmost dialog (e.g. the Annotator) is mounted in\n // our shadow root — it owns the keystroke. Without this guard the\n // Esc fires both handlers on the same event and dismisses the form\n // behind the annotator.\n const root = modalRef.current?.getRootNode()\n if (\n root instanceof ShadowRoot &&\n root.querySelector('.annotator-backdrop')\n ) {\n return\n }\n e.stopPropagation()\n onDismiss()\n }\n window.addEventListener('keydown', onKey)\n // Focus first focusable element inside the modal so the keyboard user\n // lands inside, not still on the FAB or whatever opened the modal.\n const first = modalRef.current?.querySelector<HTMLElement>(\n 'textarea, input, select, button',\n )\n first?.focus()\n return () => {\n window.removeEventListener('keydown', onKey)\n // Restore focus on dismiss so screen-readers don't lose place.\n const prev = previouslyFocused.current as HTMLElement | null\n if (prev && typeof prev.focus === 'function') prev.focus()\n }\n }, [onDismiss])\n\n return (\n <div\n class=\"backdrop\"\n role=\"presentation\"\n onClick={(e) => {\n if (e.target === e.currentTarget) onDismiss()\n }}\n >\n <div ref={modalRef} class=\"modal\" role=\"dialog\" aria-modal=\"true\">\n <button\n type=\"button\"\n class=\"modal-close\"\n aria-label={closeLabel}\n onClick={onDismiss}\n >\n ×\n </button>\n {children}\n </div>\n </div>\n )\n}\n","export const WIDGET_STYLES = `\n:host {\n --mfb-accent: #3b82f6;\n --mfb-accent-contrast: #ffffff;\n --mfb-bg: #ffffff;\n --mfb-surface: #f9fafb;\n --mfb-text: #0a0a0a;\n --mfb-text-muted: #6b7280;\n --mfb-border: #e5e7eb;\n --mfb-radius: 8px;\n --mfb-font: system-ui, -apple-system, sans-serif;\n --mfb-z-index: 2147483640;\n\n all: initial;\n font-family: var(--mfb-font);\n color: var(--mfb-text);\n position: fixed;\n z-index: var(--mfb-z-index);\n}\n\n@media (prefers-color-scheme: dark) {\n :host {\n --mfb-bg: #111827;\n --mfb-surface: #1f2937;\n --mfb-text: #f9fafb;\n --mfb-text-muted: #9ca3af;\n --mfb-border: #374151;\n }\n}\n\n.fab {\n position: fixed;\n bottom: 24px;\n right: 24px;\n width: 52px;\n height: 52px;\n border-radius: 999px;\n background: var(--mfb-accent);\n color: var(--mfb-accent-contrast);\n border: none;\n cursor: pointer;\n box-shadow: 0 4px 14px rgba(0, 0, 0, 0.18);\n font-size: 22px;\n display: grid;\n place-items: center;\n transition: transform 120ms ease, box-shadow 120ms ease;\n}\n\n.fab:hover { transform: translateY(-1px); box-shadow: 0 6px 18px rgba(0, 0, 0, 0.24); }\n.fab:active { transform: translateY(0) scale(0.96); box-shadow: 0 3px 10px rgba(0, 0, 0, 0.22); }\n.fab:focus-visible { outline: 2px solid #fff; outline-offset: 3px; box-shadow: 0 0 0 4px var(--mfb-accent), 0 4px 14px rgba(0, 0, 0, 0.18); }\n@media (prefers-reduced-motion: reduce) { .fab { transition: none; } .fab:hover, .fab:active { transform: none; } }\n\n.backdrop {\n position: fixed;\n inset: 0;\n background: rgba(0, 0, 0, 0.45);\n display: grid;\n place-items: center;\n}\n\n.modal {\n background: var(--mfb-bg);\n border-radius: calc(var(--mfb-radius) * 1.5);\n box-shadow: 0 20px 48px rgba(0, 0, 0, 0.25);\n width: min(420px, 92vw);\n padding: 20px;\n display: flex;\n flex-direction: column;\n gap: 12px;\n position: relative;\n /* Cap modal height on short viewports (mobile landscape, tiny laptops)\n so the form scrolls inside the modal rather than overflowing the\n viewport with no way to reach the actions row. */\n max-height: calc(100vh - 32px);\n overflow-y: auto;\n}\n\n.modal h2 { margin: 0 0 4px; font-size: 18px; font-weight: 600; padding-right: 28px; }\n\n.modal-close {\n position: absolute;\n top: 8px;\n right: 8px;\n width: 32px;\n height: 32px;\n display: grid;\n place-items: center;\n background: transparent;\n border: none;\n border-radius: var(--mfb-radius);\n color: var(--mfb-text-muted);\n font: inherit;\n font-size: 22px;\n line-height: 1;\n cursor: pointer;\n}\n.modal-close:hover { background: var(--mfb-surface); color: var(--mfb-text); }\n.modal-close:focus-visible { outline: 2px solid var(--mfb-accent); outline-offset: 2px; }\n\n.field { display: flex; flex-direction: column; gap: 4px; font-size: 13px; }\n\n.field label { color: var(--mfb-text-muted); }\n\n.field input, .field select, .field textarea {\n font-family: inherit;\n font-size: 14px;\n color: inherit;\n padding: 8px 10px;\n border: 1px solid var(--mfb-border);\n border-radius: var(--mfb-radius);\n background: var(--mfb-surface);\n transition: border-color 120ms ease, box-shadow 120ms ease;\n}\n\n.field input:hover, .field select:hover, .field textarea:hover { border-color: var(--mfb-text-muted); }\n.field input:focus, .field select:focus, .field textarea:focus {\n outline: none;\n border-color: var(--mfb-accent);\n box-shadow: 0 0 0 3px color-mix(in srgb, var(--mfb-accent) 22%, transparent);\n}\n\n.field select {\n -webkit-appearance: none;\n -moz-appearance: none;\n appearance: none;\n padding-right: 28px;\n background-image: url(\"data:image/svg+xml;utf8,<svg xmlns='http://www.w3.org/2000/svg' width='10' height='6' viewBox='0 0 10 6'><path fill='none' stroke='%236b7280' stroke-width='1.5' stroke-linecap='round' stroke-linejoin='round' d='M1 1l4 4 4-4'/></svg>\");\n background-repeat: no-repeat;\n background-position: right 10px center;\n}\n\n.field textarea { min-height: 88px; resize: vertical; }\n\n.row { display: flex; gap: 8px; }\n.row > * { flex: 1; }\n\n.actions { display: flex; gap: 8px; justify-content: flex-end; padding-top: 8px; }\n\n.btn {\n padding: 8px 14px;\n border-radius: var(--mfb-radius);\n border: 1px solid var(--mfb-border);\n background: var(--mfb-bg);\n color: var(--mfb-text);\n font: inherit;\n cursor: pointer;\n}\n\n.btn--primary {\n background: var(--mfb-accent);\n color: var(--mfb-accent-contrast);\n border-color: var(--mfb-accent);\n}\n\n.btn[disabled] { opacity: 0.6; cursor: not-allowed; }\n\n.error { color: #dc2626; font-size: 13px; }\n.success { color: #059669; font-size: 13px; }\n\n/* ---- v0.6.0: manual screenshot upload + annotator -------------------- */\n\n.mfb-sr-only {\n position: absolute;\n width: 1px;\n height: 1px;\n padding: 0;\n margin: -1px;\n overflow: hidden;\n clip: rect(0, 0, 0, 0);\n white-space: nowrap;\n border: 0;\n}\n\n.screenshot-dropzone {\n border: 1px dashed var(--mfb-border);\n border-radius: var(--mfb-radius);\n padding: 14px 12px;\n text-align: center;\n cursor: pointer;\n background: var(--mfb-surface);\n transition: border-color 120ms ease, background 120ms ease;\n}\n.screenshot-dropzone:hover { border-color: var(--mfb-text-muted); }\n.screenshot-dropzone.is-dragover {\n border-color: var(--mfb-accent);\n border-style: solid;\n background: color-mix(in srgb, var(--mfb-accent) 8%, var(--mfb-surface));\n}\n.screenshot-dropzone:focus-visible {\n outline: 2px solid var(--mfb-accent);\n outline-offset: 2px;\n}\n.screenshot-cta { font-size: 13px; color: var(--mfb-text); }\n.screenshot-cta strong { color: var(--mfb-accent); font-weight: 600; }\n.screenshot-formats { font-size: 11px; color: var(--mfb-text-muted); margin-top: 4px; }\n\n.screenshot-preview {\n position: relative;\n border: 1px solid var(--mfb-border);\n border-radius: var(--mfb-radius);\n overflow: hidden;\n background: var(--mfb-surface);\n display: flex;\n flex-direction: column;\n}\n.screenshot-preview img {\n display: block;\n width: 100%;\n height: auto;\n max-height: 180px;\n object-fit: contain;\n background: #1a1a1a;\n}\n.screenshot-remove {\n position: absolute;\n top: 6px;\n right: 6px;\n width: 26px;\n height: 26px;\n display: grid;\n place-items: center;\n background: rgba(255, 255, 255, 0.9);\n border: 1px solid var(--mfb-border);\n border-radius: 999px;\n font-size: 18px;\n line-height: 1;\n cursor: pointer;\n color: #111827;\n}\n.screenshot-remove:hover { background: #fff; }\n.screenshot-annotate {\n border-radius: 0;\n border-width: 0;\n border-top: 1px solid var(--mfb-border);\n background: var(--mfb-bg);\n}\n.screenshot-annotate:hover { background: var(--mfb-surface); }\n\n.page-context {\n display: flex;\n align-items: center;\n gap: 8px;\n font-size: 11px;\n color: var(--mfb-text-muted);\n}\n.page-context-label {\n text-transform: uppercase;\n font-weight: 600;\n letter-spacing: 0.04em;\n}\n.page-context-url {\n font-family: ui-monospace, SFMono-Regular, Menlo, monospace;\n background: var(--mfb-surface);\n padding: 4px 6px;\n border-radius: 4px;\n flex: 1;\n overflow: hidden;\n text-overflow: ellipsis;\n white-space: nowrap;\n}\n\n/* Annotator modal — sits above the feedback modal (z-index +1). */\n\n.annotator-backdrop {\n position: fixed;\n inset: 0;\n background: rgba(0, 0, 0, 0.78);\n display: grid;\n place-items: center;\n z-index: 1;\n padding: 12px;\n}\n.annotator {\n position: relative;\n background: var(--mfb-bg);\n color: var(--mfb-text);\n border-radius: calc(var(--mfb-radius) * 1.5);\n width: min(960px, 96vw);\n max-height: calc(100vh - 24px);\n display: flex;\n flex-direction: column;\n box-shadow: 0 24px 60px rgba(0, 0, 0, 0.4);\n}\n.annotator-header {\n display: flex;\n align-items: center;\n justify-content: space-between;\n padding: 10px 14px;\n border-bottom: 1px solid var(--mfb-border);\n font-size: 13px;\n font-weight: 600;\n}\n.annotator-toolbar {\n display: flex;\n flex-wrap: wrap;\n align-items: center;\n gap: 8px;\n padding: 8px 14px;\n border-bottom: 1px solid var(--mfb-border);\n}\n.annotator-tools, .annotator-colors { display: flex; gap: 4px; }\n.annotator-sep {\n display: inline-block;\n width: 1px;\n height: 18px;\n background: var(--mfb-border);\n margin: 0 4px;\n}\n.annotator-spacer { flex: 1; }\n.annotator-tool {\n width: 30px;\n height: 30px;\n display: grid;\n place-items: center;\n background: var(--mfb-bg);\n color: var(--mfb-text);\n border: 1px solid var(--mfb-border);\n border-radius: var(--mfb-radius);\n cursor: pointer;\n}\n.annotator-tool:hover { background: var(--mfb-surface); }\n.annotator-tool.is-active {\n background: var(--mfb-text);\n color: var(--mfb-bg);\n border-color: var(--mfb-text);\n}\n.annotator-color {\n width: 24px;\n height: 24px;\n border-radius: 999px;\n border: 2px solid var(--mfb-border);\n cursor: pointer;\n padding: 0;\n transition: transform 120ms ease;\n}\n.annotator-color.is-active {\n transform: scale(1.12);\n border-color: var(--mfb-text);\n}\n.annotator-btn {\n display: inline-flex;\n align-items: center;\n gap: 4px;\n height: 30px;\n padding: 0 10px;\n font: inherit;\n font-size: 12px;\n background: var(--mfb-bg);\n color: var(--mfb-text);\n border: 1px solid var(--mfb-border);\n border-radius: var(--mfb-radius);\n cursor: pointer;\n}\n.annotator-btn:hover { background: var(--mfb-surface); }\n.annotator-btn[disabled] { opacity: 0.5; cursor: not-allowed; }\n.annotator-count { font-size: 11px; color: var(--mfb-text-muted); }\n.annotator-canvas-wrap {\n flex: 1;\n overflow: auto;\n background: #1a1a1a;\n display: flex;\n align-items: center;\n justify-content: center;\n padding: 12px;\n min-height: 200px;\n}\n.annotator-canvas {\n cursor: crosshair;\n box-shadow: 0 8px 28px rgba(0, 0, 0, 0.45);\n background: #fff;\n}\n.annotator-loading {\n color: rgba(255, 255, 255, 0.7);\n font-size: 13px;\n}\n.annotator-footer {\n display: flex;\n align-items: center;\n justify-content: flex-end;\n gap: 8px;\n padding: 10px 14px;\n border-top: 1px solid var(--mfb-border);\n}\n`\n","import { createApiClient } from './api/client'\nimport { installCapture } from './capture'\nimport { takeScreenshot } from './screenshot'\nimport { resolveStrings } from './widget/i18n'\nimport { mountWidget } from './widget/mount'\nimport type { FeedbackApi, FeedbackConfig, ReportPayload, ReportTransformer, UserIdentity } from './types'\n\nexport interface InternalConfig extends FeedbackConfig {\n fetchImpl?: typeof fetch\n}\n\ninterface WindowWithGlobal extends Window {\n mhosaicFeedback?: FeedbackApi\n}\n\nexport function createFeedback(config: InternalConfig): FeedbackApi & { _registerTransformer(fn: ReportTransformer): void } {\n const env = config.env ?? 'prod'\n const locale =\n config.locale ?? (typeof navigator !== 'undefined' ? navigator.language : undefined)\n const strings = resolveStrings(\n config.translations ?? {},\n locale !== undefined ? { locale } : {},\n )\n const capture = installCapture({\n ...(config.sanitizeUrl !== undefined && { sanitizeUrl: config.sanitizeUrl }),\n })\n const api = createApiClient({\n apiKey: config.apiKey,\n endpoint: config.endpoint,\n ...(config.fetchImpl !== undefined && { fetch: config.fetchImpl }),\n ...(config.beforeSend !== undefined && { beforeSend: config.beforeSend }),\n })\n\n let user: UserIdentity | undefined = config.user\n let metadata: Record<string, unknown> = config.metadata ?? {}\n const transformers: ReportTransformer[] = []\n\n const host = document.createElement('div')\n host.className = 'mhosaic-feedback'\n if (config.attachTo) {\n const attach = typeof config.attachTo === 'string' ? document.querySelector(config.attachTo) : config.attachTo\n attach?.appendChild(host)\n } else {\n document.body.appendChild(host)\n }\n\n async function buildAndSubmit(values: {\n description: string\n feedback_type?: string\n severity?: string\n synthetic?: boolean\n /** When set, used as-is and html2canvas is skipped. v0.6.0 manual upload. */\n screenshot?: Blob\n }) {\n // Auto-error reports skip screenshot capture: html2canvas is async/slow,\n // and the DOM is often in an inconsistent state when a JS error fires.\n // The captured ring buffer (errors, console, network) carries the signal.\n // Manual uploads (user dropped/pasted/annotated their own image) take\n // precedence over the html2canvas auto-grab.\n const manualScreenshot = values.screenshot\n const screenshot = values.synthetic\n ? undefined\n : (manualScreenshot ??\n (await takeScreenshot(document.body, {\n mask: ['.mhosaic-feedback', '[data-mfb-mask]'],\n })))\n const technical_context = capture.snapshot()\n // Surface identify()/setMetadata() values on the report. Without this\n // the host-supplied user identity and metadata sit in closure forever\n // and never reach the operator — a stack trace from a logged-in user\n // looks anonymous on the dashboard.\n if (user) technical_context.user = user\n if (metadata && Object.keys(metadata).length > 0) {\n technical_context.metadata = { ...metadata }\n }\n const payload: ReportPayload = {\n description: values.description,\n feedback_type: (values.feedback_type ?? 'bug') as ReportPayload['feedback_type'],\n severity: (values.severity ?? 'medium') as ReportPayload['severity'],\n env,\n page_url: window.location.href,\n user_agent: navigator.userAgent,\n capture_method: screenshot\n ? manualScreenshot\n ? 'manual'\n : 'html2canvas'\n : 'none',\n technical_context,\n }\n if (screenshot) payload.screenshot = screenshot\n if (values.synthetic) payload.synthetic = true\n let finalPayload: ReportPayload = payload\n for (const t of transformers) finalPayload = await t(finalPayload)\n try {\n const result = await api.submitReport(finalPayload)\n config.onSubmitSuccess?.(result)\n capture.clear()\n return result\n } catch (err) {\n const error = err instanceof Error ? err : new Error(String(err))\n config.onError?.(error)\n throw error\n }\n }\n\n const handle = mountWidget({\n host,\n strings,\n showFAB: config.showFAB ?? true,\n onSubmit: async (values) => { await buildAndSubmit(values) },\n })\n\n const instance: FeedbackApi & { _registerTransformer(fn: ReportTransformer): void } = {\n show() { handle.open() },\n hide() { handle.close() },\n open(opts) { handle.open(); void opts },\n async submit(partial) {\n return buildAndSubmit({\n description: partial.description,\n ...(partial.feedback_type !== undefined && { feedback_type: partial.feedback_type }),\n ...(partial.severity !== undefined && { severity: partial.severity }),\n ...(partial.synthetic !== undefined && { synthetic: partial.synthetic }),\n ...(partial.screenshot !== undefined && { screenshot: partial.screenshot }),\n })\n },\n identify(u) { user = u },\n setMetadata(kv) { metadata = { ...metadata, ...kv } },\n shutdown() {\n handle.dispose()\n capture.dispose()\n host.remove()\n // Only release the global if it still points at *us* — otherwise a\n // newer instance has taken ownership and we mustn't blow it away.\n const w = window as unknown as WindowWithGlobal\n if (w.mhosaicFeedback === instance) {\n delete w.mhosaicFeedback\n }\n },\n _registerTransformer(fn: ReportTransformer) { transformers.push(fn) },\n }\n\n // Expose the instance globally for ad-hoc callers (DevTools, docs pages,\n // help-widget integrations). The most-recently-created instance wins.\n ;(window as unknown as WindowWithGlobal).mhosaicFeedback = instance\n\n return instance\n}\n"],"mappings":"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AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;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","names":["useEffect","useRef","useState","jsx","jsx","jsxs","useState","useRef","useEffect","useEffect","useRef","jsx","jsxs","jsx","jsxs"]}