gotcha-feedback 1.0.7 → 1.0.8
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +88 -0
- package/dist/index.d.mts +20 -1
- package/dist/index.d.ts +20 -1
- package/dist/index.js +2 -2
- package/dist/index.js.map +1 -1
- package/dist/index.mjs +2 -2
- package/dist/index.mjs.map +1 -1
- package/package.json +1 -1
package/dist/index.js.map
CHANGED
|
@@ -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/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","GotchaContext","createContext","GotchaProvider","children","disabled","defaultUser","activeModalId","setActiveModalId","useState","client","useMemo","openModal","useCallback","elementId","closeModal","value","jsx","useGotchaContext","context","useContext","useSubmit","isLoading","setIsLoading","setError","err","errorMessage","cn","classes","isTouchDevice","getResponsiveSize","size","isTouch","sizes","GotchaButton","theme","customStyles","showOnHover","touchBehavior","onClick","isOpen","isParentHovered","setIsTouch","tapRevealed","setTapRevealed","systemTheme","setSystemTheme","useEffect","darkQuery","handler","e","shouldShow","handleClick","buttonSize","resolvedTheme","baseStyles","GotchaIcon","Spinner","color","jsxs","FeedbackMode","placeholder","submitText","onSubmit","content","setContent","rating","setRating","isDark","handleSubmit","inputStyles","buttonStyles","StarRating","onChange","hovered","setHovered","starSize","buttonPadding","star","isFilled","VoteMode","activeVote","setActiveVote","handleVote","vote","buttonBase","iconSize","Fragment","ThumbsUpIcon","ThumbsDownIcon","GotchaModal","mode","promptText","thankYouMessage","isSubmitted","onClose","anchorRect","modalRef","useRef","firstFocusableRef","isVisible","setIsVisible","isMobile","setIsMobile","timer","showAbove","modal","handleKeyDown","focusableElements","firstElement","lastElement","defaultPrompt","modalPadding","modalStyles","Gotcha","experimentId","variant","allowMultiple","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.js","sourcesContent":["// API URLs\nexport const API_BASE_URL = 'https://api.gotcha.cx/v1';\nexport const API_STAGING_URL = 'https://api.staging.gotcha.cx/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 } 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 * 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 } from 'react';\nimport { useGotchaContext } from '../components/GotchaProvider';\nimport { ResponseMode, GotchaUser, GotchaResponse, VoteType } 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 [error, setError] = useState<string | null>(null);\n\n const submit = useCallback(\n async (data: SubmitData) => {\n setIsLoading(true);\n setError(null);\n\n try {\n const 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 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]\n );\n\n return {\n submit,\n isLoading,\n error,\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\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'>('light');\n\n useEffect(() => {\n setIsTouch(isTouchDevice());\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 // Determine visibility\n const shouldShow = (() => {\n // Always show if modal is open\n if (isOpen) return true;\n\n // Desktop with showOnHover: only show when parent is hovered\n if (!isTouch && showOnHover) {\n return isParentHovered;\n }\n\n // Touch device with tap-to-reveal: show only after first tap\n if (isTouch && touchBehavior === 'tap-to-reveal') {\n return tapRevealed;\n }\n\n // All other cases: always visible\n return true;\n })();\n\n const handleClick = () => {\n // For tap-to-reveal on touch: first tap reveals, second tap opens\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 // Determine theme colors\n const resolvedTheme = theme === 'auto' ? systemTheme : theme;\n\n const baseStyles: React.CSSProperties = {\n width: buttonSize,\n height: buttonSize,\n borderRadius: '50%',\n border: 'none',\n cursor: 'pointer',\n display: 'flex',\n alignItems: 'center',\n justifyContent: 'center',\n backgroundColor: resolvedTheme === 'dark' ? '#374151' : '#c7d2dc',\n color: resolvedTheme === 'dark' ? '#e5e7eb' : '#4b5563',\n boxShadow: '0 1px 3px rgba(0, 0, 0, 0.1)',\n // CSS transition for animations\n transition: 'opacity 0.2s ease-out, transform 0.2s ease-out',\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.75} />\n </button>\n );\n}\n\nfunction GotchaIcon({ size }: { size: number }) {\n return (\n <svg\n width={size}\n height={size}\n viewBox=\"0 0 24 24\"\n fill=\"none\"\n xmlns=\"http://www.w3.org/2000/svg\"\n aria-hidden=\"true\"\n >\n <text\n x=\"50%\"\n y=\"50%\"\n dominantBaseline=\"central\"\n textAnchor=\"middle\"\n fontSize=\"16\"\n fontWeight=\"bold\"\n fill=\"currentColor\"\n fontFamily=\"system-ui, -apple-system, sans-serif\"\n >\n G\n </text>\n </svg>\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 1s linear infinite',\n }}\n >\n <style>\n {`\n @keyframes gotcha-spin {\n from { transform: rotate(0deg); }\n to { transform: rotate(360deg); }\n }\n `}\n </style>\n <circle\n cx=\"12\"\n cy=\"12\"\n r=\"10\"\n stroke={color}\n strokeWidth=\"3\"\n strokeOpacity=\"0.25\"\n />\n <path\n d=\"M12 2a10 10 0 0 1 10 10\"\n stroke={color}\n strokeWidth=\"3\"\n strokeLinecap=\"round\"\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}\n\nexport function FeedbackMode({\n theme,\n placeholder,\n submitText,\n isLoading,\n onSubmit,\n customStyles,\n}: FeedbackModeProps) {\n const [content, setContent] = useState('');\n const [rating, setRating] = useState<number | null>(null);\n const [isTouch, setIsTouch] = useState(false);\n\n useEffect(() => {\n setIsTouch(isTouchDevice());\n }, []);\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 ? '#374151' : '#d1d5db'}`,\n borderRadius: isTouch ? 8 : 6,\n backgroundColor: isDark ? '#374151' : '#ffffff',\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 ...customStyles?.input,\n };\n\n const buttonStyles: React.CSSProperties = {\n width: '100%',\n padding: isTouch ? '14px 16px' : '10px 16px',\n border: 'none',\n borderRadius: isTouch ? 8 : 6,\n backgroundColor: isLoading ? (isDark ? '#4b5563' : '#9ca3af') : '#6366f1',\n color: '#ffffff',\n fontSize: isTouch ? 16 : 14,\n fontWeight: 500,\n cursor: isLoading ? 'not-allowed' : 'pointer',\n transition: 'background-color 150ms ease',\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 />\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: (!content.trim() && rating === null) ? 0.5 : 1,\n display: 'flex',\n alignItems: 'center',\n justifyContent: 'center',\n gap: 8,\n }}\n >\n {isLoading && <Spinner size={isTouch ? 18 : 16} color=\"#ffffff\" />}\n {isLoading ? 'Submitting...' : 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 ? 32 : 20;\n const buttonPadding = isTouch ? 6 : 2;\n\n return (\n <div\n style={{\n display: 'flex',\n gap: isTouch ? 8 : 4,\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 ? '#4b5563' : '#d1d5db'),\n transition: 'color 150ms ease',\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}\n\nexport function VoteMode({ theme, isLoading, onSubmit }: VoteModeProps) {\n const [isTouch, setIsTouch] = useState(false);\n const [activeVote, setActiveVote] = useState<'up' | 'down' | null>(null);\n\n useEffect(() => {\n setIsTouch(isTouchDevice());\n }, []);\n\n // Reset active vote when loading completes\n useEffect(() => {\n if (!isLoading) {\n setActiveVote(null);\n }\n }, [isLoading]);\n\n const handleVote = (vote: 'up' | 'down') => {\n setActiveVote(vote);\n onSubmit({ vote });\n };\n\n const isDark = theme === 'dark';\n\n const buttonBase: React.CSSProperties = {\n flex: 1,\n padding: isTouch ? '16px 20px' : '12px 16px',\n border: `1px solid ${isDark ? '#374151' : '#e5e7eb'}`,\n borderRadius: isTouch ? 12 : 8,\n backgroundColor: isDark ? '#374151' : '#f9fafb',\n color: isDark ? '#f9fafb' : '#111827',\n fontSize: isTouch ? 28 : 24,\n cursor: isLoading ? 'not-allowed' : 'pointer',\n transition: 'all 150ms ease',\n display: 'flex',\n alignItems: 'center',\n justifyContent: 'center',\n gap: isTouch ? 10 : 8,\n };\n\n const iconSize = isTouch ? 28 : 24;\n\n return (\n <div\n style={{\n display: 'flex',\n gap: isTouch ? 16 : 12,\n }}\n role=\"group\"\n aria-label=\"Vote\"\n >\n <button\n type=\"button\"\n onClick={() => handleVote('up')}\n disabled={isLoading}\n style={buttonBase}\n aria-label=\"Vote up - I like this\"\n >\n {isLoading && activeVote === 'up' ? (\n <>\n <Spinner size={iconSize} color={isDark ? '#f9fafb' : '#111827'} />\n <span style={{ fontSize: isTouch ? 16 : 14, fontWeight: 500 }}>Sending...</span>\n </>\n ) : (\n <>\n <ThumbsUpIcon size={iconSize} />\n <span style={{ fontSize: isTouch ? 16 : 14, fontWeight: 500 }}>Like</span>\n </>\n )}\n </button>\n\n <button\n type=\"button\"\n onClick={() => handleVote('down')}\n disabled={isLoading}\n style={buttonBase}\n aria-label=\"Vote down - I don't like this\"\n >\n {isLoading && activeVote === 'down' ? (\n <>\n <Spinner size={iconSize} color={isDark ? '#f9fafb' : '#111827'} />\n <span style={{ fontSize: isTouch ? 16 : 14, fontWeight: 500 }}>Sending...</span>\n </>\n ) : (\n <>\n <ThumbsDownIcon size={iconSize} />\n <span style={{ fontSize: isTouch ? 16 : 14, fontWeight: 500 }}>Dislike</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=\"2\">\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=\"2\">\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, { useRef, useEffect, useState } from 'react';\nimport { Theme, GotchaStyles, ResponseMode } from '../types';\nimport { cn } from '../utils/cn';\nimport { FeedbackMode } from './modes/FeedbackMode';\nimport { VoteMode } from './modes/VoteMode';\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 // Handlers\n onSubmit: (data: { content?: string; rating?: number; vote?: 'up' | 'down' }) => 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 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 : '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 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: '0 10px 25px rgba(0, 0, 0, 0.2)',\n border: `1px solid ${isDark ? '#374151' : '#e5e7eb'}`,\n zIndex: 9999,\n transition: 'opacity 0.2s ease-out, transform 0.2s ease-out',\n opacity: isVisible ? 1 : 0,\n transform: isVisible\n ? 'translate(-50%, -50%) scale(1)'\n : 'translate(-50%, -50%) scale(0.95)',\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: 8,\n backgroundColor: isDark ? '#1f2937' : '#ffffff',\n color: isDark ? '#f9fafb' : '#111827',\n boxShadow: '0 10px 25px rgba(0, 0, 0, 0.15)',\n border: `1px solid ${isDark ? '#374151' : '#e5e7eb'}`,\n zIndex: 9999,\n ...(showAbove\n ? { bottom: '100%', marginBottom: 8 }\n : { top: '100%', marginTop: 8 }),\n transition: 'opacity 0.2s ease-out, transform 0.2s ease-out',\n opacity: isVisible ? 1 : 0,\n transform: isVisible\n ? 'translateX(-50%) scale(1) translateY(0)'\n : `translateX(-50%) scale(0.95) translateY(${showAbove ? '10px' : '-10px'})`,\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 : 24,\n height: isMobile ? 36 : 24,\n border: 'none',\n background: 'none',\n cursor: 'pointer',\n color: isDark ? '#9ca3af' : '#6b7280',\n display: 'flex',\n alignItems: 'center',\n justifyContent: 'center',\n borderRadius: 4,\n }}\n >\n <svg width={isMobile ? 18 : 14} height={isMobile ? 18 : 14} viewBox=\"0 0 14 14\" fill=\"none\">\n <path\n d=\"M1 1L13 13M1 13L13 1\"\n stroke=\"currentColor\"\n strokeWidth=\"2\"\n strokeLinecap=\"round\"\n />\n </svg>\n </button>\n\n {/* Title */}\n <h2\n id=\"gotcha-modal-title\"\n style={{\n margin: '0 0 12px 0',\n fontSize: isMobile ? 16 : 14,\n fontWeight: 500,\n paddingRight: isMobile ? 40 : 24,\n }}\n >\n {promptText || defaultPrompt}\n </h2>\n\n {/* Success state */}\n {isSubmitted && (\n <div\n style={{\n textAlign: 'center',\n padding: '20px 0',\n color: isDark ? '#10b981' : '#059669',\n }}\n >\n <svg\n width=\"32\"\n height=\"32\"\n viewBox=\"0 0 24 24\"\n fill=\"none\"\n style={{ margin: '0 auto 8px' }}\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 <p style={{ margin: 0, fontSize: 14 }}>{thankYouMessage}</p>\n </div>\n )}\n\n {/* Error state */}\n {error && !isSubmitted && (\n <div\n style={{\n padding: 8,\n marginBottom: 12,\n borderRadius: 4,\n backgroundColor: isDark ? '#7f1d1d' : '#fef2f2',\n color: isDark ? '#fecaca' : '#dc2626',\n fontSize: 13,\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 />\n )}\n {mode === 'vote' && (\n <VoteMode\n theme={resolvedTheme}\n isLoading={isLoading}\n onSubmit={onSubmit}\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 // 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 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 } = 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 2.5 seconds\n setTimeout(() => {\n closeModal();\n setIsSubmitted(false);\n }, 2500);\n },\n onError: (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' }) => {\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={thankYouMessage}\n isLoading={isLoading}\n isSubmitted={isSubmitted}\n error={error}\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={thankYouMessage}\n isLoading={isLoading}\n isSubmitted={isSubmitted}\n error={error}\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/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","GotchaButton","theme","customStyles","showOnHover","touchBehavior","onClick","isOpen","isParentHovered","setIsTouch","tapRevealed","setTapRevealed","systemTheme","setSystemTheme","darkQuery","handler","e","shouldShow","handleClick","buttonSize","resolvedTheme","baseStyles","GotchaIcon","Spinner","color","jsxs","FeedbackMode","placeholder","submitText","onSubmit","initialValues","isEditing","content","setContent","rating","setRating","isDark","handleSubmit","inputStyles","buttonStyles","StarRating","onChange","hovered","setHovered","starSize","buttonPadding","star","isFilled","VoteMode","initialVote","activeVote","setActiveVote","previousVote","setPreviousVote","handleVote","vote","getButtonStyles","voteType","isSelected","iconSize","Fragment","ThumbsUpIcon","ThumbsDownIcon","GotchaModal","mode","promptText","thankYouMessage","isSubmitted","onClose","anchorRect","modalRef","useRef","firstFocusableRef","isVisible","setIsVisible","isMobile","setIsMobile","timer","showAbove","modal","handleKeyDown","focusableElements","firstElement","lastElement","defaultPrompt","modalPadding","modalStyles","Gotcha","experimentId","variant","allowMultiple","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.js","sourcesContent":["// API URLs\nexport const API_BASE_URL = 'https://api.gotcha.cx/v1';\nexport const API_STAGING_URL = 'https://api.staging.gotcha.cx/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\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'>('light');\n\n useEffect(() => {\n setIsTouch(isTouchDevice());\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 // Determine visibility\n const shouldShow = (() => {\n // Always show if modal is open\n if (isOpen) return true;\n\n // Desktop with showOnHover: only show when parent is hovered\n if (!isTouch && showOnHover) {\n return isParentHovered;\n }\n\n // Touch device with tap-to-reveal: show only after first tap\n if (isTouch && touchBehavior === 'tap-to-reveal') {\n return tapRevealed;\n }\n\n // All other cases: always visible\n return true;\n })();\n\n const handleClick = () => {\n // For tap-to-reveal on touch: first tap reveals, second tap opens\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 // Determine theme colors\n const resolvedTheme = theme === 'auto' ? systemTheme : theme;\n\n const baseStyles: React.CSSProperties = {\n width: buttonSize,\n height: buttonSize,\n borderRadius: '50%',\n border: 'none',\n cursor: 'pointer',\n display: 'flex',\n alignItems: 'center',\n justifyContent: 'center',\n backgroundColor: resolvedTheme === 'dark' ? '#374151' : '#c7d2dc',\n color: resolvedTheme === 'dark' ? '#e5e7eb' : '#4b5563',\n boxShadow: '0 1px 3px rgba(0, 0, 0, 0.1)',\n // CSS transition for animations\n transition: 'opacity 0.2s ease-out, transform 0.2s ease-out',\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.75} />\n </button>\n );\n}\n\nfunction GotchaIcon({ size }: { size: number }) {\n return (\n <svg\n width={size}\n height={size}\n viewBox=\"0 0 24 24\"\n fill=\"none\"\n xmlns=\"http://www.w3.org/2000/svg\"\n aria-hidden=\"true\"\n >\n <text\n x=\"50%\"\n y=\"50%\"\n dominantBaseline=\"central\"\n textAnchor=\"middle\"\n fontSize=\"16\"\n fontWeight=\"bold\"\n fill=\"currentColor\"\n fontFamily=\"system-ui, -apple-system, sans-serif\"\n >\n G\n </text>\n </svg>\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 1s linear infinite',\n }}\n >\n <style>\n {`\n @keyframes gotcha-spin {\n from { transform: rotate(0deg); }\n to { transform: rotate(360deg); }\n }\n `}\n </style>\n <circle\n cx=\"12\"\n cy=\"12\"\n r=\"10\"\n stroke={color}\n strokeWidth=\"3\"\n strokeOpacity=\"0.25\"\n />\n <path\n d=\"M12 2a10 10 0 0 1 10 10\"\n stroke={color}\n strokeWidth=\"3\"\n strokeLinecap=\"round\"\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 ? '#374151' : '#d1d5db'}`,\n borderRadius: isTouch ? 8 : 6,\n backgroundColor: isDark ? '#374151' : '#ffffff',\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 ...customStyles?.input,\n };\n\n const buttonStyles: React.CSSProperties = {\n width: '100%',\n padding: isTouch ? '14px 16px' : '10px 16px',\n border: 'none',\n borderRadius: isTouch ? 8 : 6,\n backgroundColor: isLoading ? (isDark ? '#4b5563' : '#9ca3af') : '#6366f1',\n color: '#ffffff',\n fontSize: isTouch ? 16 : 14,\n fontWeight: 500,\n cursor: isLoading ? 'not-allowed' : 'pointer',\n transition: 'background-color 150ms ease',\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 />\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: (!content.trim() && rating === null) ? 0.5 : 1,\n display: 'flex',\n alignItems: 'center',\n justifyContent: 'center',\n gap: 8,\n }}\n >\n {isLoading && <Spinner size={isTouch ? 18 : 16} color=\"#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 ? 32 : 20;\n const buttonPadding = isTouch ? 6 : 2;\n\n return (\n <div\n style={{\n display: 'flex',\n gap: isTouch ? 8 : 4,\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 ? '#4b5563' : '#d1d5db'),\n transition: 'color 150ms ease',\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}\n\nexport function VoteMode({ theme, isLoading, onSubmit, initialVote, isEditing = false }: 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 return {\n flex: 1,\n padding: isTouch ? '16px 20px' : '12px 16px',\n border: isSelected\n ? `2px solid ${voteType === 'up' ? '#22c55e' : '#ef4444'}`\n : `1px solid ${isDark ? '#374151' : '#e5e7eb'}`,\n borderRadius: isTouch ? 12 : 8,\n backgroundColor: isSelected\n ? (voteType === 'up' ? (isDark ? '#14532d' : '#dcfce7') : (isDark ? '#450a0a' : '#fee2e2'))\n : (isDark ? '#374151' : '#f9fafb'),\n color: isDark ? '#f9fafb' : '#111827',\n fontSize: isTouch ? 28 : 24,\n cursor: isLoading ? 'not-allowed' : 'pointer',\n transition: 'all 150ms ease',\n display: 'flex',\n alignItems: 'center',\n justifyContent: 'center',\n gap: isTouch ? 10 : 8,\n };\n };\n\n const iconSize = isTouch ? 28 : 24;\n\n return (\n <div\n style={{\n display: 'flex',\n gap: isTouch ? 16 : 12,\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 >\n {isLoading && activeVote === 'up' ? (\n <>\n <Spinner size={iconSize} color={isDark ? '#f9fafb' : '#111827'} />\n <span style={{ fontSize: isTouch ? 16 : 14, fontWeight: 500 }}>\n {isEditing ? 'Updating...' : 'Sending...'}\n </span>\n </>\n ) : (\n <>\n <ThumbsUpIcon size={iconSize} />\n <span style={{ fontSize: isTouch ? 16 : 14, fontWeight: 500 }}>\n {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 >\n {isLoading && activeVote === 'down' ? (\n <>\n <Spinner size={iconSize} color={isDark ? '#f9fafb' : '#111827'} />\n <span style={{ fontSize: isTouch ? 16 : 14, fontWeight: 500 }}>\n {isEditing ? 'Updating...' : 'Sending...'}\n </span>\n </>\n ) : (\n <>\n <ThumbsDownIcon size={iconSize} />\n <span style={{ fontSize: isTouch ? 16 : 14, fontWeight: 500 }}>\n {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=\"2\">\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=\"2\">\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, { 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';\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 // Handlers\n onSubmit: (data: { content?: string; rating?: number; vote?: 'up' | 'down' }) => 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 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 : '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 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: '0 10px 25px rgba(0, 0, 0, 0.2)',\n border: `1px solid ${isDark ? '#374151' : '#e5e7eb'}`,\n zIndex: 9999,\n transition: 'opacity 0.2s ease-out, transform 0.2s ease-out',\n opacity: isVisible ? 1 : 0,\n transform: isVisible\n ? 'translate(-50%, -50%) scale(1)'\n : 'translate(-50%, -50%) scale(0.95)',\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: 8,\n backgroundColor: isDark ? '#1f2937' : '#ffffff',\n color: isDark ? '#f9fafb' : '#111827',\n boxShadow: '0 10px 25px rgba(0, 0, 0, 0.15)',\n border: `1px solid ${isDark ? '#374151' : '#e5e7eb'}`,\n zIndex: 9999,\n ...(showAbove\n ? { bottom: '100%', marginBottom: 8 }\n : { top: '100%', marginTop: 8 }),\n transition: 'opacity 0.2s ease-out, transform 0.2s ease-out',\n opacity: isVisible ? 1 : 0,\n transform: isVisible\n ? 'translateX(-50%) scale(1) translateY(0)'\n : `translateX(-50%) scale(0.95) translateY(${showAbove ? '10px' : '-10px'})`,\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 : 24,\n height: isMobile ? 36 : 24,\n border: 'none',\n background: 'none',\n cursor: 'pointer',\n color: isDark ? '#9ca3af' : '#6b7280',\n display: 'flex',\n alignItems: 'center',\n justifyContent: 'center',\n borderRadius: 4,\n }}\n >\n <svg width={isMobile ? 18 : 14} height={isMobile ? 18 : 14} viewBox=\"0 0 14 14\" fill=\"none\">\n <path\n d=\"M1 1L13 13M1 13L13 1\"\n stroke=\"currentColor\"\n strokeWidth=\"2\"\n strokeLinecap=\"round\"\n />\n </svg>\n </button>\n\n {/* Title */}\n <h2\n id=\"gotcha-modal-title\"\n style={{\n margin: '0 0 12px 0',\n fontSize: isMobile ? 16 : 14,\n fontWeight: 500,\n paddingRight: isMobile ? 40 : 24,\n }}\n >\n {promptText || defaultPrompt}\n </h2>\n\n {/* Success state */}\n {isSubmitted && (\n <div\n style={{\n textAlign: 'center',\n padding: '20px 0',\n color: isDark ? '#10b981' : '#059669',\n }}\n >\n <svg\n width=\"32\"\n height=\"32\"\n viewBox=\"0 0 24 24\"\n fill=\"none\"\n style={{ margin: '0 auto 8px' }}\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 <p style={{ margin: 0, fontSize: 14 }}>{thankYouMessage}</p>\n </div>\n )}\n\n {/* Error state */}\n {error && !isSubmitted && (\n <div\n style={{\n padding: 8,\n marginBottom: 12,\n borderRadius: 4,\n backgroundColor: isDark ? '#7f1d1d' : '#fef2f2',\n color: isDark ? '#fecaca' : '#dc2626',\n fontSize: 13,\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 />\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 // 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 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 2.5 seconds\n setTimeout(() => {\n closeModal();\n setIsSubmitted(false);\n }, 2500);\n },\n onError: (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' }) => {\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 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 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/dist/index.mjs
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
|
-
import {createContext,useState,useMemo,useCallback,useRef,useEffect,useContext}from'react';import {jsx,jsxs,Fragment}from'react/jsx-runtime';import {createPortal}from'react-dom';var
|
|
1
|
+
import {createContext,useState,useMemo,useCallback,useRef,useEffect,useContext}from'react';import {jsx,jsxs,Fragment}from'react/jsx-runtime';import {createPortal}from'react-dom';var Ee="https://api.gotcha.cx/v1";var se={ANONYMOUS_ID:"gotcha_anonymous_id"},T={POSITION:"top-right",SIZE:"md",THEME:"light",SHOW_ON_HOVER:true,TOUCH_BEHAVIOR:"always-visible",SUBMIT_TEXT:"Submit",THANK_YOU_MESSAGE:"Thanks for your feedback!"};var X={MAX_RETRIES:2,BASE_DELAY_MS:500,MAX_DELAY_MS:5e3};function Re(){if(typeof window>"u")return `anon_${crypto.randomUUID()}`;let e=localStorage.getItem(se.ANONYMOUS_ID);if(e)return e;let s=`anon_${crypto.randomUUID()}`;return localStorage.setItem(se.ANONYMOUS_ID,s),s}var Q={maxRetries:X.MAX_RETRIES,baseDelayMs:X.BASE_DELAY_MS,maxDelayMs:X.MAX_DELAY_MS};async function ie(e,s,i=Q,n=false){let p=null;for(let a=0;a<=i.maxRetries;a++){try{n&&a>0&&console.log(`[Gotcha] Retry attempt ${a}/${i.maxRetries}`);let t=await fetch(e,s);if(t.status>=400&&t.status<500&&t.status!==429||t.ok)return t;p=new Error(`HTTP ${t.status}`);}catch(t){p=t,n&&console.log(`[Gotcha] Network error: ${p.message}`);}if(a<i.maxRetries){let t=Math.min(i.baseDelayMs*Math.pow(2,a),i.maxDelayMs);await new Promise(u=>setTimeout(u,t));}}throw p}function ke(e){let{apiKey:s,baseUrl:i=Ee,debug:n=false}=e,p={"Content-Type":"application/json",Authorization:`Bearer ${s}`};async function a(t,u,r){let c=`${i}${u}`,l=crypto.randomUUID();n&&console.log(`[Gotcha] ${t} ${u}`,r);let f=await ie(c,{method:t,headers:{...p,"Idempotency-Key":l},body:r?JSON.stringify(r):void 0},Q,n),o=await f.json();if(!f.ok){let d=o.error;throw n&&console.error(`[Gotcha] Error: ${d.code} - ${d.message}`),d}return n&&console.log("[Gotcha] Response:",o),o}return {async submitResponse(t){let u=t.user||{};u.id||(u.id=Re());let r={...t,user:u,context:{url:typeof window<"u"?window.location.href:void 0,userAgent:typeof navigator<"u"?navigator.userAgent:void 0}};return a("POST","/responses",r)},async checkExistingResponse(t,u){let r=`${i}/responses/check?elementId=${encodeURIComponent(t)}&userId=${encodeURIComponent(u)}`;n&&console.log("[Gotcha] GET /responses/check");let c=await ie(r,{method:"GET",headers:p},Q,n),l=await c.json();if(!c.ok){let f=l.error;throw n&&console.error(`[Gotcha] Error: ${f.code} - ${f.message}`),f}return l.exists?(n&&console.log("[Gotcha] Found existing response:",l.response),l.response):null},async updateResponse(t,u,r){let c=`${i}/responses/${t}${r?`?userId=${encodeURIComponent(r)}`:""}`;n&&console.log(`[Gotcha] PATCH /responses/${t}`,u);let l=await ie(c,{method:"PATCH",headers:p,body:JSON.stringify(u)},Q,n),f=await l.json();if(!l.ok){let o=f.error;throw n&&console.error(`[Gotcha] Error: ${o.code} - ${o.message}`),o}return n&&console.log("[Gotcha] Response updated:",f),f},getBaseUrl(){return i}}}var Ge=createContext(null);function He({apiKey:e,children:s,baseUrl:i,debug:n=false,disabled:p=false,defaultUser:a={}}){let[t,u]=useState(null),r=useMemo(()=>ke({apiKey:e,baseUrl:i,debug:n}),[e,i,n]),c=useCallback(o=>{u(o);},[]),l=useCallback(()=>{u(null);},[]),f=useMemo(()=>({client:r,disabled:p,defaultUser:a,debug:n,activeModalId:t,openModal:c,closeModal:l}),[r,p,a,n,t,c,l]);return jsx(Ge.Provider,{value:f,children:s})}function _(){let e=useContext(Ge);if(!e)throw new Error("useGotchaContext must be used within a GotchaProvider");return e}function Ie(e){let{client:s,defaultUser:i}=_(),[n,p]=useState(false),[a,t]=useState(false),[u,r]=useState(null),[c,l]=useState(null);return useEffect(()=>{let o=e.user?.id||i?.id;if(!o){l(null);return}let d=false;return (async()=>{t(true);try{let h=await s.checkExistingResponse(e.elementId,o);d||l(h);}catch{d||l(null);}finally{d||t(false);}})(),()=>{d=true;}},[s,e.elementId,e.user?.id,i?.id]),{submit:useCallback(async o=>{p(true),r(null);try{let d=e.user?.id||i?.id,m;return c&&d?m=await s.updateResponse(c.id,{content:o.content,title:o.title,rating:o.rating,vote:o.vote,pollSelected:o.pollSelected},d):m=await s.submitResponse({elementId:e.elementId,mode:e.mode,content:o.content,title:o.title,rating:o.rating,vote:o.vote,pollOptions:e.pollOptions,pollSelected:o.pollSelected,experimentId:e.experimentId,variant:e.variant,user:{...i,...e.user}}),e.onSuccess?.(m),m}catch(d){let m=d instanceof Error?d.message:"Something went wrong";throw r(m),e.onError?.(d instanceof Error?d:new Error(m)),d}finally{p(false);}},[s,i,e,c]),isLoading:n,isCheckingExisting:a,error:u,existingResponse:c,isEditing:!!c,clearError:()=>r(null)}}function j(...e){return e.filter(Boolean).join(" ")}var O=()=>typeof window>"u"?false:"ontouchstart"in window||navigator.maxTouchPoints>0,Me=(e,s)=>{let i={sm:{desktop:24,mobile:32},md:{desktop:32,mobile:36},lg:{desktop:40,mobile:40}};return s?i[e].mobile:i[e].desktop};function Ce({size:e,theme:s,customStyles:i,showOnHover:n,touchBehavior:p,onClick:a,isOpen:t,isParentHovered:u=false}){let[r,c]=useState(false),[l,f]=useState(false),[o,d]=useState("light");useEffect(()=>{c(O());let g=window.matchMedia("(prefers-color-scheme: dark)");d(g.matches?"dark":"light");let I=P=>d(P.matches?"dark":"light");return g.addEventListener("change",I),()=>g.removeEventListener("change",I)},[]);let m=t?true:!r&&n?u:r&&p==="tap-to-reveal"?l:true,h=()=>{if(r&&p==="tap-to-reveal"&&!l){f(true);return}a();},b=Me(e,r),S=s==="auto"?o:s,R={width:b,height:b,borderRadius:"50%",border:"none",cursor:"pointer",display:"flex",alignItems:"center",justifyContent:"center",backgroundColor:S==="dark"?"#374151":"#c7d2dc",color:S==="dark"?"#e5e7eb":"#4b5563",boxShadow:"0 1px 3px rgba(0, 0, 0, 0.1)",transition:"opacity 0.2s ease-out, transform 0.2s ease-out",opacity:m?1:0,transform:m?"scale(1)":"scale(0.6)",pointerEvents:m?"auto":"none",...i?.button};return jsx("button",{type:"button",onClick:h,style:R,className:j("gotcha-button",t&&"gotcha-button--open"),"aria-label":"Give feedback on this feature","aria-expanded":t,"aria-haspopup":"dialog",children:jsx(We,{size:b*.75})})}function We({size:e}){return jsx("svg",{width:e,height:e,viewBox:"0 0 24 24",fill:"none",xmlns:"http://www.w3.org/2000/svg","aria-hidden":"true",children:jsx("text",{x:"50%",y:"50%",dominantBaseline:"central",textAnchor:"middle",fontSize:"16",fontWeight:"bold",fill:"currentColor",fontFamily:"system-ui, -apple-system, sans-serif",children:"G"})})}function B({size:e=16,color:s="currentColor"}){return jsxs("svg",{width:e,height:e,viewBox:"0 0 24 24",fill:"none",style:{animation:"gotcha-spin 1s linear infinite"},children:[jsx("style",{children:`
|
|
2
2
|
@keyframes gotcha-spin {
|
|
3
3
|
from { transform: rotate(0deg); }
|
|
4
4
|
to { transform: rotate(360deg); }
|
|
5
5
|
}
|
|
6
|
-
`}),jsx("circle",{cx:"12",cy:"12",r:"10",stroke:r,strokeWidth:"3",strokeOpacity:"0.25"}),jsx("path",{d:"M12 2a10 10 0 0 1 10 10",stroke:r,strokeWidth:"3",strokeLinecap:"round"})]})}function Me({theme:e,placeholder:r,submitText:s,isLoading:o,onSubmit:c,customStyles:l}){let[n,d]=useState(""),[t,a]=useState(null),[i,u]=useState(false);useEffect(()=>{u(_());},[]);let p=e==="dark",m=g=>{g.preventDefault(),!(!n.trim()&&t===null)&&c({content:n.trim()||void 0,rating:t??void 0});},S={width:"100%",padding:i?"12px 14px":"10px 12px",border:`1px solid ${p?"#374151":"#d1d5db"}`,borderRadius:i?8:6,backgroundColor:p?"#374151":"#ffffff",color:p?"#f9fafb":"#111827",fontSize:i?16:14,resize:"vertical",minHeight:i?100:80,fontFamily:"inherit",...l?.input},v={width:"100%",padding:i?"14px 16px":"10px 16px",border:"none",borderRadius:i?8:6,backgroundColor:o?p?"#4b5563":"#9ca3af":"#6366f1",color:"#ffffff",fontSize:i?16:14,fontWeight:500,cursor:o?"not-allowed":"pointer",transition:"background-color 150ms ease",...l?.submitButton};return jsxs("form",{onSubmit:m,children:[jsx("div",{style:{marginBottom:i?16:12},children:jsx(Fe,{value:t,onChange:a,isDark:p,isTouch:i})}),jsx("textarea",{value:n,onChange:g=>d(g.target.value),placeholder:r||"Share your thoughts...",style:S,disabled:o,"aria-label":"Your feedback"}),jsxs("button",{type:"submit",disabled:o||!n.trim()&&t===null,style:{...v,marginTop:12,opacity:!n.trim()&&t===null?.5:1,display:"flex",alignItems:"center",justifyContent:"center",gap:8},children:[o&&jsx(B,{size:i?18:16,color:"#ffffff"}),o?"Submitting...":s]})]})}function Fe({value:e,onChange:r,isDark:s,isTouch:o}){let[c,l]=useState(null),n=o?32:20,d=o?6:2;return jsx("div",{style:{display:"flex",gap:o?8:4},role:"group","aria-label":"Rating",children:[1,2,3,4,5].map(t=>{let a=(c??e??0)>=t;return jsx("button",{type:"button",onClick:()=>r(t),onMouseEnter:()=>l(t),onMouseLeave:()=>l(null),"aria-label":`Rate ${t} out of 5`,"aria-pressed":e===t,style:{background:"none",border:"none",cursor:"pointer",padding:d,color:a?"#f59e0b":s?"#4b5563":"#d1d5db",transition:"color 150ms ease"},children:jsx("svg",{width:n,height:n,viewBox:"0 0 24 24",fill:"currentColor",children:jsx("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"})})},t)})})}function Ce({theme:e,isLoading:r,onSubmit:s}){let[o,c]=useState(false),[l,n]=useState(null);useEffect(()=>{c(_());},[]),useEffect(()=>{r||n(null);},[r]);let d=u=>{n(u),s({vote:u});},t=e==="dark",a={flex:1,padding:o?"16px 20px":"12px 16px",border:`1px solid ${t?"#374151":"#e5e7eb"}`,borderRadius:o?12:8,backgroundColor:t?"#374151":"#f9fafb",color:t?"#f9fafb":"#111827",fontSize:o?28:24,cursor:r?"not-allowed":"pointer",transition:"all 150ms ease",display:"flex",alignItems:"center",justifyContent:"center",gap:o?10:8},i=o?28:24;return jsxs("div",{style:{display:"flex",gap:o?16:12},role:"group","aria-label":"Vote",children:[jsx("button",{type:"button",onClick:()=>d("up"),disabled:r,style:a,"aria-label":"Vote up - I like this",children:r&&l==="up"?jsxs(Fragment,{children:[jsx(B,{size:i,color:t?"#f9fafb":"#111827"}),jsx("span",{style:{fontSize:o?16:14,fontWeight:500},children:"Sending..."})]}):jsxs(Fragment,{children:[jsx($e,{size:i}),jsx("span",{style:{fontSize:o?16:14,fontWeight:500},children:"Like"})]})}),jsx("button",{type:"button",onClick:()=>d("down"),disabled:r,style:a,"aria-label":"Vote down - I don't like this",children:r&&l==="down"?jsxs(Fragment,{children:[jsx(B,{size:i,color:t?"#f9fafb":"#111827"}),jsx("span",{style:{fontSize:o?16:14,fontWeight:500},children:"Sending..."})]}):jsxs(Fragment,{children:[jsx(Ke,{size:i}),jsx("span",{style:{fontSize:o?16:14,fontWeight:500},children:"Dislike"})]})})]})}function $e({size:e=24}){return jsx("svg",{width:e,height:e,viewBox:"0 0 24 24",fill:"none",stroke:"currentColor",strokeWidth:"2",children:jsx("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"})})}function Ke({size:e=24}){return jsx("svg",{width:e,height:e,viewBox:"0 0 24 24",fill:"none",stroke:"currentColor",strokeWidth:"2",children:jsx("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"})})}function se({mode:e,theme:r,customStyles:s,promptText:o,placeholder:c,submitText:l,thankYouMessage:n,isLoading:d,isSubmitted:t,error:a,onSubmit:i,onClose:u,anchorRect:p}){let m=useRef(null),S=useRef(null),[v,g]=useState(false),[f,C]=useState(false),[G,k]=useState("light");useEffect(()=>{C(window.innerWidth<640);let x=window.matchMedia("(prefers-color-scheme: dark)");k(x.matches?"dark":"light");let w=y=>k(y.matches?"dark":"light");return x.addEventListener("change",w),()=>x.removeEventListener("change",w)},[]),useEffect(()=>{let x=requestAnimationFrame(()=>g(true));return ()=>cancelAnimationFrame(x)},[]);let T=r==="auto"?G:r,b=T==="dark",P=(p?window.innerHeight-p.bottom:window.innerHeight/2)<280+20;useEffect(()=>{let x=m.current;if(!x)return;S.current?.focus();let w=y=>{if(y.key==="Escape"){u();return}if(y.key==="Tab"){let U=x.querySelectorAll('button, [href], input, select, textarea, [tabindex]:not([tabindex="-1"])'),N=U[0],Y=U[U.length-1];y.shiftKey&&document.activeElement===N?(y.preventDefault(),Y?.focus()):!y.shiftKey&&document.activeElement===Y&&(y.preventDefault(),N?.focus());}};return document.addEventListener("keydown",w),()=>document.removeEventListener("keydown",w)},[u]);let O=e==="vote"?"What do you think?":"What do you think of this feature?",D=f?20:16,L=f?{position:"fixed",left:"50%",top:"50%",width:"calc(100vw - 32px)",maxWidth:320,padding:D,borderRadius:12,backgroundColor:b?"#1f2937":"#ffffff",color:b?"#f9fafb":"#111827",boxShadow:"0 10px 25px rgba(0, 0, 0, 0.2)",border:`1px solid ${b?"#374151":"#e5e7eb"}`,zIndex:9999,transition:"opacity 0.2s ease-out, transform 0.2s ease-out",opacity:v?1:0,transform:v?"translate(-50%, -50%) scale(1)":"translate(-50%, -50%) scale(0.95)",...s?.modal}:{position:"absolute",left:"50%",width:320,padding:D,borderRadius:8,backgroundColor:b?"#1f2937":"#ffffff",color:b?"#f9fafb":"#111827",boxShadow:"0 10px 25px rgba(0, 0, 0, 0.15)",border:`1px solid ${b?"#374151":"#e5e7eb"}`,zIndex:9999,...P?{bottom:"100%",marginBottom:8}:{top:"100%",marginTop:8},transition:"opacity 0.2s ease-out, transform 0.2s ease-out",opacity:v?1:0,transform:v?"translateX(-50%) scale(1) translateY(0)":`translateX(-50%) scale(0.95) translateY(${P?"10px":"-10px"})`,...s?.modal};return jsxs("div",{ref:m,role:"dialog","aria-modal":"true","aria-labelledby":"gotcha-modal-title",style:L,className:K("gotcha-modal",b&&"gotcha-modal--dark"),children:[jsx("button",{ref:S,type:"button",onClick:u,"aria-label":"Close feedback form",style:{position:"absolute",top:f?12:8,right:f?12:8,width:f?36:24,height:f?36:24,border:"none",background:"none",cursor:"pointer",color:b?"#9ca3af":"#6b7280",display:"flex",alignItems:"center",justifyContent:"center",borderRadius:4},children:jsx("svg",{width:f?18:14,height:f?18:14,viewBox:"0 0 14 14",fill:"none",children:jsx("path",{d:"M1 1L13 13M1 13L13 1",stroke:"currentColor",strokeWidth:"2",strokeLinecap:"round"})})}),jsx("h2",{id:"gotcha-modal-title",style:{margin:"0 0 12px 0",fontSize:f?16:14,fontWeight:500,paddingRight:f?40:24},children:o||O}),t&&jsxs("div",{style:{textAlign:"center",padding:"20px 0",color:b?"#10b981":"#059669"},children:[jsx("svg",{width:"32",height:"32",viewBox:"0 0 24 24",fill:"none",style:{margin:"0 auto 8px"},children:jsx("path",{d:"M20 6L9 17L4 12",stroke:"currentColor",strokeWidth:"2",strokeLinecap:"round",strokeLinejoin:"round"})}),jsx("p",{style:{margin:0,fontSize:14},children:n})]}),a&&!t&&jsx("div",{style:{padding:8,marginBottom:12,borderRadius:4,backgroundColor:b?"#7f1d1d":"#fef2f2",color:b?"#fecaca":"#dc2626",fontSize:13},children:a}),!t&&jsxs(Fragment,{children:[e==="feedback"&&jsx(Me,{theme:T,placeholder:c,submitText:l,isLoading:d,onSubmit:i,customStyles:s}),e==="vote"&&jsx(Ce,{theme:T,isLoading:d,onSubmit:i})]}),jsxs("div",{"aria-live":"polite",className:"sr-only",style:{position:"absolute",left:-9999},children:[t&&"Thank you! Your feedback has been submitted.",a&&`Error: ${a}`]})]})}function Ze({elementId:e,user:r,mode:s="feedback",experimentId:o,variant:c,options:l,allowMultiple:n=false,showResults:d=true,position:t=M.POSITION,size:a=M.SIZE,theme:i=M.THEME,customStyles:u,visible:p=true,showOnHover:m=M.SHOW_ON_HOVER,touchBehavior:S=M.TOUCH_BEHAVIOR,promptText:v,placeholder:g,submitText:f=M.SUBMIT_TEXT,thankYouMessage:C=M.THANK_YOU_MESSAGE,onSubmit:G,onOpen:k,onClose:T,onError:b}){let{disabled:ae,activeModalId:le,openModal:P,closeModal:O}=A(),[D,L]=useState(false),[x,w]=useState(false),[y,U]=useState(null),[N,Y]=useState(false),W=useRef(null);useEffect(()=>{Y(window.innerWidth<640);},[]);let F=le===e;useEffect(()=>{if(!m)return;let E=W.current;if(!E)return;let z=E.parentElement;if(!z)return;let fe=()=>w(true),me=()=>w(false);return z.addEventListener("mouseenter",fe),z.addEventListener("mouseleave",me),()=>{z.removeEventListener("mouseenter",fe),z.removeEventListener("mouseleave",me);}},[m]);let{submit:ce,isLoading:de,error:ue}=Re({elementId:e,mode:s,experimentId:o,variant:c,pollOptions:l,user:r,onSuccess:E=>{L(true),G?.(E),setTimeout(()=>{O(),L(false);},2500);},onError:E=>{b?.(E);}}),Pe=useCallback(()=>{W.current&&U(W.current.getBoundingClientRect()),P(e),k?.();},[e,P,k]),J=useCallback(()=>{O(),L(false),T?.();},[O,T]),pe=useCallback(E=>{ce(E);},[ce]);return ae||!p?null:jsxs("div",{ref:W,style:{...{"top-right":{position:"absolute",top:0,right:0,transform:"translate(50%, -50%)"},"top-left":{position:"absolute",top:0,left:0,transform:"translate(-50%, -50%)"},"bottom-right":{position:"absolute",bottom:0,right:0,transform:"translate(50%, 50%)"},"bottom-left":{position:"absolute",bottom:0,left:0,transform:"translate(-50%, 50%)"},inline:{position:"relative",display:"inline-flex"}}[t],zIndex:F?1e4:"auto"},className:"gotcha-container","data-gotcha-element":e,children:[jsx(Te,{size:a,theme:i,customStyles:u,showOnHover:m,touchBehavior:S,onClick:Pe,isOpen:F,isParentHovered:x}),F&&!N&&jsx(se,{mode:s,theme:i,customStyles:u,promptText:v,placeholder:g,submitText:f,thankYouMessage:C,isLoading:de,isSubmitted:D,error:ue,onSubmit:pe,onClose:J,anchorRect:y||void 0}),F&&N&&createPortal(jsx("div",{style:{position:"fixed",inset:0,zIndex:99999,backgroundColor:"rgba(0, 0, 0, 0.3)"},onClick:J,"aria-hidden":"true",children:jsx("div",{onClick:E=>E.stopPropagation(),children:jsx(se,{mode:s,theme:i,customStyles:u,promptText:v,placeholder:g,submitText:f,thankYouMessage:C,isLoading:de,isSubmitted:D,error:ue,onSubmit:pe,onClose:J,anchorRect:y||void 0})})}),document.body)]})}function Je(){let{client:e,disabled:r,defaultUser:s,debug:o}=A();return {client:e,disabled:r,defaultUser:s,debug:o,submitFeedback:e.submitResponse.bind(e)}}export{Ze as Gotcha,Ne as GotchaProvider,Je as useGotcha};//# sourceMappingURL=index.mjs.map
|
|
6
|
+
`}),jsx("circle",{cx:"12",cy:"12",r:"10",stroke:s,strokeWidth:"3",strokeOpacity:"0.25"}),jsx("path",{d:"M12 2a10 10 0 0 1 10 10",stroke:s,strokeWidth:"3",strokeLinecap:"round"})]})}function _e({theme:e,placeholder:s,submitText:i,isLoading:n,onSubmit:p,customStyles:a,initialValues:t,isEditing:u=false}){let[r,c]=useState(t?.content||""),[l,f]=useState(t?.rating??null),[o,d]=useState(false);useEffect(()=>{d(O());},[]),useEffect(()=>{t?.content!==void 0&&c(t.content||""),t?.rating!==void 0&&f(t.rating??null);},[t?.content,t?.rating]);let m=e==="dark",h=R=>{R.preventDefault(),!(!r.trim()&&l===null)&&p({content:r.trim()||void 0,rating:l??void 0});},b={width:"100%",padding:o?"12px 14px":"10px 12px",border:`1px solid ${m?"#374151":"#d1d5db"}`,borderRadius:o?8:6,backgroundColor:m?"#374151":"#ffffff",color:m?"#f9fafb":"#111827",fontSize:o?16:14,resize:"vertical",minHeight:o?100:80,fontFamily:"inherit",...a?.input},S={width:"100%",padding:o?"14px 16px":"10px 16px",border:"none",borderRadius:o?8:6,backgroundColor:n?m?"#4b5563":"#9ca3af":"#6366f1",color:"#ffffff",fontSize:o?16:14,fontWeight:500,cursor:n?"not-allowed":"pointer",transition:"background-color 150ms ease",...a?.submitButton};return jsxs("form",{onSubmit:h,children:[jsx("div",{style:{marginBottom:o?16:12},children:jsx(Xe,{value:l,onChange:f,isDark:m,isTouch:o})}),jsx("textarea",{value:r,onChange:R=>c(R.target.value),placeholder:s||"Share your thoughts...",style:b,disabled:n,"aria-label":"Your feedback"}),jsxs("button",{type:"submit",disabled:n||!r.trim()&&l===null,style:{...S,marginTop:12,opacity:!r.trim()&&l===null?.5:1,display:"flex",alignItems:"center",justifyContent:"center",gap:8},children:[n&&jsx(B,{size:o?18:16,color:"#ffffff"}),n?u?"Updating...":"Submitting...":u?"Update":i]})]})}function Xe({value:e,onChange:s,isDark:i,isTouch:n}){let[p,a]=useState(null),t=n?32:20,u=n?6:2;return jsx("div",{style:{display:"flex",gap:n?8:4},role:"group","aria-label":"Rating",children:[1,2,3,4,5].map(r=>{let c=(p??e??0)>=r;return jsx("button",{type:"button",onClick:()=>s(r),onMouseEnter:()=>a(r),onMouseLeave:()=>a(null),"aria-label":`Rate ${r} out of 5`,"aria-pressed":e===r,style:{background:"none",border:"none",cursor:"pointer",padding:u,color:c?"#f59e0b":i?"#4b5563":"#d1d5db",transition:"color 150ms ease"},children:jsx("svg",{width:t,height:t,viewBox:"0 0 24 24",fill:"currentColor",children:jsx("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"})})},r)})})}function Oe({theme:e,isLoading:s,onSubmit:i,initialVote:n,isEditing:p=false}){let[a,t]=useState(false),[u,r]=useState(n||null),[c,l]=useState(n||null);useEffect(()=>{t(O());},[]),useEffect(()=>{n!==void 0&&(l(n),r(n));},[n]),useEffect(()=>{!s&&!p&&r(null);},[s,p]);let f=h=>{r(h),i({vote:h});},o=e==="dark",d=h=>{let b=c===h;return {flex:1,padding:a?"16px 20px":"12px 16px",border:b?`2px solid ${h==="up"?"#22c55e":"#ef4444"}`:`1px solid ${o?"#374151":"#e5e7eb"}`,borderRadius:a?12:8,backgroundColor:b?h==="up"?o?"#14532d":"#dcfce7":o?"#450a0a":"#fee2e2":o?"#374151":"#f9fafb",color:o?"#f9fafb":"#111827",fontSize:a?28:24,cursor:s?"not-allowed":"pointer",transition:"all 150ms ease",display:"flex",alignItems:"center",justifyContent:"center",gap:a?10:8}},m=a?28:24;return jsxs("div",{style:{display:"flex",gap:a?16:12},role:"group","aria-label":"Vote",children:[jsx("button",{type:"button",onClick:()=>f("up"),disabled:s,style:d("up"),"aria-label":"Vote up - I like this","aria-pressed":c==="up",children:s&&u==="up"?jsxs(Fragment,{children:[jsx(B,{size:m,color:o?"#f9fafb":"#111827"}),jsx("span",{style:{fontSize:a?16:14,fontWeight:500},children:p?"Updating...":"Sending..."})]}):jsxs(Fragment,{children:[jsx(Qe,{size:m}),jsx("span",{style:{fontSize:a?16:14,fontWeight:500},children:c==="up"?"Liked":"Like"})]})}),jsx("button",{type:"button",onClick:()=>f("down"),disabled:s,style:d("down"),"aria-label":"Vote down - I don't like this","aria-pressed":c==="down",children:s&&u==="down"?jsxs(Fragment,{children:[jsx(B,{size:m,color:o?"#f9fafb":"#111827"}),jsx("span",{style:{fontSize:a?16:14,fontWeight:500},children:p?"Updating...":"Sending..."})]}):jsxs(Fragment,{children:[jsx(qe,{size:m}),jsx("span",{style:{fontSize:a?16:14,fontWeight:500},children:c==="down"?"Disliked":"Dislike"})]})})]})}function Qe({size:e=24}){return jsx("svg",{width:e,height:e,viewBox:"0 0 24 24",fill:"none",stroke:"currentColor",strokeWidth:"2",children:jsx("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"})})}function qe({size:e=24}){return jsx("svg",{width:e,height:e,viewBox:"0 0 24 24",fill:"none",stroke:"currentColor",strokeWidth:"2",children:jsx("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"})})}function fe({mode:e,theme:s,customStyles:i,promptText:n,placeholder:p,submitText:a,thankYouMessage:t,isLoading:u,isSubmitted:r,error:c,existingResponse:l,isEditing:f=false,onSubmit:o,onClose:d,anchorRect:m}){let h=useRef(null),b=useRef(null),[S,R]=useState(false),[g,I]=useState(false),[P,Y]=useState("light");useEffect(()=>{I(window.innerWidth<640);let x=window.matchMedia("(prefers-color-scheme: dark)");Y(x.matches?"dark":"light");let M=E=>Y(E.matches?"dark":"light");return x.addEventListener("change",M),()=>x.removeEventListener("change",M)},[]),useEffect(()=>{let x=requestAnimationFrame(()=>R(true));return ()=>cancelAnimationFrame(x)},[]);let D=s==="auto"?P:s,y=D==="dark",U=(m?window.innerHeight-m.bottom:window.innerHeight/2)<280+20;useEffect(()=>{let x=h.current;if(!x)return;b.current?.focus();let M=E=>{if(E.key==="Escape"){d();return}if(E.key==="Tab"){let N=x.querySelectorAll('button, [href], input, select, textarea, [tabindex]:not([tabindex="-1"])'),C=N[0],A=N[N.length-1];E.shiftKey&&document.activeElement===C?(E.preventDefault(),A?.focus()):!E.shiftKey&&document.activeElement===A&&(E.preventDefault(),C?.focus());}};return document.addEventListener("keydown",M),()=>document.removeEventListener("keydown",M)},[d]);let L=e==="vote"?"What do you think?":"What do you think of this feature?",F=g?20:16,W=g?{position:"fixed",left:"50%",top:"50%",width:"calc(100vw - 32px)",maxWidth:320,padding:F,borderRadius:12,backgroundColor:y?"#1f2937":"#ffffff",color:y?"#f9fafb":"#111827",boxShadow:"0 10px 25px rgba(0, 0, 0, 0.2)",border:`1px solid ${y?"#374151":"#e5e7eb"}`,zIndex:9999,transition:"opacity 0.2s ease-out, transform 0.2s ease-out",opacity:S?1:0,transform:S?"translate(-50%, -50%) scale(1)":"translate(-50%, -50%) scale(0.95)",...i?.modal}:{position:"absolute",left:"50%",width:320,padding:F,borderRadius:8,backgroundColor:y?"#1f2937":"#ffffff",color:y?"#f9fafb":"#111827",boxShadow:"0 10px 25px rgba(0, 0, 0, 0.15)",border:`1px solid ${y?"#374151":"#e5e7eb"}`,zIndex:9999,...U?{bottom:"100%",marginBottom:8}:{top:"100%",marginTop:8},transition:"opacity 0.2s ease-out, transform 0.2s ease-out",opacity:S?1:0,transform:S?"translateX(-50%) scale(1) translateY(0)":`translateX(-50%) scale(0.95) translateY(${U?"10px":"-10px"})`,...i?.modal};return jsxs("div",{ref:h,role:"dialog","aria-modal":"true","aria-labelledby":"gotcha-modal-title",style:W,className:j("gotcha-modal",y&&"gotcha-modal--dark"),children:[jsx("button",{ref:b,type:"button",onClick:d,"aria-label":"Close feedback form",style:{position:"absolute",top:g?12:8,right:g?12:8,width:g?36:24,height:g?36:24,border:"none",background:"none",cursor:"pointer",color:y?"#9ca3af":"#6b7280",display:"flex",alignItems:"center",justifyContent:"center",borderRadius:4},children:jsx("svg",{width:g?18:14,height:g?18:14,viewBox:"0 0 14 14",fill:"none",children:jsx("path",{d:"M1 1L13 13M1 13L13 1",stroke:"currentColor",strokeWidth:"2",strokeLinecap:"round"})})}),jsx("h2",{id:"gotcha-modal-title",style:{margin:"0 0 12px 0",fontSize:g?16:14,fontWeight:500,paddingRight:g?40:24},children:n||L}),r&&jsxs("div",{style:{textAlign:"center",padding:"20px 0",color:y?"#10b981":"#059669"},children:[jsx("svg",{width:"32",height:"32",viewBox:"0 0 24 24",fill:"none",style:{margin:"0 auto 8px"},children:jsx("path",{d:"M20 6L9 17L4 12",stroke:"currentColor",strokeWidth:"2",strokeLinecap:"round",strokeLinejoin:"round"})}),jsx("p",{style:{margin:0,fontSize:14},children:t})]}),c&&!r&&jsx("div",{style:{padding:8,marginBottom:12,borderRadius:4,backgroundColor:y?"#7f1d1d":"#fef2f2",color:y?"#fecaca":"#dc2626",fontSize:13},children:c}),!r&&jsxs(Fragment,{children:[e==="feedback"&&jsx(_e,{theme:D,placeholder:p,submitText:a,isLoading:u,onSubmit:o,customStyles:i,initialValues:l?{content:l.content,rating:l.rating}:void 0,isEditing:f}),e==="vote"&&jsx(Oe,{theme:D,isLoading:u,onSubmit:o,initialVote:l?.vote||void 0,isEditing:f})]}),jsxs("div",{"aria-live":"polite",className:"sr-only",style:{position:"absolute",left:-9999},children:[r&&"Thank you! Your feedback has been submitted.",c&&`Error: ${c}`]})]})}function et({elementId:e,user:s,mode:i="feedback",experimentId:n,variant:p,options:a,allowMultiple:t=false,showResults:u=true,position:r=T.POSITION,size:c=T.SIZE,theme:l=T.THEME,customStyles:f,visible:o=true,showOnHover:d=T.SHOW_ON_HOVER,touchBehavior:m=T.TOUCH_BEHAVIOR,promptText:h,placeholder:b,submitText:S=T.SUBMIT_TEXT,thankYouMessage:R=T.THANK_YOU_MESSAGE,onSubmit:g,onOpen:I,onClose:P,onError:Y}){let{disabled:D,activeModalId:y,openModal:ne,closeModal:V}=_(),[U,L]=useState(false),[F,W]=useState(false),[x,M]=useState(null),[E,N]=useState(false),C=useRef(null);useEffect(()=>{N(window.innerWidth<640);},[]);let A=y===e;useEffect(()=>{if(!d)return;let k=C.current;if(!k)return;let z=k.parentElement;if(!z)return;let Se=()=>W(true),xe=()=>W(false);return z.addEventListener("mouseenter",Se),z.addEventListener("mouseleave",xe),()=>{z.removeEventListener("mouseenter",Se),z.removeEventListener("mouseleave",xe);}},[d]);let{submit:he,isLoading:ge,error:be,existingResponse:ve,isEditing:K}=Ie({elementId:e,mode:i,experimentId:n,variant:p,pollOptions:a,user:s,onSuccess:k=>{L(true),g?.(k),setTimeout(()=>{V(),L(false);},2500);},onError:k=>{Y?.(k);}}),Le=useCallback(()=>{C.current&&M(C.current.getBoundingClientRect()),ne(e),I?.();},[e,ne,I]),re=useCallback(()=>{V(),L(false),P?.();},[V,P]),ye=useCallback(k=>{he(k);},[he]);return D||!o?null:jsxs("div",{ref:C,style:{...{"top-right":{position:"absolute",top:0,right:0,transform:"translate(50%, -50%)"},"top-left":{position:"absolute",top:0,left:0,transform:"translate(-50%, -50%)"},"bottom-right":{position:"absolute",bottom:0,right:0,transform:"translate(50%, 50%)"},"bottom-left":{position:"absolute",bottom:0,left:0,transform:"translate(-50%, 50%)"},inline:{position:"relative",display:"inline-flex"}}[r],zIndex:A?1e4:"auto"},className:"gotcha-container","data-gotcha-element":e,children:[jsx(Ce,{size:c,theme:l,customStyles:f,showOnHover:d,touchBehavior:m,onClick:Le,isOpen:A,isParentHovered:F}),A&&!E&&jsx(fe,{mode:i,theme:l,customStyles:f,promptText:h,placeholder:b,submitText:S,thankYouMessage:K?"Your feedback has been updated!":R,isLoading:ge,isSubmitted:U,error:be,existingResponse:ve,isEditing:K,onSubmit:ye,onClose:re,anchorRect:x||void 0}),A&&E&&createPortal(jsx("div",{style:{position:"fixed",inset:0,zIndex:99999,backgroundColor:"rgba(0, 0, 0, 0.3)"},onClick:re,"aria-hidden":"true",children:jsx("div",{onClick:k=>k.stopPropagation(),children:jsx(fe,{mode:i,theme:l,customStyles:f,promptText:h,placeholder:b,submitText:S,thankYouMessage:K?"Your feedback has been updated!":R,isLoading:ge,isSubmitted:U,error:be,existingResponse:ve,isEditing:K,onSubmit:ye,onClose:re,anchorRect:x||void 0})})}),document.body)]})}function ot(){let{client:e,disabled:s,defaultUser:i,debug:n}=_();return {client:e,disabled:s,defaultUser:i,debug:n,submitFeedback:e.submitResponse.bind(e)}}export{et as Gotcha,He as GotchaProvider,ot as useGotcha};//# sourceMappingURL=index.mjs.map
|
|
7
7
|
//# sourceMappingURL=index.mjs.map
|