@marktiderman/genesis-support 0.2.0 → 0.2.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.
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/web-chat/report-thread.tsx","../src/web-chat/staff-thread.tsx"],"names":["useChat","useQuery","jsxs","jsx","useMemo"],"mappings":"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","file":"web-chat.js","sourcesContent":["/**\n * A report and its conversation on genesis-chat, for the web: the report (its type, status,\n * message and screenshots) on top, and genesis-chat's `ChatThread` for the replies, live, with\n * photos, files and voice notes. The person's view (`SupportReportThread`) and the staff view\n * (`SupportStaffThread`: status, assignee, and internal notes in the composer) share it.\n *\n * Render under genesis-chat's `ChatProvider` (from `@marktiderman/genesis-chat/react`) inside a\n * TanStack QueryClientProvider, with a support client made with the `chat` option.\n */\nimport { useMemo, type ReactNode } from \"react\";\nimport { useQuery } from \"@tanstack/react-query\";\nimport { Badge, Card, CardContent, CardDescription, CardHeader, CardTitle, EmptyState, Skeleton, cn } from \"@marktiderman/genesis-ui\";\nimport { ChatThread, type ResolveUser } from \"@marktiderman/genesis-chat/web\";\nimport { useChat } from \"@marktiderman/genesis-chat/react\";\nimport type { SupportClient } from \"../client\";\nimport { resolveSupportCopy, type SupportCopy, type SupportCopyOverrides } from \"../copy\";\n\n/** The query keys, under genesis-support's root (as on native). */\nexport const supportWebKeys = {\n report: (id: string) => [\"genesis-support\", \"report\", id] as const,\n attachments: (id: string) => [\"genesis-support\", \"attachments\", id] as const,\n thread: (id: string) => [\"genesis-support\", \"thread\", id] as const,\n};\n\nexport interface SupportReportThreadProps {\n /** A support client made with the `chat` option (`createSupportClient(supabase, { chat })`). */\n client: SupportClient;\n reportId: string;\n /**\n * Names people. Default: the signed-in person is \"You\" and anyone else \"Support\" (only staff\n * write in a report's conversation besides its person).\n */\n resolveUser?: ResolveUser;\n copy?: SupportCopyOverrides;\n /** A back button in the thread's header. */\n onBack?: () => void;\n className?: string;\n}\n\ninterface ShellProps extends SupportReportThreadProps {\n /** Above the conversation, under the report (the staff controls). */\n toolbar?: (report: NonNullable<Awaited<ReturnType<SupportClient[\"report\"]>>>, conversationId: string) => ReactNode;\n copyResolved: SupportCopy;\n testID: string;\n}\n\nexport function ReportThreadShell({ client, reportId, resolveUser, onBack, className, toolbar, copyResolved: copy, testID }: ShellProps) {\n const { userId: me } = useChat();\n const report = useQuery({ queryKey: supportWebKeys.report(reportId), queryFn: () => client.report(reportId) });\n const where = useQuery({ queryKey: supportWebKeys.thread(reportId), queryFn: () => client.thread(reportId), staleTime: Infinity });\n const shots = useQuery({ queryKey: supportWebKeys.attachments(reportId), queryFn: () => client.attachments(reportId), staleTime: 50 * 60_000 });\n const names = useMemo<ResolveUser>(\n () => resolveUser ?? ((id: string) => ({ name: id === me ? copy.thread.you : copy.thread.support })),\n [resolveUser, me, copy],\n );\n\n if (report.isPending || where.isPending) {\n return (\n <div className={cn(\"flex flex-col gap-3 p-4\", className)} data-testid={testID} aria-busy=\"true\">\n <Skeleton className=\"h-24 w-full\" />\n <Skeleton className=\"h-64 w-full\" />\n </div>\n );\n }\n const r = report.data;\n if (!r || where.data?.mode !== \"chat\") {\n return (\n <div className={className} data-testid={testID}>\n <EmptyState\n title={r ? copy.staff.unavailableTitle : copy.thread.notFound}\n description={r ? copy.staff.unavailableBody : undefined}\n />\n </div>\n );\n }\n const conversationId = where.data.conversationId;\n return (\n <div className={cn(\"flex h-full min-h-0 flex-col gap-3\", className)} data-testid={testID}>\n <Card>\n <CardHeader className=\"gap-2\">\n <div className=\"flex flex-wrap items-center gap-2\">\n <Badge variant=\"secondary\">{copy.feedback.types[r.type]}</Badge>\n <Badge variant=\"outline\" data-testid=\"genesis-support-report-status\">\n {copy.status[r.status]}\n </Badge>\n </div>\n <CardTitle>{r.title || copy.feedback.types[r.type]}</CardTitle>\n <CardDescription className=\"whitespace-pre-wrap\">{r.message}</CardDescription>\n </CardHeader>\n {(shots.data ?? []).some((a) => a.url) ? (\n <CardContent className=\"flex flex-wrap gap-2\">\n {(shots.data ?? [])\n .filter((a) => a.url)\n .map((a) => (\n <a key={a.id} href={a.url!} target=\"_blank\" rel=\"noreferrer noopener\" className=\"block\">\n <img src={a.url!} alt={copy.thread.screenshot} className=\"h-24 w-auto rounded-md border object-cover\" />\n </a>\n ))}\n </CardContent>\n ) : null}\n {toolbar ? <CardContent className=\"border-t pt-4\">{toolbar(r, conversationId)}</CardContent> : null}\n </Card>\n <div className=\"min-h-0 flex-1\">\n <ChatThread\n conversationId={conversationId}\n resolveUser={names}\n title={r.title || copy.feedback.types[r.type]}\n onBack={onBack}\n search={false}\n scheduling={false}\n availability={false}\n placeholder={copy.thread.placeholder}\n />\n </div>\n </div>\n );\n}\n\n/** The person's view of their report: the report, then the conversation with support, live. */\nexport function SupportReportThread(props: SupportReportThreadProps) {\n const copy = useMemo(() => resolveSupportCopy(props.copy), [props.copy]);\n return <ReportThreadShell {...props} copyResolved={copy} testID=\"genesis-support-report-thread\" />;\n}\n","/**\n * The staff view of a report on genesis-chat: the report, its status and who has it, and the\n * conversation, where staff reply as observers and write internal notes (the composer's note\n * toggle) the person never sees.\n */\nimport { useMemo, useState } from \"react\";\nimport { useQuery, useQueryClient } from \"@tanstack/react-query\";\nimport { Label, Select, SelectContent, SelectItem, SelectTrigger, SelectValue } from \"@marktiderman/genesis-ui\";\nimport { chatKeys, useChat } from \"@marktiderman/genesis-chat/react\";\nimport type { ResolveUser } from \"@marktiderman/genesis-chat/web\";\nimport { FEEDBACK_STATUSES, type FeedbackStatus } from \"../contract\";\nimport { resolveSupportCopy, type SupportCopy } from \"../copy\";\nimport { ReportThreadShell, supportWebKeys, type SupportReportThreadProps } from \"./report-thread\";\n\nexport interface SupportStaffThreadProps extends Omit<SupportReportThreadProps, \"resolveUser\"> {\n /** Names people: the reporter and staff. Required, since staff see who wrote what. */\n resolveUser: ResolveUser;\n /** Who a report can be given to (support staff). Without it there is no assignee picker. */\n staff?: readonly { id: string; name: string }[];\n /** Every refused change (not staff, a network failure), for reporting. */\n onError?: (error: unknown) => void;\n}\n\nconst NOBODY = \"__nobody__\";\n\ninterface ControlsProps {\n client: SupportStaffThreadProps[\"client\"];\n reportId: string;\n status: FeedbackStatus;\n reporter: string | null;\n conversationId: string;\n staff?: SupportStaffThreadProps[\"staff\"];\n resolveUser: ResolveUser;\n copy: SupportCopy;\n onError?: (error: unknown) => void;\n}\n\nfunction StaffControls({ client, reportId, status, reporter, conversationId, staff, resolveUser, copy, onError }: ControlsProps) {\n const chat = useChat();\n const queryClient = useQueryClient();\n const [failed, setFailed] = useState(false);\n const conversation = useQuery({ queryKey: chatKeys.conversation(conversationId), queryFn: () => chat.client.conversation(conversationId) });\n const assignee = conversation.data?.assigneeId ?? null;\n const run = (work: Promise<unknown>) =>\n work\n .then(() => {\n setFailed(false);\n void queryClient.invalidateQueries({ queryKey: supportWebKeys.report(reportId) });\n void queryClient.invalidateQueries({ queryKey: chatKeys.conversation(conversationId) });\n })\n .catch((error: unknown) => {\n setFailed(true);\n onError?.(error);\n });\n return (\n <div className=\"flex flex-wrap items-end gap-4\">\n {reporter ? (\n <div className=\"flex flex-col gap-1\">\n <Label>{copy.staff.reporter}</Label>\n <span className=\"text-sm\">{resolveUser(reporter).name}</span>\n </div>\n ) : null}\n <div className=\"flex flex-col gap-1\">\n <Label htmlFor=\"genesis-support-staff-status\">{copy.staff.status}</Label>\n <Select value={status} onValueChange={(value) => void run(client.setStatus(reportId, value as FeedbackStatus))}>\n <SelectTrigger id=\"genesis-support-staff-status\" className=\"w-44\" data-testid=\"genesis-support-staff-status\">\n <SelectValue />\n </SelectTrigger>\n <SelectContent>\n {FEEDBACK_STATUSES.map((s) => (\n <SelectItem key={s} value={s}>\n {copy.status[s]}\n </SelectItem>\n ))}\n </SelectContent>\n </Select>\n </div>\n {staff ? (\n <div className=\"flex flex-col gap-1\">\n <Label htmlFor=\"genesis-support-staff-assignee\">{copy.staff.assignee}</Label>\n <Select value={assignee ?? NOBODY} onValueChange={(value) => void run(client.assign(reportId, value === NOBODY ? null : value))}>\n <SelectTrigger id=\"genesis-support-staff-assignee\" className=\"w-48\" data-testid=\"genesis-support-staff-assignee\">\n <SelectValue />\n </SelectTrigger>\n <SelectContent>\n <SelectItem value={NOBODY}>{copy.staff.unassigned}</SelectItem>\n {staff.map((s) => (\n <SelectItem key={s.id} value={s.id}>\n {s.name}\n </SelectItem>\n ))}\n </SelectContent>\n </Select>\n </div>\n ) : null}\n {failed ? (\n <p role=\"alert\" className=\"text-sm text-destructive\">\n {copy.staff.failed}\n </p>\n ) : null}\n </div>\n );\n}\n\n/** A report for staff: status and assignee controls over the live conversation, with internal notes. */\nexport function SupportStaffThread({ staff, onError, ...props }: SupportStaffThreadProps) {\n const copy = useMemo(() => resolveSupportCopy(props.copy), [props.copy]);\n return (\n <ReportThreadShell\n {...props}\n copyResolved={copy}\n testID=\"genesis-support-staff-thread\"\n toolbar={(report, conversationId) => (\n <StaffControls\n client={props.client}\n reportId={props.reportId}\n status={report.status}\n reporter={report.userId ?? null}\n conversationId={conversationId}\n staff={staff}\n resolveUser={props.resolveUser}\n copy={copy}\n onError={onError}\n />\n )}\n />\n );\n}\n"]}
package/dist/web.d.ts CHANGED
@@ -1,5 +1,5 @@
1
1
  import * as react from 'react';
