reflet-sdk 0.3.4 → 0.4.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +7 -0
- package/dist/client-BYuSKJw5.js.map +1 -1
- package/dist/{client-BpEYxx4d.d.ts → client-BomgCsXm.d.ts} +2 -2
- package/dist/{client-BpEYxx4d.d.ts.map → client-BomgCsXm.d.ts.map} +1 -1
- package/dist/feedback.d.ts +11 -15
- package/dist/feedback.d.ts.map +1 -1
- package/dist/feedback.js +748 -407
- package/dist/feedback.js.map +1 -1
- package/dist/index.d.ts +2 -2
- package/dist/{react-context-DZw_HHjj.js → react-context-3_IbhIFB.js} +11 -2
- package/dist/react-context-3_IbhIFB.js.map +1 -0
- package/dist/react.d.ts +22 -33
- package/dist/react.d.ts.map +1 -1
- package/dist/react.js +206 -241
- package/dist/react.js.map +1 -1
- package/dist/server.d.ts +5 -5
- package/dist/server.d.ts.map +1 -1
- package/dist/{types-wANRMsGI.d.ts → types-Cak4ZkSy.d.ts} +3 -1
- package/dist/types-Cak4ZkSy.d.ts.map +1 -0
- package/package.json +44 -44
- package/dist/react-context-DZw_HHjj.js.map +0 -1
- package/dist/types-wANRMsGI.d.ts.map +0 -1
package/dist/react.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"react.js","names":[],"sources":["../src/react-changelog-widget.tsx","../src/react-feedback-dialog-types.ts","../src/react-feedback-styles-parts.ts","../src/react-feedback-styles.ts","../src/react-feedback-dialog-hook.ts","../src/react-feedback-dialog.tsx","../src/react-feedback-button.tsx","../src/react-mutation-hooks.ts","../src/react-query-hooks.ts"],"sourcesContent":["import { useCallback, useEffect, useRef } from \"react\";\nimport type { ChangelogEntry } from \"./types\";\n\ninterface ChangelogWidgetProps {\n autoOpenForNew?: boolean;\n locale?: string;\n maxEntries?: number;\n mode?: \"card\" | \"popup\" | \"trigger\";\n onClose?: () => void;\n onEntryClick?: (entry: ChangelogEntry) => void;\n onOpen?: () => void;\n position?: \"bottom-right\" | \"bottom-left\";\n primaryColor?: string;\n publicKey: string;\n theme?: \"light\" | \"dark\" | \"auto\";\n triggerSelector?: string;\n}\n\ninterface WidgetInstance {\n close: () => void;\n destroy: () => void;\n getUnreadCount: () => number;\n init: () => Promise<void>;\n markAsRead: () => void;\n open: () => void;\n}\n\ndeclare global {\n interface Window {\n RefletChangelogWidget?: new (\n config: ChangelogWidgetProps\n ) => WidgetInstance;\n }\n}\n\n/**\n * React component that wraps the Reflet Changelog Widget.\n *\n * Dynamically loads and initializes a RefletChangelogWidget instance.\n *\n * @example\n * ```tsx\n * import { ChangelogWidget } from 'reflet-sdk/react';\n *\n * export function MyApp() {\n * return <ChangelogWidget publicKey=\"fb_pub_xxx\" mode=\"card\" theme=\"auto\" />;\n * }\n * ```\n */\nexport function ChangelogWidget({\n publicKey,\n mode = \"card\",\n position = \"bottom-right\",\n theme = \"light\",\n primaryColor,\n maxEntries,\n triggerSelector,\n autoOpenForNew,\n locale,\n onOpen,\n onClose,\n onEntryClick,\n}: ChangelogWidgetProps) {\n const widgetRef = useRef<WidgetInstance | null>(null);\n\n const initWidget = useCallback(async () => {\n // Check if RefletChangelogWidget is available globally\n const WidgetClass = window.RefletChangelogWidget;\n\n if (WidgetClass) {\n const instance = new WidgetClass({\n autoOpenForNew,\n locale,\n maxEntries,\n mode,\n onClose,\n onEntryClick,\n onOpen,\n position,\n primaryColor,\n publicKey,\n theme,\n triggerSelector,\n });\n\n widgetRef.current = instance;\n await instance.init();\n return;\n }\n\n // Try loading the script dynamically\n const existingScript = document.querySelector(\n 'script[src*=\"reflet-changelog\"]'\n );\n if (!existingScript) {\n const script = document.createElement(\"script\");\n script.src = \"https://cdn.reflet.app/widget/reflet-changelog.v1.js\";\n script.async = true;\n script.onload = () => {\n const LoadedClass = window.RefletChangelogWidget;\n\n if (LoadedClass) {\n const instance = new LoadedClass({\n autoOpenForNew,\n locale,\n maxEntries,\n mode,\n onClose,\n onEntryClick,\n onOpen,\n position,\n primaryColor,\n publicKey,\n theme,\n triggerSelector,\n });\n\n widgetRef.current = instance;\n instance.init();\n }\n };\n document.head.appendChild(script);\n }\n }, [\n publicKey,\n mode,\n position,\n theme,\n primaryColor,\n maxEntries,\n triggerSelector,\n autoOpenForNew,\n locale,\n onOpen,\n onClose,\n onEntryClick,\n ]);\n\n useEffect(() => {\n initWidget();\n\n return () => {\n if (widgetRef.current) {\n widgetRef.current.destroy();\n widgetRef.current = null;\n }\n };\n }, [initWidget]);\n\n // This component doesn't render visible DOM - the widget manages its own Shadow DOM\n return null;\n}\n","import type { CreateFeedbackResponse, RefletUser } from \"./types\";\n\nexport type FeedbackCategory = \"feature\" | \"bug\" | \"question\";\n\nexport interface FeedbackDialogLabels {\n cancel?: string;\n categoryBug?: string;\n categoryFeature?: string;\n categoryQuestion?: string;\n descriptionPlaceholder?: string;\n emailLabel?: string;\n emailPlaceholder?: string;\n required?: string;\n submit?: string;\n successMessage?: string;\n successTitle?: string;\n title?: string;\n titlePlaceholder?: string;\n}\n\nexport interface FeedbackDialogProps {\n /** API base URL override */\n baseUrl?: string;\n /** Categories to show (default: all three) */\n categories?: FeedbackCategory[];\n /** Default selected category */\n defaultCategory?: FeedbackCategory;\n /** Custom labels / i18n */\n labels?: FeedbackDialogLabels;\n /** Called when dialog closes */\n onClose?: () => void;\n /** Called when dialog opens */\n onOpen?: () => void;\n /** Callback when open state changes */\n onOpenChange: (open: boolean) => void;\n /** Called after successful submission */\n onSubmit?: (result: CreateFeedbackResponse) => void;\n /** Whether the dialog is open */\n open: boolean;\n /** Primary brand color (CSS value) */\n primaryColor?: string;\n /** Public API key (falls back to RefletProvider context) */\n publicKey?: string;\n /** Color theme */\n theme?: \"light\" | \"dark\" | \"auto\";\n /** User identification (falls back to RefletProvider context) */\n user?: RefletUser;\n /** Pre-signed user token */\n userToken?: string;\n}\n\nexport const DEFAULT_LABELS: Required<FeedbackDialogLabels> = {\n cancel: \"Cancel\",\n categoryBug: \"Bug\",\n categoryFeature: \"Feature\",\n categoryQuestion: \"Question\",\n descriptionPlaceholder: \"Tell us more... (optional)\",\n emailLabel: \"Email\",\n emailPlaceholder: \"your@email.com (optional)\",\n required: \"Required\",\n submit: \"Send Feedback\",\n successMessage: \"Your feedback has been received. We appreciate your input.\",\n successTitle: \"Thank you!\",\n title: \"Send Feedback\",\n titlePlaceholder: \"What's on your mind?\",\n};\n\nexport const CATEGORY_ICONS: Record<FeedbackCategory, string> = {\n bug: \"🐛\",\n feature: \"✨\",\n question: \"💬\",\n};\n\nexport const AUTO_CLOSE_DELAY = 2500;\n","export function getFeedbackChromeCSS(): string {\n return `\n/* ===== Footer ===== */\n.reflet-footer {\n display: flex;\n justify-content: flex-end;\n gap: 8px;\n padding-top: 4px;\n}\n\n.reflet-btn {\n padding: 10px 20px;\n border: none;\n border-radius: var(--reflet-radius-sm);\n font-family: var(--reflet-font);\n font-size: 14px;\n font-weight: 500;\n cursor: pointer;\n transition: all 150ms;\n display: inline-flex;\n align-items: center;\n justify-content: center;\n gap: 6px;\n line-height: 1;\n}\n\n.reflet-btn-primary {\n background: var(--reflet-primary);\n color: #ffffff;\n}\n\n.reflet-btn-primary:hover:not(:disabled) {\n background: var(--reflet-primary-hover);\n}\n\n.reflet-btn-primary:disabled {\n opacity: 0.5;\n cursor: not-allowed;\n}\n\n.reflet-btn-secondary {\n background: transparent;\n color: var(--reflet-text-secondary);\n}\n\n.reflet-btn-secondary:hover {\n background: var(--reflet-bg-secondary);\n color: var(--reflet-text);\n}\n\n/* ===== Spinner ===== */\n.reflet-spinner {\n width: 16px;\n height: 16px;\n border: 2px solid rgba(255,255,255,0.3);\n border-top-color: #ffffff;\n border-radius: 50%;\n animation: reflet-spin 600ms linear infinite;\n}\n\n/* ===== Success State ===== */\n.reflet-success {\n display: flex;\n flex-direction: column;\n align-items: center;\n justify-content: center;\n padding: 48px 24px;\n text-align: center;\n gap: 16px;\n}\n\n.reflet-success-icon {\n width: 56px;\n height: 56px;\n border-radius: 50%;\n background: color-mix(in srgb, var(--reflet-success) 12%, transparent);\n display: flex;\n align-items: center;\n justify-content: center;\n}\n\n.reflet-success-icon svg {\n width: 28px;\n height: 28px;\n color: var(--reflet-success);\n}\n\n.reflet-success-icon svg path {\n stroke-dasharray: 24;\n stroke-dashoffset: 24;\n animation: reflet-checkmark 400ms ease-out 100ms forwards;\n}\n\n.reflet-success-title {\n font-size: 18px;\n font-weight: 600;\n color: var(--reflet-text);\n margin: 0;\n}\n\n.reflet-success-text {\n font-size: 14px;\n color: var(--reflet-text-secondary);\n margin: 0;\n}\n\n/* ===== Error State ===== */\n.reflet-error-msg {\n font-size: 13px;\n color: var(--reflet-error);\n margin: 0;\n}\n\n/* ===== Trigger Button ===== */\n.reflet-trigger {\n display: inline-flex;\n align-items: center;\n gap: 8px;\n padding: 10px 18px;\n background: var(--reflet-primary);\n color: #ffffff;\n border: none;\n border-radius: var(--reflet-radius-sm);\n font-family: var(--reflet-font);\n font-size: 14px;\n font-weight: 500;\n cursor: pointer;\n transition: background 150ms;\n line-height: 1;\n}\n\n.reflet-trigger:hover {\n background: var(--reflet-primary-hover);\n}\n\n.reflet-trigger svg {\n width: 16px;\n height: 16px;\n}\n\n/* ===== Honeypot ===== */\n.reflet-hp {\n position: absolute;\n top: -9999px;\n left: -9999px;\n opacity: 0;\n height: 0;\n width: 0;\n z-index: -1;\n}\n\n/* ===== Powered by ===== */\n.reflet-powered {\n text-align: center;\n padding: 0 24px 16px;\n font-size: 11px;\n color: var(--reflet-text-tertiary);\n}\n\n.reflet-powered a {\n color: var(--reflet-text-secondary);\n text-decoration: none;\n font-weight: 500;\n}\n\n.reflet-powered a:hover {\n color: var(--reflet-primary);\n}\n\n/* ===== Mobile handle ===== */\n@media (max-width: 640px) {\n .reflet-header::before {\n content: '';\n position: absolute;\n top: 8px;\n left: 50%;\n transform: translateX(-50%);\n width: 36px;\n height: 4px;\n border-radius: 2px;\n background: var(--reflet-border);\n }\n\n .reflet-header {\n position: relative;\n padding-top: 24px;\n }\n}\n`;\n}\n","/**\n * Self-contained styles for the FeedbackButton and FeedbackDialog components.\n * Uses CSS custom properties for theming. Injected via <style> tag with a unique ID\n * to avoid duplication. All selectors are scoped under `[data-reflet-feedback]`.\n */\n\nimport { getFeedbackChromeCSS } from \"./react-feedback-styles-parts\";\n\nconst STYLE_ID = \"reflet-feedback-styles\";\n\nexport function injectFeedbackStyles(): void {\n if (typeof document === \"undefined\") {\n return;\n }\n if (document.getElementById(STYLE_ID)) {\n return;\n }\n\n const style = document.createElement(\"style\");\n style.id = STYLE_ID;\n style.textContent = getFeedbackCSS();\n document.head.appendChild(style);\n}\n\nfunction getFeedbackCSS(): string {\n return `\n[data-reflet-feedback] {\n --reflet-primary: #6366f1;\n --reflet-primary-hover: #4f46e5;\n --reflet-bg: #ffffff;\n --reflet-bg-secondary: #f9fafb;\n --reflet-text: #111827;\n --reflet-text-secondary: #6b7280;\n --reflet-text-tertiary: #9ca3af;\n --reflet-border: #e5e7eb;\n --reflet-radius: 12px;\n --reflet-radius-sm: 8px;\n --reflet-shadow: 0 20px 60px -12px rgba(0,0,0,0.25), 0 0 0 1px rgba(0,0,0,0.05);\n --reflet-font: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, sans-serif;\n --reflet-success: #22c55e;\n --reflet-error: #ef4444;\n}\n\n@media (prefers-color-scheme: dark) {\n [data-reflet-feedback][data-theme=\"auto\"] {\n --reflet-bg: #1f2937;\n --reflet-bg-secondary: #111827;\n --reflet-text: #f9fafb;\n --reflet-text-secondary: #9ca3af;\n --reflet-text-tertiary: #6b7280;\n --reflet-border: #374151;\n --reflet-shadow: 0 20px 60px -12px rgba(0,0,0,0.5), 0 0 0 1px rgba(255,255,255,0.05);\n }\n}\n\n[data-reflet-feedback][data-theme=\"dark\"] {\n --reflet-bg: #1f2937;\n --reflet-bg-secondary: #111827;\n --reflet-text: #f9fafb;\n --reflet-text-secondary: #9ca3af;\n --reflet-text-tertiary: #6b7280;\n --reflet-border: #374151;\n --reflet-shadow: 0 20px 60px -12px rgba(0,0,0,0.5), 0 0 0 1px rgba(255,255,255,0.05);\n}\n\n/* ===== Overlay ===== */\n.reflet-overlay {\n position: fixed;\n inset: 0;\n background: rgba(0,0,0,0.4);\n z-index: 99998;\n animation: reflet-fade-in 150ms ease-out;\n}\n\n@keyframes reflet-fade-in {\n from { opacity: 0; }\n to { opacity: 1; }\n}\n\n@keyframes reflet-fade-out {\n from { opacity: 1; }\n to { opacity: 0; }\n}\n\n@keyframes reflet-slide-up {\n from { transform: translateY(100%); }\n to { transform: translateY(0); }\n}\n\n@keyframes reflet-slide-down {\n from { transform: translateY(0); }\n to { transform: translateY(100%); }\n}\n\n@keyframes reflet-scale-in {\n from { opacity: 0; transform: translate(-50%, -50%) scale(0.95); }\n to { opacity: 1; transform: translate(-50%, -50%) scale(1); }\n}\n\n@keyframes reflet-scale-out {\n from { opacity: 1; transform: translate(-50%, -50%) scale(1); }\n to { opacity: 0; transform: translate(-50%, -50%) scale(0.95); }\n}\n\n@keyframes reflet-checkmark {\n 0% { stroke-dashoffset: 24; }\n 100% { stroke-dashoffset: 0; }\n}\n\n@keyframes reflet-spin {\n to { transform: rotate(360deg); }\n}\n\n.reflet-overlay[data-closing=\"true\"] {\n animation: reflet-fade-out 150ms ease-in forwards;\n}\n\n/* ===== Dialog (Desktop) ===== */\n.reflet-dialog {\n position: fixed;\n top: 50%;\n left: 50%;\n transform: translate(-50%, -50%);\n z-index: 99999;\n background: var(--reflet-bg);\n border-radius: var(--reflet-radius);\n box-shadow: var(--reflet-shadow);\n width: 480px;\n max-width: calc(100vw - 32px);\n max-height: calc(100vh - 64px);\n overflow: hidden;\n font-family: var(--reflet-font);\n color: var(--reflet-text);\n animation: reflet-scale-in 200ms cubic-bezier(0.16, 1, 0.3, 1);\n}\n\n.reflet-dialog[data-closing=\"true\"] {\n animation: reflet-scale-out 150ms ease-in forwards;\n}\n\n/* ===== Sheet (Mobile) ===== */\n@media (max-width: 640px) {\n .reflet-dialog {\n top: auto;\n left: 0;\n right: 0;\n bottom: 0;\n transform: none;\n width: 100%;\n max-width: 100%;\n border-radius: var(--reflet-radius) var(--reflet-radius) 0 0;\n max-height: 90vh;\n animation: reflet-slide-up 300ms cubic-bezier(0.16, 1, 0.3, 1);\n }\n\n .reflet-dialog[data-closing=\"true\"] {\n animation: reflet-slide-down 200ms ease-in forwards;\n }\n}\n\n/* ===== Header ===== */\n.reflet-header {\n display: flex;\n align-items: center;\n justify-content: space-between;\n padding: 20px 24px 0;\n}\n\n.reflet-title {\n font-size: 18px;\n font-weight: 600;\n margin: 0;\n color: var(--reflet-text);\n line-height: 1.3;\n}\n\n.reflet-close {\n display: flex;\n align-items: center;\n justify-content: center;\n width: 32px;\n height: 32px;\n border: none;\n background: transparent;\n border-radius: 8px;\n color: var(--reflet-text-secondary);\n cursor: pointer;\n padding: 0;\n flex-shrink: 0;\n transition: background 150ms, color 150ms;\n}\n\n.reflet-close:hover {\n background: var(--reflet-bg-secondary);\n color: var(--reflet-text);\n}\n\n.reflet-close svg {\n width: 18px;\n height: 18px;\n}\n\n/* ===== Form ===== */\n.reflet-form {\n padding: 20px 24px 24px;\n display: flex;\n flex-direction: column;\n gap: 16px;\n}\n\n.reflet-field {\n display: flex;\n flex-direction: column;\n gap: 6px;\n}\n\n.reflet-label {\n font-size: 13px;\n font-weight: 500;\n color: var(--reflet-text-secondary);\n}\n\n.reflet-input,\n.reflet-textarea {\n width: 100%;\n padding: 10px 12px;\n border: 1px solid var(--reflet-border);\n border-radius: var(--reflet-radius-sm);\n background: var(--reflet-bg);\n color: var(--reflet-text);\n font-family: var(--reflet-font);\n font-size: 14px;\n line-height: 1.5;\n outline: none;\n transition: border-color 150ms, box-shadow 150ms;\n box-sizing: border-box;\n}\n\n.reflet-input::placeholder,\n.reflet-textarea::placeholder {\n color: var(--reflet-text-tertiary);\n}\n\n.reflet-input:focus,\n.reflet-textarea:focus {\n border-color: var(--reflet-primary);\n box-shadow: 0 0 0 3px color-mix(in srgb, var(--reflet-primary) 15%, transparent);\n}\n\n.reflet-textarea {\n resize: vertical;\n min-height: 100px;\n}\n\n/* ===== Category Selector ===== */\n.reflet-categories {\n display: flex;\n gap: 8px;\n}\n\n.reflet-category {\n flex: 1;\n padding: 8px 12px;\n border: 1px solid var(--reflet-border);\n border-radius: var(--reflet-radius-sm);\n background: var(--reflet-bg);\n color: var(--reflet-text-secondary);\n font-family: var(--reflet-font);\n font-size: 13px;\n font-weight: 500;\n cursor: pointer;\n text-align: center;\n transition: all 150ms;\n}\n\n.reflet-category:hover {\n border-color: var(--reflet-primary);\n color: var(--reflet-text);\n}\n\n.reflet-category[data-selected=\"true\"] {\n border-color: var(--reflet-primary);\n background: color-mix(in srgb, var(--reflet-primary) 8%, transparent);\n color: var(--reflet-primary);\n}\n${getFeedbackChromeCSS()}\n`;\n}\n","import {\n type FormEvent,\n type KeyboardEvent,\n useCallback,\n useContext,\n useEffect,\n useRef,\n useState,\n} from \"react\";\nimport { Reflet } from \"./client\";\nimport { RefletContext } from \"./react-context\";\nimport {\n AUTO_CLOSE_DELAY,\n DEFAULT_LABELS,\n type FeedbackCategory,\n type FeedbackDialogProps,\n} from \"./react-feedback-dialog-types\";\nimport { injectFeedbackStyles } from \"./react-feedback-styles\";\n\nexport function useFeedbackDialog({\n open,\n onOpenChange,\n publicKey: publicKeyProp,\n baseUrl,\n user: userProp,\n userToken: userTokenProp,\n primaryColor,\n defaultCategory = \"feature\",\n labels: labelsProp,\n onSubmit,\n onOpen,\n onClose,\n}: Omit<FeedbackDialogProps, \"theme\" | \"categories\">) {\n const context = useContext(RefletContext);\n const publicKey = publicKeyProp ?? context?.publicKey;\n const user = userProp ?? context?.user;\n const userToken = userTokenProp ?? context?.userToken;\n\n const labels = { ...DEFAULT_LABELS, ...labelsProp };\n\n const [title, setTitle] = useState(\"\");\n const [description, setDescription] = useState(\"\");\n const [email, setEmail] = useState(\"\");\n const [category, setCategory] = useState<FeedbackCategory>(defaultCategory);\n const [honeypot, setHoneypot] = useState(\"\");\n const [isSubmitting, setIsSubmitting] = useState(false);\n const [isSuccess, setIsSuccess] = useState(false);\n const [error, setError] = useState<string | null>(null);\n const [isClosing, setIsClosing] = useState(false);\n\n const titleInputRef = useRef<HTMLInputElement>(null);\n const dialogRef = useRef<HTMLDivElement>(null);\n const previousActiveElement = useRef<Element | null>(null);\n\n const isAnonymous = !(user || userToken);\n\n // Inject styles on mount\n useEffect(() => {\n injectFeedbackStyles();\n }, []);\n\n // Apply primary color\n useEffect(() => {\n if (!(primaryColor && dialogRef.current)) {\n return;\n }\n const el = dialogRef.current.closest(\"[data-reflet-feedback]\");\n if (el instanceof HTMLElement) {\n el.style.setProperty(\"--reflet-primary\", primaryColor);\n }\n }, [primaryColor]);\n\n // Focus management\n useEffect(() => {\n if (open) {\n previousActiveElement.current = document.activeElement;\n onOpen?.();\n requestAnimationFrame(() => {\n titleInputRef.current?.focus();\n });\n }\n }, [open, onOpen]);\n\n // Escape key\n useEffect(() => {\n if (!open) {\n return;\n }\n\n const handleKeyDown = (e: globalThis.KeyboardEvent) => {\n if (e.key === \"Escape\") {\n e.preventDefault();\n handleClose();\n }\n };\n\n document.addEventListener(\"keydown\", handleKeyDown);\n return () => document.removeEventListener(\"keydown\", handleKeyDown);\n });\n\n // Lock body scroll\n useEffect(() => {\n if (!open) {\n return;\n }\n\n const originalOverflow = document.body.style.overflow;\n document.body.style.overflow = \"hidden\";\n return () => {\n document.body.style.overflow = originalOverflow;\n };\n }, [open]);\n\n const resetForm = useCallback(() => {\n setTitle(\"\");\n setDescription(\"\");\n setEmail(\"\");\n setCategory(defaultCategory);\n setHoneypot(\"\");\n setError(null);\n setIsSuccess(false);\n setIsSubmitting(false);\n }, [defaultCategory]);\n\n const handleClose = useCallback(() => {\n setIsClosing(true);\n setTimeout(() => {\n setIsClosing(false);\n onOpenChange(false);\n onClose?.();\n resetForm();\n // Restore focus\n if (previousActiveElement.current instanceof HTMLElement) {\n previousActiveElement.current.focus();\n }\n }, 200);\n }, [onOpenChange, onClose, resetForm]);\n\n const handleSubmit = useCallback(\n async (e: FormEvent) => {\n e.preventDefault();\n\n // Honeypot check (spam prevention)\n if (honeypot) {\n setIsSuccess(true);\n return;\n }\n\n if (!publicKey) {\n setError(\n \"Missing publicKey. Provide it as a prop or via RefletProvider.\"\n );\n return;\n }\n\n if (!title.trim()) {\n setError(labels.required);\n return;\n }\n\n setIsSubmitting(true);\n setError(null);\n\n try {\n const client = new Reflet({\n baseUrl,\n publicKey,\n user,\n userToken,\n });\n\n const categoryPrefix = `[${category.charAt(0).toUpperCase() + category.slice(1)}] `;\n const fullDescription = description.trim()\n ? description.trim()\n : \"No additional details provided.\";\n\n const result = await client.create({\n description: `${categoryPrefix}${fullDescription}${isAnonymous && email ? `\\n\\n---\\nContact: ${email}` : \"\"}`,\n title: title.trim(),\n });\n\n setIsSuccess(true);\n onSubmit?.(result);\n\n setTimeout(() => {\n handleClose();\n }, AUTO_CLOSE_DELAY);\n } catch (err) {\n const message =\n err instanceof Error\n ? err.message\n : \"Something went wrong. Please try again.\";\n setError(message);\n } finally {\n setIsSubmitting(false);\n }\n },\n [\n honeypot,\n publicKey,\n title,\n description,\n email,\n category,\n baseUrl,\n user,\n userToken,\n isAnonymous,\n labels.required,\n onSubmit,\n handleClose,\n ]\n );\n\n const handleTrapFocus = useCallback((e: KeyboardEvent<HTMLDivElement>) => {\n if (e.key !== \"Tab\" || !dialogRef.current) {\n return;\n }\n\n const focusable = dialogRef.current.querySelectorAll<HTMLElement>(\n 'button, input, textarea, [tabindex]:not([tabindex=\"-1\"])'\n );\n const first = focusable[0];\n // biome-ignore lint/style/useAtIndex: NodeListOf doesn't support .at()\n const last = focusable[focusable.length - 1];\n\n if (!(first && last)) {\n return;\n }\n\n if (e.shiftKey && document.activeElement === first) {\n e.preventDefault();\n last.focus();\n } else if (!e.shiftKey && document.activeElement === last) {\n e.preventDefault();\n first.focus();\n }\n }, []);\n\n return {\n category,\n description,\n dialogRef,\n email,\n error,\n handleClose,\n handleSubmit,\n handleTrapFocus,\n honeypot,\n isAnonymous,\n isClosing,\n isSubmitting,\n isSuccess,\n labels,\n setCategory,\n setDescription,\n setEmail,\n setError,\n setHoneypot,\n setTitle,\n title,\n titleInputRef,\n };\n}\n","import { useFeedbackDialog } from \"./react-feedback-dialog-hook\";\nimport {\n CATEGORY_ICONS,\n type FeedbackDialogLabels,\n type FeedbackDialogProps,\n} from \"./react-feedback-dialog-types\";\n\nexport type {\n FeedbackCategory,\n FeedbackDialogLabels,\n FeedbackDialogProps,\n} from \"./react-feedback-dialog-types\";\n\nexport function FeedbackDialog({\n open,\n onOpenChange,\n publicKey,\n baseUrl,\n user,\n userToken,\n theme = \"auto\",\n primaryColor,\n defaultCategory = \"feature\",\n categories = [\"feature\", \"bug\", \"question\"],\n labels: labelsProp,\n onSubmit,\n onOpen,\n onClose,\n}: FeedbackDialogProps) {\n const {\n labels,\n title,\n setTitle,\n description,\n setDescription,\n email,\n setEmail,\n category,\n setCategory,\n honeypot,\n setHoneypot,\n isSubmitting,\n isSuccess,\n error,\n setError,\n isClosing,\n isAnonymous,\n titleInputRef,\n dialogRef,\n handleClose,\n handleSubmit,\n handleTrapFocus,\n } = useFeedbackDialog({\n baseUrl,\n defaultCategory,\n labels: labelsProp,\n onClose,\n onOpen,\n onOpenChange,\n onSubmit,\n open,\n primaryColor,\n publicKey,\n user,\n userToken,\n });\n\n if (!open) {\n return null;\n }\n\n return (\n <div data-reflet-feedback=\"\" data-theme={theme}>\n {/* Overlay */}\n <button\n aria-label=\"Close feedback dialog\"\n className=\"reflet-overlay\"\n data-closing={isClosing ? \"true\" : undefined}\n onClick={handleClose}\n tabIndex={0}\n type=\"button\"\n />\n\n {/* Dialog */}\n {/* biome-ignore lint/a11y/noNoninteractiveElementInteractions: dialog role requires keyboard trap */}\n <div\n aria-label={labels.title}\n aria-modal=\"true\"\n className=\"reflet-dialog\"\n data-closing={isClosing ? \"true\" : undefined}\n onKeyDown={handleTrapFocus}\n ref={dialogRef}\n role=\"dialog\"\n >\n {isSuccess ? (\n <div className=\"reflet-success\">\n <div className=\"reflet-success-icon\">\n <svg\n aria-hidden=\"true\"\n fill=\"none\"\n stroke=\"currentColor\"\n strokeLinecap=\"round\"\n strokeLinejoin=\"round\"\n strokeWidth=\"2.5\"\n viewBox=\"0 0 24 24\"\n >\n <path d=\"M5 13l4 4L19 7\" />\n </svg>\n </div>\n <h2 className=\"reflet-success-title\">{labels.successTitle}</h2>\n <p className=\"reflet-success-text\">{labels.successMessage}</p>\n </div>\n ) : (\n <>\n {/* Header */}\n <div className=\"reflet-header\">\n <h2 className=\"reflet-title\">{labels.title}</h2>\n <button\n aria-label=\"Close\"\n className=\"reflet-close\"\n onClick={handleClose}\n type=\"button\"\n >\n <svg\n aria-hidden=\"true\"\n fill=\"none\"\n stroke=\"currentColor\"\n strokeLinecap=\"round\"\n strokeLinejoin=\"round\"\n strokeWidth=\"2\"\n viewBox=\"0 0 24 24\"\n >\n <line x1=\"18\" x2=\"6\" y1=\"6\" y2=\"18\" />\n <line x1=\"6\" x2=\"18\" y1=\"6\" y2=\"18\" />\n </svg>\n </button>\n </div>\n\n {/* Form */}\n <form className=\"reflet-form\" onSubmit={handleSubmit}>\n {/* Category selector */}\n {categories.length > 1 && (\n <div className=\"reflet-categories\">\n {categories.map((cat) => (\n <button\n className=\"reflet-category\"\n data-selected={cat === category ? \"true\" : undefined}\n key={cat}\n onClick={() => setCategory(cat)}\n type=\"button\"\n >\n {CATEGORY_ICONS[cat]}{\" \"}\n {\n labels[\n `category${cat.charAt(0).toUpperCase()}${cat.slice(1)}` as keyof FeedbackDialogLabels\n ]\n }\n </button>\n ))}\n </div>\n )}\n\n {/* Title */}\n <div className=\"reflet-field\">\n <input\n aria-label=\"Feedback title\"\n autoComplete=\"off\"\n className=\"reflet-input\"\n maxLength={100}\n onChange={(e) => {\n setTitle(e.target.value);\n if (error) {\n setError(null);\n }\n }}\n placeholder={labels.titlePlaceholder}\n ref={titleInputRef}\n required\n type=\"text\"\n value={title}\n />\n </div>\n\n {/* Description */}\n <div className=\"reflet-field\">\n <textarea\n aria-label=\"Feedback description\"\n className=\"reflet-textarea\"\n maxLength={2000}\n onChange={(e) => setDescription(e.target.value)}\n placeholder={labels.descriptionPlaceholder}\n rows={3}\n value={description}\n />\n </div>\n\n {/* Email (anonymous only) */}\n {isAnonymous && (\n <div className=\"reflet-field\">\n <label className=\"reflet-label\" htmlFor=\"reflet-email\">\n {labels.emailLabel}\n </label>\n <input\n aria-label=\"Email address\"\n autoComplete=\"email\"\n className=\"reflet-input\"\n id=\"reflet-email\"\n onChange={(e) => setEmail(e.target.value)}\n placeholder={labels.emailPlaceholder}\n type=\"email\"\n value={email}\n />\n </div>\n )}\n\n {/* Honeypot */}\n <div aria-hidden=\"true\" className=\"reflet-hp\">\n <input\n autoComplete=\"off\"\n name=\"website\"\n onChange={(e) => setHoneypot(e.target.value)}\n tabIndex={-1}\n type=\"text\"\n value={honeypot}\n />\n </div>\n\n {/* Error */}\n {error && <p className=\"reflet-error-msg\">{error}</p>}\n\n {/* Footer */}\n <div className=\"reflet-footer\">\n <button\n className=\"reflet-btn reflet-btn-secondary\"\n onClick={handleClose}\n type=\"button\"\n >\n {labels.cancel}\n </button>\n <button\n className=\"reflet-btn reflet-btn-primary\"\n disabled={isSubmitting || !title.trim()}\n type=\"submit\"\n >\n {isSubmitting ? (\n <span className=\"reflet-spinner\" />\n ) : (\n labels.submit\n )}\n </button>\n </div>\n </form>\n\n {/* Powered by */}\n <div className=\"reflet-powered\">\n Powered by{\" \"}\n <a\n href=\"https://reflet.app\"\n rel=\"noopener noreferrer\"\n target=\"_blank\"\n >\n Reflet\n </a>\n </div>\n </>\n )}\n </div>\n </div>\n );\n}\n","import {\n cloneElement,\n isValidElement,\n type ReactElement,\n type ReactNode,\n useCallback,\n useState,\n} from \"react\";\nimport {\n type FeedbackCategory,\n FeedbackDialog,\n type FeedbackDialogLabels,\n} from \"./react-feedback-dialog\";\nimport { injectFeedbackStyles } from \"./react-feedback-styles\";\nimport type { CreateFeedbackResponse, RefletUser } from \"./types\";\n\n// ============================================\n// Types\n// ============================================\n\nexport interface FeedbackButtonProps {\n /**\n * Render as child element instead of the default button.\n * When true, the first child element receives the onClick handler.\n */\n asChild?: boolean;\n /** API base URL override */\n baseUrl?: string;\n /** Categories to show */\n categories?: FeedbackCategory[];\n /** Custom trigger content or element (used with asChild) */\n children?: ReactNode;\n /** Custom CSS class for the default trigger button */\n className?: string;\n /** Default selected category */\n defaultCategory?: FeedbackCategory;\n /** Custom labels / i18n */\n labels?: FeedbackDialogLabels & { trigger?: string };\n /** Called when dialog closes */\n onClose?: () => void;\n /** Called when dialog opens */\n onOpen?: () => void;\n /** Called after successful submission */\n onSubmit?: (result: CreateFeedbackResponse) => void;\n /** Primary brand color (CSS value) */\n primaryColor?: string;\n /** Public API key (falls back to RefletProvider context) */\n publicKey?: string;\n /** Color theme */\n theme?: \"light\" | \"dark\" | \"auto\";\n /** User identification (falls back to RefletProvider context) */\n user?: RefletUser;\n /** Pre-signed user token */\n userToken?: string;\n}\n\n// ============================================\n// Feedback Icon SVG\n// ============================================\n\nfunction FeedbackIcon() {\n return (\n <svg\n aria-hidden=\"true\"\n fill=\"none\"\n height=\"16\"\n stroke=\"currentColor\"\n strokeLinecap=\"round\"\n strokeLinejoin=\"round\"\n strokeWidth=\"2\"\n viewBox=\"0 0 24 24\"\n width=\"16\"\n >\n <path d=\"M21 15a2 2 0 0 1-2 2H7l-4 4V5a2 2 0 0 1 2-2h14a2 2 0 0 1 2 2z\" />\n </svg>\n );\n}\n\n// ============================================\n// Component\n// ============================================\n\nexport function FeedbackButton({\n publicKey,\n baseUrl,\n user,\n userToken,\n theme = \"auto\",\n primaryColor,\n defaultCategory = \"feature\",\n categories,\n labels,\n onSubmit,\n onOpen,\n onClose,\n className,\n asChild = false,\n children,\n}: FeedbackButtonProps) {\n const [open, setOpen] = useState(false);\n\n // Inject styles so the trigger button is styled\n useState(() => {\n injectFeedbackStyles();\n });\n\n const handleClick = useCallback(() => {\n setOpen(true);\n }, []);\n\n // Render trigger\n let trigger: ReactNode;\n\n if (asChild && isValidElement(children)) {\n trigger = cloneElement(children as ReactElement<{ onClick?: () => void }>, {\n onClick: handleClick,\n });\n } else {\n const triggerLabel = labels?.trigger ?? \"Feedback\";\n trigger = (\n <div data-reflet-feedback=\"\" data-theme={theme}>\n <button\n aria-label={triggerLabel}\n className={className ?? \"reflet-trigger\"}\n onClick={handleClick}\n style={\n primaryColor\n ? ({\n \"--reflet-primary\": primaryColor,\n \"--reflet-primary-hover\": primaryColor,\n } as React.CSSProperties)\n : undefined\n }\n type=\"button\"\n >\n <FeedbackIcon />\n {triggerLabel}\n </button>\n </div>\n );\n }\n\n return (\n <>\n {trigger}\n <FeedbackDialog\n baseUrl={baseUrl}\n categories={categories}\n defaultCategory={defaultCategory}\n labels={labels}\n onClose={onClose}\n onOpen={onOpen}\n onOpenChange={setOpen}\n onSubmit={onSubmit}\n open={open}\n primaryColor={primaryColor}\n publicKey={publicKey}\n theme={theme}\n user={user}\n userToken={userToken}\n />\n </>\n );\n}\n","import { useCallback, useState } from \"react\";\nimport { useRefletClient } from \"./react-context\";\nimport type { UseMutationResult } from \"./react-hooks-types\";\nimport type { AddCommentParams, CreateFeedbackParams } from \"./types\";\n\n// ============================================\n// Generic mutation hook — single source of truth\n// ============================================\n\nfunction useRefletMutation<TData, TVariables>(\n mutateFn: (variables: TVariables) => Promise<TData>\n): UseMutationResult<TData, TVariables> {\n const [isLoading, setIsLoading] = useState(false);\n const [error, setError] = useState<Error | null>(null);\n const [data, setData] = useState<TData | undefined>();\n\n const mutate = useCallback(\n async (variables: TVariables) => {\n setIsLoading(true);\n setError(null);\n try {\n const result = await mutateFn(variables);\n setData(result);\n return result;\n } catch (err) {\n const wrapped =\n err instanceof Error ? err : new Error(\"Request failed\");\n setError(wrapped);\n throw wrapped;\n } finally {\n setIsLoading(false);\n }\n },\n [mutateFn]\n );\n\n const reset = useCallback(() => {\n setData(undefined);\n setError(null);\n }, []);\n\n return { data, error, isLoading, mutate, reset };\n}\n\n// ============================================\n// Create Feedback Mutation Hook\n// ============================================\n\n/**\n * Hook to create new feedback\n *\n * @example\n * ```tsx\n * const { mutate: createFeedback, isLoading } = useCreateFeedback();\n *\n * const handleSubmit = async (data) => {\n * const result = await createFeedback(data);\n * console.log('Created:', result.feedbackId);\n * };\n * ```\n */\nexport function useCreateFeedback(): UseMutationResult<\n { feedbackId: string; isApproved: boolean },\n CreateFeedbackParams\n> {\n const client = useRefletClient();\n const mutateFn = useCallback(\n (params: CreateFeedbackParams) => client.create(params),\n [client]\n );\n return useRefletMutation(mutateFn);\n}\n\n// ============================================\n// Vote Mutation Hook\n// ============================================\n\n/**\n * Hook to vote on feedback\n *\n * @example\n * ```tsx\n * const { mutate: vote } = useVote();\n *\n * <button onClick={() => vote({ feedbackId: 'xxx' })}>\n * Vote\n * </button>\n * ```\n */\nexport function useVote(): UseMutationResult<\n { voted: boolean; voteCount: number },\n { feedbackId: string; type?: \"upvote\" | \"downvote\" }\n> {\n const client = useRefletClient();\n const mutateFn = useCallback(\n ({\n feedbackId,\n type = \"upvote\",\n }: {\n feedbackId: string;\n type?: \"upvote\" | \"downvote\";\n }) => client.vote(feedbackId, type),\n [client]\n );\n return useRefletMutation(mutateFn);\n}\n\n// ============================================\n// Comment Mutation Hook\n// ============================================\n\n/**\n * Hook to add a comment\n */\nexport function useAddComment(): UseMutationResult<\n { commentId: string },\n AddCommentParams\n> {\n const client = useRefletClient();\n const mutateFn = useCallback(\n (params: AddCommentParams) => client.comment(params),\n [client]\n );\n return useRefletMutation(mutateFn);\n}\n\n// ============================================\n// Subscribe Mutation Hook\n// ============================================\n\n/**\n * Hook to subscribe/unsubscribe to feedback\n */\nexport function useSubscription(): {\n subscribe: (feedbackId: string) => Promise<{ subscribed: boolean }>;\n unsubscribe: (feedbackId: string) => Promise<{ unsubscribed: boolean }>;\n isLoading: boolean;\n error: Error | null;\n} {\n const client = useRefletClient();\n const [isLoading, setIsLoading] = useState(false);\n const [error, setError] = useState<Error | null>(null);\n\n const subscribe = useCallback(\n async (feedbackId: string) => {\n setIsLoading(true);\n setError(null);\n try {\n return await client.subscribe(feedbackId);\n } catch (err) {\n const wrapped =\n err instanceof Error ? err : new Error(\"Failed to subscribe\");\n setError(wrapped);\n throw wrapped;\n } finally {\n setIsLoading(false);\n }\n },\n [client]\n );\n\n const unsubscribe = useCallback(\n async (feedbackId: string) => {\n setIsLoading(true);\n setError(null);\n try {\n return await client.unsubscribe(feedbackId);\n } catch (err) {\n const wrapped =\n err instanceof Error ? err : new Error(\"Failed to unsubscribe\");\n setError(wrapped);\n throw wrapped;\n } finally {\n setIsLoading(false);\n }\n },\n [client]\n );\n\n return { error, isLoading, subscribe, unsubscribe };\n}\n","import { useCallback, useEffect, useMemo, useState } from \"react\";\nimport { useRefletClient } from \"./react-context\";\nimport type { UseQueryResult } from \"./react-hooks-types\";\nimport type {\n ChangelogEntry,\n Comment,\n FeedbackDetail,\n FeedbackItem,\n FeedbackListParams,\n OrganizationConfig,\n Roadmap,\n} from \"./types\";\n\n// ============================================\n// Generic query hook — single source of truth\n// ============================================\n\nfunction useRefletQuery<T>(\n fetchFn: () => Promise<T>,\n enabled = true\n): UseQueryResult<T> {\n const [data, setData] = useState<T | undefined>();\n const [isLoading, setIsLoading] = useState(enabled);\n const [error, setError] = useState<Error | null>(null);\n\n const refetch = useCallback(async () => {\n setIsLoading(true);\n setError(null);\n try {\n const result = await fetchFn();\n setData(result);\n } catch (err) {\n setError(err instanceof Error ? err : new Error(\"Request failed\"));\n } finally {\n setIsLoading(false);\n }\n }, [fetchFn]);\n\n useEffect(() => {\n if (enabled) {\n refetch();\n }\n }, [refetch, enabled]);\n\n return { data, error, isLoading, refetch };\n}\n\n// ============================================\n// Organization Config Hook\n// ============================================\n\nexport function useOrganizationConfig(): UseQueryResult<OrganizationConfig> {\n const client = useRefletClient();\n const fetchFn = useCallback(() => client.getConfig(), [client]);\n return useRefletQuery(fetchFn);\n}\n\n// ============================================\n// Feedback List Hook\n// ============================================\n\nexport interface UseFeedbackListOptions extends FeedbackListParams {\n enabled?: boolean;\n}\n\nexport function useFeedbackList(\n options: UseFeedbackListOptions = {}\n): UseQueryResult<{ items: FeedbackItem[]; total: number; hasMore: boolean }> {\n const client = useRefletClient();\n const {\n enabled = true,\n statusId,\n status,\n search,\n sortBy,\n limit,\n offset,\n } = options;\n\n const params = useMemo(\n () => ({ limit, offset, search, sortBy, status, statusId }),\n [statusId, status, search, sortBy, limit, offset]\n );\n\n const fetchFn = useCallback(() => client.list(params), [client, params]);\n return useRefletQuery(fetchFn, enabled);\n}\n\n// ============================================\n// Single Feedback Hook\n// ============================================\n\nexport function useFeedback(\n feedbackId: string | undefined\n): UseQueryResult<FeedbackDetail> {\n const client = useRefletClient();\n\n const fetchFn = useCallback(() => {\n if (!feedbackId) {\n return Promise.resolve(undefined as unknown as FeedbackDetail);\n }\n return client.get(feedbackId);\n }, [client, feedbackId]);\n\n return useRefletQuery(fetchFn, !!feedbackId);\n}\n\n// ============================================\n// Comments Hook\n// ============================================\n\nexport function useComments(\n feedbackId: string | undefined,\n sortBy: \"newest\" | \"oldest\" = \"oldest\"\n): UseQueryResult<Comment[]> {\n const client = useRefletClient();\n\n const fetchFn = useCallback(() => {\n if (!feedbackId) {\n return Promise.resolve(undefined as unknown as Comment[]);\n }\n return client.getComments(feedbackId, sortBy);\n }, [client, feedbackId, sortBy]);\n\n return useRefletQuery(fetchFn, !!feedbackId);\n}\n\n// ============================================\n// Roadmap Hook\n// ============================================\n\nexport function useRoadmap(): UseQueryResult<Roadmap> {\n const client = useRefletClient();\n const fetchFn = useCallback(() => client.getRoadmap(), [client]);\n return useRefletQuery(fetchFn);\n}\n\n// ============================================\n// Changelog Hook\n// ============================================\n\nexport function useChangelog(limit?: number): UseQueryResult<ChangelogEntry[]> {\n const client = useRefletClient();\n const fetchFn = useCallback(\n () => client.getChangelog(limit),\n [client, limit]\n );\n return useRefletQuery(fetchFn);\n}\n\n// ============================================\n// Unread Changelog Count Hook\n// ============================================\n\nconst CHANGELOG_STORAGE_KEY_PREFIX = \"reflet_changelog_seen_\";\n\nexport function useUnreadChangelogCount(publicKey: string): {\n unreadCount: number;\n markAsRead: () => void;\n} {\n const { data: entries } = useChangelog();\n const [unreadCount, setUnreadCount] = useState(0);\n\n const storageKey = `${CHANGELOG_STORAGE_KEY_PREFIX}${publicKey}`;\n\n useEffect(() => {\n if (!entries || entries.length === 0) {\n setUnreadCount(0);\n return;\n }\n\n let lastSeen = 0;\n try {\n const stored = localStorage.getItem(storageKey);\n lastSeen = stored ? Number(stored) : 0;\n } catch {\n // localStorage unavailable\n }\n\n let count = 0;\n for (const entry of entries) {\n if (entry.publishedAt && entry.publishedAt > lastSeen) {\n count++;\n }\n }\n setUnreadCount(count);\n }, [entries, storageKey]);\n\n const markAsRead = useCallback(() => {\n if (!entries || entries.length === 0) {\n return;\n }\n\n let latestTimestamp = 0;\n for (const entry of entries) {\n if (entry.publishedAt && entry.publishedAt > latestTimestamp) {\n latestTimestamp = entry.publishedAt;\n }\n }\n\n if (latestTimestamp > 0) {\n try {\n localStorage.setItem(storageKey, String(latestTimestamp));\n } catch {\n // localStorage unavailable\n }\n setUnreadCount(0);\n }\n }, [entries, storageKey]);\n\n return { markAsRead, unreadCount };\n}\n"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"react.js","names":[],"sources":["../src/react-changelog-widget.tsx","../src/react-feedback-dialog-types.ts","../src/react-feedback-styles-parts.ts","../src/react-feedback-styles.ts","../src/react-feedback-dialog-hook.ts","../src/react-feedback-dialog.tsx","../src/react-feedback-button.tsx","../src/react-mutation-hooks.ts","../src/react-query-hooks.ts"],"sourcesContent":["import { useCallback, useEffect, useRef } from \"react\";\nimport type { ChangelogEntry } from \"./types\";\n\ninterface ChangelogWidgetProps {\n autoOpenForNew?: boolean;\n locale?: string;\n maxEntries?: number;\n mode?: \"card\" | \"popup\" | \"trigger\";\n onClose?: () => void;\n onEntryClick?: (entry: ChangelogEntry) => void;\n onOpen?: () => void;\n position?: \"bottom-right\" | \"bottom-left\";\n primaryColor?: string;\n publicKey: string;\n theme?: \"light\" | \"dark\" | \"auto\";\n triggerSelector?: string;\n}\n\ninterface WidgetInstance {\n close: () => void;\n destroy: () => void;\n getUnreadCount: () => number;\n init: () => Promise<void>;\n markAsRead: () => void;\n open: () => void;\n}\n\ndeclare global {\n interface Window {\n RefletChangelogWidget?: new (\n config: ChangelogWidgetProps\n ) => WidgetInstance;\n }\n}\n\n/**\n * React component that wraps the Reflet Changelog Widget.\n *\n * Dynamically loads and initializes a RefletChangelogWidget instance.\n *\n * @example\n * ```tsx\n * import { ChangelogWidget } from 'reflet-sdk/react';\n *\n * export function MyApp() {\n * return <ChangelogWidget publicKey=\"fb_pub_xxx\" mode=\"card\" theme=\"auto\" />;\n * }\n * ```\n */\nexport function ChangelogWidget({\n publicKey,\n mode = \"card\",\n position = \"bottom-right\",\n theme = \"light\",\n primaryColor,\n maxEntries,\n triggerSelector,\n autoOpenForNew,\n locale,\n onOpen,\n onClose,\n onEntryClick,\n}: ChangelogWidgetProps) {\n const widgetRef = useRef<WidgetInstance | null>(null);\n\n const initWidget = useCallback(async () => {\n // Check if RefletChangelogWidget is available globally\n const WidgetClass = window.RefletChangelogWidget;\n\n if (WidgetClass) {\n const instance = new WidgetClass({\n autoOpenForNew,\n locale,\n maxEntries,\n mode,\n onClose,\n onEntryClick,\n onOpen,\n position,\n primaryColor,\n publicKey,\n theme,\n triggerSelector,\n });\n\n widgetRef.current = instance;\n await instance.init();\n return;\n }\n\n // Try loading the script dynamically\n const existingScript = document.querySelector(\n 'script[src*=\"reflet-changelog\"]'\n );\n if (!existingScript) {\n const script = document.createElement(\"script\");\n script.src = \"https://cdn.reflet.app/widget/reflet-changelog.v1.js\";\n script.async = true;\n script.onload = () => {\n const LoadedClass = window.RefletChangelogWidget;\n\n if (LoadedClass) {\n const instance = new LoadedClass({\n autoOpenForNew,\n locale,\n maxEntries,\n mode,\n onClose,\n onEntryClick,\n onOpen,\n position,\n primaryColor,\n publicKey,\n theme,\n triggerSelector,\n });\n\n widgetRef.current = instance;\n instance.init();\n }\n };\n document.head.appendChild(script);\n }\n }, [\n publicKey,\n mode,\n position,\n theme,\n primaryColor,\n maxEntries,\n triggerSelector,\n autoOpenForNew,\n locale,\n onOpen,\n onClose,\n onEntryClick,\n ]);\n\n useEffect(() => {\n initWidget();\n\n return () => {\n if (widgetRef.current) {\n widgetRef.current.destroy();\n widgetRef.current = null;\n }\n };\n }, [initWidget]);\n\n // This component doesn't render visible DOM - the widget manages its own Shadow DOM\n return null;\n}\n","import type { CreateFeedbackResponse, RefletUser } from \"./types\";\n\nexport interface FeedbackDialogLabels {\n cancel?: string;\n close?: string;\n descriptionPlaceholder?: string;\n emailLabel?: string;\n emailPlaceholder?: string;\n required?: string;\n submit?: string;\n successMessage?: string;\n successTitle?: string;\n title?: string;\n titlePlaceholder?: string;\n}\n\nexport interface FeedbackDialogProps {\n /** API base URL override */\n baseUrl?: string;\n /** Custom labels / i18n */\n labels?: FeedbackDialogLabels;\n /** Called when dialog closes */\n onClose?: () => void;\n /** Called when dialog opens */\n onOpen?: () => void;\n /** Callback when open state changes */\n onOpenChange: (open: boolean) => void;\n /** Called after successful submission */\n onSubmit?: (result: CreateFeedbackResponse) => void;\n /** Whether the dialog is open */\n open: boolean;\n /** Primary brand color (CSS value) */\n primaryColor?: string;\n /** Public API key (falls back to RefletProvider context) */\n publicKey?: string;\n /** Color theme */\n theme?: \"light\" | \"dark\" | \"auto\";\n /** User identification (falls back to RefletProvider context) */\n user?: RefletUser;\n /** Pre-signed user token */\n userToken?: string;\n}\n\nexport const DEFAULT_LABELS: Required<FeedbackDialogLabels> = {\n cancel: \"Cancel\",\n close: \"Close\",\n descriptionPlaceholder: \"Tell us more... (optional)\",\n emailLabel: \"Email\",\n emailPlaceholder: \"your@email.com (optional)\",\n required: \"Required\",\n submit: \"Send Feedback\",\n successMessage: \"Your feedback has been received. We appreciate your input.\",\n successTitle: \"Thank you!\",\n title: \"Send Feedback\",\n titlePlaceholder: \"What's on your mind?\",\n};\n\nexport const AUTO_CLOSE_DELAY = 2500;\n","export function getFeedbackChromeCSS(): string {\n return `\n.reflet-footer {\n display: flex;\n justify-content: flex-end;\n gap: 8px;\n padding-top: 4px;\n}\n\n.reflet-btn {\n min-height: 40px;\n padding: 10px 20px;\n border: none;\n border-radius: var(--reflet-radius-sm);\n font-family: var(--reflet-font);\n font-size: 14px;\n font-weight: 500;\n cursor: pointer;\n transition: background 150ms, color 150ms, opacity 150ms, transform 150ms var(--reflet-ease);\n display: inline-flex;\n align-items: center;\n justify-content: center;\n gap: 6px;\n line-height: 1;\n}\n\n.reflet-btn-primary {\n background: var(--reflet-primary);\n color: var(--reflet-on-primary);\n}\n\n.reflet-btn-primary:hover:not(:disabled) {\n background: var(--reflet-primary-hover);\n}\n\n.reflet-btn-primary:disabled {\n opacity: 0.5;\n cursor: not-allowed;\n}\n\n.reflet-btn-secondary {\n background: transparent;\n color: var(--reflet-text-secondary);\n}\n\n.reflet-btn-secondary:hover {\n background: var(--reflet-bg-secondary);\n color: var(--reflet-text);\n}\n\n.reflet-spinner {\n width: 16px;\n height: 16px;\n border: 2px solid var(--reflet-on-primary-soft);\n border-top-color: var(--reflet-on-primary);\n border-radius: 50%;\n animation: reflet-spin 600ms linear infinite;\n}\n\n.reflet-success {\n display: flex;\n flex-direction: column;\n align-items: center;\n justify-content: center;\n padding: 48px 24px;\n text-align: center;\n gap: 16px;\n}\n\n.reflet-success-icon {\n width: 56px;\n height: 56px;\n border-radius: 50%;\n background: color-mix(in srgb, var(--reflet-success) 12%, transparent);\n display: flex;\n align-items: center;\n justify-content: center;\n}\n\n.reflet-success-icon svg {\n width: 28px;\n height: 28px;\n color: var(--reflet-success);\n}\n\n.reflet-success-icon svg path {\n stroke-dasharray: 24;\n stroke-dashoffset: 24;\n animation: reflet-checkmark 400ms ease-out 100ms forwards;\n}\n\n.reflet-success-title {\n font-size: 18px;\n font-weight: 600;\n color: var(--reflet-text);\n margin: 0;\n}\n\n.reflet-success-text {\n font-size: 14px;\n color: var(--reflet-text-secondary);\n margin: 0;\n}\n\n.reflet-error-msg {\n font-size: 13px;\n color: var(--reflet-error);\n margin: 0;\n}\n\n.reflet-trigger {\n display: inline-flex;\n align-items: center;\n gap: 8px;\n min-height: 40px;\n padding: 10px 18px;\n background: var(--reflet-primary);\n color: var(--reflet-on-primary);\n border: none;\n border-radius: var(--reflet-radius-sm);\n font-family: var(--reflet-font);\n font-size: 14px;\n font-weight: 500;\n cursor: pointer;\n transition: background 150ms, transform 150ms var(--reflet-ease);\n line-height: 1;\n}\n\n.reflet-trigger:hover {\n background: var(--reflet-primary-hover);\n}\n\n.reflet-trigger svg {\n width: 16px;\n height: 16px;\n}\n\n.reflet-hp {\n position: absolute;\n top: -9999px;\n left: -9999px;\n opacity: 0;\n height: 0;\n width: 0;\n z-index: -1;\n}\n\n.reflet-powered {\n text-align: center;\n padding: 0 24px 16px;\n font-size: 11px;\n color: var(--reflet-text-tertiary);\n}\n\n.reflet-powered a {\n color: var(--reflet-text-secondary);\n text-decoration: none;\n font-weight: 500;\n}\n\n.reflet-powered a:hover {\n color: var(--reflet-primary);\n}\n\n@media (max-width: 640px) {\n .reflet-header::before {\n content: '';\n position: absolute;\n top: 8px;\n left: 50%;\n transform: translateX(-50%);\n width: 36px;\n height: 4px;\n border-radius: 2px;\n background: var(--reflet-border);\n }\n\n .reflet-header {\n position: relative;\n padding-top: 24px;\n }\n}\n\n@media (prefers-reduced-motion: reduce) {\n .reflet-success-icon svg path {\n stroke-dasharray: none;\n stroke-dashoffset: 0;\n animation: none;\n }\n}\n`;\n}\n","import { getFeedbackChromeCSS } from \"./react-feedback-styles-parts\";\nimport { REFLET_Z_INDEX } from \"./z-index\";\n\nconst STYLE_ID = \"reflet-feedback-styles\";\n\nexport function injectFeedbackStyles(): void {\n if (typeof document === \"undefined\") {\n return;\n }\n if (document.getElementById(STYLE_ID)) {\n return;\n }\n\n const style = document.createElement(\"style\");\n style.id = STYLE_ID;\n style.textContent = getFeedbackCSS();\n document.head.appendChild(style);\n}\n\nfunction getFeedbackCSS(): string {\n return `\n:root {\n --reflet-scrim: rgb(0 0 0 / 45%);\n}\n\n[data-reflet-feedback] {\n --reflet-primary: #6366f1;\n --reflet-primary-hover: #4f46e5;\n --reflet-on-primary: #ffffff;\n --reflet-on-primary-soft: rgb(255 255 255 / 30%);\n --reflet-bg: #ffffff;\n --reflet-bg-secondary: #f9fafb;\n --reflet-text: #111827;\n --reflet-text-secondary: #6b7280;\n --reflet-text-tertiary: #9ca3af;\n --reflet-border: #e5e7eb;\n --reflet-radius: 12px;\n --reflet-radius-sm: 8px;\n --reflet-shadow: 0 20px 60px -12px rgb(0 0 0 / 25%), 0 0 0 1px rgb(0 0 0 / 5%);\n --reflet-font: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, sans-serif;\n --reflet-success: #22c55e;\n --reflet-error: #ef4444;\n --reflet-ease: cubic-bezier(0.16, 1, 0.3, 1);\n}\n\n@media (prefers-color-scheme: dark) {\n [data-reflet-feedback][data-theme=\"auto\"] {\n --reflet-bg: #1f2937;\n --reflet-bg-secondary: #111827;\n --reflet-text: #f9fafb;\n --reflet-text-secondary: #9ca3af;\n --reflet-text-tertiary: #6b7280;\n --reflet-border: #374151;\n --reflet-shadow: 0 20px 60px -12px rgb(0 0 0 / 50%), 0 0 0 1px rgb(255 255 255 / 5%);\n }\n}\n\n[data-reflet-feedback][data-theme=\"dark\"] {\n --reflet-bg: #1f2937;\n --reflet-bg-secondary: #111827;\n --reflet-text: #f9fafb;\n --reflet-text-secondary: #9ca3af;\n --reflet-text-tertiary: #6b7280;\n --reflet-border: #374151;\n --reflet-shadow: 0 20px 60px -12px rgb(0 0 0 / 50%), 0 0 0 1px rgb(255 255 255 / 5%);\n}\n\n@keyframes reflet-fade-in {\n from { opacity: 0; }\n to { opacity: 1; }\n}\n\n@keyframes reflet-fade-out {\n from { opacity: 1; }\n to { opacity: 0; }\n}\n\n@keyframes reflet-slide-up {\n from { transform: translateY(100%); }\n to { transform: translateY(0); }\n}\n\n@keyframes reflet-slide-down {\n from { transform: translateY(0); }\n to { transform: translateY(100%); }\n}\n\n@keyframes reflet-scale-in {\n from { opacity: 0; transform: translate(-50%, -50%) scale(0.95); }\n to { opacity: 1; transform: translate(-50%, -50%) scale(1); }\n}\n\n@keyframes reflet-scale-out {\n from { opacity: 1; transform: translate(-50%, -50%) scale(1); }\n to { opacity: 0; transform: translate(-50%, -50%) scale(0.95); }\n}\n\n@keyframes reflet-checkmark {\n 0% { stroke-dashoffset: 24; }\n 100% { stroke-dashoffset: 0; }\n}\n\n@keyframes reflet-spin {\n to { transform: rotate(360deg); }\n}\n\n.reflet-dialog {\n position: fixed;\n top: 50%;\n left: 50%;\n transform: translate(-50%, -50%);\n z-index: ${REFLET_Z_INDEX.dialogContent};\n margin: 0;\n border: 0;\n padding: 0;\n background: var(--reflet-bg);\n border-radius: var(--reflet-radius);\n box-shadow: var(--reflet-shadow);\n width: 480px;\n max-width: calc(100vw - 32px);\n max-height: calc(100dvh - 64px);\n overflow: hidden;\n overscroll-behavior: contain;\n font-family: var(--reflet-font);\n color: var(--reflet-text);\n animation: reflet-scale-in 200ms var(--reflet-ease);\n}\n\n.reflet-dialog::backdrop {\n z-index: ${REFLET_Z_INDEX.dialogOverlay};\n background: var(--reflet-scrim);\n animation: reflet-fade-in 150ms ease-out;\n}\n\n.reflet-dialog[data-closing=\"true\"] {\n animation: reflet-scale-out 150ms ease-out forwards;\n}\n\n.reflet-dialog[data-closing=\"true\"]::backdrop {\n animation: reflet-fade-out 150ms ease-out forwards;\n}\n\n@media (max-width: 640px) {\n .reflet-dialog {\n top: auto;\n left: 0;\n right: 0;\n bottom: 0;\n transform: none;\n width: 100%;\n max-width: 100%;\n border-radius: var(--reflet-radius) var(--reflet-radius) 0 0;\n max-height: 90dvh;\n padding-bottom: env(safe-area-inset-bottom);\n animation: reflet-slide-up 300ms var(--reflet-ease);\n }\n\n .reflet-dialog[data-closing=\"true\"] {\n animation: reflet-slide-down 200ms ease-out forwards;\n }\n}\n\n.reflet-header {\n display: flex;\n align-items: center;\n justify-content: space-between;\n padding: 20px 24px 0;\n}\n\n.reflet-title {\n font-size: 18px;\n font-weight: 600;\n margin: 0;\n color: var(--reflet-text);\n line-height: 1.3;\n}\n\n.reflet-close {\n display: flex;\n align-items: center;\n justify-content: center;\n width: 40px;\n height: 40px;\n border: none;\n background: transparent;\n border-radius: 8px;\n color: var(--reflet-text-secondary);\n cursor: pointer;\n padding: 0;\n flex-shrink: 0;\n transition: background 150ms, color 150ms, transform 150ms var(--reflet-ease);\n}\n\n.reflet-close:hover {\n background: var(--reflet-bg-secondary);\n color: var(--reflet-text);\n}\n\n.reflet-close svg {\n width: 18px;\n height: 18px;\n}\n\n.reflet-form {\n padding: 20px 24px 24px;\n display: flex;\n flex-direction: column;\n gap: 16px;\n}\n\n.reflet-field {\n display: flex;\n flex-direction: column;\n gap: 6px;\n}\n\n.reflet-label {\n font-size: 13px;\n font-weight: 500;\n color: var(--reflet-text-secondary);\n}\n\n.reflet-input,\n.reflet-textarea {\n width: 100%;\n padding: 10px 12px;\n border: 1px solid var(--reflet-border);\n border-radius: var(--reflet-radius-sm);\n background: var(--reflet-bg);\n color: var(--reflet-text);\n font-family: var(--reflet-font);\n font-size: 14px;\n line-height: 1.5;\n outline: none;\n transition: border-color 150ms, box-shadow 150ms;\n box-sizing: border-box;\n}\n\n.reflet-input::placeholder,\n.reflet-textarea::placeholder {\n color: var(--reflet-text-tertiary);\n}\n\n.reflet-input:focus,\n.reflet-textarea:focus {\n border-color: var(--reflet-primary);\n box-shadow: 0 0 0 3px color-mix(in srgb, var(--reflet-primary) 15%, transparent);\n}\n\n.reflet-textarea {\n resize: vertical;\n min-height: 100px;\n}\n\n[data-reflet-feedback] :focus-visible {\n outline: 2px solid var(--reflet-primary);\n outline-offset: 2px;\n}\n\n[data-reflet-feedback] button:active:not(:disabled) {\n transform: scale(0.97);\n}\n\n@media (pointer: coarse), (max-width: 640px) {\n .reflet-input,\n .reflet-textarea {\n font-size: 16px;\n }\n}\n${getFeedbackChromeCSS()}\n@media (prefers-reduced-motion: reduce) {\n [data-reflet-feedback] *,\n [data-reflet-feedback] *::before,\n [data-reflet-feedback] *::after,\n .reflet-dialog,\n .reflet-dialog::backdrop {\n animation-duration: 1ms !important;\n animation-iteration-count: 1 !important;\n transition-duration: 1ms !important;\n }\n\n [data-reflet-feedback] button:active:not(:disabled) {\n transform: none;\n }\n}\n`;\n}\n","import {\n type FormEvent,\n type RefObject,\n useContext,\n useEffect,\n useRef,\n useState,\n} from \"react\";\nimport { Reflet } from \"./client\";\nimport { RefletContext } from \"./react-context\";\nimport {\n AUTO_CLOSE_DELAY,\n DEFAULT_LABELS,\n type FeedbackDialogProps,\n} from \"./react-feedback-dialog-types\";\nimport { injectFeedbackStyles } from \"./react-feedback-styles\";\n\nconst CLOSE_ANIMATION_MS = 200;\n\nfunction openDialog(dialog: HTMLDialogElement) {\n if (typeof dialog.showModal === \"function\") {\n dialog.showModal();\n return;\n }\n dialog.open = true;\n}\n\nfunction closeDialog(dialog: HTMLDialogElement) {\n if (typeof dialog.close === \"function\") {\n dialog.close();\n return;\n }\n dialog.open = false;\n}\n\nfunction useModalDialog(\n open: boolean,\n dialogRef: RefObject<HTMLDialogElement | null>,\n titleInputRef: RefObject<HTMLInputElement | null>\n) {\n useEffect(() => {\n const dialog = dialogRef.current;\n if (!(open && dialog) || dialog.open) {\n return;\n }\n openDialog(dialog);\n titleInputRef.current?.focus();\n return () => closeDialog(dialog);\n }, [open, dialogRef, titleInputRef]);\n}\n\nfunction useBackdropDismiss(\n open: boolean,\n dialogRef: RefObject<HTMLDialogElement | null>,\n onDismiss: () => void\n) {\n useEffect(() => {\n const dialog = dialogRef.current;\n if (!(open && dialog)) {\n return;\n }\n const dismiss = (event: MouseEvent) => {\n if (event.target === dialog) {\n onDismiss();\n }\n };\n dialog.addEventListener(\"click\", dismiss);\n return () => dialog.removeEventListener(\"click\", dismiss);\n }, [open, dialogRef, onDismiss]);\n}\n\nfunction useScrollLock(open: boolean) {\n useEffect(() => {\n if (!open) {\n return;\n }\n const root = document.documentElement;\n const previousOverflow = root.style.overflow;\n const previousGutter = root.style.getPropertyValue(\"scrollbar-gutter\");\n root.style.setProperty(\"scrollbar-gutter\", \"stable\");\n root.style.overflow = \"hidden\";\n return () => {\n root.style.overflow = previousOverflow;\n if (previousGutter) {\n root.style.setProperty(\"scrollbar-gutter\", previousGutter);\n } else {\n root.style.removeProperty(\"scrollbar-gutter\");\n }\n };\n }, [open]);\n}\n\nfunction usePrimaryColor(\n primaryColor: string | undefined,\n dialogRef: RefObject<HTMLDialogElement | null>\n) {\n useEffect(() => {\n injectFeedbackStyles();\n }, []);\n\n useEffect(() => {\n if (!(primaryColor && dialogRef.current)) {\n return;\n }\n const host = dialogRef.current.closest(\"[data-reflet-feedback]\");\n if (host instanceof HTMLElement) {\n host.style.setProperty(\"--reflet-primary\", primaryColor);\n }\n }, [primaryColor, dialogRef]);\n}\n\nexport function useFeedbackDialog({\n open,\n onOpenChange,\n publicKey: publicKeyProp,\n baseUrl,\n user: userProp,\n userToken: userTokenProp,\n primaryColor,\n labels: labelsProp,\n onSubmit,\n onOpen,\n onClose,\n}: Omit<FeedbackDialogProps, \"theme\">) {\n const context = useContext(RefletContext);\n const publicKey = publicKeyProp ?? context?.publicKey;\n const user = userProp ?? context?.user;\n const userToken = userTokenProp ?? context?.userToken;\n\n const labels = { ...DEFAULT_LABELS, ...labelsProp };\n\n const [title, setTitle] = useState(\"\");\n const [description, setDescription] = useState(\"\");\n const [email, setEmail] = useState(\"\");\n const [honeypot, setHoneypot] = useState(\"\");\n const [isSubmitting, setIsSubmitting] = useState(false);\n const [isSuccess, setIsSuccess] = useState(false);\n const [error, setError] = useState<string | null>(null);\n const [isClosing, setIsClosing] = useState(false);\n\n const titleInputRef = useRef<HTMLInputElement>(null);\n const dialogRef = useRef<HTMLDialogElement>(null);\n\n const isAnonymous = !(user || userToken);\n\n usePrimaryColor(primaryColor, dialogRef);\n useModalDialog(open, dialogRef, titleInputRef);\n useScrollLock(open);\n\n useEffect(() => {\n if (open) {\n onOpen?.();\n }\n }, [open, onOpen]);\n\n const resetForm = () => {\n setTitle(\"\");\n setDescription(\"\");\n setEmail(\"\");\n setHoneypot(\"\");\n setError(null);\n setIsSuccess(false);\n setIsSubmitting(false);\n };\n\n const handleClose = () => {\n setIsClosing(true);\n setTimeout(() => {\n setIsClosing(false);\n onOpenChange(false);\n onClose?.();\n resetForm();\n }, CLOSE_ANIMATION_MS);\n };\n\n useBackdropDismiss(open, dialogRef, handleClose);\n\n const buildDescription = () => {\n const body = description.trim() || \"No additional details provided.\";\n const contact = isAnonymous && email ? `\\n\\n---\\nContact: ${email}` : \"\";\n return `${body}${contact}`;\n };\n\n const handleSubmit = async (event: FormEvent) => {\n event.preventDefault();\n\n if (honeypot) {\n setIsSuccess(true);\n return;\n }\n\n if (!publicKey) {\n setError(\n \"Missing publicKey. Provide it as a prop or via RefletProvider.\"\n );\n return;\n }\n\n if (!title.trim()) {\n setError(labels.required);\n return;\n }\n\n setIsSubmitting(true);\n setError(null);\n\n try {\n const client = new Reflet({ baseUrl, publicKey, user, userToken });\n const result = await client.create({\n description: buildDescription(),\n title: title.trim(),\n });\n\n setIsSuccess(true);\n onSubmit?.(result);\n setTimeout(handleClose, AUTO_CLOSE_DELAY);\n } catch (err) {\n setError(\n err instanceof Error\n ? err.message\n : \"Something went wrong. Please try again.\"\n );\n } finally {\n setIsSubmitting(false);\n }\n };\n\n return {\n description,\n dialogRef,\n email,\n error,\n handleClose,\n handleSubmit,\n honeypot,\n isAnonymous,\n isClosing,\n isSubmitting,\n isSuccess,\n labels,\n setDescription,\n setEmail,\n setError,\n setHoneypot,\n setTitle,\n title,\n titleInputRef,\n };\n}\n","import { useFeedbackDialog } from \"./react-feedback-dialog-hook\";\nimport type { FeedbackDialogProps } from \"./react-feedback-dialog-types\";\n\nexport type {\n FeedbackDialogLabels,\n FeedbackDialogProps,\n} from \"./react-feedback-dialog-types\";\n\nexport function FeedbackDialog({\n open,\n onOpenChange,\n publicKey,\n baseUrl,\n user,\n userToken,\n theme = \"auto\",\n primaryColor,\n labels: labelsProp,\n onSubmit,\n onOpen,\n onClose,\n}: FeedbackDialogProps) {\n const {\n labels,\n title,\n setTitle,\n description,\n setDescription,\n email,\n setEmail,\n honeypot,\n setHoneypot,\n isSubmitting,\n isSuccess,\n error,\n setError,\n isClosing,\n isAnonymous,\n titleInputRef,\n dialogRef,\n handleClose,\n handleSubmit,\n } = useFeedbackDialog({\n baseUrl,\n labels: labelsProp,\n onClose,\n onOpen,\n onOpenChange,\n onSubmit,\n open,\n primaryColor,\n publicKey,\n user,\n userToken,\n });\n\n if (!open) {\n return null;\n }\n\n return (\n <div data-reflet-feedback=\"\" data-theme={theme}>\n <dialog\n aria-label={labels.title}\n className=\"reflet-dialog\"\n data-closing={isClosing ? \"true\" : undefined}\n onCancel={(event) => {\n event.preventDefault();\n handleClose();\n }}\n ref={dialogRef}\n >\n {isSuccess ? (\n <div className=\"reflet-success\">\n <div className=\"reflet-success-icon\">\n <svg\n aria-hidden=\"true\"\n fill=\"none\"\n stroke=\"currentColor\"\n strokeLinecap=\"round\"\n strokeLinejoin=\"round\"\n strokeWidth=\"2.5\"\n viewBox=\"0 0 24 24\"\n >\n <path d=\"M5 13l4 4L19 7\" />\n </svg>\n </div>\n <h2 className=\"reflet-success-title\">{labels.successTitle}</h2>\n <p className=\"reflet-success-text\">{labels.successMessage}</p>\n </div>\n ) : (\n <>\n <div className=\"reflet-header\">\n <h2 className=\"reflet-title\">{labels.title}</h2>\n <button\n aria-label={labels.close}\n className=\"reflet-close\"\n onClick={handleClose}\n type=\"button\"\n >\n <svg\n aria-hidden=\"true\"\n fill=\"none\"\n stroke=\"currentColor\"\n strokeLinecap=\"round\"\n strokeLinejoin=\"round\"\n strokeWidth=\"2\"\n viewBox=\"0 0 24 24\"\n >\n <line x1=\"18\" x2=\"6\" y1=\"6\" y2=\"18\" />\n <line x1=\"6\" x2=\"18\" y1=\"6\" y2=\"18\" />\n </svg>\n </button>\n </div>\n\n <form className=\"reflet-form\" onSubmit={handleSubmit}>\n <div className=\"reflet-field\">\n <input\n aria-label=\"Feedback title\"\n autoComplete=\"off\"\n className=\"reflet-input\"\n maxLength={100}\n onChange={(e) => {\n setTitle(e.target.value);\n if (error) {\n setError(null);\n }\n }}\n placeholder={labels.titlePlaceholder}\n ref={titleInputRef}\n required\n type=\"text\"\n value={title}\n />\n </div>\n\n <div className=\"reflet-field\">\n <textarea\n aria-label=\"Feedback description\"\n className=\"reflet-textarea\"\n maxLength={2000}\n onChange={(e) => setDescription(e.target.value)}\n placeholder={labels.descriptionPlaceholder}\n rows={3}\n value={description}\n />\n </div>\n\n {isAnonymous && (\n <div className=\"reflet-field\">\n <label className=\"reflet-label\" htmlFor=\"reflet-email\">\n {labels.emailLabel}\n </label>\n <input\n autoComplete=\"email\"\n className=\"reflet-input\"\n id=\"reflet-email\"\n onChange={(e) => setEmail(e.target.value)}\n placeholder={labels.emailPlaceholder}\n type=\"email\"\n value={email}\n />\n </div>\n )}\n\n <div aria-hidden=\"true\" className=\"reflet-hp\">\n <input\n autoComplete=\"off\"\n name=\"website\"\n onChange={(e) => setHoneypot(e.target.value)}\n tabIndex={-1}\n type=\"text\"\n value={honeypot}\n />\n </div>\n\n {error && <p className=\"reflet-error-msg\">{error}</p>}\n\n <div className=\"reflet-footer\">\n <button\n className=\"reflet-btn reflet-btn-secondary\"\n onClick={handleClose}\n type=\"button\"\n >\n {labels.cancel}\n </button>\n <button\n className=\"reflet-btn reflet-btn-primary\"\n disabled={isSubmitting || !title.trim()}\n type=\"submit\"\n >\n {isSubmitting ? (\n <span className=\"reflet-spinner\" />\n ) : (\n labels.submit\n )}\n </button>\n </div>\n </form>\n\n <div className=\"reflet-powered\">\n Powered by{\" \"}\n <a\n href=\"https://reflet.app\"\n rel=\"noopener noreferrer\"\n target=\"_blank\"\n >\n Reflet\n </a>\n </div>\n </>\n )}\n </dialog>\n </div>\n );\n}\n","import {\n cloneElement,\n isValidElement,\n type ReactElement,\n type ReactNode,\n useCallback,\n useState,\n} from \"react\";\nimport {\n FeedbackDialog,\n type FeedbackDialogLabels,\n} from \"./react-feedback-dialog\";\nimport { injectFeedbackStyles } from \"./react-feedback-styles\";\nimport type { CreateFeedbackResponse, RefletUser } from \"./types\";\n\n// ============================================\n// Types\n// ============================================\n\nexport interface FeedbackButtonProps {\n /**\n * Render as child element instead of the default button.\n * When true, the first child element receives the onClick handler.\n */\n asChild?: boolean;\n /** API base URL override */\n baseUrl?: string;\n /** Custom trigger content or element (used with asChild) */\n children?: ReactNode;\n /** Custom CSS class for the default trigger button */\n className?: string;\n /** Custom labels / i18n */\n labels?: FeedbackDialogLabels & { trigger?: string };\n /** Called when dialog closes */\n onClose?: () => void;\n /** Called when dialog opens */\n onOpen?: () => void;\n /** Called after successful submission */\n onSubmit?: (result: CreateFeedbackResponse) => void;\n /** Primary brand color (CSS value) */\n primaryColor?: string;\n /** Public API key (falls back to RefletProvider context) */\n publicKey?: string;\n /** Color theme */\n theme?: \"light\" | \"dark\" | \"auto\";\n /** User identification (falls back to RefletProvider context) */\n user?: RefletUser;\n /** Pre-signed user token */\n userToken?: string;\n}\n\n// ============================================\n// Feedback Icon SVG\n// ============================================\n\nfunction FeedbackIcon() {\n return (\n <svg\n aria-hidden=\"true\"\n fill=\"none\"\n height=\"16\"\n stroke=\"currentColor\"\n strokeLinecap=\"round\"\n strokeLinejoin=\"round\"\n strokeWidth=\"2\"\n viewBox=\"0 0 24 24\"\n width=\"16\"\n >\n <path d=\"M21 15a2 2 0 0 1-2 2H7l-4 4V5a2 2 0 0 1 2-2h14a2 2 0 0 1 2 2z\" />\n </svg>\n );\n}\n\n// ============================================\n// Component\n// ============================================\n\nexport function FeedbackButton({\n publicKey,\n baseUrl,\n user,\n userToken,\n theme = \"auto\",\n primaryColor,\n labels,\n onSubmit,\n onOpen,\n onClose,\n className,\n asChild = false,\n children,\n}: FeedbackButtonProps) {\n const [open, setOpen] = useState(false);\n\n // Inject styles so the trigger button is styled\n useState(() => {\n injectFeedbackStyles();\n });\n\n const handleClick = useCallback(() => {\n setOpen(true);\n }, []);\n\n // Render trigger\n let trigger: ReactNode;\n\n if (asChild && isValidElement(children)) {\n trigger = cloneElement(children as ReactElement<{ onClick?: () => void }>, {\n onClick: handleClick,\n });\n } else {\n const triggerLabel = labels?.trigger ?? \"Feedback\";\n trigger = (\n <div data-reflet-feedback=\"\" data-theme={theme}>\n <button\n aria-label={triggerLabel}\n className={className ?? \"reflet-trigger\"}\n onClick={handleClick}\n style={\n primaryColor\n ? ({\n \"--reflet-primary\": primaryColor,\n \"--reflet-primary-hover\": primaryColor,\n } as React.CSSProperties)\n : undefined\n }\n type=\"button\"\n >\n <FeedbackIcon />\n {triggerLabel}\n </button>\n </div>\n );\n }\n\n return (\n <>\n {trigger}\n <FeedbackDialog\n baseUrl={baseUrl}\n labels={labels}\n onClose={onClose}\n onOpen={onOpen}\n onOpenChange={setOpen}\n onSubmit={onSubmit}\n open={open}\n primaryColor={primaryColor}\n publicKey={publicKey}\n theme={theme}\n user={user}\n userToken={userToken}\n />\n </>\n );\n}\n","import { useCallback, useState } from \"react\";\nimport { useRefletClient } from \"./react-context\";\nimport type { UseMutationResult } from \"./react-hooks-types\";\nimport type { AddCommentParams, CreateFeedbackParams } from \"./types\";\n\n// ============================================\n// Generic mutation hook — single source of truth\n// ============================================\n\nfunction useRefletMutation<TData, TVariables>(\n mutateFn: (variables: TVariables) => Promise<TData>\n): UseMutationResult<TData, TVariables> {\n const [isLoading, setIsLoading] = useState(false);\n const [error, setError] = useState<Error | null>(null);\n const [data, setData] = useState<TData | undefined>();\n\n const mutate = useCallback(\n async (variables: TVariables) => {\n setIsLoading(true);\n setError(null);\n try {\n const result = await mutateFn(variables);\n setData(result);\n return result;\n } catch (err) {\n const wrapped =\n err instanceof Error ? err : new Error(\"Request failed\");\n setError(wrapped);\n throw wrapped;\n } finally {\n setIsLoading(false);\n }\n },\n [mutateFn]\n );\n\n const reset = useCallback(() => {\n setData(undefined);\n setError(null);\n }, []);\n\n return { data, error, isLoading, mutate, reset };\n}\n\n// ============================================\n// Create Feedback Mutation Hook\n// ============================================\n\n/**\n * Hook to create new feedback\n *\n * @example\n * ```tsx\n * const { mutate: createFeedback, isLoading } = useCreateFeedback();\n *\n * const handleSubmit = async (data) => {\n * const result = await createFeedback(data);\n * console.log('Created:', result.feedbackId);\n * };\n * ```\n */\nexport function useCreateFeedback(): UseMutationResult<\n { feedbackId: string; isApproved: boolean },\n CreateFeedbackParams\n> {\n const client = useRefletClient();\n const mutateFn = useCallback(\n (params: CreateFeedbackParams) => client.create(params),\n [client]\n );\n return useRefletMutation(mutateFn);\n}\n\n// ============================================\n// Vote Mutation Hook\n// ============================================\n\n/**\n * Hook to vote on feedback\n *\n * @example\n * ```tsx\n * const { mutate: vote } = useVote();\n *\n * <button onClick={() => vote({ feedbackId: 'xxx' })}>\n * Vote\n * </button>\n * ```\n */\nexport function useVote(): UseMutationResult<\n { voted: boolean; voteCount: number },\n { feedbackId: string; type?: \"upvote\" | \"downvote\" }\n> {\n const client = useRefletClient();\n const mutateFn = useCallback(\n ({\n feedbackId,\n type = \"upvote\",\n }: {\n feedbackId: string;\n type?: \"upvote\" | \"downvote\";\n }) => client.vote(feedbackId, type),\n [client]\n );\n return useRefletMutation(mutateFn);\n}\n\n// ============================================\n// Comment Mutation Hook\n// ============================================\n\n/**\n * Hook to add a comment\n */\nexport function useAddComment(): UseMutationResult<\n { commentId: string },\n AddCommentParams\n> {\n const client = useRefletClient();\n const mutateFn = useCallback(\n (params: AddCommentParams) => client.comment(params),\n [client]\n );\n return useRefletMutation(mutateFn);\n}\n\n// ============================================\n// Subscribe Mutation Hook\n// ============================================\n\n/**\n * Hook to subscribe/unsubscribe to feedback\n */\nexport function useSubscription(): {\n subscribe: (feedbackId: string) => Promise<{ subscribed: boolean }>;\n unsubscribe: (feedbackId: string) => Promise<{ unsubscribed: boolean }>;\n isLoading: boolean;\n error: Error | null;\n} {\n const client = useRefletClient();\n const [isLoading, setIsLoading] = useState(false);\n const [error, setError] = useState<Error | null>(null);\n\n const subscribe = useCallback(\n async (feedbackId: string) => {\n setIsLoading(true);\n setError(null);\n try {\n return await client.subscribe(feedbackId);\n } catch (err) {\n const wrapped =\n err instanceof Error ? err : new Error(\"Failed to subscribe\");\n setError(wrapped);\n throw wrapped;\n } finally {\n setIsLoading(false);\n }\n },\n [client]\n );\n\n const unsubscribe = useCallback(\n async (feedbackId: string) => {\n setIsLoading(true);\n setError(null);\n try {\n return await client.unsubscribe(feedbackId);\n } catch (err) {\n const wrapped =\n err instanceof Error ? err : new Error(\"Failed to unsubscribe\");\n setError(wrapped);\n throw wrapped;\n } finally {\n setIsLoading(false);\n }\n },\n [client]\n );\n\n return { error, isLoading, subscribe, unsubscribe };\n}\n","import { useCallback, useEffect, useMemo, useState } from \"react\";\nimport { useRefletClient } from \"./react-context\";\nimport type { UseQueryResult } from \"./react-hooks-types\";\nimport type {\n ChangelogEntry,\n Comment,\n FeedbackDetail,\n FeedbackItem,\n FeedbackListParams,\n OrganizationConfig,\n Roadmap,\n} from \"./types\";\n\n// ============================================\n// Generic query hook — single source of truth\n// ============================================\n\nfunction useRefletQuery<T>(\n fetchFn: () => Promise<T>,\n enabled = true\n): UseQueryResult<T> {\n const [data, setData] = useState<T | undefined>();\n const [isLoading, setIsLoading] = useState(enabled);\n const [error, setError] = useState<Error | null>(null);\n\n const refetch = useCallback(async () => {\n setIsLoading(true);\n setError(null);\n try {\n const result = await fetchFn();\n setData(result);\n } catch (err) {\n setError(err instanceof Error ? err : new Error(\"Request failed\"));\n } finally {\n setIsLoading(false);\n }\n }, [fetchFn]);\n\n useEffect(() => {\n if (enabled) {\n refetch();\n }\n }, [refetch, enabled]);\n\n return { data, error, isLoading, refetch };\n}\n\n// ============================================\n// Organization Config Hook\n// ============================================\n\nexport function useOrganizationConfig(): UseQueryResult<OrganizationConfig> {\n const client = useRefletClient();\n const fetchFn = useCallback(() => client.getConfig(), [client]);\n return useRefletQuery(fetchFn);\n}\n\n// ============================================\n// Feedback List Hook\n// ============================================\n\nexport interface UseFeedbackListOptions extends FeedbackListParams {\n enabled?: boolean;\n}\n\nexport function useFeedbackList(\n options: UseFeedbackListOptions = {}\n): UseQueryResult<{ items: FeedbackItem[]; total: number; hasMore: boolean }> {\n const client = useRefletClient();\n const {\n enabled = true,\n statusId,\n status,\n search,\n sortBy,\n limit,\n offset,\n } = options;\n\n const params = useMemo(\n () => ({ limit, offset, search, sortBy, status, statusId }),\n [statusId, status, search, sortBy, limit, offset]\n );\n\n const fetchFn = useCallback(() => client.list(params), [client, params]);\n return useRefletQuery(fetchFn, enabled);\n}\n\n// ============================================\n// Single Feedback Hook\n// ============================================\n\nexport function useFeedback(\n feedbackId: string | undefined\n): UseQueryResult<FeedbackDetail> {\n const client = useRefletClient();\n\n const fetchFn = useCallback(() => {\n if (!feedbackId) {\n return Promise.resolve(undefined as unknown as FeedbackDetail);\n }\n return client.get(feedbackId);\n }, [client, feedbackId]);\n\n return useRefletQuery(fetchFn, !!feedbackId);\n}\n\n// ============================================\n// Comments Hook\n// ============================================\n\nexport function useComments(\n feedbackId: string | undefined,\n sortBy: \"newest\" | \"oldest\" = \"oldest\"\n): UseQueryResult<Comment[]> {\n const client = useRefletClient();\n\n const fetchFn = useCallback(() => {\n if (!feedbackId) {\n return Promise.resolve(undefined as unknown as Comment[]);\n }\n return client.getComments(feedbackId, sortBy);\n }, [client, feedbackId, sortBy]);\n\n return useRefletQuery(fetchFn, !!feedbackId);\n}\n\n// ============================================\n// Roadmap Hook\n// ============================================\n\nexport function useRoadmap(): UseQueryResult<Roadmap> {\n const client = useRefletClient();\n const fetchFn = useCallback(() => client.getRoadmap(), [client]);\n return useRefletQuery(fetchFn);\n}\n\n// ============================================\n// Changelog Hook\n// ============================================\n\nexport function useChangelog(limit?: number): UseQueryResult<ChangelogEntry[]> {\n const client = useRefletClient();\n const fetchFn = useCallback(\n () => client.getChangelog(limit),\n [client, limit]\n );\n return useRefletQuery(fetchFn);\n}\n\n// ============================================\n// Unread Changelog Count Hook\n// ============================================\n\nconst CHANGELOG_STORAGE_KEY_PREFIX = \"reflet_changelog_seen_\";\n\nexport function useUnreadChangelogCount(publicKey: string): {\n unreadCount: number;\n markAsRead: () => void;\n} {\n const { data: entries } = useChangelog();\n const [unreadCount, setUnreadCount] = useState(0);\n\n const storageKey = `${CHANGELOG_STORAGE_KEY_PREFIX}${publicKey}`;\n\n useEffect(() => {\n if (!entries || entries.length === 0) {\n setUnreadCount(0);\n return;\n }\n\n let lastSeen = 0;\n try {\n const stored = localStorage.getItem(storageKey);\n lastSeen = stored ? Number(stored) : 0;\n } catch {\n // localStorage unavailable\n }\n\n let count = 0;\n for (const entry of entries) {\n if (entry.publishedAt && entry.publishedAt > lastSeen) {\n count++;\n }\n }\n setUnreadCount(count);\n }, [entries, storageKey]);\n\n const markAsRead = useCallback(() => {\n if (!entries || entries.length === 0) {\n return;\n }\n\n let latestTimestamp = 0;\n for (const entry of entries) {\n if (entry.publishedAt && entry.publishedAt > latestTimestamp) {\n latestTimestamp = entry.publishedAt;\n }\n }\n\n if (latestTimestamp > 0) {\n try {\n localStorage.setItem(storageKey, String(latestTimestamp));\n } catch {\n // localStorage unavailable\n }\n setUnreadCount(0);\n }\n }, [entries, storageKey]);\n\n return { markAsRead, unreadCount };\n}\n"],"mappings":"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"}
|
package/dist/server.d.ts
CHANGED
|
@@ -13,7 +13,7 @@
|
|
|
13
13
|
* );
|
|
14
14
|
* ```
|
|
15
15
|
*/
|
|
16
|
-
interface SignUserOptions {
|
|
16
|
+
export interface SignUserOptions {
|
|
17
17
|
/** URL to user's avatar image */
|
|
18
18
|
avatar?: string;
|
|
19
19
|
/** User's email address */
|
|
@@ -25,7 +25,7 @@ interface SignUserOptions {
|
|
|
25
25
|
/** User's display name */
|
|
26
26
|
name?: string;
|
|
27
27
|
}
|
|
28
|
-
interface SignedUserToken {
|
|
28
|
+
export interface SignedUserToken {
|
|
29
29
|
/** Token expiration timestamp (ms) */
|
|
30
30
|
expiresAt: number;
|
|
31
31
|
/** The signed JWT token */
|
|
@@ -35,12 +35,12 @@ interface SignedUserToken {
|
|
|
35
35
|
* Sign a user token for secure client-side identification
|
|
36
36
|
* Uses HMAC-SHA256 via Web Crypto API (works in all runtimes)
|
|
37
37
|
*/
|
|
38
|
-
declare function signUser(user: SignUserOptions, secretKey: string, expiresInSeconds?: number): Promise<SignedUserToken>;
|
|
38
|
+
export declare function signUser(user: SignUserOptions, secretKey: string, expiresInSeconds?: number): Promise<SignedUserToken>;
|
|
39
39
|
/**
|
|
40
40
|
* Verify a user token
|
|
41
41
|
* Returns the user data if valid, null otherwise
|
|
42
42
|
*/
|
|
43
|
-
declare function verifyUser(token: string, secretKey: string): Promise<SignUserOptions | null>;
|
|
43
|
+
export declare function verifyUser(token: string, secretKey: string): Promise<SignUserOptions | null>;
|
|
44
44
|
//#endregion
|
|
45
|
-
export {
|
|
45
|
+
export type { SignUserOptions as RefletServerUser };
|
|
46
46
|
//# sourceMappingURL=server.d.ts.map
|
package/dist/server.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"server.d.ts","names":[],"sources":["../src/server.ts"],"mappings":";;;;;;;;;;;;;;;
|
|
1
|
+
{"version":3,"file":"server.d.ts","names":[],"sources":["../src/server.ts"],"mappings":";;;;;;;;;;;;;;;iBAsBiB;;EAEf;;EAEA;;EAEA;;EAEA,WAAW;;EAEX;;iBAGe;;EAEf;;EAEA;;;;;;wBAOoB,SACpB,MAAM,iBACN,mBACA,4BACC,QAAQ;;;;;wBA2CW,WACpB,eACA,oBACC,QAAQ"}
|
|
@@ -108,6 +108,8 @@ interface ElementRect {
|
|
|
108
108
|
y: number;
|
|
109
109
|
}
|
|
110
110
|
interface ElementSelection {
|
|
111
|
+
/** What the reporter wrote about this element while picking it. */
|
|
112
|
+
comment?: string;
|
|
111
113
|
/** React component names owning the element, innermost first. */
|
|
112
114
|
componentStack: string[];
|
|
113
115
|
/** Truncated, redacted outerHTML of the selected element. */
|
|
@@ -277,4 +279,4 @@ declare class RefletNotFoundError extends RefletError {
|
|
|
277
279
|
}
|
|
278
280
|
//#endregion
|
|
279
281
|
export { SubscribeResponse as A, RefletNotFoundError as C, RoadmapItem as D, Roadmap as E, VoteResponse as M, RoadmapLane as O, RefletError as S, RefletValidationError as T, OrganizationConfig as _, CommentReply as a, RefletAuthError as b, ElementSelection as c, FeedbackDetail as d, FeedbackItem as f, FeedbackTag as g, FeedbackStatus as h, Comment as i, UnsubscribeResponse as j, SaveScreenshotParams as k, FeedbackAuthor as l, FeedbackListResponse as m, AddCommentResponse as n, CreateFeedbackParams as o, FeedbackListParams as p, ChangelogEntry as r, CreateFeedbackResponse as s, AddCommentParams as t, FeedbackContext as u, OrganizationSettings as v, RefletUser as w, RefletConfig as x, OrganizationStatus as y };
|
|
280
|
-
//# sourceMappingURL=types-
|
|
282
|
+
//# sourceMappingURL=types-Cak4ZkSy.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"types-Cak4ZkSy.d.ts","names":[],"sources":["../src/types.ts"],"mappings":";;;;UAQiB;;EAEf;;EAEA;;EAEA,OAAO;;EAEP;;UAGe;;EAEf;;EAEA;;EAEA;;EAEA,WAAW;;EAEX;;UAOe;EACf;EACA;EACA;EACA;EACA;EACA;EACA,WAAW;EACX;EACA,UAAU;;UAGK;EACf;EACA,gBAAgB;EAChB;;UAGe;EACf;EACA;EACA;EACA;EACA;;KAGU;UAYK;EACf,QAAQ;EACR;EACA;EACA;EACA;EACA;EACA;EACA;EACA;IACE;IACA;IACA;;EAEF,QAAQ;EACR,MAAM;EACN;EACA;EACA;;UAGe,uBAAuB;EACtC;;UAGe;EACf;EACA;EACA;;UAGe;EACf;EACA;EACA;EACA;;UAGe;EACf;EACA,OAAO;EACP;;UAGe;;EAEf;;EAEA;;EAEA;;EAEA;;EAEA,SAAS;;EAET;;UAGe;EACf;EACA;EACA;EACA;;UAGe;;EAEf;;EAEA;;EAEA;;EAEA;EACA,MAAM;;EAEN;EACA;;EAEA;;EAEA;;UAGe;EACf;EACA;EACA;;UAGe;EACf;EACA;EACA;EACA;EACA;EACA;EACA;IAAW;IAAgB;;;EAE3B;IAAW;IAAW;;EACtB;EACA;EACA;EACA;IAAa;IAA0B;IAAgB;;;;UAIxC,wBAAwB;EACvC,gBAAgB;EAChB,WAAW;EACX;EACA,YAAY;;UAGG;EACf,UAAU;EACV;EACA;;UAGe;EACf;EACA;EACA;EACA;EACA,SAAS;IAAQ;IAAW;;EAC5B;EACA;EAQA;EACA;EACA;;UAGe;EACf;EACA,cAAc;;EAEd;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;;UAGe;EACf;EACA;;UAGe;EACf;EACA;;UAOe;EACf,QAAQ;EACR;EACA;EACA;EACA;EACA,SAAS;EACT;;UAGe;EACf,QAAQ;EACR;EACA;EACA;EACA;EACA;;UAGe;EACf;EACA;EACA;;UAGe;EACf;;UAOe;EACf;EACA;;UAGe;EACf;EACA;;UAOe;EACf,OAAO;;UAGQ;EACf;EACA;EACA,OAAO;EACP;;UAGe;EACf;EACA,QAAQ;EACR;EACA;;UAOe;EACf;EACA;IAAY;IAAY;;EACxB;EACA;EACA;EACA;;cAOW,oBAAoB;WACtB;WACA;EAET,YAAY,iBAAiB,gBAAgB;;cAQlC,wBAAwB;EACnC,YAAY;;cAMD,8BAA8B;EACzC,YAAY;;cAMD,4BAA4B;EACvC,YAAY"}
|
package/package.json
CHANGED
|
@@ -1,18 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "reflet-sdk",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.4.0",
|
|
4
4
|
"description": "Official Reflet SDK - Collect user feedback, feature requests, and bug reports from your app",
|
|
5
|
-
"license": "MIT",
|
|
6
|
-
"author": "Reflet <hello@reflet.app>",
|
|
7
|
-
"homepage": "https://reflet.app",
|
|
8
|
-
"bugs": {
|
|
9
|
-
"url": "https://github.com/reflet-app/reflet/issues"
|
|
10
|
-
},
|
|
11
|
-
"repository": {
|
|
12
|
-
"type": "git",
|
|
13
|
-
"url": "git+https://github.com/reflet-app/reflet.git",
|
|
14
|
-
"directory": "packages/sdk"
|
|
15
|
-
},
|
|
16
5
|
"keywords": [
|
|
17
6
|
"feedback",
|
|
18
7
|
"feature-requests",
|
|
@@ -28,24 +17,35 @@
|
|
|
28
17
|
"roadmap",
|
|
29
18
|
"changelog"
|
|
30
19
|
],
|
|
31
|
-
"
|
|
20
|
+
"homepage": "https://reflet.app",
|
|
21
|
+
"bugs": {
|
|
22
|
+
"url": "https://github.com/reflet-app/reflet/issues"
|
|
23
|
+
},
|
|
24
|
+
"repository": {
|
|
25
|
+
"type": "git",
|
|
26
|
+
"url": "git+https://github.com/reflet-app/reflet.git",
|
|
27
|
+
"directory": "packages/sdk"
|
|
28
|
+
},
|
|
29
|
+
"license": "MIT",
|
|
30
|
+
"author": "Reflet <hello@reflet.app>",
|
|
32
31
|
"sideEffects": false,
|
|
32
|
+
"type": "module",
|
|
33
33
|
"exports": {
|
|
34
34
|
".": {
|
|
35
|
-
"
|
|
36
|
-
"
|
|
35
|
+
"types": "./dist/index.d.ts",
|
|
36
|
+
"import": "./dist/index.js"
|
|
37
37
|
},
|
|
38
38
|
"./react": {
|
|
39
|
-
"
|
|
40
|
-
"
|
|
39
|
+
"types": "./dist/react.d.ts",
|
|
40
|
+
"import": "./dist/react.js"
|
|
41
41
|
},
|
|
42
42
|
"./feedback": {
|
|
43
|
-
"
|
|
44
|
-
"
|
|
43
|
+
"types": "./dist/feedback.d.ts",
|
|
44
|
+
"import": "./dist/feedback.js"
|
|
45
45
|
},
|
|
46
46
|
"./server": {
|
|
47
|
-
"
|
|
48
|
-
"
|
|
47
|
+
"types": "./dist/server.d.ts",
|
|
48
|
+
"import": "./dist/server.js"
|
|
49
49
|
}
|
|
50
50
|
},
|
|
51
51
|
"main": "./dist/index.js",
|
|
@@ -58,15 +58,33 @@
|
|
|
58
58
|
],
|
|
59
59
|
"scripts": {
|
|
60
60
|
"build": "tsdown",
|
|
61
|
-
"dev": "tsdown --watch",
|
|
62
61
|
"check-types": "tsc --noEmit",
|
|
63
|
-
"
|
|
62
|
+
"dev": "tsdown --watch",
|
|
64
63
|
"lint": "cd ../.. && bun x ultracite check packages/sdk",
|
|
65
64
|
"prepublishOnly": "npm run build",
|
|
66
|
-
"
|
|
67
|
-
"
|
|
65
|
+
"release": "npm run build && npm publish",
|
|
66
|
+
"test:unit": "vitest run",
|
|
68
67
|
"version:major": "npm version major && npm run release",
|
|
69
|
-
"
|
|
68
|
+
"version:minor": "npm version minor && npm run release",
|
|
69
|
+
"version:patch": "npm version patch && npm run release"
|
|
70
|
+
},
|
|
71
|
+
"dependencies": {
|
|
72
|
+
"@base-ui/react": "^1.8.0",
|
|
73
|
+
"@zumer/snapdom": "^3.0.0"
|
|
74
|
+
},
|
|
75
|
+
"devDependencies": {
|
|
76
|
+
"@testing-library/dom": "^10.4.2",
|
|
77
|
+
"@testing-library/react": "^16.3.3",
|
|
78
|
+
"@testing-library/user-event": "^14.6.7",
|
|
79
|
+
"@types/react": "^19.3.0",
|
|
80
|
+
"@types/react-dom": "19.3.0",
|
|
81
|
+
"jsdom": "^30.1.0",
|
|
82
|
+
"react": "^19.3.0",
|
|
83
|
+
"react-dom": "^19.3.0",
|
|
84
|
+
"tsdown": "catalog:",
|
|
85
|
+
"typescript": "catalog:",
|
|
86
|
+
"vite": "catalog:",
|
|
87
|
+
"vitest": "catalog:"
|
|
70
88
|
},
|
|
71
89
|
"peerDependencies": {
|
|
72
90
|
"react": "^18.0.0 || ^19.0.0",
|
|
@@ -80,24 +98,6 @@
|
|
|
80
98
|
"optional": true
|
|
81
99
|
}
|
|
82
100
|
},
|
|
83
|
-
"dependencies": {
|
|
84
|
-
"@base-ui/react": "^1.8.0",
|
|
85
|
-
"@zumer/snapdom": "^2.23.1"
|
|
86
|
-
},
|
|
87
|
-
"devDependencies": {
|
|
88
|
-
"@testing-library/dom": "^10.4.1",
|
|
89
|
-
"@testing-library/react": "^16.3.2",
|
|
90
|
-
"@testing-library/user-event": "^14.6.1",
|
|
91
|
-
"@types/react": "^19.2.17",
|
|
92
|
-
"jsdom": "^30.0.1",
|
|
93
|
-
"react": "^19.2.8",
|
|
94
|
-
"react-dom": "^19.2.8",
|
|
95
|
-
"tsdown": "catalog:",
|
|
96
|
-
"typescript": "catalog:",
|
|
97
|
-
"vite": "catalog:",
|
|
98
|
-
"vitest": "catalog:",
|
|
99
|
-
"@types/react-dom": "19.2.3"
|
|
100
|
-
},
|
|
101
101
|
"engines": {
|
|
102
102
|
"node": ">=18.0.0"
|
|
103
103
|
},
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"react-context-DZw_HHjj.js","names":[],"sources":["../src/react-context.tsx"],"sourcesContent":["import {\n createContext,\n type ReactNode,\n useContext,\n useEffect,\n useMemo,\n useState,\n} from \"react\";\nimport { Reflet } from \"./client\";\nimport type { RefletConfig, RefletUser } from \"./types\";\n\n// ============================================\n// Context Types\n// ============================================\n\nexport interface RefletContextValue {\n baseUrl?: string;\n client: Reflet;\n isReady: boolean;\n publicKey: string;\n setUser: (user: RefletUser | undefined) => void;\n user: RefletUser | undefined;\n userToken: string | undefined;\n}\n\n// ============================================\n// Context\n// ============================================\n\nexport const RefletContext = createContext<RefletContextValue | null>(null);\n\n// ============================================\n// Provider\n// ============================================\n\nexport interface RefletProviderProps {\n /** API base URL (optional, defaults to Reflet production API) */\n baseUrl?: string;\n /** Children */\n children: ReactNode;\n /** Your organization's public API key */\n publicKey: string;\n /** Initial user identification */\n user?: RefletUser;\n /** Pre-signed user token (alternative to user) */\n userToken?: string;\n}\n\n/**\n * Provider component for Reflet SDK\n *\n * @example\n * ```tsx\n * import { RefletProvider } from 'reflet-sdk/react';\n *\n * function App() {\n * return (\n * <RefletProvider\n * publicKey=\"fb_pub_xxx\"\n * user={{ id: 'user_123', email: 'user@example.com', name: 'John' }}\n * >\n * <YourApp />\n * </RefletProvider>\n * );\n * }\n * ```\n */\nexport function RefletProvider({\n publicKey,\n baseUrl,\n user: initialUser,\n userToken,\n children,\n}: RefletProviderProps) {\n const [user, setUser] = useState<RefletUser | undefined>(initialUser);\n const [isReady, setIsReady] = useState(false);\n\n const client = useMemo(() => {\n const config: RefletConfig = {\n baseUrl,\n publicKey,\n user,\n userToken,\n };\n return new Reflet(config);\n }, [publicKey, baseUrl, user, userToken]);\n\n // Update client when user changes\n useEffect(() => {\n if (userToken) {\n client.setUserToken(userToken);\n } else {\n client.setUser(user);\n }\n }, [client, user, userToken]);\n\n // Mark as ready after mount\n useEffect(() => {\n setIsReady(true);\n }, []);\n\n const value = useMemo(\n () => ({\n baseUrl,\n client,\n isReady,\n publicKey,\n setUser,\n user,\n userToken,\n }),\n [client, publicKey, baseUrl, isReady, user, userToken]\n );\n\n return (\n <RefletContext.Provider value={value}>{children}</RefletContext.Provider>\n );\n}\n\n// ============================================\n// Hook to access context\n// ============================================\n\nexport function useRefletContext(): RefletContextValue {\n const context = useContext(RefletContext);\n if (!context) {\n throw new Error(\"useRefletContext must be used within a RefletProvider\");\n }\n return context;\n}\n\nexport function useRefletClient(): Reflet {\n const { client } = useRefletContext();\n return client;\n}\n"],"mappings":";;;;AA6BA,MAAa,gBAAgB,cAAyC,IAAI;;;;;;;;;;;;;;;;;;;;AAsC1E,SAAgB,eAAe,EAC7B,WACA,SACA,MAAM,aACN,WACA,YACsB;CACtB,MAAM,CAAC,MAAM,WAAW,SAAiC,WAAW;CACpE,MAAM,CAAC,SAAS,cAAc,SAAS,KAAK;CAE5C,MAAM,SAAS,cAAc;EAO3B,OAAO,IAAI,OAAO;GALhB;GACA;GACA;GACA;EAEqB,CAAC;CAC1B,GAAG;EAAC;EAAW;EAAS;EAAM;CAAS,CAAC;CAGxC,gBAAgB;EACd,IAAI,WACF,OAAO,aAAa,SAAS;OAE7B,OAAO,QAAQ,IAAI;CAEvB,GAAG;EAAC;EAAQ;EAAM;CAAS,CAAC;CAG5B,gBAAgB;EACd,WAAW,IAAI;CACjB,GAAG,CAAC,CAAC;CAEL,MAAM,QAAQ,eACL;EACL;EACA;EACA;EACA;EACA;EACA;EACA;CACF,IACA;EAAC;EAAQ;EAAW;EAAS;EAAS;EAAM;CAAS,CACvD;CAEA,OACE,oBAAC,cAAc,UAAf;EAA+B;EAAQ;CAAiC,CAAA;AAE5E;AAMA,SAAgB,mBAAuC;CACrD,MAAM,UAAU,WAAW,aAAa;CACxC,IAAI,CAAC,SACH,MAAM,IAAI,MAAM,uDAAuD;CAEzE,OAAO;AACT;AAEA,SAAgB,kBAA0B;CACxC,MAAM,EAAE,WAAW,iBAAiB;CACpC,OAAO;AACT"}
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"types-wANRMsGI.d.ts","names":[],"sources":["../src/types.ts"],"mappings":";;;;UAQiB;;EAEf;;EAEA;;EAEA,OAAO;;EAEP;;UAGe;;EAEf;;EAEA;;EAEA;;EAEA,WAAW;;EAEX;;UAOe;EACf;EACA;EACA;EACA;EACA;EACA;EACA,WAAW;EACX;EACA,UAAU;;UAGK;EACf;EACA,gBAAgB;EAChB;;UAGe;EACf;EACA;EACA;EACA;EACA;;KAGU;UAYK;EACf,QAAQ;EACR;EACA;EACA;EACA;EACA;EACA;EACA;EACA;IACE;IACA;IACA;;EAEF,QAAQ;EACR,MAAM;EACN;EACA;EACA;;UAGe,uBAAuB;EACtC;;UAGe;EACf;EACA;EACA;;UAGe;EACf;EACA;EACA;EACA;;UAGe;EACf;EACA,OAAO;EACP;;UAGe;;EAEf;;EAEA;;EAEA;;EAEA;;EAEA,SAAS;;EAET;;UAGe;EACf;EACA;EACA;EACA;;UAGe;;EAEf;;EAEA;;EAEA;EACA,MAAM;;EAEN;EACA;;EAEA;;EAEA;;UAGe;EACf;EACA;EACA;;UAGe;EACf;EACA;EACA;EACA;EACA;EACA;EACA;IAAW;IAAgB;;;EAE3B;IAAW;IAAW;;EACtB;EACA;EACA;EACA;IAAa;IAA0B;IAAgB;;;;UAIxC,wBAAwB;EACvC,gBAAgB;EAChB,WAAW;EACX;EACA,YAAY;;UAGG;EACf,UAAU;EACV;EACA;;UAGe;EACf;EACA;EACA;EACA;EACA,SAAS;IAAQ;IAAW;;EAC5B;EACA;EAQA;EACA;EACA;;UAGe;EACf;EACA,cAAc;;EAEd;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;;UAGe;EACf;EACA;;UAGe;EACf;EACA;;UAOe;EACf,QAAQ;EACR;EACA;EACA;EACA;EACA,SAAS;EACT;;UAGe;EACf,QAAQ;EACR;EACA;EACA;EACA;EACA;;UAGe;EACf;EACA;EACA;;UAGe;EACf;;UAOe;EACf;EACA;;UAGe;EACf;EACA;;UAOe;EACf,OAAO;;UAGQ;EACf;EACA;EACA,OAAO;EACP;;UAGe;EACf;EACA,QAAQ;EACR;EACA;;UAOe;EACf;EACA;IAAY;IAAY;;EACxB;EACA;EACA;EACA;;cAOW,oBAAoB;WACtB;WACA;EAET,YAAY,iBAAiB,gBAAgB;;cAQlC,wBAAwB;EACnC,YAAY;;cAMD,8BAA8B;EACzC,YAAY;;cAMD,4BAA4B;EACvC,YAAY"}
|