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

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.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);
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","../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.\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","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"]}
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);
@@ -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","../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.\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","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"]}
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.3",
4
4
  "description": "Drop-in React feedback widget that captures component context for LLM consumption",
5
5
  "license": "MIT",
6
6
  "author": "david-xpn",