@perspective-ai/sdk-react 0.0.0-pr-21-20260224144030

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md ADDED
@@ -0,0 +1,339 @@
1
+ # @perspective-ai/sdk-react
2
+
3
+ React hooks and components for [Perspective AI](https://getperspective.ai).
4
+
5
+ > **Not using React?** Use [`@perspective-ai/sdk`](https://www.npmjs.com/package/@perspective-ai/sdk) for vanilla JavaScript.
6
+
7
+ ## Installation
8
+
9
+ ```bash
10
+ npm install @perspective-ai/sdk-react
11
+ ```
12
+
13
+ **Peer Dependencies:** React 18+ or 19+
14
+
15
+ ## Quick Start
16
+
17
+ ```tsx
18
+ import { usePopup } from "@perspective-ai/sdk-react";
19
+
20
+ function App() {
21
+ const { open } = usePopup({
22
+ researchId: "your-research-id",
23
+ onSubmit: () => console.log("Interview completed!"),
24
+ });
25
+
26
+ return <button onClick={open}>Give Feedback</button>;
27
+ }
28
+ ```
29
+
30
+ ## API Overview
31
+
32
+ | API | Type | Description |
33
+ | ---------------- | --------- | -------------------------------------- |
34
+ | `usePopup` | Hook | Open popup modal programmatically |
35
+ | `useSlider` | Hook | Open slider panel programmatically |
36
+ | `useAutoOpen` | Hook | Auto-trigger popup (timeout/exit) |
37
+ | `useFloatBubble` | Hook | Floating chat bubble lifecycle |
38
+ | `Widget` | Component | Inline embed in a container |
39
+ | `Fullpage` | Component | Full viewport takeover |
40
+ | `FloatBubble` | Component | Convenience wrapper for useFloatBubble |
41
+
42
+ **Mental Model:**
43
+
44
+ - **Hooks** for overlays (popup, slider, float bubble) - you control the trigger
45
+ - **Components** for embeds (widget, fullpage) - render inline DOM
46
+
47
+ ## Hooks
48
+
49
+ ### usePopup
50
+
51
+ Open a popup modal with your own trigger element.
52
+
53
+ ```tsx
54
+ import { usePopup } from "@perspective-ai/sdk-react";
55
+
56
+ function App() {
57
+ const { open, close, isOpen } = usePopup({
58
+ researchId: "your-research-id",
59
+ onSubmit: () => console.log("Done!"),
60
+ });
61
+
62
+ return (
63
+ <>
64
+ <button onClick={open}>Take Survey</button>
65
+ {isOpen && <span>Survey is open</span>}
66
+ </>
67
+ );
68
+ }
69
+ ```
70
+
71
+ **Programmatic trigger:**
72
+
73
+ ```tsx
74
+ const { open } = usePopup({ researchId: "xxx" });
75
+
76
+ useEffect(() => {
77
+ if (userCompletedCheckout) {
78
+ open();
79
+ }
80
+ }, [userCompletedCheckout, open]);
81
+ ```
82
+
83
+ **Controlled mode:**
84
+
85
+ ```tsx
86
+ const [isOpen, setIsOpen] = useState(false);
87
+
88
+ const popup = usePopup({
89
+ researchId: "xxx",
90
+ open: isOpen,
91
+ onOpenChange: setIsOpen,
92
+ });
93
+
94
+ // External control
95
+ <button onClick={() => setIsOpen(true)}>Open from anywhere</button>;
96
+ ```
97
+
98
+ ### useSlider
99
+
100
+ Open a slider panel with your own trigger element.
101
+
102
+ ```tsx
103
+ import { useSlider } from "@perspective-ai/sdk-react";
104
+
105
+ function App() {
106
+ const { open, close, isOpen } = useSlider({
107
+ researchId: "your-research-id",
108
+ });
109
+
110
+ return <button onClick={open}>Open Feedback Panel</button>;
111
+ }
112
+ ```
113
+
114
+ ### useAutoOpen
115
+
116
+ Auto-trigger a popup based on a timeout or exit intent — no user click needed.
117
+
118
+ ```tsx
119
+ import { useAutoOpen } from "@perspective-ai/sdk-react";
120
+
121
+ function FeedbackTrigger() {
122
+ const { cancel, triggered } = useAutoOpen({
123
+ researchId: "your-research-id",
124
+ trigger: { type: "timeout", delay: 5000 },
125
+ showOnce: "session",
126
+ onSubmit: () => console.log("Completed!"),
127
+ });
128
+
129
+ // Renders nothing — popup opens automatically after 5s
130
+ return null;
131
+ }
132
+ ```
133
+
134
+ **Exit intent:**
135
+
136
+ ```tsx
137
+ useAutoOpen({
138
+ researchId: "your-research-id",
139
+ trigger: { type: "exit-intent" },
140
+ showOnce: "visitor",
141
+ });
142
+ ```
143
+
144
+ **Options:**
145
+
146
+ | Option | Type | Default | Description |
147
+ | ------------ | --------------- | ----------- | ------------------------------------------------------------------------ |
148
+ | `researchId` | `string` | — | Research ID (required) |
149
+ | `trigger` | `TriggerConfig` | — | `{ type: "timeout", delay: ms }` or `{ type: "exit-intent" }` (required) |
150
+ | `showOnce` | `ShowOnce` | `"session"` | `"session"`, `"visitor"`, or `false` |
151
+
152
+ Plus all standard `EmbedConfig` options (`theme`, `params`, `brand`, callbacks).
153
+
154
+ **Returns:**
155
+
156
+ | Property | Type | Description |
157
+ | ----------- | ------------ | ----------------------------- |
158
+ | `cancel` | `() => void` | Cancel the pending trigger |
159
+ | `triggered` | `boolean` | Whether the trigger has fired |
160
+
161
+ ### useFloatBubble
162
+
163
+ Manage a floating chat bubble lifecycle.
164
+
165
+ ```tsx
166
+ import { useFloatBubble } from "@perspective-ai/sdk-react";
167
+
168
+ function App() {
169
+ const { open, close, isOpen } = useFloatBubble({
170
+ researchId: "your-research-id",
171
+ });
172
+
173
+ // Bubble mounts on component mount
174
+ // Use open/close for programmatic control
175
+ return null;
176
+ }
177
+ ```
178
+
179
+ ## Components
180
+
181
+ ### Widget
182
+
183
+ Inline embed that renders in a container.
184
+
185
+ ```tsx
186
+ import { Widget } from "@perspective-ai/sdk-react";
187
+
188
+ <Widget
189
+ researchId="your-research-id"
190
+ onSubmit={() => console.log("Done!")}
191
+ className="my-widget"
192
+ style={{ height: 600 }}
193
+ />;
194
+ ```
195
+
196
+ ### Fullpage
197
+
198
+ Full viewport takeover embed.
199
+
200
+ ```tsx
201
+ import { Fullpage } from "@perspective-ai/sdk-react";
202
+
203
+ <Fullpage researchId="your-research-id" />;
204
+ ```
205
+
206
+ ### FloatBubble
207
+
208
+ Convenience wrapper around `useFloatBubble` hook.
209
+
210
+ ```tsx
211
+ import { FloatBubble } from "@perspective-ai/sdk-react";
212
+
213
+ <FloatBubble researchId="your-research-id" />;
214
+ ```
215
+
216
+ ## Hook Options
217
+
218
+ All hooks accept options from `EmbedConfig`:
219
+
220
+ ```typescript
221
+ interface UsePopupOptions {
222
+ researchId: string;
223
+ host?: string;
224
+ theme?: "light" | "dark" | "system";
225
+ params?: Record<string, string>;
226
+ brand?: {
227
+ light?: {
228
+ primary?: string;
229
+ secondary?: string;
230
+ bg?: string;
231
+ text?: string;
232
+ };
233
+ dark?: { primary?: string; secondary?: string; bg?: string; text?: string };
234
+ };
235
+
236
+ // Callbacks
237
+ onReady?: () => void;
238
+ onSubmit?: (data: { researchId: string }) => void;
239
+ onClose?: () => void;
240
+ onNavigate?: (url: string) => void;
241
+ onError?: (error: EmbedError) => void;
242
+
243
+ // Controlled mode
244
+ open?: boolean;
245
+ onOpenChange?: (open: boolean) => void;
246
+ }
247
+ ```
248
+
249
+ ## Hook Return Types
250
+
251
+ ```typescript
252
+ interface UsePopupReturn {
253
+ open: () => void;
254
+ close: () => void;
255
+ toggle: () => void;
256
+ isOpen: boolean;
257
+ handle: EmbedHandle | null;
258
+ }
259
+
260
+ interface UseSliderReturn {
261
+ open: () => void;
262
+ close: () => void;
263
+ toggle: () => void;
264
+ isOpen: boolean;
265
+ handle: EmbedHandle | null;
266
+ }
267
+
268
+ interface UseFloatBubbleReturn {
269
+ open: () => void;
270
+ close: () => void;
271
+ toggle: () => void;
272
+ unmount: () => void;
273
+ isOpen: boolean;
274
+ handle: FloatHandle | null;
275
+ }
276
+ ```
277
+
278
+ ## Other Hooks
279
+
280
+ ### useThemeSync
281
+
282
+ Sync theme between your app and embedded interviews:
283
+
284
+ ```tsx
285
+ import { useThemeSync } from "@perspective-ai/sdk-react";
286
+
287
+ function App() {
288
+ const [theme, setTheme] = useState<"light" | "dark">("light");
289
+
290
+ // Syncs theme changes to all active embeds
291
+ useThemeSync(theme);
292
+
293
+ return (
294
+ <button onClick={() => setTheme((t) => (t === "light" ? "dark" : "light"))}>
295
+ Toggle Theme
296
+ </button>
297
+ );
298
+ }
299
+ ```
300
+
301
+ ## TypeScript
302
+
303
+ All types are exported:
304
+
305
+ ```typescript
306
+ import type {
307
+ // Hook types
308
+ UsePopupOptions,
309
+ UsePopupReturn,
310
+ UseSliderOptions,
311
+ UseSliderReturn,
312
+ UseFloatBubbleOptions,
313
+ UseFloatBubbleReturn,
314
+ UseAutoOpenOptions,
315
+ UseAutoOpenReturn,
316
+ // Component types
317
+ WidgetProps,
318
+ FloatBubbleProps,
319
+ FullpageProps,
320
+ } from "@perspective-ai/sdk-react";
321
+
322
+ // Re-exported from @perspective-ai/sdk
323
+ import type {
324
+ EmbedConfig,
325
+ EmbedHandle,
326
+ FloatHandle,
327
+ BrandColors,
328
+ ThemeValue,
329
+ EmbedError,
330
+ } from "@perspective-ai/sdk-react";
331
+ ```
332
+
333
+ ## SSR Safety
334
+
335
+ All hooks and components are SSR-safe and include the `"use client"` directive. Works with Next.js, Remix, and other React frameworks.
336
+
337
+ ## License
338
+
339
+ MIT