@david-xpn/llm-ui-feedback 0.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -0,0 +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/FeedbackDialog.tsx","../src/utils/prompt.ts","../src/utils/storage.ts","../src/components/FeedbackListPanel.tsx","../src/utils/time.ts","../src/components/EntryCard.tsx","../src/components/ListButton.tsx","../src/utils/fiber.ts","../src/utils/screenshot.ts"],"sourcesContent":["export { FeedbackWidget } from './components/FeedbackWidget';\nexport type { FeedbackWidgetProps } from './components/FeedbackWidget';\nexport { loadEntries, deleteEntry, clearEntries } from './utils/storage';\nexport type { FeedbackEntry, CapturedContext, ComponentInfo, WidgetPosition } from './types';\n","import React, { useReducer, useCallback, useState, useEffect } from 'react';\nimport { createPortal } from 'react-dom';\nimport { FloatingButton } from './FloatingButton';\nimport { PickOverlay } from './PickOverlay';\nimport { FeedbackDialog } from './FeedbackDialog';\nimport { FeedbackListPanel } from './FeedbackListPanel';\nimport { ListButton } from './ListButton';\nimport { getComponentPath } from '../utils/fiber';\nimport { captureScreenshot } from '../utils/screenshot';\nimport { loadEntries } from '../utils/storage';\nimport { CapturedContext, 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 /** Corner position for the floating buttons. Default: 'bottom-right' */\n position?: WidgetPosition;\n /** Hex color for the FAB and badge accent. Default: '#3b82f6' */\n buttonColor?: string;\n /** Keyboard shortcut to toggle pick mode, e.g. 'Alt+F'. No default (opt-in only). */\n hotkey?: string;\n}\n\ntype WidgetState =\n | { mode: 'idle' }\n | { mode: 'picking' }\n | { mode: 'dialog'; context: CapturedContext; screenshot: string | null }\n | { mode: 'list' };\n\ntype WidgetAction =\n | { type: 'START_PICKING' }\n | { type: 'CANCEL' }\n | { type: 'ELEMENT_PICKED'; context: CapturedContext; screenshot: string | null }\n | { type: 'OPEN_LIST' }\n | { type: 'CLOSE' };\n\nfunction widgetReducer(state: WidgetState, action: WidgetAction): WidgetState {\n switch (action.type) {\n case 'START_PICKING':\n return state.mode === 'idle' ? { mode: 'picking' } : state;\n case 'CANCEL':\n case 'CLOSE':\n return { mode: 'idle' };\n case 'ELEMENT_PICKED':\n return { mode: 'dialog', context: action.context, screenshot: action.screenshot };\n case 'OPEN_LIST':\n return state.mode === 'idle' ? { mode: 'list' } : state;\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 position = 'bottom-right',\n buttonColor = '#3b82f6',\n hotkey,\n}: FeedbackWidgetProps = {}) {\n const [state, dispatch] = useReducer(widgetReducer, { mode: 'idle' });\n const [entryCount, setEntryCount] = useState(0);\n\n // Refresh count whenever we return to idle (after save, delete, clear, or close)\n useEffect(() => {\n if (state.mode === 'idle') {\n setEntryCount(loadEntries().length);\n }\n }, [state.mode]);\n\n // Also load count on mount\n useEffect(() => {\n setEntryCount(loadEntries().length);\n }, []);\n\n // Hotkey listener\n useEffect(() => {\n if (!hotkey) return;\n const parsed = parseHotkey(hotkey);\n\n function handler(e: KeyboardEvent) {\n // Don't fire when user is typing in an input\n if (isEditableTarget(document.activeElement)) return;\n\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(\n state.mode === 'picking'\n ? { type: 'CANCEL' }\n : state.mode === 'idle'\n ? { type: 'START_PICKING' }\n : { type: 'CLOSE' }\n );\n }\n }\n\n window.addEventListener('keydown', handler);\n return () => window.removeEventListener('keydown', handler);\n }, [hotkey, state.mode]);\n\n const handleToggle = useCallback(() => {\n dispatch({ type: 'START_PICKING' });\n }, []);\n\n const handlePick = useCallback(async (element: Element, x: number, y: number) => {\n const components = getComponentPath(element);\n const componentPath = components.map((c) => c.name).join(' > ') || '(no React component found)';\n const rawText = ((element as HTMLElement).innerText || element.textContent || '').trim();\n const elementText = rawText.length > 100 ? rawText.slice(0, 100) + '...' : rawText;\n\n const context: CapturedContext = {\n url: window.location.href,\n componentPath,\n components,\n elementText,\n clickX: x,\n clickY: y,\n };\n\n let screenshot: string | null = null;\n try {\n screenshot = await captureScreenshot(x, y);\n } catch {\n // Screenshot failed — continue without it\n }\n\n dispatch({ type: 'ELEMENT_PICKED', context, screenshot });\n }, []);\n\n const handleCancel = useCallback(() => {\n dispatch({ type: 'CANCEL' });\n }, []);\n\n const handleClose = useCallback(() => {\n dispatch({ type: 'CLOSE' });\n }, []);\n\n const handleOpenList = useCallback(() => {\n dispatch({ type: 'OPEN_LIST' });\n }, []);\n\n const handleCloseList = useCallback(() => {\n dispatch({ type: 'CLOSE' });\n }, []);\n\n return createPortal(\n <>\n {state.mode === 'idle' && (\n <ListButton\n onClick={handleOpenList}\n count={entryCount}\n position={position}\n buttonColor={buttonColor}\n />\n )}\n <FloatingButton\n onClick={state.mode === 'picking' ? handleCancel : handleToggle}\n active={state.mode === 'picking'}\n position={position}\n buttonColor={buttonColor}\n />\n {state.mode === 'picking' && <PickOverlay onPick={handlePick} onCancel={handleCancel} />}\n {state.mode === 'dialog' && (\n <FeedbackDialog context={state.context} screenshot={state.screenshot} onClose={handleClose} />\n )}\n {state.mode === 'list' && (\n <FeedbackListPanel onClose={handleCloseList} position={position} />\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 onClick: () => void;\n active: boolean;\n position: WidgetPosition;\n buttonColor: string;\n}\n\nexport function FloatingButton({ onClick, active, position, buttonColor }: FloatingButtonProps) {\n const isBottom = position.includes('bottom');\n const isRight = position.includes('right');\n\n return (\n <button\n onClick={onClick}\n aria-label={active ? 'Cancel feedback' : 'Add feedback'}\n style={{\n position: 'fixed',\n [isBottom ? 'bottom' : 'top']: 24,\n [isRight ? 'right' : 'left']: 24,\n zIndex: 99999,\n width: 48,\n height: 48,\n borderRadius: '50%',\n border: 'none',\n background: active ? '#ef4444' : buttonColor,\n color: active ? '#fff' : getContrastColor(buttonColor),\n fontSize: 24,\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: active ? 'rotate(45deg)' : 'none',\n }}\n >\n +\n </button>\n );\n}\n","import React, { useCallback, useEffect, useRef } from 'react';\n\nconst WIDGET_CONTAINER_ID = 'llm-ui-feedback-root';\n\nfunction getElementBeneath(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 // Safety: if element is still a widget descendant, return null\n if (el && container?.contains(el)) return null;\n return el;\n}\n\ninterface PickOverlayProps {\n onPick: (element: Element, x: number, y: number) => void;\n onCancel: () => void;\n}\n\nexport function PickOverlay({ onPick, onCancel }: PickOverlayProps) {\n const lastOutlinedRef = useRef<HTMLElement | null>(null);\n\n const clearOutline = useCallback(() => {\n if (lastOutlinedRef.current) {\n lastOutlinedRef.current.style.outline = '';\n lastOutlinedRef.current = null;\n }\n }, []);\n\n const handleMouseMove = useCallback((e: MouseEvent) => {\n const el = getElementBeneath(e.clientX, e.clientY);\n\n // Clear previous outline\n clearOutline();\n\n // Set new outline\n if (el && el instanceof HTMLElement) {\n el.style.outline = '2px solid #3b82f6';\n lastOutlinedRef.current = el;\n }\n }, [clearOutline]);\n\n const handleClick = useCallback(\n (e: MouseEvent) => {\n e.preventDefault();\n e.stopPropagation();\n clearOutline();\n const el = getElementBeneath(e.clientX, e.clientY);\n if (el) {\n onPick(el, e.clientX, e.clientY);\n }\n },\n [onPick, clearOutline]\n );\n\n const handleKeyDown = useCallback(\n (e: KeyboardEvent) => {\n if (e.key === 'Escape') {\n clearOutline();\n onCancel();\n }\n },\n [onCancel, clearOutline]\n );\n\n useEffect(() => {\n document.addEventListener('mousemove', handleMouseMove, true);\n document.addEventListener('click', handleClick, true);\n document.addEventListener('keydown', handleKeyDown, true);\n\n return () => {\n document.removeEventListener('mousemove', handleMouseMove, true);\n document.removeEventListener('click', handleClick, true);\n document.removeEventListener('keydown', handleKeyDown, true);\n // Always clean up outline on unmount\n if (lastOutlinedRef.current) {\n lastOutlinedRef.current.style.outline = '';\n lastOutlinedRef.current = null;\n }\n };\n }, [handleMouseMove, handleClick, handleKeyDown]);\n\n return (\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 on any element to leave feedback. Press <strong>Esc</strong> to cancel.\n </div>\n );\n}\n","import React, { useState } from 'react';\nimport { CapturedContext, FeedbackEntry } from '../types';\nimport { buildPrompt } from '../utils/prompt';\nimport { saveEntry } from '../utils/storage';\n\nasync function copyToClipboard(text: string): Promise<'success' | 'fallback-success' | 'failed'> {\n // Try modern Clipboard API (requires secure context)\n if (navigator.clipboard?.writeText) {\n try {\n await navigator.clipboard.writeText(text);\n return 'success';\n } catch { /* fall through to fallback */ }\n }\n // Fallback: hidden textarea + execCommand for non-HTTPS\n try {\n const textarea = document.createElement('textarea');\n textarea.value = text;\n textarea.style.cssText = 'position:fixed;left:-9999px;top:-9999px';\n document.body.appendChild(textarea);\n textarea.focus();\n textarea.select();\n const ok = document.execCommand('copy');\n document.body.removeChild(textarea);\n if (ok) return 'fallback-success';\n } catch { /* fall through */ }\n return 'failed';\n}\n\ninterface FeedbackDialogProps {\n context: CapturedContext;\n screenshot: string | null;\n onClose: () => void;\n}\n\nexport function FeedbackDialog({ context, screenshot, onClose }: FeedbackDialogProps) {\n const [comment, setComment] = useState('');\n const [saved, setSaved] = useState(false);\n const [copyStatus, setCopyStatus] = useState<'idle' | 'copied' | 'failed'>('idle');\n const [saveError, setSaveError] = useState<string | null>(null);\n const [showPromptText, setShowPromptText] = useState(false);\n\n const handleSubmit = () => {\n if (!comment.trim()) return;\n\n const prompt = buildPrompt(context, comment);\n const entry: FeedbackEntry = {\n id: `f_${Date.now()}`,\n timestamp: new Date().toISOString(),\n url: context.url,\n componentPath: context.componentPath,\n components: context.components,\n elementText: context.elementText,\n comment,\n screenshot,\n prompt,\n };\n\n const result = saveEntry(entry);\n if (result.ok) {\n setSaved(true);\n setSaveError(null);\n } else {\n setSaveError(result.error || 'Failed to save.');\n }\n };\n\n const handleCopyPrompt = async () => {\n const prompt = buildPrompt(context, comment || '(no comment)');\n const result = await copyToClipboard(prompt);\n if (result === 'failed') {\n setCopyStatus('failed');\n setShowPromptText(true);\n } else {\n setCopyStatus('copied');\n setTimeout(() => setCopyStatus('idle'), 2000);\n }\n };\n\n const handleDownloadScreenshot = () => {\n if (!screenshot) return;\n const link = document.createElement('a');\n link.download = `feedback_${Date.now()}.png`;\n link.href = screenshot;\n link.click();\n };\n\n const copyButtonLabel = copyStatus === 'copied' ? 'Copied!' : copyStatus === 'failed' ? 'Copy failed' : 'Copy Prompt';\n const copyButtonBg = copyStatus === 'copied' ? '#dcfce7' : copyStatus === 'failed' ? '#fee2e2' : '#f3f4f6';\n const copyButtonColor = copyStatus === 'copied' ? '#16a34a' : copyStatus === 'failed' ? '#dc2626' : '#374151';\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) onClose();\n }}\n >\n <div\n style={{\n background: '#fff',\n borderRadius: 12,\n padding: 24,\n width: 480,\n maxWidth: '90vw',\n maxHeight: '80vh',\n overflow: 'auto',\n boxShadow: '0 8px 32px rgba(0,0,0,0.2)',\n }}\n >\n <div style={{ display: 'flex', justifyContent: 'space-between', alignItems: 'center', marginBottom: 16 }}>\n <h3 style={{ margin: 0, fontSize: 16 }}>Leave Feedback</h3>\n <button\n onClick={onClose}\n style={{\n background: 'none',\n border: 'none',\n fontSize: 20,\n cursor: 'pointer',\n color: '#666',\n }}\n >\n x\n </button>\n </div>\n\n <div style={{ fontSize: 12, color: '#666', marginBottom: 12 }}>\n <div><strong>Page:</strong> {context.url}</div>\n <div><strong>Component:</strong> {context.componentPath}</div>\n {context.elementText && (\n <div><strong>Element:</strong> \"{context.elementText.slice(0, 100)}\"</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 }}\n />\n )}\n\n {!saved ? (\n <>\n <textarea\n value={comment}\n onChange={(e) => setComment(e.target.value)}\n placeholder=\"Describe the issue or suggestion...\"\n autoFocus\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 {saveError && (\n <div style={{ color: '#dc2626', fontSize: 13, marginTop: 8 }}>\n {saveError}\n </div>\n )}\n <div style={{ display: 'flex', gap: 8, marginTop: 12 }}>\n <button onClick={handleSubmit} style={btnStyle('#3b82f6', '#fff')}>\n Save\n </button>\n <button onClick={handleCopyPrompt} style={btnStyle(copyButtonBg, copyButtonColor)}>\n {copyButtonLabel}\n </button>\n {screenshot && (\n <button onClick={handleDownloadScreenshot} style={btnStyle('#f3f4f6', '#374151')}>\n Download Screenshot\n </button>\n )}\n </div>\n </>\n ) : (\n <div style={{ textAlign: 'center', padding: 16, color: '#16a34a' }}>\n Saved to localStorage.\n <div style={{ display: 'flex', gap: 8, marginTop: 12, justifyContent: 'center' }}>\n <button onClick={handleCopyPrompt} style={btnStyle(copyButtonBg, copyButtonColor)}>\n {copyButtonLabel}\n </button>\n {screenshot && (\n <button onClick={handleDownloadScreenshot} style={btnStyle('#f3f4f6', '#374151')}>\n Download Screenshot\n </button>\n )}\n <button onClick={onClose} style={btnStyle('#3b82f6', '#fff')}>\n Done\n </button>\n </div>\n </div>\n )}\n\n {showPromptText && (\n <div style={{ marginTop: 12 }}>\n <div style={{ fontSize: 12, color: '#666', marginBottom: 4 }}>\n Could not copy automatically. Select and copy manually:\n </div>\n <textarea\n readOnly\n value={buildPrompt(context, comment || '(no comment)')}\n style={{\n width: '100%',\n minHeight: 120,\n padding: 10,\n borderRadius: 8,\n border: '1px solid #d1d5db',\n fontSize: 12,\n fontFamily: 'monospace',\n resize: 'vertical',\n boxSizing: 'border-box',\n background: '#f9fafb',\n }}\n onClick={(e) => (e.target as HTMLTextAreaElement).select()}\n />\n </div>\n )}\n </div>\n </div>\n );\n}\n\nfunction btnStyle(bg: string, color: string): React.CSSProperties {\n return {\n padding: '8px 16px',\n borderRadius: 6,\n border: '1px solid #d1d5db',\n background: bg,\n color,\n fontSize: 13,\n cursor: 'pointer',\n };\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 `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 with red X marking the clicked element.');\n\n return lines.join('\\n');\n}\n","import { FeedbackEntry } from '../types';\n\nconst STORAGE_KEY = 'llm_ui_feedback_items';\n\nexport function loadEntries(): FeedbackEntry[] {\n try {\n const raw = localStorage.getItem(STORAGE_KEY);\n return raw ? JSON.parse(raw) : [];\n } catch {\n return [];\n }\n}\n\nexport function saveEntry(entry: FeedbackEntry): { ok: boolean; error?: string } {\n const entries = loadEntries();\n entries.push(entry);\n try {\n localStorage.setItem(STORAGE_KEY, JSON.stringify(entries));\n return { ok: true };\n } catch (e) {\n if (e instanceof DOMException && (e.name === 'QuotaExceededError' || (e as any).code === 22)) {\n // Fallback: strip screenshot from oldest entry that has one, then retry\n const oldestWithScreenshot = entries.findIndex((ent) => ent.screenshot !== null);\n if (oldestWithScreenshot >= 0) {\n entries[oldestWithScreenshot] = { ...entries[oldestWithScreenshot], screenshot: null };\n try {\n localStorage.setItem(STORAGE_KEY, JSON.stringify(entries));\n return { ok: true };\n } catch {\n // Still over quota even after stripping\n }\n }\n return { ok: false, error: 'Storage is full. Delete old feedback entries to free space.' };\n }\n return { ok: false, error: 'Failed to save feedback entry.' };\n }\n}\n\nexport function deleteEntry(id: string): void {\n const entries = loadEntries().filter((e) => e.id !== id);\n localStorage.setItem(STORAGE_KEY, JSON.stringify(entries));\n}\n\nexport function clearEntries(): void {\n localStorage.removeItem(STORAGE_KEY);\n}\n","import React, { useState, useCallback } from 'react';\nimport { FeedbackEntry } from '../types';\nimport { WidgetPosition } from '../types';\nimport { loadEntries, deleteEntry, clearEntries } from '../utils/storage';\nimport { EntryCard } from './EntryCard';\n\ninterface FeedbackListPanelProps {\n onClose: () => void;\n position: WidgetPosition;\n}\n\nasync function copyToClipboard(text: string): Promise<boolean> {\n if (navigator.clipboard?.writeText) {\n try {\n await navigator.clipboard.writeText(text);\n return true;\n } catch { /* fall through */ }\n }\n try {\n const textarea = document.createElement('textarea');\n textarea.value = text;\n textarea.style.cssText = 'position:fixed;left:-9999px;top:-9999px';\n document.body.appendChild(textarea);\n textarea.focus();\n textarea.select();\n const ok = document.execCommand('copy');\n document.body.removeChild(textarea);\n return ok;\n } catch { /* fall through */ }\n return false;\n}\n\nexport function FeedbackListPanel({ onClose, position }: FeedbackListPanelProps) {\n const [entries, setEntries] = useState<FeedbackEntry[]>(() => loadEntries());\n const [confirmClear, setConfirmClear] = useState(false);\n const [copiedId, setCopiedId] = useState<string | null>(null);\n\n const isRight = position.includes('right');\n\n const refreshEntries = useCallback(() => {\n setEntries(loadEntries());\n }, []);\n\n const handleDelete = useCallback(\n (id: string) => {\n deleteEntry(id);\n refreshEntries();\n },\n [refreshEntries]\n );\n\n const handleCopyPrompt = useCallback(async (prompt: string) => {\n const ok = await copyToClipboard(prompt);\n if (ok) {\n // Brief visual feedback could be added per-card, but for now the action is silent-success\n }\n }, []);\n\n const handleClear = useCallback(() => {\n if (!confirmClear) {\n setConfirmClear(true);\n setTimeout(() => setConfirmClear(false), 3000);\n return;\n }\n clearEntries();\n setConfirmClear(false);\n refreshEntries();\n }, [confirmClear, refreshEntries]);\n\n const sortedEntries = [...entries].reverse();\n\n return (\n <div\n style={{\n position: 'fixed',\n top: 0,\n [isRight ? 'right' : 'left']: 0,\n bottom: 0,\n width: 380,\n maxWidth: '90vw',\n zIndex: 99999,\n background: '#fff',\n boxShadow: isRight\n ? '-4px 0 24px rgba(0,0,0,0.15)'\n : '4px 0 24px rgba(0,0,0,0.15)',\n display: 'flex',\n flexDirection: 'column',\n fontFamily: 'system-ui, sans-serif',\n }}\n >\n {/* Header */}\n <div\n style={{\n padding: 16,\n borderBottom: '1px solid #e5e7eb',\n display: 'flex',\n justifyContent: 'space-between',\n alignItems: 'center',\n flexShrink: 0,\n }}\n >\n <h3 style={{ margin: 0, fontSize: 15, color: '#111827' }}>\n Feedback ({entries.length})\n </h3>\n <button\n onClick={onClose}\n style={{\n background: 'none',\n border: 'none',\n fontSize: 20,\n cursor: 'pointer',\n color: '#666',\n padding: '0 4px',\n }}\n >\n ×\n </button>\n </div>\n\n {/* Content */}\n <div style={{ flex: 1, overflowY: 'auto', padding: 0 }}>\n {sortedEntries.length === 0 ? (\n <div\n style={{\n textAlign: 'center',\n padding: 32,\n color: '#9ca3af',\n fontSize: 13,\n }}\n >\n No feedback entries yet\n </div>\n ) : (\n sortedEntries.map((entry) => (\n <EntryCard\n key={entry.id}\n entry={entry}\n onDelete={handleDelete}\n onCopyPrompt={handleCopyPrompt}\n />\n ))\n )}\n </div>\n\n {/* Footer */}\n <div\n style={{\n padding: '12px 16px',\n borderTop: '1px solid #e5e7eb',\n flexShrink: 0,\n }}\n >\n <button\n onClick={handleClear}\n disabled={entries.length === 0}\n style={{\n width: '100%',\n padding: '8px 16px',\n borderRadius: 6,\n border: '1px solid #d1d5db',\n background: confirmClear ? '#fef2f2' : '#f9fafb',\n color: confirmClear ? '#dc2626' : entries.length === 0 ? '#9ca3af' : '#374151',\n fontSize: 13,\n cursor: entries.length === 0 ? 'default' : 'pointer',\n }}\n >\n {confirmClear ? 'Are you sure? Clear' : 'Clear All'}\n </button>\n </div>\n </div>\n );\n}\n","export function relativeTime(iso: string): string {\n const seconds = Math.floor((Date.now() - new Date(iso).getTime()) / 1000);\n if (seconds < 0) return 'just now';\n if (seconds < 60) return 'just now';\n const minutes = Math.floor(seconds / 60);\n if (minutes < 60) return `${minutes}m ago`;\n const hours = Math.floor(minutes / 60);\n if (hours < 24) return `${hours}h ago`;\n const days = Math.floor(hours / 24);\n if (days < 30) return `${days}d ago`;\n return new Date(iso).toLocaleDateString();\n}\n","import React from 'react';\nimport { FeedbackEntry } from '../types';\nimport { relativeTime } from '../utils/time';\n\ninterface EntryCardProps {\n entry: FeedbackEntry;\n onDelete: (id: string) => void;\n onCopyPrompt: (prompt: string) => void;\n}\n\nexport function EntryCard({ entry, onDelete, onCopyPrompt }: EntryCardProps) {\n const truncatedComment =\n entry.comment.length > 80\n ? entry.comment.slice(0, 80) + '...'\n : entry.comment;\n\n return (\n <div\n style={{\n padding: 12,\n borderBottom: '1px solid #e5e7eb',\n fontFamily: 'system-ui, sans-serif',\n }}\n >\n <div style={{ display: 'flex', justifyContent: 'space-between', alignItems: 'flex-start', marginBottom: 6 }}>\n <span style={{ fontSize: 13, color: '#111827', flex: 1, marginRight: 8 }}>\n {truncatedComment || '(no comment)'}\n </span>\n <span style={{ fontSize: 11, color: '#9ca3af', whiteSpace: 'nowrap', flexShrink: 0 }}>\n {relativeTime(entry.timestamp)}\n </span>\n </div>\n\n <div style={{ fontSize: 11, color: '#6b7280', marginBottom: 4 }}>\n {entry.url}\n </div>\n\n <div style={{ fontSize: 11, color: '#9ca3af', marginBottom: 8 }}>\n {entry.componentPath}\n </div>\n\n {entry.screenshot && (\n <img\n src={entry.screenshot}\n alt=\"Screenshot thumbnail\"\n style={{\n width: 60,\n height: 40,\n objectFit: 'cover',\n borderRadius: 4,\n border: '1px solid #e5e7eb',\n marginBottom: 8,\n display: 'block',\n }}\n />\n )}\n\n <div style={{ display: 'flex', gap: 6 }}>\n <button\n onClick={() => onCopyPrompt(entry.prompt)}\n style={{\n padding: '4px 10px',\n fontSize: 11,\n borderRadius: 4,\n border: '1px solid #d1d5db',\n background: '#f9fafb',\n color: '#374151',\n cursor: 'pointer',\n }}\n >\n Copy Prompt\n </button>\n <button\n onClick={() => onDelete(entry.id)}\n style={{\n padding: '4px 10px',\n fontSize: 11,\n borderRadius: 4,\n border: '1px solid #fecaca',\n background: '#fef2f2',\n color: '#dc2626',\n cursor: 'pointer',\n }}\n >\n Delete\n </button>\n </div>\n </div>\n );\n}\n","import React from 'react';\nimport { WidgetPosition } from '../types';\nimport { getContrastColor } from '../utils/color';\n\ninterface ListButtonProps {\n onClick: () => void;\n count: number;\n position: WidgetPosition;\n buttonColor: string;\n}\n\nexport function ListButton({ onClick, count, position, buttonColor }: ListButtonProps) {\n if (count === 0) return null;\n\n const isBottom = position.includes('bottom');\n const isRight = position.includes('right');\n\n return (\n <button\n onClick={onClick}\n aria-label={`View ${count} feedback entries`}\n style={{\n position: 'fixed',\n [isBottom ? 'bottom' : 'top']: 80,\n [isRight ? 'right' : 'left']: 24,\n zIndex: 99999,\n width: 36,\n height: 36,\n borderRadius: '50%',\n border: '1px solid #d1d5db',\n background: '#f3f4f6',\n color: '#374151',\n fontSize: 16,\n cursor: 'pointer',\n display: 'flex',\n alignItems: 'center',\n justifyContent: 'center',\n boxShadow: '0 2px 6px rgba(0,0,0,0.15)',\n padding: 0,\n }}\n >\n <span style={{ lineHeight: 1 }}>&#9776;</span>\n\n {/* Count badge */}\n <span\n style={{\n position: 'absolute',\n top: -4,\n [isRight ? 'right' : 'left']: -4,\n background: buttonColor,\n color: getContrastColor(buttonColor),\n fontSize: 10,\n fontWeight: 600,\n borderRadius: '50%',\n width: 18,\n height: 18,\n display: 'flex',\n alignItems: 'center',\n justifyContent: 'center',\n lineHeight: 1,\n }}\n >\n {count > 99 ? '99+' : count}\n </span>\n </button>\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 async function captureScreenshot(clickX: number, clickY: number): Promise<string> {\n // Convert viewport coordinates to document coordinates\n // html2canvas captures the full document, so canvas pixels = document coordinates\n const docX = clickX + window.scrollX;\n const docY = clickY + window.scrollY;\n\n const canvas = await html2canvas(document.body, {\n logging: false,\n useCORS: true,\n });\n\n const ctx = canvas.getContext('2d');\n if (ctx) {\n ctx.strokeStyle = 'red';\n ctx.lineWidth = 3;\n const size = 14;\n\n // Draw X marker at document coordinates\n ctx.beginPath();\n ctx.moveTo(docX - size, docY - size);\n ctx.lineTo(docX + size, docY + size);\n ctx.moveTo(docX + size, docY - size);\n ctx.lineTo(docX - size, docY + size);\n ctx.stroke();\n\n // Draw circle around X\n ctx.beginPath();\n ctx.arc(docX, docY, size + 4, 0, Math.PI * 2);\n ctx.stroke();\n }\n\n return canvas.toDataURL('image/png');\n}\n"],"mappings":"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","names":["import_react","import_jsx_runtime","import_react","import_jsx_runtime","import_react","import_jsx_runtime","import_jsx_runtime","copyToClipboard","import_jsx_runtime","html2canvas","import_jsx_runtime"]}