@david-xpn/llm-ui-feedback 0.1.2 → 0.1.4

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/index.d.mts CHANGED
@@ -59,8 +59,8 @@ interface CapturedContext {
59
59
  interface FeedbackWidgetProps {
60
60
  /** Tenant identifier — required. */
61
61
  clientId: string;
62
- /** Backend API URL. Defaults to the production Lambda Function URL. */
63
- apiUrl?: string;
62
+ /** Backend API URL required. */
63
+ apiUrl: string;
64
64
  /** Corner position for the floating button. Default: 'bottom-right' */
65
65
  position?: WidgetPosition;
66
66
  /** Hex color for the FAB accent. Default: '#3b82f6' */
package/dist/index.d.ts CHANGED
@@ -59,8 +59,8 @@ interface CapturedContext {
59
59
  interface FeedbackWidgetProps {
60
60
  /** Tenant identifier — required. */
61
61
  clientId: string;
62
- /** Backend API URL. Defaults to the production Lambda Function URL. */
63
- apiUrl?: string;
62
+ /** Backend API URL required. */
63
+ apiUrl: string;
64
64
  /** Corner position for the floating button. Default: 'bottom-right' */
65
65
  position?: WidgetPosition;
66
66
  /** Hex color for the FAB accent. Default: '#3b82f6' */
package/dist/index.js CHANGED
@@ -1037,10 +1037,9 @@ function dataUrlToBlob(dataUrl) {
1037
1037
 
1038
1038
  // src/hooks/useSession.ts
1039
1039
  var import_react6 = require("react");
1040
- var import_meta = {};
1041
1040
  var SESSION_TOKEN_KEY = "llm_feedback_session_token";
1042
1041
  var USER_KEY = "llm_feedback_user";
1043
- var AUTH_BYPASS = typeof globalThis !== "undefined" && globalThis.__FEEDBACK_AUTH_BYPASS__ || typeof import_meta !== "undefined" && import_meta.env?.VITE_AUTH_BYPASS === "true";
1042
+ var AUTH_BYPASS = !!(typeof globalThis !== "undefined" && globalThis.__FEEDBACK_AUTH_BYPASS__);
1044
1043
  function getSessionToken() {
1045
1044
  if (AUTH_BYPASS) return "bypass-token";
1046
1045
  return localStorage.getItem(SESSION_TOKEN_KEY);
@@ -1215,9 +1214,6 @@ function createApiClient(apiUrl, clientId) {
1215
1214
  };
1216
1215
  }
1217
1216
 
1218
- // src/config.ts
1219
- var DEFAULT_API_URL = "https://your-lambda-function-url.lambda-url.us-east-1.on.aws";
1220
-
1221
1217
  // src/components/FeedbackWidget.tsx
1222
1218
  var import_jsx_runtime7 = require("react/jsx-runtime");
1223
1219
  var CONTAINER_ID = "llm-ui-feedback-root";
@@ -1317,7 +1313,7 @@ function isEditableTarget(el) {
1317
1313
  }
1318
1314
  function FeedbackWidget({
1319
1315
  clientId,
1320
- apiUrl = DEFAULT_API_URL,
1316
+ apiUrl,
1321
1317
  position = "bottom-right",
1322
1318
  buttonColor = "#3b82f6",
1323
1319
  hotkey
package/dist/index.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"sources":["../src/index.ts","../src/components/FeedbackWidget.tsx","../src/utils/color.ts","../src/components/FloatingButton.tsx","../src/components/PickOverlay.tsx","../src/components/SidePanel.tsx","../src/components/DraftItem.tsx","../src/components/DraftModal.tsx","../src/components/SubmitModal.tsx","../src/utils/fiber.ts","../src/utils/screenshot.ts","../src/utils/prompt.ts","../src/utils/blob.ts","../src/hooks/useSession.ts","../src/api/client.ts","../src/config.ts"],"sourcesContent":["export { FeedbackWidget } from './components/FeedbackWidget';\nexport type { FeedbackWidgetProps } from './components/FeedbackWidget';\nexport type { FeedbackEntry, CapturedContext, ComponentInfo, WidgetPosition, Draft, FeedbackGroup } from './types';\n","import React, { useReducer, useCallback, useEffect, useMemo, useRef } from 'react';\nimport { createPortal } from 'react-dom';\nimport { FloatingButton } from './FloatingButton';\nimport { PickOverlay } from './PickOverlay';\nimport { SidePanel } from './SidePanel';\nimport { DraftModal } from './DraftModal';\nimport { SubmitModal } from './SubmitModal';\nimport { getComponentPath } from '../utils/fiber';\nimport { captureScreenshot } from '../utils/screenshot';\nimport { buildPrompt } from '../utils/prompt';\nimport { dataUrlToBlob } from '../utils/blob';\nimport { createApiClient } from '../api/client';\nimport { useSession } from '../hooks/useSession';\nimport { DEFAULT_API_URL } from '../config';\nimport { CapturedContext, Draft, WidgetPosition } from '../types';\n\nexport const CONTAINER_ID = 'llm-ui-feedback-root';\n\nfunction getOrCreateContainer(): HTMLElement {\n let el = document.getElementById(CONTAINER_ID);\n if (!el) {\n el = document.createElement('div');\n el.id = CONTAINER_ID;\n document.body.appendChild(el);\n }\n return el;\n}\n\nexport interface FeedbackWidgetProps {\n /** Tenant identifier — required. */\n clientId: string;\n /** Backend API URL. Defaults to the production Lambda Function URL. */\n apiUrl?: string;\n /** Corner position for the floating button. Default: 'bottom-right' */\n position?: WidgetPosition;\n /** Hex color for the FAB accent. Default: '#3b82f6' */\n buttonColor?: string;\n /** Keyboard shortcut to toggle the panel, e.g. 'Alt+F'. No default (opt-in only). */\n hotkey?: string;\n}\n\ninterface WidgetState {\n panelOpen: boolean;\n picking: boolean;\n pendingContext: { context: CapturedContext; screenshot: string | null } | null;\n drafts: Draft[];\n selectedDraftIds: Set<string>;\n submitModalOpen: boolean;\n addingDraft: boolean;\n submitting: boolean;\n}\n\ntype WidgetAction =\n | { type: 'TOGGLE_PANEL' }\n | { type: 'OPEN_PANEL' }\n | { type: 'CLOSE_PANEL' }\n | { type: 'START_PICKING' }\n | { type: 'CANCEL_PICKING' }\n | { type: 'CANCEL_DRAFT_MODAL' }\n | { type: 'ELEMENT_PICKED'; context: CapturedContext; screenshot: string | null }\n | { type: 'SET_ADDING_DRAFT'; adding: boolean }\n | { type: 'DRAFT_ADDED'; draft: Draft }\n | { type: 'SET_DRAFTS'; drafts: Draft[] }\n | { type: 'DRAFT_UPDATED'; id: string; comment: string }\n | { type: 'DRAFT_DELETED'; id: string }\n | { type: 'TOGGLE_SELECT'; id: string }\n | { type: 'SELECT_ALL'; selected: boolean }\n | { type: 'OPEN_SUBMIT_MODAL' }\n | { type: 'CLOSE_SUBMIT_MODAL' }\n | { type: 'SET_SUBMITTING'; submitting: boolean }\n | { type: 'SUBMIT_COMPLETE'; submittedIds: string[] };\n\nconst initialState: WidgetState = {\n panelOpen: false,\n picking: false,\n pendingContext: null,\n drafts: [],\n selectedDraftIds: new Set(),\n submitModalOpen: false,\n addingDraft: false,\n submitting: false,\n};\n\nfunction widgetReducer(state: WidgetState, action: WidgetAction): WidgetState {\n switch (action.type) {\n case 'TOGGLE_PANEL':\n return state.panelOpen\n ? { ...state, panelOpen: false, picking: false, pendingContext: null }\n : { ...state, panelOpen: true };\n case 'OPEN_PANEL':\n return { ...state, panelOpen: true };\n case 'CLOSE_PANEL':\n return { ...state, panelOpen: false, picking: false, pendingContext: null };\n case 'START_PICKING':\n return { ...state, picking: true };\n case 'CANCEL_PICKING':\n return { ...state, picking: false };\n case 'CANCEL_DRAFT_MODAL':\n return { ...state, pendingContext: null, addingDraft: false };\n case 'ELEMENT_PICKED':\n return { ...state, picking: false, pendingContext: { context: action.context, screenshot: action.screenshot } };\n case 'SET_ADDING_DRAFT':\n return { ...state, addingDraft: action.adding };\n case 'DRAFT_ADDED':\n return { ...state, pendingContext: null, addingDraft: false, drafts: [action.draft, ...state.drafts] };\n case 'SET_DRAFTS':\n return { ...state, drafts: action.drafts };\n case 'DRAFT_UPDATED':\n return { ...state, drafts: state.drafts.map((d) => d.id === action.id ? { ...d, comment: action.comment } : d) };\n case 'DRAFT_DELETED': {\n const next = new Set(state.selectedDraftIds);\n next.delete(action.id);\n return { ...state, drafts: state.drafts.filter((d) => d.id !== action.id), selectedDraftIds: next };\n }\n case 'TOGGLE_SELECT': {\n const next = new Set(state.selectedDraftIds);\n if (next.has(action.id)) next.delete(action.id);\n else next.add(action.id);\n return { ...state, selectedDraftIds: next };\n }\n case 'SELECT_ALL':\n return { ...state, selectedDraftIds: action.selected ? new Set(state.drafts.map((d) => d.id)) : new Set() };\n case 'OPEN_SUBMIT_MODAL':\n return { ...state, submitModalOpen: true };\n case 'CLOSE_SUBMIT_MODAL':\n return { ...state, submitModalOpen: false };\n case 'SET_SUBMITTING':\n return { ...state, submitting: action.submitting };\n case 'SUBMIT_COMPLETE': {\n const submitted = new Set(action.submittedIds);\n return {\n ...state,\n submitting: false,\n submitModalOpen: false,\n drafts: state.drafts.filter((d) => !submitted.has(d.id)),\n selectedDraftIds: new Set(),\n };\n }\n default:\n return state;\n }\n}\n\nfunction parseHotkey(hotkey: string) {\n const parts = hotkey.split('+').map((p) => p.trim().toLowerCase());\n const key = parts.pop()!;\n return {\n key,\n ctrl: parts.includes('ctrl'),\n alt: parts.includes('alt'),\n shift: parts.includes('shift'),\n meta: parts.includes('meta'),\n };\n}\n\nfunction isEditableTarget(el: Element | null): boolean {\n if (!el) return false;\n const tag = el.tagName;\n if (tag === 'INPUT' || tag === 'TEXTAREA' || tag === 'SELECT') return true;\n if ((el as HTMLElement).isContentEditable) return true;\n return false;\n}\n\nexport function FeedbackWidget({\n clientId,\n apiUrl = DEFAULT_API_URL,\n position = 'bottom-right',\n buttonColor = '#3b82f6',\n hotkey,\n}: FeedbackWidgetProps) {\n const session = useSession(apiUrl, clientId);\n const [state, dispatch] = useReducer(widgetReducer, initialState);\n const pendingOpenRef = useRef(false);\n\n const api = useMemo(\n () => createApiClient(apiUrl, clientId),\n [apiUrl, clientId],\n );\n\n // Auto-open panel after successful auth\n useEffect(() => {\n if (session.status === 'authenticated' && pendingOpenRef.current) {\n pendingOpenRef.current = false;\n dispatch({ type: 'OPEN_PANEL' });\n }\n }, [session.status]);\n\n // Fetch drafts on auth and when panel opens\n useEffect(() => {\n if (session.status === 'authenticated') {\n api.fetchDrafts().then((drafts) => {\n dispatch({ type: 'SET_DRAFTS', drafts });\n }).catch(() => {\n // silently fail\n });\n }\n }, [state.panelOpen, session.status, api]);\n\n // Hotkey listener\n useEffect(() => {\n if (!hotkey) return;\n const parsed = parseHotkey(hotkey);\n\n function handler(e: KeyboardEvent) {\n if (isEditableTarget(document.activeElement)) return;\n if (\n e.key.toLowerCase() === parsed.key &&\n e.ctrlKey === parsed.ctrl &&\n e.altKey === parsed.alt &&\n e.shiftKey === parsed.shift &&\n e.metaKey === parsed.meta\n ) {\n e.preventDefault();\n dispatch({ type: 'TOGGLE_PANEL' });\n }\n }\n\n window.addEventListener('keydown', handler);\n return () => window.removeEventListener('keydown', handler);\n }, [hotkey]);\n\n const handlePickClick = useCallback(() => {\n if (session.status === 'unauthenticated') {\n pendingOpenRef.current = true;\n session.signIn();\n return;\n }\n dispatch({ type: 'START_PICKING' });\n }, [session]);\n\n const handlePanelToggle = useCallback(() => {\n if (session.status === 'unauthenticated') {\n pendingOpenRef.current = true;\n session.signIn();\n return;\n }\n dispatch({ type: 'TOGGLE_PANEL' });\n }, [session]);\n\n const handlePick = useCallback(async (rect: { x: number; y: number; width: number; height: number }, elements: Element[]) => {\n // Collect unique components from all elements in the selection\n const seenNames = new Set<string>();\n const allComponents: { name: string; props: Record<string, unknown> }[] = [];\n for (const el of elements) {\n for (const comp of getComponentPath(el)) {\n if (!seenNames.has(comp.name)) {\n seenNames.add(comp.name);\n allComponents.push(comp);\n }\n }\n }\n\n const componentPath = allComponents.map((c) => c.name).join(', ') || '(no React component found)';\n\n // Gather text from selected elements\n const textParts = new Set<string>();\n for (const el of elements) {\n const raw = ((el as HTMLElement).innerText || el.textContent || '').trim();\n if (raw) textParts.add(raw);\n }\n const combined = Array.from(textParts).join(' ').trim();\n const elementText = combined.length > 200 ? combined.slice(0, 200) + '...' : combined;\n\n const centerX = rect.x + rect.width / 2;\n const centerY = rect.y + rect.height / 2;\n\n const context: CapturedContext = {\n url: window.location.href,\n urlPath: window.location.pathname,\n reportedAt: new Date().toISOString(),\n componentPath,\n components: allComponents,\n elementText,\n clickX: centerX,\n clickY: centerY,\n };\n\n // Only capture screenshot for drag selections, not single-element clicks\n const isDrag = rect.width > 20 && rect.height > 20;\n let screenshot: string | null = null;\n if (isDrag) {\n try {\n screenshot = await captureScreenshot(rect);\n } catch {\n // Screenshot failed — continue without it\n }\n }\n\n dispatch({ type: 'ELEMENT_PICKED', context, screenshot });\n }, []);\n\n const handleCancelPicking = useCallback(() => {\n dispatch({ type: 'CANCEL_PICKING' });\n }, []);\n\n const handleAddDraft = useCallback(async (comment: string) => {\n if (!state.pendingContext) return;\n dispatch({ type: 'SET_ADDING_DRAFT', adding: true });\n\n const { context, screenshot } = state.pendingContext;\n const entryId = `f_${Date.now()}`;\n const timestamp = new Date().toISOString();\n let screenshotKey: string | undefined;\n\n // Upload screenshot\n if (screenshot) {\n const blob = dataUrlToBlob(screenshot);\n try {\n const { uploadUrl, key } = await api.getUploadUrl(entryId, timestamp);\n await api.uploadScreenshot(uploadUrl, blob);\n screenshotKey = key;\n } catch {\n // continue without screenshot\n }\n }\n\n try {\n const draft = await api.createDraft({\n id: entryId,\n url: context.url,\n componentPath: context.componentPath,\n components: context.components,\n elementText: context.elementText,\n comment,\n prompt: buildPrompt(context, comment),\n ...(screenshotKey ? { screenshotKey } : {}),\n });\n dispatch({ type: 'DRAFT_ADDED', draft });\n } catch {\n dispatch({ type: 'SET_ADDING_DRAFT', adding: false });\n }\n }, [state.pendingContext, api]);\n\n const handleUpdateDraft = useCallback(async (id: string, comment: string) => {\n dispatch({ type: 'DRAFT_UPDATED', id, comment });\n try {\n await api.updateDraft(id, { comment });\n } catch {\n // revert on error — refetch\n api.fetchDrafts().then((drafts) => dispatch({ type: 'SET_DRAFTS', drafts })).catch(() => {});\n }\n }, [api]);\n\n const handleDeleteDraft = useCallback(async (id: string) => {\n dispatch({ type: 'DRAFT_DELETED', id });\n try {\n await api.deleteDraft(id);\n } catch {\n // refetch on error\n api.fetchDrafts().then((drafts) => dispatch({ type: 'SET_DRAFTS', drafts })).catch(() => {});\n }\n }, [api]);\n\n const handleSubmit = useCallback(async (title: string) => {\n dispatch({ type: 'SET_SUBMITTING', submitting: true });\n const draftIds = Array.from(state.selectedDraftIds);\n try {\n await api.submitSession({ title, draftIds });\n dispatch({ type: 'SUBMIT_COMPLETE', submittedIds: draftIds });\n } catch {\n dispatch({ type: 'SET_SUBMITTING', submitting: false });\n }\n }, [state.selectedDraftIds, api]);\n\n // Don't render while checking auth status\n if (session.status === 'loading') return null;\n\n return createPortal(\n <>\n <FloatingButton\n onPickClick={handlePickClick}\n onPanelToggle={handlePanelToggle}\n draftCount={state.drafts.length}\n panelOpen={state.panelOpen}\n position={position}\n buttonColor={buttonColor}\n />\n {state.picking && <PickOverlay onPick={handlePick} onCancel={handleCancelPicking} />}\n {state.panelOpen && (\n <SidePanel\n position={position}\n drafts={state.drafts}\n selectedDraftIds={state.selectedDraftIds}\n onToggleSelect={(id) => dispatch({ type: 'TOGGLE_SELECT', id })}\n onSelectAll={(selected) => dispatch({ type: 'SELECT_ALL', selected })}\n onUpdateDraft={handleUpdateDraft}\n onDeleteDraft={handleDeleteDraft}\n onSubmit={() => dispatch({ type: 'OPEN_SUBMIT_MODAL' })}\n onClose={() => dispatch({ type: 'CLOSE_PANEL' })}\n api={api}\n user={session.user}\n />\n )}\n {state.pendingContext && !state.picking && (\n <DraftModal\n pendingContext={state.pendingContext}\n addingDraft={state.addingDraft}\n onAdd={handleAddDraft}\n onCancel={() => dispatch({ type: 'CANCEL_DRAFT_MODAL' })}\n />\n )}\n {state.submitModalOpen && (\n <SubmitModal\n count={state.selectedDraftIds.size}\n onSubmit={handleSubmit}\n onCancel={() => dispatch({ type: 'CLOSE_SUBMIT_MODAL' })}\n submitting={state.submitting}\n />\n )}\n </>,\n getOrCreateContainer()\n );\n}\n","/**\n * Compute whether to use light or dark text on a given background color.\n * Uses the WCAG relative luminance formula.\n * @param hexColor - Hex color string (e.g., '#3b82f6' or '#fff')\n * @returns '#000000' for light backgrounds, '#ffffff' for dark backgrounds\n */\nexport function getContrastColor(hexColor: string): string {\n const hex = hexColor.replace('#', '');\n // Expand 3-char hex to 6-char (e.g., #fff -> #ffffff)\n const fullHex =\n hex.length === 3\n ? hex[0] + hex[0] + hex[1] + hex[1] + hex[2] + hex[2]\n : hex;\n\n const r = parseInt(fullHex.substring(0, 2), 16) / 255;\n const g = parseInt(fullHex.substring(2, 4), 16) / 255;\n const b = parseInt(fullHex.substring(4, 6), 16) / 255;\n\n const toLinear = (c: number) =>\n c <= 0.03928 ? c / 12.92 : Math.pow((c + 0.055) / 1.055, 2.4);\n\n // Relative luminance (WCAG 2.0)\n const luminance =\n 0.2126 * toLinear(r) + 0.7152 * toLinear(g) + 0.0722 * toLinear(b);\n\n return luminance > 0.179 ? '#000000' : '#ffffff';\n}\n","import React from 'react';\nimport { WidgetPosition } from '../types';\nimport { getContrastColor } from '../utils/color';\n\ninterface FloatingButtonProps {\n onPickClick: () => void;\n onPanelToggle: () => void;\n draftCount: number;\n panelOpen: boolean;\n position: WidgetPosition;\n buttonColor: string;\n}\n\nexport function FloatingButton({ onPickClick, onPanelToggle, draftCount, panelOpen, position, buttonColor }: FloatingButtonProps) {\n const isBottom = position.includes('bottom');\n const isRight = position.includes('right');\n\n const anchor: React.CSSProperties = {\n position: 'fixed',\n [isBottom ? 'bottom' : 'top']: 24,\n [isRight ? 'right' : 'left']: 24,\n zIndex: 99999,\n display: 'flex',\n flexDirection: 'column',\n alignItems: 'center',\n gap: 8,\n };\n\n return (\n <div style={anchor}>\n {/* Badge button — draft count, only visible when drafts exist */}\n {draftCount > 0 && (\n <button\n onClick={onPanelToggle}\n aria-label={panelOpen ? 'Close drafts panel' : `Open drafts panel (${draftCount})`}\n style={{\n width: 32,\n height: 32,\n borderRadius: '50%',\n border: 'none',\n background: panelOpen ? '#ef4444' : buttonColor,\n color: panelOpen ? '#fff' : getContrastColor(buttonColor),\n fontFamily: 'system-ui, -apple-system, sans-serif',\n fontSize: 13,\n fontWeight: 700,\n lineHeight: 1,\n cursor: 'pointer',\n display: 'flex',\n alignItems: 'center',\n justifyContent: 'center',\n boxShadow: '0 2px 8px rgba(0,0,0,0.25)',\n transition: 'background 0.15s',\n padding: 0,\n }}\n >\n {draftCount}\n </button>\n )}\n\n {/* FAB — starts picking, or closes panel when open */}\n <button\n onClick={panelOpen ? onPanelToggle : onPickClick}\n aria-label={panelOpen ? 'Close panel' : 'Pick element for feedback'}\n style={{\n width: 48,\n height: 48,\n borderRadius: '50%',\n border: 'none',\n background: panelOpen ? '#ef4444' : buttonColor,\n color: panelOpen ? '#fff' : getContrastColor(buttonColor),\n fontFamily: 'system-ui, -apple-system, sans-serif',\n fontSize: 28,\n fontWeight: 300,\n lineHeight: 1,\n cursor: 'pointer',\n display: 'flex',\n alignItems: 'center',\n justifyContent: 'center',\n boxShadow: '0 2px 8px rgba(0,0,0,0.25)',\n transition: 'background 0.15s, transform 0.15s',\n transform: panelOpen ? 'rotate(45deg)' : 'none',\n padding: 0,\n }}\n >\n +\n </button>\n </div>\n );\n}\n","import React, { useCallback, useEffect, useRef, useState } from 'react';\n\nconst WIDGET_CONTAINER_ID = 'llm-ui-feedback-root';\n\ninterface Rect {\n x: number;\n y: number;\n width: number;\n height: number;\n}\n\ninterface PickOverlayProps {\n onPick: (rect: Rect, elements: Element[]) => void;\n onCancel: () => void;\n}\n\nfunction getElementsBeneathRect(rect: Rect): Element[] {\n const container = document.getElementById(WIDGET_CONTAINER_ID);\n if (container) container.style.display = 'none';\n\n const seen = new Set<Element>();\n const step = 8;\n\n for (let x = rect.x; x <= rect.x + rect.width; x += step) {\n for (let y = rect.y; y <= rect.y + rect.height; y += step) {\n const el = document.elementFromPoint(x, y);\n if (el && !seen.has(el)) seen.add(el);\n }\n }\n\n for (const [x, y] of [\n [rect.x, rect.y],\n [rect.x + rect.width, rect.y],\n [rect.x, rect.y + rect.height],\n [rect.x + rect.width, rect.y + rect.height],\n [rect.x + rect.width / 2, rect.y + rect.height / 2],\n ]) {\n const el = document.elementFromPoint(x, y);\n if (el && !seen.has(el)) seen.add(el);\n }\n\n if (container) container.style.display = '';\n return Array.from(seen).filter((el) => !container?.contains(el));\n}\n\nfunction getElementAtPoint(x: number, y: number): Element | null {\n const container = document.getElementById(WIDGET_CONTAINER_ID);\n if (container) container.style.display = 'none';\n const el = document.elementFromPoint(x, y);\n if (container) container.style.display = '';\n if (el && container?.contains(el)) return null;\n return el;\n}\n\nconst DRAG_THRESHOLD = 10;\n\nexport function PickOverlay({ onPick, onCancel }: PickOverlayProps) {\n // Use refs for drag state so event handlers always see current values\n const activeRef = useRef(false);\n const startRef = useRef<{ x: number; y: number } | null>(null);\n const isDragRef = useRef(false);\n\n // State only for rendering (hover highlight and drag rectangle)\n const [hoverRect, setHoverRect] = useState<Rect | null>(null);\n const [selRect, setSelRect] = useState<{ left: number; top: number; width: number; height: number } | null>(null);\n\n const onPickRef = useRef(onPick);\n onPickRef.current = onPick;\n const onCancelRef = useRef(onCancel);\n onCancelRef.current = onCancel;\n\n useEffect(() => {\n function handleMouseMove(e: MouseEvent) {\n if (activeRef.current && startRef.current) {\n // Dragging\n const dx = Math.abs(e.clientX - startRef.current.x);\n const dy = Math.abs(e.clientY - startRef.current.y);\n if (dx >= DRAG_THRESHOLD || dy >= DRAG_THRESHOLD) {\n isDragRef.current = true;\n }\n\n if (isDragRef.current) {\n setHoverRect(null);\n setSelRect({\n left: Math.min(startRef.current.x, e.clientX),\n top: Math.min(startRef.current.y, e.clientY),\n width: Math.abs(e.clientX - startRef.current.x),\n height: Math.abs(e.clientY - startRef.current.y),\n });\n }\n e.preventDefault();\n } else {\n // Hover — highlight element under cursor\n const el = getElementAtPoint(e.clientX, e.clientY);\n if (el) {\n const r = el.getBoundingClientRect();\n setHoverRect({ x: r.left, y: r.top, width: r.width, height: r.height });\n } else {\n setHoverRect(null);\n }\n }\n }\n\n function handleMouseDown(e: MouseEvent) {\n if (e.button !== 0) return;\n e.preventDefault();\n e.stopPropagation();\n startRef.current = { x: e.clientX, y: e.clientY };\n isDragRef.current = false;\n activeRef.current = true;\n }\n\n function handleMouseUp(e: MouseEvent) {\n if (!activeRef.current || !startRef.current) return;\n e.preventDefault();\n e.stopPropagation();\n\n const start = startRef.current;\n activeRef.current = false;\n startRef.current = null;\n setSelRect(null);\n setHoverRect(null);\n\n if (!isDragRef.current) {\n // Click — select single element\n const el = getElementAtPoint(e.clientX, e.clientY);\n if (el) {\n const r = el.getBoundingClientRect();\n onPickRef.current({ x: r.left, y: r.top, width: r.width, height: r.height }, [el]);\n }\n return;\n }\n\n // Drag — select area\n const x = Math.min(start.x, e.clientX);\n const y = Math.min(start.y, e.clientY);\n const width = Math.abs(e.clientX - start.x);\n const height = Math.abs(e.clientY - start.y);\n\n const rect = { x, y, width, height };\n const elements = getElementsBeneathRect(rect);\n onPickRef.current(rect, elements);\n }\n\n function handleKeyDown(e: KeyboardEvent) {\n if (e.key === 'Escape') {\n activeRef.current = false;\n startRef.current = null;\n setSelRect(null);\n setHoverRect(null);\n onCancelRef.current();\n }\n }\n\n document.addEventListener('mousedown', handleMouseDown, true);\n document.addEventListener('mousemove', handleMouseMove, true);\n document.addEventListener('mouseup', handleMouseUp, true);\n document.addEventListener('keydown', handleKeyDown, true);\n\n return () => {\n document.removeEventListener('mousedown', handleMouseDown, true);\n document.removeEventListener('mousemove', handleMouseMove, true);\n document.removeEventListener('mouseup', handleMouseUp, true);\n document.removeEventListener('keydown', handleKeyDown, true);\n };\n }, []);\n\n return (\n <>\n <div\n style={{\n position: 'fixed',\n top: 0,\n left: 0,\n right: 0,\n bottom: 0,\n zIndex: 99997,\n cursor: 'crosshair',\n }}\n />\n\n <div\n style={{\n position: 'fixed',\n top: 0,\n left: 0,\n right: 0,\n zIndex: 99998,\n background: 'rgba(59, 130, 246, 0.08)',\n padding: '8px 16px',\n textAlign: 'center',\n fontSize: 14,\n color: '#1e40af',\n fontFamily: 'system-ui, sans-serif',\n pointerEvents: 'none',\n }}\n >\n Click an element or drag to select an area. Press <strong>Esc</strong> to cancel.\n </div>\n\n {/* Hover highlight */}\n {hoverRect && (\n <div\n style={{\n position: 'fixed',\n left: hoverRect.x,\n top: hoverRect.y,\n width: hoverRect.width,\n height: hoverRect.height,\n border: '2px solid #3b82f6',\n background: 'rgba(59, 130, 246, 0.08)',\n zIndex: 99998,\n pointerEvents: 'none',\n borderRadius: 2,\n transition: 'all 0.1s ease-out',\n }}\n />\n )}\n\n {/* Drag selection rectangle */}\n {selRect && (\n <div\n style={{\n position: 'fixed',\n left: selRect.left,\n top: selRect.top,\n width: selRect.width,\n height: selRect.height,\n border: '2px dashed #3b82f6',\n background: 'rgba(59, 130, 246, 0.1)',\n zIndex: 99998,\n pointerEvents: 'none',\n borderRadius: 2,\n }}\n />\n )}\n </>\n );\n}\n","import React, { useState } from 'react';\nimport type { Draft, WidgetPosition } from '../types';\nimport type { ApiClient } from '../api/client';\nimport type { UserInfo } from '../hooks/useSession';\nimport { DraftItem } from './DraftItem';\n\ninterface SidePanelProps {\n position: WidgetPosition;\n drafts: Draft[];\n selectedDraftIds: Set<string>;\n onToggleSelect: (id: string) => void;\n onSelectAll: (selected: boolean) => void;\n onUpdateDraft: (id: string, comment: string) => void;\n onDeleteDraft: (id: string) => void;\n onSubmit: () => void;\n onClose: () => void;\n api: ApiClient;\n user: UserInfo | null;\n}\n\nexport function SidePanel({\n position,\n drafts,\n selectedDraftIds,\n onToggleSelect,\n onSelectAll,\n onUpdateDraft,\n onDeleteDraft,\n onSubmit,\n onClose,\n api,\n user,\n}: SidePanelProps) {\n const isRight = position.includes('right');\n const allSelected = drafts.length > 0 && selectedDraftIds.size === drafts.length;\n const [screenshotUrls, setScreenshotUrls] = useState<Record<string, string>>({});\n const [previewUrl, setPreviewUrl] = useState<string | null>(null);\n\n // Fetch screenshot URLs for drafts that have them\n React.useEffect(() => {\n const draftsWithScreenshots = drafts.filter((d) => d.screenshotKey && !screenshotUrls[d.id]);\n draftsWithScreenshots.forEach((draft) => {\n api.getScreenshotUrl(draft.id).then((url) => {\n setScreenshotUrls((prev) => ({ ...prev, [draft.id]: url }));\n }).catch(() => {});\n });\n }, [drafts, api]);\n\n const handlePreviewScreenshot = (draftId: string) => {\n const url = screenshotUrls[draftId];\n if (url) setPreviewUrl(url);\n };\n\n return (\n <div\n style={{\n position: 'fixed',\n top: 0,\n [isRight ? 'right' : 'left']: 0,\n width: 360,\n maxWidth: '100vw',\n height: '100vh',\n background: '#fff',\n boxShadow: isRight ? '-4px 0 16px rgba(0,0,0,0.1)' : '4px 0 16px rgba(0,0,0,0.1)',\n zIndex: 99998,\n display: 'flex',\n flexDirection: 'column',\n fontFamily: 'system-ui, sans-serif',\n }}\n >\n {/* Header */}\n <div\n style={{\n padding: '16px 16px 12px',\n borderBottom: '1px solid #e5e7eb',\n }}\n >\n <div style={{ display: 'flex', justifyContent: 'space-between', alignItems: 'center' }}>\n <h3 style={{ margin: 0, fontSize: 15, fontWeight: 600 }}>Feedback Session</h3>\n <button\n onClick={onClose}\n style={{\n background: 'none',\n border: 'none',\n fontSize: 18,\n cursor: 'pointer',\n color: '#6b7280',\n padding: '0 4px',\n }}\n >\n x\n </button>\n </div>\n {user && (\n <div style={{ marginTop: 6, fontSize: 12, color: '#6b7280', lineHeight: 1.4 }}>\n <div style={{ fontWeight: 500, color: '#374151' }}>{user.name}</div>\n <div>{user.email}</div>\n </div>\n )}\n </div>\n\n {/* Draft List */}\n <div style={{ flex: 1, overflow: 'auto' }}>\n {drafts.length === 0 ? (\n <div style={{ padding: 24, textAlign: 'center', color: '#9ca3af', fontSize: 13 }}>\n No drafts yet. Pick an element to start.\n </div>\n ) : (\n drafts.map((draft) => (\n <DraftItem\n key={draft.id}\n draft={draft}\n selected={selectedDraftIds.has(draft.id)}\n screenshotUrl={screenshotUrls[draft.id] || null}\n onToggleSelect={onToggleSelect}\n onUpdate={onUpdateDraft}\n onDelete={onDeleteDraft}\n onPreviewScreenshot={handlePreviewScreenshot}\n />\n ))\n )}\n </div>\n\n {/* Footer */}\n {drafts.length > 0 && (\n <div\n style={{\n padding: '12px 16px',\n borderTop: '1px solid #e5e7eb',\n display: 'flex',\n alignItems: 'center',\n gap: 12,\n }}\n >\n <label style={{ display: 'flex', alignItems: 'center', gap: 6, fontSize: 13, cursor: 'pointer', whiteSpace: 'nowrap' }}>\n <input\n type=\"checkbox\"\n checked={allSelected}\n onChange={(e) => onSelectAll(e.target.checked)}\n />\n Select All\n </label>\n <button\n onClick={onSubmit}\n disabled={selectedDraftIds.size === 0}\n style={{\n flex: 1,\n padding: '8px 12px',\n borderRadius: 6,\n border: 'none',\n background: selectedDraftIds.size === 0 ? '#93c5fd' : '#3b82f6',\n color: '#fff',\n fontSize: 13,\n fontWeight: 500,\n cursor: selectedDraftIds.size === 0 ? 'default' : 'pointer',\n }}\n >\n Submit Feedback ({selectedDraftIds.size})\n </button>\n </div>\n )}\n\n {/* Screenshot Preview Modal */}\n {previewUrl && (\n <div\n onClick={() => setPreviewUrl(null)}\n style={{\n position: 'fixed',\n top: 0,\n left: 0,\n right: 0,\n bottom: 0,\n background: 'rgba(0,0,0,0.6)',\n zIndex: 99999,\n display: 'flex',\n alignItems: 'center',\n justifyContent: 'center',\n }}\n >\n <div\n onClick={(e) => e.stopPropagation()}\n style={{\n background: '#fff',\n borderRadius: 8,\n padding: 8,\n maxWidth: '90vw',\n maxHeight: '90vh',\n position: 'relative',\n }}\n >\n <button\n onClick={() => setPreviewUrl(null)}\n style={{\n position: 'absolute',\n top: 4,\n right: 8,\n background: 'none',\n border: 'none',\n fontSize: 18,\n cursor: 'pointer',\n color: '#6b7280',\n zIndex: 1,\n }}\n >\n x\n </button>\n <img\n src={previewUrl}\n alt=\"Screenshot preview\"\n style={{ maxWidth: '85vw', maxHeight: '85vh', display: 'block', borderRadius: 4 }}\n />\n </div>\n </div>\n )}\n </div>\n );\n}\n","import React, { useState } from 'react';\nimport type { Draft } from '../types';\n\ninterface DraftItemProps {\n draft: Draft;\n selected: boolean;\n screenshotUrl: string | null;\n onToggleSelect: (id: string) => void;\n onUpdate: (id: string, comment: string) => void;\n onDelete: (id: string) => void;\n onPreviewScreenshot: (draftId: string) => void;\n}\n\nexport function DraftItem({ draft, selected, screenshotUrl, onToggleSelect, onUpdate, onDelete, onPreviewScreenshot }: DraftItemProps) {\n const [editing, setEditing] = useState(false);\n const [editComment, setEditComment] = useState(draft.comment);\n const [confirmDelete, setConfirmDelete] = useState(false);\n\n const handleSaveEdit = () => {\n if (editComment.trim()) {\n onUpdate(draft.id, editComment.trim());\n }\n setEditing(false);\n };\n\n const truncatedPath = draft.componentPath.length > 50\n ? '...' + draft.componentPath.slice(-47)\n : draft.componentPath;\n\n return (\n <div\n style={{\n padding: '10px 12px',\n borderBottom: '1px solid #e5e7eb',\n fontSize: 13,\n fontFamily: 'system-ui, sans-serif',\n }}\n >\n <div style={{ display: 'flex', alignItems: 'flex-start', gap: 8 }}>\n <input\n type=\"checkbox\"\n checked={selected}\n onChange={() => onToggleSelect(draft.id)}\n style={{ marginTop: 3, cursor: 'pointer' }}\n />\n <div style={{ flex: 1, minWidth: 0 }}>\n <div style={{ color: '#6b7280', fontSize: 11, marginBottom: 2 }} title={draft.componentPath}>\n {truncatedPath}\n </div>\n <div style={{ color: '#9ca3af', fontSize: 11, marginBottom: 4 }} title={draft.url}>\n {draft.url.length > 60 ? draft.url.slice(0, 60) + '...' : draft.url}\n </div>\n\n {screenshotUrl && (\n <img\n src={screenshotUrl}\n alt=\"Screenshot\"\n onClick={() => onPreviewScreenshot(draft.id)}\n style={{\n width: '100%',\n maxHeight: 160,\n objectFit: 'cover',\n borderRadius: 4,\n border: '1px solid #e5e7eb',\n cursor: 'pointer',\n marginBottom: 6,\n }}\n title=\"Click to enlarge\"\n />\n )}\n\n {editing ? (\n <div>\n <textarea\n value={editComment}\n onChange={(e) => setEditComment(e.target.value)}\n autoFocus\n style={{\n width: '100%',\n minHeight: 48,\n padding: 6,\n borderRadius: 4,\n border: '1px solid #d1d5db',\n fontSize: 13,\n resize: 'vertical',\n boxSizing: 'border-box',\n }}\n />\n <div style={{ display: 'flex', gap: 4, marginTop: 4 }}>\n <button onClick={handleSaveEdit} style={smallBtn('#3b82f6', '#fff')}>Save</button>\n <button onClick={() => { setEditing(false); setEditComment(draft.comment); }} style={smallBtn('#f3f4f6', '#374151')}>Cancel</button>\n </div>\n </div>\n ) : (\n <div\n onClick={() => setEditing(true)}\n style={{ cursor: 'pointer', color: '#1f2937', lineHeight: 1.4 }}\n title=\"Click to edit\"\n >\n {draft.comment}\n </div>\n )}\n </div>\n\n <div style={{ flexShrink: 0 }}>\n {confirmDelete ? (\n <div style={{ display: 'flex', gap: 4, fontSize: 12 }}>\n <button onClick={() => onDelete(draft.id)} style={smallBtn('#ef4444', '#fff')}>Yes</button>\n <button onClick={() => setConfirmDelete(false)} style={smallBtn('#f3f4f6', '#374151')}>No</button>\n </div>\n ) : (\n <button\n onClick={() => setConfirmDelete(true)}\n style={{\n background: 'none',\n border: 'none',\n cursor: 'pointer',\n color: '#9ca3af',\n fontSize: 16,\n padding: '0 4px',\n }}\n title=\"Delete draft\"\n >\n x\n </button>\n )}\n </div>\n </div>\n </div>\n );\n}\n\nfunction smallBtn(bg: string, color: string): React.CSSProperties {\n return {\n padding: '3px 8px',\n borderRadius: 4,\n border: '1px solid #d1d5db',\n background: bg,\n color,\n fontSize: 12,\n cursor: 'pointer',\n };\n}\n","import React, { useState, useEffect } from 'react';\nimport type { CapturedContext } from '../types';\n\nconst WIDGET_CONTAINER_ID = 'llm-ui-feedback-root';\n\ninterface DraftModalProps {\n pendingContext: { context: CapturedContext; screenshot: string | null };\n addingDraft: boolean;\n onAdd: (comment: string) => void;\n onCancel: () => void;\n}\n\nexport function DraftModal({ pendingContext, addingDraft, onAdd, onCancel }: DraftModalProps) {\n const [comment, setComment] = useState('');\n\n // Disable focus traps from host app modals (e.g. MUI Dialog) while our modal is open\n useEffect(() => {\n const container = document.getElementById(WIDGET_CONTAINER_ID);\n const inerted: Element[] = [];\n\n // Set inert on all top-level body children except the widget container\n for (const child of Array.from(document.body.children)) {\n if (child === container || child.id === WIDGET_CONTAINER_ID) continue;\n if (!child.hasAttribute('inert')) {\n child.setAttribute('inert', '');\n inerted.push(child);\n }\n }\n\n return () => {\n for (const el of inerted) {\n el.removeAttribute('inert');\n }\n };\n }, []);\n\n const handleAdd = () => {\n if (comment.trim() && !addingDraft) {\n onAdd(comment.trim());\n }\n };\n\n const { context, screenshot } = pendingContext;\n\n return (\n <div\n style={{\n position: 'fixed',\n inset: 0,\n zIndex: 99999,\n display: 'flex',\n alignItems: 'center',\n justifyContent: 'center',\n background: 'rgba(0,0,0,0.4)',\n fontFamily: 'system-ui, sans-serif',\n }}\n onClick={(e) => {\n if (e.target === e.currentTarget && !addingDraft) onCancel();\n }}\n >\n <div\n style={{\n background: '#fff',\n borderRadius: 12,\n padding: 24,\n width: 480,\n maxWidth: '90vw',\n maxHeight: '85vh',\n overflow: 'auto',\n boxShadow: '0 8px 32px rgba(0,0,0,0.2)',\n }}\n >\n <h3 style={{ margin: '0 0 16px', fontSize: 16 }}>New Feedback</h3>\n\n <div style={{ fontSize: 12, color: '#6b7280', marginBottom: 12 }}>\n <div><strong>Component:</strong> {context.componentPath}</div>\n <div><strong>Path:</strong> {context.urlPath}</div>\n {context.elementText && (\n <div><strong>Element:</strong> &quot;{context.elementText.slice(0, 80)}&quot;</div>\n )}\n </div>\n\n {screenshot && (\n <img\n src={screenshot}\n alt=\"Screenshot\"\n style={{\n width: '100%',\n borderRadius: 8,\n border: '1px solid #e5e7eb',\n marginBottom: 12,\n maxHeight: 180,\n objectFit: 'cover',\n }}\n />\n )}\n\n <textarea\n value={comment}\n onChange={(e) => setComment(e.target.value)}\n placeholder=\"Describe the issue or suggestion...\"\n autoFocus\n onKeyDown={(e) => {\n if (e.key === 'Enter' && (e.metaKey || e.ctrlKey)) handleAdd();\n }}\n style={{\n width: '100%',\n minHeight: 80,\n padding: 10,\n borderRadius: 8,\n border: '1px solid #d1d5db',\n fontSize: 14,\n resize: 'vertical',\n boxSizing: 'border-box',\n }}\n />\n\n <div style={{ display: 'flex', gap: 8, marginTop: 16, justifyContent: 'flex-end' }}>\n <button\n onClick={onCancel}\n disabled={addingDraft}\n style={{\n padding: '8px 16px',\n borderRadius: 6,\n border: '1px solid #d1d5db',\n background: '#f3f4f6',\n color: '#374151',\n fontSize: 13,\n cursor: 'pointer',\n }}\n >\n Cancel\n </button>\n <button\n onClick={handleAdd}\n disabled={!comment.trim() || addingDraft}\n style={{\n padding: '8px 16px',\n borderRadius: 6,\n border: 'none',\n background: !comment.trim() || addingDraft ? '#93c5fd' : '#3b82f6',\n color: '#fff',\n fontSize: 13,\n cursor: !comment.trim() || addingDraft ? 'default' : 'pointer',\n }}\n >\n {addingDraft ? 'Adding...' : 'Add to Drafts'}\n </button>\n </div>\n </div>\n </div>\n );\n}\n","import React, { useState } from 'react';\n\ninterface SubmitModalProps {\n count: number;\n onSubmit: (title: string) => void;\n onCancel: () => void;\n submitting: boolean;\n}\n\nexport function SubmitModal({ count, onSubmit, onCancel, submitting }: SubmitModalProps) {\n const [title, setTitle] = useState('');\n\n const handleSubmit = () => {\n if (title.trim() && !submitting) {\n onSubmit(title.trim());\n }\n };\n\n return (\n <div\n style={{\n position: 'fixed',\n inset: 0,\n zIndex: 99999,\n display: 'flex',\n alignItems: 'center',\n justifyContent: 'center',\n background: 'rgba(0,0,0,0.4)',\n fontFamily: 'system-ui, sans-serif',\n }}\n onClick={(e) => {\n if (e.target === e.currentTarget && !submitting) onCancel();\n }}\n >\n <div\n style={{\n background: '#fff',\n borderRadius: 12,\n padding: 24,\n width: 400,\n maxWidth: '90vw',\n boxShadow: '0 8px 32px rgba(0,0,0,0.2)',\n }}\n >\n <h3 style={{ margin: '0 0 16px', fontSize: 16 }}>Submit Feedback</h3>\n <p style={{ margin: '0 0 12px', fontSize: 14, color: '#6b7280' }}>\n {count} item{count !== 1 ? 's' : ''} selected. Name this feedback session:\n </p>\n <input\n type=\"text\"\n value={title}\n onChange={(e) => setTitle(e.target.value)}\n placeholder=\"e.g. Homepage redesign feedback\"\n autoFocus\n onKeyDown={(e) => { if (e.key === 'Enter') handleSubmit(); }}\n style={{\n width: '100%',\n padding: 10,\n borderRadius: 8,\n border: '1px solid #d1d5db',\n fontSize: 14,\n boxSizing: 'border-box',\n }}\n />\n <div style={{ display: 'flex', gap: 8, marginTop: 16, justifyContent: 'flex-end' }}>\n <button\n onClick={onCancel}\n disabled={submitting}\n style={{\n padding: '8px 16px',\n borderRadius: 6,\n border: '1px solid #d1d5db',\n background: '#f3f4f6',\n color: '#374151',\n fontSize: 13,\n cursor: 'pointer',\n }}\n >\n Cancel\n </button>\n <button\n onClick={handleSubmit}\n disabled={!title.trim() || submitting}\n style={{\n padding: '8px 16px',\n borderRadius: 6,\n border: 'none',\n background: !title.trim() || submitting ? '#93c5fd' : '#3b82f6',\n color: '#fff',\n fontSize: 13,\n cursor: !title.trim() || submitting ? 'default' : 'pointer',\n }}\n >\n {submitting ? 'Submitting...' : 'Submit'}\n </button>\n </div>\n </div>\n </div>\n );\n}\n","import { ComponentInfo } from '../types';\n\nlet minificationWarned = false;\n\nfunction getFiber(el: Element): any | null {\n const key = Object.keys(el).find((k) => k.startsWith('__reactFiber$'));\n return key ? (el as any)[key] : null;\n}\n\nfunction pickShortProps(props: Record<string, unknown>): Record<string, unknown> {\n const short: Record<string, unknown> = {};\n for (const [key, value] of Object.entries(props)) {\n if (key === 'children') continue;\n if (typeof value === 'function') continue;\n if (typeof value === 'string' || typeof value === 'number' || typeof value === 'boolean') {\n short[key] = value;\n }\n }\n return short;\n}\n\nexport function getComponentPath(el: Element, maxDepth = 8): ComponentInfo[] {\n const fiber = getFiber(el);\n if (!fiber) return [];\n\n const path: ComponentInfo[] = [];\n let current = fiber;\n\n while (current && path.length < maxDepth) {\n if (typeof current.type === 'function' || typeof current.type === 'object') {\n const name =\n current.type?.displayName || current.type?.name || null;\n if (name) {\n // Detect minified names: single-char lowercase names are typical minifier output\n if (\n !minificationWarned &&\n name.length <= 2 &&\n /^[a-z]/.test(name)\n ) {\n minificationWarned = true;\n console.warn(\n '[llm-ui-feedback] Component names appear minified (e.g., \"' +\n name +\n '\"). The generated LLM prompts will lack meaningful component paths. ' +\n 'To fix, configure your bundler to preserve function names. ' +\n 'See: https://github.com/user/llm-ui-feedback/blob/main/docs/production-setup.md'\n );\n }\n path.push({\n name,\n props: pickShortProps(current.memoizedProps || {}),\n });\n }\n }\n current = current.return;\n }\n\n return path.reverse();\n}\n","import html2canvas from 'html2canvas-pro';\n\nexport interface ScreenshotRect {\n x: number;\n y: number;\n width: number;\n height: number;\n}\n\nexport async function captureScreenshot(rect: ScreenshotRect): Promise<string> {\n const fullCanvas = await html2canvas(document.body, {\n logging: false,\n useCORS: true,\n });\n\n // Convert viewport coords to document coords\n const docX = rect.x + window.scrollX;\n const docY = rect.y + window.scrollY;\n\n // html2canvas may scale the canvas vs the document — compute ratio\n const scaleX = fullCanvas.width / document.documentElement.scrollWidth;\n const scaleY = fullCanvas.height / document.documentElement.scrollHeight;\n\n const sx = Math.round(docX * scaleX);\n const sy = Math.round(docY * scaleY);\n const sw = Math.round(rect.width * scaleX);\n const sh = Math.round(rect.height * scaleY);\n\n // Crop to the selected region\n const cropped = document.createElement('canvas');\n cropped.width = sw;\n cropped.height = sh;\n const ctx = cropped.getContext('2d');\n if (ctx) {\n ctx.drawImage(fullCanvas, sx, sy, sw, sh, 0, 0, sw, sh);\n\n // Draw a blue border to indicate the selection\n ctx.strokeStyle = '#3b82f6';\n ctx.lineWidth = 3;\n ctx.strokeRect(1, 1, sw - 2, sh - 2);\n }\n\n return cropped.toDataURL('image/png');\n}\n","import { CapturedContext } from '../types';\n\nexport function buildPrompt(context: CapturedContext, comment: string): string {\n const propsStr = context.components\n .filter((c) => Object.keys(c.props).length > 0)\n .map((c) => ` ${c.name}: ${JSON.stringify(c.props)}`)\n .join('\\n');\n\n const lines = [\n `Page: ${context.url}`,\n `Path: ${context.urlPath}`,\n `Reported at: ${context.reportedAt}`,\n `Component: ${context.componentPath}`,\n ];\n\n if (propsStr) {\n lines.push(`Props:\\n${propsStr}`);\n }\n\n if (context.elementText) {\n lines.push(`Element text: \"${context.elementText}\"`);\n }\n\n lines.push('', `User feedback: \"${comment}\"`, '', 'Screenshot attached showing the selected region.');\n\n return lines.join('\\n');\n}\n","export function dataUrlToBlob(dataUrl: string): Blob {\n const [header, base64] = dataUrl.split(',');\n const mime = header.match(/:(.*?);/)?.[1] || 'image/png';\n const binary = atob(base64);\n const bytes = new Uint8Array(binary.length);\n for (let i = 0; i < binary.length; i++) {\n bytes[i] = binary.charCodeAt(i);\n }\n return new Blob([bytes], { type: mime });\n}\n","import { useState, useEffect, useCallback, useRef } from 'react';\n\nconst SESSION_TOKEN_KEY = 'llm_feedback_session_token';\nconst USER_KEY = 'llm_feedback_user';\n\n// Check for auth bypass flag — Vite replaces import.meta.env at build time.\n// In non-Vite contexts (npm package CJS), import.meta.env is undefined which is fine.\nconst AUTH_BYPASS = (typeof globalThis !== 'undefined' && (globalThis as any).__FEEDBACK_AUTH_BYPASS__)\n || (typeof import.meta !== 'undefined' && (import.meta as any).env?.VITE_AUTH_BYPASS === 'true');\n\nexport interface UserInfo {\n email: string;\n name: string;\n picture: string;\n sub: string;\n}\n\nexport interface SessionState {\n status: 'loading' | 'unauthenticated' | 'authenticated';\n user: UserInfo | null;\n signIn: () => void;\n signOut: () => void;\n}\n\nexport function getSessionToken(): string | null {\n if (AUTH_BYPASS) return 'bypass-token';\n return localStorage.getItem(SESSION_TOKEN_KEY);\n}\n\nconst BYPASS_USER: UserInfo = {\n email: 'bypass@test.local',\n name: 'Bypass User',\n picture: '',\n sub: 'bypass-user',\n};\n\nexport function useSession(apiUrl: string, clientId: string): SessionState {\n const [status, setStatus] = useState<SessionState['status']>(AUTH_BYPASS ? 'authenticated' : 'loading');\n const [user, setUser] = useState<UserInfo | null>(AUTH_BYPASS ? BYPASS_USER : null);\n const pendingAuthRef = useRef(false);\n\n // On mount: check localStorage for existing session\n useEffect(() => {\n if (AUTH_BYPASS) return;\n let cancelled = false;\n\n async function checkSession() {\n const token = localStorage.getItem(SESSION_TOKEN_KEY);\n const savedUser = localStorage.getItem(USER_KEY);\n\n if (!token || !savedUser) {\n if (!cancelled) setStatus('unauthenticated');\n return;\n }\n\n try {\n const res = await fetch(`${apiUrl}/auth/status`, {\n headers: { 'X-Session-Token': token },\n });\n const data = await res.json();\n\n if (!cancelled) {\n if (data.authenticated) {\n setUser(data.user);\n setStatus('authenticated');\n } else {\n localStorage.removeItem(SESSION_TOKEN_KEY);\n localStorage.removeItem(USER_KEY);\n setStatus('unauthenticated');\n }\n }\n } catch {\n if (!cancelled) {\n // Network error — use cached user optimistically\n try {\n setUser(JSON.parse(savedUser));\n setStatus('authenticated');\n } catch {\n setStatus('unauthenticated');\n }\n }\n }\n }\n\n checkSession();\n return () => { cancelled = true; };\n }, [apiUrl]);\n\n // Listen for postMessage from auth popup\n useEffect(() => {\n function handleMessage(event: MessageEvent) {\n if (event.data?.type !== 'feedback-auth') return;\n const { sessionToken, user: userData } = event.data;\n if (sessionToken && userData) {\n localStorage.setItem(SESSION_TOKEN_KEY, sessionToken);\n localStorage.setItem(USER_KEY, JSON.stringify(userData));\n setUser(userData);\n setStatus('authenticated');\n pendingAuthRef.current = false;\n }\n }\n\n window.addEventListener('message', handleMessage);\n return () => window.removeEventListener('message', handleMessage);\n }, []);\n\n const signIn = useCallback(() => {\n if (pendingAuthRef.current) return;\n pendingAuthRef.current = true;\n\n const loginUrl = `${apiUrl}/auth/login?clientId=${encodeURIComponent(clientId)}&origin=${encodeURIComponent(window.location.origin)}`;\n const popup = window.open(loginUrl, 'feedback-auth', 'width=500,height=600,menubar=no,toolbar=no');\n\n if (!popup) {\n // Popup blocked — can't do much, reset flag\n pendingAuthRef.current = false;\n return;\n }\n\n // Poll for popup closed (user cancelled)\n const interval = setInterval(() => {\n if (popup.closed) {\n clearInterval(interval);\n pendingAuthRef.current = false;\n }\n }, 500);\n }, [apiUrl, clientId]);\n\n const signOut = useCallback(async () => {\n const token = localStorage.getItem(SESSION_TOKEN_KEY);\n localStorage.removeItem(SESSION_TOKEN_KEY);\n localStorage.removeItem(USER_KEY);\n setUser(null);\n setStatus('unauthenticated');\n\n if (token) {\n try {\n await fetch(`${apiUrl}/auth/logout`, {\n method: 'POST',\n headers: { 'X-Session-Token': token },\n });\n } catch {\n // Best-effort logout\n }\n }\n }, [apiUrl]);\n\n return { status, user, signIn, signOut };\n}\n","import type { Draft, FeedbackGroup } from '../types';\nimport { getSessionToken } from '../hooks/useSession';\n\nexport interface DraftPayload {\n id: string;\n url: string;\n componentPath: string;\n components: { name: string; props: Record<string, unknown> }[];\n elementText: string;\n comment: string;\n prompt: string;\n screenshotKey?: string;\n}\n\nexport interface ApiClient {\n fetchDrafts(): Promise<Draft[]>;\n createDraft(draft: DraftPayload): Promise<Draft>;\n updateDraft(id: string, data: { comment: string }): Promise<Draft>;\n deleteDraft(id: string): Promise<void>;\n submitSession(data: { title: string; draftIds: string[] }): Promise<{ feedbackGroup: FeedbackGroup; entriesCreated: number }>;\n getUploadUrl(\n entryId: string,\n timestamp: string,\n ): Promise<{ uploadUrl: string; key: string }>;\n uploadScreenshot(uploadUrl: string, blob: Blob): Promise<void>;\n getScreenshotUrl(draftId: string): Promise<string>;\n}\n\nexport function createApiClient(apiUrl: string, clientId: string): ApiClient {\n async function apiFetch(path: string, options: RequestInit = {}) {\n const token = getSessionToken();\n const res = await fetch(`${apiUrl}${path}`, {\n ...options,\n headers: {\n 'Content-Type': 'application/json',\n ...(token ? { 'X-Session-Token': token } : {}),\n 'X-Client-Id': clientId,\n ...(options.headers as Record<string, string> | undefined),\n },\n });\n if (!res.ok) {\n const body = await res.json().catch(() => ({}));\n throw new Error(\n (body as Record<string, string>).error ||\n `API error ${res.status}`,\n );\n }\n if (res.status === 204) return undefined;\n return res.json();\n }\n\n return {\n async fetchDrafts() {\n const data = await apiFetch('/drafts');\n return (data as { items: Draft[] }).items;\n },\n\n async createDraft(draft: DraftPayload) {\n return apiFetch('/drafts', {\n method: 'POST',\n body: JSON.stringify(draft),\n }) as Promise<Draft>;\n },\n\n async updateDraft(id: string, data: { comment: string }) {\n return apiFetch(`/drafts/${id}`, {\n method: 'PATCH',\n body: JSON.stringify(data),\n }) as Promise<Draft>;\n },\n\n async deleteDraft(id: string) {\n await apiFetch(`/drafts/${id}`, { method: 'DELETE' });\n },\n\n async submitSession(data: { title: string; draftIds: string[] }) {\n return apiFetch('/feedback-groups/submit', {\n method: 'POST',\n body: JSON.stringify(data),\n }) as Promise<{ feedbackGroup: FeedbackGroup; entriesCreated: number }>;\n },\n\n async getUploadUrl(entryId: string, timestamp: string) {\n return apiFetch('/upload-url', {\n method: 'POST',\n body: JSON.stringify({ entryId, timestamp }),\n }) as Promise<{ uploadUrl: string; key: string }>;\n },\n\n async getScreenshotUrl(draftId: string) {\n const data = await apiFetch(`/drafts/${draftId}/screenshot-url`);\n return (data as { url: string }).url;\n },\n\n async uploadScreenshot(uploadUrl: string, blob: Blob) {\n const res = await fetch(uploadUrl, {\n method: 'PUT',\n body: blob,\n headers: { 'Content-Type': 'image/png' },\n });\n if (!res.ok) throw new Error(`S3 upload failed: ${res.status}`);\n },\n };\n}\n","export const DEFAULT_API_URL = 'https://your-lambda-function-url.lambda-url.us-east-1.on.aws';\n"],"mappings":"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","names":["import_react","import_jsx_runtime","import_react","import_react","import_jsx_runtime","import_jsx_runtime","React","import_react","import_jsx_runtime","WIDGET_CONTAINER_ID","import_react","import_jsx_runtime","html2canvas","import_react","import_jsx_runtime"]}
1
+ {"version":3,"sources":["../src/index.ts","../src/components/FeedbackWidget.tsx","../src/utils/color.ts","../src/components/FloatingButton.tsx","../src/components/PickOverlay.tsx","../src/components/SidePanel.tsx","../src/components/DraftItem.tsx","../src/components/DraftModal.tsx","../src/components/SubmitModal.tsx","../src/utils/fiber.ts","../src/utils/screenshot.ts","../src/utils/prompt.ts","../src/utils/blob.ts","../src/hooks/useSession.ts","../src/api/client.ts"],"sourcesContent":["export { FeedbackWidget } from './components/FeedbackWidget';\nexport type { FeedbackWidgetProps } from './components/FeedbackWidget';\nexport type { FeedbackEntry, CapturedContext, ComponentInfo, WidgetPosition, Draft, FeedbackGroup } from './types';\n","import React, { useReducer, useCallback, useEffect, useMemo, useRef } from 'react';\nimport { createPortal } from 'react-dom';\nimport { FloatingButton } from './FloatingButton';\nimport { PickOverlay } from './PickOverlay';\nimport { SidePanel } from './SidePanel';\nimport { DraftModal } from './DraftModal';\nimport { SubmitModal } from './SubmitModal';\nimport { getComponentPath } from '../utils/fiber';\nimport { captureScreenshot } from '../utils/screenshot';\nimport { buildPrompt } from '../utils/prompt';\nimport { dataUrlToBlob } from '../utils/blob';\nimport { createApiClient } from '../api/client';\nimport { useSession } from '../hooks/useSession';\nimport { CapturedContext, Draft, WidgetPosition } from '../types';\n\nexport const CONTAINER_ID = 'llm-ui-feedback-root';\n\nfunction getOrCreateContainer(): HTMLElement {\n let el = document.getElementById(CONTAINER_ID);\n if (!el) {\n el = document.createElement('div');\n el.id = CONTAINER_ID;\n document.body.appendChild(el);\n }\n return el;\n}\n\nexport interface FeedbackWidgetProps {\n /** Tenant identifier — required. */\n clientId: string;\n /** Backend API URL — required. */\n apiUrl: string;\n /** Corner position for the floating button. Default: 'bottom-right' */\n position?: WidgetPosition;\n /** Hex color for the FAB accent. Default: '#3b82f6' */\n buttonColor?: string;\n /** Keyboard shortcut to toggle the panel, e.g. 'Alt+F'. No default (opt-in only). */\n hotkey?: string;\n}\n\ninterface WidgetState {\n panelOpen: boolean;\n picking: boolean;\n pendingContext: { context: CapturedContext; screenshot: string | null } | null;\n drafts: Draft[];\n selectedDraftIds: Set<string>;\n submitModalOpen: boolean;\n addingDraft: boolean;\n submitting: boolean;\n}\n\ntype WidgetAction =\n | { type: 'TOGGLE_PANEL' }\n | { type: 'OPEN_PANEL' }\n | { type: 'CLOSE_PANEL' }\n | { type: 'START_PICKING' }\n | { type: 'CANCEL_PICKING' }\n | { type: 'CANCEL_DRAFT_MODAL' }\n | { type: 'ELEMENT_PICKED'; context: CapturedContext; screenshot: string | null }\n | { type: 'SET_ADDING_DRAFT'; adding: boolean }\n | { type: 'DRAFT_ADDED'; draft: Draft }\n | { type: 'SET_DRAFTS'; drafts: Draft[] }\n | { type: 'DRAFT_UPDATED'; id: string; comment: string }\n | { type: 'DRAFT_DELETED'; id: string }\n | { type: 'TOGGLE_SELECT'; id: string }\n | { type: 'SELECT_ALL'; selected: boolean }\n | { type: 'OPEN_SUBMIT_MODAL' }\n | { type: 'CLOSE_SUBMIT_MODAL' }\n | { type: 'SET_SUBMITTING'; submitting: boolean }\n | { type: 'SUBMIT_COMPLETE'; submittedIds: string[] };\n\nconst initialState: WidgetState = {\n panelOpen: false,\n picking: false,\n pendingContext: null,\n drafts: [],\n selectedDraftIds: new Set(),\n submitModalOpen: false,\n addingDraft: false,\n submitting: false,\n};\n\nfunction widgetReducer(state: WidgetState, action: WidgetAction): WidgetState {\n switch (action.type) {\n case 'TOGGLE_PANEL':\n return state.panelOpen\n ? { ...state, panelOpen: false, picking: false, pendingContext: null }\n : { ...state, panelOpen: true };\n case 'OPEN_PANEL':\n return { ...state, panelOpen: true };\n case 'CLOSE_PANEL':\n return { ...state, panelOpen: false, picking: false, pendingContext: null };\n case 'START_PICKING':\n return { ...state, picking: true };\n case 'CANCEL_PICKING':\n return { ...state, picking: false };\n case 'CANCEL_DRAFT_MODAL':\n return { ...state, pendingContext: null, addingDraft: false };\n case 'ELEMENT_PICKED':\n return { ...state, picking: false, pendingContext: { context: action.context, screenshot: action.screenshot } };\n case 'SET_ADDING_DRAFT':\n return { ...state, addingDraft: action.adding };\n case 'DRAFT_ADDED':\n return { ...state, pendingContext: null, addingDraft: false, drafts: [action.draft, ...state.drafts] };\n case 'SET_DRAFTS':\n return { ...state, drafts: action.drafts };\n case 'DRAFT_UPDATED':\n return { ...state, drafts: state.drafts.map((d) => d.id === action.id ? { ...d, comment: action.comment } : d) };\n case 'DRAFT_DELETED': {\n const next = new Set(state.selectedDraftIds);\n next.delete(action.id);\n return { ...state, drafts: state.drafts.filter((d) => d.id !== action.id), selectedDraftIds: next };\n }\n case 'TOGGLE_SELECT': {\n const next = new Set(state.selectedDraftIds);\n if (next.has(action.id)) next.delete(action.id);\n else next.add(action.id);\n return { ...state, selectedDraftIds: next };\n }\n case 'SELECT_ALL':\n return { ...state, selectedDraftIds: action.selected ? new Set(state.drafts.map((d) => d.id)) : new Set() };\n case 'OPEN_SUBMIT_MODAL':\n return { ...state, submitModalOpen: true };\n case 'CLOSE_SUBMIT_MODAL':\n return { ...state, submitModalOpen: false };\n case 'SET_SUBMITTING':\n return { ...state, submitting: action.submitting };\n case 'SUBMIT_COMPLETE': {\n const submitted = new Set(action.submittedIds);\n return {\n ...state,\n submitting: false,\n submitModalOpen: false,\n drafts: state.drafts.filter((d) => !submitted.has(d.id)),\n selectedDraftIds: new Set(),\n };\n }\n default:\n return state;\n }\n}\n\nfunction parseHotkey(hotkey: string) {\n const parts = hotkey.split('+').map((p) => p.trim().toLowerCase());\n const key = parts.pop()!;\n return {\n key,\n ctrl: parts.includes('ctrl'),\n alt: parts.includes('alt'),\n shift: parts.includes('shift'),\n meta: parts.includes('meta'),\n };\n}\n\nfunction isEditableTarget(el: Element | null): boolean {\n if (!el) return false;\n const tag = el.tagName;\n if (tag === 'INPUT' || tag === 'TEXTAREA' || tag === 'SELECT') return true;\n if ((el as HTMLElement).isContentEditable) return true;\n return false;\n}\n\nexport function FeedbackWidget({\n clientId,\n apiUrl,\n position = 'bottom-right',\n buttonColor = '#3b82f6',\n hotkey,\n}: FeedbackWidgetProps) {\n const session = useSession(apiUrl, clientId);\n const [state, dispatch] = useReducer(widgetReducer, initialState);\n const pendingOpenRef = useRef(false);\n\n const api = useMemo(\n () => createApiClient(apiUrl, clientId),\n [apiUrl, clientId],\n );\n\n // Auto-open panel after successful auth\n useEffect(() => {\n if (session.status === 'authenticated' && pendingOpenRef.current) {\n pendingOpenRef.current = false;\n dispatch({ type: 'OPEN_PANEL' });\n }\n }, [session.status]);\n\n // Fetch drafts on auth and when panel opens\n useEffect(() => {\n if (session.status === 'authenticated') {\n api.fetchDrafts().then((drafts) => {\n dispatch({ type: 'SET_DRAFTS', drafts });\n }).catch(() => {\n // silently fail\n });\n }\n }, [state.panelOpen, session.status, api]);\n\n // Hotkey listener\n useEffect(() => {\n if (!hotkey) return;\n const parsed = parseHotkey(hotkey);\n\n function handler(e: KeyboardEvent) {\n if (isEditableTarget(document.activeElement)) return;\n if (\n e.key.toLowerCase() === parsed.key &&\n e.ctrlKey === parsed.ctrl &&\n e.altKey === parsed.alt &&\n e.shiftKey === parsed.shift &&\n e.metaKey === parsed.meta\n ) {\n e.preventDefault();\n dispatch({ type: 'TOGGLE_PANEL' });\n }\n }\n\n window.addEventListener('keydown', handler);\n return () => window.removeEventListener('keydown', handler);\n }, [hotkey]);\n\n const handlePickClick = useCallback(() => {\n if (session.status === 'unauthenticated') {\n pendingOpenRef.current = true;\n session.signIn();\n return;\n }\n dispatch({ type: 'START_PICKING' });\n }, [session]);\n\n const handlePanelToggle = useCallback(() => {\n if (session.status === 'unauthenticated') {\n pendingOpenRef.current = true;\n session.signIn();\n return;\n }\n dispatch({ type: 'TOGGLE_PANEL' });\n }, [session]);\n\n const handlePick = useCallback(async (rect: { x: number; y: number; width: number; height: number }, elements: Element[]) => {\n // Collect unique components from all elements in the selection\n const seenNames = new Set<string>();\n const allComponents: { name: string; props: Record<string, unknown> }[] = [];\n for (const el of elements) {\n for (const comp of getComponentPath(el)) {\n if (!seenNames.has(comp.name)) {\n seenNames.add(comp.name);\n allComponents.push(comp);\n }\n }\n }\n\n const componentPath = allComponents.map((c) => c.name).join(', ') || '(no React component found)';\n\n // Gather text from selected elements\n const textParts = new Set<string>();\n for (const el of elements) {\n const raw = ((el as HTMLElement).innerText || el.textContent || '').trim();\n if (raw) textParts.add(raw);\n }\n const combined = Array.from(textParts).join(' ').trim();\n const elementText = combined.length > 200 ? combined.slice(0, 200) + '...' : combined;\n\n const centerX = rect.x + rect.width / 2;\n const centerY = rect.y + rect.height / 2;\n\n const context: CapturedContext = {\n url: window.location.href,\n urlPath: window.location.pathname,\n reportedAt: new Date().toISOString(),\n componentPath,\n components: allComponents,\n elementText,\n clickX: centerX,\n clickY: centerY,\n };\n\n // Only capture screenshot for drag selections, not single-element clicks\n const isDrag = rect.width > 20 && rect.height > 20;\n let screenshot: string | null = null;\n if (isDrag) {\n try {\n screenshot = await captureScreenshot(rect);\n } catch {\n // Screenshot failed — continue without it\n }\n }\n\n dispatch({ type: 'ELEMENT_PICKED', context, screenshot });\n }, []);\n\n const handleCancelPicking = useCallback(() => {\n dispatch({ type: 'CANCEL_PICKING' });\n }, []);\n\n const handleAddDraft = useCallback(async (comment: string) => {\n if (!state.pendingContext) return;\n dispatch({ type: 'SET_ADDING_DRAFT', adding: true });\n\n const { context, screenshot } = state.pendingContext;\n const entryId = `f_${Date.now()}`;\n const timestamp = new Date().toISOString();\n let screenshotKey: string | undefined;\n\n // Upload screenshot\n if (screenshot) {\n const blob = dataUrlToBlob(screenshot);\n try {\n const { uploadUrl, key } = await api.getUploadUrl(entryId, timestamp);\n await api.uploadScreenshot(uploadUrl, blob);\n screenshotKey = key;\n } catch {\n // continue without screenshot\n }\n }\n\n try {\n const draft = await api.createDraft({\n id: entryId,\n url: context.url,\n componentPath: context.componentPath,\n components: context.components,\n elementText: context.elementText,\n comment,\n prompt: buildPrompt(context, comment),\n ...(screenshotKey ? { screenshotKey } : {}),\n });\n dispatch({ type: 'DRAFT_ADDED', draft });\n } catch {\n dispatch({ type: 'SET_ADDING_DRAFT', adding: false });\n }\n }, [state.pendingContext, api]);\n\n const handleUpdateDraft = useCallback(async (id: string, comment: string) => {\n dispatch({ type: 'DRAFT_UPDATED', id, comment });\n try {\n await api.updateDraft(id, { comment });\n } catch {\n // revert on error — refetch\n api.fetchDrafts().then((drafts) => dispatch({ type: 'SET_DRAFTS', drafts })).catch(() => {});\n }\n }, [api]);\n\n const handleDeleteDraft = useCallback(async (id: string) => {\n dispatch({ type: 'DRAFT_DELETED', id });\n try {\n await api.deleteDraft(id);\n } catch {\n // refetch on error\n api.fetchDrafts().then((drafts) => dispatch({ type: 'SET_DRAFTS', drafts })).catch(() => {});\n }\n }, [api]);\n\n const handleSubmit = useCallback(async (title: string) => {\n dispatch({ type: 'SET_SUBMITTING', submitting: true });\n const draftIds = Array.from(state.selectedDraftIds);\n try {\n await api.submitSession({ title, draftIds });\n dispatch({ type: 'SUBMIT_COMPLETE', submittedIds: draftIds });\n } catch {\n dispatch({ type: 'SET_SUBMITTING', submitting: false });\n }\n }, [state.selectedDraftIds, api]);\n\n // Don't render while checking auth status\n if (session.status === 'loading') return null;\n\n return createPortal(\n <>\n <FloatingButton\n onPickClick={handlePickClick}\n onPanelToggle={handlePanelToggle}\n draftCount={state.drafts.length}\n panelOpen={state.panelOpen}\n position={position}\n buttonColor={buttonColor}\n />\n {state.picking && <PickOverlay onPick={handlePick} onCancel={handleCancelPicking} />}\n {state.panelOpen && (\n <SidePanel\n position={position}\n drafts={state.drafts}\n selectedDraftIds={state.selectedDraftIds}\n onToggleSelect={(id) => dispatch({ type: 'TOGGLE_SELECT', id })}\n onSelectAll={(selected) => dispatch({ type: 'SELECT_ALL', selected })}\n onUpdateDraft={handleUpdateDraft}\n onDeleteDraft={handleDeleteDraft}\n onSubmit={() => dispatch({ type: 'OPEN_SUBMIT_MODAL' })}\n onClose={() => dispatch({ type: 'CLOSE_PANEL' })}\n api={api}\n user={session.user}\n />\n )}\n {state.pendingContext && !state.picking && (\n <DraftModal\n pendingContext={state.pendingContext}\n addingDraft={state.addingDraft}\n onAdd={handleAddDraft}\n onCancel={() => dispatch({ type: 'CANCEL_DRAFT_MODAL' })}\n />\n )}\n {state.submitModalOpen && (\n <SubmitModal\n count={state.selectedDraftIds.size}\n onSubmit={handleSubmit}\n onCancel={() => dispatch({ type: 'CLOSE_SUBMIT_MODAL' })}\n submitting={state.submitting}\n />\n )}\n </>,\n getOrCreateContainer()\n );\n}\n","/**\n * Compute whether to use light or dark text on a given background color.\n * Uses the WCAG relative luminance formula.\n * @param hexColor - Hex color string (e.g., '#3b82f6' or '#fff')\n * @returns '#000000' for light backgrounds, '#ffffff' for dark backgrounds\n */\nexport function getContrastColor(hexColor: string): string {\n const hex = hexColor.replace('#', '');\n // Expand 3-char hex to 6-char (e.g., #fff -> #ffffff)\n const fullHex =\n hex.length === 3\n ? hex[0] + hex[0] + hex[1] + hex[1] + hex[2] + hex[2]\n : hex;\n\n const r = parseInt(fullHex.substring(0, 2), 16) / 255;\n const g = parseInt(fullHex.substring(2, 4), 16) / 255;\n const b = parseInt(fullHex.substring(4, 6), 16) / 255;\n\n const toLinear = (c: number) =>\n c <= 0.03928 ? c / 12.92 : Math.pow((c + 0.055) / 1.055, 2.4);\n\n // Relative luminance (WCAG 2.0)\n const luminance =\n 0.2126 * toLinear(r) + 0.7152 * toLinear(g) + 0.0722 * toLinear(b);\n\n return luminance > 0.179 ? '#000000' : '#ffffff';\n}\n","import React from 'react';\nimport { WidgetPosition } from '../types';\nimport { getContrastColor } from '../utils/color';\n\ninterface FloatingButtonProps {\n onPickClick: () => void;\n onPanelToggle: () => void;\n draftCount: number;\n panelOpen: boolean;\n position: WidgetPosition;\n buttonColor: string;\n}\n\nexport function FloatingButton({ onPickClick, onPanelToggle, draftCount, panelOpen, position, buttonColor }: FloatingButtonProps) {\n const isBottom = position.includes('bottom');\n const isRight = position.includes('right');\n\n const anchor: React.CSSProperties = {\n position: 'fixed',\n [isBottom ? 'bottom' : 'top']: 24,\n [isRight ? 'right' : 'left']: 24,\n zIndex: 99999,\n display: 'flex',\n flexDirection: 'column',\n alignItems: 'center',\n gap: 8,\n };\n\n return (\n <div style={anchor}>\n {/* Badge button — draft count, only visible when drafts exist */}\n {draftCount > 0 && (\n <button\n onClick={onPanelToggle}\n aria-label={panelOpen ? 'Close drafts panel' : `Open drafts panel (${draftCount})`}\n style={{\n width: 32,\n height: 32,\n borderRadius: '50%',\n border: 'none',\n background: panelOpen ? '#ef4444' : buttonColor,\n color: panelOpen ? '#fff' : getContrastColor(buttonColor),\n fontFamily: 'system-ui, -apple-system, sans-serif',\n fontSize: 13,\n fontWeight: 700,\n lineHeight: 1,\n cursor: 'pointer',\n display: 'flex',\n alignItems: 'center',\n justifyContent: 'center',\n boxShadow: '0 2px 8px rgba(0,0,0,0.25)',\n transition: 'background 0.15s',\n padding: 0,\n }}\n >\n {draftCount}\n </button>\n )}\n\n {/* FAB — starts picking, or closes panel when open */}\n <button\n onClick={panelOpen ? onPanelToggle : onPickClick}\n aria-label={panelOpen ? 'Close panel' : 'Pick element for feedback'}\n style={{\n width: 48,\n height: 48,\n borderRadius: '50%',\n border: 'none',\n background: panelOpen ? '#ef4444' : buttonColor,\n color: panelOpen ? '#fff' : getContrastColor(buttonColor),\n fontFamily: 'system-ui, -apple-system, sans-serif',\n fontSize: 28,\n fontWeight: 300,\n lineHeight: 1,\n cursor: 'pointer',\n display: 'flex',\n alignItems: 'center',\n justifyContent: 'center',\n boxShadow: '0 2px 8px rgba(0,0,0,0.25)',\n transition: 'background 0.15s, transform 0.15s',\n transform: panelOpen ? 'rotate(45deg)' : 'none',\n padding: 0,\n }}\n >\n +\n </button>\n </div>\n );\n}\n","import React, { useCallback, useEffect, useRef, useState } from 'react';\n\nconst WIDGET_CONTAINER_ID = 'llm-ui-feedback-root';\n\ninterface Rect {\n x: number;\n y: number;\n width: number;\n height: number;\n}\n\ninterface PickOverlayProps {\n onPick: (rect: Rect, elements: Element[]) => void;\n onCancel: () => void;\n}\n\nfunction getElementsBeneathRect(rect: Rect): Element[] {\n const container = document.getElementById(WIDGET_CONTAINER_ID);\n if (container) container.style.display = 'none';\n\n const seen = new Set<Element>();\n const step = 8;\n\n for (let x = rect.x; x <= rect.x + rect.width; x += step) {\n for (let y = rect.y; y <= rect.y + rect.height; y += step) {\n const el = document.elementFromPoint(x, y);\n if (el && !seen.has(el)) seen.add(el);\n }\n }\n\n for (const [x, y] of [\n [rect.x, rect.y],\n [rect.x + rect.width, rect.y],\n [rect.x, rect.y + rect.height],\n [rect.x + rect.width, rect.y + rect.height],\n [rect.x + rect.width / 2, rect.y + rect.height / 2],\n ]) {\n const el = document.elementFromPoint(x, y);\n if (el && !seen.has(el)) seen.add(el);\n }\n\n if (container) container.style.display = '';\n return Array.from(seen).filter((el) => !container?.contains(el));\n}\n\nfunction getElementAtPoint(x: number, y: number): Element | null {\n const container = document.getElementById(WIDGET_CONTAINER_ID);\n if (container) container.style.display = 'none';\n const el = document.elementFromPoint(x, y);\n if (container) container.style.display = '';\n if (el && container?.contains(el)) return null;\n return el;\n}\n\nconst DRAG_THRESHOLD = 10;\n\nexport function PickOverlay({ onPick, onCancel }: PickOverlayProps) {\n // Use refs for drag state so event handlers always see current values\n const activeRef = useRef(false);\n const startRef = useRef<{ x: number; y: number } | null>(null);\n const isDragRef = useRef(false);\n\n // State only for rendering (hover highlight and drag rectangle)\n const [hoverRect, setHoverRect] = useState<Rect | null>(null);\n const [selRect, setSelRect] = useState<{ left: number; top: number; width: number; height: number } | null>(null);\n\n const onPickRef = useRef(onPick);\n onPickRef.current = onPick;\n const onCancelRef = useRef(onCancel);\n onCancelRef.current = onCancel;\n\n useEffect(() => {\n function handleMouseMove(e: MouseEvent) {\n if (activeRef.current && startRef.current) {\n // Dragging\n const dx = Math.abs(e.clientX - startRef.current.x);\n const dy = Math.abs(e.clientY - startRef.current.y);\n if (dx >= DRAG_THRESHOLD || dy >= DRAG_THRESHOLD) {\n isDragRef.current = true;\n }\n\n if (isDragRef.current) {\n setHoverRect(null);\n setSelRect({\n left: Math.min(startRef.current.x, e.clientX),\n top: Math.min(startRef.current.y, e.clientY),\n width: Math.abs(e.clientX - startRef.current.x),\n height: Math.abs(e.clientY - startRef.current.y),\n });\n }\n e.preventDefault();\n } else {\n // Hover — highlight element under cursor\n const el = getElementAtPoint(e.clientX, e.clientY);\n if (el) {\n const r = el.getBoundingClientRect();\n setHoverRect({ x: r.left, y: r.top, width: r.width, height: r.height });\n } else {\n setHoverRect(null);\n }\n }\n }\n\n function handleMouseDown(e: MouseEvent) {\n if (e.button !== 0) return;\n e.preventDefault();\n e.stopPropagation();\n startRef.current = { x: e.clientX, y: e.clientY };\n isDragRef.current = false;\n activeRef.current = true;\n }\n\n function handleMouseUp(e: MouseEvent) {\n if (!activeRef.current || !startRef.current) return;\n e.preventDefault();\n e.stopPropagation();\n\n const start = startRef.current;\n activeRef.current = false;\n startRef.current = null;\n setSelRect(null);\n setHoverRect(null);\n\n if (!isDragRef.current) {\n // Click — select single element\n const el = getElementAtPoint(e.clientX, e.clientY);\n if (el) {\n const r = el.getBoundingClientRect();\n onPickRef.current({ x: r.left, y: r.top, width: r.width, height: r.height }, [el]);\n }\n return;\n }\n\n // Drag — select area\n const x = Math.min(start.x, e.clientX);\n const y = Math.min(start.y, e.clientY);\n const width = Math.abs(e.clientX - start.x);\n const height = Math.abs(e.clientY - start.y);\n\n const rect = { x, y, width, height };\n const elements = getElementsBeneathRect(rect);\n onPickRef.current(rect, elements);\n }\n\n function handleKeyDown(e: KeyboardEvent) {\n if (e.key === 'Escape') {\n activeRef.current = false;\n startRef.current = null;\n setSelRect(null);\n setHoverRect(null);\n onCancelRef.current();\n }\n }\n\n document.addEventListener('mousedown', handleMouseDown, true);\n document.addEventListener('mousemove', handleMouseMove, true);\n document.addEventListener('mouseup', handleMouseUp, true);\n document.addEventListener('keydown', handleKeyDown, true);\n\n return () => {\n document.removeEventListener('mousedown', handleMouseDown, true);\n document.removeEventListener('mousemove', handleMouseMove, true);\n document.removeEventListener('mouseup', handleMouseUp, true);\n document.removeEventListener('keydown', handleKeyDown, true);\n };\n }, []);\n\n return (\n <>\n <div\n style={{\n position: 'fixed',\n top: 0,\n left: 0,\n right: 0,\n bottom: 0,\n zIndex: 99997,\n cursor: 'crosshair',\n }}\n />\n\n <div\n style={{\n position: 'fixed',\n top: 0,\n left: 0,\n right: 0,\n zIndex: 99998,\n background: 'rgba(59, 130, 246, 0.08)',\n padding: '8px 16px',\n textAlign: 'center',\n fontSize: 14,\n color: '#1e40af',\n fontFamily: 'system-ui, sans-serif',\n pointerEvents: 'none',\n }}\n >\n Click an element or drag to select an area. Press <strong>Esc</strong> to cancel.\n </div>\n\n {/* Hover highlight */}\n {hoverRect && (\n <div\n style={{\n position: 'fixed',\n left: hoverRect.x,\n top: hoverRect.y,\n width: hoverRect.width,\n height: hoverRect.height,\n border: '2px solid #3b82f6',\n background: 'rgba(59, 130, 246, 0.08)',\n zIndex: 99998,\n pointerEvents: 'none',\n borderRadius: 2,\n transition: 'all 0.1s ease-out',\n }}\n />\n )}\n\n {/* Drag selection rectangle */}\n {selRect && (\n <div\n style={{\n position: 'fixed',\n left: selRect.left,\n top: selRect.top,\n width: selRect.width,\n height: selRect.height,\n border: '2px dashed #3b82f6',\n background: 'rgba(59, 130, 246, 0.1)',\n zIndex: 99998,\n pointerEvents: 'none',\n borderRadius: 2,\n }}\n />\n )}\n </>\n );\n}\n","import React, { useState } from 'react';\nimport type { Draft, WidgetPosition } from '../types';\nimport type { ApiClient } from '../api/client';\nimport type { UserInfo } from '../hooks/useSession';\nimport { DraftItem } from './DraftItem';\n\ninterface SidePanelProps {\n position: WidgetPosition;\n drafts: Draft[];\n selectedDraftIds: Set<string>;\n onToggleSelect: (id: string) => void;\n onSelectAll: (selected: boolean) => void;\n onUpdateDraft: (id: string, comment: string) => void;\n onDeleteDraft: (id: string) => void;\n onSubmit: () => void;\n onClose: () => void;\n api: ApiClient;\n user: UserInfo | null;\n}\n\nexport function SidePanel({\n position,\n drafts,\n selectedDraftIds,\n onToggleSelect,\n onSelectAll,\n onUpdateDraft,\n onDeleteDraft,\n onSubmit,\n onClose,\n api,\n user,\n}: SidePanelProps) {\n const isRight = position.includes('right');\n const allSelected = drafts.length > 0 && selectedDraftIds.size === drafts.length;\n const [screenshotUrls, setScreenshotUrls] = useState<Record<string, string>>({});\n const [previewUrl, setPreviewUrl] = useState<string | null>(null);\n\n // Fetch screenshot URLs for drafts that have them\n React.useEffect(() => {\n const draftsWithScreenshots = drafts.filter((d) => d.screenshotKey && !screenshotUrls[d.id]);\n draftsWithScreenshots.forEach((draft) => {\n api.getScreenshotUrl(draft.id).then((url) => {\n setScreenshotUrls((prev) => ({ ...prev, [draft.id]: url }));\n }).catch(() => {});\n });\n }, [drafts, api]);\n\n const handlePreviewScreenshot = (draftId: string) => {\n const url = screenshotUrls[draftId];\n if (url) setPreviewUrl(url);\n };\n\n return (\n <div\n style={{\n position: 'fixed',\n top: 0,\n [isRight ? 'right' : 'left']: 0,\n width: 360,\n maxWidth: '100vw',\n height: '100vh',\n background: '#fff',\n boxShadow: isRight ? '-4px 0 16px rgba(0,0,0,0.1)' : '4px 0 16px rgba(0,0,0,0.1)',\n zIndex: 99998,\n display: 'flex',\n flexDirection: 'column',\n fontFamily: 'system-ui, sans-serif',\n }}\n >\n {/* Header */}\n <div\n style={{\n padding: '16px 16px 12px',\n borderBottom: '1px solid #e5e7eb',\n }}\n >\n <div style={{ display: 'flex', justifyContent: 'space-between', alignItems: 'center' }}>\n <h3 style={{ margin: 0, fontSize: 15, fontWeight: 600 }}>Feedback Session</h3>\n <button\n onClick={onClose}\n style={{\n background: 'none',\n border: 'none',\n fontSize: 18,\n cursor: 'pointer',\n color: '#6b7280',\n padding: '0 4px',\n }}\n >\n x\n </button>\n </div>\n {user && (\n <div style={{ marginTop: 6, fontSize: 12, color: '#6b7280', lineHeight: 1.4 }}>\n <div style={{ fontWeight: 500, color: '#374151' }}>{user.name}</div>\n <div>{user.email}</div>\n </div>\n )}\n </div>\n\n {/* Draft List */}\n <div style={{ flex: 1, overflow: 'auto' }}>\n {drafts.length === 0 ? (\n <div style={{ padding: 24, textAlign: 'center', color: '#9ca3af', fontSize: 13 }}>\n No drafts yet. Pick an element to start.\n </div>\n ) : (\n drafts.map((draft) => (\n <DraftItem\n key={draft.id}\n draft={draft}\n selected={selectedDraftIds.has(draft.id)}\n screenshotUrl={screenshotUrls[draft.id] || null}\n onToggleSelect={onToggleSelect}\n onUpdate={onUpdateDraft}\n onDelete={onDeleteDraft}\n onPreviewScreenshot={handlePreviewScreenshot}\n />\n ))\n )}\n </div>\n\n {/* Footer */}\n {drafts.length > 0 && (\n <div\n style={{\n padding: '12px 16px',\n borderTop: '1px solid #e5e7eb',\n display: 'flex',\n alignItems: 'center',\n gap: 12,\n }}\n >\n <label style={{ display: 'flex', alignItems: 'center', gap: 6, fontSize: 13, cursor: 'pointer', whiteSpace: 'nowrap' }}>\n <input\n type=\"checkbox\"\n checked={allSelected}\n onChange={(e) => onSelectAll(e.target.checked)}\n />\n Select All\n </label>\n <button\n onClick={onSubmit}\n disabled={selectedDraftIds.size === 0}\n style={{\n flex: 1,\n padding: '8px 12px',\n borderRadius: 6,\n border: 'none',\n background: selectedDraftIds.size === 0 ? '#93c5fd' : '#3b82f6',\n color: '#fff',\n fontSize: 13,\n fontWeight: 500,\n cursor: selectedDraftIds.size === 0 ? 'default' : 'pointer',\n }}\n >\n Submit Feedback ({selectedDraftIds.size})\n </button>\n </div>\n )}\n\n {/* Screenshot Preview Modal */}\n {previewUrl && (\n <div\n onClick={() => setPreviewUrl(null)}\n style={{\n position: 'fixed',\n top: 0,\n left: 0,\n right: 0,\n bottom: 0,\n background: 'rgba(0,0,0,0.6)',\n zIndex: 99999,\n display: 'flex',\n alignItems: 'center',\n justifyContent: 'center',\n }}\n >\n <div\n onClick={(e) => e.stopPropagation()}\n style={{\n background: '#fff',\n borderRadius: 8,\n padding: 8,\n maxWidth: '90vw',\n maxHeight: '90vh',\n position: 'relative',\n }}\n >\n <button\n onClick={() => setPreviewUrl(null)}\n style={{\n position: 'absolute',\n top: 4,\n right: 8,\n background: 'none',\n border: 'none',\n fontSize: 18,\n cursor: 'pointer',\n color: '#6b7280',\n zIndex: 1,\n }}\n >\n x\n </button>\n <img\n src={previewUrl}\n alt=\"Screenshot preview\"\n style={{ maxWidth: '85vw', maxHeight: '85vh', display: 'block', borderRadius: 4 }}\n />\n </div>\n </div>\n )}\n </div>\n );\n}\n","import React, { useState } from 'react';\nimport type { Draft } from '../types';\n\ninterface DraftItemProps {\n draft: Draft;\n selected: boolean;\n screenshotUrl: string | null;\n onToggleSelect: (id: string) => void;\n onUpdate: (id: string, comment: string) => void;\n onDelete: (id: string) => void;\n onPreviewScreenshot: (draftId: string) => void;\n}\n\nexport function DraftItem({ draft, selected, screenshotUrl, onToggleSelect, onUpdate, onDelete, onPreviewScreenshot }: DraftItemProps) {\n const [editing, setEditing] = useState(false);\n const [editComment, setEditComment] = useState(draft.comment);\n const [confirmDelete, setConfirmDelete] = useState(false);\n\n const handleSaveEdit = () => {\n if (editComment.trim()) {\n onUpdate(draft.id, editComment.trim());\n }\n setEditing(false);\n };\n\n const truncatedPath = draft.componentPath.length > 50\n ? '...' + draft.componentPath.slice(-47)\n : draft.componentPath;\n\n return (\n <div\n style={{\n padding: '10px 12px',\n borderBottom: '1px solid #e5e7eb',\n fontSize: 13,\n fontFamily: 'system-ui, sans-serif',\n }}\n >\n <div style={{ display: 'flex', alignItems: 'flex-start', gap: 8 }}>\n <input\n type=\"checkbox\"\n checked={selected}\n onChange={() => onToggleSelect(draft.id)}\n style={{ marginTop: 3, cursor: 'pointer' }}\n />\n <div style={{ flex: 1, minWidth: 0 }}>\n <div style={{ color: '#6b7280', fontSize: 11, marginBottom: 2 }} title={draft.componentPath}>\n {truncatedPath}\n </div>\n <div style={{ color: '#9ca3af', fontSize: 11, marginBottom: 4 }} title={draft.url}>\n {draft.url.length > 60 ? draft.url.slice(0, 60) + '...' : draft.url}\n </div>\n\n {screenshotUrl && (\n <img\n src={screenshotUrl}\n alt=\"Screenshot\"\n onClick={() => onPreviewScreenshot(draft.id)}\n style={{\n width: '100%',\n maxHeight: 160,\n objectFit: 'cover',\n borderRadius: 4,\n border: '1px solid #e5e7eb',\n cursor: 'pointer',\n marginBottom: 6,\n }}\n title=\"Click to enlarge\"\n />\n )}\n\n {editing ? (\n <div>\n <textarea\n value={editComment}\n onChange={(e) => setEditComment(e.target.value)}\n autoFocus\n style={{\n width: '100%',\n minHeight: 48,\n padding: 6,\n borderRadius: 4,\n border: '1px solid #d1d5db',\n fontSize: 13,\n resize: 'vertical',\n boxSizing: 'border-box',\n }}\n />\n <div style={{ display: 'flex', gap: 4, marginTop: 4 }}>\n <button onClick={handleSaveEdit} style={smallBtn('#3b82f6', '#fff')}>Save</button>\n <button onClick={() => { setEditing(false); setEditComment(draft.comment); }} style={smallBtn('#f3f4f6', '#374151')}>Cancel</button>\n </div>\n </div>\n ) : (\n <div\n onClick={() => setEditing(true)}\n style={{ cursor: 'pointer', color: '#1f2937', lineHeight: 1.4 }}\n title=\"Click to edit\"\n >\n {draft.comment}\n </div>\n )}\n </div>\n\n <div style={{ flexShrink: 0 }}>\n {confirmDelete ? (\n <div style={{ display: 'flex', gap: 4, fontSize: 12 }}>\n <button onClick={() => onDelete(draft.id)} style={smallBtn('#ef4444', '#fff')}>Yes</button>\n <button onClick={() => setConfirmDelete(false)} style={smallBtn('#f3f4f6', '#374151')}>No</button>\n </div>\n ) : (\n <button\n onClick={() => setConfirmDelete(true)}\n style={{\n background: 'none',\n border: 'none',\n cursor: 'pointer',\n color: '#9ca3af',\n fontSize: 16,\n padding: '0 4px',\n }}\n title=\"Delete draft\"\n >\n x\n </button>\n )}\n </div>\n </div>\n </div>\n );\n}\n\nfunction smallBtn(bg: string, color: string): React.CSSProperties {\n return {\n padding: '3px 8px',\n borderRadius: 4,\n border: '1px solid #d1d5db',\n background: bg,\n color,\n fontSize: 12,\n cursor: 'pointer',\n };\n}\n","import React, { useState, useEffect } from 'react';\nimport type { CapturedContext } from '../types';\n\nconst WIDGET_CONTAINER_ID = 'llm-ui-feedback-root';\n\ninterface DraftModalProps {\n pendingContext: { context: CapturedContext; screenshot: string | null };\n addingDraft: boolean;\n onAdd: (comment: string) => void;\n onCancel: () => void;\n}\n\nexport function DraftModal({ pendingContext, addingDraft, onAdd, onCancel }: DraftModalProps) {\n const [comment, setComment] = useState('');\n\n // Disable focus traps from host app modals (e.g. MUI Dialog) while our modal is open\n useEffect(() => {\n const container = document.getElementById(WIDGET_CONTAINER_ID);\n const inerted: Element[] = [];\n\n // Set inert on all top-level body children except the widget container\n for (const child of Array.from(document.body.children)) {\n if (child === container || child.id === WIDGET_CONTAINER_ID) continue;\n if (!child.hasAttribute('inert')) {\n child.setAttribute('inert', '');\n inerted.push(child);\n }\n }\n\n return () => {\n for (const el of inerted) {\n el.removeAttribute('inert');\n }\n };\n }, []);\n\n const handleAdd = () => {\n if (comment.trim() && !addingDraft) {\n onAdd(comment.trim());\n }\n };\n\n const { context, screenshot } = pendingContext;\n\n return (\n <div\n style={{\n position: 'fixed',\n inset: 0,\n zIndex: 99999,\n display: 'flex',\n alignItems: 'center',\n justifyContent: 'center',\n background: 'rgba(0,0,0,0.4)',\n fontFamily: 'system-ui, sans-serif',\n }}\n onClick={(e) => {\n if (e.target === e.currentTarget && !addingDraft) onCancel();\n }}\n >\n <div\n style={{\n background: '#fff',\n borderRadius: 12,\n padding: 24,\n width: 480,\n maxWidth: '90vw',\n maxHeight: '85vh',\n overflow: 'auto',\n boxShadow: '0 8px 32px rgba(0,0,0,0.2)',\n }}\n >\n <h3 style={{ margin: '0 0 16px', fontSize: 16 }}>New Feedback</h3>\n\n <div style={{ fontSize: 12, color: '#6b7280', marginBottom: 12 }}>\n <div><strong>Component:</strong> {context.componentPath}</div>\n <div><strong>Path:</strong> {context.urlPath}</div>\n {context.elementText && (\n <div><strong>Element:</strong> &quot;{context.elementText.slice(0, 80)}&quot;</div>\n )}\n </div>\n\n {screenshot && (\n <img\n src={screenshot}\n alt=\"Screenshot\"\n style={{\n width: '100%',\n borderRadius: 8,\n border: '1px solid #e5e7eb',\n marginBottom: 12,\n maxHeight: 180,\n objectFit: 'cover',\n }}\n />\n )}\n\n <textarea\n value={comment}\n onChange={(e) => setComment(e.target.value)}\n placeholder=\"Describe the issue or suggestion...\"\n autoFocus\n onKeyDown={(e) => {\n if (e.key === 'Enter' && (e.metaKey || e.ctrlKey)) handleAdd();\n }}\n style={{\n width: '100%',\n minHeight: 80,\n padding: 10,\n borderRadius: 8,\n border: '1px solid #d1d5db',\n fontSize: 14,\n resize: 'vertical',\n boxSizing: 'border-box',\n }}\n />\n\n <div style={{ display: 'flex', gap: 8, marginTop: 16, justifyContent: 'flex-end' }}>\n <button\n onClick={onCancel}\n disabled={addingDraft}\n style={{\n padding: '8px 16px',\n borderRadius: 6,\n border: '1px solid #d1d5db',\n background: '#f3f4f6',\n color: '#374151',\n fontSize: 13,\n cursor: 'pointer',\n }}\n >\n Cancel\n </button>\n <button\n onClick={handleAdd}\n disabled={!comment.trim() || addingDraft}\n style={{\n padding: '8px 16px',\n borderRadius: 6,\n border: 'none',\n background: !comment.trim() || addingDraft ? '#93c5fd' : '#3b82f6',\n color: '#fff',\n fontSize: 13,\n cursor: !comment.trim() || addingDraft ? 'default' : 'pointer',\n }}\n >\n {addingDraft ? 'Adding...' : 'Add to Drafts'}\n </button>\n </div>\n </div>\n </div>\n );\n}\n","import React, { useState } from 'react';\n\ninterface SubmitModalProps {\n count: number;\n onSubmit: (title: string) => void;\n onCancel: () => void;\n submitting: boolean;\n}\n\nexport function SubmitModal({ count, onSubmit, onCancel, submitting }: SubmitModalProps) {\n const [title, setTitle] = useState('');\n\n const handleSubmit = () => {\n if (title.trim() && !submitting) {\n onSubmit(title.trim());\n }\n };\n\n return (\n <div\n style={{\n position: 'fixed',\n inset: 0,\n zIndex: 99999,\n display: 'flex',\n alignItems: 'center',\n justifyContent: 'center',\n background: 'rgba(0,0,0,0.4)',\n fontFamily: 'system-ui, sans-serif',\n }}\n onClick={(e) => {\n if (e.target === e.currentTarget && !submitting) onCancel();\n }}\n >\n <div\n style={{\n background: '#fff',\n borderRadius: 12,\n padding: 24,\n width: 400,\n maxWidth: '90vw',\n boxShadow: '0 8px 32px rgba(0,0,0,0.2)',\n }}\n >\n <h3 style={{ margin: '0 0 16px', fontSize: 16 }}>Submit Feedback</h3>\n <p style={{ margin: '0 0 12px', fontSize: 14, color: '#6b7280' }}>\n {count} item{count !== 1 ? 's' : ''} selected. Name this feedback session:\n </p>\n <input\n type=\"text\"\n value={title}\n onChange={(e) => setTitle(e.target.value)}\n placeholder=\"e.g. Homepage redesign feedback\"\n autoFocus\n onKeyDown={(e) => { if (e.key === 'Enter') handleSubmit(); }}\n style={{\n width: '100%',\n padding: 10,\n borderRadius: 8,\n border: '1px solid #d1d5db',\n fontSize: 14,\n boxSizing: 'border-box',\n }}\n />\n <div style={{ display: 'flex', gap: 8, marginTop: 16, justifyContent: 'flex-end' }}>\n <button\n onClick={onCancel}\n disabled={submitting}\n style={{\n padding: '8px 16px',\n borderRadius: 6,\n border: '1px solid #d1d5db',\n background: '#f3f4f6',\n color: '#374151',\n fontSize: 13,\n cursor: 'pointer',\n }}\n >\n Cancel\n </button>\n <button\n onClick={handleSubmit}\n disabled={!title.trim() || submitting}\n style={{\n padding: '8px 16px',\n borderRadius: 6,\n border: 'none',\n background: !title.trim() || submitting ? '#93c5fd' : '#3b82f6',\n color: '#fff',\n fontSize: 13,\n cursor: !title.trim() || submitting ? 'default' : 'pointer',\n }}\n >\n {submitting ? 'Submitting...' : 'Submit'}\n </button>\n </div>\n </div>\n </div>\n );\n}\n","import { ComponentInfo } from '../types';\n\nlet minificationWarned = false;\n\nfunction getFiber(el: Element): any | null {\n const key = Object.keys(el).find((k) => k.startsWith('__reactFiber$'));\n return key ? (el as any)[key] : null;\n}\n\nfunction pickShortProps(props: Record<string, unknown>): Record<string, unknown> {\n const short: Record<string, unknown> = {};\n for (const [key, value] of Object.entries(props)) {\n if (key === 'children') continue;\n if (typeof value === 'function') continue;\n if (typeof value === 'string' || typeof value === 'number' || typeof value === 'boolean') {\n short[key] = value;\n }\n }\n return short;\n}\n\nexport function getComponentPath(el: Element, maxDepth = 8): ComponentInfo[] {\n const fiber = getFiber(el);\n if (!fiber) return [];\n\n const path: ComponentInfo[] = [];\n let current = fiber;\n\n while (current && path.length < maxDepth) {\n if (typeof current.type === 'function' || typeof current.type === 'object') {\n const name =\n current.type?.displayName || current.type?.name || null;\n if (name) {\n // Detect minified names: single-char lowercase names are typical minifier output\n if (\n !minificationWarned &&\n name.length <= 2 &&\n /^[a-z]/.test(name)\n ) {\n minificationWarned = true;\n console.warn(\n '[llm-ui-feedback] Component names appear minified (e.g., \"' +\n name +\n '\"). The generated LLM prompts will lack meaningful component paths. ' +\n 'To fix, configure your bundler to preserve function names. ' +\n 'See: https://github.com/user/llm-ui-feedback/blob/main/docs/production-setup.md'\n );\n }\n path.push({\n name,\n props: pickShortProps(current.memoizedProps || {}),\n });\n }\n }\n current = current.return;\n }\n\n return path.reverse();\n}\n","import html2canvas from 'html2canvas-pro';\n\nexport interface ScreenshotRect {\n x: number;\n y: number;\n width: number;\n height: number;\n}\n\nexport async function captureScreenshot(rect: ScreenshotRect): Promise<string> {\n const fullCanvas = await html2canvas(document.body, {\n logging: false,\n useCORS: true,\n });\n\n // Convert viewport coords to document coords\n const docX = rect.x + window.scrollX;\n const docY = rect.y + window.scrollY;\n\n // html2canvas may scale the canvas vs the document — compute ratio\n const scaleX = fullCanvas.width / document.documentElement.scrollWidth;\n const scaleY = fullCanvas.height / document.documentElement.scrollHeight;\n\n const sx = Math.round(docX * scaleX);\n const sy = Math.round(docY * scaleY);\n const sw = Math.round(rect.width * scaleX);\n const sh = Math.round(rect.height * scaleY);\n\n // Crop to the selected region\n const cropped = document.createElement('canvas');\n cropped.width = sw;\n cropped.height = sh;\n const ctx = cropped.getContext('2d');\n if (ctx) {\n ctx.drawImage(fullCanvas, sx, sy, sw, sh, 0, 0, sw, sh);\n\n // Draw a blue border to indicate the selection\n ctx.strokeStyle = '#3b82f6';\n ctx.lineWidth = 3;\n ctx.strokeRect(1, 1, sw - 2, sh - 2);\n }\n\n return cropped.toDataURL('image/png');\n}\n","import { CapturedContext } from '../types';\n\nexport function buildPrompt(context: CapturedContext, comment: string): string {\n const propsStr = context.components\n .filter((c) => Object.keys(c.props).length > 0)\n .map((c) => ` ${c.name}: ${JSON.stringify(c.props)}`)\n .join('\\n');\n\n const lines = [\n `Page: ${context.url}`,\n `Path: ${context.urlPath}`,\n `Reported at: ${context.reportedAt}`,\n `Component: ${context.componentPath}`,\n ];\n\n if (propsStr) {\n lines.push(`Props:\\n${propsStr}`);\n }\n\n if (context.elementText) {\n lines.push(`Element text: \"${context.elementText}\"`);\n }\n\n lines.push('', `User feedback: \"${comment}\"`, '', 'Screenshot attached showing the selected region.');\n\n return lines.join('\\n');\n}\n","export function dataUrlToBlob(dataUrl: string): Blob {\n const [header, base64] = dataUrl.split(',');\n const mime = header.match(/:(.*?);/)?.[1] || 'image/png';\n const binary = atob(base64);\n const bytes = new Uint8Array(binary.length);\n for (let i = 0; i < binary.length; i++) {\n bytes[i] = binary.charCodeAt(i);\n }\n return new Blob([bytes], { type: mime });\n}\n","import { useState, useEffect, useCallback, useRef } from 'react';\n\nconst SESSION_TOKEN_KEY = 'llm_feedback_session_token';\nconst USER_KEY = 'llm_feedback_user';\n\n// Check for auth bypass flag.\n// globalThis.__FEEDBACK_AUTH_BYPASS__ works in any context (CJS/ESM).\n// Vite consumers get automatic support because Vite statically replaces\n// import.meta.env.VITE_AUTH_BYPASS at build time in the ESM bundle.\nconst AUTH_BYPASS = !!(typeof globalThis !== 'undefined' && (globalThis as any).__FEEDBACK_AUTH_BYPASS__);\n\nexport interface UserInfo {\n email: string;\n name: string;\n picture: string;\n sub: string;\n}\n\nexport interface SessionState {\n status: 'loading' | 'unauthenticated' | 'authenticated';\n user: UserInfo | null;\n signIn: () => void;\n signOut: () => void;\n}\n\nexport function getSessionToken(): string | null {\n if (AUTH_BYPASS) return 'bypass-token';\n return localStorage.getItem(SESSION_TOKEN_KEY);\n}\n\nconst BYPASS_USER: UserInfo = {\n email: 'bypass@test.local',\n name: 'Bypass User',\n picture: '',\n sub: 'bypass-user',\n};\n\nexport function useSession(apiUrl: string, clientId: string): SessionState {\n const [status, setStatus] = useState<SessionState['status']>(AUTH_BYPASS ? 'authenticated' : 'loading');\n const [user, setUser] = useState<UserInfo | null>(AUTH_BYPASS ? BYPASS_USER : null);\n const pendingAuthRef = useRef(false);\n\n // On mount: check localStorage for existing session\n useEffect(() => {\n if (AUTH_BYPASS) return;\n let cancelled = false;\n\n async function checkSession() {\n const token = localStorage.getItem(SESSION_TOKEN_KEY);\n const savedUser = localStorage.getItem(USER_KEY);\n\n if (!token || !savedUser) {\n if (!cancelled) setStatus('unauthenticated');\n return;\n }\n\n try {\n const res = await fetch(`${apiUrl}/auth/status`, {\n headers: { 'X-Session-Token': token },\n });\n const data = await res.json();\n\n if (!cancelled) {\n if (data.authenticated) {\n setUser(data.user);\n setStatus('authenticated');\n } else {\n localStorage.removeItem(SESSION_TOKEN_KEY);\n localStorage.removeItem(USER_KEY);\n setStatus('unauthenticated');\n }\n }\n } catch {\n if (!cancelled) {\n // Network error — use cached user optimistically\n try {\n setUser(JSON.parse(savedUser));\n setStatus('authenticated');\n } catch {\n setStatus('unauthenticated');\n }\n }\n }\n }\n\n checkSession();\n return () => { cancelled = true; };\n }, [apiUrl]);\n\n // Listen for postMessage from auth popup\n useEffect(() => {\n function handleMessage(event: MessageEvent) {\n if (event.data?.type !== 'feedback-auth') return;\n const { sessionToken, user: userData } = event.data;\n if (sessionToken && userData) {\n localStorage.setItem(SESSION_TOKEN_KEY, sessionToken);\n localStorage.setItem(USER_KEY, JSON.stringify(userData));\n setUser(userData);\n setStatus('authenticated');\n pendingAuthRef.current = false;\n }\n }\n\n window.addEventListener('message', handleMessage);\n return () => window.removeEventListener('message', handleMessage);\n }, []);\n\n const signIn = useCallback(() => {\n if (pendingAuthRef.current) return;\n pendingAuthRef.current = true;\n\n const loginUrl = `${apiUrl}/auth/login?clientId=${encodeURIComponent(clientId)}&origin=${encodeURIComponent(window.location.origin)}`;\n const popup = window.open(loginUrl, 'feedback-auth', 'width=500,height=600,menubar=no,toolbar=no');\n\n if (!popup) {\n // Popup blocked — can't do much, reset flag\n pendingAuthRef.current = false;\n return;\n }\n\n // Poll for popup closed (user cancelled)\n const interval = setInterval(() => {\n if (popup.closed) {\n clearInterval(interval);\n pendingAuthRef.current = false;\n }\n }, 500);\n }, [apiUrl, clientId]);\n\n const signOut = useCallback(async () => {\n const token = localStorage.getItem(SESSION_TOKEN_KEY);\n localStorage.removeItem(SESSION_TOKEN_KEY);\n localStorage.removeItem(USER_KEY);\n setUser(null);\n setStatus('unauthenticated');\n\n if (token) {\n try {\n await fetch(`${apiUrl}/auth/logout`, {\n method: 'POST',\n headers: { 'X-Session-Token': token },\n });\n } catch {\n // Best-effort logout\n }\n }\n }, [apiUrl]);\n\n return { status, user, signIn, signOut };\n}\n","import type { Draft, FeedbackGroup } from '../types';\nimport { getSessionToken } from '../hooks/useSession';\n\nexport interface DraftPayload {\n id: string;\n url: string;\n componentPath: string;\n components: { name: string; props: Record<string, unknown> }[];\n elementText: string;\n comment: string;\n prompt: string;\n screenshotKey?: string;\n}\n\nexport interface ApiClient {\n fetchDrafts(): Promise<Draft[]>;\n createDraft(draft: DraftPayload): Promise<Draft>;\n updateDraft(id: string, data: { comment: string }): Promise<Draft>;\n deleteDraft(id: string): Promise<void>;\n submitSession(data: { title: string; draftIds: string[] }): Promise<{ feedbackGroup: FeedbackGroup; entriesCreated: number }>;\n getUploadUrl(\n entryId: string,\n timestamp: string,\n ): Promise<{ uploadUrl: string; key: string }>;\n uploadScreenshot(uploadUrl: string, blob: Blob): Promise<void>;\n getScreenshotUrl(draftId: string): Promise<string>;\n}\n\nexport function createApiClient(apiUrl: string, clientId: string): ApiClient {\n async function apiFetch(path: string, options: RequestInit = {}) {\n const token = getSessionToken();\n const res = await fetch(`${apiUrl}${path}`, {\n ...options,\n headers: {\n 'Content-Type': 'application/json',\n ...(token ? { 'X-Session-Token': token } : {}),\n 'X-Client-Id': clientId,\n ...(options.headers as Record<string, string> | undefined),\n },\n });\n if (!res.ok) {\n const body = await res.json().catch(() => ({}));\n throw new Error(\n (body as Record<string, string>).error ||\n `API error ${res.status}`,\n );\n }\n if (res.status === 204) return undefined;\n return res.json();\n }\n\n return {\n async fetchDrafts() {\n const data = await apiFetch('/drafts');\n return (data as { items: Draft[] }).items;\n },\n\n async createDraft(draft: DraftPayload) {\n return apiFetch('/drafts', {\n method: 'POST',\n body: JSON.stringify(draft),\n }) as Promise<Draft>;\n },\n\n async updateDraft(id: string, data: { comment: string }) {\n return apiFetch(`/drafts/${id}`, {\n method: 'PATCH',\n body: JSON.stringify(data),\n }) as Promise<Draft>;\n },\n\n async deleteDraft(id: string) {\n await apiFetch(`/drafts/${id}`, { method: 'DELETE' });\n },\n\n async submitSession(data: { title: string; draftIds: string[] }) {\n return apiFetch('/feedback-groups/submit', {\n method: 'POST',\n body: JSON.stringify(data),\n }) as Promise<{ feedbackGroup: FeedbackGroup; entriesCreated: number }>;\n },\n\n async getUploadUrl(entryId: string, timestamp: string) {\n return apiFetch('/upload-url', {\n method: 'POST',\n body: JSON.stringify({ entryId, timestamp }),\n }) as Promise<{ uploadUrl: string; key: string }>;\n },\n\n async getScreenshotUrl(draftId: string) {\n const data = await apiFetch(`/drafts/${draftId}/screenshot-url`);\n return (data as { url: string }).url;\n },\n\n async uploadScreenshot(uploadUrl: string, blob: Blob) {\n const res = await fetch(uploadUrl, {\n method: 'PUT',\n body: blob,\n headers: { 'Content-Type': 'image/png' },\n });\n if (!res.ok) throw new Error(`S3 upload failed: ${res.status}`);\n },\n };\n}\n"],"mappings":"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","names":["import_react","import_jsx_runtime","import_react","import_react","import_jsx_runtime","import_jsx_runtime","React","import_react","import_jsx_runtime","WIDGET_CONTAINER_ID","import_react","import_jsx_runtime","html2canvas","import_react","import_jsx_runtime"]}
package/dist/index.mjs CHANGED
@@ -1003,7 +1003,7 @@ function dataUrlToBlob(dataUrl) {
1003
1003
  import { useState as useState6, useEffect as useEffect3, useCallback as useCallback2, useRef as useRef2 } from "react";
1004
1004
  var SESSION_TOKEN_KEY = "llm_feedback_session_token";
1005
1005
  var USER_KEY = "llm_feedback_user";
1006
- var AUTH_BYPASS = typeof globalThis !== "undefined" && globalThis.__FEEDBACK_AUTH_BYPASS__ || typeof import.meta !== "undefined" && import.meta.env?.VITE_AUTH_BYPASS === "true";
1006
+ var AUTH_BYPASS = !!(typeof globalThis !== "undefined" && globalThis.__FEEDBACK_AUTH_BYPASS__);
1007
1007
  function getSessionToken() {
1008
1008
  if (AUTH_BYPASS) return "bypass-token";
1009
1009
  return localStorage.getItem(SESSION_TOKEN_KEY);
@@ -1178,9 +1178,6 @@ function createApiClient(apiUrl, clientId) {
1178
1178
  };
1179
1179
  }
1180
1180
 
1181
- // src/config.ts
1182
- var DEFAULT_API_URL = "https://your-lambda-function-url.lambda-url.us-east-1.on.aws";
1183
-
1184
1181
  // src/components/FeedbackWidget.tsx
1185
1182
  import { Fragment as Fragment2, jsx as jsx7, jsxs as jsxs7 } from "react/jsx-runtime";
1186
1183
  var CONTAINER_ID = "llm-ui-feedback-root";
@@ -1280,7 +1277,7 @@ function isEditableTarget(el) {
1280
1277
  }
1281
1278
  function FeedbackWidget({
1282
1279
  clientId,
1283
- apiUrl = DEFAULT_API_URL,
1280
+ apiUrl,
1284
1281
  position = "bottom-right",
1285
1282
  buttonColor = "#3b82f6",
1286
1283
  hotkey
@@ -1 +1 @@
1
- {"version":3,"sources":["../src/components/FeedbackWidget.tsx","../src/utils/color.ts","../src/components/FloatingButton.tsx","../src/components/PickOverlay.tsx","../src/components/SidePanel.tsx","../src/components/DraftItem.tsx","../src/components/DraftModal.tsx","../src/components/SubmitModal.tsx","../src/utils/fiber.ts","../src/utils/screenshot.ts","../src/utils/prompt.ts","../src/utils/blob.ts","../src/hooks/useSession.ts","../src/api/client.ts","../src/config.ts"],"sourcesContent":["import React, { useReducer, useCallback, useEffect, useMemo, useRef } from 'react';\nimport { createPortal } from 'react-dom';\nimport { FloatingButton } from './FloatingButton';\nimport { PickOverlay } from './PickOverlay';\nimport { SidePanel } from './SidePanel';\nimport { DraftModal } from './DraftModal';\nimport { SubmitModal } from './SubmitModal';\nimport { getComponentPath } from '../utils/fiber';\nimport { captureScreenshot } from '../utils/screenshot';\nimport { buildPrompt } from '../utils/prompt';\nimport { dataUrlToBlob } from '../utils/blob';\nimport { createApiClient } from '../api/client';\nimport { useSession } from '../hooks/useSession';\nimport { DEFAULT_API_URL } from '../config';\nimport { CapturedContext, Draft, WidgetPosition } from '../types';\n\nexport const CONTAINER_ID = 'llm-ui-feedback-root';\n\nfunction getOrCreateContainer(): HTMLElement {\n let el = document.getElementById(CONTAINER_ID);\n if (!el) {\n el = document.createElement('div');\n el.id = CONTAINER_ID;\n document.body.appendChild(el);\n }\n return el;\n}\n\nexport interface FeedbackWidgetProps {\n /** Tenant identifier — required. */\n clientId: string;\n /** Backend API URL. Defaults to the production Lambda Function URL. */\n apiUrl?: string;\n /** Corner position for the floating button. Default: 'bottom-right' */\n position?: WidgetPosition;\n /** Hex color for the FAB accent. Default: '#3b82f6' */\n buttonColor?: string;\n /** Keyboard shortcut to toggle the panel, e.g. 'Alt+F'. No default (opt-in only). */\n hotkey?: string;\n}\n\ninterface WidgetState {\n panelOpen: boolean;\n picking: boolean;\n pendingContext: { context: CapturedContext; screenshot: string | null } | null;\n drafts: Draft[];\n selectedDraftIds: Set<string>;\n submitModalOpen: boolean;\n addingDraft: boolean;\n submitting: boolean;\n}\n\ntype WidgetAction =\n | { type: 'TOGGLE_PANEL' }\n | { type: 'OPEN_PANEL' }\n | { type: 'CLOSE_PANEL' }\n | { type: 'START_PICKING' }\n | { type: 'CANCEL_PICKING' }\n | { type: 'CANCEL_DRAFT_MODAL' }\n | { type: 'ELEMENT_PICKED'; context: CapturedContext; screenshot: string | null }\n | { type: 'SET_ADDING_DRAFT'; adding: boolean }\n | { type: 'DRAFT_ADDED'; draft: Draft }\n | { type: 'SET_DRAFTS'; drafts: Draft[] }\n | { type: 'DRAFT_UPDATED'; id: string; comment: string }\n | { type: 'DRAFT_DELETED'; id: string }\n | { type: 'TOGGLE_SELECT'; id: string }\n | { type: 'SELECT_ALL'; selected: boolean }\n | { type: 'OPEN_SUBMIT_MODAL' }\n | { type: 'CLOSE_SUBMIT_MODAL' }\n | { type: 'SET_SUBMITTING'; submitting: boolean }\n | { type: 'SUBMIT_COMPLETE'; submittedIds: string[] };\n\nconst initialState: WidgetState = {\n panelOpen: false,\n picking: false,\n pendingContext: null,\n drafts: [],\n selectedDraftIds: new Set(),\n submitModalOpen: false,\n addingDraft: false,\n submitting: false,\n};\n\nfunction widgetReducer(state: WidgetState, action: WidgetAction): WidgetState {\n switch (action.type) {\n case 'TOGGLE_PANEL':\n return state.panelOpen\n ? { ...state, panelOpen: false, picking: false, pendingContext: null }\n : { ...state, panelOpen: true };\n case 'OPEN_PANEL':\n return { ...state, panelOpen: true };\n case 'CLOSE_PANEL':\n return { ...state, panelOpen: false, picking: false, pendingContext: null };\n case 'START_PICKING':\n return { ...state, picking: true };\n case 'CANCEL_PICKING':\n return { ...state, picking: false };\n case 'CANCEL_DRAFT_MODAL':\n return { ...state, pendingContext: null, addingDraft: false };\n case 'ELEMENT_PICKED':\n return { ...state, picking: false, pendingContext: { context: action.context, screenshot: action.screenshot } };\n case 'SET_ADDING_DRAFT':\n return { ...state, addingDraft: action.adding };\n case 'DRAFT_ADDED':\n return { ...state, pendingContext: null, addingDraft: false, drafts: [action.draft, ...state.drafts] };\n case 'SET_DRAFTS':\n return { ...state, drafts: action.drafts };\n case 'DRAFT_UPDATED':\n return { ...state, drafts: state.drafts.map((d) => d.id === action.id ? { ...d, comment: action.comment } : d) };\n case 'DRAFT_DELETED': {\n const next = new Set(state.selectedDraftIds);\n next.delete(action.id);\n return { ...state, drafts: state.drafts.filter((d) => d.id !== action.id), selectedDraftIds: next };\n }\n case 'TOGGLE_SELECT': {\n const next = new Set(state.selectedDraftIds);\n if (next.has(action.id)) next.delete(action.id);\n else next.add(action.id);\n return { ...state, selectedDraftIds: next };\n }\n case 'SELECT_ALL':\n return { ...state, selectedDraftIds: action.selected ? new Set(state.drafts.map((d) => d.id)) : new Set() };\n case 'OPEN_SUBMIT_MODAL':\n return { ...state, submitModalOpen: true };\n case 'CLOSE_SUBMIT_MODAL':\n return { ...state, submitModalOpen: false };\n case 'SET_SUBMITTING':\n return { ...state, submitting: action.submitting };\n case 'SUBMIT_COMPLETE': {\n const submitted = new Set(action.submittedIds);\n return {\n ...state,\n submitting: false,\n submitModalOpen: false,\n drafts: state.drafts.filter((d) => !submitted.has(d.id)),\n selectedDraftIds: new Set(),\n };\n }\n default:\n return state;\n }\n}\n\nfunction parseHotkey(hotkey: string) {\n const parts = hotkey.split('+').map((p) => p.trim().toLowerCase());\n const key = parts.pop()!;\n return {\n key,\n ctrl: parts.includes('ctrl'),\n alt: parts.includes('alt'),\n shift: parts.includes('shift'),\n meta: parts.includes('meta'),\n };\n}\n\nfunction isEditableTarget(el: Element | null): boolean {\n if (!el) return false;\n const tag = el.tagName;\n if (tag === 'INPUT' || tag === 'TEXTAREA' || tag === 'SELECT') return true;\n if ((el as HTMLElement).isContentEditable) return true;\n return false;\n}\n\nexport function FeedbackWidget({\n clientId,\n apiUrl = DEFAULT_API_URL,\n position = 'bottom-right',\n buttonColor = '#3b82f6',\n hotkey,\n}: FeedbackWidgetProps) {\n const session = useSession(apiUrl, clientId);\n const [state, dispatch] = useReducer(widgetReducer, initialState);\n const pendingOpenRef = useRef(false);\n\n const api = useMemo(\n () => createApiClient(apiUrl, clientId),\n [apiUrl, clientId],\n );\n\n // Auto-open panel after successful auth\n useEffect(() => {\n if (session.status === 'authenticated' && pendingOpenRef.current) {\n pendingOpenRef.current = false;\n dispatch({ type: 'OPEN_PANEL' });\n }\n }, [session.status]);\n\n // Fetch drafts on auth and when panel opens\n useEffect(() => {\n if (session.status === 'authenticated') {\n api.fetchDrafts().then((drafts) => {\n dispatch({ type: 'SET_DRAFTS', drafts });\n }).catch(() => {\n // silently fail\n });\n }\n }, [state.panelOpen, session.status, api]);\n\n // Hotkey listener\n useEffect(() => {\n if (!hotkey) return;\n const parsed = parseHotkey(hotkey);\n\n function handler(e: KeyboardEvent) {\n if (isEditableTarget(document.activeElement)) return;\n if (\n e.key.toLowerCase() === parsed.key &&\n e.ctrlKey === parsed.ctrl &&\n e.altKey === parsed.alt &&\n e.shiftKey === parsed.shift &&\n e.metaKey === parsed.meta\n ) {\n e.preventDefault();\n dispatch({ type: 'TOGGLE_PANEL' });\n }\n }\n\n window.addEventListener('keydown', handler);\n return () => window.removeEventListener('keydown', handler);\n }, [hotkey]);\n\n const handlePickClick = useCallback(() => {\n if (session.status === 'unauthenticated') {\n pendingOpenRef.current = true;\n session.signIn();\n return;\n }\n dispatch({ type: 'START_PICKING' });\n }, [session]);\n\n const handlePanelToggle = useCallback(() => {\n if (session.status === 'unauthenticated') {\n pendingOpenRef.current = true;\n session.signIn();\n return;\n }\n dispatch({ type: 'TOGGLE_PANEL' });\n }, [session]);\n\n const handlePick = useCallback(async (rect: { x: number; y: number; width: number; height: number }, elements: Element[]) => {\n // Collect unique components from all elements in the selection\n const seenNames = new Set<string>();\n const allComponents: { name: string; props: Record<string, unknown> }[] = [];\n for (const el of elements) {\n for (const comp of getComponentPath(el)) {\n if (!seenNames.has(comp.name)) {\n seenNames.add(comp.name);\n allComponents.push(comp);\n }\n }\n }\n\n const componentPath = allComponents.map((c) => c.name).join(', ') || '(no React component found)';\n\n // Gather text from selected elements\n const textParts = new Set<string>();\n for (const el of elements) {\n const raw = ((el as HTMLElement).innerText || el.textContent || '').trim();\n if (raw) textParts.add(raw);\n }\n const combined = Array.from(textParts).join(' ').trim();\n const elementText = combined.length > 200 ? combined.slice(0, 200) + '...' : combined;\n\n const centerX = rect.x + rect.width / 2;\n const centerY = rect.y + rect.height / 2;\n\n const context: CapturedContext = {\n url: window.location.href,\n urlPath: window.location.pathname,\n reportedAt: new Date().toISOString(),\n componentPath,\n components: allComponents,\n elementText,\n clickX: centerX,\n clickY: centerY,\n };\n\n // Only capture screenshot for drag selections, not single-element clicks\n const isDrag = rect.width > 20 && rect.height > 20;\n let screenshot: string | null = null;\n if (isDrag) {\n try {\n screenshot = await captureScreenshot(rect);\n } catch {\n // Screenshot failed — continue without it\n }\n }\n\n dispatch({ type: 'ELEMENT_PICKED', context, screenshot });\n }, []);\n\n const handleCancelPicking = useCallback(() => {\n dispatch({ type: 'CANCEL_PICKING' });\n }, []);\n\n const handleAddDraft = useCallback(async (comment: string) => {\n if (!state.pendingContext) return;\n dispatch({ type: 'SET_ADDING_DRAFT', adding: true });\n\n const { context, screenshot } = state.pendingContext;\n const entryId = `f_${Date.now()}`;\n const timestamp = new Date().toISOString();\n let screenshotKey: string | undefined;\n\n // Upload screenshot\n if (screenshot) {\n const blob = dataUrlToBlob(screenshot);\n try {\n const { uploadUrl, key } = await api.getUploadUrl(entryId, timestamp);\n await api.uploadScreenshot(uploadUrl, blob);\n screenshotKey = key;\n } catch {\n // continue without screenshot\n }\n }\n\n try {\n const draft = await api.createDraft({\n id: entryId,\n url: context.url,\n componentPath: context.componentPath,\n components: context.components,\n elementText: context.elementText,\n comment,\n prompt: buildPrompt(context, comment),\n ...(screenshotKey ? { screenshotKey } : {}),\n });\n dispatch({ type: 'DRAFT_ADDED', draft });\n } catch {\n dispatch({ type: 'SET_ADDING_DRAFT', adding: false });\n }\n }, [state.pendingContext, api]);\n\n const handleUpdateDraft = useCallback(async (id: string, comment: string) => {\n dispatch({ type: 'DRAFT_UPDATED', id, comment });\n try {\n await api.updateDraft(id, { comment });\n } catch {\n // revert on error — refetch\n api.fetchDrafts().then((drafts) => dispatch({ type: 'SET_DRAFTS', drafts })).catch(() => {});\n }\n }, [api]);\n\n const handleDeleteDraft = useCallback(async (id: string) => {\n dispatch({ type: 'DRAFT_DELETED', id });\n try {\n await api.deleteDraft(id);\n } catch {\n // refetch on error\n api.fetchDrafts().then((drafts) => dispatch({ type: 'SET_DRAFTS', drafts })).catch(() => {});\n }\n }, [api]);\n\n const handleSubmit = useCallback(async (title: string) => {\n dispatch({ type: 'SET_SUBMITTING', submitting: true });\n const draftIds = Array.from(state.selectedDraftIds);\n try {\n await api.submitSession({ title, draftIds });\n dispatch({ type: 'SUBMIT_COMPLETE', submittedIds: draftIds });\n } catch {\n dispatch({ type: 'SET_SUBMITTING', submitting: false });\n }\n }, [state.selectedDraftIds, api]);\n\n // Don't render while checking auth status\n if (session.status === 'loading') return null;\n\n return createPortal(\n <>\n <FloatingButton\n onPickClick={handlePickClick}\n onPanelToggle={handlePanelToggle}\n draftCount={state.drafts.length}\n panelOpen={state.panelOpen}\n position={position}\n buttonColor={buttonColor}\n />\n {state.picking && <PickOverlay onPick={handlePick} onCancel={handleCancelPicking} />}\n {state.panelOpen && (\n <SidePanel\n position={position}\n drafts={state.drafts}\n selectedDraftIds={state.selectedDraftIds}\n onToggleSelect={(id) => dispatch({ type: 'TOGGLE_SELECT', id })}\n onSelectAll={(selected) => dispatch({ type: 'SELECT_ALL', selected })}\n onUpdateDraft={handleUpdateDraft}\n onDeleteDraft={handleDeleteDraft}\n onSubmit={() => dispatch({ type: 'OPEN_SUBMIT_MODAL' })}\n onClose={() => dispatch({ type: 'CLOSE_PANEL' })}\n api={api}\n user={session.user}\n />\n )}\n {state.pendingContext && !state.picking && (\n <DraftModal\n pendingContext={state.pendingContext}\n addingDraft={state.addingDraft}\n onAdd={handleAddDraft}\n onCancel={() => dispatch({ type: 'CANCEL_DRAFT_MODAL' })}\n />\n )}\n {state.submitModalOpen && (\n <SubmitModal\n count={state.selectedDraftIds.size}\n onSubmit={handleSubmit}\n onCancel={() => dispatch({ type: 'CLOSE_SUBMIT_MODAL' })}\n submitting={state.submitting}\n />\n )}\n </>,\n getOrCreateContainer()\n );\n}\n","/**\n * Compute whether to use light or dark text on a given background color.\n * Uses the WCAG relative luminance formula.\n * @param hexColor - Hex color string (e.g., '#3b82f6' or '#fff')\n * @returns '#000000' for light backgrounds, '#ffffff' for dark backgrounds\n */\nexport function getContrastColor(hexColor: string): string {\n const hex = hexColor.replace('#', '');\n // Expand 3-char hex to 6-char (e.g., #fff -> #ffffff)\n const fullHex =\n hex.length === 3\n ? hex[0] + hex[0] + hex[1] + hex[1] + hex[2] + hex[2]\n : hex;\n\n const r = parseInt(fullHex.substring(0, 2), 16) / 255;\n const g = parseInt(fullHex.substring(2, 4), 16) / 255;\n const b = parseInt(fullHex.substring(4, 6), 16) / 255;\n\n const toLinear = (c: number) =>\n c <= 0.03928 ? c / 12.92 : Math.pow((c + 0.055) / 1.055, 2.4);\n\n // Relative luminance (WCAG 2.0)\n const luminance =\n 0.2126 * toLinear(r) + 0.7152 * toLinear(g) + 0.0722 * toLinear(b);\n\n return luminance > 0.179 ? '#000000' : '#ffffff';\n}\n","import React from 'react';\nimport { WidgetPosition } from '../types';\nimport { getContrastColor } from '../utils/color';\n\ninterface FloatingButtonProps {\n onPickClick: () => void;\n onPanelToggle: () => void;\n draftCount: number;\n panelOpen: boolean;\n position: WidgetPosition;\n buttonColor: string;\n}\n\nexport function FloatingButton({ onPickClick, onPanelToggle, draftCount, panelOpen, position, buttonColor }: FloatingButtonProps) {\n const isBottom = position.includes('bottom');\n const isRight = position.includes('right');\n\n const anchor: React.CSSProperties = {\n position: 'fixed',\n [isBottom ? 'bottom' : 'top']: 24,\n [isRight ? 'right' : 'left']: 24,\n zIndex: 99999,\n display: 'flex',\n flexDirection: 'column',\n alignItems: 'center',\n gap: 8,\n };\n\n return (\n <div style={anchor}>\n {/* Badge button — draft count, only visible when drafts exist */}\n {draftCount > 0 && (\n <button\n onClick={onPanelToggle}\n aria-label={panelOpen ? 'Close drafts panel' : `Open drafts panel (${draftCount})`}\n style={{\n width: 32,\n height: 32,\n borderRadius: '50%',\n border: 'none',\n background: panelOpen ? '#ef4444' : buttonColor,\n color: panelOpen ? '#fff' : getContrastColor(buttonColor),\n fontFamily: 'system-ui, -apple-system, sans-serif',\n fontSize: 13,\n fontWeight: 700,\n lineHeight: 1,\n cursor: 'pointer',\n display: 'flex',\n alignItems: 'center',\n justifyContent: 'center',\n boxShadow: '0 2px 8px rgba(0,0,0,0.25)',\n transition: 'background 0.15s',\n padding: 0,\n }}\n >\n {draftCount}\n </button>\n )}\n\n {/* FAB — starts picking, or closes panel when open */}\n <button\n onClick={panelOpen ? onPanelToggle : onPickClick}\n aria-label={panelOpen ? 'Close panel' : 'Pick element for feedback'}\n style={{\n width: 48,\n height: 48,\n borderRadius: '50%',\n border: 'none',\n background: panelOpen ? '#ef4444' : buttonColor,\n color: panelOpen ? '#fff' : getContrastColor(buttonColor),\n fontFamily: 'system-ui, -apple-system, sans-serif',\n fontSize: 28,\n fontWeight: 300,\n lineHeight: 1,\n cursor: 'pointer',\n display: 'flex',\n alignItems: 'center',\n justifyContent: 'center',\n boxShadow: '0 2px 8px rgba(0,0,0,0.25)',\n transition: 'background 0.15s, transform 0.15s',\n transform: panelOpen ? 'rotate(45deg)' : 'none',\n padding: 0,\n }}\n >\n +\n </button>\n </div>\n );\n}\n","import React, { useCallback, useEffect, useRef, useState } from 'react';\n\nconst WIDGET_CONTAINER_ID = 'llm-ui-feedback-root';\n\ninterface Rect {\n x: number;\n y: number;\n width: number;\n height: number;\n}\n\ninterface PickOverlayProps {\n onPick: (rect: Rect, elements: Element[]) => void;\n onCancel: () => void;\n}\n\nfunction getElementsBeneathRect(rect: Rect): Element[] {\n const container = document.getElementById(WIDGET_CONTAINER_ID);\n if (container) container.style.display = 'none';\n\n const seen = new Set<Element>();\n const step = 8;\n\n for (let x = rect.x; x <= rect.x + rect.width; x += step) {\n for (let y = rect.y; y <= rect.y + rect.height; y += step) {\n const el = document.elementFromPoint(x, y);\n if (el && !seen.has(el)) seen.add(el);\n }\n }\n\n for (const [x, y] of [\n [rect.x, rect.y],\n [rect.x + rect.width, rect.y],\n [rect.x, rect.y + rect.height],\n [rect.x + rect.width, rect.y + rect.height],\n [rect.x + rect.width / 2, rect.y + rect.height / 2],\n ]) {\n const el = document.elementFromPoint(x, y);\n if (el && !seen.has(el)) seen.add(el);\n }\n\n if (container) container.style.display = '';\n return Array.from(seen).filter((el) => !container?.contains(el));\n}\n\nfunction getElementAtPoint(x: number, y: number): Element | null {\n const container = document.getElementById(WIDGET_CONTAINER_ID);\n if (container) container.style.display = 'none';\n const el = document.elementFromPoint(x, y);\n if (container) container.style.display = '';\n if (el && container?.contains(el)) return null;\n return el;\n}\n\nconst DRAG_THRESHOLD = 10;\n\nexport function PickOverlay({ onPick, onCancel }: PickOverlayProps) {\n // Use refs for drag state so event handlers always see current values\n const activeRef = useRef(false);\n const startRef = useRef<{ x: number; y: number } | null>(null);\n const isDragRef = useRef(false);\n\n // State only for rendering (hover highlight and drag rectangle)\n const [hoverRect, setHoverRect] = useState<Rect | null>(null);\n const [selRect, setSelRect] = useState<{ left: number; top: number; width: number; height: number } | null>(null);\n\n const onPickRef = useRef(onPick);\n onPickRef.current = onPick;\n const onCancelRef = useRef(onCancel);\n onCancelRef.current = onCancel;\n\n useEffect(() => {\n function handleMouseMove(e: MouseEvent) {\n if (activeRef.current && startRef.current) {\n // Dragging\n const dx = Math.abs(e.clientX - startRef.current.x);\n const dy = Math.abs(e.clientY - startRef.current.y);\n if (dx >= DRAG_THRESHOLD || dy >= DRAG_THRESHOLD) {\n isDragRef.current = true;\n }\n\n if (isDragRef.current) {\n setHoverRect(null);\n setSelRect({\n left: Math.min(startRef.current.x, e.clientX),\n top: Math.min(startRef.current.y, e.clientY),\n width: Math.abs(e.clientX - startRef.current.x),\n height: Math.abs(e.clientY - startRef.current.y),\n });\n }\n e.preventDefault();\n } else {\n // Hover — highlight element under cursor\n const el = getElementAtPoint(e.clientX, e.clientY);\n if (el) {\n const r = el.getBoundingClientRect();\n setHoverRect({ x: r.left, y: r.top, width: r.width, height: r.height });\n } else {\n setHoverRect(null);\n }\n }\n }\n\n function handleMouseDown(e: MouseEvent) {\n if (e.button !== 0) return;\n e.preventDefault();\n e.stopPropagation();\n startRef.current = { x: e.clientX, y: e.clientY };\n isDragRef.current = false;\n activeRef.current = true;\n }\n\n function handleMouseUp(e: MouseEvent) {\n if (!activeRef.current || !startRef.current) return;\n e.preventDefault();\n e.stopPropagation();\n\n const start = startRef.current;\n activeRef.current = false;\n startRef.current = null;\n setSelRect(null);\n setHoverRect(null);\n\n if (!isDragRef.current) {\n // Click — select single element\n const el = getElementAtPoint(e.clientX, e.clientY);\n if (el) {\n const r = el.getBoundingClientRect();\n onPickRef.current({ x: r.left, y: r.top, width: r.width, height: r.height }, [el]);\n }\n return;\n }\n\n // Drag — select area\n const x = Math.min(start.x, e.clientX);\n const y = Math.min(start.y, e.clientY);\n const width = Math.abs(e.clientX - start.x);\n const height = Math.abs(e.clientY - start.y);\n\n const rect = { x, y, width, height };\n const elements = getElementsBeneathRect(rect);\n onPickRef.current(rect, elements);\n }\n\n function handleKeyDown(e: KeyboardEvent) {\n if (e.key === 'Escape') {\n activeRef.current = false;\n startRef.current = null;\n setSelRect(null);\n setHoverRect(null);\n onCancelRef.current();\n }\n }\n\n document.addEventListener('mousedown', handleMouseDown, true);\n document.addEventListener('mousemove', handleMouseMove, true);\n document.addEventListener('mouseup', handleMouseUp, true);\n document.addEventListener('keydown', handleKeyDown, true);\n\n return () => {\n document.removeEventListener('mousedown', handleMouseDown, true);\n document.removeEventListener('mousemove', handleMouseMove, true);\n document.removeEventListener('mouseup', handleMouseUp, true);\n document.removeEventListener('keydown', handleKeyDown, true);\n };\n }, []);\n\n return (\n <>\n <div\n style={{\n position: 'fixed',\n top: 0,\n left: 0,\n right: 0,\n bottom: 0,\n zIndex: 99997,\n cursor: 'crosshair',\n }}\n />\n\n <div\n style={{\n position: 'fixed',\n top: 0,\n left: 0,\n right: 0,\n zIndex: 99998,\n background: 'rgba(59, 130, 246, 0.08)',\n padding: '8px 16px',\n textAlign: 'center',\n fontSize: 14,\n color: '#1e40af',\n fontFamily: 'system-ui, sans-serif',\n pointerEvents: 'none',\n }}\n >\n Click an element or drag to select an area. Press <strong>Esc</strong> to cancel.\n </div>\n\n {/* Hover highlight */}\n {hoverRect && (\n <div\n style={{\n position: 'fixed',\n left: hoverRect.x,\n top: hoverRect.y,\n width: hoverRect.width,\n height: hoverRect.height,\n border: '2px solid #3b82f6',\n background: 'rgba(59, 130, 246, 0.08)',\n zIndex: 99998,\n pointerEvents: 'none',\n borderRadius: 2,\n transition: 'all 0.1s ease-out',\n }}\n />\n )}\n\n {/* Drag selection rectangle */}\n {selRect && (\n <div\n style={{\n position: 'fixed',\n left: selRect.left,\n top: selRect.top,\n width: selRect.width,\n height: selRect.height,\n border: '2px dashed #3b82f6',\n background: 'rgba(59, 130, 246, 0.1)',\n zIndex: 99998,\n pointerEvents: 'none',\n borderRadius: 2,\n }}\n />\n )}\n </>\n );\n}\n","import React, { useState } from 'react';\nimport type { Draft, WidgetPosition } from '../types';\nimport type { ApiClient } from '../api/client';\nimport type { UserInfo } from '../hooks/useSession';\nimport { DraftItem } from './DraftItem';\n\ninterface SidePanelProps {\n position: WidgetPosition;\n drafts: Draft[];\n selectedDraftIds: Set<string>;\n onToggleSelect: (id: string) => void;\n onSelectAll: (selected: boolean) => void;\n onUpdateDraft: (id: string, comment: string) => void;\n onDeleteDraft: (id: string) => void;\n onSubmit: () => void;\n onClose: () => void;\n api: ApiClient;\n user: UserInfo | null;\n}\n\nexport function SidePanel({\n position,\n drafts,\n selectedDraftIds,\n onToggleSelect,\n onSelectAll,\n onUpdateDraft,\n onDeleteDraft,\n onSubmit,\n onClose,\n api,\n user,\n}: SidePanelProps) {\n const isRight = position.includes('right');\n const allSelected = drafts.length > 0 && selectedDraftIds.size === drafts.length;\n const [screenshotUrls, setScreenshotUrls] = useState<Record<string, string>>({});\n const [previewUrl, setPreviewUrl] = useState<string | null>(null);\n\n // Fetch screenshot URLs for drafts that have them\n React.useEffect(() => {\n const draftsWithScreenshots = drafts.filter((d) => d.screenshotKey && !screenshotUrls[d.id]);\n draftsWithScreenshots.forEach((draft) => {\n api.getScreenshotUrl(draft.id).then((url) => {\n setScreenshotUrls((prev) => ({ ...prev, [draft.id]: url }));\n }).catch(() => {});\n });\n }, [drafts, api]);\n\n const handlePreviewScreenshot = (draftId: string) => {\n const url = screenshotUrls[draftId];\n if (url) setPreviewUrl(url);\n };\n\n return (\n <div\n style={{\n position: 'fixed',\n top: 0,\n [isRight ? 'right' : 'left']: 0,\n width: 360,\n maxWidth: '100vw',\n height: '100vh',\n background: '#fff',\n boxShadow: isRight ? '-4px 0 16px rgba(0,0,0,0.1)' : '4px 0 16px rgba(0,0,0,0.1)',\n zIndex: 99998,\n display: 'flex',\n flexDirection: 'column',\n fontFamily: 'system-ui, sans-serif',\n }}\n >\n {/* Header */}\n <div\n style={{\n padding: '16px 16px 12px',\n borderBottom: '1px solid #e5e7eb',\n }}\n >\n <div style={{ display: 'flex', justifyContent: 'space-between', alignItems: 'center' }}>\n <h3 style={{ margin: 0, fontSize: 15, fontWeight: 600 }}>Feedback Session</h3>\n <button\n onClick={onClose}\n style={{\n background: 'none',\n border: 'none',\n fontSize: 18,\n cursor: 'pointer',\n color: '#6b7280',\n padding: '0 4px',\n }}\n >\n x\n </button>\n </div>\n {user && (\n <div style={{ marginTop: 6, fontSize: 12, color: '#6b7280', lineHeight: 1.4 }}>\n <div style={{ fontWeight: 500, color: '#374151' }}>{user.name}</div>\n <div>{user.email}</div>\n </div>\n )}\n </div>\n\n {/* Draft List */}\n <div style={{ flex: 1, overflow: 'auto' }}>\n {drafts.length === 0 ? (\n <div style={{ padding: 24, textAlign: 'center', color: '#9ca3af', fontSize: 13 }}>\n No drafts yet. Pick an element to start.\n </div>\n ) : (\n drafts.map((draft) => (\n <DraftItem\n key={draft.id}\n draft={draft}\n selected={selectedDraftIds.has(draft.id)}\n screenshotUrl={screenshotUrls[draft.id] || null}\n onToggleSelect={onToggleSelect}\n onUpdate={onUpdateDraft}\n onDelete={onDeleteDraft}\n onPreviewScreenshot={handlePreviewScreenshot}\n />\n ))\n )}\n </div>\n\n {/* Footer */}\n {drafts.length > 0 && (\n <div\n style={{\n padding: '12px 16px',\n borderTop: '1px solid #e5e7eb',\n display: 'flex',\n alignItems: 'center',\n gap: 12,\n }}\n >\n <label style={{ display: 'flex', alignItems: 'center', gap: 6, fontSize: 13, cursor: 'pointer', whiteSpace: 'nowrap' }}>\n <input\n type=\"checkbox\"\n checked={allSelected}\n onChange={(e) => onSelectAll(e.target.checked)}\n />\n Select All\n </label>\n <button\n onClick={onSubmit}\n disabled={selectedDraftIds.size === 0}\n style={{\n flex: 1,\n padding: '8px 12px',\n borderRadius: 6,\n border: 'none',\n background: selectedDraftIds.size === 0 ? '#93c5fd' : '#3b82f6',\n color: '#fff',\n fontSize: 13,\n fontWeight: 500,\n cursor: selectedDraftIds.size === 0 ? 'default' : 'pointer',\n }}\n >\n Submit Feedback ({selectedDraftIds.size})\n </button>\n </div>\n )}\n\n {/* Screenshot Preview Modal */}\n {previewUrl && (\n <div\n onClick={() => setPreviewUrl(null)}\n style={{\n position: 'fixed',\n top: 0,\n left: 0,\n right: 0,\n bottom: 0,\n background: 'rgba(0,0,0,0.6)',\n zIndex: 99999,\n display: 'flex',\n alignItems: 'center',\n justifyContent: 'center',\n }}\n >\n <div\n onClick={(e) => e.stopPropagation()}\n style={{\n background: '#fff',\n borderRadius: 8,\n padding: 8,\n maxWidth: '90vw',\n maxHeight: '90vh',\n position: 'relative',\n }}\n >\n <button\n onClick={() => setPreviewUrl(null)}\n style={{\n position: 'absolute',\n top: 4,\n right: 8,\n background: 'none',\n border: 'none',\n fontSize: 18,\n cursor: 'pointer',\n color: '#6b7280',\n zIndex: 1,\n }}\n >\n x\n </button>\n <img\n src={previewUrl}\n alt=\"Screenshot preview\"\n style={{ maxWidth: '85vw', maxHeight: '85vh', display: 'block', borderRadius: 4 }}\n />\n </div>\n </div>\n )}\n </div>\n );\n}\n","import React, { useState } from 'react';\nimport type { Draft } from '../types';\n\ninterface DraftItemProps {\n draft: Draft;\n selected: boolean;\n screenshotUrl: string | null;\n onToggleSelect: (id: string) => void;\n onUpdate: (id: string, comment: string) => void;\n onDelete: (id: string) => void;\n onPreviewScreenshot: (draftId: string) => void;\n}\n\nexport function DraftItem({ draft, selected, screenshotUrl, onToggleSelect, onUpdate, onDelete, onPreviewScreenshot }: DraftItemProps) {\n const [editing, setEditing] = useState(false);\n const [editComment, setEditComment] = useState(draft.comment);\n const [confirmDelete, setConfirmDelete] = useState(false);\n\n const handleSaveEdit = () => {\n if (editComment.trim()) {\n onUpdate(draft.id, editComment.trim());\n }\n setEditing(false);\n };\n\n const truncatedPath = draft.componentPath.length > 50\n ? '...' + draft.componentPath.slice(-47)\n : draft.componentPath;\n\n return (\n <div\n style={{\n padding: '10px 12px',\n borderBottom: '1px solid #e5e7eb',\n fontSize: 13,\n fontFamily: 'system-ui, sans-serif',\n }}\n >\n <div style={{ display: 'flex', alignItems: 'flex-start', gap: 8 }}>\n <input\n type=\"checkbox\"\n checked={selected}\n onChange={() => onToggleSelect(draft.id)}\n style={{ marginTop: 3, cursor: 'pointer' }}\n />\n <div style={{ flex: 1, minWidth: 0 }}>\n <div style={{ color: '#6b7280', fontSize: 11, marginBottom: 2 }} title={draft.componentPath}>\n {truncatedPath}\n </div>\n <div style={{ color: '#9ca3af', fontSize: 11, marginBottom: 4 }} title={draft.url}>\n {draft.url.length > 60 ? draft.url.slice(0, 60) + '...' : draft.url}\n </div>\n\n {screenshotUrl && (\n <img\n src={screenshotUrl}\n alt=\"Screenshot\"\n onClick={() => onPreviewScreenshot(draft.id)}\n style={{\n width: '100%',\n maxHeight: 160,\n objectFit: 'cover',\n borderRadius: 4,\n border: '1px solid #e5e7eb',\n cursor: 'pointer',\n marginBottom: 6,\n }}\n title=\"Click to enlarge\"\n />\n )}\n\n {editing ? (\n <div>\n <textarea\n value={editComment}\n onChange={(e) => setEditComment(e.target.value)}\n autoFocus\n style={{\n width: '100%',\n minHeight: 48,\n padding: 6,\n borderRadius: 4,\n border: '1px solid #d1d5db',\n fontSize: 13,\n resize: 'vertical',\n boxSizing: 'border-box',\n }}\n />\n <div style={{ display: 'flex', gap: 4, marginTop: 4 }}>\n <button onClick={handleSaveEdit} style={smallBtn('#3b82f6', '#fff')}>Save</button>\n <button onClick={() => { setEditing(false); setEditComment(draft.comment); }} style={smallBtn('#f3f4f6', '#374151')}>Cancel</button>\n </div>\n </div>\n ) : (\n <div\n onClick={() => setEditing(true)}\n style={{ cursor: 'pointer', color: '#1f2937', lineHeight: 1.4 }}\n title=\"Click to edit\"\n >\n {draft.comment}\n </div>\n )}\n </div>\n\n <div style={{ flexShrink: 0 }}>\n {confirmDelete ? (\n <div style={{ display: 'flex', gap: 4, fontSize: 12 }}>\n <button onClick={() => onDelete(draft.id)} style={smallBtn('#ef4444', '#fff')}>Yes</button>\n <button onClick={() => setConfirmDelete(false)} style={smallBtn('#f3f4f6', '#374151')}>No</button>\n </div>\n ) : (\n <button\n onClick={() => setConfirmDelete(true)}\n style={{\n background: 'none',\n border: 'none',\n cursor: 'pointer',\n color: '#9ca3af',\n fontSize: 16,\n padding: '0 4px',\n }}\n title=\"Delete draft\"\n >\n x\n </button>\n )}\n </div>\n </div>\n </div>\n );\n}\n\nfunction smallBtn(bg: string, color: string): React.CSSProperties {\n return {\n padding: '3px 8px',\n borderRadius: 4,\n border: '1px solid #d1d5db',\n background: bg,\n color,\n fontSize: 12,\n cursor: 'pointer',\n };\n}\n","import React, { useState, useEffect } from 'react';\nimport type { CapturedContext } from '../types';\n\nconst WIDGET_CONTAINER_ID = 'llm-ui-feedback-root';\n\ninterface DraftModalProps {\n pendingContext: { context: CapturedContext; screenshot: string | null };\n addingDraft: boolean;\n onAdd: (comment: string) => void;\n onCancel: () => void;\n}\n\nexport function DraftModal({ pendingContext, addingDraft, onAdd, onCancel }: DraftModalProps) {\n const [comment, setComment] = useState('');\n\n // Disable focus traps from host app modals (e.g. MUI Dialog) while our modal is open\n useEffect(() => {\n const container = document.getElementById(WIDGET_CONTAINER_ID);\n const inerted: Element[] = [];\n\n // Set inert on all top-level body children except the widget container\n for (const child of Array.from(document.body.children)) {\n if (child === container || child.id === WIDGET_CONTAINER_ID) continue;\n if (!child.hasAttribute('inert')) {\n child.setAttribute('inert', '');\n inerted.push(child);\n }\n }\n\n return () => {\n for (const el of inerted) {\n el.removeAttribute('inert');\n }\n };\n }, []);\n\n const handleAdd = () => {\n if (comment.trim() && !addingDraft) {\n onAdd(comment.trim());\n }\n };\n\n const { context, screenshot } = pendingContext;\n\n return (\n <div\n style={{\n position: 'fixed',\n inset: 0,\n zIndex: 99999,\n display: 'flex',\n alignItems: 'center',\n justifyContent: 'center',\n background: 'rgba(0,0,0,0.4)',\n fontFamily: 'system-ui, sans-serif',\n }}\n onClick={(e) => {\n if (e.target === e.currentTarget && !addingDraft) onCancel();\n }}\n >\n <div\n style={{\n background: '#fff',\n borderRadius: 12,\n padding: 24,\n width: 480,\n maxWidth: '90vw',\n maxHeight: '85vh',\n overflow: 'auto',\n boxShadow: '0 8px 32px rgba(0,0,0,0.2)',\n }}\n >\n <h3 style={{ margin: '0 0 16px', fontSize: 16 }}>New Feedback</h3>\n\n <div style={{ fontSize: 12, color: '#6b7280', marginBottom: 12 }}>\n <div><strong>Component:</strong> {context.componentPath}</div>\n <div><strong>Path:</strong> {context.urlPath}</div>\n {context.elementText && (\n <div><strong>Element:</strong> &quot;{context.elementText.slice(0, 80)}&quot;</div>\n )}\n </div>\n\n {screenshot && (\n <img\n src={screenshot}\n alt=\"Screenshot\"\n style={{\n width: '100%',\n borderRadius: 8,\n border: '1px solid #e5e7eb',\n marginBottom: 12,\n maxHeight: 180,\n objectFit: 'cover',\n }}\n />\n )}\n\n <textarea\n value={comment}\n onChange={(e) => setComment(e.target.value)}\n placeholder=\"Describe the issue or suggestion...\"\n autoFocus\n onKeyDown={(e) => {\n if (e.key === 'Enter' && (e.metaKey || e.ctrlKey)) handleAdd();\n }}\n style={{\n width: '100%',\n minHeight: 80,\n padding: 10,\n borderRadius: 8,\n border: '1px solid #d1d5db',\n fontSize: 14,\n resize: 'vertical',\n boxSizing: 'border-box',\n }}\n />\n\n <div style={{ display: 'flex', gap: 8, marginTop: 16, justifyContent: 'flex-end' }}>\n <button\n onClick={onCancel}\n disabled={addingDraft}\n style={{\n padding: '8px 16px',\n borderRadius: 6,\n border: '1px solid #d1d5db',\n background: '#f3f4f6',\n color: '#374151',\n fontSize: 13,\n cursor: 'pointer',\n }}\n >\n Cancel\n </button>\n <button\n onClick={handleAdd}\n disabled={!comment.trim() || addingDraft}\n style={{\n padding: '8px 16px',\n borderRadius: 6,\n border: 'none',\n background: !comment.trim() || addingDraft ? '#93c5fd' : '#3b82f6',\n color: '#fff',\n fontSize: 13,\n cursor: !comment.trim() || addingDraft ? 'default' : 'pointer',\n }}\n >\n {addingDraft ? 'Adding...' : 'Add to Drafts'}\n </button>\n </div>\n </div>\n </div>\n );\n}\n","import React, { useState } from 'react';\n\ninterface SubmitModalProps {\n count: number;\n onSubmit: (title: string) => void;\n onCancel: () => void;\n submitting: boolean;\n}\n\nexport function SubmitModal({ count, onSubmit, onCancel, submitting }: SubmitModalProps) {\n const [title, setTitle] = useState('');\n\n const handleSubmit = () => {\n if (title.trim() && !submitting) {\n onSubmit(title.trim());\n }\n };\n\n return (\n <div\n style={{\n position: 'fixed',\n inset: 0,\n zIndex: 99999,\n display: 'flex',\n alignItems: 'center',\n justifyContent: 'center',\n background: 'rgba(0,0,0,0.4)',\n fontFamily: 'system-ui, sans-serif',\n }}\n onClick={(e) => {\n if (e.target === e.currentTarget && !submitting) onCancel();\n }}\n >\n <div\n style={{\n background: '#fff',\n borderRadius: 12,\n padding: 24,\n width: 400,\n maxWidth: '90vw',\n boxShadow: '0 8px 32px rgba(0,0,0,0.2)',\n }}\n >\n <h3 style={{ margin: '0 0 16px', fontSize: 16 }}>Submit Feedback</h3>\n <p style={{ margin: '0 0 12px', fontSize: 14, color: '#6b7280' }}>\n {count} item{count !== 1 ? 's' : ''} selected. Name this feedback session:\n </p>\n <input\n type=\"text\"\n value={title}\n onChange={(e) => setTitle(e.target.value)}\n placeholder=\"e.g. Homepage redesign feedback\"\n autoFocus\n onKeyDown={(e) => { if (e.key === 'Enter') handleSubmit(); }}\n style={{\n width: '100%',\n padding: 10,\n borderRadius: 8,\n border: '1px solid #d1d5db',\n fontSize: 14,\n boxSizing: 'border-box',\n }}\n />\n <div style={{ display: 'flex', gap: 8, marginTop: 16, justifyContent: 'flex-end' }}>\n <button\n onClick={onCancel}\n disabled={submitting}\n style={{\n padding: '8px 16px',\n borderRadius: 6,\n border: '1px solid #d1d5db',\n background: '#f3f4f6',\n color: '#374151',\n fontSize: 13,\n cursor: 'pointer',\n }}\n >\n Cancel\n </button>\n <button\n onClick={handleSubmit}\n disabled={!title.trim() || submitting}\n style={{\n padding: '8px 16px',\n borderRadius: 6,\n border: 'none',\n background: !title.trim() || submitting ? '#93c5fd' : '#3b82f6',\n color: '#fff',\n fontSize: 13,\n cursor: !title.trim() || submitting ? 'default' : 'pointer',\n }}\n >\n {submitting ? 'Submitting...' : 'Submit'}\n </button>\n </div>\n </div>\n </div>\n );\n}\n","import { ComponentInfo } from '../types';\n\nlet minificationWarned = false;\n\nfunction getFiber(el: Element): any | null {\n const key = Object.keys(el).find((k) => k.startsWith('__reactFiber$'));\n return key ? (el as any)[key] : null;\n}\n\nfunction pickShortProps(props: Record<string, unknown>): Record<string, unknown> {\n const short: Record<string, unknown> = {};\n for (const [key, value] of Object.entries(props)) {\n if (key === 'children') continue;\n if (typeof value === 'function') continue;\n if (typeof value === 'string' || typeof value === 'number' || typeof value === 'boolean') {\n short[key] = value;\n }\n }\n return short;\n}\n\nexport function getComponentPath(el: Element, maxDepth = 8): ComponentInfo[] {\n const fiber = getFiber(el);\n if (!fiber) return [];\n\n const path: ComponentInfo[] = [];\n let current = fiber;\n\n while (current && path.length < maxDepth) {\n if (typeof current.type === 'function' || typeof current.type === 'object') {\n const name =\n current.type?.displayName || current.type?.name || null;\n if (name) {\n // Detect minified names: single-char lowercase names are typical minifier output\n if (\n !minificationWarned &&\n name.length <= 2 &&\n /^[a-z]/.test(name)\n ) {\n minificationWarned = true;\n console.warn(\n '[llm-ui-feedback] Component names appear minified (e.g., \"' +\n name +\n '\"). The generated LLM prompts will lack meaningful component paths. ' +\n 'To fix, configure your bundler to preserve function names. ' +\n 'See: https://github.com/user/llm-ui-feedback/blob/main/docs/production-setup.md'\n );\n }\n path.push({\n name,\n props: pickShortProps(current.memoizedProps || {}),\n });\n }\n }\n current = current.return;\n }\n\n return path.reverse();\n}\n","import html2canvas from 'html2canvas-pro';\n\nexport interface ScreenshotRect {\n x: number;\n y: number;\n width: number;\n height: number;\n}\n\nexport async function captureScreenshot(rect: ScreenshotRect): Promise<string> {\n const fullCanvas = await html2canvas(document.body, {\n logging: false,\n useCORS: true,\n });\n\n // Convert viewport coords to document coords\n const docX = rect.x + window.scrollX;\n const docY = rect.y + window.scrollY;\n\n // html2canvas may scale the canvas vs the document — compute ratio\n const scaleX = fullCanvas.width / document.documentElement.scrollWidth;\n const scaleY = fullCanvas.height / document.documentElement.scrollHeight;\n\n const sx = Math.round(docX * scaleX);\n const sy = Math.round(docY * scaleY);\n const sw = Math.round(rect.width * scaleX);\n const sh = Math.round(rect.height * scaleY);\n\n // Crop to the selected region\n const cropped = document.createElement('canvas');\n cropped.width = sw;\n cropped.height = sh;\n const ctx = cropped.getContext('2d');\n if (ctx) {\n ctx.drawImage(fullCanvas, sx, sy, sw, sh, 0, 0, sw, sh);\n\n // Draw a blue border to indicate the selection\n ctx.strokeStyle = '#3b82f6';\n ctx.lineWidth = 3;\n ctx.strokeRect(1, 1, sw - 2, sh - 2);\n }\n\n return cropped.toDataURL('image/png');\n}\n","import { CapturedContext } from '../types';\n\nexport function buildPrompt(context: CapturedContext, comment: string): string {\n const propsStr = context.components\n .filter((c) => Object.keys(c.props).length > 0)\n .map((c) => ` ${c.name}: ${JSON.stringify(c.props)}`)\n .join('\\n');\n\n const lines = [\n `Page: ${context.url}`,\n `Path: ${context.urlPath}`,\n `Reported at: ${context.reportedAt}`,\n `Component: ${context.componentPath}`,\n ];\n\n if (propsStr) {\n lines.push(`Props:\\n${propsStr}`);\n }\n\n if (context.elementText) {\n lines.push(`Element text: \"${context.elementText}\"`);\n }\n\n lines.push('', `User feedback: \"${comment}\"`, '', 'Screenshot attached showing the selected region.');\n\n return lines.join('\\n');\n}\n","export function dataUrlToBlob(dataUrl: string): Blob {\n const [header, base64] = dataUrl.split(',');\n const mime = header.match(/:(.*?);/)?.[1] || 'image/png';\n const binary = atob(base64);\n const bytes = new Uint8Array(binary.length);\n for (let i = 0; i < binary.length; i++) {\n bytes[i] = binary.charCodeAt(i);\n }\n return new Blob([bytes], { type: mime });\n}\n","import { useState, useEffect, useCallback, useRef } from 'react';\n\nconst SESSION_TOKEN_KEY = 'llm_feedback_session_token';\nconst USER_KEY = 'llm_feedback_user';\n\n// Check for auth bypass flag — Vite replaces import.meta.env at build time.\n// In non-Vite contexts (npm package CJS), import.meta.env is undefined which is fine.\nconst AUTH_BYPASS = (typeof globalThis !== 'undefined' && (globalThis as any).__FEEDBACK_AUTH_BYPASS__)\n || (typeof import.meta !== 'undefined' && (import.meta as any).env?.VITE_AUTH_BYPASS === 'true');\n\nexport interface UserInfo {\n email: string;\n name: string;\n picture: string;\n sub: string;\n}\n\nexport interface SessionState {\n status: 'loading' | 'unauthenticated' | 'authenticated';\n user: UserInfo | null;\n signIn: () => void;\n signOut: () => void;\n}\n\nexport function getSessionToken(): string | null {\n if (AUTH_BYPASS) return 'bypass-token';\n return localStorage.getItem(SESSION_TOKEN_KEY);\n}\n\nconst BYPASS_USER: UserInfo = {\n email: 'bypass@test.local',\n name: 'Bypass User',\n picture: '',\n sub: 'bypass-user',\n};\n\nexport function useSession(apiUrl: string, clientId: string): SessionState {\n const [status, setStatus] = useState<SessionState['status']>(AUTH_BYPASS ? 'authenticated' : 'loading');\n const [user, setUser] = useState<UserInfo | null>(AUTH_BYPASS ? BYPASS_USER : null);\n const pendingAuthRef = useRef(false);\n\n // On mount: check localStorage for existing session\n useEffect(() => {\n if (AUTH_BYPASS) return;\n let cancelled = false;\n\n async function checkSession() {\n const token = localStorage.getItem(SESSION_TOKEN_KEY);\n const savedUser = localStorage.getItem(USER_KEY);\n\n if (!token || !savedUser) {\n if (!cancelled) setStatus('unauthenticated');\n return;\n }\n\n try {\n const res = await fetch(`${apiUrl}/auth/status`, {\n headers: { 'X-Session-Token': token },\n });\n const data = await res.json();\n\n if (!cancelled) {\n if (data.authenticated) {\n setUser(data.user);\n setStatus('authenticated');\n } else {\n localStorage.removeItem(SESSION_TOKEN_KEY);\n localStorage.removeItem(USER_KEY);\n setStatus('unauthenticated');\n }\n }\n } catch {\n if (!cancelled) {\n // Network error — use cached user optimistically\n try {\n setUser(JSON.parse(savedUser));\n setStatus('authenticated');\n } catch {\n setStatus('unauthenticated');\n }\n }\n }\n }\n\n checkSession();\n return () => { cancelled = true; };\n }, [apiUrl]);\n\n // Listen for postMessage from auth popup\n useEffect(() => {\n function handleMessage(event: MessageEvent) {\n if (event.data?.type !== 'feedback-auth') return;\n const { sessionToken, user: userData } = event.data;\n if (sessionToken && userData) {\n localStorage.setItem(SESSION_TOKEN_KEY, sessionToken);\n localStorage.setItem(USER_KEY, JSON.stringify(userData));\n setUser(userData);\n setStatus('authenticated');\n pendingAuthRef.current = false;\n }\n }\n\n window.addEventListener('message', handleMessage);\n return () => window.removeEventListener('message', handleMessage);\n }, []);\n\n const signIn = useCallback(() => {\n if (pendingAuthRef.current) return;\n pendingAuthRef.current = true;\n\n const loginUrl = `${apiUrl}/auth/login?clientId=${encodeURIComponent(clientId)}&origin=${encodeURIComponent(window.location.origin)}`;\n const popup = window.open(loginUrl, 'feedback-auth', 'width=500,height=600,menubar=no,toolbar=no');\n\n if (!popup) {\n // Popup blocked — can't do much, reset flag\n pendingAuthRef.current = false;\n return;\n }\n\n // Poll for popup closed (user cancelled)\n const interval = setInterval(() => {\n if (popup.closed) {\n clearInterval(interval);\n pendingAuthRef.current = false;\n }\n }, 500);\n }, [apiUrl, clientId]);\n\n const signOut = useCallback(async () => {\n const token = localStorage.getItem(SESSION_TOKEN_KEY);\n localStorage.removeItem(SESSION_TOKEN_KEY);\n localStorage.removeItem(USER_KEY);\n setUser(null);\n setStatus('unauthenticated');\n\n if (token) {\n try {\n await fetch(`${apiUrl}/auth/logout`, {\n method: 'POST',\n headers: { 'X-Session-Token': token },\n });\n } catch {\n // Best-effort logout\n }\n }\n }, [apiUrl]);\n\n return { status, user, signIn, signOut };\n}\n","import type { Draft, FeedbackGroup } from '../types';\nimport { getSessionToken } from '../hooks/useSession';\n\nexport interface DraftPayload {\n id: string;\n url: string;\n componentPath: string;\n components: { name: string; props: Record<string, unknown> }[];\n elementText: string;\n comment: string;\n prompt: string;\n screenshotKey?: string;\n}\n\nexport interface ApiClient {\n fetchDrafts(): Promise<Draft[]>;\n createDraft(draft: DraftPayload): Promise<Draft>;\n updateDraft(id: string, data: { comment: string }): Promise<Draft>;\n deleteDraft(id: string): Promise<void>;\n submitSession(data: { title: string; draftIds: string[] }): Promise<{ feedbackGroup: FeedbackGroup; entriesCreated: number }>;\n getUploadUrl(\n entryId: string,\n timestamp: string,\n ): Promise<{ uploadUrl: string; key: string }>;\n uploadScreenshot(uploadUrl: string, blob: Blob): Promise<void>;\n getScreenshotUrl(draftId: string): Promise<string>;\n}\n\nexport function createApiClient(apiUrl: string, clientId: string): ApiClient {\n async function apiFetch(path: string, options: RequestInit = {}) {\n const token = getSessionToken();\n const res = await fetch(`${apiUrl}${path}`, {\n ...options,\n headers: {\n 'Content-Type': 'application/json',\n ...(token ? { 'X-Session-Token': token } : {}),\n 'X-Client-Id': clientId,\n ...(options.headers as Record<string, string> | undefined),\n },\n });\n if (!res.ok) {\n const body = await res.json().catch(() => ({}));\n throw new Error(\n (body as Record<string, string>).error ||\n `API error ${res.status}`,\n );\n }\n if (res.status === 204) return undefined;\n return res.json();\n }\n\n return {\n async fetchDrafts() {\n const data = await apiFetch('/drafts');\n return (data as { items: Draft[] }).items;\n },\n\n async createDraft(draft: DraftPayload) {\n return apiFetch('/drafts', {\n method: 'POST',\n body: JSON.stringify(draft),\n }) as Promise<Draft>;\n },\n\n async updateDraft(id: string, data: { comment: string }) {\n return apiFetch(`/drafts/${id}`, {\n method: 'PATCH',\n body: JSON.stringify(data),\n }) as Promise<Draft>;\n },\n\n async deleteDraft(id: string) {\n await apiFetch(`/drafts/${id}`, { method: 'DELETE' });\n },\n\n async submitSession(data: { title: string; draftIds: string[] }) {\n return apiFetch('/feedback-groups/submit', {\n method: 'POST',\n body: JSON.stringify(data),\n }) as Promise<{ feedbackGroup: FeedbackGroup; entriesCreated: number }>;\n },\n\n async getUploadUrl(entryId: string, timestamp: string) {\n return apiFetch('/upload-url', {\n method: 'POST',\n body: JSON.stringify({ entryId, timestamp }),\n }) as Promise<{ uploadUrl: string; key: string }>;\n },\n\n async getScreenshotUrl(draftId: string) {\n const data = await apiFetch(`/drafts/${draftId}/screenshot-url`);\n return (data as { url: string }).url;\n },\n\n async uploadScreenshot(uploadUrl: string, blob: Blob) {\n const res = await fetch(uploadUrl, {\n method: 'PUT',\n body: blob,\n headers: { 'Content-Type': 'image/png' },\n });\n if (!res.ok) throw new Error(`S3 upload failed: ${res.status}`);\n },\n };\n}\n","export const DEFAULT_API_URL = 'https://your-lambda-function-url.lambda-url.us-east-1.on.aws';\n"],"mappings":"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","names":["useCallback","useEffect","useRef","jsx","jsxs","React","useState","useState","jsx","jsxs","jsx","jsxs","useState","React","useState","useEffect","jsx","jsxs","WIDGET_CONTAINER_ID","useState","jsx","jsxs","useState","useEffect","useCallback","useRef","Fragment","jsx","jsxs","useRef","useEffect","useCallback"]}
1
+ {"version":3,"sources":["../src/components/FeedbackWidget.tsx","../src/utils/color.ts","../src/components/FloatingButton.tsx","../src/components/PickOverlay.tsx","../src/components/SidePanel.tsx","../src/components/DraftItem.tsx","../src/components/DraftModal.tsx","../src/components/SubmitModal.tsx","../src/utils/fiber.ts","../src/utils/screenshot.ts","../src/utils/prompt.ts","../src/utils/blob.ts","../src/hooks/useSession.ts","../src/api/client.ts"],"sourcesContent":["import React, { useReducer, useCallback, useEffect, useMemo, useRef } from 'react';\nimport { createPortal } from 'react-dom';\nimport { FloatingButton } from './FloatingButton';\nimport { PickOverlay } from './PickOverlay';\nimport { SidePanel } from './SidePanel';\nimport { DraftModal } from './DraftModal';\nimport { SubmitModal } from './SubmitModal';\nimport { getComponentPath } from '../utils/fiber';\nimport { captureScreenshot } from '../utils/screenshot';\nimport { buildPrompt } from '../utils/prompt';\nimport { dataUrlToBlob } from '../utils/blob';\nimport { createApiClient } from '../api/client';\nimport { useSession } from '../hooks/useSession';\nimport { CapturedContext, Draft, WidgetPosition } from '../types';\n\nexport const CONTAINER_ID = 'llm-ui-feedback-root';\n\nfunction getOrCreateContainer(): HTMLElement {\n let el = document.getElementById(CONTAINER_ID);\n if (!el) {\n el = document.createElement('div');\n el.id = CONTAINER_ID;\n document.body.appendChild(el);\n }\n return el;\n}\n\nexport interface FeedbackWidgetProps {\n /** Tenant identifier — required. */\n clientId: string;\n /** Backend API URL — required. */\n apiUrl: string;\n /** Corner position for the floating button. Default: 'bottom-right' */\n position?: WidgetPosition;\n /** Hex color for the FAB accent. Default: '#3b82f6' */\n buttonColor?: string;\n /** Keyboard shortcut to toggle the panel, e.g. 'Alt+F'. No default (opt-in only). */\n hotkey?: string;\n}\n\ninterface WidgetState {\n panelOpen: boolean;\n picking: boolean;\n pendingContext: { context: CapturedContext; screenshot: string | null } | null;\n drafts: Draft[];\n selectedDraftIds: Set<string>;\n submitModalOpen: boolean;\n addingDraft: boolean;\n submitting: boolean;\n}\n\ntype WidgetAction =\n | { type: 'TOGGLE_PANEL' }\n | { type: 'OPEN_PANEL' }\n | { type: 'CLOSE_PANEL' }\n | { type: 'START_PICKING' }\n | { type: 'CANCEL_PICKING' }\n | { type: 'CANCEL_DRAFT_MODAL' }\n | { type: 'ELEMENT_PICKED'; context: CapturedContext; screenshot: string | null }\n | { type: 'SET_ADDING_DRAFT'; adding: boolean }\n | { type: 'DRAFT_ADDED'; draft: Draft }\n | { type: 'SET_DRAFTS'; drafts: Draft[] }\n | { type: 'DRAFT_UPDATED'; id: string; comment: string }\n | { type: 'DRAFT_DELETED'; id: string }\n | { type: 'TOGGLE_SELECT'; id: string }\n | { type: 'SELECT_ALL'; selected: boolean }\n | { type: 'OPEN_SUBMIT_MODAL' }\n | { type: 'CLOSE_SUBMIT_MODAL' }\n | { type: 'SET_SUBMITTING'; submitting: boolean }\n | { type: 'SUBMIT_COMPLETE'; submittedIds: string[] };\n\nconst initialState: WidgetState = {\n panelOpen: false,\n picking: false,\n pendingContext: null,\n drafts: [],\n selectedDraftIds: new Set(),\n submitModalOpen: false,\n addingDraft: false,\n submitting: false,\n};\n\nfunction widgetReducer(state: WidgetState, action: WidgetAction): WidgetState {\n switch (action.type) {\n case 'TOGGLE_PANEL':\n return state.panelOpen\n ? { ...state, panelOpen: false, picking: false, pendingContext: null }\n : { ...state, panelOpen: true };\n case 'OPEN_PANEL':\n return { ...state, panelOpen: true };\n case 'CLOSE_PANEL':\n return { ...state, panelOpen: false, picking: false, pendingContext: null };\n case 'START_PICKING':\n return { ...state, picking: true };\n case 'CANCEL_PICKING':\n return { ...state, picking: false };\n case 'CANCEL_DRAFT_MODAL':\n return { ...state, pendingContext: null, addingDraft: false };\n case 'ELEMENT_PICKED':\n return { ...state, picking: false, pendingContext: { context: action.context, screenshot: action.screenshot } };\n case 'SET_ADDING_DRAFT':\n return { ...state, addingDraft: action.adding };\n case 'DRAFT_ADDED':\n return { ...state, pendingContext: null, addingDraft: false, drafts: [action.draft, ...state.drafts] };\n case 'SET_DRAFTS':\n return { ...state, drafts: action.drafts };\n case 'DRAFT_UPDATED':\n return { ...state, drafts: state.drafts.map((d) => d.id === action.id ? { ...d, comment: action.comment } : d) };\n case 'DRAFT_DELETED': {\n const next = new Set(state.selectedDraftIds);\n next.delete(action.id);\n return { ...state, drafts: state.drafts.filter((d) => d.id !== action.id), selectedDraftIds: next };\n }\n case 'TOGGLE_SELECT': {\n const next = new Set(state.selectedDraftIds);\n if (next.has(action.id)) next.delete(action.id);\n else next.add(action.id);\n return { ...state, selectedDraftIds: next };\n }\n case 'SELECT_ALL':\n return { ...state, selectedDraftIds: action.selected ? new Set(state.drafts.map((d) => d.id)) : new Set() };\n case 'OPEN_SUBMIT_MODAL':\n return { ...state, submitModalOpen: true };\n case 'CLOSE_SUBMIT_MODAL':\n return { ...state, submitModalOpen: false };\n case 'SET_SUBMITTING':\n return { ...state, submitting: action.submitting };\n case 'SUBMIT_COMPLETE': {\n const submitted = new Set(action.submittedIds);\n return {\n ...state,\n submitting: false,\n submitModalOpen: false,\n drafts: state.drafts.filter((d) => !submitted.has(d.id)),\n selectedDraftIds: new Set(),\n };\n }\n default:\n return state;\n }\n}\n\nfunction parseHotkey(hotkey: string) {\n const parts = hotkey.split('+').map((p) => p.trim().toLowerCase());\n const key = parts.pop()!;\n return {\n key,\n ctrl: parts.includes('ctrl'),\n alt: parts.includes('alt'),\n shift: parts.includes('shift'),\n meta: parts.includes('meta'),\n };\n}\n\nfunction isEditableTarget(el: Element | null): boolean {\n if (!el) return false;\n const tag = el.tagName;\n if (tag === 'INPUT' || tag === 'TEXTAREA' || tag === 'SELECT') return true;\n if ((el as HTMLElement).isContentEditable) return true;\n return false;\n}\n\nexport function FeedbackWidget({\n clientId,\n apiUrl,\n position = 'bottom-right',\n buttonColor = '#3b82f6',\n hotkey,\n}: FeedbackWidgetProps) {\n const session = useSession(apiUrl, clientId);\n const [state, dispatch] = useReducer(widgetReducer, initialState);\n const pendingOpenRef = useRef(false);\n\n const api = useMemo(\n () => createApiClient(apiUrl, clientId),\n [apiUrl, clientId],\n );\n\n // Auto-open panel after successful auth\n useEffect(() => {\n if (session.status === 'authenticated' && pendingOpenRef.current) {\n pendingOpenRef.current = false;\n dispatch({ type: 'OPEN_PANEL' });\n }\n }, [session.status]);\n\n // Fetch drafts on auth and when panel opens\n useEffect(() => {\n if (session.status === 'authenticated') {\n api.fetchDrafts().then((drafts) => {\n dispatch({ type: 'SET_DRAFTS', drafts });\n }).catch(() => {\n // silently fail\n });\n }\n }, [state.panelOpen, session.status, api]);\n\n // Hotkey listener\n useEffect(() => {\n if (!hotkey) return;\n const parsed = parseHotkey(hotkey);\n\n function handler(e: KeyboardEvent) {\n if (isEditableTarget(document.activeElement)) return;\n if (\n e.key.toLowerCase() === parsed.key &&\n e.ctrlKey === parsed.ctrl &&\n e.altKey === parsed.alt &&\n e.shiftKey === parsed.shift &&\n e.metaKey === parsed.meta\n ) {\n e.preventDefault();\n dispatch({ type: 'TOGGLE_PANEL' });\n }\n }\n\n window.addEventListener('keydown', handler);\n return () => window.removeEventListener('keydown', handler);\n }, [hotkey]);\n\n const handlePickClick = useCallback(() => {\n if (session.status === 'unauthenticated') {\n pendingOpenRef.current = true;\n session.signIn();\n return;\n }\n dispatch({ type: 'START_PICKING' });\n }, [session]);\n\n const handlePanelToggle = useCallback(() => {\n if (session.status === 'unauthenticated') {\n pendingOpenRef.current = true;\n session.signIn();\n return;\n }\n dispatch({ type: 'TOGGLE_PANEL' });\n }, [session]);\n\n const handlePick = useCallback(async (rect: { x: number; y: number; width: number; height: number }, elements: Element[]) => {\n // Collect unique components from all elements in the selection\n const seenNames = new Set<string>();\n const allComponents: { name: string; props: Record<string, unknown> }[] = [];\n for (const el of elements) {\n for (const comp of getComponentPath(el)) {\n if (!seenNames.has(comp.name)) {\n seenNames.add(comp.name);\n allComponents.push(comp);\n }\n }\n }\n\n const componentPath = allComponents.map((c) => c.name).join(', ') || '(no React component found)';\n\n // Gather text from selected elements\n const textParts = new Set<string>();\n for (const el of elements) {\n const raw = ((el as HTMLElement).innerText || el.textContent || '').trim();\n if (raw) textParts.add(raw);\n }\n const combined = Array.from(textParts).join(' ').trim();\n const elementText = combined.length > 200 ? combined.slice(0, 200) + '...' : combined;\n\n const centerX = rect.x + rect.width / 2;\n const centerY = rect.y + rect.height / 2;\n\n const context: CapturedContext = {\n url: window.location.href,\n urlPath: window.location.pathname,\n reportedAt: new Date().toISOString(),\n componentPath,\n components: allComponents,\n elementText,\n clickX: centerX,\n clickY: centerY,\n };\n\n // Only capture screenshot for drag selections, not single-element clicks\n const isDrag = rect.width > 20 && rect.height > 20;\n let screenshot: string | null = null;\n if (isDrag) {\n try {\n screenshot = await captureScreenshot(rect);\n } catch {\n // Screenshot failed — continue without it\n }\n }\n\n dispatch({ type: 'ELEMENT_PICKED', context, screenshot });\n }, []);\n\n const handleCancelPicking = useCallback(() => {\n dispatch({ type: 'CANCEL_PICKING' });\n }, []);\n\n const handleAddDraft = useCallback(async (comment: string) => {\n if (!state.pendingContext) return;\n dispatch({ type: 'SET_ADDING_DRAFT', adding: true });\n\n const { context, screenshot } = state.pendingContext;\n const entryId = `f_${Date.now()}`;\n const timestamp = new Date().toISOString();\n let screenshotKey: string | undefined;\n\n // Upload screenshot\n if (screenshot) {\n const blob = dataUrlToBlob(screenshot);\n try {\n const { uploadUrl, key } = await api.getUploadUrl(entryId, timestamp);\n await api.uploadScreenshot(uploadUrl, blob);\n screenshotKey = key;\n } catch {\n // continue without screenshot\n }\n }\n\n try {\n const draft = await api.createDraft({\n id: entryId,\n url: context.url,\n componentPath: context.componentPath,\n components: context.components,\n elementText: context.elementText,\n comment,\n prompt: buildPrompt(context, comment),\n ...(screenshotKey ? { screenshotKey } : {}),\n });\n dispatch({ type: 'DRAFT_ADDED', draft });\n } catch {\n dispatch({ type: 'SET_ADDING_DRAFT', adding: false });\n }\n }, [state.pendingContext, api]);\n\n const handleUpdateDraft = useCallback(async (id: string, comment: string) => {\n dispatch({ type: 'DRAFT_UPDATED', id, comment });\n try {\n await api.updateDraft(id, { comment });\n } catch {\n // revert on error — refetch\n api.fetchDrafts().then((drafts) => dispatch({ type: 'SET_DRAFTS', drafts })).catch(() => {});\n }\n }, [api]);\n\n const handleDeleteDraft = useCallback(async (id: string) => {\n dispatch({ type: 'DRAFT_DELETED', id });\n try {\n await api.deleteDraft(id);\n } catch {\n // refetch on error\n api.fetchDrafts().then((drafts) => dispatch({ type: 'SET_DRAFTS', drafts })).catch(() => {});\n }\n }, [api]);\n\n const handleSubmit = useCallback(async (title: string) => {\n dispatch({ type: 'SET_SUBMITTING', submitting: true });\n const draftIds = Array.from(state.selectedDraftIds);\n try {\n await api.submitSession({ title, draftIds });\n dispatch({ type: 'SUBMIT_COMPLETE', submittedIds: draftIds });\n } catch {\n dispatch({ type: 'SET_SUBMITTING', submitting: false });\n }\n }, [state.selectedDraftIds, api]);\n\n // Don't render while checking auth status\n if (session.status === 'loading') return null;\n\n return createPortal(\n <>\n <FloatingButton\n onPickClick={handlePickClick}\n onPanelToggle={handlePanelToggle}\n draftCount={state.drafts.length}\n panelOpen={state.panelOpen}\n position={position}\n buttonColor={buttonColor}\n />\n {state.picking && <PickOverlay onPick={handlePick} onCancel={handleCancelPicking} />}\n {state.panelOpen && (\n <SidePanel\n position={position}\n drafts={state.drafts}\n selectedDraftIds={state.selectedDraftIds}\n onToggleSelect={(id) => dispatch({ type: 'TOGGLE_SELECT', id })}\n onSelectAll={(selected) => dispatch({ type: 'SELECT_ALL', selected })}\n onUpdateDraft={handleUpdateDraft}\n onDeleteDraft={handleDeleteDraft}\n onSubmit={() => dispatch({ type: 'OPEN_SUBMIT_MODAL' })}\n onClose={() => dispatch({ type: 'CLOSE_PANEL' })}\n api={api}\n user={session.user}\n />\n )}\n {state.pendingContext && !state.picking && (\n <DraftModal\n pendingContext={state.pendingContext}\n addingDraft={state.addingDraft}\n onAdd={handleAddDraft}\n onCancel={() => dispatch({ type: 'CANCEL_DRAFT_MODAL' })}\n />\n )}\n {state.submitModalOpen && (\n <SubmitModal\n count={state.selectedDraftIds.size}\n onSubmit={handleSubmit}\n onCancel={() => dispatch({ type: 'CLOSE_SUBMIT_MODAL' })}\n submitting={state.submitting}\n />\n )}\n </>,\n getOrCreateContainer()\n );\n}\n","/**\n * Compute whether to use light or dark text on a given background color.\n * Uses the WCAG relative luminance formula.\n * @param hexColor - Hex color string (e.g., '#3b82f6' or '#fff')\n * @returns '#000000' for light backgrounds, '#ffffff' for dark backgrounds\n */\nexport function getContrastColor(hexColor: string): string {\n const hex = hexColor.replace('#', '');\n // Expand 3-char hex to 6-char (e.g., #fff -> #ffffff)\n const fullHex =\n hex.length === 3\n ? hex[0] + hex[0] + hex[1] + hex[1] + hex[2] + hex[2]\n : hex;\n\n const r = parseInt(fullHex.substring(0, 2), 16) / 255;\n const g = parseInt(fullHex.substring(2, 4), 16) / 255;\n const b = parseInt(fullHex.substring(4, 6), 16) / 255;\n\n const toLinear = (c: number) =>\n c <= 0.03928 ? c / 12.92 : Math.pow((c + 0.055) / 1.055, 2.4);\n\n // Relative luminance (WCAG 2.0)\n const luminance =\n 0.2126 * toLinear(r) + 0.7152 * toLinear(g) + 0.0722 * toLinear(b);\n\n return luminance > 0.179 ? '#000000' : '#ffffff';\n}\n","import React from 'react';\nimport { WidgetPosition } from '../types';\nimport { getContrastColor } from '../utils/color';\n\ninterface FloatingButtonProps {\n onPickClick: () => void;\n onPanelToggle: () => void;\n draftCount: number;\n panelOpen: boolean;\n position: WidgetPosition;\n buttonColor: string;\n}\n\nexport function FloatingButton({ onPickClick, onPanelToggle, draftCount, panelOpen, position, buttonColor }: FloatingButtonProps) {\n const isBottom = position.includes('bottom');\n const isRight = position.includes('right');\n\n const anchor: React.CSSProperties = {\n position: 'fixed',\n [isBottom ? 'bottom' : 'top']: 24,\n [isRight ? 'right' : 'left']: 24,\n zIndex: 99999,\n display: 'flex',\n flexDirection: 'column',\n alignItems: 'center',\n gap: 8,\n };\n\n return (\n <div style={anchor}>\n {/* Badge button — draft count, only visible when drafts exist */}\n {draftCount > 0 && (\n <button\n onClick={onPanelToggle}\n aria-label={panelOpen ? 'Close drafts panel' : `Open drafts panel (${draftCount})`}\n style={{\n width: 32,\n height: 32,\n borderRadius: '50%',\n border: 'none',\n background: panelOpen ? '#ef4444' : buttonColor,\n color: panelOpen ? '#fff' : getContrastColor(buttonColor),\n fontFamily: 'system-ui, -apple-system, sans-serif',\n fontSize: 13,\n fontWeight: 700,\n lineHeight: 1,\n cursor: 'pointer',\n display: 'flex',\n alignItems: 'center',\n justifyContent: 'center',\n boxShadow: '0 2px 8px rgba(0,0,0,0.25)',\n transition: 'background 0.15s',\n padding: 0,\n }}\n >\n {draftCount}\n </button>\n )}\n\n {/* FAB — starts picking, or closes panel when open */}\n <button\n onClick={panelOpen ? onPanelToggle : onPickClick}\n aria-label={panelOpen ? 'Close panel' : 'Pick element for feedback'}\n style={{\n width: 48,\n height: 48,\n borderRadius: '50%',\n border: 'none',\n background: panelOpen ? '#ef4444' : buttonColor,\n color: panelOpen ? '#fff' : getContrastColor(buttonColor),\n fontFamily: 'system-ui, -apple-system, sans-serif',\n fontSize: 28,\n fontWeight: 300,\n lineHeight: 1,\n cursor: 'pointer',\n display: 'flex',\n alignItems: 'center',\n justifyContent: 'center',\n boxShadow: '0 2px 8px rgba(0,0,0,0.25)',\n transition: 'background 0.15s, transform 0.15s',\n transform: panelOpen ? 'rotate(45deg)' : 'none',\n padding: 0,\n }}\n >\n +\n </button>\n </div>\n );\n}\n","import React, { useCallback, useEffect, useRef, useState } from 'react';\n\nconst WIDGET_CONTAINER_ID = 'llm-ui-feedback-root';\n\ninterface Rect {\n x: number;\n y: number;\n width: number;\n height: number;\n}\n\ninterface PickOverlayProps {\n onPick: (rect: Rect, elements: Element[]) => void;\n onCancel: () => void;\n}\n\nfunction getElementsBeneathRect(rect: Rect): Element[] {\n const container = document.getElementById(WIDGET_CONTAINER_ID);\n if (container) container.style.display = 'none';\n\n const seen = new Set<Element>();\n const step = 8;\n\n for (let x = rect.x; x <= rect.x + rect.width; x += step) {\n for (let y = rect.y; y <= rect.y + rect.height; y += step) {\n const el = document.elementFromPoint(x, y);\n if (el && !seen.has(el)) seen.add(el);\n }\n }\n\n for (const [x, y] of [\n [rect.x, rect.y],\n [rect.x + rect.width, rect.y],\n [rect.x, rect.y + rect.height],\n [rect.x + rect.width, rect.y + rect.height],\n [rect.x + rect.width / 2, rect.y + rect.height / 2],\n ]) {\n const el = document.elementFromPoint(x, y);\n if (el && !seen.has(el)) seen.add(el);\n }\n\n if (container) container.style.display = '';\n return Array.from(seen).filter((el) => !container?.contains(el));\n}\n\nfunction getElementAtPoint(x: number, y: number): Element | null {\n const container = document.getElementById(WIDGET_CONTAINER_ID);\n if (container) container.style.display = 'none';\n const el = document.elementFromPoint(x, y);\n if (container) container.style.display = '';\n if (el && container?.contains(el)) return null;\n return el;\n}\n\nconst DRAG_THRESHOLD = 10;\n\nexport function PickOverlay({ onPick, onCancel }: PickOverlayProps) {\n // Use refs for drag state so event handlers always see current values\n const activeRef = useRef(false);\n const startRef = useRef<{ x: number; y: number } | null>(null);\n const isDragRef = useRef(false);\n\n // State only for rendering (hover highlight and drag rectangle)\n const [hoverRect, setHoverRect] = useState<Rect | null>(null);\n const [selRect, setSelRect] = useState<{ left: number; top: number; width: number; height: number } | null>(null);\n\n const onPickRef = useRef(onPick);\n onPickRef.current = onPick;\n const onCancelRef = useRef(onCancel);\n onCancelRef.current = onCancel;\n\n useEffect(() => {\n function handleMouseMove(e: MouseEvent) {\n if (activeRef.current && startRef.current) {\n // Dragging\n const dx = Math.abs(e.clientX - startRef.current.x);\n const dy = Math.abs(e.clientY - startRef.current.y);\n if (dx >= DRAG_THRESHOLD || dy >= DRAG_THRESHOLD) {\n isDragRef.current = true;\n }\n\n if (isDragRef.current) {\n setHoverRect(null);\n setSelRect({\n left: Math.min(startRef.current.x, e.clientX),\n top: Math.min(startRef.current.y, e.clientY),\n width: Math.abs(e.clientX - startRef.current.x),\n height: Math.abs(e.clientY - startRef.current.y),\n });\n }\n e.preventDefault();\n } else {\n // Hover — highlight element under cursor\n const el = getElementAtPoint(e.clientX, e.clientY);\n if (el) {\n const r = el.getBoundingClientRect();\n setHoverRect({ x: r.left, y: r.top, width: r.width, height: r.height });\n } else {\n setHoverRect(null);\n }\n }\n }\n\n function handleMouseDown(e: MouseEvent) {\n if (e.button !== 0) return;\n e.preventDefault();\n e.stopPropagation();\n startRef.current = { x: e.clientX, y: e.clientY };\n isDragRef.current = false;\n activeRef.current = true;\n }\n\n function handleMouseUp(e: MouseEvent) {\n if (!activeRef.current || !startRef.current) return;\n e.preventDefault();\n e.stopPropagation();\n\n const start = startRef.current;\n activeRef.current = false;\n startRef.current = null;\n setSelRect(null);\n setHoverRect(null);\n\n if (!isDragRef.current) {\n // Click — select single element\n const el = getElementAtPoint(e.clientX, e.clientY);\n if (el) {\n const r = el.getBoundingClientRect();\n onPickRef.current({ x: r.left, y: r.top, width: r.width, height: r.height }, [el]);\n }\n return;\n }\n\n // Drag — select area\n const x = Math.min(start.x, e.clientX);\n const y = Math.min(start.y, e.clientY);\n const width = Math.abs(e.clientX - start.x);\n const height = Math.abs(e.clientY - start.y);\n\n const rect = { x, y, width, height };\n const elements = getElementsBeneathRect(rect);\n onPickRef.current(rect, elements);\n }\n\n function handleKeyDown(e: KeyboardEvent) {\n if (e.key === 'Escape') {\n activeRef.current = false;\n startRef.current = null;\n setSelRect(null);\n setHoverRect(null);\n onCancelRef.current();\n }\n }\n\n document.addEventListener('mousedown', handleMouseDown, true);\n document.addEventListener('mousemove', handleMouseMove, true);\n document.addEventListener('mouseup', handleMouseUp, true);\n document.addEventListener('keydown', handleKeyDown, true);\n\n return () => {\n document.removeEventListener('mousedown', handleMouseDown, true);\n document.removeEventListener('mousemove', handleMouseMove, true);\n document.removeEventListener('mouseup', handleMouseUp, true);\n document.removeEventListener('keydown', handleKeyDown, true);\n };\n }, []);\n\n return (\n <>\n <div\n style={{\n position: 'fixed',\n top: 0,\n left: 0,\n right: 0,\n bottom: 0,\n zIndex: 99997,\n cursor: 'crosshair',\n }}\n />\n\n <div\n style={{\n position: 'fixed',\n top: 0,\n left: 0,\n right: 0,\n zIndex: 99998,\n background: 'rgba(59, 130, 246, 0.08)',\n padding: '8px 16px',\n textAlign: 'center',\n fontSize: 14,\n color: '#1e40af',\n fontFamily: 'system-ui, sans-serif',\n pointerEvents: 'none',\n }}\n >\n Click an element or drag to select an area. Press <strong>Esc</strong> to cancel.\n </div>\n\n {/* Hover highlight */}\n {hoverRect && (\n <div\n style={{\n position: 'fixed',\n left: hoverRect.x,\n top: hoverRect.y,\n width: hoverRect.width,\n height: hoverRect.height,\n border: '2px solid #3b82f6',\n background: 'rgba(59, 130, 246, 0.08)',\n zIndex: 99998,\n pointerEvents: 'none',\n borderRadius: 2,\n transition: 'all 0.1s ease-out',\n }}\n />\n )}\n\n {/* Drag selection rectangle */}\n {selRect && (\n <div\n style={{\n position: 'fixed',\n left: selRect.left,\n top: selRect.top,\n width: selRect.width,\n height: selRect.height,\n border: '2px dashed #3b82f6',\n background: 'rgba(59, 130, 246, 0.1)',\n zIndex: 99998,\n pointerEvents: 'none',\n borderRadius: 2,\n }}\n />\n )}\n </>\n );\n}\n","import React, { useState } from 'react';\nimport type { Draft, WidgetPosition } from '../types';\nimport type { ApiClient } from '../api/client';\nimport type { UserInfo } from '../hooks/useSession';\nimport { DraftItem } from './DraftItem';\n\ninterface SidePanelProps {\n position: WidgetPosition;\n drafts: Draft[];\n selectedDraftIds: Set<string>;\n onToggleSelect: (id: string) => void;\n onSelectAll: (selected: boolean) => void;\n onUpdateDraft: (id: string, comment: string) => void;\n onDeleteDraft: (id: string) => void;\n onSubmit: () => void;\n onClose: () => void;\n api: ApiClient;\n user: UserInfo | null;\n}\n\nexport function SidePanel({\n position,\n drafts,\n selectedDraftIds,\n onToggleSelect,\n onSelectAll,\n onUpdateDraft,\n onDeleteDraft,\n onSubmit,\n onClose,\n api,\n user,\n}: SidePanelProps) {\n const isRight = position.includes('right');\n const allSelected = drafts.length > 0 && selectedDraftIds.size === drafts.length;\n const [screenshotUrls, setScreenshotUrls] = useState<Record<string, string>>({});\n const [previewUrl, setPreviewUrl] = useState<string | null>(null);\n\n // Fetch screenshot URLs for drafts that have them\n React.useEffect(() => {\n const draftsWithScreenshots = drafts.filter((d) => d.screenshotKey && !screenshotUrls[d.id]);\n draftsWithScreenshots.forEach((draft) => {\n api.getScreenshotUrl(draft.id).then((url) => {\n setScreenshotUrls((prev) => ({ ...prev, [draft.id]: url }));\n }).catch(() => {});\n });\n }, [drafts, api]);\n\n const handlePreviewScreenshot = (draftId: string) => {\n const url = screenshotUrls[draftId];\n if (url) setPreviewUrl(url);\n };\n\n return (\n <div\n style={{\n position: 'fixed',\n top: 0,\n [isRight ? 'right' : 'left']: 0,\n width: 360,\n maxWidth: '100vw',\n height: '100vh',\n background: '#fff',\n boxShadow: isRight ? '-4px 0 16px rgba(0,0,0,0.1)' : '4px 0 16px rgba(0,0,0,0.1)',\n zIndex: 99998,\n display: 'flex',\n flexDirection: 'column',\n fontFamily: 'system-ui, sans-serif',\n }}\n >\n {/* Header */}\n <div\n style={{\n padding: '16px 16px 12px',\n borderBottom: '1px solid #e5e7eb',\n }}\n >\n <div style={{ display: 'flex', justifyContent: 'space-between', alignItems: 'center' }}>\n <h3 style={{ margin: 0, fontSize: 15, fontWeight: 600 }}>Feedback Session</h3>\n <button\n onClick={onClose}\n style={{\n background: 'none',\n border: 'none',\n fontSize: 18,\n cursor: 'pointer',\n color: '#6b7280',\n padding: '0 4px',\n }}\n >\n x\n </button>\n </div>\n {user && (\n <div style={{ marginTop: 6, fontSize: 12, color: '#6b7280', lineHeight: 1.4 }}>\n <div style={{ fontWeight: 500, color: '#374151' }}>{user.name}</div>\n <div>{user.email}</div>\n </div>\n )}\n </div>\n\n {/* Draft List */}\n <div style={{ flex: 1, overflow: 'auto' }}>\n {drafts.length === 0 ? (\n <div style={{ padding: 24, textAlign: 'center', color: '#9ca3af', fontSize: 13 }}>\n No drafts yet. Pick an element to start.\n </div>\n ) : (\n drafts.map((draft) => (\n <DraftItem\n key={draft.id}\n draft={draft}\n selected={selectedDraftIds.has(draft.id)}\n screenshotUrl={screenshotUrls[draft.id] || null}\n onToggleSelect={onToggleSelect}\n onUpdate={onUpdateDraft}\n onDelete={onDeleteDraft}\n onPreviewScreenshot={handlePreviewScreenshot}\n />\n ))\n )}\n </div>\n\n {/* Footer */}\n {drafts.length > 0 && (\n <div\n style={{\n padding: '12px 16px',\n borderTop: '1px solid #e5e7eb',\n display: 'flex',\n alignItems: 'center',\n gap: 12,\n }}\n >\n <label style={{ display: 'flex', alignItems: 'center', gap: 6, fontSize: 13, cursor: 'pointer', whiteSpace: 'nowrap' }}>\n <input\n type=\"checkbox\"\n checked={allSelected}\n onChange={(e) => onSelectAll(e.target.checked)}\n />\n Select All\n </label>\n <button\n onClick={onSubmit}\n disabled={selectedDraftIds.size === 0}\n style={{\n flex: 1,\n padding: '8px 12px',\n borderRadius: 6,\n border: 'none',\n background: selectedDraftIds.size === 0 ? '#93c5fd' : '#3b82f6',\n color: '#fff',\n fontSize: 13,\n fontWeight: 500,\n cursor: selectedDraftIds.size === 0 ? 'default' : 'pointer',\n }}\n >\n Submit Feedback ({selectedDraftIds.size})\n </button>\n </div>\n )}\n\n {/* Screenshot Preview Modal */}\n {previewUrl && (\n <div\n onClick={() => setPreviewUrl(null)}\n style={{\n position: 'fixed',\n top: 0,\n left: 0,\n right: 0,\n bottom: 0,\n background: 'rgba(0,0,0,0.6)',\n zIndex: 99999,\n display: 'flex',\n alignItems: 'center',\n justifyContent: 'center',\n }}\n >\n <div\n onClick={(e) => e.stopPropagation()}\n style={{\n background: '#fff',\n borderRadius: 8,\n padding: 8,\n maxWidth: '90vw',\n maxHeight: '90vh',\n position: 'relative',\n }}\n >\n <button\n onClick={() => setPreviewUrl(null)}\n style={{\n position: 'absolute',\n top: 4,\n right: 8,\n background: 'none',\n border: 'none',\n fontSize: 18,\n cursor: 'pointer',\n color: '#6b7280',\n zIndex: 1,\n }}\n >\n x\n </button>\n <img\n src={previewUrl}\n alt=\"Screenshot preview\"\n style={{ maxWidth: '85vw', maxHeight: '85vh', display: 'block', borderRadius: 4 }}\n />\n </div>\n </div>\n )}\n </div>\n );\n}\n","import React, { useState } from 'react';\nimport type { Draft } from '../types';\n\ninterface DraftItemProps {\n draft: Draft;\n selected: boolean;\n screenshotUrl: string | null;\n onToggleSelect: (id: string) => void;\n onUpdate: (id: string, comment: string) => void;\n onDelete: (id: string) => void;\n onPreviewScreenshot: (draftId: string) => void;\n}\n\nexport function DraftItem({ draft, selected, screenshotUrl, onToggleSelect, onUpdate, onDelete, onPreviewScreenshot }: DraftItemProps) {\n const [editing, setEditing] = useState(false);\n const [editComment, setEditComment] = useState(draft.comment);\n const [confirmDelete, setConfirmDelete] = useState(false);\n\n const handleSaveEdit = () => {\n if (editComment.trim()) {\n onUpdate(draft.id, editComment.trim());\n }\n setEditing(false);\n };\n\n const truncatedPath = draft.componentPath.length > 50\n ? '...' + draft.componentPath.slice(-47)\n : draft.componentPath;\n\n return (\n <div\n style={{\n padding: '10px 12px',\n borderBottom: '1px solid #e5e7eb',\n fontSize: 13,\n fontFamily: 'system-ui, sans-serif',\n }}\n >\n <div style={{ display: 'flex', alignItems: 'flex-start', gap: 8 }}>\n <input\n type=\"checkbox\"\n checked={selected}\n onChange={() => onToggleSelect(draft.id)}\n style={{ marginTop: 3, cursor: 'pointer' }}\n />\n <div style={{ flex: 1, minWidth: 0 }}>\n <div style={{ color: '#6b7280', fontSize: 11, marginBottom: 2 }} title={draft.componentPath}>\n {truncatedPath}\n </div>\n <div style={{ color: '#9ca3af', fontSize: 11, marginBottom: 4 }} title={draft.url}>\n {draft.url.length > 60 ? draft.url.slice(0, 60) + '...' : draft.url}\n </div>\n\n {screenshotUrl && (\n <img\n src={screenshotUrl}\n alt=\"Screenshot\"\n onClick={() => onPreviewScreenshot(draft.id)}\n style={{\n width: '100%',\n maxHeight: 160,\n objectFit: 'cover',\n borderRadius: 4,\n border: '1px solid #e5e7eb',\n cursor: 'pointer',\n marginBottom: 6,\n }}\n title=\"Click to enlarge\"\n />\n )}\n\n {editing ? (\n <div>\n <textarea\n value={editComment}\n onChange={(e) => setEditComment(e.target.value)}\n autoFocus\n style={{\n width: '100%',\n minHeight: 48,\n padding: 6,\n borderRadius: 4,\n border: '1px solid #d1d5db',\n fontSize: 13,\n resize: 'vertical',\n boxSizing: 'border-box',\n }}\n />\n <div style={{ display: 'flex', gap: 4, marginTop: 4 }}>\n <button onClick={handleSaveEdit} style={smallBtn('#3b82f6', '#fff')}>Save</button>\n <button onClick={() => { setEditing(false); setEditComment(draft.comment); }} style={smallBtn('#f3f4f6', '#374151')}>Cancel</button>\n </div>\n </div>\n ) : (\n <div\n onClick={() => setEditing(true)}\n style={{ cursor: 'pointer', color: '#1f2937', lineHeight: 1.4 }}\n title=\"Click to edit\"\n >\n {draft.comment}\n </div>\n )}\n </div>\n\n <div style={{ flexShrink: 0 }}>\n {confirmDelete ? (\n <div style={{ display: 'flex', gap: 4, fontSize: 12 }}>\n <button onClick={() => onDelete(draft.id)} style={smallBtn('#ef4444', '#fff')}>Yes</button>\n <button onClick={() => setConfirmDelete(false)} style={smallBtn('#f3f4f6', '#374151')}>No</button>\n </div>\n ) : (\n <button\n onClick={() => setConfirmDelete(true)}\n style={{\n background: 'none',\n border: 'none',\n cursor: 'pointer',\n color: '#9ca3af',\n fontSize: 16,\n padding: '0 4px',\n }}\n title=\"Delete draft\"\n >\n x\n </button>\n )}\n </div>\n </div>\n </div>\n );\n}\n\nfunction smallBtn(bg: string, color: string): React.CSSProperties {\n return {\n padding: '3px 8px',\n borderRadius: 4,\n border: '1px solid #d1d5db',\n background: bg,\n color,\n fontSize: 12,\n cursor: 'pointer',\n };\n}\n","import React, { useState, useEffect } from 'react';\nimport type { CapturedContext } from '../types';\n\nconst WIDGET_CONTAINER_ID = 'llm-ui-feedback-root';\n\ninterface DraftModalProps {\n pendingContext: { context: CapturedContext; screenshot: string | null };\n addingDraft: boolean;\n onAdd: (comment: string) => void;\n onCancel: () => void;\n}\n\nexport function DraftModal({ pendingContext, addingDraft, onAdd, onCancel }: DraftModalProps) {\n const [comment, setComment] = useState('');\n\n // Disable focus traps from host app modals (e.g. MUI Dialog) while our modal is open\n useEffect(() => {\n const container = document.getElementById(WIDGET_CONTAINER_ID);\n const inerted: Element[] = [];\n\n // Set inert on all top-level body children except the widget container\n for (const child of Array.from(document.body.children)) {\n if (child === container || child.id === WIDGET_CONTAINER_ID) continue;\n if (!child.hasAttribute('inert')) {\n child.setAttribute('inert', '');\n inerted.push(child);\n }\n }\n\n return () => {\n for (const el of inerted) {\n el.removeAttribute('inert');\n }\n };\n }, []);\n\n const handleAdd = () => {\n if (comment.trim() && !addingDraft) {\n onAdd(comment.trim());\n }\n };\n\n const { context, screenshot } = pendingContext;\n\n return (\n <div\n style={{\n position: 'fixed',\n inset: 0,\n zIndex: 99999,\n display: 'flex',\n alignItems: 'center',\n justifyContent: 'center',\n background: 'rgba(0,0,0,0.4)',\n fontFamily: 'system-ui, sans-serif',\n }}\n onClick={(e) => {\n if (e.target === e.currentTarget && !addingDraft) onCancel();\n }}\n >\n <div\n style={{\n background: '#fff',\n borderRadius: 12,\n padding: 24,\n width: 480,\n maxWidth: '90vw',\n maxHeight: '85vh',\n overflow: 'auto',\n boxShadow: '0 8px 32px rgba(0,0,0,0.2)',\n }}\n >\n <h3 style={{ margin: '0 0 16px', fontSize: 16 }}>New Feedback</h3>\n\n <div style={{ fontSize: 12, color: '#6b7280', marginBottom: 12 }}>\n <div><strong>Component:</strong> {context.componentPath}</div>\n <div><strong>Path:</strong> {context.urlPath}</div>\n {context.elementText && (\n <div><strong>Element:</strong> &quot;{context.elementText.slice(0, 80)}&quot;</div>\n )}\n </div>\n\n {screenshot && (\n <img\n src={screenshot}\n alt=\"Screenshot\"\n style={{\n width: '100%',\n borderRadius: 8,\n border: '1px solid #e5e7eb',\n marginBottom: 12,\n maxHeight: 180,\n objectFit: 'cover',\n }}\n />\n )}\n\n <textarea\n value={comment}\n onChange={(e) => setComment(e.target.value)}\n placeholder=\"Describe the issue or suggestion...\"\n autoFocus\n onKeyDown={(e) => {\n if (e.key === 'Enter' && (e.metaKey || e.ctrlKey)) handleAdd();\n }}\n style={{\n width: '100%',\n minHeight: 80,\n padding: 10,\n borderRadius: 8,\n border: '1px solid #d1d5db',\n fontSize: 14,\n resize: 'vertical',\n boxSizing: 'border-box',\n }}\n />\n\n <div style={{ display: 'flex', gap: 8, marginTop: 16, justifyContent: 'flex-end' }}>\n <button\n onClick={onCancel}\n disabled={addingDraft}\n style={{\n padding: '8px 16px',\n borderRadius: 6,\n border: '1px solid #d1d5db',\n background: '#f3f4f6',\n color: '#374151',\n fontSize: 13,\n cursor: 'pointer',\n }}\n >\n Cancel\n </button>\n <button\n onClick={handleAdd}\n disabled={!comment.trim() || addingDraft}\n style={{\n padding: '8px 16px',\n borderRadius: 6,\n border: 'none',\n background: !comment.trim() || addingDraft ? '#93c5fd' : '#3b82f6',\n color: '#fff',\n fontSize: 13,\n cursor: !comment.trim() || addingDraft ? 'default' : 'pointer',\n }}\n >\n {addingDraft ? 'Adding...' : 'Add to Drafts'}\n </button>\n </div>\n </div>\n </div>\n );\n}\n","import React, { useState } from 'react';\n\ninterface SubmitModalProps {\n count: number;\n onSubmit: (title: string) => void;\n onCancel: () => void;\n submitting: boolean;\n}\n\nexport function SubmitModal({ count, onSubmit, onCancel, submitting }: SubmitModalProps) {\n const [title, setTitle] = useState('');\n\n const handleSubmit = () => {\n if (title.trim() && !submitting) {\n onSubmit(title.trim());\n }\n };\n\n return (\n <div\n style={{\n position: 'fixed',\n inset: 0,\n zIndex: 99999,\n display: 'flex',\n alignItems: 'center',\n justifyContent: 'center',\n background: 'rgba(0,0,0,0.4)',\n fontFamily: 'system-ui, sans-serif',\n }}\n onClick={(e) => {\n if (e.target === e.currentTarget && !submitting) onCancel();\n }}\n >\n <div\n style={{\n background: '#fff',\n borderRadius: 12,\n padding: 24,\n width: 400,\n maxWidth: '90vw',\n boxShadow: '0 8px 32px rgba(0,0,0,0.2)',\n }}\n >\n <h3 style={{ margin: '0 0 16px', fontSize: 16 }}>Submit Feedback</h3>\n <p style={{ margin: '0 0 12px', fontSize: 14, color: '#6b7280' }}>\n {count} item{count !== 1 ? 's' : ''} selected. Name this feedback session:\n </p>\n <input\n type=\"text\"\n value={title}\n onChange={(e) => setTitle(e.target.value)}\n placeholder=\"e.g. Homepage redesign feedback\"\n autoFocus\n onKeyDown={(e) => { if (e.key === 'Enter') handleSubmit(); }}\n style={{\n width: '100%',\n padding: 10,\n borderRadius: 8,\n border: '1px solid #d1d5db',\n fontSize: 14,\n boxSizing: 'border-box',\n }}\n />\n <div style={{ display: 'flex', gap: 8, marginTop: 16, justifyContent: 'flex-end' }}>\n <button\n onClick={onCancel}\n disabled={submitting}\n style={{\n padding: '8px 16px',\n borderRadius: 6,\n border: '1px solid #d1d5db',\n background: '#f3f4f6',\n color: '#374151',\n fontSize: 13,\n cursor: 'pointer',\n }}\n >\n Cancel\n </button>\n <button\n onClick={handleSubmit}\n disabled={!title.trim() || submitting}\n style={{\n padding: '8px 16px',\n borderRadius: 6,\n border: 'none',\n background: !title.trim() || submitting ? '#93c5fd' : '#3b82f6',\n color: '#fff',\n fontSize: 13,\n cursor: !title.trim() || submitting ? 'default' : 'pointer',\n }}\n >\n {submitting ? 'Submitting...' : 'Submit'}\n </button>\n </div>\n </div>\n </div>\n );\n}\n","import { ComponentInfo } from '../types';\n\nlet minificationWarned = false;\n\nfunction getFiber(el: Element): any | null {\n const key = Object.keys(el).find((k) => k.startsWith('__reactFiber$'));\n return key ? (el as any)[key] : null;\n}\n\nfunction pickShortProps(props: Record<string, unknown>): Record<string, unknown> {\n const short: Record<string, unknown> = {};\n for (const [key, value] of Object.entries(props)) {\n if (key === 'children') continue;\n if (typeof value === 'function') continue;\n if (typeof value === 'string' || typeof value === 'number' || typeof value === 'boolean') {\n short[key] = value;\n }\n }\n return short;\n}\n\nexport function getComponentPath(el: Element, maxDepth = 8): ComponentInfo[] {\n const fiber = getFiber(el);\n if (!fiber) return [];\n\n const path: ComponentInfo[] = [];\n let current = fiber;\n\n while (current && path.length < maxDepth) {\n if (typeof current.type === 'function' || typeof current.type === 'object') {\n const name =\n current.type?.displayName || current.type?.name || null;\n if (name) {\n // Detect minified names: single-char lowercase names are typical minifier output\n if (\n !minificationWarned &&\n name.length <= 2 &&\n /^[a-z]/.test(name)\n ) {\n minificationWarned = true;\n console.warn(\n '[llm-ui-feedback] Component names appear minified (e.g., \"' +\n name +\n '\"). The generated LLM prompts will lack meaningful component paths. ' +\n 'To fix, configure your bundler to preserve function names. ' +\n 'See: https://github.com/user/llm-ui-feedback/blob/main/docs/production-setup.md'\n );\n }\n path.push({\n name,\n props: pickShortProps(current.memoizedProps || {}),\n });\n }\n }\n current = current.return;\n }\n\n return path.reverse();\n}\n","import html2canvas from 'html2canvas-pro';\n\nexport interface ScreenshotRect {\n x: number;\n y: number;\n width: number;\n height: number;\n}\n\nexport async function captureScreenshot(rect: ScreenshotRect): Promise<string> {\n const fullCanvas = await html2canvas(document.body, {\n logging: false,\n useCORS: true,\n });\n\n // Convert viewport coords to document coords\n const docX = rect.x + window.scrollX;\n const docY = rect.y + window.scrollY;\n\n // html2canvas may scale the canvas vs the document — compute ratio\n const scaleX = fullCanvas.width / document.documentElement.scrollWidth;\n const scaleY = fullCanvas.height / document.documentElement.scrollHeight;\n\n const sx = Math.round(docX * scaleX);\n const sy = Math.round(docY * scaleY);\n const sw = Math.round(rect.width * scaleX);\n const sh = Math.round(rect.height * scaleY);\n\n // Crop to the selected region\n const cropped = document.createElement('canvas');\n cropped.width = sw;\n cropped.height = sh;\n const ctx = cropped.getContext('2d');\n if (ctx) {\n ctx.drawImage(fullCanvas, sx, sy, sw, sh, 0, 0, sw, sh);\n\n // Draw a blue border to indicate the selection\n ctx.strokeStyle = '#3b82f6';\n ctx.lineWidth = 3;\n ctx.strokeRect(1, 1, sw - 2, sh - 2);\n }\n\n return cropped.toDataURL('image/png');\n}\n","import { CapturedContext } from '../types';\n\nexport function buildPrompt(context: CapturedContext, comment: string): string {\n const propsStr = context.components\n .filter((c) => Object.keys(c.props).length > 0)\n .map((c) => ` ${c.name}: ${JSON.stringify(c.props)}`)\n .join('\\n');\n\n const lines = [\n `Page: ${context.url}`,\n `Path: ${context.urlPath}`,\n `Reported at: ${context.reportedAt}`,\n `Component: ${context.componentPath}`,\n ];\n\n if (propsStr) {\n lines.push(`Props:\\n${propsStr}`);\n }\n\n if (context.elementText) {\n lines.push(`Element text: \"${context.elementText}\"`);\n }\n\n lines.push('', `User feedback: \"${comment}\"`, '', 'Screenshot attached showing the selected region.');\n\n return lines.join('\\n');\n}\n","export function dataUrlToBlob(dataUrl: string): Blob {\n const [header, base64] = dataUrl.split(',');\n const mime = header.match(/:(.*?);/)?.[1] || 'image/png';\n const binary = atob(base64);\n const bytes = new Uint8Array(binary.length);\n for (let i = 0; i < binary.length; i++) {\n bytes[i] = binary.charCodeAt(i);\n }\n return new Blob([bytes], { type: mime });\n}\n","import { useState, useEffect, useCallback, useRef } from 'react';\n\nconst SESSION_TOKEN_KEY = 'llm_feedback_session_token';\nconst USER_KEY = 'llm_feedback_user';\n\n// Check for auth bypass flag.\n// globalThis.__FEEDBACK_AUTH_BYPASS__ works in any context (CJS/ESM).\n// Vite consumers get automatic support because Vite statically replaces\n// import.meta.env.VITE_AUTH_BYPASS at build time in the ESM bundle.\nconst AUTH_BYPASS = !!(typeof globalThis !== 'undefined' && (globalThis as any).__FEEDBACK_AUTH_BYPASS__);\n\nexport interface UserInfo {\n email: string;\n name: string;\n picture: string;\n sub: string;\n}\n\nexport interface SessionState {\n status: 'loading' | 'unauthenticated' | 'authenticated';\n user: UserInfo | null;\n signIn: () => void;\n signOut: () => void;\n}\n\nexport function getSessionToken(): string | null {\n if (AUTH_BYPASS) return 'bypass-token';\n return localStorage.getItem(SESSION_TOKEN_KEY);\n}\n\nconst BYPASS_USER: UserInfo = {\n email: 'bypass@test.local',\n name: 'Bypass User',\n picture: '',\n sub: 'bypass-user',\n};\n\nexport function useSession(apiUrl: string, clientId: string): SessionState {\n const [status, setStatus] = useState<SessionState['status']>(AUTH_BYPASS ? 'authenticated' : 'loading');\n const [user, setUser] = useState<UserInfo | null>(AUTH_BYPASS ? BYPASS_USER : null);\n const pendingAuthRef = useRef(false);\n\n // On mount: check localStorage for existing session\n useEffect(() => {\n if (AUTH_BYPASS) return;\n let cancelled = false;\n\n async function checkSession() {\n const token = localStorage.getItem(SESSION_TOKEN_KEY);\n const savedUser = localStorage.getItem(USER_KEY);\n\n if (!token || !savedUser) {\n if (!cancelled) setStatus('unauthenticated');\n return;\n }\n\n try {\n const res = await fetch(`${apiUrl}/auth/status`, {\n headers: { 'X-Session-Token': token },\n });\n const data = await res.json();\n\n if (!cancelled) {\n if (data.authenticated) {\n setUser(data.user);\n setStatus('authenticated');\n } else {\n localStorage.removeItem(SESSION_TOKEN_KEY);\n localStorage.removeItem(USER_KEY);\n setStatus('unauthenticated');\n }\n }\n } catch {\n if (!cancelled) {\n // Network error — use cached user optimistically\n try {\n setUser(JSON.parse(savedUser));\n setStatus('authenticated');\n } catch {\n setStatus('unauthenticated');\n }\n }\n }\n }\n\n checkSession();\n return () => { cancelled = true; };\n }, [apiUrl]);\n\n // Listen for postMessage from auth popup\n useEffect(() => {\n function handleMessage(event: MessageEvent) {\n if (event.data?.type !== 'feedback-auth') return;\n const { sessionToken, user: userData } = event.data;\n if (sessionToken && userData) {\n localStorage.setItem(SESSION_TOKEN_KEY, sessionToken);\n localStorage.setItem(USER_KEY, JSON.stringify(userData));\n setUser(userData);\n setStatus('authenticated');\n pendingAuthRef.current = false;\n }\n }\n\n window.addEventListener('message', handleMessage);\n return () => window.removeEventListener('message', handleMessage);\n }, []);\n\n const signIn = useCallback(() => {\n if (pendingAuthRef.current) return;\n pendingAuthRef.current = true;\n\n const loginUrl = `${apiUrl}/auth/login?clientId=${encodeURIComponent(clientId)}&origin=${encodeURIComponent(window.location.origin)}`;\n const popup = window.open(loginUrl, 'feedback-auth', 'width=500,height=600,menubar=no,toolbar=no');\n\n if (!popup) {\n // Popup blocked — can't do much, reset flag\n pendingAuthRef.current = false;\n return;\n }\n\n // Poll for popup closed (user cancelled)\n const interval = setInterval(() => {\n if (popup.closed) {\n clearInterval(interval);\n pendingAuthRef.current = false;\n }\n }, 500);\n }, [apiUrl, clientId]);\n\n const signOut = useCallback(async () => {\n const token = localStorage.getItem(SESSION_TOKEN_KEY);\n localStorage.removeItem(SESSION_TOKEN_KEY);\n localStorage.removeItem(USER_KEY);\n setUser(null);\n setStatus('unauthenticated');\n\n if (token) {\n try {\n await fetch(`${apiUrl}/auth/logout`, {\n method: 'POST',\n headers: { 'X-Session-Token': token },\n });\n } catch {\n // Best-effort logout\n }\n }\n }, [apiUrl]);\n\n return { status, user, signIn, signOut };\n}\n","import type { Draft, FeedbackGroup } from '../types';\nimport { getSessionToken } from '../hooks/useSession';\n\nexport interface DraftPayload {\n id: string;\n url: string;\n componentPath: string;\n components: { name: string; props: Record<string, unknown> }[];\n elementText: string;\n comment: string;\n prompt: string;\n screenshotKey?: string;\n}\n\nexport interface ApiClient {\n fetchDrafts(): Promise<Draft[]>;\n createDraft(draft: DraftPayload): Promise<Draft>;\n updateDraft(id: string, data: { comment: string }): Promise<Draft>;\n deleteDraft(id: string): Promise<void>;\n submitSession(data: { title: string; draftIds: string[] }): Promise<{ feedbackGroup: FeedbackGroup; entriesCreated: number }>;\n getUploadUrl(\n entryId: string,\n timestamp: string,\n ): Promise<{ uploadUrl: string; key: string }>;\n uploadScreenshot(uploadUrl: string, blob: Blob): Promise<void>;\n getScreenshotUrl(draftId: string): Promise<string>;\n}\n\nexport function createApiClient(apiUrl: string, clientId: string): ApiClient {\n async function apiFetch(path: string, options: RequestInit = {}) {\n const token = getSessionToken();\n const res = await fetch(`${apiUrl}${path}`, {\n ...options,\n headers: {\n 'Content-Type': 'application/json',\n ...(token ? { 'X-Session-Token': token } : {}),\n 'X-Client-Id': clientId,\n ...(options.headers as Record<string, string> | undefined),\n },\n });\n if (!res.ok) {\n const body = await res.json().catch(() => ({}));\n throw new Error(\n (body as Record<string, string>).error ||\n `API error ${res.status}`,\n );\n }\n if (res.status === 204) return undefined;\n return res.json();\n }\n\n return {\n async fetchDrafts() {\n const data = await apiFetch('/drafts');\n return (data as { items: Draft[] }).items;\n },\n\n async createDraft(draft: DraftPayload) {\n return apiFetch('/drafts', {\n method: 'POST',\n body: JSON.stringify(draft),\n }) as Promise<Draft>;\n },\n\n async updateDraft(id: string, data: { comment: string }) {\n return apiFetch(`/drafts/${id}`, {\n method: 'PATCH',\n body: JSON.stringify(data),\n }) as Promise<Draft>;\n },\n\n async deleteDraft(id: string) {\n await apiFetch(`/drafts/${id}`, { method: 'DELETE' });\n },\n\n async submitSession(data: { title: string; draftIds: string[] }) {\n return apiFetch('/feedback-groups/submit', {\n method: 'POST',\n body: JSON.stringify(data),\n }) as Promise<{ feedbackGroup: FeedbackGroup; entriesCreated: number }>;\n },\n\n async getUploadUrl(entryId: string, timestamp: string) {\n return apiFetch('/upload-url', {\n method: 'POST',\n body: JSON.stringify({ entryId, timestamp }),\n }) as Promise<{ uploadUrl: string; key: string }>;\n },\n\n async getScreenshotUrl(draftId: string) {\n const data = await apiFetch(`/drafts/${draftId}/screenshot-url`);\n return (data as { url: string }).url;\n },\n\n async uploadScreenshot(uploadUrl: string, blob: Blob) {\n const res = await fetch(uploadUrl, {\n method: 'PUT',\n body: blob,\n headers: { 'Content-Type': 'image/png' },\n });\n if (!res.ok) throw new Error(`S3 upload failed: ${res.status}`);\n },\n };\n}\n"],"mappings":"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","names":["useCallback","useEffect","useRef","jsx","jsxs","React","useState","useState","jsx","jsxs","jsx","jsxs","useState","React","useState","useEffect","jsx","jsxs","WIDGET_CONTAINER_ID","useState","jsx","jsxs","useState","useEffect","useCallback","useRef","Fragment","jsx","jsxs","useRef","useEffect","useCallback"]}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@david-xpn/llm-ui-feedback",
3
- "version": "0.1.2",
3
+ "version": "0.1.4",
4
4
  "description": "Drop-in React feedback widget that captures component context for LLM consumption",
5
5
  "license": "MIT",
6
6
  "author": "david-xpn",