gotcha-feedback 1.0.16 → 1.0.18

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.
@@ -1 +1 @@
1
- {"version":3,"sources":["../src/constants.ts","../src/utils/anonymous.ts","../src/api/client.ts","../src/components/GotchaProvider.tsx","../src/hooks/useSubmit.ts","../src/utils/cn.ts","../src/utils/device.ts","../src/components/GotchaButton.tsx","../src/components/Spinner.tsx","../src/components/modes/FeedbackMode.tsx","../src/components/modes/VoteMode.tsx","../src/components/modes/PollMode.tsx","../src/components/GotchaModal.tsx","../src/components/Gotcha.tsx","../src/hooks/useGotcha.ts"],"names":["API_BASE_URL","STORAGE_KEYS","DEFAULTS","RETRY_CONFIG","getAnonymousId","stored","id","DEFAULT_RETRY_CONFIG","fetchWithRetry","url","options","config","debug","lastError","attempt","response","error","delay","resolve","createApiClient","apiKey","baseUrl","headers","request","method","endpoint","body","idempotencyKey","data","payload","user","fullPayload","elementId","userId","GotchaContext","createContext","GotchaProvider","children","disabled","defaultUser","activeModalId","setActiveModalId","useState","client","useMemo","openModal","useCallback","closeModal","value","jsx","useGotchaContext","context","useContext","useSubmit","isLoading","setIsLoading","isCheckingExisting","setIsCheckingExisting","setError","existingResponse","setExistingResponse","useEffect","cancelled","existing","err","errorMessage","cn","classes","isTouchDevice","getResponsiveSize","size","isTouch","sizes","getInitialSystemTheme","GotchaButton","theme","customStyles","showOnHover","touchBehavior","onClick","isOpen","isParentHovered","setIsTouch","tapRevealed","setTapRevealed","systemTheme","setSystemTheme","darkQuery","handler","e","shouldShow","handleClick","buttonSize","isDark","baseStyles","GotchaIcon","FONT_ID","useCarterOneFont","link","Spinner","color","jsxs","FeedbackMode","placeholder","submitText","onSubmit","initialValues","isEditing","content","setContent","rating","setRating","handleSubmit","inputStyles","buttonStyles","StarRating","onChange","hovered","setHovered","starSize","buttonPadding","star","isFilled","VoteMode","initialVote","labels","activeVote","setActiveVote","previousVote","setPreviousVote","handleVote","vote","getButtonStyles","voteType","isSelected","iconSize","Fragment","ThumbsUpIcon","ThumbsDownIcon","PollMode","allowMultiple","initialSelected","selected","setSelected","handleToggle","option","prev","o","getOptionStyles","GotchaModal","mode","promptText","thankYouMessage","isSubmitted","voteLabels","onClose","anchorRect","modalRef","useRef","firstFocusableRef","isVisible","setIsVisible","isMobile","setIsMobile","timer","resolvedTheme","showAbove","modal","handleKeyDown","focusableElements","firstElement","lastElement","defaultPrompt","modalPadding","layeredShadow","modalStyles","Gotcha","experimentId","variant","showResults","position","visible","onOpen","onError","setIsSubmitted","setIsParentHovered","setAnchorRect","containerRef","container","parent","handleMouseEnter","handleMouseLeave","submit","handleOpen","handleClose","createPortal","useGotcha"],"mappings":"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","file":"index.mjs","sourcesContent":["// API URL\nexport const API_BASE_URL = 'https://gotcha.cx/api/v1';\n\n// Error codes\nexport const ERROR_CODES = {\n INVALID_API_KEY: 'INVALID_API_KEY',\n ORIGIN_NOT_ALLOWED: 'ORIGIN_NOT_ALLOWED',\n RATE_LIMITED: 'RATE_LIMITED',\n QUOTA_EXCEEDED: 'QUOTA_EXCEEDED',\n INVALID_REQUEST: 'INVALID_REQUEST',\n USER_NOT_FOUND: 'USER_NOT_FOUND',\n INTERNAL_ERROR: 'INTERNAL_ERROR',\n} as const;\n\n// Local storage keys\nexport const STORAGE_KEYS = {\n ANONYMOUS_ID: 'gotcha_anonymous_id',\n OFFLINE_QUEUE: 'gotcha_offline_queue',\n} as const;\n\n// Default values\nexport const DEFAULTS = {\n POSITION: 'top-right' as const,\n SIZE: 'md' as const,\n THEME: 'light' as const,\n SHOW_ON_HOVER: true,\n TOUCH_BEHAVIOR: 'always-visible' as const,\n SUBMIT_TEXT: 'Submit',\n THANK_YOU_MESSAGE: 'Thanks for your feedback!',\n} as const;\n\n// Size mappings (desktop/mobile in pixels)\nexport const SIZE_MAP = {\n sm: { desktop: 24, mobile: 44 },\n md: { desktop: 32, mobile: 44 },\n lg: { desktop: 40, mobile: 48 },\n} as const;\n\n// Retry config\nexport const RETRY_CONFIG = {\n MAX_RETRIES: 2,\n BASE_DELAY_MS: 500,\n MAX_DELAY_MS: 5000,\n} as const;\n","import { STORAGE_KEYS } from '../constants';\n\n/**\n * Get or create an anonymous user ID\n * Stored in localStorage for consistency across sessions\n */\nexport function getAnonymousId(): string {\n if (typeof window === 'undefined') {\n // SSR fallback - generate but don't persist\n return `anon_${crypto.randomUUID()}`;\n }\n\n const stored = localStorage.getItem(STORAGE_KEYS.ANONYMOUS_ID);\n if (stored) return stored;\n\n const id = `anon_${crypto.randomUUID()}`;\n localStorage.setItem(STORAGE_KEYS.ANONYMOUS_ID, id);\n return id;\n}\n\n/**\n * Clear the anonymous ID (useful for testing)\n */\nexport function clearAnonymousId(): void {\n if (typeof window !== 'undefined') {\n localStorage.removeItem(STORAGE_KEYS.ANONYMOUS_ID);\n }\n}\n","import { API_BASE_URL, RETRY_CONFIG } from '../constants';\nimport { SubmitResponsePayload, GotchaResponse, GotchaError, ExistingResponse, VoteType } from '../types';\nimport { getAnonymousId } from '../utils/anonymous';\n\ninterface ApiClientConfig {\n apiKey: string;\n baseUrl?: string;\n debug?: boolean;\n}\n\ninterface RetryConfig {\n maxRetries: number;\n baseDelayMs: number;\n maxDelayMs: number;\n}\n\nconst DEFAULT_RETRY_CONFIG: RetryConfig = {\n maxRetries: RETRY_CONFIG.MAX_RETRIES,\n baseDelayMs: RETRY_CONFIG.BASE_DELAY_MS,\n maxDelayMs: RETRY_CONFIG.MAX_DELAY_MS,\n};\n\n/**\n * Fetch with automatic retry and exponential backoff\n */\nasync function fetchWithRetry(\n url: string,\n options: RequestInit,\n config: RetryConfig = DEFAULT_RETRY_CONFIG,\n debug: boolean = false\n): Promise<Response> {\n let lastError: Error | null = null;\n\n for (let attempt = 0; attempt <= config.maxRetries; attempt++) {\n try {\n if (debug && attempt > 0) {\n console.log(`[Gotcha] Retry attempt ${attempt}/${config.maxRetries}`);\n }\n\n const response = await fetch(url, options);\n\n // Don't retry client errors (4xx) except 429 (rate limit)\n if (response.status >= 400 && response.status < 500 && response.status !== 429) {\n return response;\n }\n\n // Success - return immediately\n if (response.ok) {\n return response;\n }\n\n lastError = new Error(`HTTP ${response.status}`);\n } catch (error) {\n // Network error - retry\n lastError = error as Error;\n if (debug) {\n console.log(`[Gotcha] Network error: ${lastError.message}`);\n }\n }\n\n // Don't delay after last attempt\n if (attempt < config.maxRetries) {\n const delay = Math.min(\n config.baseDelayMs * Math.pow(2, attempt),\n config.maxDelayMs\n );\n await new Promise((resolve) => setTimeout(resolve, delay));\n }\n }\n\n throw lastError;\n}\n\nexport function createApiClient(config: ApiClientConfig) {\n const { apiKey, baseUrl = API_BASE_URL, debug = false } = config;\n\n const headers = {\n 'Content-Type': 'application/json',\n Authorization: `Bearer ${apiKey}`,\n };\n\n async function request<T>(\n method: string,\n endpoint: string,\n body?: unknown\n ): Promise<T> {\n const url = `${baseUrl}${endpoint}`;\n const idempotencyKey = crypto.randomUUID();\n\n if (debug) {\n console.log(`[Gotcha] ${method} ${endpoint}`, body);\n }\n\n const response = await fetchWithRetry(\n url,\n {\n method,\n headers: {\n ...headers,\n 'Idempotency-Key': idempotencyKey,\n },\n body: body ? JSON.stringify(body) : undefined,\n },\n DEFAULT_RETRY_CONFIG,\n debug\n );\n\n const data = await response.json();\n\n if (!response.ok) {\n const error = data.error as GotchaError;\n if (debug) {\n console.error(`[Gotcha] Error: ${error.code} - ${error.message}`);\n }\n throw error;\n }\n\n if (debug) {\n console.log(`[Gotcha] Response:`, data);\n }\n\n return data as T;\n }\n\n return {\n /**\n * Submit a response (feedback, vote, etc.)\n */\n async submitResponse(\n payload: Omit<SubmitResponsePayload, 'context'>\n ): Promise<GotchaResponse> {\n // Ensure user has an ID (anonymous if not provided)\n const user = payload.user || {};\n if (!user.id) {\n user.id = getAnonymousId();\n }\n\n const fullPayload: SubmitResponsePayload = {\n ...payload,\n user,\n context: {\n url: typeof window !== 'undefined' ? window.location.href : undefined,\n userAgent: typeof navigator !== 'undefined' ? navigator.userAgent : undefined,\n },\n };\n\n return request<GotchaResponse>('POST', '/responses', fullPayload);\n },\n\n /**\n * Check if a user has an existing response for an element\n */\n async checkExistingResponse(\n elementId: string,\n userId: string\n ): Promise<ExistingResponse | null> {\n const url = `${baseUrl}/responses/check?elementId=${encodeURIComponent(elementId)}&userId=${encodeURIComponent(userId)}`;\n\n if (debug) {\n console.log(`[Gotcha] GET /responses/check`);\n }\n\n const response = await fetchWithRetry(\n url,\n {\n method: 'GET',\n headers,\n },\n DEFAULT_RETRY_CONFIG,\n debug\n );\n\n const data = await response.json();\n\n if (!response.ok) {\n const error = data.error as GotchaError;\n if (debug) {\n console.error(`[Gotcha] Error: ${error.code} - ${error.message}`);\n }\n throw error;\n }\n\n if (data.exists) {\n if (debug) {\n console.log(`[Gotcha] Found existing response:`, data.response);\n }\n return data.response as ExistingResponse;\n }\n\n return null;\n },\n\n /**\n * Update an existing response\n */\n async updateResponse(\n id: string,\n payload: {\n content?: string;\n title?: string;\n rating?: number;\n vote?: VoteType;\n pollSelected?: string[];\n },\n userId?: string\n ): Promise<GotchaResponse> {\n const url = `${baseUrl}/responses/${id}${userId ? `?userId=${encodeURIComponent(userId)}` : ''}`;\n\n if (debug) {\n console.log(`[Gotcha] PATCH /responses/${id}`, payload);\n }\n\n const response = await fetchWithRetry(\n url,\n {\n method: 'PATCH',\n headers,\n body: JSON.stringify(payload),\n },\n DEFAULT_RETRY_CONFIG,\n debug\n );\n\n const data = await response.json();\n\n if (!response.ok) {\n const error = data.error as GotchaError;\n if (debug) {\n console.error(`[Gotcha] Error: ${error.code} - ${error.message}`);\n }\n throw error;\n }\n\n if (debug) {\n console.log(`[Gotcha] Response updated:`, data);\n }\n\n return data as GotchaResponse;\n },\n\n /**\n * Get the base URL (for debugging)\n */\n getBaseUrl(): string {\n return baseUrl;\n },\n };\n}\n\nexport type ApiClient = ReturnType<typeof createApiClient>;\n","import React, { createContext, useContext, useMemo, useState, useCallback } from 'react';\nimport { createApiClient, ApiClient } from '../api/client';\nimport { GotchaUser } from '../types';\n\nexport interface GotchaProviderProps {\n /** Your Gotcha API key */\n apiKey: string;\n /** React children */\n children: React.ReactNode;\n /** Override the API base URL (for testing/staging) */\n baseUrl?: string;\n /** Enable debug logging */\n debug?: boolean;\n /** Disable all Gotcha buttons globally */\n disabled?: boolean;\n /** Default user metadata applied to all submissions */\n defaultUser?: GotchaUser;\n}\n\nexport interface GotchaContextValue {\n client: ApiClient;\n disabled: boolean;\n defaultUser: GotchaUser;\n debug: boolean;\n // Modal management - only one open at a time\n activeModalId: string | null;\n openModal: (elementId: string) => void;\n closeModal: () => void;\n}\n\nconst GotchaContext = createContext<GotchaContextValue | null>(null);\n\nexport function GotchaProvider({\n apiKey,\n children,\n baseUrl,\n debug = false,\n disabled = false,\n defaultUser = {},\n}: GotchaProviderProps) {\n const [activeModalId, setActiveModalId] = useState<string | null>(null);\n\n const client = useMemo(\n () => createApiClient({ apiKey, baseUrl, debug }),\n [apiKey, baseUrl, debug]\n );\n\n const openModal = useCallback((elementId: string) => {\n setActiveModalId(elementId);\n }, []);\n\n const closeModal = useCallback(() => {\n setActiveModalId(null);\n }, []);\n\n const value: GotchaContextValue = useMemo(\n () => ({\n client,\n disabled,\n defaultUser,\n debug,\n activeModalId,\n openModal,\n closeModal,\n }),\n [client, disabled, defaultUser, debug, activeModalId, openModal, closeModal]\n );\n\n return (\n <GotchaContext.Provider value={value}>{children}</GotchaContext.Provider>\n );\n}\n\nexport function useGotchaContext(): GotchaContextValue {\n const context = useContext(GotchaContext);\n if (!context) {\n throw new Error('useGotchaContext must be used within a GotchaProvider');\n }\n return context;\n}\n","import { useState, useCallback, useEffect } from 'react';\nimport { useGotchaContext } from '../components/GotchaProvider';\nimport { ResponseMode, GotchaUser, GotchaResponse, VoteType, ExistingResponse } from '../types';\n\ninterface UseSubmitOptions {\n elementId: string;\n mode: ResponseMode;\n experimentId?: string;\n variant?: string;\n pollOptions?: string[];\n user?: GotchaUser;\n onSuccess?: (response: GotchaResponse) => void;\n onError?: (error: Error) => void;\n}\n\ninterface SubmitData {\n content?: string;\n title?: string;\n rating?: number;\n vote?: VoteType;\n pollSelected?: string[];\n}\n\nexport function useSubmit(options: UseSubmitOptions) {\n const { client, defaultUser } = useGotchaContext();\n const [isLoading, setIsLoading] = useState(false);\n const [isCheckingExisting, setIsCheckingExisting] = useState(false);\n const [error, setError] = useState<string | null>(null);\n const [existingResponse, setExistingResponse] = useState<ExistingResponse | null>(null);\n\n // Check for existing response when user ID is provided\n useEffect(() => {\n const userId = options.user?.id || defaultUser?.id;\n if (!userId) {\n setExistingResponse(null);\n return;\n }\n\n let cancelled = false;\n\n const checkExisting = async () => {\n setIsCheckingExisting(true);\n try {\n const existing = await client.checkExistingResponse(options.elementId, userId);\n if (!cancelled) {\n setExistingResponse(existing);\n }\n } catch {\n // Ignore errors - just means no existing response found\n if (!cancelled) {\n setExistingResponse(null);\n }\n } finally {\n if (!cancelled) {\n setIsCheckingExisting(false);\n }\n }\n };\n\n checkExisting();\n\n return () => {\n cancelled = true;\n };\n }, [client, options.elementId, options.user?.id, defaultUser?.id]);\n\n const submit = useCallback(\n async (data: SubmitData) => {\n setIsLoading(true);\n setError(null);\n\n try {\n const userId = options.user?.id || defaultUser?.id;\n let response: GotchaResponse;\n\n // If we have an existing response and a user ID, update instead of create\n if (existingResponse && userId) {\n response = await client.updateResponse(\n existingResponse.id,\n {\n content: data.content,\n title: data.title,\n rating: data.rating,\n vote: data.vote,\n pollSelected: data.pollSelected,\n },\n userId\n );\n } else {\n response = await client.submitResponse({\n elementId: options.elementId,\n mode: options.mode,\n content: data.content,\n title: data.title,\n rating: data.rating,\n vote: data.vote,\n pollOptions: options.pollOptions,\n pollSelected: data.pollSelected,\n experimentId: options.experimentId,\n variant: options.variant,\n user: { ...defaultUser, ...options.user },\n });\n }\n\n options.onSuccess?.(response);\n return response;\n } catch (err) {\n const errorMessage = err instanceof Error ? err.message : 'Something went wrong';\n setError(errorMessage);\n options.onError?.(err instanceof Error ? err : new Error(errorMessage));\n throw err;\n } finally {\n setIsLoading(false);\n }\n },\n [client, defaultUser, options, existingResponse]\n );\n\n return {\n submit,\n isLoading,\n isCheckingExisting,\n error,\n existingResponse,\n isEditing: !!existingResponse,\n clearError: () => setError(null),\n };\n}\n","/**\n * Simple class name utility\n * Combines class names, filtering out falsy values\n */\nexport function cn(...classes: (string | undefined | null | false)[]): string {\n return classes.filter(Boolean).join(' ');\n}\n","/**\n * Detect if the device supports touch\n */\nexport const isTouchDevice = (): boolean => {\n if (typeof window === 'undefined') return false;\n return 'ontouchstart' in window || navigator.maxTouchPoints > 0;\n};\n\n/**\n * Get the appropriate size based on device type\n */\nexport const getResponsiveSize = (\n size: 'sm' | 'md' | 'lg',\n isTouch: boolean\n): number => {\n const sizes = {\n sm: { desktop: 24, mobile: 32 },\n md: { desktop: 32, mobile: 36 },\n lg: { desktop: 40, mobile: 40 },\n };\n\n return isTouch ? sizes[size].mobile : sizes[size].desktop;\n};\n","import React, { useState, useEffect } from 'react';\nimport { Size, Theme, GotchaStyles } from '../types';\nimport { cn } from '../utils/cn';\nimport { isTouchDevice, getResponsiveSize } from '../utils/device';\n\nexport interface GotchaButtonProps {\n size: Size;\n theme: Theme;\n customStyles?: GotchaStyles;\n showOnHover: boolean;\n touchBehavior: 'always-visible' | 'tap-to-reveal';\n onClick: () => void;\n isOpen: boolean;\n isParentHovered?: boolean;\n}\n\n/**\n * Detect system color-scheme preference synchronously where possible,\n * falling back to 'light'. This avoids the flash that occurred when\n * the old code always initialised state as 'light' and corrected it\n * inside useEffect.\n */\nfunction getInitialSystemTheme(): 'light' | 'dark' {\n if (typeof window === 'undefined') return 'light';\n return window.matchMedia('(prefers-color-scheme: dark)').matches\n ? 'dark'\n : 'light';\n}\n\nexport function GotchaButton({\n size,\n theme,\n customStyles,\n showOnHover,\n touchBehavior,\n onClick,\n isOpen,\n isParentHovered = false,\n}: GotchaButtonProps) {\n const [isTouch, setIsTouch] = useState(false);\n const [tapRevealed, setTapRevealed] = useState(false);\n const [systemTheme, setSystemTheme] = useState<'light' | 'dark'>(getInitialSystemTheme);\n\n useEffect(() => {\n setIsTouch(isTouchDevice());\n\n // Keep systemTheme in sync when user changes OS preference\n const darkQuery = window.matchMedia('(prefers-color-scheme: dark)');\n const handler = (e: MediaQueryListEvent) =>\n setSystemTheme(e.matches ? 'dark' : 'light');\n darkQuery.addEventListener('change', handler);\n return () => darkQuery.removeEventListener('change', handler);\n }, []);\n\n // Determine visibility\n const shouldShow = (() => {\n if (isOpen) return true;\n if (!isTouch && showOnHover) return isParentHovered;\n if (isTouch && touchBehavior === 'tap-to-reveal') return tapRevealed;\n return true;\n })();\n\n const handleClick = () => {\n if (isTouch && touchBehavior === 'tap-to-reveal' && !tapRevealed) {\n setTapRevealed(true);\n return;\n }\n onClick();\n };\n\n const buttonSize = getResponsiveSize(size, isTouch);\n\n // ── Resolve theme ────────────────────────────────────────────────\n // \"auto\" must produce the *exact* same styles as the explicit theme\n // it resolves to. Previously the initial state defaulted to 'light'\n // regardless of the actual preference, causing a mismatch on the\n // first render when the system was dark.\n const resolvedTheme = theme === 'auto' ? systemTheme : theme;\n const isDark = resolvedTheme === 'dark';\n\n // ── Glass-bubble styles ──────────────────────────────────────────\n // Simulates a raised glass dome / marble sitting on the surface:\n // - Bright borderTop highlight mimics light hitting the top edge\n // - Subtle darker base border grounds the bottom\n // - Vertical gradient: bright at top, more opaque at bottom\n // - Inset top shadow for inner refraction glow\n // - Inset bottom shadow for depth within the dome\n // - Outer shadow to anchor the bubble to the surface\n const baseStyles: React.CSSProperties = {\n width: buttonSize,\n height: buttonSize,\n borderRadius: '50%',\n border: isDark\n ? '1px solid rgba(255,255,255,0.15)'\n : 'none',\n cursor: 'pointer',\n display: 'flex',\n alignItems: 'center',\n justifyContent: 'center',\n background: isDark\n ? 'linear-gradient(180deg, rgba(255,255,255,0.16) 0%, rgba(255,255,255,0.04) 60%, rgba(0,0,0,0.05) 100%)'\n : 'linear-gradient(160deg, rgba(255,255,255,0.7) 0%, rgba(200,210,230,0.4) 40%, rgba(180,192,220,0.5) 100%)',\n backdropFilter: 'blur(16px) saturate(170%)',\n WebkitBackdropFilter: 'blur(16px) saturate(170%)',\n color: isDark ? 'rgba(255,255,255,0.88)' : 'rgba(0,0,0,0.75)',\n boxShadow: isDark\n ? '0 4px 14px rgba(0,0,0,0.45), 0 1px 3px rgba(0,0,0,0.35)'\n : '0 3px 12px rgba(0,0,0,0.12), 0 0 1px rgba(0,0,0,0.2)',\n transition: 'all 0.2s cubic-bezier(0.4, 0, 0.2, 1)',\n opacity: shouldShow ? 1 : 0,\n transform: shouldShow ? 'scale(1)' : 'scale(0.6)',\n pointerEvents: shouldShow ? 'auto' : 'none',\n ...customStyles?.button,\n };\n\n return (\n <button\n type=\"button\"\n onClick={handleClick}\n style={baseStyles}\n className={cn('gotcha-button', isOpen && 'gotcha-button--open')}\n aria-label=\"Give feedback on this feature\"\n aria-expanded={isOpen}\n aria-haspopup=\"dialog\"\n >\n <GotchaIcon size={buttonSize * 0.65} />\n </button>\n );\n}\n\nconst FONT_ID = 'gotcha-carter-one';\n\nfunction useCarterOneFont() {\n useEffect(() => {\n if (document.getElementById(FONT_ID)) return;\n const link = document.createElement('link');\n link.id = FONT_ID;\n link.rel = 'stylesheet';\n link.href = 'https://fonts.googleapis.com/css2?family=Carter+One&display=swap';\n document.head.appendChild(link);\n }, []);\n}\n\nfunction GotchaIcon({ size }: { size: number }) {\n useCarterOneFont();\n return (\n <span\n aria-hidden=\"true\"\n style={{\n fontFamily: \"'Carter One', cursive\",\n fontSize: size,\n lineHeight: 1,\n display: 'flex',\n alignItems: 'center',\n justifyContent: 'center',\n marginTop: size * 0.05,\n marginRight: size * 0.05,\n userSelect: 'none',\n }}\n >\n G\n </span>\n );\n}\n","import React from 'react';\n\ninterface SpinnerProps {\n size?: number;\n color?: string;\n}\n\nexport function Spinner({ size = 16, color = 'currentColor' }: SpinnerProps) {\n return (\n <svg\n width={size}\n height={size}\n viewBox=\"0 0 24 24\"\n fill=\"none\"\n style={{\n animation: 'gotcha-spin 0.8s linear infinite',\n }}\n >\n <style>\n {`\n @keyframes gotcha-spin {\n from { transform: rotate(0deg); }\n to { transform: rotate(360deg); }\n }\n @keyframes gotcha-dash {\n 0% { stroke-dasharray: 1, 62; stroke-dashoffset: 0; }\n 50% { stroke-dasharray: 40, 62; stroke-dashoffset: -12; }\n 100% { stroke-dasharray: 1, 62; stroke-dashoffset: -62; }\n }\n `}\n </style>\n <circle\n cx=\"12\"\n cy=\"12\"\n r=\"10\"\n stroke={color}\n strokeWidth=\"2\"\n strokeOpacity=\"0.12\"\n />\n <circle\n cx=\"12\"\n cy=\"12\"\n r=\"10\"\n stroke={color}\n strokeWidth=\"2\"\n strokeLinecap=\"round\"\n style={{\n animation: 'gotcha-dash 1.2s ease-in-out infinite',\n }}\n />\n </svg>\n );\n}\n","import React, { useState, useEffect } from 'react';\nimport { GotchaStyles } from '../../types';\nimport { isTouchDevice } from '../../utils/device';\nimport { Spinner } from '../Spinner';\n\ninterface FeedbackModeProps {\n theme: 'light' | 'dark' | 'custom';\n placeholder?: string;\n submitText: string;\n isLoading: boolean;\n onSubmit: (data: { content?: string; rating?: number }) => void;\n customStyles?: GotchaStyles;\n initialValues?: {\n content?: string | null;\n rating?: number | null;\n };\n isEditing?: boolean;\n}\n\nexport function FeedbackMode({\n theme,\n placeholder,\n submitText,\n isLoading,\n onSubmit,\n customStyles,\n initialValues,\n isEditing = false,\n}: FeedbackModeProps) {\n const [content, setContent] = useState(initialValues?.content || '');\n const [rating, setRating] = useState<number | null>(initialValues?.rating ?? null);\n const [isTouch, setIsTouch] = useState(false);\n\n useEffect(() => {\n setIsTouch(isTouchDevice());\n }, []);\n\n // Update local state when initialValues change (e.g., after loading existing response)\n useEffect(() => {\n if (initialValues?.content !== undefined) {\n setContent(initialValues.content || '');\n }\n if (initialValues?.rating !== undefined) {\n setRating(initialValues.rating ?? null);\n }\n }, [initialValues?.content, initialValues?.rating]);\n\n const isDark = theme === 'dark';\n\n const handleSubmit = (e: React.FormEvent) => {\n e.preventDefault();\n if (!content.trim() && rating === null) return;\n onSubmit({ content: content.trim() || undefined, rating: rating ?? undefined });\n };\n\n const inputStyles: React.CSSProperties = {\n width: '100%',\n padding: isTouch ? '12px 14px' : '10px 12px',\n border: `1px solid ${isDark ? 'rgba(255,255,255,0.08)' : '#e2e8f0'}`,\n borderRadius: 8,\n backgroundColor: isDark ? 'rgba(55,65,81,0.5)' : '#fafbfc',\n color: isDark ? '#f9fafb' : '#111827',\n fontSize: isTouch ? 16 : 14, // 16px prevents iOS zoom on focus\n resize: 'vertical',\n minHeight: isTouch ? 100 : 80,\n fontFamily: 'inherit',\n outline: 'none',\n transition: 'border-color 0.2s cubic-bezier(0.4, 0, 0.2, 1), box-shadow 0.2s cubic-bezier(0.4, 0, 0.2, 1)',\n lineHeight: 1.5,\n ...customStyles?.input,\n };\n\n const buttonStyles: React.CSSProperties = {\n width: '100%',\n padding: isTouch ? '14px 16px' : '10px 16px',\n border: 'none',\n borderRadius: 8,\n backgroundColor: isDark ? '#e2e8f0' : '#1e293b',\n color: isDark ? '#1e293b' : '#ffffff',\n fontSize: isTouch ? 16 : 14,\n fontWeight: 500,\n cursor: isLoading ? 'not-allowed' : 'pointer',\n transition: 'all 0.2s cubic-bezier(0.4, 0, 0.2, 1)',\n letterSpacing: '0.01em',\n ...customStyles?.submitButton,\n };\n\n return (\n <form onSubmit={handleSubmit}>\n {/* Rating (optional) */}\n <div style={{ marginBottom: isTouch ? 16 : 12 }}>\n <StarRating value={rating} onChange={setRating} isDark={isDark} isTouch={isTouch} />\n </div>\n\n {/* Text input */}\n <textarea\n value={content}\n onChange={(e) => setContent(e.target.value)}\n placeholder={placeholder || 'Share your thoughts...'}\n style={inputStyles}\n disabled={isLoading}\n aria-label=\"Your feedback\"\n onFocus={(e) => {\n e.currentTarget.style.borderColor = '#1e293b';\n e.currentTarget.style.boxShadow = '0 0 0 2px rgba(30,41,59,0.15)';\n e.currentTarget.style.backgroundColor = isDark ? 'rgba(55,65,81,0.7)' : '#ffffff';\n }}\n onBlur={(e) => {\n e.currentTarget.style.borderColor = isDark ? 'rgba(255,255,255,0.08)' : '#e2e8f0';\n e.currentTarget.style.boxShadow = 'none';\n e.currentTarget.style.backgroundColor = isDark ? 'rgba(55,65,81,0.5)' : '#fafbfc';\n }}\n />\n\n {/* Submit button */}\n <button\n type=\"submit\"\n disabled={isLoading || (!content.trim() && rating === null)}\n style={{\n ...buttonStyles,\n marginTop: 12,\n opacity: isLoading ? 0.8 : 1,\n backgroundColor: (!content.trim() && rating === null)\n ? (isDark ? '#374151' : '#e2e8f0')\n : (isDark ? '#e2e8f0' : '#1e293b'),\n color: (!content.trim() && rating === null)\n ? (isDark ? '#6b7280' : '#94a3b8')\n : (isDark ? '#1e293b' : '#ffffff'),\n display: 'flex',\n alignItems: 'center',\n justifyContent: 'center',\n gap: 8,\n }}\n onMouseEnter={(e) => {\n if (!e.currentTarget.disabled) {\n e.currentTarget.style.backgroundColor = isDark ? '#cbd5e1' : '#334155';\n }\n }}\n onMouseLeave={(e) => {\n if (!e.currentTarget.disabled) {\n e.currentTarget.style.backgroundColor = isDark ? '#e2e8f0' : '#1e293b';\n }\n }}\n >\n {isLoading && <Spinner size={isTouch ? 18 : 16} color={isDark ? '#1e293b' : '#ffffff'} />}\n {isLoading ? (isEditing ? 'Updating...' : 'Submitting...') : (isEditing ? 'Update' : submitText)}\n </button>\n </form>\n );\n}\n\ninterface StarRatingProps {\n value: number | null;\n onChange: (rating: number) => void;\n isDark: boolean;\n isTouch: boolean;\n}\n\nfunction StarRating({ value, onChange, isDark, isTouch }: StarRatingProps) {\n const [hovered, setHovered] = useState<number | null>(null);\n const starSize = isTouch ? 28 : 18;\n const buttonPadding = isTouch ? 6 : 3;\n\n return (\n <div\n style={{\n display: 'flex',\n gap: isTouch ? 6 : 2,\n }}\n role=\"group\"\n aria-label=\"Rating\"\n >\n {[1, 2, 3, 4, 5].map((star) => {\n const isFilled = (hovered ?? value ?? 0) >= star;\n return (\n <button\n key={star}\n type=\"button\"\n onClick={() => onChange(star)}\n onMouseEnter={() => setHovered(star)}\n onMouseLeave={() => setHovered(null)}\n aria-label={`Rate ${star} out of 5`}\n aria-pressed={value === star}\n style={{\n background: 'none',\n border: 'none',\n cursor: 'pointer',\n padding: buttonPadding,\n color: isFilled ? '#f59e0b' : (isDark ? 'rgba(255,255,255,0.12)' : '#e2e8f0'),\n transition: 'color 0.15s cubic-bezier(0.4, 0, 0.2, 1), transform 0.15s cubic-bezier(0.4, 0, 0.2, 1)',\n transform: (hovered !== null && hovered >= star) ? 'scale(1.1)' : 'scale(1)',\n }}\n >\n <svg width={starSize} height={starSize} viewBox=\"0 0 24 24\" fill=\"currentColor\">\n <path d=\"M12 2l3.09 6.26L22 9.27l-5 4.87 1.18 6.88L12 17.77l-6.18 3.25L7 14.14 2 9.27l6.91-1.01L12 2z\" />\n </svg>\n </button>\n );\n })}\n </div>\n );\n}\n","import React, { useEffect, useState } from 'react';\nimport { isTouchDevice } from '../../utils/device';\nimport { Spinner } from '../Spinner';\n\ninterface VoteModeProps {\n theme: 'light' | 'dark' | 'custom';\n isLoading: boolean;\n onSubmit: (data: { vote: 'up' | 'down' }) => void;\n initialVote?: 'up' | 'down' | null;\n isEditing?: boolean;\n labels?: { up: string; down: string };\n}\n\nexport function VoteMode({ theme, isLoading, onSubmit, initialVote, isEditing = false, labels }: VoteModeProps) {\n const [isTouch, setIsTouch] = useState(false);\n const [activeVote, setActiveVote] = useState<'up' | 'down' | null>(initialVote || null);\n const [previousVote, setPreviousVote] = useState<'up' | 'down' | null>(initialVote || null);\n\n useEffect(() => {\n setIsTouch(isTouchDevice());\n }, []);\n\n // Update when initialVote changes (e.g., after loading existing response)\n useEffect(() => {\n if (initialVote !== undefined) {\n setPreviousVote(initialVote);\n setActiveVote(initialVote);\n }\n }, [initialVote]);\n\n // Reset active vote when loading completes (but keep previous vote for edit mode)\n useEffect(() => {\n if (!isLoading && !isEditing) {\n setActiveVote(null);\n }\n }, [isLoading, isEditing]);\n\n const handleVote = (vote: 'up' | 'down') => {\n setActiveVote(vote);\n onSubmit({ vote });\n };\n\n const isDark = theme === 'dark';\n\n const getButtonStyles = (voteType: 'up' | 'down'): React.CSSProperties => {\n const isSelected = previousVote === voteType;\n const selectedColor = voteType === 'up' ? '#10b981' : '#ef4444';\n return {\n flex: 1,\n minWidth: 0,\n overflow: 'hidden' as const,\n padding: isTouch ? '14px 18px' : '10px 14px',\n border: `1px solid ${isSelected\n ? (voteType === 'up'\n ? (isDark ? 'rgba(16,185,129,0.3)' : 'rgba(16,185,129,0.25)')\n : (isDark ? 'rgba(239,68,68,0.3)' : 'rgba(239,68,68,0.25)'))\n : (isDark ? 'rgba(255,255,255,0.08)' : '#e2e8f0')}`,\n borderRadius: isTouch ? 10 : 8,\n backgroundColor: isSelected\n ? (voteType === 'up'\n ? (isDark ? 'rgba(16,185,129,0.08)' : 'rgba(16,185,129,0.06)')\n : (isDark ? 'rgba(239,68,68,0.08)' : 'rgba(239,68,68,0.06)'))\n : (isDark ? 'rgba(55,65,81,0.5)' : '#fafbfc'),\n color: isSelected\n ? selectedColor\n : (isDark ? '#d1d5db' : '#64748b'),\n fontSize: isTouch ? 28 : 24,\n cursor: isLoading ? 'not-allowed' : 'pointer',\n transition: 'background-color 0.2s, border-color 0.2s, color 0.2s, transform 0.2s, box-shadow 0.2s',\n display: 'flex',\n alignItems: 'center',\n justifyContent: 'center',\n gap: isTouch ? 10 : 8,\n };\n };\n\n const iconSize = isTouch ? 24 : 20;\n\n return (\n <div\n style={{\n display: 'flex',\n gap: isTouch ? 12 : 10,\n }}\n role=\"group\"\n aria-label=\"Vote\"\n >\n <button\n type=\"button\"\n onClick={() => handleVote('up')}\n disabled={isLoading}\n style={getButtonStyles('up')}\n aria-label=\"Vote up - I like this\"\n aria-pressed={previousVote === 'up'}\n onMouseEnter={(e) => {\n if (!isLoading) {\n e.currentTarget.style.transform = 'translateY(-1px)';\n e.currentTarget.style.boxShadow = '0 2px 8px rgba(0,0,0,0.06)';\n }\n }}\n onMouseLeave={(e) => {\n e.currentTarget.style.transform = 'translateY(0)';\n e.currentTarget.style.boxShadow = 'none';\n }}\n >\n {isLoading && activeVote === 'up' ? (\n <>\n <Spinner size={iconSize} color={isDark ? '#f9fafb' : '#111827'} />\n <span style={{ fontSize: isTouch ? 15 : 13, fontWeight: 500, letterSpacing: '0.01em' }}>\n {isEditing ? 'Updating...' : 'Sending...'}\n </span>\n </>\n ) : (\n <>\n <ThumbsUpIcon size={iconSize} />\n <span style={{ fontSize: isTouch ? 15 : 13, fontWeight: 500, letterSpacing: '0.01em' }}>\n {labels?.up || (previousVote === 'up' ? 'Liked' : 'Like')}\n </span>\n </>\n )}\n </button>\n\n <button\n type=\"button\"\n onClick={() => handleVote('down')}\n disabled={isLoading}\n style={getButtonStyles('down')}\n aria-label=\"Vote down - I don't like this\"\n aria-pressed={previousVote === 'down'}\n onMouseEnter={(e) => {\n if (!isLoading) {\n e.currentTarget.style.transform = 'translateY(-1px)';\n e.currentTarget.style.boxShadow = '0 2px 8px rgba(0,0,0,0.06)';\n }\n }}\n onMouseLeave={(e) => {\n e.currentTarget.style.transform = 'translateY(0)';\n e.currentTarget.style.boxShadow = 'none';\n }}\n >\n {isLoading && activeVote === 'down' ? (\n <>\n <Spinner size={iconSize} color={isDark ? '#f9fafb' : '#111827'} />\n <span style={{ fontSize: isTouch ? 15 : 13, fontWeight: 500, letterSpacing: '0.01em' }}>\n {isEditing ? 'Updating...' : 'Sending...'}\n </span>\n </>\n ) : (\n <>\n <ThumbsDownIcon size={iconSize} />\n <span style={{ fontSize: isTouch ? 15 : 13, fontWeight: 500, letterSpacing: '0.01em' }}>\n {labels?.down || (previousVote === 'down' ? 'Disliked' : 'Dislike')}\n </span>\n </>\n )}\n </button>\n </div>\n );\n}\n\nfunction ThumbsUpIcon({ size = 24 }: { size?: number }) {\n return (\n <svg width={size} height={size} viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" strokeWidth=\"1.75\" strokeLinecap=\"round\" strokeLinejoin=\"round\">\n <path d=\"M14 9V5a3 3 0 0 0-3-3l-4 9v11h11.28a2 2 0 0 0 2-1.7l1.38-9a2 2 0 0 0-2-2.3zM7 22H4a2 2 0 0 1-2-2v-7a2 2 0 0 1 2-2h3\" />\n </svg>\n );\n}\n\nfunction ThumbsDownIcon({ size = 24 }: { size?: number }) {\n return (\n <svg width={size} height={size} viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" strokeWidth=\"1.75\" strokeLinecap=\"round\" strokeLinejoin=\"round\">\n <path d=\"M10 15v4a3 3 0 0 0 3 3l4-9V2H5.72a2 2 0 0 0-2 1.7l-1.38 9a2 2 0 0 0 2 2.3zm7-13h2.67A2.31 2.31 0 0 1 22 4v7a2.31 2.31 0 0 1-2.33 2H17\" />\n </svg>\n );\n}\n","import React, { useState, useEffect } from 'react';\nimport { isTouchDevice } from '../../utils/device';\nimport { Spinner } from '../Spinner';\n\ninterface PollModeProps {\n theme: 'light' | 'dark' | 'custom';\n options: string[];\n allowMultiple: boolean;\n isLoading: boolean;\n onSubmit: (data: { pollSelected: string[] }) => void;\n initialSelected?: string[] | null;\n isEditing?: boolean;\n}\n\nexport function PollMode({\n theme,\n options,\n allowMultiple,\n isLoading,\n onSubmit,\n initialSelected,\n isEditing = false,\n}: PollModeProps) {\n const [selected, setSelected] = useState<string[]>(initialSelected || []);\n const [isTouch, setIsTouch] = useState(false);\n\n useEffect(() => {\n setIsTouch(isTouchDevice());\n }, []);\n\n useEffect(() => {\n if (initialSelected) {\n setSelected(initialSelected);\n }\n }, [initialSelected]);\n\n const isDark = theme === 'dark';\n\n const handleToggle = (option: string) => {\n if (allowMultiple) {\n setSelected((prev) =>\n prev.includes(option) ? prev.filter((o) => o !== option) : [...prev, option]\n );\n } else {\n setSelected((prev) => (prev.includes(option) ? [] : [option]));\n }\n };\n\n const handleSubmit = () => {\n if (selected.length === 0) return;\n onSubmit({ pollSelected: selected });\n };\n\n const getOptionStyles = (option: string): React.CSSProperties => {\n const isSelected = selected.includes(option);\n return {\n width: '100%',\n padding: isTouch ? '12px 14px' : '9px 12px',\n border: `1px solid ${isSelected\n ? (isDark ? 'rgba(226,232,240,0.25)' : 'rgba(30,41,59,0.25)')\n : (isDark ? 'rgba(255,255,255,0.08)' : '#e2e8f0')}`,\n borderRadius: isTouch ? 10 : 8,\n backgroundColor: isSelected\n ? (isDark ? 'rgba(226,232,240,0.08)' : 'rgba(30,41,59,0.05)')\n : (isDark ? 'rgba(55,65,81,0.5)' : '#fafbfc'),\n color: isSelected\n ? (isDark ? '#e2e8f0' : '#1e293b')\n : (isDark ? '#d1d5db' : '#374151'),\n fontSize: isTouch ? 15 : 13,\n fontWeight: 500,\n cursor: isLoading ? 'not-allowed' : 'pointer',\n transition: 'background-color 0.2s, border-color 0.2s, color 0.2s',\n textAlign: 'left' as const,\n letterSpacing: '0.01em',\n display: 'flex',\n alignItems: 'center',\n gap: 8,\n };\n };\n\n return (\n <div>\n <div\n style={{\n display: 'flex',\n flexDirection: 'column',\n gap: isTouch ? 8 : 6,\n }}\n role=\"group\"\n aria-label={allowMultiple ? 'Select one or more options' : 'Select an option'}\n >\n {options.map((option) => {\n const isSelected = selected.includes(option);\n return (\n <button\n key={option}\n type=\"button\"\n onClick={() => handleToggle(option)}\n disabled={isLoading}\n style={getOptionStyles(option)}\n aria-pressed={isSelected}\n >\n <span\n style={{\n width: 16,\n height: 16,\n borderRadius: allowMultiple ? 4 : '50%',\n border: `2px solid ${isSelected\n ? (isDark ? '#e2e8f0' : '#1e293b')\n : (isDark ? 'rgba(255,255,255,0.2)' : '#cbd5e1')}`,\n backgroundColor: isSelected\n ? (isDark ? '#e2e8f0' : '#1e293b')\n : 'transparent',\n display: 'flex',\n alignItems: 'center',\n justifyContent: 'center',\n flexShrink: 0,\n transition: 'all 0.15s',\n }}\n >\n {isSelected && (\n <svg width={10} height={10} viewBox=\"0 0 12 12\" fill=\"none\">\n <path\n d=\"M2 6l3 3 5-5\"\n stroke=\"#fff\"\n strokeWidth=\"2\"\n strokeLinecap=\"round\"\n strokeLinejoin=\"round\"\n />\n </svg>\n )}\n </span>\n {option}\n </button>\n );\n })}\n </div>\n\n <button\n type=\"button\"\n onClick={handleSubmit}\n disabled={isLoading || selected.length === 0}\n style={{\n width: '100%',\n marginTop: 12,\n padding: isTouch ? '14px 16px' : '10px 16px',\n border: 'none',\n borderRadius: 8,\n backgroundColor: selected.length === 0\n ? (isDark ? '#374151' : '#e2e8f0')\n : (isDark ? '#e2e8f0' : '#1e293b'),\n color: selected.length === 0\n ? (isDark ? '#6b7280' : '#94a3b8')\n : (isDark ? '#1e293b' : '#ffffff'),\n fontSize: isTouch ? 16 : 14,\n fontWeight: 500,\n cursor: isLoading || selected.length === 0 ? 'not-allowed' : 'pointer',\n transition: 'all 0.2s cubic-bezier(0.4, 0, 0.2, 1)',\n letterSpacing: '0.01em',\n display: 'flex',\n alignItems: 'center',\n justifyContent: 'center',\n gap: 8,\n opacity: isLoading ? 0.8 : 1,\n }}\n onMouseEnter={(e) => {\n if (!e.currentTarget.disabled) {\n e.currentTarget.style.backgroundColor = isDark ? '#cbd5e1' : '#334155';\n }\n }}\n onMouseLeave={(e) => {\n if (!e.currentTarget.disabled) {\n e.currentTarget.style.backgroundColor = selected.length === 0\n ? (isDark ? '#374151' : '#e2e8f0')\n : (isDark ? '#e2e8f0' : '#1e293b');\n }\n }}\n >\n {isLoading && <Spinner size={isTouch ? 18 : 16} color={isDark ? '#1e293b' : '#ffffff'} />}\n {isLoading ? (isEditing ? 'Updating...' : 'Submitting...') : (isEditing ? 'Update' : 'Submit')}\n </button>\n </div>\n );\n}\n","import React, { useRef, useEffect, useState } from 'react';\nimport { Theme, GotchaStyles, ResponseMode, ExistingResponse } from '../types';\nimport { cn } from '../utils/cn';\nimport { FeedbackMode } from './modes/FeedbackMode';\nimport { VoteMode } from './modes/VoteMode';\nimport { PollMode } from './modes/PollMode';\n\nexport interface GotchaModalProps {\n mode: ResponseMode;\n theme: Theme;\n customStyles?: GotchaStyles;\n promptText?: string;\n placeholder?: string;\n submitText: string;\n thankYouMessage: string;\n // State\n isLoading: boolean;\n isSubmitted: boolean;\n error: string | null;\n // Edit mode\n existingResponse?: ExistingResponse | null;\n isEditing?: boolean;\n // Vote mode\n voteLabels?: { up: string; down: string };\n // Poll mode\n options?: string[];\n allowMultiple?: boolean;\n // Handlers\n onSubmit: (data: { content?: string; rating?: number; vote?: 'up' | 'down'; pollSelected?: string[] }) => void;\n onClose: () => void;\n // Position info from parent\n anchorRect?: DOMRect;\n}\n\nexport function GotchaModal({\n mode,\n theme,\n customStyles,\n promptText,\n placeholder,\n submitText,\n thankYouMessage,\n isLoading,\n isSubmitted,\n error,\n existingResponse,\n isEditing = false,\n voteLabels,\n options,\n allowMultiple = false,\n onSubmit,\n onClose,\n anchorRect,\n}: GotchaModalProps) {\n const modalRef = useRef<HTMLDivElement>(null);\n const firstFocusableRef = useRef<HTMLButtonElement>(null);\n const [isVisible, setIsVisible] = useState(false);\n const [isMobile, setIsMobile] = useState(false);\n const [systemTheme, setSystemTheme] = useState<'light' | 'dark'>('light');\n\n // Detect mobile and system theme after mount (SSR-safe)\n useEffect(() => {\n setIsMobile(window.innerWidth < 640);\n\n // Detect system theme preference\n const darkQuery = window.matchMedia('(prefers-color-scheme: dark)');\n setSystemTheme(darkQuery.matches ? 'dark' : 'light');\n\n // Listen for theme changes\n const handler = (e: MediaQueryListEvent) => setSystemTheme(e.matches ? 'dark' : 'light');\n darkQuery.addEventListener('change', handler);\n return () => darkQuery.removeEventListener('change', handler);\n }, []);\n\n // Trigger animation after mount\n useEffect(() => {\n const timer = requestAnimationFrame(() => setIsVisible(true));\n return () => cancelAnimationFrame(timer);\n }, []);\n\n // Resolve theme\n const resolvedTheme = theme === 'auto' ? systemTheme : theme;\n\n const isDark = resolvedTheme === 'dark';\n\n // Determine if modal should appear above or below\n const modalHeight = 280; // approximate modal height\n const spaceBelow = anchorRect\n ? window.innerHeight - anchorRect.bottom\n : window.innerHeight / 2;\n const showAbove = spaceBelow < modalHeight + 20;\n\n // Focus trap\n useEffect(() => {\n const modal = modalRef.current;\n if (!modal) return;\n\n // Focus first element\n firstFocusableRef.current?.focus();\n\n const handleKeyDown = (e: KeyboardEvent) => {\n if (e.key === 'Escape') {\n onClose();\n return;\n }\n\n if (e.key === 'Tab') {\n const focusableElements = modal.querySelectorAll<HTMLElement>(\n 'button, [href], input, select, textarea, [tabindex]:not([tabindex=\"-1\"])'\n );\n const firstElement = focusableElements[0];\n const lastElement = focusableElements[focusableElements.length - 1];\n\n if (e.shiftKey && document.activeElement === firstElement) {\n e.preventDefault();\n lastElement?.focus();\n } else if (!e.shiftKey && document.activeElement === lastElement) {\n e.preventDefault();\n firstElement?.focus();\n }\n }\n };\n\n document.addEventListener('keydown', handleKeyDown);\n return () => document.removeEventListener('keydown', handleKeyDown);\n }, [onClose]);\n\n const defaultPrompt = mode === 'vote'\n ? 'What do you think?'\n : mode === 'poll'\n ? 'Cast your vote'\n : 'What do you think of this feature?';\n\n // Responsive sizing - on mobile, use fixed positioning centered on screen\n const modalPadding = isMobile ? 20 : 16;\n\n const layeredShadow = isDark\n ? '0 1px 2px rgba(0,0,0,0.2), 0 4px 12px rgba(0,0,0,0.3), 0 12px 32px rgba(0,0,0,0.2)'\n : '0 1px 2px rgba(0,0,0,0.04), 0 4px 12px rgba(0,0,0,0.06), 0 12px 32px rgba(0,0,0,0.06)';\n\n const modalStyles: React.CSSProperties = isMobile\n ? {\n // Mobile: fixed position, centered on screen\n position: 'fixed',\n left: '50%',\n top: '50%',\n width: 'calc(100vw - 32px)',\n maxWidth: 320,\n padding: modalPadding,\n borderRadius: 12,\n backgroundColor: isDark ? '#1f2937' : '#ffffff',\n color: isDark ? '#f9fafb' : '#111827',\n boxShadow: layeredShadow,\n border: `1px solid ${isDark ? 'rgba(255,255,255,0.06)' : 'rgba(0,0,0,0.06)'}`,\n zIndex: 9999,\n transition: 'opacity 0.25s cubic-bezier(0.4, 0, 0.2, 1), transform 0.25s cubic-bezier(0.4, 0, 0.2, 1)',\n opacity: isVisible ? 1 : 0,\n transform: isVisible\n ? 'translate(-50%, -50%) scale(1)'\n : 'translate(-50%, -50%) scale(0.96)',\n ...customStyles?.modal,\n }\n : {\n // Desktop: absolute position relative to button\n position: 'absolute',\n left: '50%',\n width: 320,\n padding: modalPadding,\n borderRadius: 10,\n backgroundColor: isDark ? '#1f2937' : '#ffffff',\n color: isDark ? '#f9fafb' : '#111827',\n boxShadow: layeredShadow,\n border: `1px solid ${isDark ? 'rgba(255,255,255,0.06)' : 'rgba(0,0,0,0.06)'}`,\n zIndex: 9999,\n ...(showAbove\n ? { bottom: '100%', marginBottom: 8 }\n : { top: '100%', marginTop: 8 }),\n transition: 'opacity 0.25s cubic-bezier(0.4, 0, 0.2, 1), transform 0.25s cubic-bezier(0.4, 0, 0.2, 1)',\n opacity: isVisible ? 1 : 0,\n transform: isVisible\n ? 'translateX(-50%) scale(1) translateY(0)'\n : `translateX(-50%) scale(0.96) translateY(${showAbove ? '6px' : '-6px'})`,\n ...customStyles?.modal,\n };\n\n return (\n <div\n ref={modalRef}\n role=\"dialog\"\n aria-modal=\"true\"\n aria-labelledby=\"gotcha-modal-title\"\n style={modalStyles}\n className={cn('gotcha-modal', isDark && 'gotcha-modal--dark')}\n >\n {/* Close button - larger on touch devices */}\n <button\n ref={firstFocusableRef}\n type=\"button\"\n onClick={onClose}\n aria-label=\"Close feedback form\"\n style={{\n position: 'absolute',\n top: isMobile ? 12 : 8,\n right: isMobile ? 12 : 8,\n width: isMobile ? 36 : 28,\n height: isMobile ? 36 : 28,\n border: 'none',\n background: 'transparent',\n cursor: 'pointer',\n color: isDark ? '#6b7280' : '#9ca3af',\n display: 'flex',\n alignItems: 'center',\n justifyContent: 'center',\n borderRadius: 6,\n transition: 'all 0.15s cubic-bezier(0.4, 0, 0.2, 1)',\n }}\n onMouseEnter={(e) => {\n e.currentTarget.style.backgroundColor = isDark ? 'rgba(255,255,255,0.06)' : 'rgba(0,0,0,0.04)';\n e.currentTarget.style.color = isDark ? '#9ca3af' : '#6b7280';\n }}\n onMouseLeave={(e) => {\n e.currentTarget.style.backgroundColor = 'transparent';\n e.currentTarget.style.color = isDark ? '#6b7280' : '#9ca3af';\n }}\n >\n <svg width={isMobile ? 16 : 12} height={isMobile ? 16 : 12} viewBox=\"0 0 14 14\" fill=\"none\">\n <path\n d=\"M1 1L13 13M1 13L13 1\"\n stroke=\"currentColor\"\n strokeWidth=\"1.5\"\n strokeLinecap=\"round\"\n />\n </svg>\n </button>\n\n {/* Title */}\n <h2\n id=\"gotcha-modal-title\"\n style={{\n margin: '0 0 16px 0',\n fontSize: isMobile ? 16 : 14,\n fontWeight: 600,\n paddingRight: isMobile ? 40 : 32,\n letterSpacing: '-0.01em',\n lineHeight: 1.4,\n }}\n >\n {promptText || defaultPrompt}\n </h2>\n\n {/* Success state */}\n {isSubmitted && (\n <div\n style={{\n textAlign: 'center',\n padding: '24px 0',\n color: isDark ? '#10b981' : '#059669',\n }}\n >\n <div\n style={{\n width: 44,\n height: 44,\n borderRadius: '50%',\n backgroundColor: isDark ? 'rgba(16,185,129,0.1)' : 'rgba(5,150,105,0.08)',\n display: 'flex',\n alignItems: 'center',\n justifyContent: 'center',\n margin: '0 auto 12px',\n }}\n >\n <svg\n width=\"22\"\n height=\"22\"\n viewBox=\"0 0 24 24\"\n fill=\"none\"\n >\n <path\n d=\"M20 6L9 17L4 12\"\n stroke=\"currentColor\"\n strokeWidth=\"2\"\n strokeLinecap=\"round\"\n strokeLinejoin=\"round\"\n />\n </svg>\n </div>\n <p style={{ margin: 0, fontSize: 13, fontWeight: 500, color: isDark ? '#d1d5db' : '#374151' }}>\n {thankYouMessage}\n </p>\n </div>\n )}\n\n {/* Error state */}\n {error && !isSubmitted && (\n <div\n style={{\n padding: '8px 10px',\n marginBottom: 12,\n borderRadius: 8,\n backgroundColor: isDark ? 'rgba(127,29,29,0.3)' : '#fef2f2',\n border: `1px solid ${isDark ? 'rgba(254,202,202,0.1)' : 'rgba(220,38,38,0.1)'}`,\n color: isDark ? '#fecaca' : '#dc2626',\n fontSize: 13,\n lineHeight: 1.4,\n }}\n >\n {error}\n </div>\n )}\n\n {/* Form content based on mode */}\n {!isSubmitted && (\n <>\n {mode === 'feedback' && (\n <FeedbackMode\n theme={resolvedTheme}\n placeholder={placeholder}\n submitText={submitText}\n isLoading={isLoading}\n onSubmit={onSubmit}\n customStyles={customStyles}\n initialValues={existingResponse ? {\n content: existingResponse.content,\n rating: existingResponse.rating,\n } : undefined}\n isEditing={isEditing}\n />\n )}\n {mode === 'vote' && (\n <VoteMode\n theme={resolvedTheme}\n isLoading={isLoading}\n onSubmit={onSubmit}\n initialVote={existingResponse?.vote || undefined}\n isEditing={isEditing}\n labels={voteLabels}\n />\n )}\n {mode === 'poll' && options && options.length > 0 && (\n <PollMode\n theme={resolvedTheme}\n options={options}\n allowMultiple={allowMultiple}\n isLoading={isLoading}\n onSubmit={onSubmit}\n initialSelected={existingResponse?.pollSelected || undefined}\n isEditing={isEditing}\n />\n )}\n </>\n )}\n\n {/* Screen reader announcement */}\n <div aria-live=\"polite\" className=\"sr-only\" style={{ position: 'absolute', left: -9999 }}>\n {isSubmitted && 'Thank you! Your feedback has been submitted.'}\n {error && `Error: ${error}`}\n </div>\n </div>\n );\n}\n","import React, { useState, useCallback, useEffect, useRef } from 'react';\nimport { createPortal } from 'react-dom';\nimport {\n ResponseMode,\n GotchaUser,\n Position,\n Size,\n Theme,\n TouchBehavior,\n GotchaStyles,\n GotchaResponse,\n GotchaError,\n} from '../types';\nimport { DEFAULTS } from '../constants';\nimport { useGotchaContext } from './GotchaProvider';\nimport { useSubmit } from '../hooks/useSubmit';\nimport { GotchaButton } from './GotchaButton';\nimport { GotchaModal } from './GotchaModal';\n\nexport interface GotchaProps {\n /** Unique identifier for this element */\n elementId: string;\n\n // User data\n /** User metadata for segmentation */\n user?: GotchaUser;\n\n // Behavior\n /** Feedback mode */\n mode?: ResponseMode;\n /** Required if mode is 'ab' */\n experimentId?: string;\n /** Current A/B variant shown to user */\n variant?: string;\n\n // Vote mode specific\n /** Custom labels for vote buttons (default: Like/Dislike) */\n voteLabels?: { up: string; down: string };\n\n // Poll mode specific (Phase 2)\n /** Required if mode is 'poll' (2-6 options) */\n options?: string[];\n /** Allow selecting multiple options */\n allowMultiple?: boolean;\n /** Show results after voting */\n showResults?: boolean;\n\n // Appearance\n /** Button position relative to parent */\n position?: Position;\n /** Button size */\n size?: Size;\n /** Color theme */\n theme?: Theme;\n /** Custom style overrides */\n customStyles?: GotchaStyles;\n /** Control visibility programmatically */\n visible?: boolean;\n /** Only show when parent is hovered (default: true) */\n showOnHover?: boolean;\n /** Mobile behavior (default: 'always-visible') */\n touchBehavior?: TouchBehavior;\n\n // Content\n /** Custom prompt text */\n promptText?: string;\n /** Input placeholder text */\n placeholder?: string;\n /** Submit button text */\n submitText?: string;\n /** Post-submission message */\n thankYouMessage?: string;\n\n // Callbacks\n /** Called after successful submission */\n onSubmit?: (response: GotchaResponse) => void;\n /** Called when modal opens */\n onOpen?: () => void;\n /** Called when modal closes */\n onClose?: () => void;\n /** Called on error */\n onError?: (error: GotchaError) => void;\n}\n\nexport function Gotcha({\n elementId,\n user,\n mode = 'feedback',\n experimentId,\n variant,\n voteLabels,\n options,\n allowMultiple = false,\n showResults = true,\n position = DEFAULTS.POSITION,\n size = DEFAULTS.SIZE,\n theme = DEFAULTS.THEME,\n customStyles,\n visible = true,\n showOnHover = DEFAULTS.SHOW_ON_HOVER,\n touchBehavior = DEFAULTS.TOUCH_BEHAVIOR,\n promptText,\n placeholder,\n submitText = DEFAULTS.SUBMIT_TEXT,\n thankYouMessage = DEFAULTS.THANK_YOU_MESSAGE,\n onSubmit,\n onOpen,\n onClose,\n onError,\n}: GotchaProps) {\n const { disabled, activeModalId, openModal, closeModal } = useGotchaContext();\n const [isSubmitted, setIsSubmitted] = useState(false);\n const [isParentHovered, setIsParentHovered] = useState(false);\n const [anchorRect, setAnchorRect] = useState<DOMRect | null>(null);\n const [isMobile, setIsMobile] = useState(false);\n const containerRef = useRef<HTMLDivElement>(null);\n\n // Detect mobile for portal rendering (SSR-safe)\n useEffect(() => {\n setIsMobile(window.innerWidth < 640);\n }, []);\n\n // This instance's modal is open if activeModalId matches our elementId\n const isOpen = activeModalId === elementId;\n\n // Attach hover listeners to the parent element (not the button container)\n useEffect(() => {\n if (!showOnHover) return;\n\n const container = containerRef.current;\n if (!container) return;\n\n // Find the parent element with position: relative\n const parent = container.parentElement;\n if (!parent) return;\n\n const handleMouseEnter = () => setIsParentHovered(true);\n const handleMouseLeave = () => setIsParentHovered(false);\n\n parent.addEventListener('mouseenter', handleMouseEnter);\n parent.addEventListener('mouseleave', handleMouseLeave);\n\n return () => {\n parent.removeEventListener('mouseenter', handleMouseEnter);\n parent.removeEventListener('mouseleave', handleMouseLeave);\n };\n }, [showOnHover]);\n\n const { submit, isLoading, error, existingResponse, isEditing } = useSubmit({\n elementId,\n mode,\n experimentId,\n variant,\n pollOptions: options,\n user,\n onSuccess: (response) => {\n setIsSubmitted(true);\n onSubmit?.(response);\n // Auto-close after 3 seconds\n setTimeout(() => {\n closeModal();\n setIsSubmitted(false);\n }, 3000);\n },\n onError: (err) => {\n console.warn('[Gotcha] Submission failed:', err instanceof Error ? err.message : err);\n onError?.(err as unknown as GotchaError);\n },\n });\n\n const handleOpen = useCallback(() => {\n if (containerRef.current) {\n setAnchorRect(containerRef.current.getBoundingClientRect());\n }\n openModal(elementId);\n onOpen?.();\n }, [elementId, openModal, onOpen]);\n\n const handleClose = useCallback(() => {\n closeModal();\n setIsSubmitted(false);\n onClose?.();\n }, [closeModal, onClose]);\n\n const handleSubmit = useCallback(\n (data: { content?: string; rating?: number; vote?: 'up' | 'down'; pollSelected?: string[] }) => {\n submit(data);\n },\n [submit]\n );\n\n // Don't render if disabled or not visible\n if (disabled || !visible) return null;\n\n // Position styles\n const positionStyles: Record<Position, React.CSSProperties> = {\n 'top-right': { position: 'absolute', top: 0, right: 0, transform: 'translate(50%, -50%)' },\n 'top-left': { position: 'absolute', top: 0, left: 0, transform: 'translate(-50%, -50%)' },\n 'bottom-right': { position: 'absolute', bottom: 0, right: 0, transform: 'translate(50%, 50%)' },\n 'bottom-left': { position: 'absolute', bottom: 0, left: 0, transform: 'translate(-50%, 50%)' },\n 'inline': { position: 'relative', display: 'inline-flex' },\n };\n\n return (\n <div\n ref={containerRef}\n style={{\n ...positionStyles[position],\n zIndex: isOpen ? 10000 : 'auto',\n }}\n className=\"gotcha-container\"\n data-gotcha-element={elementId}\n >\n <GotchaButton\n size={size}\n theme={theme}\n customStyles={customStyles}\n showOnHover={showOnHover}\n touchBehavior={touchBehavior}\n onClick={handleOpen}\n isOpen={isOpen}\n isParentHovered={isParentHovered}\n />\n\n {isOpen && !isMobile && (\n <GotchaModal\n mode={mode}\n theme={theme}\n customStyles={customStyles}\n promptText={promptText}\n placeholder={placeholder}\n submitText={submitText}\n thankYouMessage={isEditing ? 'Your feedback has been updated!' : thankYouMessage}\n isLoading={isLoading}\n isSubmitted={isSubmitted}\n error={error}\n existingResponse={existingResponse}\n isEditing={isEditing}\n voteLabels={voteLabels}\n options={options}\n allowMultiple={allowMultiple}\n onSubmit={handleSubmit}\n onClose={handleClose}\n anchorRect={anchorRect || undefined}\n />\n )}\n\n {/* On mobile, render modal via portal to escape parent transform */}\n {isOpen && isMobile && createPortal(\n <div\n style={{\n position: 'fixed',\n inset: 0,\n zIndex: 99999,\n backgroundColor: 'rgba(0, 0, 0, 0.3)',\n }}\n onClick={handleClose}\n aria-hidden=\"true\"\n >\n <div onClick={(e) => e.stopPropagation()}>\n <GotchaModal\n mode={mode}\n theme={theme}\n customStyles={customStyles}\n promptText={promptText}\n placeholder={placeholder}\n submitText={submitText}\n thankYouMessage={isEditing ? 'Your feedback has been updated!' : thankYouMessage}\n isLoading={isLoading}\n isSubmitted={isSubmitted}\n error={error}\n existingResponse={existingResponse}\n isEditing={isEditing}\n voteLabels={voteLabels}\n options={options}\n allowMultiple={allowMultiple}\n onSubmit={handleSubmit}\n onClose={handleClose}\n anchorRect={anchorRect || undefined}\n />\n </div>\n </div>,\n document.body\n )}\n </div>\n );\n}\n","import { useGotchaContext } from '../components/GotchaProvider';\n\n/**\n * Hook to access Gotcha context\n * Must be used within a GotchaProvider\n */\nexport function useGotcha() {\n const { client, disabled, defaultUser, debug } = useGotchaContext();\n\n return {\n /** The API client for manual submissions */\n client,\n /** Whether Gotcha is globally disabled */\n disabled,\n /** Default user metadata */\n defaultUser,\n /** Whether debug mode is enabled */\n debug,\n /** Submit feedback programmatically */\n submitFeedback: client.submitResponse.bind(client),\n };\n}\n"]}
1
+ {"version":3,"sources":["../src/constants.ts","../src/utils/anonymous.ts","../src/api/client.ts","../src/components/GotchaProvider.tsx","../src/hooks/useSubmit.ts","../src/utils/cn.ts","../src/utils/device.ts","../src/components/GotchaButton.tsx","../src/components/Spinner.tsx","../src/components/modes/FeedbackMode.tsx","../src/components/modes/VoteMode.tsx","../src/components/modes/PollMode.tsx","../src/components/GotchaModal.tsx","../src/components/Gotcha.tsx","../src/hooks/useGotcha.ts"],"names":["API_BASE_URL","STORAGE_KEYS","DEFAULTS","RETRY_CONFIG","getAnonymousId","stored","id","DEFAULT_RETRY_CONFIG","fetchWithRetry","url","options","config","debug","lastError","attempt","response","error","delay","resolve","createApiClient","apiKey","baseUrl","headers","request","method","endpoint","body","idempotencyKey","data","payload","user","fullPayload","elementId","userId","GotchaContext","createContext","GotchaProvider","children","disabled","defaultUser","activeModalId","setActiveModalId","useState","client","useMemo","openModal","useCallback","closeModal","value","jsx","useGotchaContext","context","useContext","useSubmit","isLoading","setIsLoading","isCheckingExisting","setIsCheckingExisting","setError","existingResponse","setExistingResponse","useEffect","cancelled","existing","err","errorMessage","cn","classes","isTouchDevice","getResponsiveSize","size","isTouch","sizes","getInitialSystemTheme","GotchaButton","theme","customStyles","showOnHover","touchBehavior","onClick","isOpen","isParentHovered","setIsTouch","tapRevealed","setTapRevealed","systemTheme","setSystemTheme","darkQuery","handler","e","shouldShow","handleClick","buttonSize","isDark","baseStyles","GotchaIcon","FONT_ID","useCarterOneFont","link","Spinner","color","jsxs","FeedbackMode","placeholder","submitText","onSubmit","initialValues","isEditing","showText","showRating","content","setContent","rating","setRating","canSubmit","handleSubmit","inputStyles","buttonStyles","StarRating","onChange","large","hovered","setHovered","starSize","buttonPadding","star","isFilled","VoteMode","initialVote","labels","activeVote","setActiveVote","previousVote","setPreviousVote","handleVote","vote","getButtonStyles","voteType","isSelected","iconSize","Fragment","ThumbsUpIcon","ThumbsDownIcon","PollMode","allowMultiple","initialSelected","selected","setSelected","handleToggle","option","prev","o","getOptionStyles","GotchaModal","mode","promptText","thankYouMessage","isSubmitted","voteLabels","onClose","anchorRect","modalRef","useRef","firstFocusableRef","isVisible","setIsVisible","isMobile","setIsMobile","timer","resolvedTheme","showAbove","modal","handleKeyDown","focusableElements","firstElement","lastElement","defaultPrompt","modalPadding","layeredShadow","modalStyles","Gotcha","experimentId","variant","showResults","position","visible","onOpen","onError","setIsSubmitted","setIsParentHovered","setAnchorRect","containerRef","container","parent","handleMouseEnter","handleMouseLeave","submit","handleOpen","handleClose","createPortal","useGotcha"],"mappings":"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","file":"index.mjs","sourcesContent":["// API URL\nexport const API_BASE_URL = 'https://gotcha.cx/api/v1';\n\n// Error codes\nexport const ERROR_CODES = {\n INVALID_API_KEY: 'INVALID_API_KEY',\n ORIGIN_NOT_ALLOWED: 'ORIGIN_NOT_ALLOWED',\n RATE_LIMITED: 'RATE_LIMITED',\n QUOTA_EXCEEDED: 'QUOTA_EXCEEDED',\n INVALID_REQUEST: 'INVALID_REQUEST',\n USER_NOT_FOUND: 'USER_NOT_FOUND',\n INTERNAL_ERROR: 'INTERNAL_ERROR',\n} as const;\n\n// Local storage keys\nexport const STORAGE_KEYS = {\n ANONYMOUS_ID: 'gotcha_anonymous_id',\n OFFLINE_QUEUE: 'gotcha_offline_queue',\n} as const;\n\n// Default values\nexport const DEFAULTS = {\n POSITION: 'top-right' as const,\n SIZE: 'md' as const,\n THEME: 'light' as const,\n SHOW_ON_HOVER: true,\n TOUCH_BEHAVIOR: 'always-visible' as const,\n SUBMIT_TEXT: 'Submit',\n THANK_YOU_MESSAGE: 'Thanks for your feedback!',\n} as const;\n\n// Size mappings (desktop/mobile in pixels)\nexport const SIZE_MAP = {\n sm: { desktop: 24, mobile: 44 },\n md: { desktop: 32, mobile: 44 },\n lg: { desktop: 40, mobile: 48 },\n} as const;\n\n// Retry config\nexport const RETRY_CONFIG = {\n MAX_RETRIES: 2,\n BASE_DELAY_MS: 500,\n MAX_DELAY_MS: 5000,\n} as const;\n","import { STORAGE_KEYS } from '../constants';\n\n/**\n * Get or create an anonymous user ID\n * Stored in localStorage for consistency across sessions\n */\nexport function getAnonymousId(): string {\n if (typeof window === 'undefined') {\n // SSR fallback - generate but don't persist\n return `anon_${crypto.randomUUID()}`;\n }\n\n const stored = localStorage.getItem(STORAGE_KEYS.ANONYMOUS_ID);\n if (stored) return stored;\n\n const id = `anon_${crypto.randomUUID()}`;\n localStorage.setItem(STORAGE_KEYS.ANONYMOUS_ID, id);\n return id;\n}\n\n/**\n * Clear the anonymous ID (useful for testing)\n */\nexport function clearAnonymousId(): void {\n if (typeof window !== 'undefined') {\n localStorage.removeItem(STORAGE_KEYS.ANONYMOUS_ID);\n }\n}\n","import { API_BASE_URL, RETRY_CONFIG } from '../constants';\nimport { SubmitResponsePayload, GotchaResponse, GotchaError, ExistingResponse, VoteType } from '../types';\nimport { getAnonymousId } from '../utils/anonymous';\n\ninterface ApiClientConfig {\n apiKey: string;\n baseUrl?: string;\n debug?: boolean;\n}\n\ninterface RetryConfig {\n maxRetries: number;\n baseDelayMs: number;\n maxDelayMs: number;\n}\n\nconst DEFAULT_RETRY_CONFIG: RetryConfig = {\n maxRetries: RETRY_CONFIG.MAX_RETRIES,\n baseDelayMs: RETRY_CONFIG.BASE_DELAY_MS,\n maxDelayMs: RETRY_CONFIG.MAX_DELAY_MS,\n};\n\n/**\n * Fetch with automatic retry and exponential backoff\n */\nasync function fetchWithRetry(\n url: string,\n options: RequestInit,\n config: RetryConfig = DEFAULT_RETRY_CONFIG,\n debug: boolean = false\n): Promise<Response> {\n let lastError: Error | null = null;\n\n for (let attempt = 0; attempt <= config.maxRetries; attempt++) {\n try {\n if (debug && attempt > 0) {\n console.log(`[Gotcha] Retry attempt ${attempt}/${config.maxRetries}`);\n }\n\n const response = await fetch(url, options);\n\n // Don't retry client errors (4xx) except 429 (rate limit)\n if (response.status >= 400 && response.status < 500 && response.status !== 429) {\n return response;\n }\n\n // Success - return immediately\n if (response.ok) {\n return response;\n }\n\n lastError = new Error(`HTTP ${response.status}`);\n } catch (error) {\n // Network error - retry\n lastError = error as Error;\n if (debug) {\n console.log(`[Gotcha] Network error: ${lastError.message}`);\n }\n }\n\n // Don't delay after last attempt\n if (attempt < config.maxRetries) {\n const delay = Math.min(\n config.baseDelayMs * Math.pow(2, attempt),\n config.maxDelayMs\n );\n await new Promise((resolve) => setTimeout(resolve, delay));\n }\n }\n\n throw lastError;\n}\n\nexport function createApiClient(config: ApiClientConfig) {\n const { apiKey, baseUrl = API_BASE_URL, debug = false } = config;\n\n const headers = {\n 'Content-Type': 'application/json',\n Authorization: `Bearer ${apiKey}`,\n };\n\n async function request<T>(\n method: string,\n endpoint: string,\n body?: unknown\n ): Promise<T> {\n const url = `${baseUrl}${endpoint}`;\n const idempotencyKey = crypto.randomUUID();\n\n if (debug) {\n console.log(`[Gotcha] ${method} ${endpoint}`, body);\n }\n\n const response = await fetchWithRetry(\n url,\n {\n method,\n headers: {\n ...headers,\n 'Idempotency-Key': idempotencyKey,\n },\n body: body ? JSON.stringify(body) : undefined,\n },\n DEFAULT_RETRY_CONFIG,\n debug\n );\n\n const data = await response.json();\n\n if (!response.ok) {\n const error = data.error as GotchaError;\n if (debug) {\n console.error(`[Gotcha] Error: ${error.code} - ${error.message}`);\n }\n throw error;\n }\n\n if (debug) {\n console.log(`[Gotcha] Response:`, data);\n }\n\n return data as T;\n }\n\n return {\n /**\n * Submit a response (feedback, vote, etc.)\n */\n async submitResponse(\n payload: Omit<SubmitResponsePayload, 'context'>\n ): Promise<GotchaResponse> {\n // Ensure user has an ID (anonymous if not provided)\n const user = payload.user || {};\n if (!user.id) {\n user.id = getAnonymousId();\n }\n\n const fullPayload: SubmitResponsePayload = {\n ...payload,\n user,\n context: {\n url: typeof window !== 'undefined' ? window.location.href : undefined,\n userAgent: typeof navigator !== 'undefined' ? navigator.userAgent : undefined,\n },\n };\n\n return request<GotchaResponse>('POST', '/responses', fullPayload);\n },\n\n /**\n * Check if a user has an existing response for an element\n */\n async checkExistingResponse(\n elementId: string,\n userId: string\n ): Promise<ExistingResponse | null> {\n const url = `${baseUrl}/responses/check?elementId=${encodeURIComponent(elementId)}&userId=${encodeURIComponent(userId)}`;\n\n if (debug) {\n console.log(`[Gotcha] GET /responses/check`);\n }\n\n const response = await fetchWithRetry(\n url,\n {\n method: 'GET',\n headers,\n },\n DEFAULT_RETRY_CONFIG,\n debug\n );\n\n const data = await response.json();\n\n if (!response.ok) {\n const error = data.error as GotchaError;\n if (debug) {\n console.error(`[Gotcha] Error: ${error.code} - ${error.message}`);\n }\n throw error;\n }\n\n if (data.exists) {\n if (debug) {\n console.log(`[Gotcha] Found existing response:`, data.response);\n }\n return data.response as ExistingResponse;\n }\n\n return null;\n },\n\n /**\n * Update an existing response\n */\n async updateResponse(\n id: string,\n payload: {\n content?: string;\n title?: string;\n rating?: number;\n vote?: VoteType;\n pollSelected?: string[];\n },\n userId?: string\n ): Promise<GotchaResponse> {\n const url = `${baseUrl}/responses/${id}${userId ? `?userId=${encodeURIComponent(userId)}` : ''}`;\n\n if (debug) {\n console.log(`[Gotcha] PATCH /responses/${id}`, payload);\n }\n\n const response = await fetchWithRetry(\n url,\n {\n method: 'PATCH',\n headers,\n body: JSON.stringify(payload),\n },\n DEFAULT_RETRY_CONFIG,\n debug\n );\n\n const data = await response.json();\n\n if (!response.ok) {\n const error = data.error as GotchaError;\n if (debug) {\n console.error(`[Gotcha] Error: ${error.code} - ${error.message}`);\n }\n throw error;\n }\n\n if (debug) {\n console.log(`[Gotcha] Response updated:`, data);\n }\n\n return data as GotchaResponse;\n },\n\n /**\n * Get the base URL (for debugging)\n */\n getBaseUrl(): string {\n return baseUrl;\n },\n };\n}\n\nexport type ApiClient = ReturnType<typeof createApiClient>;\n","import React, { createContext, useContext, useMemo, useState, useCallback } from 'react';\nimport { createApiClient, ApiClient } from '../api/client';\nimport { GotchaUser } from '../types';\n\nexport interface GotchaProviderProps {\n /** Your Gotcha API key */\n apiKey: string;\n /** React children */\n children: React.ReactNode;\n /** Override the API base URL (for testing/staging) */\n baseUrl?: string;\n /** Enable debug logging */\n debug?: boolean;\n /** Disable all Gotcha buttons globally */\n disabled?: boolean;\n /** Default user metadata applied to all submissions */\n defaultUser?: GotchaUser;\n}\n\nexport interface GotchaContextValue {\n client: ApiClient;\n disabled: boolean;\n defaultUser: GotchaUser;\n debug: boolean;\n // Modal management - only one open at a time\n activeModalId: string | null;\n openModal: (elementId: string) => void;\n closeModal: () => void;\n}\n\nconst GotchaContext = createContext<GotchaContextValue | null>(null);\n\nexport function GotchaProvider({\n apiKey,\n children,\n baseUrl,\n debug = false,\n disabled = false,\n defaultUser = {},\n}: GotchaProviderProps) {\n const [activeModalId, setActiveModalId] = useState<string | null>(null);\n\n const client = useMemo(\n () => createApiClient({ apiKey, baseUrl, debug }),\n [apiKey, baseUrl, debug]\n );\n\n const openModal = useCallback((elementId: string) => {\n setActiveModalId(elementId);\n }, []);\n\n const closeModal = useCallback(() => {\n setActiveModalId(null);\n }, []);\n\n const value: GotchaContextValue = useMemo(\n () => ({\n client,\n disabled,\n defaultUser,\n debug,\n activeModalId,\n openModal,\n closeModal,\n }),\n [client, disabled, defaultUser, debug, activeModalId, openModal, closeModal]\n );\n\n return (\n <GotchaContext.Provider value={value}>{children}</GotchaContext.Provider>\n );\n}\n\nexport function useGotchaContext(): GotchaContextValue {\n const context = useContext(GotchaContext);\n if (!context) {\n throw new Error('useGotchaContext must be used within a GotchaProvider');\n }\n return context;\n}\n","import { useState, useCallback, useEffect } from 'react';\nimport { useGotchaContext } from '../components/GotchaProvider';\nimport { ResponseMode, GotchaUser, GotchaResponse, VoteType, ExistingResponse } from '../types';\n\ninterface UseSubmitOptions {\n elementId: string;\n mode: ResponseMode;\n experimentId?: string;\n variant?: string;\n pollOptions?: string[];\n user?: GotchaUser;\n onSuccess?: (response: GotchaResponse) => void;\n onError?: (error: Error) => void;\n}\n\ninterface SubmitData {\n content?: string;\n title?: string;\n rating?: number;\n vote?: VoteType;\n pollSelected?: string[];\n}\n\nexport function useSubmit(options: UseSubmitOptions) {\n const { client, defaultUser } = useGotchaContext();\n const [isLoading, setIsLoading] = useState(false);\n const [isCheckingExisting, setIsCheckingExisting] = useState(false);\n const [error, setError] = useState<string | null>(null);\n const [existingResponse, setExistingResponse] = useState<ExistingResponse | null>(null);\n\n // Check for existing response when user ID is provided\n useEffect(() => {\n const userId = options.user?.id || defaultUser?.id;\n if (!userId) {\n setExistingResponse(null);\n return;\n }\n\n let cancelled = false;\n\n const checkExisting = async () => {\n setIsCheckingExisting(true);\n try {\n const existing = await client.checkExistingResponse(options.elementId, userId);\n if (!cancelled) {\n setExistingResponse(existing);\n }\n } catch {\n // Ignore errors - just means no existing response found\n if (!cancelled) {\n setExistingResponse(null);\n }\n } finally {\n if (!cancelled) {\n setIsCheckingExisting(false);\n }\n }\n };\n\n checkExisting();\n\n return () => {\n cancelled = true;\n };\n }, [client, options.elementId, options.user?.id, defaultUser?.id]);\n\n const submit = useCallback(\n async (data: SubmitData) => {\n setIsLoading(true);\n setError(null);\n\n try {\n const userId = options.user?.id || defaultUser?.id;\n let response: GotchaResponse;\n\n // If we have an existing response and a user ID, update instead of create\n if (existingResponse && userId) {\n response = await client.updateResponse(\n existingResponse.id,\n {\n content: data.content,\n title: data.title,\n rating: data.rating,\n vote: data.vote,\n pollSelected: data.pollSelected,\n },\n userId\n );\n } else {\n response = await client.submitResponse({\n elementId: options.elementId,\n mode: options.mode,\n content: data.content,\n title: data.title,\n rating: data.rating,\n vote: data.vote,\n pollOptions: options.pollOptions,\n pollSelected: data.pollSelected,\n experimentId: options.experimentId,\n variant: options.variant,\n user: { ...defaultUser, ...options.user },\n });\n }\n\n options.onSuccess?.(response);\n return response;\n } catch (err) {\n const errorMessage = err instanceof Error ? err.message : 'Something went wrong';\n setError(errorMessage);\n options.onError?.(err instanceof Error ? err : new Error(errorMessage));\n throw err;\n } finally {\n setIsLoading(false);\n }\n },\n [client, defaultUser, options, existingResponse]\n );\n\n return {\n submit,\n isLoading,\n isCheckingExisting,\n error,\n existingResponse,\n isEditing: !!existingResponse,\n clearError: () => setError(null),\n };\n}\n","/**\n * Simple class name utility\n * Combines class names, filtering out falsy values\n */\nexport function cn(...classes: (string | undefined | null | false)[]): string {\n return classes.filter(Boolean).join(' ');\n}\n","/**\n * Detect if the device supports touch\n */\nexport const isTouchDevice = (): boolean => {\n if (typeof window === 'undefined') return false;\n return 'ontouchstart' in window || navigator.maxTouchPoints > 0;\n};\n\n/**\n * Get the appropriate size based on device type\n */\nexport const getResponsiveSize = (\n size: 'sm' | 'md' | 'lg',\n isTouch: boolean\n): number => {\n const sizes = {\n sm: { desktop: 24, mobile: 32 },\n md: { desktop: 32, mobile: 36 },\n lg: { desktop: 40, mobile: 40 },\n };\n\n return isTouch ? sizes[size].mobile : sizes[size].desktop;\n};\n","import React, { useState, useEffect } from 'react';\nimport { Size, Theme, GotchaStyles } from '../types';\nimport { cn } from '../utils/cn';\nimport { isTouchDevice, getResponsiveSize } from '../utils/device';\n\nexport interface GotchaButtonProps {\n size: Size;\n theme: Theme;\n customStyles?: GotchaStyles;\n showOnHover: boolean;\n touchBehavior: 'always-visible' | 'tap-to-reveal';\n onClick: () => void;\n isOpen: boolean;\n isParentHovered?: boolean;\n}\n\n/**\n * Detect system color-scheme preference synchronously where possible,\n * falling back to 'light'. This avoids the flash that occurred when\n * the old code always initialised state as 'light' and corrected it\n * inside useEffect.\n */\nfunction getInitialSystemTheme(): 'light' | 'dark' {\n if (typeof window === 'undefined') return 'light';\n return window.matchMedia('(prefers-color-scheme: dark)').matches\n ? 'dark'\n : 'light';\n}\n\nexport function GotchaButton({\n size,\n theme,\n customStyles,\n showOnHover,\n touchBehavior,\n onClick,\n isOpen,\n isParentHovered = false,\n}: GotchaButtonProps) {\n const [isTouch, setIsTouch] = useState(false);\n const [tapRevealed, setTapRevealed] = useState(false);\n const [systemTheme, setSystemTheme] = useState<'light' | 'dark'>(getInitialSystemTheme);\n\n useEffect(() => {\n setIsTouch(isTouchDevice());\n\n // Keep systemTheme in sync when user changes OS preference\n const darkQuery = window.matchMedia('(prefers-color-scheme: dark)');\n const handler = (e: MediaQueryListEvent) =>\n setSystemTheme(e.matches ? 'dark' : 'light');\n darkQuery.addEventListener('change', handler);\n return () => darkQuery.removeEventListener('change', handler);\n }, []);\n\n // Determine visibility\n const shouldShow = (() => {\n if (isOpen) return true;\n if (!isTouch && showOnHover) return isParentHovered;\n if (isTouch && touchBehavior === 'tap-to-reveal') return tapRevealed;\n return true;\n })();\n\n const handleClick = () => {\n if (isTouch && touchBehavior === 'tap-to-reveal' && !tapRevealed) {\n setTapRevealed(true);\n return;\n }\n onClick();\n };\n\n const buttonSize = getResponsiveSize(size, isTouch);\n\n // ── Resolve theme ────────────────────────────────────────────────\n // \"auto\" must produce the *exact* same styles as the explicit theme\n // it resolves to. Previously the initial state defaulted to 'light'\n // regardless of the actual preference, causing a mismatch on the\n // first render when the system was dark.\n const resolvedTheme = theme === 'auto' ? systemTheme : theme;\n const isDark = resolvedTheme === 'dark';\n\n // ── Glass-bubble styles ──────────────────────────────────────────\n // Simulates a raised glass dome / marble sitting on the surface:\n // - Bright borderTop highlight mimics light hitting the top edge\n // - Subtle darker base border grounds the bottom\n // - Vertical gradient: bright at top, more opaque at bottom\n // - Inset top shadow for inner refraction glow\n // - Inset bottom shadow for depth within the dome\n // - Outer shadow to anchor the bubble to the surface\n const baseStyles: React.CSSProperties = {\n width: buttonSize,\n height: buttonSize,\n borderRadius: '50%',\n border: isDark\n ? '1px solid rgba(255,255,255,0.15)'\n : 'none',\n cursor: 'pointer',\n display: 'flex',\n alignItems: 'center',\n justifyContent: 'center',\n background: isDark\n ? 'linear-gradient(180deg, rgba(255,255,255,0.16) 0%, rgba(255,255,255,0.04) 60%, rgba(0,0,0,0.05) 100%)'\n : 'linear-gradient(160deg, rgba(255,255,255,0.7) 0%, rgba(200,210,230,0.4) 40%, rgba(180,192,220,0.5) 100%)',\n backdropFilter: 'blur(16px) saturate(170%)',\n WebkitBackdropFilter: 'blur(16px) saturate(170%)',\n color: isDark ? 'rgba(255,255,255,0.88)' : 'rgba(0,0,0,0.75)',\n boxShadow: isDark\n ? '0 4px 14px rgba(0,0,0,0.45), 0 1px 3px rgba(0,0,0,0.35)'\n : '0 3px 12px rgba(0,0,0,0.12), 0 0 1px rgba(0,0,0,0.2)',\n transition: 'all 0.2s cubic-bezier(0.4, 0, 0.2, 1)',\n opacity: shouldShow ? 1 : 0,\n transform: shouldShow ? 'scale(1)' : 'scale(0.6)',\n pointerEvents: shouldShow ? 'auto' : 'none',\n ...customStyles?.button,\n };\n\n return (\n <button\n type=\"button\"\n onClick={handleClick}\n style={baseStyles}\n className={cn('gotcha-button', isOpen && 'gotcha-button--open')}\n aria-label=\"Give feedback on this feature\"\n aria-expanded={isOpen}\n aria-haspopup=\"dialog\"\n >\n <GotchaIcon size={buttonSize * 0.65} />\n </button>\n );\n}\n\nconst FONT_ID = 'gotcha-carter-one';\n\nfunction useCarterOneFont() {\n useEffect(() => {\n if (document.getElementById(FONT_ID)) return;\n const link = document.createElement('link');\n link.id = FONT_ID;\n link.rel = 'stylesheet';\n link.href = 'https://fonts.googleapis.com/css2?family=Carter+One&display=swap';\n document.head.appendChild(link);\n }, []);\n}\n\nfunction GotchaIcon({ size }: { size: number }) {\n useCarterOneFont();\n return (\n <span\n aria-hidden=\"true\"\n style={{\n fontFamily: \"'Carter One', cursive\",\n fontSize: size,\n lineHeight: 1,\n display: 'flex',\n alignItems: 'center',\n justifyContent: 'center',\n marginTop: size * 0.05,\n marginRight: size * 0.05,\n userSelect: 'none',\n }}\n >\n G\n </span>\n );\n}\n","import React from 'react';\n\ninterface SpinnerProps {\n size?: number;\n color?: string;\n}\n\nexport function Spinner({ size = 16, color = 'currentColor' }: SpinnerProps) {\n return (\n <svg\n width={size}\n height={size}\n viewBox=\"0 0 24 24\"\n fill=\"none\"\n style={{\n animation: 'gotcha-spin 0.8s linear infinite',\n }}\n >\n <style>\n {`\n @keyframes gotcha-spin {\n from { transform: rotate(0deg); }\n to { transform: rotate(360deg); }\n }\n @keyframes gotcha-dash {\n 0% { stroke-dasharray: 1, 62; stroke-dashoffset: 0; }\n 50% { stroke-dasharray: 40, 62; stroke-dashoffset: -12; }\n 100% { stroke-dasharray: 1, 62; stroke-dashoffset: -62; }\n }\n `}\n </style>\n <circle\n cx=\"12\"\n cy=\"12\"\n r=\"10\"\n stroke={color}\n strokeWidth=\"2\"\n strokeOpacity=\"0.12\"\n />\n <circle\n cx=\"12\"\n cy=\"12\"\n r=\"10\"\n stroke={color}\n strokeWidth=\"2\"\n strokeLinecap=\"round\"\n style={{\n animation: 'gotcha-dash 1.2s ease-in-out infinite',\n }}\n />\n </svg>\n );\n}\n","import React, { useState, useEffect } from 'react';\nimport { GotchaStyles } from '../../types';\nimport { isTouchDevice } from '../../utils/device';\nimport { Spinner } from '../Spinner';\n\ninterface FeedbackModeProps {\n theme: 'light' | 'dark' | 'custom';\n placeholder?: string;\n submitText: string;\n isLoading: boolean;\n onSubmit: (data: { content?: string; rating?: number }) => void;\n customStyles?: GotchaStyles;\n initialValues?: {\n content?: string | null;\n rating?: number | null;\n };\n isEditing?: boolean;\n /** Show the text input (default: true) */\n showText?: boolean;\n /** Show the star rating (default: true) */\n showRating?: boolean;\n}\n\nexport function FeedbackMode({\n theme,\n placeholder,\n submitText,\n isLoading,\n onSubmit,\n customStyles,\n initialValues,\n isEditing = false,\n showText = true,\n showRating = true,\n}: FeedbackModeProps) {\n const [content, setContent] = useState(initialValues?.content || '');\n const [rating, setRating] = useState<number | null>(initialValues?.rating ?? null);\n const [isTouch, setIsTouch] = useState(false);\n\n useEffect(() => {\n setIsTouch(isTouchDevice());\n }, []);\n\n // Update local state when initialValues change (e.g., after loading existing response)\n useEffect(() => {\n if (initialValues?.content !== undefined) {\n setContent(initialValues.content || '');\n }\n if (initialValues?.rating !== undefined) {\n setRating(initialValues.rating ?? null);\n }\n }, [initialValues?.content, initialValues?.rating]);\n\n const isDark = theme === 'dark';\n\n const canSubmit = (() => {\n if (showText && showRating) return content.trim().length > 0 || rating !== null;\n if (showText) return content.trim().length > 0;\n if (showRating) return rating !== null;\n return false;\n })();\n\n const handleSubmit = (e: React.FormEvent) => {\n e.preventDefault();\n if (!canSubmit) return;\n onSubmit({\n content: showText && content.trim() ? content.trim() : undefined,\n rating: showRating && rating !== null ? rating : undefined,\n });\n };\n\n const inputStyles: React.CSSProperties = {\n width: '100%',\n padding: isTouch ? '12px 14px' : '10px 12px',\n border: `1px solid ${isDark ? 'rgba(255,255,255,0.08)' : '#e2e8f0'}`,\n borderRadius: 8,\n backgroundColor: isDark ? 'rgba(55,65,81,0.5)' : '#fafbfc',\n color: isDark ? '#f9fafb' : '#111827',\n fontSize: isTouch ? 16 : 14, // 16px prevents iOS zoom on focus\n resize: 'vertical',\n minHeight: isTouch ? 100 : 80,\n fontFamily: 'inherit',\n outline: 'none',\n transition: 'border-color 0.2s cubic-bezier(0.4, 0, 0.2, 1), box-shadow 0.2s cubic-bezier(0.4, 0, 0.2, 1)',\n lineHeight: 1.5,\n ...customStyles?.input,\n };\n\n const buttonStyles: React.CSSProperties = {\n width: '100%',\n padding: isTouch ? '14px 16px' : '10px 16px',\n border: 'none',\n borderRadius: 8,\n backgroundColor: isDark ? '#e2e8f0' : '#1e293b',\n color: isDark ? '#1e293b' : '#ffffff',\n fontSize: isTouch ? 16 : 14,\n fontWeight: 500,\n cursor: isLoading ? 'not-allowed' : 'pointer',\n transition: 'all 0.2s cubic-bezier(0.4, 0, 0.2, 1)',\n letterSpacing: '0.01em',\n ...customStyles?.submitButton,\n };\n\n return (\n <form onSubmit={handleSubmit}>\n {/* Rating */}\n {showRating && (\n <div style={{\n marginBottom: showText ? (isTouch ? 16 : 12) : 0,\n ...(!showText ? { display: 'flex', justifyContent: 'center', padding: '8px 0' } : {}),\n }}>\n <StarRating value={rating} onChange={setRating} isDark={isDark} isTouch={isTouch} large={!showText} />\n </div>\n )}\n\n {/* Text input */}\n {showText && (\n <textarea\n value={content}\n onChange={(e) => setContent(e.target.value)}\n placeholder={placeholder || 'Share your thoughts...'}\n style={inputStyles}\n disabled={isLoading}\n aria-label=\"Your feedback\"\n onFocus={(e) => {\n e.currentTarget.style.borderColor = '#1e293b';\n e.currentTarget.style.boxShadow = '0 0 0 2px rgba(30,41,59,0.15)';\n e.currentTarget.style.backgroundColor = isDark ? 'rgba(55,65,81,0.7)' : '#ffffff';\n }}\n onBlur={(e) => {\n e.currentTarget.style.borderColor = isDark ? 'rgba(255,255,255,0.08)' : '#e2e8f0';\n e.currentTarget.style.boxShadow = 'none';\n e.currentTarget.style.backgroundColor = isDark ? 'rgba(55,65,81,0.5)' : '#fafbfc';\n }}\n />\n )}\n\n {/* Submit button */}\n <button\n type=\"submit\"\n disabled={isLoading || !canSubmit}\n style={{\n ...buttonStyles,\n marginTop: 12,\n opacity: isLoading ? 0.8 : 1,\n backgroundColor: !canSubmit\n ? (isDark ? '#374151' : '#e2e8f0')\n : (isDark ? '#e2e8f0' : '#1e293b'),\n color: !canSubmit\n ? (isDark ? '#6b7280' : '#94a3b8')\n : (isDark ? '#1e293b' : '#ffffff'),\n display: 'flex',\n alignItems: 'center',\n justifyContent: 'center',\n gap: 8,\n }}\n onMouseEnter={(e) => {\n if (!e.currentTarget.disabled) {\n e.currentTarget.style.backgroundColor = isDark ? '#cbd5e1' : '#334155';\n }\n }}\n onMouseLeave={(e) => {\n if (!e.currentTarget.disabled) {\n e.currentTarget.style.backgroundColor = isDark ? '#e2e8f0' : '#1e293b';\n }\n }}\n >\n {isLoading && <Spinner size={isTouch ? 18 : 16} color={isDark ? '#1e293b' : '#ffffff'} />}\n {isLoading ? (isEditing ? 'Updating...' : 'Submitting...') : (isEditing ? 'Update' : submitText)}\n </button>\n </form>\n );\n}\n\ninterface StarRatingProps {\n value: number | null;\n onChange: (rating: number) => void;\n isDark: boolean;\n isTouch: boolean;\n large?: boolean;\n}\n\nfunction StarRating({ value, onChange, isDark, isTouch, large = false }: StarRatingProps) {\n const [hovered, setHovered] = useState<number | null>(null);\n const starSize = large ? (isTouch ? 36 : 28) : (isTouch ? 28 : 18);\n const buttonPadding = large ? (isTouch ? 8 : 5) : (isTouch ? 6 : 3);\n\n return (\n <div\n style={{\n display: 'flex',\n gap: large ? (isTouch ? 8 : 6) : (isTouch ? 6 : 2),\n }}\n role=\"group\"\n aria-label=\"Rating\"\n >\n {[1, 2, 3, 4, 5].map((star) => {\n const isFilled = (hovered ?? value ?? 0) >= star;\n return (\n <button\n key={star}\n type=\"button\"\n onClick={() => onChange(star)}\n onMouseEnter={() => setHovered(star)}\n onMouseLeave={() => setHovered(null)}\n aria-label={`Rate ${star} out of 5`}\n aria-pressed={value === star}\n style={{\n background: 'none',\n border: 'none',\n cursor: 'pointer',\n padding: buttonPadding,\n color: isFilled ? '#f59e0b' : (isDark ? 'rgba(255,255,255,0.12)' : '#e2e8f0'),\n transition: 'color 0.15s cubic-bezier(0.4, 0, 0.2, 1), transform 0.15s cubic-bezier(0.4, 0, 0.2, 1)',\n transform: (hovered !== null && hovered >= star) ? 'scale(1.1)' : 'scale(1)',\n }}\n >\n <svg width={starSize} height={starSize} viewBox=\"0 0 24 24\" fill=\"currentColor\">\n <path d=\"M12 2l3.09 6.26L22 9.27l-5 4.87 1.18 6.88L12 17.77l-6.18 3.25L7 14.14 2 9.27l6.91-1.01L12 2z\" />\n </svg>\n </button>\n );\n })}\n </div>\n );\n}\n","import React, { useEffect, useState } from 'react';\nimport { isTouchDevice } from '../../utils/device';\nimport { Spinner } from '../Spinner';\n\ninterface VoteModeProps {\n theme: 'light' | 'dark' | 'custom';\n isLoading: boolean;\n onSubmit: (data: { vote: 'up' | 'down' }) => void;\n initialVote?: 'up' | 'down' | null;\n isEditing?: boolean;\n labels?: { up: string; down: string };\n}\n\nexport function VoteMode({ theme, isLoading, onSubmit, initialVote, isEditing = false, labels }: VoteModeProps) {\n const [isTouch, setIsTouch] = useState(false);\n const [activeVote, setActiveVote] = useState<'up' | 'down' | null>(initialVote || null);\n const [previousVote, setPreviousVote] = useState<'up' | 'down' | null>(initialVote || null);\n\n useEffect(() => {\n setIsTouch(isTouchDevice());\n }, []);\n\n // Update when initialVote changes (e.g., after loading existing response)\n useEffect(() => {\n if (initialVote !== undefined) {\n setPreviousVote(initialVote);\n setActiveVote(initialVote);\n }\n }, [initialVote]);\n\n // Reset active vote when loading completes (but keep previous vote for edit mode)\n useEffect(() => {\n if (!isLoading && !isEditing) {\n setActiveVote(null);\n }\n }, [isLoading, isEditing]);\n\n const handleVote = (vote: 'up' | 'down') => {\n setActiveVote(vote);\n onSubmit({ vote });\n };\n\n const isDark = theme === 'dark';\n\n const getButtonStyles = (voteType: 'up' | 'down'): React.CSSProperties => {\n const isSelected = previousVote === voteType;\n const selectedColor = voteType === 'up' ? '#10b981' : '#ef4444';\n return {\n flex: 1,\n minWidth: 0,\n overflow: 'hidden' as const,\n padding: isTouch ? '14px 18px' : '10px 14px',\n border: `1px solid ${isSelected\n ? (voteType === 'up'\n ? (isDark ? 'rgba(16,185,129,0.3)' : 'rgba(16,185,129,0.25)')\n : (isDark ? 'rgba(239,68,68,0.3)' : 'rgba(239,68,68,0.25)'))\n : (isDark ? 'rgba(255,255,255,0.08)' : '#e2e8f0')}`,\n borderRadius: isTouch ? 10 : 8,\n backgroundColor: isSelected\n ? (voteType === 'up'\n ? (isDark ? 'rgba(16,185,129,0.08)' : 'rgba(16,185,129,0.06)')\n : (isDark ? 'rgba(239,68,68,0.08)' : 'rgba(239,68,68,0.06)'))\n : (isDark ? 'rgba(55,65,81,0.5)' : '#fafbfc'),\n color: isSelected\n ? selectedColor\n : (isDark ? '#d1d5db' : '#64748b'),\n fontSize: isTouch ? 28 : 24,\n cursor: isLoading ? 'not-allowed' : 'pointer',\n transition: 'background-color 0.2s, border-color 0.2s, color 0.2s, transform 0.2s, box-shadow 0.2s',\n display: 'flex',\n alignItems: 'center',\n justifyContent: 'center',\n gap: isTouch ? 10 : 8,\n };\n };\n\n const iconSize = isTouch ? 24 : 20;\n\n return (\n <div\n style={{\n display: 'flex',\n gap: isTouch ? 12 : 10,\n }}\n role=\"group\"\n aria-label=\"Vote\"\n >\n <button\n type=\"button\"\n onClick={() => handleVote('up')}\n disabled={isLoading}\n style={getButtonStyles('up')}\n aria-label=\"Vote up - I like this\"\n aria-pressed={previousVote === 'up'}\n onMouseEnter={(e) => {\n if (!isLoading) {\n e.currentTarget.style.transform = 'translateY(-1px)';\n e.currentTarget.style.boxShadow = '0 2px 8px rgba(0,0,0,0.06)';\n }\n }}\n onMouseLeave={(e) => {\n e.currentTarget.style.transform = 'translateY(0)';\n e.currentTarget.style.boxShadow = 'none';\n }}\n >\n {isLoading && activeVote === 'up' ? (\n <>\n <Spinner size={iconSize} color={isDark ? '#f9fafb' : '#111827'} />\n <span style={{ fontSize: isTouch ? 15 : 13, fontWeight: 500, letterSpacing: '0.01em' }}>\n {isEditing ? 'Updating...' : 'Sending...'}\n </span>\n </>\n ) : (\n <>\n <ThumbsUpIcon size={iconSize} />\n <span style={{ fontSize: isTouch ? 15 : 13, fontWeight: 500, letterSpacing: '0.01em' }}>\n {labels?.up || (previousVote === 'up' ? 'Liked' : 'Like')}\n </span>\n </>\n )}\n </button>\n\n <button\n type=\"button\"\n onClick={() => handleVote('down')}\n disabled={isLoading}\n style={getButtonStyles('down')}\n aria-label=\"Vote down - I don't like this\"\n aria-pressed={previousVote === 'down'}\n onMouseEnter={(e) => {\n if (!isLoading) {\n e.currentTarget.style.transform = 'translateY(-1px)';\n e.currentTarget.style.boxShadow = '0 2px 8px rgba(0,0,0,0.06)';\n }\n }}\n onMouseLeave={(e) => {\n e.currentTarget.style.transform = 'translateY(0)';\n e.currentTarget.style.boxShadow = 'none';\n }}\n >\n {isLoading && activeVote === 'down' ? (\n <>\n <Spinner size={iconSize} color={isDark ? '#f9fafb' : '#111827'} />\n <span style={{ fontSize: isTouch ? 15 : 13, fontWeight: 500, letterSpacing: '0.01em' }}>\n {isEditing ? 'Updating...' : 'Sending...'}\n </span>\n </>\n ) : (\n <>\n <ThumbsDownIcon size={iconSize} />\n <span style={{ fontSize: isTouch ? 15 : 13, fontWeight: 500, letterSpacing: '0.01em' }}>\n {labels?.down || (previousVote === 'down' ? 'Disliked' : 'Dislike')}\n </span>\n </>\n )}\n </button>\n </div>\n );\n}\n\nfunction ThumbsUpIcon({ size = 24 }: { size?: number }) {\n return (\n <svg width={size} height={size} viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" strokeWidth=\"1.75\" strokeLinecap=\"round\" strokeLinejoin=\"round\">\n <path d=\"M14 9V5a3 3 0 0 0-3-3l-4 9v11h11.28a2 2 0 0 0 2-1.7l1.38-9a2 2 0 0 0-2-2.3zM7 22H4a2 2 0 0 1-2-2v-7a2 2 0 0 1 2-2h3\" />\n </svg>\n );\n}\n\nfunction ThumbsDownIcon({ size = 24 }: { size?: number }) {\n return (\n <svg width={size} height={size} viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" strokeWidth=\"1.75\" strokeLinecap=\"round\" strokeLinejoin=\"round\">\n <path d=\"M10 15v4a3 3 0 0 0 3 3l4-9V2H5.72a2 2 0 0 0-2 1.7l-1.38 9a2 2 0 0 0 2 2.3zm7-13h2.67A2.31 2.31 0 0 1 22 4v7a2.31 2.31 0 0 1-2.33 2H17\" />\n </svg>\n );\n}\n","import React, { useState, useEffect } from 'react';\nimport { isTouchDevice } from '../../utils/device';\nimport { Spinner } from '../Spinner';\n\ninterface PollModeProps {\n theme: 'light' | 'dark' | 'custom';\n options: string[];\n allowMultiple: boolean;\n isLoading: boolean;\n onSubmit: (data: { pollSelected: string[] }) => void;\n initialSelected?: string[] | null;\n isEditing?: boolean;\n}\n\nexport function PollMode({\n theme,\n options,\n allowMultiple,\n isLoading,\n onSubmit,\n initialSelected,\n isEditing = false,\n}: PollModeProps) {\n const [selected, setSelected] = useState<string[]>(initialSelected || []);\n const [isTouch, setIsTouch] = useState(false);\n\n useEffect(() => {\n setIsTouch(isTouchDevice());\n }, []);\n\n useEffect(() => {\n if (initialSelected) {\n setSelected(initialSelected);\n }\n }, [initialSelected]);\n\n const isDark = theme === 'dark';\n\n const handleToggle = (option: string) => {\n if (allowMultiple) {\n setSelected((prev) =>\n prev.includes(option) ? prev.filter((o) => o !== option) : [...prev, option]\n );\n } else {\n setSelected((prev) => (prev.includes(option) ? [] : [option]));\n }\n };\n\n const handleSubmit = () => {\n if (selected.length === 0) return;\n onSubmit({ pollSelected: selected });\n };\n\n const getOptionStyles = (option: string): React.CSSProperties => {\n const isSelected = selected.includes(option);\n return {\n width: '100%',\n padding: isTouch ? '12px 14px' : '9px 12px',\n border: `1px solid ${isSelected\n ? (isDark ? 'rgba(226,232,240,0.25)' : 'rgba(30,41,59,0.25)')\n : (isDark ? 'rgba(255,255,255,0.08)' : '#e2e8f0')}`,\n borderRadius: isTouch ? 10 : 8,\n backgroundColor: isSelected\n ? (isDark ? 'rgba(226,232,240,0.08)' : 'rgba(30,41,59,0.05)')\n : (isDark ? 'rgba(55,65,81,0.5)' : '#fafbfc'),\n color: isSelected\n ? (isDark ? '#e2e8f0' : '#1e293b')\n : (isDark ? '#d1d5db' : '#374151'),\n fontSize: isTouch ? 15 : 13,\n fontWeight: 500,\n cursor: isLoading ? 'not-allowed' : 'pointer',\n transition: 'background-color 0.2s, border-color 0.2s, color 0.2s',\n textAlign: 'left' as const,\n letterSpacing: '0.01em',\n display: 'flex',\n alignItems: 'center',\n gap: 8,\n };\n };\n\n return (\n <div>\n <div\n style={{\n display: 'flex',\n flexDirection: 'column',\n gap: isTouch ? 8 : 6,\n }}\n role=\"group\"\n aria-label={allowMultiple ? 'Select one or more options' : 'Select an option'}\n >\n {options.map((option) => {\n const isSelected = selected.includes(option);\n return (\n <button\n key={option}\n type=\"button\"\n onClick={() => handleToggle(option)}\n disabled={isLoading}\n style={getOptionStyles(option)}\n aria-pressed={isSelected}\n >\n <span\n style={{\n width: 16,\n height: 16,\n borderRadius: allowMultiple ? 4 : '50%',\n border: `2px solid ${isSelected\n ? (isDark ? '#e2e8f0' : '#1e293b')\n : (isDark ? 'rgba(255,255,255,0.2)' : '#cbd5e1')}`,\n backgroundColor: isSelected\n ? (isDark ? '#e2e8f0' : '#1e293b')\n : 'transparent',\n display: 'flex',\n alignItems: 'center',\n justifyContent: 'center',\n flexShrink: 0,\n transition: 'all 0.15s',\n }}\n >\n {isSelected && (\n <svg width={10} height={10} viewBox=\"0 0 12 12\" fill=\"none\">\n <path\n d=\"M2 6l3 3 5-5\"\n stroke=\"#fff\"\n strokeWidth=\"2\"\n strokeLinecap=\"round\"\n strokeLinejoin=\"round\"\n />\n </svg>\n )}\n </span>\n {option}\n </button>\n );\n })}\n </div>\n\n <button\n type=\"button\"\n onClick={handleSubmit}\n disabled={isLoading || selected.length === 0}\n style={{\n width: '100%',\n marginTop: 12,\n padding: isTouch ? '14px 16px' : '10px 16px',\n border: 'none',\n borderRadius: 8,\n backgroundColor: selected.length === 0\n ? (isDark ? '#374151' : '#e2e8f0')\n : (isDark ? '#e2e8f0' : '#1e293b'),\n color: selected.length === 0\n ? (isDark ? '#6b7280' : '#94a3b8')\n : (isDark ? '#1e293b' : '#ffffff'),\n fontSize: isTouch ? 16 : 14,\n fontWeight: 500,\n cursor: isLoading || selected.length === 0 ? 'not-allowed' : 'pointer',\n transition: 'all 0.2s cubic-bezier(0.4, 0, 0.2, 1)',\n letterSpacing: '0.01em',\n display: 'flex',\n alignItems: 'center',\n justifyContent: 'center',\n gap: 8,\n opacity: isLoading ? 0.8 : 1,\n }}\n onMouseEnter={(e) => {\n if (!e.currentTarget.disabled) {\n e.currentTarget.style.backgroundColor = isDark ? '#cbd5e1' : '#334155';\n }\n }}\n onMouseLeave={(e) => {\n if (!e.currentTarget.disabled) {\n e.currentTarget.style.backgroundColor = selected.length === 0\n ? (isDark ? '#374151' : '#e2e8f0')\n : (isDark ? '#e2e8f0' : '#1e293b');\n }\n }}\n >\n {isLoading && <Spinner size={isTouch ? 18 : 16} color={isDark ? '#1e293b' : '#ffffff'} />}\n {isLoading ? (isEditing ? 'Updating...' : 'Submitting...') : (isEditing ? 'Update' : 'Submit')}\n </button>\n </div>\n );\n}\n","import React, { useRef, useEffect, useState } from 'react';\nimport { Theme, GotchaStyles, ResponseMode, ExistingResponse } from '../types';\nimport { cn } from '../utils/cn';\nimport { FeedbackMode } from './modes/FeedbackMode';\nimport { VoteMode } from './modes/VoteMode';\nimport { PollMode } from './modes/PollMode';\n\nexport interface GotchaModalProps {\n mode: ResponseMode;\n theme: Theme;\n customStyles?: GotchaStyles;\n promptText?: string;\n placeholder?: string;\n submitText: string;\n thankYouMessage: string;\n // State\n isLoading: boolean;\n isSubmitted: boolean;\n error: string | null;\n // Edit mode\n existingResponse?: ExistingResponse | null;\n isEditing?: boolean;\n // Vote mode\n voteLabels?: { up: string; down: string };\n // Feedback mode field visibility\n /** Show the text input in feedback mode (default: true) */\n showText?: boolean;\n /** Show the star rating in feedback mode (default: true) */\n showRating?: boolean;\n // Poll mode\n options?: string[];\n allowMultiple?: boolean;\n // Handlers\n onSubmit: (data: { content?: string; rating?: number; vote?: 'up' | 'down'; pollSelected?: string[] }) => void;\n onClose: () => void;\n // Position info from parent\n anchorRect?: DOMRect;\n}\n\nexport function GotchaModal({\n mode,\n theme,\n customStyles,\n promptText,\n placeholder,\n submitText,\n thankYouMessage,\n isLoading,\n isSubmitted,\n error,\n existingResponse,\n isEditing = false,\n showText = true,\n showRating = true,\n voteLabels,\n options,\n allowMultiple = false,\n onSubmit,\n onClose,\n anchorRect,\n}: GotchaModalProps) {\n const modalRef = useRef<HTMLDivElement>(null);\n const firstFocusableRef = useRef<HTMLButtonElement>(null);\n const [isVisible, setIsVisible] = useState(false);\n const [isMobile, setIsMobile] = useState(false);\n const [systemTheme, setSystemTheme] = useState<'light' | 'dark'>('light');\n\n // Detect mobile and system theme after mount (SSR-safe)\n useEffect(() => {\n setIsMobile(window.innerWidth < 640);\n\n // Detect system theme preference\n const darkQuery = window.matchMedia('(prefers-color-scheme: dark)');\n setSystemTheme(darkQuery.matches ? 'dark' : 'light');\n\n // Listen for theme changes\n const handler = (e: MediaQueryListEvent) => setSystemTheme(e.matches ? 'dark' : 'light');\n darkQuery.addEventListener('change', handler);\n return () => darkQuery.removeEventListener('change', handler);\n }, []);\n\n // Trigger animation after mount\n useEffect(() => {\n const timer = requestAnimationFrame(() => setIsVisible(true));\n return () => cancelAnimationFrame(timer);\n }, []);\n\n // Resolve theme\n const resolvedTheme = theme === 'auto' ? systemTheme : theme;\n\n const isDark = resolvedTheme === 'dark';\n\n // Determine if modal should appear above or below\n const modalHeight = 280; // approximate modal height\n const spaceBelow = anchorRect\n ? window.innerHeight - anchorRect.bottom\n : window.innerHeight / 2;\n const showAbove = spaceBelow < modalHeight + 20;\n\n // Focus trap\n useEffect(() => {\n const modal = modalRef.current;\n if (!modal) return;\n\n // Focus first element\n firstFocusableRef.current?.focus();\n\n const handleKeyDown = (e: KeyboardEvent) => {\n if (e.key === 'Escape') {\n onClose();\n return;\n }\n\n if (e.key === 'Tab') {\n const focusableElements = modal.querySelectorAll<HTMLElement>(\n 'button, [href], input, select, textarea, [tabindex]:not([tabindex=\"-1\"])'\n );\n const firstElement = focusableElements[0];\n const lastElement = focusableElements[focusableElements.length - 1];\n\n if (e.shiftKey && document.activeElement === firstElement) {\n e.preventDefault();\n lastElement?.focus();\n } else if (!e.shiftKey && document.activeElement === lastElement) {\n e.preventDefault();\n firstElement?.focus();\n }\n }\n };\n\n document.addEventListener('keydown', handleKeyDown);\n return () => document.removeEventListener('keydown', handleKeyDown);\n }, [onClose]);\n\n const defaultPrompt = mode === 'vote'\n ? 'What do you think?'\n : mode === 'poll'\n ? 'Cast your vote'\n : 'What do you think of this feature?';\n\n // Responsive sizing - on mobile, use fixed positioning centered on screen\n const modalPadding = isMobile ? 20 : 16;\n\n const layeredShadow = isDark\n ? '0 1px 2px rgba(0,0,0,0.2), 0 4px 12px rgba(0,0,0,0.3), 0 12px 32px rgba(0,0,0,0.2)'\n : '0 1px 2px rgba(0,0,0,0.04), 0 4px 12px rgba(0,0,0,0.06), 0 12px 32px rgba(0,0,0,0.06)';\n\n const modalStyles: React.CSSProperties = isMobile\n ? {\n // Mobile: fixed position, centered on screen\n position: 'fixed',\n left: '50%',\n top: '50%',\n width: 'calc(100vw - 32px)',\n maxWidth: 320,\n padding: modalPadding,\n borderRadius: 12,\n backgroundColor: isDark ? '#1f2937' : '#ffffff',\n color: isDark ? '#f9fafb' : '#111827',\n boxShadow: layeredShadow,\n border: `1px solid ${isDark ? 'rgba(255,255,255,0.06)' : 'rgba(0,0,0,0.06)'}`,\n zIndex: 9999,\n transition: 'opacity 0.25s cubic-bezier(0.4, 0, 0.2, 1), transform 0.25s cubic-bezier(0.4, 0, 0.2, 1)',\n opacity: isVisible ? 1 : 0,\n transform: isVisible\n ? 'translate(-50%, -50%) scale(1)'\n : 'translate(-50%, -50%) scale(0.96)',\n ...customStyles?.modal,\n textAlign: 'left',\n }\n : {\n // Desktop: absolute position relative to button\n position: 'absolute',\n left: '50%',\n width: 320,\n padding: modalPadding,\n borderRadius: 10,\n backgroundColor: isDark ? '#1f2937' : '#ffffff',\n color: isDark ? '#f9fafb' : '#111827',\n boxShadow: layeredShadow,\n border: `1px solid ${isDark ? 'rgba(255,255,255,0.06)' : 'rgba(0,0,0,0.06)'}`,\n zIndex: 9999,\n ...(showAbove\n ? { bottom: '100%', marginBottom: 8 }\n : { top: '100%', marginTop: 8 }),\n transition: 'opacity 0.25s cubic-bezier(0.4, 0, 0.2, 1), transform 0.25s cubic-bezier(0.4, 0, 0.2, 1)',\n opacity: isVisible ? 1 : 0,\n transform: isVisible\n ? 'translateX(-50%) scale(1) translateY(0)'\n : `translateX(-50%) scale(0.96) translateY(${showAbove ? '6px' : '-6px'})`,\n ...customStyles?.modal,\n textAlign: 'left',\n };\n\n return (\n <div\n ref={modalRef}\n role=\"dialog\"\n aria-modal=\"true\"\n aria-labelledby=\"gotcha-modal-title\"\n style={modalStyles}\n className={cn('gotcha-modal', isDark && 'gotcha-modal--dark')}\n >\n {/* Close button - larger on touch devices */}\n <button\n ref={firstFocusableRef}\n type=\"button\"\n onClick={onClose}\n aria-label=\"Close feedback form\"\n style={{\n position: 'absolute',\n top: isMobile ? 12 : 8,\n right: isMobile ? 12 : 8,\n width: isMobile ? 36 : 28,\n height: isMobile ? 36 : 28,\n border: 'none',\n background: 'transparent',\n cursor: 'pointer',\n color: isDark ? '#6b7280' : '#9ca3af',\n display: 'flex',\n alignItems: 'center',\n justifyContent: 'center',\n borderRadius: 6,\n transition: 'all 0.15s cubic-bezier(0.4, 0, 0.2, 1)',\n }}\n onMouseEnter={(e) => {\n e.currentTarget.style.backgroundColor = isDark ? 'rgba(255,255,255,0.06)' : 'rgba(0,0,0,0.04)';\n e.currentTarget.style.color = isDark ? '#9ca3af' : '#6b7280';\n }}\n onMouseLeave={(e) => {\n e.currentTarget.style.backgroundColor = 'transparent';\n e.currentTarget.style.color = isDark ? '#6b7280' : '#9ca3af';\n }}\n >\n <svg width={isMobile ? 16 : 12} height={isMobile ? 16 : 12} viewBox=\"0 0 14 14\" fill=\"none\">\n <path\n d=\"M1 1L13 13M1 13L13 1\"\n stroke=\"currentColor\"\n strokeWidth=\"1.5\"\n strokeLinecap=\"round\"\n />\n </svg>\n </button>\n\n {/* Title */}\n <h2\n id=\"gotcha-modal-title\"\n style={{\n margin: '0 0 16px 0',\n fontSize: isMobile ? 16 : 14,\n fontWeight: 600,\n paddingRight: isMobile ? 40 : 32,\n letterSpacing: '-0.01em',\n lineHeight: 1.4,\n textAlign: 'left',\n }}\n >\n {promptText || defaultPrompt}\n </h2>\n\n {/* Success state */}\n {isSubmitted && (\n <div\n style={{\n textAlign: 'center',\n padding: '24px 0',\n color: isDark ? '#10b981' : '#059669',\n }}\n >\n <div\n style={{\n width: 44,\n height: 44,\n borderRadius: '50%',\n backgroundColor: isDark ? 'rgba(16,185,129,0.1)' : 'rgba(5,150,105,0.08)',\n display: 'flex',\n alignItems: 'center',\n justifyContent: 'center',\n margin: '0 auto 12px',\n }}\n >\n <svg\n width=\"22\"\n height=\"22\"\n viewBox=\"0 0 24 24\"\n fill=\"none\"\n >\n <path\n d=\"M20 6L9 17L4 12\"\n stroke=\"currentColor\"\n strokeWidth=\"2\"\n strokeLinecap=\"round\"\n strokeLinejoin=\"round\"\n />\n </svg>\n </div>\n <p style={{ margin: 0, fontSize: 13, fontWeight: 500, color: isDark ? '#d1d5db' : '#374151' }}>\n {thankYouMessage}\n </p>\n </div>\n )}\n\n {/* Error state */}\n {error && !isSubmitted && (\n <div\n style={{\n padding: '8px 10px',\n marginBottom: 12,\n borderRadius: 8,\n backgroundColor: isDark ? 'rgba(127,29,29,0.3)' : '#fef2f2',\n border: `1px solid ${isDark ? 'rgba(254,202,202,0.1)' : 'rgba(220,38,38,0.1)'}`,\n color: isDark ? '#fecaca' : '#dc2626',\n fontSize: 13,\n lineHeight: 1.4,\n }}\n >\n {error}\n </div>\n )}\n\n {/* Form content based on mode */}\n {!isSubmitted && (\n <>\n {mode === 'feedback' && (\n <FeedbackMode\n theme={resolvedTheme}\n placeholder={placeholder}\n submitText={submitText}\n isLoading={isLoading}\n onSubmit={onSubmit}\n customStyles={customStyles}\n initialValues={existingResponse ? {\n content: existingResponse.content,\n rating: existingResponse.rating,\n } : undefined}\n isEditing={isEditing}\n showText={showText}\n showRating={showRating}\n />\n )}\n {mode === 'vote' && (\n <VoteMode\n theme={resolvedTheme}\n isLoading={isLoading}\n onSubmit={onSubmit}\n initialVote={existingResponse?.vote || undefined}\n isEditing={isEditing}\n labels={voteLabels}\n />\n )}\n {mode === 'poll' && options && options.length > 0 && (\n <PollMode\n theme={resolvedTheme}\n options={options}\n allowMultiple={allowMultiple}\n isLoading={isLoading}\n onSubmit={onSubmit}\n initialSelected={existingResponse?.pollSelected || undefined}\n isEditing={isEditing}\n />\n )}\n </>\n )}\n\n {/* Screen reader announcement */}\n <div aria-live=\"polite\" className=\"sr-only\" style={{ position: 'absolute', left: -9999 }}>\n {isSubmitted && 'Thank you! Your feedback has been submitted.'}\n {error && `Error: ${error}`}\n </div>\n </div>\n );\n}\n","import React, { useState, useCallback, useEffect, useRef } from 'react';\nimport { createPortal } from 'react-dom';\nimport {\n ResponseMode,\n GotchaUser,\n Position,\n Size,\n Theme,\n TouchBehavior,\n GotchaStyles,\n GotchaResponse,\n GotchaError,\n} from '../types';\nimport { DEFAULTS } from '../constants';\nimport { useGotchaContext } from './GotchaProvider';\nimport { useSubmit } from '../hooks/useSubmit';\nimport { GotchaButton } from './GotchaButton';\nimport { GotchaModal } from './GotchaModal';\n\nexport interface GotchaProps {\n /** Unique identifier for this element */\n elementId: string;\n\n // User data\n /** User metadata for segmentation */\n user?: GotchaUser;\n\n // Behavior\n /** Feedback mode */\n mode?: ResponseMode;\n /** Required if mode is 'ab' */\n experimentId?: string;\n /** Current A/B variant shown to user */\n variant?: string;\n\n // Feedback mode field visibility\n /** Show the text input in feedback mode (default: true) */\n showText?: boolean;\n /** Show the star rating in feedback mode (default: true) */\n showRating?: boolean;\n\n // Vote mode specific\n /** Custom labels for vote buttons (default: Like/Dislike) */\n voteLabels?: { up: string; down: string };\n\n // Poll mode specific (Phase 2)\n /** Required if mode is 'poll' (2-6 options) */\n options?: string[];\n /** Allow selecting multiple options */\n allowMultiple?: boolean;\n /** Show results after voting */\n showResults?: boolean;\n\n // Appearance\n /** Button position relative to parent */\n position?: Position;\n /** Button size */\n size?: Size;\n /** Color theme */\n theme?: Theme;\n /** Custom style overrides */\n customStyles?: GotchaStyles;\n /** Control visibility programmatically */\n visible?: boolean;\n /** Only show when parent is hovered (default: true) */\n showOnHover?: boolean;\n /** Mobile behavior (default: 'always-visible') */\n touchBehavior?: TouchBehavior;\n\n // Content\n /** Custom prompt text */\n promptText?: string;\n /** Input placeholder text */\n placeholder?: string;\n /** Submit button text */\n submitText?: string;\n /** Post-submission message */\n thankYouMessage?: string;\n\n // Callbacks\n /** Called after successful submission */\n onSubmit?: (response: GotchaResponse) => void;\n /** Called when modal opens */\n onOpen?: () => void;\n /** Called when modal closes */\n onClose?: () => void;\n /** Called on error */\n onError?: (error: GotchaError) => void;\n}\n\nexport function Gotcha({\n elementId,\n user,\n mode = 'feedback',\n showText = true,\n showRating = true,\n experimentId,\n variant,\n voteLabels,\n options,\n allowMultiple = false,\n showResults = true,\n position = DEFAULTS.POSITION,\n size = DEFAULTS.SIZE,\n theme = DEFAULTS.THEME,\n customStyles,\n visible = true,\n showOnHover = DEFAULTS.SHOW_ON_HOVER,\n touchBehavior = DEFAULTS.TOUCH_BEHAVIOR,\n promptText,\n placeholder,\n submitText = DEFAULTS.SUBMIT_TEXT,\n thankYouMessage = DEFAULTS.THANK_YOU_MESSAGE,\n onSubmit,\n onOpen,\n onClose,\n onError,\n}: GotchaProps) {\n const { disabled, activeModalId, openModal, closeModal } = useGotchaContext();\n const [isSubmitted, setIsSubmitted] = useState(false);\n const [isParentHovered, setIsParentHovered] = useState(false);\n const [anchorRect, setAnchorRect] = useState<DOMRect | null>(null);\n const [isMobile, setIsMobile] = useState(false);\n const containerRef = useRef<HTMLDivElement>(null);\n\n // Detect mobile for portal rendering (SSR-safe)\n useEffect(() => {\n setIsMobile(window.innerWidth < 640);\n }, []);\n\n // This instance's modal is open if activeModalId matches our elementId\n const isOpen = activeModalId === elementId;\n\n // Attach hover listeners to the parent element (not the button container)\n useEffect(() => {\n if (!showOnHover) return;\n\n const container = containerRef.current;\n if (!container) return;\n\n // Find the parent element with position: relative\n const parent = container.parentElement;\n if (!parent) return;\n\n const handleMouseEnter = () => setIsParentHovered(true);\n const handleMouseLeave = () => setIsParentHovered(false);\n\n parent.addEventListener('mouseenter', handleMouseEnter);\n parent.addEventListener('mouseleave', handleMouseLeave);\n\n return () => {\n parent.removeEventListener('mouseenter', handleMouseEnter);\n parent.removeEventListener('mouseleave', handleMouseLeave);\n };\n }, [showOnHover]);\n\n const { submit, isLoading, error, existingResponse, isEditing } = useSubmit({\n elementId,\n mode,\n experimentId,\n variant,\n pollOptions: options,\n user,\n onSuccess: (response) => {\n setIsSubmitted(true);\n onSubmit?.(response);\n // Auto-close after 3 seconds\n setTimeout(() => {\n closeModal();\n setIsSubmitted(false);\n }, 3000);\n },\n onError: (err) => {\n console.warn('[Gotcha] Submission failed:', err instanceof Error ? err.message : err);\n onError?.(err as unknown as GotchaError);\n },\n });\n\n const handleOpen = useCallback(() => {\n if (containerRef.current) {\n setAnchorRect(containerRef.current.getBoundingClientRect());\n }\n openModal(elementId);\n onOpen?.();\n }, [elementId, openModal, onOpen]);\n\n const handleClose = useCallback(() => {\n closeModal();\n setIsSubmitted(false);\n onClose?.();\n }, [closeModal, onClose]);\n\n const handleSubmit = useCallback(\n (data: { content?: string; rating?: number; vote?: 'up' | 'down'; pollSelected?: string[] }) => {\n submit(data);\n },\n [submit]\n );\n\n // Don't render if disabled or not visible\n if (disabled || !visible) return null;\n\n // Position styles\n const positionStyles: Record<Position, React.CSSProperties> = {\n 'top-right': { position: 'absolute', top: 0, right: 0, transform: 'translate(50%, -50%)' },\n 'top-left': { position: 'absolute', top: 0, left: 0, transform: 'translate(-50%, -50%)' },\n 'bottom-right': { position: 'absolute', bottom: 0, right: 0, transform: 'translate(50%, 50%)' },\n 'bottom-left': { position: 'absolute', bottom: 0, left: 0, transform: 'translate(-50%, 50%)' },\n 'inline': { position: 'relative', display: 'inline-flex' },\n };\n\n return (\n <div\n ref={containerRef}\n style={{\n ...positionStyles[position],\n zIndex: isOpen ? 10000 : 'auto',\n }}\n className=\"gotcha-container\"\n data-gotcha-element={elementId}\n >\n <GotchaButton\n size={size}\n theme={theme}\n customStyles={customStyles}\n showOnHover={showOnHover}\n touchBehavior={touchBehavior}\n onClick={handleOpen}\n isOpen={isOpen}\n isParentHovered={isParentHovered}\n />\n\n {isOpen && !isMobile && (\n <GotchaModal\n mode={mode}\n theme={theme}\n customStyles={customStyles}\n promptText={promptText}\n placeholder={placeholder}\n submitText={submitText}\n thankYouMessage={isEditing ? 'Your feedback has been updated!' : thankYouMessage}\n isLoading={isLoading}\n isSubmitted={isSubmitted}\n error={error}\n existingResponse={existingResponse}\n isEditing={isEditing}\n showText={showText}\n showRating={showRating}\n voteLabels={voteLabels}\n options={options}\n allowMultiple={allowMultiple}\n onSubmit={handleSubmit}\n onClose={handleClose}\n anchorRect={anchorRect || undefined}\n />\n )}\n\n {/* On mobile, render modal via portal to escape parent transform */}\n {isOpen && isMobile && createPortal(\n <div\n style={{\n position: 'fixed',\n inset: 0,\n zIndex: 99999,\n backgroundColor: 'rgba(0, 0, 0, 0.3)',\n }}\n onClick={handleClose}\n aria-hidden=\"true\"\n >\n <div onClick={(e) => e.stopPropagation()}>\n <GotchaModal\n mode={mode}\n theme={theme}\n customStyles={customStyles}\n promptText={promptText}\n placeholder={placeholder}\n submitText={submitText}\n thankYouMessage={isEditing ? 'Your feedback has been updated!' : thankYouMessage}\n isLoading={isLoading}\n isSubmitted={isSubmitted}\n error={error}\n existingResponse={existingResponse}\n isEditing={isEditing}\n showText={showText}\n showRating={showRating}\n voteLabels={voteLabels}\n options={options}\n allowMultiple={allowMultiple}\n onSubmit={handleSubmit}\n onClose={handleClose}\n anchorRect={anchorRect || undefined}\n />\n </div>\n </div>,\n document.body\n )}\n </div>\n );\n}\n","import { useGotchaContext } from '../components/GotchaProvider';\n\n/**\n * Hook to access Gotcha context\n * Must be used within a GotchaProvider\n */\nexport function useGotcha() {\n const { client, disabled, defaultUser, debug } = useGotchaContext();\n\n return {\n /** The API client for manual submissions */\n client,\n /** Whether Gotcha is globally disabled */\n disabled,\n /** Default user metadata */\n defaultUser,\n /** Whether debug mode is enabled */\n debug,\n /** Submit feedback programmatically */\n submitFeedback: client.submitResponse.bind(client),\n };\n}\n"]}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "gotcha-feedback",
3
- "version": "1.0.16",
3
+ "version": "1.0.18",
4
4
  "description": "Developer-first contextual feedback SDK",
5
5
  "main": "./dist/index.js",
6
6
  "module": "./dist/index.mjs",