@perspective-ai/sdk-react 1.0.0-alpha.2 → 1.0.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/README.md CHANGED
@@ -1,6 +1,6 @@
1
1
  # @perspective-ai/sdk-react
2
2
 
3
- React components for [Perspective AI](https://getperspective.ai).
3
+ React hooks and components for [Perspective AI](https://getperspective.ai).
4
4
 
5
5
  > **Not using React?** Use [`@perspective-ai/sdk`](https://www.npmjs.com/package/@perspective-ai/sdk) for vanilla JavaScript.
6
6
 
@@ -15,88 +15,134 @@ npm install @perspective-ai/sdk-react
15
15
  ## Quick Start
16
16
 
17
17
  ```tsx
18
- import { PopupButton } from "@perspective-ai/sdk-react";
18
+ import { usePopup } from "@perspective-ai/sdk-react";
19
19
 
20
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
- );
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>;
29
27
  }
30
28
  ```
31
29
 
32
- ## Components
30
+ ## API Overview
33
31
 
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 |
32
+ | API | Type | Description |
33
+ | ---------------- | --------- | -------------------------------------- |
34
+ | `usePopup` | Hook | Open popup modal programmatically |
35
+ | `useSlider` | Hook | Open slider panel programmatically |
36
+ | `useFloatBubble` | Hook | Floating chat bubble lifecycle |
37
+ | `Widget` | Component | Inline embed in a container |
38
+ | `Fullpage` | Component | Full viewport takeover |
39
+ | `FloatBubble` | Component | Convenience wrapper for useFloatBubble |
41
40
 
42
- ### Widget
41
+ **Mental Model:**
43
42
 
44
- Inline embed that renders in a container.
43
+ - **Hooks** for overlays (popup, slider, float bubble) - you control the trigger
44
+ - **Components** for embeds (widget, fullpage) - render inline DOM
45
+
46
+ ## Hooks
47
+
48
+ ### usePopup
49
+
50
+ Open a popup modal with your own trigger element.
45
51
 
46
52
  ```tsx
47
- import { Widget } from "@perspective-ai/sdk-react";
53
+ import { usePopup } from "@perspective-ai/sdk-react";
48
54
 
49
- <Widget
50
- researchId="your-research-id"
51
- onSubmit={() => console.log("Done!")}
52
- className="my-widget" // or style={{ height: 600 }}
53
- />;
54
- ```
55
+ function App() {
56
+ const { open, close, isOpen } = usePopup({
57
+ researchId: "your-research-id",
58
+ onSubmit: () => console.log("Done!"),
59
+ });
55
60
 
56
- ### PopupButton
61
+ return (
62
+ <>
63
+ <button onClick={open}>Take Survey</button>
64
+ {isOpen && <span>Survey is open</span>}
65
+ </>
66
+ );
67
+ }
68
+ ```
57
69
 
58
- Button that opens a popup modal when clicked.
70
+ **Programmatic trigger:**
59
71
 
60
72
  ```tsx
61
- import { PopupButton } from "@perspective-ai/sdk-react";
73
+ const { open } = usePopup({ researchId: "xxx" });
62
74
 
63
- <PopupButton
64
- researchId="your-research-id"
65
- onSubmit={() => console.log("Done!")}
66
- className="btn btn-primary"
67
- >
68
- Take Interview
69
- </PopupButton>;
75
+ useEffect(() => {
76
+ if (userCompletedCheckout) {
77
+ open();
78
+ }
79
+ }, [userCompletedCheckout, open]);
70
80
  ```
71
81
 
72
82
  **Controlled mode:**
73
83
 
74
84
  ```tsx
75
- const [open, setOpen] = useState(false);
85
+ const [isOpen, setIsOpen] = useState(false);
86
+
87
+ const popup = usePopup({
88
+ researchId: "xxx",
89
+ open: isOpen,
90
+ onOpenChange: setIsOpen,
91
+ });
76
92
 
77
- <PopupButton researchId="xxx" open={open} onOpenChange={setOpen}>
78
- Take Interview
79
- </PopupButton>;
93
+ // External control
94
+ <button onClick={() => setIsOpen(true)}>Open from anywhere</button>;
80
95
  ```
81
96
 
82
- ### SliderButton
97
+ ### useSlider
83
98
 
84
- Button that opens a side panel when clicked.
99
+ Open a slider panel with your own trigger element.
85
100
 
86
101
  ```tsx
87
- import { SliderButton } from "@perspective-ai/sdk-react";
102
+ import { useSlider } from "@perspective-ai/sdk-react";
88
103
 
89
- <SliderButton researchId="your-research-id">Open Interview</SliderButton>;
104
+ function App() {
105
+ const { open, close, isOpen } = useSlider({
106
+ researchId: "your-research-id",
107
+ });
108
+
109
+ return <button onClick={open}>Open Feedback Panel</button>;
110
+ }
90
111
  ```
91
112
 
92
- ### FloatBubble
113
+ ### useFloatBubble
93
114
 
94
- Floating chat bubble in the corner of the screen.
115
+ Manage a floating chat bubble lifecycle.
95
116
 
96
117
  ```tsx
97
- import { FloatBubble } from "@perspective-ai/sdk-react";
118
+ import { useFloatBubble } from "@perspective-ai/sdk-react";
98
119
 
99
- <FloatBubble researchId="your-research-id" />;
120
+ function App() {
121
+ const { open, close, isOpen } = useFloatBubble({
122
+ researchId: "your-research-id",
123
+ });
124
+
125
+ // Bubble mounts on component mount
126
+ // Use open/close for programmatic control
127
+ return null;
128
+ }
129
+ ```
130
+
131
+ ## Components
132
+
133
+ ### Widget
134
+
135
+ Inline embed that renders in a container.
136
+
137
+ ```tsx
138
+ import { Widget } from "@perspective-ai/sdk-react";
139
+
140
+ <Widget
141
+ researchId="your-research-id"
142
+ onSubmit={() => console.log("Done!")}
143
+ className="my-widget"
144
+ style={{ height: 600 }}
145
+ />;
100
146
  ```
101
147
 
102
148
  ### Fullpage
@@ -109,14 +155,22 @@ import { Fullpage } from "@perspective-ai/sdk-react";
109
155
  <Fullpage researchId="your-research-id" />;
110
156
  ```
111
157
 
112
- ## Props
158
+ ### FloatBubble
113
159
 
114
- All components accept props from `EmbedConfig`:
160
+ Convenience wrapper around `useFloatBubble` hook.
115
161
 
116
- ```typescript
117
- import type { EmbedConfig } from "@perspective-ai/sdk-react";
162
+ ```tsx
163
+ import { FloatBubble } from "@perspective-ai/sdk-react";
164
+
165
+ <FloatBubble researchId="your-research-id" />;
166
+ ```
118
167
 
119
- interface EmbedConfig {
168
+ ## Hook Options
169
+
170
+ All hooks accept options from `EmbedConfig`:
171
+
172
+ ```typescript
173
+ interface UsePopupOptions {
120
174
  researchId: string;
121
175
  host?: string;
122
176
  theme?: "light" | "dark" | "system";
@@ -137,128 +191,43 @@ interface EmbedConfig {
137
191
  onClose?: () => void;
138
192
  onNavigate?: (url: string) => void;
139
193
  onError?: (error: EmbedError) => void;
140
- }
141
- ```
142
-
143
- ### Widget
144
-
145
- ```typescript
146
- import type { WidgetProps } from "@perspective-ai/sdk-react";
147
194
 
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;
195
+ // Controlled mode
174
196
  open?: boolean;
175
197
  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
198
  }
219
199
  ```
220
200
 
221
- ### Handle Types
201
+ ## Hook Return Types
222
202
 
223
203
  ```typescript
224
- // Widget, Fullpage
225
- interface EmbedHandle {
226
- unmount(): void;
227
- update(options): void;
228
- destroy(): void; // deprecated, use unmount
204
+ interface UsePopupReturn {
205
+ open: () => void;
206
+ close: () => void;
207
+ toggle: () => void;
208
+ isOpen: boolean;
209
+ handle: EmbedHandle | null;
229
210
  }
230
211
 
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;
212
+ interface UseSliderReturn {
213
+ open: () => void;
214
+ close: () => void;
215
+ toggle: () => void;
216
+ isOpen: boolean;
217
+ handle: EmbedHandle | null;
239
218
  }
240
219
 
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;
220
+ interface UseFloatBubbleReturn {
221
+ open: () => void;
222
+ close: () => void;
223
+ toggle: () => void;
224
+ unmount: () => void;
225
+ isOpen: boolean;
226
+ handle: FloatHandle | null;
258
227
  }
259
228
  ```
260
229
 
261
- ## Hooks
230
+ ## Other Hooks
262
231
 
263
232
  ### useThemeSync
264
233
 
@@ -287,11 +256,15 @@ All types are exported:
287
256
 
288
257
  ```typescript
289
258
  import type {
259
+ // Hook types
260
+ UsePopupOptions,
261
+ UsePopupReturn,
262
+ UseSliderOptions,
263
+ UseSliderReturn,
264
+ UseFloatBubbleOptions,
265
+ UseFloatBubbleReturn,
266
+ // Component types
290
267
  WidgetProps,
291
- PopupButtonProps,
292
- PopupButtonHandle,
293
- SliderButtonProps,
294
- SliderButtonHandle,
295
268
  FloatBubbleProps,
296
269
  FullpageProps,
297
270
  } from "@perspective-ai/sdk-react";
@@ -309,7 +282,7 @@ import type {
309
282
 
310
283
  ## SSR Safety
311
284
 
312
- All components are SSR-safe and include the `"use client"` directive. Works with Next.js, Remix, and other React frameworks.
285
+ All hooks and components are SSR-safe and include the `"use client"` directive. Works with Next.js, Remix, and other React frameworks.
313
286
 
314
287
  ## License
315
288