@perspective-ai/sdk 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 +414 -0
- package/dist/browser.cjs +2142 -0
- package/dist/browser.cjs.map +1 -0
- package/dist/browser.d.cts +231 -0
- package/dist/browser.d.ts +231 -0
- package/dist/browser.js +2103 -0
- package/dist/browser.js.map +1 -0
- package/dist/cdn/perspective.global.js +406 -0
- package/dist/cdn/perspective.global.js.map +1 -0
- package/dist/constants.cjs +118 -0
- package/dist/constants.cjs.map +1 -0
- package/dist/constants.d.cts +97 -0
- package/dist/constants.d.ts +97 -0
- package/dist/constants.js +104 -0
- package/dist/constants.js.map +1 -0
- package/dist/index.cjs +1777 -0
- package/dist/index.cjs.map +1 -0
- package/dist/index.d.cts +219 -0
- package/dist/index.d.ts +219 -0
- package/dist/index.js +1755 -0
- package/dist/index.js.map +1 -0
- package/package.json +90 -0
- package/src/browser.test.ts +431 -0
- package/src/browser.ts +554 -0
- package/src/config.test.ts +81 -0
- package/src/config.ts +95 -0
- package/src/constants.ts +184 -0
- package/src/float.test.ts +332 -0
- package/src/float.ts +231 -0
- package/src/fullpage.test.ts +224 -0
- package/src/fullpage.ts +126 -0
- package/src/iframe-auth.test.ts +338 -0
- package/src/iframe.test.ts +1152 -0
- package/src/iframe.ts +598 -0
- package/src/index.ts +74 -0
- package/src/loading.ts +90 -0
- package/src/popup.test.ts +344 -0
- package/src/popup.ts +157 -0
- package/src/slider.test.ts +277 -0
- package/src/slider.ts +158 -0
- package/src/styles.ts +395 -0
- package/src/triggers.test.ts +272 -0
- package/src/triggers.ts +127 -0
- package/src/types.ts +181 -0
- package/src/utils.test.ts +162 -0
- package/src/utils.ts +86 -0
- package/src/widget.test.ts +375 -0
- package/src/widget.ts +195 -0
package/README.md
ADDED
|
@@ -0,0 +1,414 @@
|
|
|
1
|
+
# @perspective-ai/sdk
|
|
2
|
+
|
|
3
|
+
Embed SDK for [Perspective AI](https://getperspective.ai).
|
|
4
|
+
|
|
5
|
+
## Installation
|
|
6
|
+
|
|
7
|
+
```bash
|
|
8
|
+
npm install @perspective-ai/sdk
|
|
9
|
+
```
|
|
10
|
+
|
|
11
|
+
## Quick Start
|
|
12
|
+
|
|
13
|
+
### Vanilla JavaScript
|
|
14
|
+
|
|
15
|
+
```html
|
|
16
|
+
<button id="feedback-btn">Give Feedback</button>
|
|
17
|
+
|
|
18
|
+
<script type="module">
|
|
19
|
+
import { openPopup } from "@perspective-ai/sdk";
|
|
20
|
+
|
|
21
|
+
document.getElementById("feedback-btn").addEventListener("click", () => {
|
|
22
|
+
openPopup({
|
|
23
|
+
researchId: "your-research-id",
|
|
24
|
+
onSubmit: () => {
|
|
25
|
+
console.log("Thank you for your feedback!");
|
|
26
|
+
},
|
|
27
|
+
});
|
|
28
|
+
});
|
|
29
|
+
</script>
|
|
30
|
+
```
|
|
31
|
+
|
|
32
|
+
> **React?** Use [`@perspective-ai/sdk-react`](https://www.npmjs.com/package/@perspective-ai/sdk-react) for hooks and components.
|
|
33
|
+
|
|
34
|
+
## Embed Types
|
|
35
|
+
|
|
36
|
+
| Type | Function | Description |
|
|
37
|
+
| -------- | --------------------------------- | ------------------------------- |
|
|
38
|
+
| Widget | `createWidget(container, config)` | Inline embed in a container |
|
|
39
|
+
| Popup | `openPopup(config)` | Centered modal overlay |
|
|
40
|
+
| Slider | `openSlider(config)` | Side panel slides in from right |
|
|
41
|
+
| Float | `createFloatBubble(config)` | Floating chat bubble in corner |
|
|
42
|
+
| Fullpage | `createFullpage(config)` | Full viewport takeover |
|
|
43
|
+
|
|
44
|
+
### Widget (Inline Embed)
|
|
45
|
+
|
|
46
|
+
```typescript
|
|
47
|
+
import { createWidget } from "@perspective-ai/sdk";
|
|
48
|
+
|
|
49
|
+
const container = document.getElementById("interview-container");
|
|
50
|
+
const handle = createWidget(container, {
|
|
51
|
+
researchId: "your-research-id",
|
|
52
|
+
});
|
|
53
|
+
```
|
|
54
|
+
|
|
55
|
+
### Popup Modal
|
|
56
|
+
|
|
57
|
+
```typescript
|
|
58
|
+
import { openPopup } from "@perspective-ai/sdk";
|
|
59
|
+
|
|
60
|
+
const handle = openPopup({
|
|
61
|
+
researchId: "your-research-id",
|
|
62
|
+
theme: "dark",
|
|
63
|
+
});
|
|
64
|
+
```
|
|
65
|
+
|
|
66
|
+
### Slider Panel
|
|
67
|
+
|
|
68
|
+
```typescript
|
|
69
|
+
import { openSlider } from "@perspective-ai/sdk";
|
|
70
|
+
|
|
71
|
+
const handle = openSlider({
|
|
72
|
+
researchId: "your-research-id",
|
|
73
|
+
});
|
|
74
|
+
```
|
|
75
|
+
|
|
76
|
+
### Float Bubble
|
|
77
|
+
|
|
78
|
+
```typescript
|
|
79
|
+
import { createFloatBubble } from "@perspective-ai/sdk";
|
|
80
|
+
|
|
81
|
+
const handle = createFloatBubble({
|
|
82
|
+
researchId: "your-research-id",
|
|
83
|
+
});
|
|
84
|
+
|
|
85
|
+
// Control the bubble
|
|
86
|
+
handle.open();
|
|
87
|
+
handle.close();
|
|
88
|
+
handle.toggle();
|
|
89
|
+
console.log(handle.isOpen); // boolean
|
|
90
|
+
```
|
|
91
|
+
|
|
92
|
+
### Fullpage
|
|
93
|
+
|
|
94
|
+
```typescript
|
|
95
|
+
import { createFullpage } from "@perspective-ai/sdk";
|
|
96
|
+
|
|
97
|
+
const handle = createFullpage({
|
|
98
|
+
researchId: "your-research-id",
|
|
99
|
+
});
|
|
100
|
+
```
|
|
101
|
+
|
|
102
|
+
## Configuration
|
|
103
|
+
|
|
104
|
+
```typescript
|
|
105
|
+
interface EmbedConfig {
|
|
106
|
+
// Required
|
|
107
|
+
researchId: string;
|
|
108
|
+
|
|
109
|
+
// Optional
|
|
110
|
+
host?: string; // Custom API host
|
|
111
|
+
theme?: "light" | "dark" | "system"; // Theme preference (default: "system")
|
|
112
|
+
params?: Record<string, string>; // Custom URL parameters for tracking
|
|
113
|
+
brand?: {
|
|
114
|
+
light?: BrandColors; // Light mode brand colors
|
|
115
|
+
dark?: BrandColors; // Dark mode brand colors
|
|
116
|
+
};
|
|
117
|
+
|
|
118
|
+
// Callbacks
|
|
119
|
+
onReady?: () => void;
|
|
120
|
+
onSubmit?: (data: { researchId: string }) => void;
|
|
121
|
+
onClose?: () => void;
|
|
122
|
+
onNavigate?: (url: string) => void; // Handle navigation (default: window.location.href)
|
|
123
|
+
onError?: (error: EmbedError) => void;
|
|
124
|
+
}
|
|
125
|
+
|
|
126
|
+
interface BrandColors {
|
|
127
|
+
primary?: string; // Primary brand color
|
|
128
|
+
secondary?: string; // Secondary brand color
|
|
129
|
+
bg?: string; // Background color
|
|
130
|
+
text?: string; // Text color
|
|
131
|
+
}
|
|
132
|
+
```
|
|
133
|
+
|
|
134
|
+
## Handle API
|
|
135
|
+
|
|
136
|
+
All embed functions return a handle for programmatic control:
|
|
137
|
+
|
|
138
|
+
### EmbedHandle (Widget, Popup, Slider, Fullpage)
|
|
139
|
+
|
|
140
|
+
```typescript
|
|
141
|
+
interface EmbedHandle {
|
|
142
|
+
unmount(): void; // Remove the embed
|
|
143
|
+
update(options): void; // Update callbacks
|
|
144
|
+
destroy(): void; // Alias for unmount (deprecated)
|
|
145
|
+
readonly iframe: HTMLIFrameElement | null;
|
|
146
|
+
readonly container: HTMLElement | null;
|
|
147
|
+
readonly researchId: string;
|
|
148
|
+
readonly type: EmbedType;
|
|
149
|
+
}
|
|
150
|
+
```
|
|
151
|
+
|
|
152
|
+
### FloatHandle (Float Bubble)
|
|
153
|
+
|
|
154
|
+
```typescript
|
|
155
|
+
interface FloatHandle extends EmbedHandle {
|
|
156
|
+
open(): void; // Open the chat window
|
|
157
|
+
close(): void; // Close the chat window
|
|
158
|
+
toggle(): void; // Toggle open/close
|
|
159
|
+
readonly isOpen: boolean; // Current state
|
|
160
|
+
readonly type: "float";
|
|
161
|
+
}
|
|
162
|
+
```
|
|
163
|
+
|
|
164
|
+
## Global Configuration
|
|
165
|
+
|
|
166
|
+
Configure SDK-wide defaults before creating embeds:
|
|
167
|
+
|
|
168
|
+
```typescript
|
|
169
|
+
import { configure, getConfig } from "@perspective-ai/sdk";
|
|
170
|
+
|
|
171
|
+
// Set global host
|
|
172
|
+
configure({ host: "https://custom-host.example.com" });
|
|
173
|
+
|
|
174
|
+
// Get current config
|
|
175
|
+
const config = getConfig();
|
|
176
|
+
```
|
|
177
|
+
|
|
178
|
+
## Custom Parameters
|
|
179
|
+
|
|
180
|
+
Pass tracking or attribution parameters:
|
|
181
|
+
|
|
182
|
+
```typescript
|
|
183
|
+
openPopup({
|
|
184
|
+
researchId: "your-research-id",
|
|
185
|
+
params: {
|
|
186
|
+
email: "user@example.com",
|
|
187
|
+
name: "John Doe",
|
|
188
|
+
source: "marketing-campaign",
|
|
189
|
+
},
|
|
190
|
+
});
|
|
191
|
+
```
|
|
192
|
+
|
|
193
|
+
### Reserved Parameters
|
|
194
|
+
|
|
195
|
+
These parameters are managed by the SDK and cannot be overridden via `params`:
|
|
196
|
+
|
|
197
|
+
- `embed`, `embed_type`, `theme`
|
|
198
|
+
- Brand colors: `brand.primary`, `brand.bg`, etc.
|
|
199
|
+
- UTM parameters: `utm_source`, `utm_medium`, `utm_campaign`, `utm_term`, `utm_content`
|
|
200
|
+
|
|
201
|
+
## Constants
|
|
202
|
+
|
|
203
|
+
Import SSR-safe constants for advanced use cases:
|
|
204
|
+
|
|
205
|
+
```typescript
|
|
206
|
+
import {
|
|
207
|
+
SDK_VERSION,
|
|
208
|
+
MESSAGE_TYPES,
|
|
209
|
+
DATA_ATTRS,
|
|
210
|
+
PARAM_KEYS,
|
|
211
|
+
THEME_VALUES,
|
|
212
|
+
} from "@perspective-ai/sdk";
|
|
213
|
+
|
|
214
|
+
// Or import from the constants submodule
|
|
215
|
+
import { MESSAGE_TYPES } from "@perspective-ai/sdk/constants";
|
|
216
|
+
```
|
|
217
|
+
|
|
218
|
+
### Available Constants
|
|
219
|
+
|
|
220
|
+
| Constant | Description |
|
|
221
|
+
| --------------- | ------------------------------------- |
|
|
222
|
+
| `SDK_VERSION` | Current SDK version |
|
|
223
|
+
| `FEATURES` | Feature flags for version negotiation |
|
|
224
|
+
| `MESSAGE_TYPES` | PostMessage event types |
|
|
225
|
+
| `DATA_ATTRS` | HTML data attribute names |
|
|
226
|
+
| `PARAM_KEYS` | URL parameter keys |
|
|
227
|
+
| `BRAND_KEYS` | Brand color parameter keys |
|
|
228
|
+
| `THEME_VALUES` | Valid theme values |
|
|
229
|
+
|
|
230
|
+
## Types
|
|
231
|
+
|
|
232
|
+
All types are exported for TypeScript users:
|
|
233
|
+
|
|
234
|
+
```typescript
|
|
235
|
+
import type {
|
|
236
|
+
EmbedConfig,
|
|
237
|
+
EmbedHandle,
|
|
238
|
+
FloatHandle,
|
|
239
|
+
EmbedError,
|
|
240
|
+
EmbedType,
|
|
241
|
+
BrandColors,
|
|
242
|
+
ThemeConfig,
|
|
243
|
+
SDKConfig,
|
|
244
|
+
// Auto-trigger types
|
|
245
|
+
TriggerConfig,
|
|
246
|
+
TriggerType,
|
|
247
|
+
ShowOnce,
|
|
248
|
+
AutoOpenConfig,
|
|
249
|
+
} from "@perspective-ai/sdk";
|
|
250
|
+
```
|
|
251
|
+
|
|
252
|
+
## Auto-Trigger Popups
|
|
253
|
+
|
|
254
|
+
Open popups automatically based on configurable triggers — no user click required. Ideal for lead capture, engagement prompts, and exit-intent surveys.
|
|
255
|
+
|
|
256
|
+
### JavaScript API
|
|
257
|
+
|
|
258
|
+
```typescript
|
|
259
|
+
import {
|
|
260
|
+
openPopup,
|
|
261
|
+
setupTrigger,
|
|
262
|
+
shouldShow,
|
|
263
|
+
markShown,
|
|
264
|
+
} from "@perspective-ai/sdk";
|
|
265
|
+
import type { TriggerConfig, ShowOnce } from "@perspective-ai/sdk";
|
|
266
|
+
|
|
267
|
+
const researchId = "your-research-id";
|
|
268
|
+
const showOnce: ShowOnce = "session"; // "session" | "visitor" | false
|
|
269
|
+
|
|
270
|
+
if (shouldShow(researchId, showOnce)) {
|
|
271
|
+
const cleanup = setupTrigger({ type: "timeout", delay: 5000 }, () => {
|
|
272
|
+
markShown(researchId, showOnce);
|
|
273
|
+
openPopup({ researchId });
|
|
274
|
+
});
|
|
275
|
+
|
|
276
|
+
// Call cleanup() to cancel the pending trigger
|
|
277
|
+
}
|
|
278
|
+
```
|
|
279
|
+
|
|
280
|
+
### Trigger Types
|
|
281
|
+
|
|
282
|
+
| Trigger | Config | Description |
|
|
283
|
+
| ----------- | ---------------------------------- | ------------------------------------ |
|
|
284
|
+
| Timeout | `{ type: "timeout", delay: 5000 }` | Open after a delay (ms) |
|
|
285
|
+
| Exit Intent | `{ type: "exit-intent" }` | Open when cursor leaves the viewport |
|
|
286
|
+
|
|
287
|
+
### Show-Once Dedup
|
|
288
|
+
|
|
289
|
+
| Value | Storage | Behavior |
|
|
290
|
+
| ----------- | ---------------- | ------------------------------------------------ |
|
|
291
|
+
| `"session"` | `sessionStorage` | Show once per browser session (default) |
|
|
292
|
+
| `"visitor"` | `localStorage` | Show once per visitor (persists across sessions) |
|
|
293
|
+
| `false` | — | Always show |
|
|
294
|
+
|
|
295
|
+
### Functions
|
|
296
|
+
|
|
297
|
+
| Function | Signature | Description |
|
|
298
|
+
| ------------------ | ------------------------------------------------------------- | -------------------------------------------------- |
|
|
299
|
+
| `setupTrigger` | `(config: TriggerConfig, callback: () => void) => () => void` | Set up a trigger, returns cleanup function |
|
|
300
|
+
| `shouldShow` | `(researchId: string, showOnce: ShowOnce) => boolean` | Check if popup should show (dedup check) |
|
|
301
|
+
| `markShown` | `(researchId: string, showOnce: ShowOnce) => void` | Mark popup as shown for dedup |
|
|
302
|
+
| `parseTriggerAttr` | `(value: string) => TriggerConfig` | Parse data attribute value (e.g. `"timeout:5000"`) |
|
|
303
|
+
|
|
304
|
+
## CDN / Script Tag Usage
|
|
305
|
+
|
|
306
|
+
For non-module environments, use the browser bundle:
|
|
307
|
+
|
|
308
|
+
```html
|
|
309
|
+
<script src="https://getperspective.ai/v1/perspective.js"></script>
|
|
310
|
+
```
|
|
311
|
+
|
|
312
|
+
### Declarative (Data Attributes)
|
|
313
|
+
|
|
314
|
+
```html
|
|
315
|
+
<!-- Inline widget -->
|
|
316
|
+
<div data-perspective-widget="your-research-id"></div>
|
|
317
|
+
|
|
318
|
+
<!-- Popup trigger -->
|
|
319
|
+
<button data-perspective-popup="your-research-id">Start Interview</button>
|
|
320
|
+
|
|
321
|
+
<!-- Slider trigger -->
|
|
322
|
+
<button data-perspective-slider="your-research-id">Open Survey</button>
|
|
323
|
+
|
|
324
|
+
<!-- Float bubble -->
|
|
325
|
+
<div data-perspective-float="your-research-id"></div>
|
|
326
|
+
|
|
327
|
+
<!-- Fullpage -->
|
|
328
|
+
<div data-perspective-fullpage="your-research-id"></div>
|
|
329
|
+
```
|
|
330
|
+
|
|
331
|
+
### Data Attributes Reference
|
|
332
|
+
|
|
333
|
+
| Attribute | Description |
|
|
334
|
+
| ----------------------------- | ------------------------------------------------------- |
|
|
335
|
+
| `data-perspective-widget` | Inline widget embed |
|
|
336
|
+
| `data-perspective-popup` | Popup trigger button |
|
|
337
|
+
| `data-perspective-slider` | Slider trigger button |
|
|
338
|
+
| `data-perspective-float` | Floating chat bubble |
|
|
339
|
+
| `data-perspective-fullpage` | Full page embed |
|
|
340
|
+
| `data-perspective-params` | Custom params: `"key1=value1,key2=value2"` |
|
|
341
|
+
| `data-perspective-theme` | Theme: `"light"`, `"dark"`, or `"system"` |
|
|
342
|
+
| `data-perspective-brand` | Light mode colors: `"primary=#xxx,bg=#yyy"` |
|
|
343
|
+
| `data-perspective-brand-dark` | Dark mode colors |
|
|
344
|
+
| `data-perspective-no-style` | Disable auto-styling on trigger buttons |
|
|
345
|
+
| `data-perspective-auto-open` | Auto-open trigger: `"timeout:5000"` or `"exit-intent"` |
|
|
346
|
+
| `data-perspective-show-once` | Show-once dedup: `"session"`, `"visitor"`, or `"false"` |
|
|
347
|
+
|
|
348
|
+
### Auto-Trigger (Data Attributes)
|
|
349
|
+
|
|
350
|
+
```html
|
|
351
|
+
<!-- Auto-open popup after 5 seconds, once per session -->
|
|
352
|
+
<div
|
|
353
|
+
data-perspective-popup="your-research-id"
|
|
354
|
+
data-perspective-auto-open="timeout:5000"
|
|
355
|
+
data-perspective-show-once="session"
|
|
356
|
+
style="display:none"
|
|
357
|
+
></div>
|
|
358
|
+
|
|
359
|
+
<!-- Exit-intent popup, show every time -->
|
|
360
|
+
<div
|
|
361
|
+
data-perspective-popup="your-research-id"
|
|
362
|
+
data-perspective-auto-open="exit-intent"
|
|
363
|
+
data-perspective-show-once="false"
|
|
364
|
+
style="display:none"
|
|
365
|
+
></div>
|
|
366
|
+
```
|
|
367
|
+
|
|
368
|
+
When `data-perspective-auto-open` is present, the element acts as a hidden config holder — no button styling is applied.
|
|
369
|
+
|
|
370
|
+
### Programmatic (Global API)
|
|
371
|
+
|
|
372
|
+
```html
|
|
373
|
+
<script>
|
|
374
|
+
// Direct functions
|
|
375
|
+
Perspective.openPopup({ researchId: "xxx" });
|
|
376
|
+
Perspective.openSlider({ researchId: "xxx" });
|
|
377
|
+
Perspective.createFloatBubble({ researchId: "xxx" });
|
|
378
|
+
Perspective.createFullpage({ researchId: "xxx" });
|
|
379
|
+
|
|
380
|
+
// Mount widget into container
|
|
381
|
+
Perspective.mount("#container", { researchId: "xxx" });
|
|
382
|
+
|
|
383
|
+
// Generic init with type
|
|
384
|
+
Perspective.init({ researchId: "xxx", type: "popup" });
|
|
385
|
+
|
|
386
|
+
// Destroy by researchId
|
|
387
|
+
Perspective.destroy("xxx");
|
|
388
|
+
Perspective.destroyAll();
|
|
389
|
+
|
|
390
|
+
// Configuration
|
|
391
|
+
Perspective.configure({ host: "https://custom.example.com" });
|
|
392
|
+
</script>
|
|
393
|
+
```
|
|
394
|
+
|
|
395
|
+
## SSR Safety
|
|
396
|
+
|
|
397
|
+
The SDK is SSR-safe. All DOM access is guarded and returns no-op handles on the server:
|
|
398
|
+
|
|
399
|
+
```typescript
|
|
400
|
+
// Safe to call during SSR - returns a no-op handle
|
|
401
|
+
const handle = openPopup({ researchId: "xxx" });
|
|
402
|
+
handle.unmount(); // No-op on server
|
|
403
|
+
```
|
|
404
|
+
|
|
405
|
+
## Browser Support
|
|
406
|
+
|
|
407
|
+
- Chrome 80+
|
|
408
|
+
- Firefox 80+
|
|
409
|
+
- Safari 14+
|
|
410
|
+
- Edge 80+
|
|
411
|
+
|
|
412
|
+
## License
|
|
413
|
+
|
|
414
|
+
MIT
|