@perspective-ai/sdk-react 1.0.0-alpha.2

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,316 @@
1
+ # @perspective-ai/sdk-react
2
+
3
+ React 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 { PopupButton } from "@perspective-ai/sdk-react";
19
+
20
+ function App() {
21
+ return (
22
+ <PopupButton
23
+ researchId="your-research-id"
24
+ onSubmit={() => console.log("Interview completed!")}
25
+ >
26
+ Give Feedback
27
+ </PopupButton>
28
+ );
29
+ }
30
+ ```
31
+
32
+ ## Components
33
+
34
+ | Component | Description |
35
+ | -------------- | ------------------------------- |
36
+ | `Widget` | Inline embed in a container |
37
+ | `PopupButton` | Button that opens a popup modal |
38
+ | `SliderButton` | Button that opens a side panel |
39
+ | `FloatBubble` | Floating chat bubble in corner |
40
+ | `Fullpage` | Full viewport takeover |
41
+
42
+ ### Widget
43
+
44
+ Inline embed that renders in a container.
45
+
46
+ ```tsx
47
+ import { Widget } from "@perspective-ai/sdk-react";
48
+
49
+ <Widget
50
+ researchId="your-research-id"
51
+ onSubmit={() => console.log("Done!")}
52
+ className="my-widget" // or style={{ height: 600 }}
53
+ />;
54
+ ```
55
+
56
+ ### PopupButton
57
+
58
+ Button that opens a popup modal when clicked.
59
+
60
+ ```tsx
61
+ import { PopupButton } from "@perspective-ai/sdk-react";
62
+
63
+ <PopupButton
64
+ researchId="your-research-id"
65
+ onSubmit={() => console.log("Done!")}
66
+ className="btn btn-primary"
67
+ >
68
+ Take Interview
69
+ </PopupButton>;
70
+ ```
71
+
72
+ **Controlled mode:**
73
+
74
+ ```tsx
75
+ const [open, setOpen] = useState(false);
76
+
77
+ <PopupButton researchId="xxx" open={open} onOpenChange={setOpen}>
78
+ Take Interview
79
+ </PopupButton>;
80
+ ```
81
+
82
+ ### SliderButton
83
+
84
+ Button that opens a side panel when clicked.
85
+
86
+ ```tsx
87
+ import { SliderButton } from "@perspective-ai/sdk-react";
88
+
89
+ <SliderButton researchId="your-research-id">Open Interview</SliderButton>;
90
+ ```
91
+
92
+ ### FloatBubble
93
+
94
+ Floating chat bubble in the corner of the screen.
95
+
96
+ ```tsx
97
+ import { FloatBubble } from "@perspective-ai/sdk-react";
98
+
99
+ <FloatBubble researchId="your-research-id" />;
100
+ ```
101
+
102
+ ### Fullpage
103
+
104
+ Full viewport takeover embed.
105
+
106
+ ```tsx
107
+ import { Fullpage } from "@perspective-ai/sdk-react";
108
+
109
+ <Fullpage researchId="your-research-id" />;
110
+ ```
111
+
112
+ ## Props
113
+
114
+ All components accept props from `EmbedConfig`:
115
+
116
+ ```typescript
117
+ import type { EmbedConfig } from "@perspective-ai/sdk-react";
118
+
119
+ interface EmbedConfig {
120
+ researchId: string;
121
+ host?: string;
122
+ theme?: "light" | "dark" | "system";
123
+ params?: Record<string, string>;
124
+ brand?: {
125
+ light?: {
126
+ primary?: string;
127
+ secondary?: string;
128
+ bg?: string;
129
+ text?: string;
130
+ };
131
+ dark?: { primary?: string; secondary?: string; bg?: string; text?: string };
132
+ };
133
+
134
+ // Callbacks
135
+ onReady?: () => void;
136
+ onSubmit?: (data: { researchId: string }) => void;
137
+ onClose?: () => void;
138
+ onNavigate?: (url: string) => void;
139
+ onError?: (error: EmbedError) => void;
140
+ }
141
+ ```
142
+
143
+ ### Widget
144
+
145
+ ```typescript
146
+ import type { WidgetProps } from "@perspective-ai/sdk-react";
147
+
148
+ interface WidgetProps extends EmbedConfig {
149
+ embedRef?: RefObject<EmbedHandle | null>;
150
+ className?: string;
151
+ style?: CSSProperties;
152
+ // ...other div props
153
+ }
154
+ ```
155
+
156
+ ### PopupButton / SliderButton
157
+
158
+ ```typescript
159
+ import type {
160
+ PopupButtonProps,
161
+ SliderButtonProps,
162
+ } from "@perspective-ai/sdk-react";
163
+
164
+ interface PopupButtonProps extends EmbedConfig {
165
+ children: ReactNode;
166
+ open?: boolean; // Controlled mode
167
+ onOpenChange?: (open: boolean) => void;
168
+ embedRef?: RefObject<PopupButtonHandle | null>;
169
+ // ...other button props
170
+ }
171
+
172
+ interface SliderButtonProps extends EmbedConfig {
173
+ children: ReactNode;
174
+ open?: boolean;
175
+ onOpenChange?: (open: boolean) => void;
176
+ embedRef?: RefObject<SliderButtonHandle | null>;
177
+ // ...other button props
178
+ }
179
+ ```
180
+
181
+ ### FloatBubble / Fullpage
182
+
183
+ ```typescript
184
+ import type {
185
+ FloatBubbleProps,
186
+ FullpageProps,
187
+ } from "@perspective-ai/sdk-react";
188
+
189
+ interface FloatBubbleProps extends EmbedConfig {
190
+ embedRef?: RefObject<FloatHandle | null>;
191
+ }
192
+
193
+ interface FullpageProps extends EmbedConfig {
194
+ embedRef?: RefObject<EmbedHandle | null>;
195
+ }
196
+ ```
197
+
198
+ ## Programmatic Control
199
+
200
+ Use `embedRef` to control components:
201
+
202
+ ```tsx
203
+ import { useRef } from "react";
204
+ import { PopupButton, type PopupButtonHandle } from "@perspective-ai/sdk-react";
205
+
206
+ function App() {
207
+ const ref = useRef<PopupButtonHandle>(null);
208
+
209
+ return (
210
+ <>
211
+ <PopupButton researchId="xxx" embedRef={ref}>
212
+ Open
213
+ </PopupButton>
214
+ <button onClick={() => ref.current?.open()}>Open Programmatically</button>
215
+ <button onClick={() => ref.current?.close()}>Close</button>
216
+ </>
217
+ );
218
+ }
219
+ ```
220
+
221
+ ### Handle Types
222
+
223
+ ```typescript
224
+ // Widget, Fullpage
225
+ interface EmbedHandle {
226
+ unmount(): void;
227
+ update(options): void;
228
+ destroy(): void; // deprecated, use unmount
229
+ }
230
+
231
+ // PopupButton
232
+ interface PopupButtonHandle {
233
+ open(): void;
234
+ close(): void;
235
+ toggle(): void;
236
+ unmount(): void;
237
+ readonly isOpen: boolean;
238
+ readonly researchId: string;
239
+ }
240
+
241
+ // SliderButton
242
+ interface SliderButtonHandle {
243
+ open(): void;
244
+ close(): void;
245
+ toggle(): void;
246
+ unmount(): void;
247
+ readonly isOpen: boolean;
248
+ readonly researchId: string;
249
+ }
250
+
251
+ // FloatBubble
252
+ interface FloatHandle {
253
+ open(): void;
254
+ close(): void;
255
+ toggle(): void;
256
+ unmount(): void;
257
+ readonly isOpen: boolean;
258
+ }
259
+ ```
260
+
261
+ ## Hooks
262
+
263
+ ### useThemeSync
264
+
265
+ Sync theme between your app and embedded interviews:
266
+
267
+ ```tsx
268
+ import { useThemeSync } from "@perspective-ai/sdk-react";
269
+
270
+ function App() {
271
+ const [theme, setTheme] = useState<"light" | "dark">("light");
272
+
273
+ // Syncs theme changes to all active embeds
274
+ useThemeSync(theme);
275
+
276
+ return (
277
+ <button onClick={() => setTheme((t) => (t === "light" ? "dark" : "light"))}>
278
+ Toggle Theme
279
+ </button>
280
+ );
281
+ }
282
+ ```
283
+
284
+ ## TypeScript
285
+
286
+ All types are exported:
287
+
288
+ ```typescript
289
+ import type {
290
+ WidgetProps,
291
+ PopupButtonProps,
292
+ PopupButtonHandle,
293
+ SliderButtonProps,
294
+ SliderButtonHandle,
295
+ FloatBubbleProps,
296
+ FullpageProps,
297
+ } from "@perspective-ai/sdk-react";
298
+
299
+ // Re-exported from @perspective-ai/sdk
300
+ import type {
301
+ EmbedConfig,
302
+ EmbedHandle,
303
+ FloatHandle,
304
+ BrandColors,
305
+ ThemeValue,
306
+ EmbedError,
307
+ } from "@perspective-ai/sdk-react";
308
+ ```
309
+
310
+ ## SSR Safety
311
+
312
+ All components are SSR-safe and include the `"use client"` directive. Works with Next.js, Remix, and other React frameworks.
313
+
314
+ ## License
315
+
316
+ MIT