2
- import { b as FeedbackSink, x as SupportClient, c as ContextCollector, A as SupportCopyOverrides, o as FeedbackType, j as FeedbackDelivery } from './copy-CuTArBFg.js';
2
+ import { b as FeedbackSink, K as SupportClient, c as ContextCollector, O as SupportCopyOverrides, o as FeedbackType, j as FeedbackDelivery } from './copy-D3rc0SCl.js';
3
3
  import '@supabase/supabase-js';
4
4
 
5
5
  /**
package/dist/web.js CHANGED
@@ -1,4 +1,5 @@
1
- import { createContextCollector, cleanRoute, resolveSupportCopy, FEEDBACK_TYPES } from './chunk-ZV4KJBUF.js';
1
+ import { createContextCollector, FEEDBACK_TYPES } from './chunk-MMBNG2NK.js';
2
+ import { cleanRoute, resolveSupportCopy } from './chunk-OSB6G6Y3.js';
2
3
  import { useMemo, useState, useEffect } from 'react';
3
4
  import { Tabs, TabsList, TabsTrigger, TabsContent, Label, ToggleGroup, ToggleGroupItem, Textarea, Button, Alert, AlertDescription, Badge, Sheet, SheetContent, SheetHeader, SheetTitle, SheetDescription } from '@marktiderman/genesis-ui';
4
5
  import { jsxs, jsx, Fragment } from 'react/jsx-runtime';
package/dist/web.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"sources":["../src/web/capture.ts","../src/web/pin.ts","../src/web/feedback-panel.tsx","../src/web/launcher.tsx"],"names":["useMemo","useState","jsxs","jsx","Button"],"mappings":"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","file":"web.js","sourcesContent":["/**\n * Screenshots on the web. The browser only lets a page capture itself with\n * the person's say-so: `getDisplayMedia` with `preferCurrentTab` asks, and a\n * single frame is kept. When the person says no (or the browser can't), there\n * is no screenshot: never a fake one.\n */\n\nexport interface WebCapture {\n /** `data:image/webp;base64,…` (or JPEG where WebP isn't encoded). */\n dataUrl: string;\n contentType: \"image/webp\" | \"image/jpeg\";\n width: number;\n height: number;\n}\n\ntype DisplayMediaDevices = MediaDevices & { getDisplayMedia(constraints: Record<string, unknown>): Promise<MediaStream> };\n\n/** Whether this browser can capture the tab at all. */\nexport function canCaptureScreenshot(): boolean {\n const devices = (globalThis.navigator as Navigator | undefined)?.mediaDevices as Partial<DisplayMediaDevices> | undefined;\n return typeof devices?.getDisplayMedia === \"function\";\n}\n\n/** One frame of the current tab, or `null` when the person declined or the browser can't. */\nexport async function captureScreenshot(doc: Document = document): Promise<WebCapture | null> {\n if (!canCaptureScreenshot()) return null;\n let stream: MediaStream;\n try {\n stream = await (navigator.mediaDevices as DisplayMediaDevices).getDisplayMedia({\n video: { preferCurrentTab: true, frameRate: 1 },\n audio: false,\n preferCurrentTab: true,\n selfBrowserSurface: \"include\",\n });\n } catch {\n return null;\n }\n try {\n const video = doc.createElement(\"video\");\n video.muted = true;\n video.playsInline = true;\n video.srcObject = stream;\n await video.play();\n await new Promise((resolve) => requestAnimationFrame(() => resolve(undefined)));\n const canvas = doc.createElement(\"canvas\");\n canvas.width = video.videoWidth;\n canvas.height = video.videoHeight;\n const ctx = canvas.getContext(\"2d\");\n if (!ctx || !canvas.width || !canvas.height) return null;\n ctx.drawImage(video, 0, 0);\n return fromCanvas(canvas);\n } catch {\n return null;\n } finally {\n stream.getTracks().forEach((track) => track.stop());\n }\n}\n\n/** The longest side a screenshot keeps: enough to read, well under the bucket's 5 MB. */\nexport const MAX_SCREENSHOT_SIDE = 2000;\n\nfunction fromCanvas(source: HTMLCanvasElement): WebCapture {\n let canvas = source;\n const scale = Math.min(1, MAX_SCREENSHOT_SIDE / Math.max(source.width, source.height));\n if (scale < 1) {\n canvas = source.ownerDocument.createElement(\"canvas\");\n canvas.width = Math.round(source.width * scale);\n canvas.height = Math.round(source.height * scale);\n canvas.getContext(\"2d\")?.drawImage(source, 0, 0, canvas.width, canvas.height);\n }\n // WebP where the browser encodes it, else JPEG (never PNG: a full tab as PNG can pass 5 MB).\n const webp = canvas.toDataURL(\"image/webp\", 0.9);\n if (webp.startsWith(\"data:image/webp\")) return { dataUrl: webp, contentType: \"image/webp\", width: canvas.width, height: canvas.height };\n return { dataUrl: canvas.toDataURL(\"image/jpeg\", 0.88), contentType: \"image/jpeg\", width: canvas.width, height: canvas.height };\n}\n\n/** A stroke in fractions of the image (0 to 1), so it survives resizing. */\nexport type Stroke = Array<{ x: number; y: number }>;\n\n/** A rectangle in fractions of the image, painted solid to hide what's under it. */\nexport interface Redaction {\n x: number;\n y: number;\n width: number;\n height: number;\n}\n\n/** Draws pen strokes and solid redactions onto a captured image; returns the new capture. */\nexport async function annotateScreenshot(\n capture: WebCapture,\n { strokes = [], redactions = [], penColor = \"red\", redactColor = \"black\" }: { strokes?: Stroke[]; redactions?: Redaction[]; penColor?: string; redactColor?: string },\n doc: Document = document,\n): Promise<WebCapture> {\n const img = doc.createElement(\"img\");\n img.src = capture.dataUrl;\n await new Promise<void>((resolve, reject) => {\n img.onload = () => resolve();\n img.onerror = () => reject(new Error(\"image_load_failed\"));\n });\n const canvas = doc.createElement(\"canvas\");\n canvas.width = img.naturalWidth;\n canvas.height = img.naturalHeight;\n const ctx = canvas.getContext(\"2d\");\n if (!ctx) return capture;\n ctx.drawImage(img, 0, 0);\n ctx.fillStyle = redactColor;\n for (const r of redactions) ctx.fillRect(r.x * canvas.width, r.y * canvas.height, r.width * canvas.width, r.height * canvas.height);\n ctx.strokeStyle = penColor;\n ctx.lineWidth = Math.max(3, canvas.width / 300);\n ctx.lineCap = \"round\";\n ctx.lineJoin = \"round\";\n for (const stroke of strokes) {\n if (stroke.length < 2) continue;\n ctx.beginPath();\n ctx.moveTo(stroke[0]!.x * canvas.width, stroke[0]!.y * canvas.height);\n for (const p of stroke.slice(1)) ctx.lineTo(p.x * canvas.width, p.y * canvas.height);\n ctx.stroke();\n }\n return fromCanvas(canvas);\n}\n","/**\n * Pins on the live page: the person points at the spot a report is about\n * (`pickPin`), and numbered pins show their open reports on the page they\n * were sent from (`createPinOverlay`). A pin travels in the report's\n * context as `pin`, so it needs no column of its own.\n *\n * Plain DOM on the host document (no iframe, no framework), colored from the\n * Genesis theme variables.\n */\n\nexport interface FeedbackPin {\n /** A CSS selector for the element under the point, when one is stable (an id or a data-testid). */\n locator?: string | null;\n /** Where in that element, in percent. */\n xPct?: number | null;\n yPct?: number | null;\n /** The point in the viewport, as a fallback. */\n viewportX: number;\n viewportY: number;\n scrollX: number;\n scrollY: number;\n}\n\nexport interface PinnedReport {\n id: string;\n title: string;\n /** The route (path) it was sent from. */\n route: string | null;\n pin: FeedbackPin;\n}\n\nconst cssEscape = (value: string) => (typeof CSS !== \"undefined\" && CSS.escape ? CSS.escape(value) : value.replace(/[^A-Za-z0-9_-]/g, \"\\\\$&\"));\n\n/** A selector for an element that is likely to survive a re-render: its id, else a data-testid. */\nexport function stableLocator(el: Element | null): string | null {\n for (let node: Element | null = el; node && node !== node.ownerDocument.documentElement; node = node.parentElement) {\n if (node.id) return `#${cssEscape(node.id)}`;\n const testId = node.getAttribute(\"data-testid\");\n if (testId) return `[data-testid=\"${testId.replace(/\"/g, '\\\\\"')}\"]`;\n }\n return null;\n}\n\n/**\n * Waits for one click anywhere on the page and returns the pin, or `null`\n * on Escape. The click doesn't reach the page.\n */\nexport function pickPin(doc: Document = document): Promise<FeedbackPin | null> {\n return new Promise((resolve) => {\n const veil = doc.createElement(\"div\");\n veil.setAttribute(\"data-genesis-support-pin-picker\", \"\");\n veil.setAttribute(\"role\", \"presentation\");\n Object.assign(veil.style, { position: \"fixed\", inset: \"0\", zIndex: \"2147483000\", cursor: \"crosshair\", background: \"hsl(var(--foreground) / 0.06)\" });\n const done = (pin: FeedbackPin | null) => {\n veil.remove();\n doc.removeEventListener(\"keydown\", onKey, true);\n resolve(pin);\n };\n const onKey = (event: KeyboardEvent) => {\n if (event.key === \"Escape\") done(null);\n };\n veil.addEventListener(\"click\", (event) => {\n event.preventDefault();\n event.stopPropagation();\n veil.style.pointerEvents = \"none\";\n const target = doc.elementFromPoint?.(event.clientX, event.clientY) ?? null;\n const locator = stableLocator(target);\n const anchor = locator ? doc.querySelector(locator) : null;\n const rect = anchor?.getBoundingClientRect();\n const view = doc.defaultView;\n done({\n locator,\n xPct: rect && rect.width ? Math.round(((event.clientX - rect.left) / rect.width) * 100) : null,\n yPct: rect && rect.height ? Math.round(((event.clientY - rect.top) / rect.height) * 100) : null,\n viewportX: event.clientX,\n viewportY: event.clientY,\n scrollX: view?.scrollX ?? 0,\n scrollY: view?.scrollY ?? 0,\n });\n });\n doc.addEventListener(\"keydown\", onKey, true);\n doc.body.appendChild(veil);\n });\n}\n\n/** Where a pin sits now: on its element if it is still there, else where it was clicked. */\nexport function resolvePin(doc: Document, pin: FeedbackPin): { left: number; top: number } {\n if (pin.locator) {\n try {\n const node = doc.querySelector(pin.locator);\n if (node) {\n const r = node.getBoundingClientRect();\n return { left: r.left + (r.width * (pin.xPct ?? 50)) / 100, top: r.top + (r.height * (pin.yPct ?? 50)) / 100 };\n }\n } catch {\n // an invalid selector: fall back to the point\n }\n }\n return { left: pin.viewportX, top: pin.viewportY };\n}\n\nexport interface PinOverlay {\n setReports(reports: PinnedReport[]): void;\n destroy(): void;\n}\n\n/** Numbered pins for reports sent from the current path. Re-drawn on navigation, scroll and resize. */\nexport function createPinOverlay(options: { reports: PinnedReport[]; onPinClick?: (report: PinnedReport) => void; document?: Document }): PinOverlay {\n const doc = options.document ?? document;\n const view = doc.defaultView;\n const host = doc.createElement(\"div\");\n host.setAttribute(\"data-genesis-support-pins\", \"\");\n host.setAttribute(\"role\", \"group\");\n host.setAttribute(\"aria-label\", \"Feedback pins\");\n Object.assign(host.style, { position: \"fixed\", inset: \"0\", zIndex: \"2147482999\", pointerEvents: \"none\" });\n doc.body.appendChild(host);\n let reports = options.reports.slice();\n\n const render = () => {\n host.replaceChildren();\n const path = view?.location.pathname ?? \"\";\n reports\n .filter((r) => !r.route || r.route === path)\n .forEach((report, i) => {\n const { left, top } = resolvePin(doc, report.pin);\n const pin = doc.createElement(\"button\");\n pin.type = \"button\";\n pin.textContent = String(i + 1);\n pin.setAttribute(\"aria-label\", `Feedback ${i + 1}: ${report.title}`);\n pin.title = report.title;\n Object.assign(pin.style, {\n position: \"fixed\",\n left: `${Math.max(12, left)}px`,\n top: `${Math.max(12, top)}px`,\n transform: \"translate(-50%, -50%)\",\n width: \"28px\",\n height: \"28px\",\n borderRadius: \"999px\",\n border: \"2px solid hsl(var(--background))\",\n background: \"hsl(var(--destructive))\",\n color: \"hsl(var(--destructive-foreground))\",\n font: \"600 12px system-ui, sans-serif\",\n pointerEvents: \"auto\",\n cursor: \"pointer\",\n });\n pin.addEventListener(\"click\", (event) => {\n event.stopPropagation();\n options.onPinClick?.(report);\n });\n host.appendChild(pin);\n });\n };\n\n view?.addEventListener(\"popstate\", render);\n view?.addEventListener(\"resize\", render);\n view?.addEventListener(\"scroll\", render, { passive: true });\n render();\n return {\n setReports(next) {\n reports = next.slice();\n render();\n },\n destroy() {\n view?.removeEventListener(\"popstate\", render);\n view?.removeEventListener(\"resize\", render);\n view?.removeEventListener(\"scroll\", render);\n host.remove();\n },\n };\n}\n","/**\n * The web feedback panel, built from Genesis UI: a \"New\" tab (type, message,\n * an optional screenshot of the tab with pen marks and hidden areas, an\n * optional pin on the page) and a \"My reports\" tab (the person's reports and\n * their status). Loading, empty and failed reads are told apart.\n *\n * Put it anywhere (a page, a Sheet); `FeedbackLauncher` puts it in a Sheet\n * behind a floating button.\n */\nimport { useEffect, useMemo, useState, type PointerEvent } from \"react\";\nimport {\n Alert,\n AlertDescription,\n Badge,\n Button,\n Label,\n Tabs,\n TabsContent,\n TabsList,\n TabsTrigger,\n Textarea,\n ToggleGroup,\n ToggleGroupItem,\n} from \"@marktiderman/genesis-ui\";\nimport type { SupportClient, SupportReport } from \"../client\";\nimport { resolveSupportCopy, type SupportCopyOverrides } from \"../copy\";\nimport { cleanRoute } from \"../contract\";\nimport { createContextCollector, FEEDBACK_TYPES, type ContextCollector, type FeedbackDelivery, type FeedbackSink, type FeedbackType } from \"../record\";\nimport { annotateScreenshot, canCaptureScreenshot, captureScreenshot, type Redaction, type Stroke, type WebCapture } from \"./capture\";\nimport { pickPin, type FeedbackPin } from \"./pin\";\n\n/** The default web collector: the path (never the query string), `web`, and the viewport and language. */\nexport function webContextCollector(options: { appVersion?: string } = {}): ContextCollector {\n return createContextCollector({\n appVersion: options.appVersion,\n platform: \"web\",\n route: () => (typeof location === \"undefined\" ? undefined : cleanRoute(location.pathname)),\n device: () =>\n typeof window === \"undefined\"\n ? undefined\n : { viewport: { width: window.innerWidth, height: window.innerHeight }, pixelRatio: window.devicePixelRatio, language: navigator.language },\n });\n}\n\nexport interface FeedbackPanelProps {\n /** Where feedback goes. A support client also fills \"My reports\". */\n client: FeedbackSink & Partial<Pick<SupportClient, \"myReports\">>;\n collector?: ContextCollector;\n copy?: SupportCopyOverrides;\n /** Offer a screenshot of the tab. Default: when the browser can capture. */\n screenshots?: boolean;\n /** Offer a pin on the page. Default on. */\n pins?: boolean;\n defaultType?: FeedbackType;\n onSent?: (delivery: FeedbackDelivery) => void;\n /** Hidden while the person picks a pin or the browser asks to capture, so the page shows. */\n onHide?: (hidden: boolean) => void;\n}\n\ntype Status = { kind: \"idle\" } | { kind: \"sending\" } | { kind: \"sent\"; dropped: number } | { kind: \"error\"; message: string };\n\nexport function FeedbackPanel({ client, collector, copy: overrides, screenshots, pins = true, defaultType = \"bug\", onSent, onHide }: FeedbackPanelProps) {\n const copy = useMemo(() => resolveSupportCopy(overrides), [overrides]);\n const collect = useMemo(() => collector ?? webContextCollector(), [collector]);\n const [type, setType] = useState<FeedbackType>(defaultType);\n const [message, setMessage] = useState(\"\");\n const [shot, setShot] = useState<WebCapture | null>(null);\n // Marks stay a list until Send, then are drawn onto the image once: a quick second mark can't\n // drop the first, and nothing is sent half-marked.\n const [marks, setMarks] = useState<Marks>({ strokes: [], redactions: [] });\n const [pin, setPin] = useState<FeedbackPin | null>(null);\n const [status, setStatus] = useState<Status>({ kind: \"idle\" });\n const canShoot = screenshots ?? canCaptureScreenshot();\n\n const takeScreenshot = async () => {\n onHide?.(true);\n try {\n setShot(await captureScreenshot());\n setMarks({ strokes: [], redactions: [] });\n } finally {\n onHide?.(false);\n }\n };\n\n const placePin = async () => {\n onHide?.(true);\n try {\n setPin(await pickPin());\n } finally {\n onHide?.(false);\n }\n };\n\n const send = async () => {\n if (!message.trim()) {\n setStatus({ kind: \"error\", message: copy.feedback.messageRequired });\n return;\n }\n setStatus({ kind: \"sending\" });\n try {\n const context = await collect.collect();\n if (pin) context.extra = { ...context.extra, pin };\n let image = shot;\n if (shot && (marks.strokes.length || marks.redactions.length)) {\n try {\n image = await annotateScreenshot(shot, marks);\n } catch {\n // Never send the screenshot without the parts the person hid.\n setStatus({ kind: \"error\", message: copy.annotate.failed });\n return;\n }\n }\n const delivery = await client.submit({\n type,\n message: message.trim(),\n context,\n attachments: image ? [{ kind: \"screenshot\", contentType: image.contentType, base64: image.dataUrl, width: image.width, height: image.height }] : [],\n });\n setStatus({ kind: \"sent\", dropped: delivery.attachmentsDropped });\n setMessage(\"\");\n setShot(null);\n setMarks({ strokes: [], redactions: [] });\n setPin(null);\n onSent?.(delivery);\n } catch (error) {\n const limited = (error as { code?: string }).code === \"GS429\";\n setStatus({ kind: \"error\", message: limited ? copy.feedback.rateLimited : copy.feedback.failedBody });\n }\n };\n\n return (\n <Tabs defaultValue=\"new\" className=\"flex flex-col gap-4\" data-testid=\"genesis-support-panel\">\n <TabsList>\n <TabsTrigger value=\"new\">{copy.feedback.title}</TabsTrigger>\n {client.myReports ? <TabsTrigger value=\"mine\">{copy.inbox.sectionTitle}</TabsTrigger> : null}\n </TabsList>\n <TabsContent value=\"new\" className=\"flex flex-col gap-4\">\n <div className=\"flex flex-col gap-2\">\n <Label>{copy.feedback.typeLabel}</Label>\n <ToggleGroup type=\"single\" value={type} onValueChange={(v: string) => v && setType(v as FeedbackType)} aria-label={copy.feedback.typeLabel}>\n {FEEDBACK_TYPES.map((t) => (\n <ToggleGroupItem key={t} value={t} data-testid={`genesis-support-type-${t}`}>\n {copy.feedback.types[t]}\n </ToggleGroupItem>\n ))}\n </ToggleGroup>\n </div>\n <div className=\"flex flex-col gap-2\">\n <Label htmlFor=\"genesis-support-message\">{copy.feedback.messageLabel}</Label>\n <Textarea\n id=\"genesis-support-message\"\n data-testid=\"genesis-support-message\"\n value={message}\n maxLength={20000}\n rows={5}\n placeholder={copy.feedback.messagePlaceholder}\n onChange={(e) => setMessage(e.target.value)}\n />\n </div>\n {canShoot || pins ? (\n <div className=\"flex flex-wrap gap-2\">\n {canShoot && !shot ? (\n <Button type=\"button\" variant=\"outline\" size=\"sm\" onClick={() => void takeScreenshot()} data-testid=\"genesis-support-capture\">\n {copy.feedback.screenshotLabel}\n </Button>\n ) : null}\n {pins ? (\n <Button type=\"button\" variant=\"outline\" size=\"sm\" onClick={() => void placePin()} data-testid=\"genesis-support-pin\">\n {pin ? copy.feedback.pinned : copy.feedback.pin}\n </Button>\n ) : null}\n </div>\n ) : null}\n {shot ? <ScreenshotEditor shot={shot} marks={marks} onMarks={setMarks} onRemove={() => setShot(null)} copy={copy} /> : null}\n {status.kind === \"error\" ? (\n <Alert variant=\"destructive\" data-testid=\"genesis-support-error\">\n <AlertDescription>{status.message}</AlertDescription>\n </Alert>\n ) : null}\n {status.kind === \"sent\" ? (\n <Alert data-testid=\"genesis-support-sent\">\n <AlertDescription>{status.dropped ? copy.feedback.sentWithoutScreenshot : copy.feedback.sentBody}</AlertDescription>\n </Alert>\n ) : null}\n <Button type=\"button\" onClick={() => void send()} disabled={status.kind === \"sending\"} data-testid=\"genesis-support-send\">\n {status.kind === \"sending\" ? copy.feedback.sending : copy.feedback.send}\n </Button>\n </TabsContent>\n {client.myReports ? (\n <TabsContent value=\"mine\">\n <MyReports load={client.myReports} copy={copy} refreshKey={status.kind === \"sent\" ? 1 : 0} />\n </TabsContent>\n ) : null}\n </Tabs>\n );\n}\n\nfunction MyReports({ load, copy, refreshKey }: { load: NonNullable<SupportClient[\"myReports\"]>; copy: ReturnType<typeof resolveSupportCopy>; refreshKey: number }) {\n const [state, setState] = useState<{ kind: \"loading\" } | { kind: \"error\" } | { kind: \"ok\"; reports: SupportReport[] }>({ kind: \"loading\" });\n useEffect(() => {\n let alive = true;\n setState({ kind: \"loading\" });\n load()\n .then((reports) => alive && setState({ kind: \"ok\", reports }))\n .catch(() => alive && setState({ kind: \"error\" }));\n return () => {\n alive = false;\n };\n }, [load, refreshKey]);\n if (state.kind === \"loading\") return <p className=\"text-sm text-muted-foreground\" data-testid=\"genesis-support-mine-loading\">…</p>;\n if (state.kind === \"error\")\n return (\n <Alert variant=\"destructive\" data-testid=\"genesis-support-mine-error\">\n <AlertDescription>{copy.feedback.failedBody}</AlertDescription>\n </Alert>\n );\n if (!state.reports.length)\n return (\n <div data-testid=\"genesis-support-mine-empty\" className=\"flex flex-col gap-1\">\n <p className=\"font-medium\">{copy.inbox.emptyTitle}</p>\n <p className=\"text-sm text-muted-foreground\">{copy.inbox.emptyBody}</p>\n </div>\n );\n return (\n <ul className=\"flex flex-col divide-y\" data-testid=\"genesis-support-mine\">\n {state.reports.map((r) => (\n <li key={r.id} className=\"flex items-center justify-between gap-3 py-2\">\n <span className=\"truncate\">{r.title || r.message}</span>\n <span className=\"flex shrink-0 items-center gap-2\">\n {r.unread ? <Badge>{copy.inbox.unread}</Badge> : null}\n <Badge variant=\"secondary\">{copy.status[r.status]}</Badge>\n </span>\n </li>\n ))}\n </ul>\n );\n}\n\n/** The box being dragged, while it is dragged. */\nfunction DraftBox({ drag }: { drag: { start: { x: number; y: number }; points: Stroke } }) {\n const end = drag.points[drag.points.length - 1] ?? drag.start;\n const x = Math.min(drag.start.x, end.x);\n const y = Math.min(drag.start.y, end.y);\n return (\n <div\n className=\"pointer-events-none absolute border-2 border-dashed border-foreground bg-foreground/60\"\n style={{ left: `${x * 100}%`, top: `${y * 100}%`, width: `${Math.abs(end.x - drag.start.x) * 100}%`, height: `${Math.abs(end.y - drag.start.y) * 100}%` }}\n />\n );\n}\n\n/** Pen strokes and hidden areas, in fractions of the image. */\nexport interface Marks {\n strokes: Stroke[];\n redactions: Redaction[];\n /** The kinds in the order they were drawn, for Undo. */\n order?: Array<\"stroke\" | \"redaction\">;\n}\n\n/** Marks without the newest one (by `order`; without it, the last redaction, then the last stroke). */\nexport function undoMark(marks: Marks): Marks {\n const order = marks.order ?? [];\n const last = order[order.length - 1] ?? (marks.redactions.length ? \"redaction\" : \"stroke\");\n const rest = order.slice(0, -1);\n return last === \"redaction\"\n ? { ...marks, redactions: marks.redactions.slice(0, -1), order: rest }\n : { ...marks, strokes: marks.strokes.slice(0, -1), order: rest };\n}\n\n/** The captured tab, with pen strokes and hidden (solid) areas shown over it; drawn into the image at Send. */\nfunction ScreenshotEditor({\n shot,\n marks,\n onMarks,\n onRemove,\n copy,\n}: {\n shot: WebCapture;\n marks: Marks;\n onMarks: (next: Marks) => void;\n onRemove: () => void;\n copy: ReturnType<typeof resolveSupportCopy>;\n}) {\n const [tool, setTool] = useState<\"pen\" | \"hide\">(\"pen\");\n const [drag, setDrag] = useState<{ start: { x: number; y: number }; points: Stroke } | null>(null);\n const point = (e: PointerEvent<HTMLDivElement>) => {\n const r = e.currentTarget.getBoundingClientRect();\n return { x: Math.min(1, Math.max(0, (e.clientX - r.left) / r.width)), y: Math.min(1, Math.max(0, (e.clientY - r.top) / r.height)) };\n };\n const finish = (end: { x: number; y: number }) => {\n if (!drag) return;\n setDrag(null);\n const order = marks.order ?? [];\n if (tool === \"pen\") onMarks({ ...marks, strokes: [...marks.strokes, [...drag.points, end]], order: [...order, \"stroke\"] });\n else\n onMarks({\n ...marks,\n order: [...order, \"redaction\"],\n redactions: [...marks.redactions, { x: Math.min(drag.start.x, end.x), y: Math.min(drag.start.y, end.y), width: Math.abs(end.x - drag.start.x), height: Math.abs(end.y - drag.start.y) }],\n });\n };\n const pct = (n: number) => `${n * 100}%`;\n const strokes = drag && tool === \"pen\" ? [...marks.strokes, drag.points] : marks.strokes;\n return (\n <div className=\"flex flex-col gap-2\" data-testid=\"genesis-support-screenshot\">\n <div className=\"flex items-center justify-between gap-2\">\n <Label>{copy.feedback.screenshotLabel}</Label>\n <div className=\"flex gap-2\">\n <ToggleGroup type=\"single\" size=\"sm\" value={tool} onValueChange={(v: string) => v && setTool(v as \"pen\" | \"hide\")}>\n <ToggleGroupItem value=\"pen\">{copy.annotate.pen}</ToggleGroupItem>\n <ToggleGroupItem value=\"hide\">{copy.annotate.hide}</ToggleGroupItem>\n </ToggleGroup>\n <Button\n type=\"button\"\n variant=\"ghost\"\n size=\"sm\"\n disabled={!marks.strokes.length && !marks.redactions.length}\n onClick={() => onMarks(undoMark(marks))}\n data-testid=\"genesis-support-undo\"\n >\n {copy.annotate.undo}\n </Button>\n <Button type=\"button\" variant=\"ghost\" size=\"sm\" onClick={onRemove} data-testid=\"genesis-support-remove-screenshot\">\n {copy.feedback.removeScreenshot}\n </Button>\n </div>\n </div>\n <div\n className=\"relative cursor-crosshair touch-none overflow-hidden rounded-md border\"\n data-testid=\"genesis-support-screenshot-surface\"\n onPointerDown={(e) => {\n // Keep the gesture when the pointer leaves the image, so a release outside still ends it.\n e.currentTarget.setPointerCapture?.(e.pointerId);\n const p = point(e);\n setDrag({ start: p, points: [p] });\n }}\n onPointerCancel={() => setDrag(null)}\n onPointerMove={(e) => drag && setDrag({ ...drag, points: tool === \"pen\" ? [...drag.points, point(e)] : [drag.start, point(e)] })}\n onPointerUp={(e) => finish(point(e))}\n >\n <img src={shot.dataUrl} alt={copy.feedback.screenshotLabel} className=\"block w-full select-none\" draggable={false} />\n <svg className=\"pointer-events-none absolute inset-0 h-full w-full\" viewBox=\"0 0 1 1\" preserveAspectRatio=\"none\" aria-hidden>\n {strokes.map((stroke, i) => (\n <polyline\n key={i}\n points={stroke.map((p) => `${p.x},${p.y}`).join(\" \")}\n fill=\"none\"\n stroke=\"hsl(var(--destructive))\"\n strokeWidth={0.006}\n strokeLinecap=\"round\"\n strokeLinejoin=\"round\"\n />\n ))}\n </svg>\n {drag && tool === \"hide\" ? <DraftBox drag={drag} /> : null}\n {marks.redactions.map((r, i) => (\n <div\n key={i}\n data-testid={`genesis-support-redaction-${i}`}\n className=\"pointer-events-none absolute bg-foreground\"\n style={{ left: pct(r.x), top: pct(r.y), width: pct(r.width), height: pct(r.height) }}\n />\n ))}\n </div>\n <p className=\"text-xs text-muted-foreground\">{copy.feedback.screenshotHint}</p>\n </div>\n );\n}\n","/**\n * The feedback launcher: a floating button that opens `FeedbackPanel` in a\n * Genesis UI Sheet, and `mountSupportWidget`, the loader that puts it on any\n * page with one call (for a page that isn't a React app of its own).\n */\nimport { useMemo, useState } from \"react\";\nimport { createRoot } from \"react-dom/client\";\nimport { Button, Sheet, SheetContent, SheetDescription, SheetHeader, SheetTitle } from \"@marktiderman/genesis-ui\";\nimport { resolveSupportCopy } from \"../copy\";\nimport { FeedbackPanel, type FeedbackPanelProps } from \"./feedback-panel\";\n\nexport type LauncherPosition = \"bottom-right\" | \"bottom-left\";\n\nexport interface FeedbackLauncherProps extends FeedbackPanelProps {\n position?: LauncherPosition;\n /** The button's text. Default the copy's \"Send feedback\". */\n label?: string;\n}\n\nconst POSITIONS: Record<LauncherPosition, string> = {\n \"bottom-right\": \"fixed bottom-4 right-4 z-50\",\n \"bottom-left\": \"fixed bottom-4 left-4 z-50\",\n};\n\nexport function FeedbackLauncher({ position = \"bottom-right\", label, ...panel }: FeedbackLauncherProps) {\n const copy = useMemo(() => resolveSupportCopy(panel.copy), [panel.copy]);\n const [open, setOpen] = useState(false);\n // While the person picks a pin or the browser asks to capture, the sheet steps aside.\n const [hidden, setHidden] = useState(false);\n return (\n <>\n <Button className={POSITIONS[position]} onClick={() => setOpen(true)} data-testid=\"genesis-support-launcher\" aria-haspopup=\"dialog\">\n {label ?? copy.settings.sendFeedback}\n </Button>\n <Sheet open={open && !hidden} onOpenChange={setOpen}>\n <SheetContent side=\"right\" className=\"flex w-full flex-col gap-4 overflow-y-auto sm:max-w-md\">\n <SheetHeader>\n <SheetTitle>{copy.feedback.title}</SheetTitle>\n <SheetDescription>{copy.feedback.messagePlaceholder}</SheetDescription>\n </SheetHeader>\n <FeedbackPanel {...panel} onHide={setHidden} />\n </SheetContent>\n </Sheet>\n </>\n );\n}\n\n/**\n * Mount the launcher into the page: into `container`, or a new element at the\n * end of `<body>`. Returns the unmount. The page needs Genesis UI's styles.\n */\nexport function mountSupportWidget(props: FeedbackLauncherProps & { container?: HTMLElement }): () => void {\n const { container, ...launcher } = props;\n const host = container ?? document.body.appendChild(document.createElement(\"div\"));\n host.setAttribute(\"data-genesis-support\", \"\");\n const root = createRoot(host);\n root.render(<FeedbackLauncher {...launcher} />);\n return () => {\n root.unmount();\n if (!container) host.remove();\n };\n}\n"]}
1
+ {"version":3,"sources":["../src/web/capture.ts","../src/web/pin.ts","../src/web/feedback-panel.tsx","../src/web/launcher.tsx"],"names":["useMemo","useState","jsxs","jsx","Button"],"mappings":"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","file":"web.js","sourcesContent":["/**\n * Screenshots on the web. The browser only lets a page capture itself with\n * the person's say-so: `getDisplayMedia` with `preferCurrentTab` asks, and a\n * single frame is kept. When the person says no (or the browser can't), there\n * is no screenshot: never a fake one.\n */\n\nexport interface WebCapture {\n /** `data:image/webp;base64,…` (or JPEG where WebP isn't encoded). */\n dataUrl: string;\n contentType: \"image/webp\" | \"image/jpeg\";\n width: number;\n height: number;\n}\n\ntype DisplayMediaDevices = MediaDevices & { getDisplayMedia(constraints: Record<string, unknown>): Promise<MediaStream> };\n\n/** Whether this browser can capture the tab at all. */\nexport function canCaptureScreenshot(): boolean {\n const devices = (globalThis.navigator as Navigator | undefined)?.mediaDevices as Partial<DisplayMediaDevices> | undefined;\n return typeof devices?.getDisplayMedia === \"function\";\n}\n\n/** One frame of the current tab, or `null` when the person declined or the browser can't. */\nexport async function captureScreenshot(doc: Document = document): Promise<WebCapture | null> {\n if (!canCaptureScreenshot()) return null;\n let stream: MediaStream;\n try {\n stream = await (navigator.mediaDevices as DisplayMediaDevices).getDisplayMedia({\n video: { preferCurrentTab: true, frameRate: 1 },\n audio: false,\n preferCurrentTab: true,\n selfBrowserSurface: \"include\",\n });\n } catch {\n return null;\n }\n try {\n const video = doc.createElement(\"video\");\n video.muted = true;\n video.playsInline = true;\n video.srcObject = stream;\n await video.play();\n await new Promise((resolve) => requestAnimationFrame(() => resolve(undefined)));\n const canvas = doc.createElement(\"canvas\");\n canvas.width = video.videoWidth;\n canvas.height = video.videoHeight;\n const ctx = canvas.getContext(\"2d\");\n if (!ctx || !canvas.width || !canvas.height) return null;\n ctx.drawImage(video, 0, 0);\n return fromCanvas(canvas);\n } catch {\n return null;\n } finally {\n stream.getTracks().forEach((track) => track.stop());\n }\n}\n\n/** The longest side a screenshot keeps: enough to read, well under the bucket's 5 MB. */\nexport const MAX_SCREENSHOT_SIDE = 2000;\n\nfunction fromCanvas(source: HTMLCanvasElement): WebCapture {\n let canvas = source;\n const scale = Math.min(1, MAX_SCREENSHOT_SIDE / Math.max(source.width, source.height));\n if (scale < 1) {\n canvas = source.ownerDocument.createElement(\"canvas\");\n canvas.width = Math.round(source.width * scale);\n canvas.height = Math.round(source.height * scale);\n canvas.getContext(\"2d\")?.drawImage(source, 0, 0, canvas.width, canvas.height);\n }\n // WebP where the browser encodes it, else JPEG (never PNG: a full tab as PNG can pass 5 MB).\n const webp = canvas.toDataURL(\"image/webp\", 0.9);\n if (webp.startsWith(\"data:image/webp\")) return { dataUrl: webp, contentType: \"image/webp\", width: canvas.width, height: canvas.height };\n return { dataUrl: canvas.toDataURL(\"image/jpeg\", 0.88), contentType: \"image/jpeg\", width: canvas.width, height: canvas.height };\n}\n\n/** A stroke in fractions of the image (0 to 1), so it survives resizing. */\nexport type Stroke = Array<{ x: number; y: number }>;\n\n/** A rectangle in fractions of the image, painted solid to hide what's under it. */\nexport interface Redaction {\n x: number;\n y: number;\n width: number;\n height: number;\n}\n\n/** Draws pen strokes and solid redactions onto a captured image; returns the new capture. */\nexport async function annotateScreenshot(\n capture: WebCapture,\n { strokes = [], redactions = [], penColor = \"red\", redactColor = \"black\" }: { strokes?: Stroke[]; redactions?: Redaction[]; penColor?: string; redactColor?: string },\n doc: Document = document,\n): Promise<WebCapture> {\n const img = doc.createElement(\"img\");\n img.src = capture.dataUrl;\n await new Promise<void>((resolve, reject) => {\n img.onload = () => resolve();\n img.onerror = () => reject(new Error(\"image_load_failed\"));\n });\n const canvas = doc.createElement(\"canvas\");\n canvas.width = img.naturalWidth;\n canvas.height = img.naturalHeight;\n const ctx = canvas.getContext(\"2d\");\n if (!ctx) return capture;\n ctx.drawImage(img, 0, 0);\n ctx.fillStyle = redactColor;\n for (const r of redactions) ctx.fillRect(r.x * canvas.width, r.y * canvas.height, r.width * canvas.width, r.height * canvas.height);\n ctx.strokeStyle = penColor;\n ctx.lineWidth = Math.max(3, canvas.width / 300);\n ctx.lineCap = \"round\";\n ctx.lineJoin = \"round\";\n for (const stroke of strokes) {\n if (stroke.length < 2) continue;\n ctx.beginPath();\n ctx.moveTo(stroke[0]!.x * canvas.width, stroke[0]!.y * canvas.height);\n for (const p of stroke.slice(1)) ctx.lineTo(p.x * canvas.width, p.y * canvas.height);\n ctx.stroke();\n }\n return fromCanvas(canvas);\n}\n","/**\n * Pins on the live page: the person points at the spot a report is about\n * (`pickPin`), and numbered pins show their open reports on the page they\n * were sent from (`createPinOverlay`). A pin travels in the report's\n * context as `pin`, so it needs no column of its own.\n *\n * Plain DOM on the host document (no iframe, no framework), colored from the\n * Genesis theme variables.\n */\n\nexport interface FeedbackPin {\n /** A CSS selector for the element under the point, when one is stable (an id or a data-testid). */\n locator?: string | null;\n /** Where in that element, in percent. */\n xPct?: number | null;\n yPct?: number | null;\n /** The point in the viewport, as a fallback. */\n viewportX: number;\n viewportY: number;\n scrollX: number;\n scrollY: number;\n}\n\nexport interface PinnedReport {\n id: string;\n title: string;\n /** The route (path) it was sent from. */\n route: string | null;\n pin: FeedbackPin;\n}\n\nconst cssEscape = (value: string) => (typeof CSS !== \"undefined\" && CSS.escape ? CSS.escape(value) : value.replace(/[^A-Za-z0-9_-]/g, \"\\\\$&\"));\n\n/** A selector for an element that is likely to survive a re-render: its id, else a data-testid. */\nexport function stableLocator(el: Element | null): string | null {\n for (let node: Element | null = el; node && node !== node.ownerDocument.documentElement; node = node.parentElement) {\n if (node.id) return `#${cssEscape(node.id)}`;\n const testId = node.getAttribute(\"data-testid\");\n if (testId) return `[data-testid=\"${testId.replace(/\"/g, '\\\\\"')}\"]`;\n }\n return null;\n}\n\n/**\n * Waits for one click anywhere on the page and returns the pin, or `null`\n * on Escape. The click doesn't reach the page.\n */\nexport function pickPin(doc: Document = document): Promise<FeedbackPin | null> {\n return new Promise((resolve) => {\n const veil = doc.createElement(\"div\");\n veil.setAttribute(\"data-genesis-support-pin-picker\", \"\");\n veil.setAttribute(\"role\", \"presentation\");\n Object.assign(veil.style, { position: \"fixed\", inset: \"0\", zIndex: \"2147483000\", cursor: \"crosshair\", background: \"hsl(var(--foreground) / 0.06)\" });\n const done = (pin: FeedbackPin | null) => {\n veil.remove();\n doc.removeEventListener(\"keydown\", onKey, true);\n resolve(pin);\n };\n const onKey = (event: KeyboardEvent) => {\n if (event.key === \"Escape\") done(null);\n };\n veil.addEventListener(\"click\", (event) => {\n event.preventDefault();\n event.stopPropagation();\n veil.style.pointerEvents = \"none\";\n const target = doc.elementFromPoint?.(event.clientX, event.clientY) ?? null;\n const locator = stableLocator(target);\n const anchor = locator ? doc.querySelector(locator) : null;\n const rect = anchor?.getBoundingClientRect();\n const view = doc.defaultView;\n done({\n locator,\n xPct: rect && rect.width ? Math.round(((event.clientX - rect.left) / rect.width) * 100) : null,\n yPct: rect && rect.height ? Math.round(((event.clientY - rect.top) / rect.height) * 100) : null,\n viewportX: event.clientX,\n viewportY: event.clientY,\n scrollX: view?.scrollX ?? 0,\n scrollY: view?.scrollY ?? 0,\n });\n });\n doc.addEventListener(\"keydown\", onKey, true);\n doc.body.appendChild(veil);\n });\n}\n\n/** Where a pin sits now: on its element if it is still there, else where it was clicked. */\nexport function resolvePin(doc: Document, pin: FeedbackPin): { left: number; top: number } {\n if (pin.locator) {\n try {\n const node = doc.querySelector(pin.locator);\n if (node) {\n const r = node.getBoundingClientRect();\n return { left: r.left + (r.width * (pin.xPct ?? 50)) / 100, top: r.top + (r.height * (pin.yPct ?? 50)) / 100 };\n }\n } catch {\n // an invalid selector: fall back to the point\n }\n }\n return { left: pin.viewportX, top: pin.viewportY };\n}\n\nexport interface PinOverlay {\n setReports(reports: PinnedReport[]): void;\n destroy(): void;\n}\n\n/** Numbered pins for reports sent from the current path. Re-drawn on navigation, scroll and resize. */\nexport function createPinOverlay(options: { reports: PinnedReport[]; onPinClick?: (report: PinnedReport) => void; document?: Document }): PinOverlay {\n const doc = options.document ?? document;\n const view = doc.defaultView;\n const host = doc.createElement(\"div\");\n host.setAttribute(\"data-genesis-support-pins\", \"\");\n host.setAttribute(\"role\", \"group\");\n host.setAttribute(\"aria-label\", \"Feedback pins\");\n Object.assign(host.style, { position: \"fixed\", inset: \"0\", zIndex: \"2147482999\", pointerEvents: \"none\" });\n doc.body.appendChild(host);\n let reports = options.reports.slice();\n\n const render = () => {\n host.replaceChildren();\n const path = view?.location.pathname ?? \"\";\n reports\n .filter((r) => !r.route || r.route === path)\n .forEach((report, i) => {\n const { left, top } = resolvePin(doc, report.pin);\n const pin = doc.createElement(\"button\");\n pin.type = \"button\";\n pin.textContent = String(i + 1);\n pin.setAttribute(\"aria-label\", `Feedback ${i + 1}: ${report.title}`);\n pin.title = report.title;\n Object.assign(pin.style, {\n position: \"fixed\",\n left: `${Math.max(12, left)}px`,\n top: `${Math.max(12, top)}px`,\n transform: \"translate(-50%, -50%)\",\n width: \"28px\",\n height: \"28px\",\n borderRadius: \"999px\",\n border: \"2px solid hsl(var(--background))\",\n background: \"hsl(var(--destructive))\",\n color: \"hsl(var(--destructive-foreground))\",\n font: \"600 12px system-ui, sans-serif\",\n pointerEvents: \"auto\",\n cursor: \"pointer\",\n });\n pin.addEventListener(\"click\", (event) => {\n event.stopPropagation();\n options.onPinClick?.(report);\n });\n host.appendChild(pin);\n });\n };\n\n view?.addEventListener(\"popstate\", render);\n view?.addEventListener(\"resize\", render);\n view?.addEventListener(\"scroll\", render, { passive: true });\n render();\n return {\n setReports(next) {\n reports = next.slice();\n render();\n },\n destroy() {\n view?.removeEventListener(\"popstate\", render);\n view?.removeEventListener(\"resize\", render);\n view?.removeEventListener(\"scroll\", render);\n host.remove();\n },\n };\n}\n","/**\n * The web feedback panel, built from Genesis UI: a \"New\" tab (type, message,\n * an optional screenshot of the tab with pen marks and hidden areas, an\n * optional pin on the page) and a \"My reports\" tab (the person's reports and\n * their status). Loading, empty and failed reads are told apart.\n *\n * Put it anywhere (a page, a Sheet); `FeedbackLauncher` puts it in a Sheet\n * behind a floating button.\n */\nimport { useEffect, useMemo, useState, type PointerEvent } from \"react\";\nimport {\n Alert,\n AlertDescription,\n Badge,\n Button,\n Label,\n Tabs,\n TabsContent,\n TabsList,\n TabsTrigger,\n Textarea,\n ToggleGroup,\n ToggleGroupItem,\n} from \"@marktiderman/genesis-ui\";\nimport type { SupportClient, SupportReport } from \"../client\";\nimport { resolveSupportCopy, type SupportCopyOverrides } from \"../copy\";\nimport { cleanRoute } from \"../contract\";\nimport { createContextCollector, FEEDBACK_TYPES, type ContextCollector, type FeedbackDelivery, type FeedbackSink, type FeedbackType } from \"../record\";\nimport { annotateScreenshot, canCaptureScreenshot, captureScreenshot, type Redaction, type Stroke, type WebCapture } from \"./capture\";\nimport { pickPin, type FeedbackPin } from \"./pin\";\n\n/** The default web collector: the path (never the query string), `web`, and the viewport and language. */\nexport function webContextCollector(options: { appVersion?: string } = {}): ContextCollector {\n return createContextCollector({\n appVersion: options.appVersion,\n platform: \"web\",\n route: () => (typeof location === \"undefined\" ? undefined : cleanRoute(location.pathname)),\n device: () =>\n typeof window === \"undefined\"\n ? undefined\n : { viewport: { width: window.innerWidth, height: window.innerHeight }, pixelRatio: window.devicePixelRatio, language: navigator.language },\n });\n}\n\nexport interface FeedbackPanelProps {\n /** Where feedback goes. A support client also fills \"My reports\". */\n client: FeedbackSink & Partial<Pick<SupportClient, \"myReports\">>;\n collector?: ContextCollector;\n copy?: SupportCopyOverrides;\n /** Offer a screenshot of the tab. Default: when the browser can capture. */\n screenshots?: boolean;\n /** Offer a pin on the page. Default on. */\n pins?: boolean;\n defaultType?: FeedbackType;\n onSent?: (delivery: FeedbackDelivery) => void;\n /** Hidden while the person picks a pin or the browser asks to capture, so the page shows. */\n onHide?: (hidden: boolean) => void;\n}\n\ntype Status = { kind: \"idle\" } | { kind: \"sending\" } | { kind: \"sent\"; dropped: number } | { kind: \"error\"; message: string };\n\nexport function FeedbackPanel({ client, collector, copy: overrides, screenshots, pins = true, defaultType = \"bug\", onSent, onHide }: FeedbackPanelProps) {\n const copy = useMemo(() => resolveSupportCopy(overrides), [overrides]);\n const collect = useMemo(() => collector ?? webContextCollector(), [collector]);\n const [type, setType] = useState<FeedbackType>(defaultType);\n const [message, setMessage] = useState(\"\");\n const [shot, setShot] = useState<WebCapture | null>(null);\n // Marks stay a list until Send, then are drawn onto the image once: a quick second mark can't\n // drop the first, and nothing is sent half-marked.\n const [marks, setMarks] = useState<Marks>({ strokes: [], redactions: [] });\n const [pin, setPin] = useState<FeedbackPin | null>(null);\n const [status, setStatus] = useState<Status>({ kind: \"idle\" });\n const canShoot = screenshots ?? canCaptureScreenshot();\n\n const takeScreenshot = async () => {\n onHide?.(true);\n try {\n setShot(await captureScreenshot());\n setMarks({ strokes: [], redactions: [] });\n } finally {\n onHide?.(false);\n }\n };\n\n const placePin = async () => {\n onHide?.(true);\n try {\n setPin(await pickPin());\n } finally {\n onHide?.(false);\n }\n };\n\n const send = async () => {\n if (!message.trim()) {\n setStatus({ kind: \"error\", message: copy.feedback.messageRequired });\n return;\n }\n setStatus({ kind: \"sending\" });\n try {\n const context = await collect.collect();\n if (pin) context.extra = { ...context.extra, pin };\n let image = shot;\n if (shot && (marks.strokes.length || marks.redactions.length)) {\n try {\n image = await annotateScreenshot(shot, marks);\n } catch {\n // Never send the screenshot without the parts the person hid.\n setStatus({ kind: \"error\", message: copy.annotate.failed });\n return;\n }\n }\n const delivery = await client.submit({\n type,\n message: message.trim(),\n context,\n attachments: image ? [{ kind: \"screenshot\", contentType: image.contentType, base64: image.dataUrl, width: image.width, height: image.height }] : [],\n });\n setStatus({ kind: \"sent\", dropped: delivery.attachmentsDropped });\n setMessage(\"\");\n setShot(null);\n setMarks({ strokes: [], redactions: [] });\n setPin(null);\n onSent?.(delivery);\n } catch (error) {\n const limited = (error as { code?: string }).code === \"GS429\";\n setStatus({ kind: \"error\", message: limited ? copy.feedback.rateLimited : copy.feedback.failedBody });\n }\n };\n\n return (\n <Tabs defaultValue=\"new\" className=\"flex flex-col gap-4\" data-testid=\"genesis-support-panel\">\n <TabsList>\n <TabsTrigger value=\"new\">{copy.feedback.title}</TabsTrigger>\n {client.myReports ? <TabsTrigger value=\"mine\">{copy.inbox.sectionTitle}</TabsTrigger> : null}\n </TabsList>\n <TabsContent value=\"new\" className=\"flex flex-col gap-4\">\n <div className=\"flex flex-col gap-2\">\n <Label>{copy.feedback.typeLabel}</Label>\n <ToggleGroup type=\"single\" value={type} onValueChange={(v: string) => v && setType(v as FeedbackType)} aria-label={copy.feedback.typeLabel}>\n {FEEDBACK_TYPES.map((t) => (\n <ToggleGroupItem key={t} value={t} data-testid={`genesis-support-type-${t}`}>\n {copy.feedback.types[t]}\n </ToggleGroupItem>\n ))}\n </ToggleGroup>\n </div>\n <div className=\"flex flex-col gap-2\">\n <Label htmlFor=\"genesis-support-message\">{copy.feedback.messageLabel}</Label>\n <Textarea\n id=\"genesis-support-message\"\n data-testid=\"genesis-support-message\"\n value={message}\n maxLength={20000}\n rows={5}\n placeholder={copy.feedback.messagePlaceholder}\n onChange={(e) => setMessage(e.target.value)}\n />\n </div>\n {canShoot || pins ? (\n <div className=\"flex flex-wrap gap-2\">\n {canShoot && !shot ? (\n <Button type=\"button\" variant=\"outline\" size=\"sm\" onClick={() => void takeScreenshot()} data-testid=\"genesis-support-capture\">\n {copy.feedback.screenshotLabel}\n </Button>\n ) : null}\n {pins ? (\n <Button type=\"button\" variant=\"outline\" size=\"sm\" onClick={() => void placePin()} data-testid=\"genesis-support-pin\">\n {pin ? copy.feedback.pinned : copy.feedback.pin}\n </Button>\n ) : null}\n </div>\n ) : null}\n {shot ? <ScreenshotEditor shot={shot} marks={marks} onMarks={setMarks} onRemove={() => setShot(null)} copy={copy} /> : null}\n {status.kind === \"error\" ? (\n <Alert variant=\"destructive\" data-testid=\"genesis-support-error\">\n <AlertDescription>{status.message}</AlertDescription>\n </Alert>\n ) : null}\n {status.kind === \"sent\" ? (\n <Alert data-testid=\"genesis-support-sent\">\n <AlertDescription>{status.dropped ? copy.feedback.sentWithoutScreenshot : copy.feedback.sentBody}</AlertDescription>\n </Alert>\n ) : null}\n <Button type=\"button\" onClick={() => void send()} disabled={status.kind === \"sending\"} data-testid=\"genesis-support-send\">\n {status.kind === \"sending\" ? copy.feedback.sending : copy.feedback.send}\n </Button>\n </TabsContent>\n {client.myReports ? (\n <TabsContent value=\"mine\">\n <MyReports load={client.myReports} copy={copy} refreshKey={status.kind === \"sent\" ? 1 : 0} />\n </TabsContent>\n ) : null}\n </Tabs>\n );\n}\n\nfunction MyReports({ load, copy, refreshKey }: { load: NonNullable<SupportClient[\"myReports\"]>; copy: ReturnType<typeof resolveSupportCopy>; refreshKey: number }) {\n const [state, setState] = useState<{ kind: \"loading\" } | { kind: \"error\" } | { kind: \"ok\"; reports: SupportReport[] }>({ kind: \"loading\" });\n useEffect(() => {\n let alive = true;\n setState({ kind: \"loading\" });\n load()\n .then((reports) => alive && setState({ kind: \"ok\", reports }))\n .catch(() => alive && setState({ kind: \"error\" }));\n return () => {\n alive = false;\n };\n }, [load, refreshKey]);\n if (state.kind === \"loading\") return <p className=\"text-sm text-muted-foreground\" data-testid=\"genesis-support-mine-loading\">…</p>;\n if (state.kind === \"error\")\n return (\n <Alert variant=\"destructive\" data-testid=\"genesis-support-mine-error\">\n <AlertDescription>{copy.feedback.failedBody}</AlertDescription>\n </Alert>\n );\n if (!state.reports.length)\n return (\n <div data-testid=\"genesis-support-mine-empty\" className=\"flex flex-col gap-1\">\n <p className=\"font-medium\">{copy.inbox.emptyTitle}</p>\n <p className=\"text-sm text-muted-foreground\">{copy.inbox.emptyBody}</p>\n </div>\n );\n return (\n <ul className=\"flex flex-col divide-y\" data-testid=\"genesis-support-mine\">\n {state.reports.map((r) => (\n <li key={r.id} className=\"flex items-center justify-between gap-3 py-2\">\n <span className=\"truncate\">{r.title || r.message}</span>\n <span className=\"flex shrink-0 items-center gap-2\">\n {r.unread ? <Badge>{copy.inbox.unread}</Badge> : null}\n <Badge variant=\"secondary\">{copy.status[r.status]}</Badge>\n </span>\n </li>\n ))}\n </ul>\n );\n}\n\n/** The box being dragged, while it is dragged. */\nfunction DraftBox({ drag }: { drag: { start: { x: number; y: number }; points: Stroke } }) {\n const end = drag.points[drag.points.length - 1] ?? drag.start;\n const x = Math.min(drag.start.x, end.x);\n const y = Math.min(drag.start.y, end.y);\n return (\n <div\n className=\"pointer-events-none absolute border-2 border-dashed border-foreground bg-foreground/60\"\n style={{ left: `${x * 100}%`, top: `${y * 100}%`, width: `${Math.abs(end.x - drag.start.x) * 100}%`, height: `${Math.abs(end.y - drag.start.y) * 100}%` }}\n />\n );\n}\n\n/** Pen strokes and hidden areas, in fractions of the image. */\nexport interface Marks {\n strokes: Stroke[];\n redactions: Redaction[];\n /** The kinds in the order they were drawn, for Undo. */\n order?: Array<\"stroke\" | \"redaction\">;\n}\n\n/** Marks without the newest one (by `order`; without it, the last redaction, then the last stroke). */\nexport function undoMark(marks: Marks): Marks {\n const order = marks.order ?? [];\n const last = order[order.length - 1] ?? (marks.redactions.length ? \"redaction\" : \"stroke\");\n const rest = order.slice(0, -1);\n return last === \"redaction\"\n ? { ...marks, redactions: marks.redactions.slice(0, -1), order: rest }\n : { ...marks, strokes: marks.strokes.slice(0, -1), order: rest };\n}\n\n/** The captured tab, with pen strokes and hidden (solid) areas shown over it; drawn into the image at Send. */\nfunction ScreenshotEditor({\n shot,\n marks,\n onMarks,\n onRemove,\n copy,\n}: {\n shot: WebCapture;\n marks: Marks;\n onMarks: (next: Marks) => void;\n onRemove: () => void;\n copy: ReturnType<typeof resolveSupportCopy>;\n}) {\n const [tool, setTool] = useState<\"pen\" | \"hide\">(\"pen\");\n const [drag, setDrag] = useState<{ start: { x: number; y: number }; points: Stroke } | null>(null);\n const point = (e: PointerEvent<HTMLDivElement>) => {\n const r = e.currentTarget.getBoundingClientRect();\n return { x: Math.min(1, Math.max(0, (e.clientX - r.left) / r.width)), y: Math.min(1, Math.max(0, (e.clientY - r.top) / r.height)) };\n };\n const finish = (end: { x: number; y: number }) => {\n if (!drag) return;\n setDrag(null);\n const order = marks.order ?? [];\n if (tool === \"pen\") onMarks({ ...marks, strokes: [...marks.strokes, [...drag.points, end]], order: [...order, \"stroke\"] });\n else\n onMarks({\n ...marks,\n order: [...order, \"redaction\"],\n redactions: [...marks.redactions, { x: Math.min(drag.start.x, end.x), y: Math.min(drag.start.y, end.y), width: Math.abs(end.x - drag.start.x), height: Math.abs(end.y - drag.start.y) }],\n });\n };\n const pct = (n: number) => `${n * 100}%`;\n const strokes = drag && tool === \"pen\" ? [...marks.strokes, drag.points] : marks.strokes;\n return (\n <div className=\"flex flex-col gap-2\" data-testid=\"genesis-support-screenshot\">\n <div className=\"flex items-center justify-between gap-2\">\n <Label>{copy.feedback.screenshotLabel}</Label>\n <div className=\"flex gap-2\">\n <ToggleGroup type=\"single\" size=\"sm\" value={tool} onValueChange={(v: string) => v && setTool(v as \"pen\" | \"hide\")}>\n <ToggleGroupItem value=\"pen\">{copy.annotate.pen}</ToggleGroupItem>\n <ToggleGroupItem value=\"hide\">{copy.annotate.hide}</ToggleGroupItem>\n </ToggleGroup>\n <Button\n type=\"button\"\n variant=\"ghost\"\n size=\"sm\"\n disabled={!marks.strokes.length && !marks.redactions.length}\n onClick={() => onMarks(undoMark(marks))}\n data-testid=\"genesis-support-undo\"\n >\n {copy.annotate.undo}\n </Button>\n <Button type=\"button\" variant=\"ghost\" size=\"sm\" onClick={onRemove} data-testid=\"genesis-support-remove-screenshot\">\n {copy.feedback.removeScreenshot}\n </Button>\n </div>\n </div>\n <div\n className=\"relative cursor-crosshair touch-none overflow-hidden rounded-md border\"\n data-testid=\"genesis-support-screenshot-surface\"\n onPointerDown={(e) => {\n // Keep the gesture when the pointer leaves the image, so a release outside still ends it.\n e.currentTarget.setPointerCapture?.(e.pointerId);\n const p = point(e);\n setDrag({ start: p, points: [p] });\n }}\n onPointerCancel={() => setDrag(null)}\n onPointerMove={(e) => drag && setDrag({ ...drag, points: tool === \"pen\" ? [...drag.points, point(e)] : [drag.start, point(e)] })}\n onPointerUp={(e) => finish(point(e))}\n >\n <img src={shot.dataUrl} alt={copy.feedback.screenshotLabel} className=\"block w-full select-none\" draggable={false} />\n <svg className=\"pointer-events-none absolute inset-0 h-full w-full\" viewBox=\"0 0 1 1\" preserveAspectRatio=\"none\" aria-hidden>\n {strokes.map((stroke, i) => (\n <polyline\n key={i}\n points={stroke.map((p) => `${p.x},${p.y}`).join(\" \")}\n fill=\"none\"\n stroke=\"hsl(var(--destructive))\"\n strokeWidth={0.006}\n strokeLinecap=\"round\"\n strokeLinejoin=\"round\"\n />\n ))}\n </svg>\n {drag && tool === \"hide\" ? <DraftBox drag={drag} /> : null}\n {marks.redactions.map((r, i) => (\n <div\n key={i}\n data-testid={`genesis-support-redaction-${i}`}\n className=\"pointer-events-none absolute bg-foreground\"\n style={{ left: pct(r.x), top: pct(r.y), width: pct(r.width), height: pct(r.height) }}\n />\n ))}\n </div>\n <p className=\"text-xs text-muted-foreground\">{copy.feedback.screenshotHint}</p>\n </div>\n );\n}\n","/**\n * The feedback launcher: a floating button that opens `FeedbackPanel` in a\n * Genesis UI Sheet, and `mountSupportWidget`, the loader that puts it on any\n * page with one call (for a page that isn't a React app of its own).\n */\nimport { useMemo, useState } from \"react\";\nimport { createRoot } from \"react-dom/client\";\nimport { Button, Sheet, SheetContent, SheetDescription, SheetHeader, SheetTitle } from \"@marktiderman/genesis-ui\";\nimport { resolveSupportCopy } from \"../copy\";\nimport { FeedbackPanel, type FeedbackPanelProps } from \"./feedback-panel\";\n\nexport type LauncherPosition = \"bottom-right\" | \"bottom-left\";\n\nexport interface FeedbackLauncherProps extends FeedbackPanelProps {\n position?: LauncherPosition;\n /** The button's text. Default the copy's \"Send feedback\". */\n label?: string;\n}\n\nconst POSITIONS: Record<LauncherPosition, string> = {\n \"bottom-right\": \"fixed bottom-4 right-4 z-50\",\n \"bottom-left\": \"fixed bottom-4 left-4 z-50\",\n};\n\nexport function FeedbackLauncher({ position = \"bottom-right\", label, ...panel }: FeedbackLauncherProps) {\n const copy = useMemo(() => resolveSupportCopy(panel.copy), [panel.copy]);\n const [open, setOpen] = useState(false);\n // While the person picks a pin or the browser asks to capture, the sheet steps aside.\n const [hidden, setHidden] = useState(false);\n return (\n <>\n <Button className={POSITIONS[position]} onClick={() => setOpen(true)} data-testid=\"genesis-support-launcher\" aria-haspopup=\"dialog\">\n {label ?? copy.settings.sendFeedback}\n </Button>\n <Sheet open={open && !hidden} onOpenChange={setOpen}>\n <SheetContent side=\"right\" className=\"flex w-full flex-col gap-4 overflow-y-auto sm:max-w-md\">\n <SheetHeader>\n <SheetTitle>{copy.feedback.title}</SheetTitle>\n <SheetDescription>{copy.feedback.messagePlaceholder}</SheetDescription>\n </SheetHeader>\n <FeedbackPanel {...panel} onHide={setHidden} />\n </SheetContent>\n </Sheet>\n </>\n );\n}\n\n/**\n * Mount the launcher into the page: into `container`, or a new element at the\n * end of `<body>`. Returns the unmount. The page needs Genesis UI's styles.\n */\nexport function mountSupportWidget(props: FeedbackLauncherProps & { container?: HTMLElement }): () => void {\n const { container, ...launcher } = props;\n const host = container ?? document.body.appendChild(document.createElement(\"div\"));\n host.setAttribute(\"data-genesis-support\", \"\");\n const root = createRoot(host);\n root.render(<FeedbackLauncher {...launcher} />);\n return () => {\n root.unmount();\n if (!container) host.remove();\n };\n}\n"]}