@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.
Files changed (48) hide show
  1. package/README.md +414 -0
  2. package/dist/browser.cjs +2142 -0
  3. package/dist/browser.cjs.map +1 -0
  4. package/dist/browser.d.cts +231 -0
  5. package/dist/browser.d.ts +231 -0
  6. package/dist/browser.js +2103 -0
  7. package/dist/browser.js.map +1 -0
  8. package/dist/cdn/perspective.global.js +406 -0
  9. package/dist/cdn/perspective.global.js.map +1 -0
  10. package/dist/constants.cjs +118 -0
  11. package/dist/constants.cjs.map +1 -0
  12. package/dist/constants.d.cts +97 -0
  13. package/dist/constants.d.ts +97 -0
  14. package/dist/constants.js +104 -0
  15. package/dist/constants.js.map +1 -0
  16. package/dist/index.cjs +1777 -0
  17. package/dist/index.cjs.map +1 -0
  18. package/dist/index.d.cts +219 -0
  19. package/dist/index.d.ts +219 -0
  20. package/dist/index.js +1755 -0
  21. package/dist/index.js.map +1 -0
  22. package/package.json +90 -0
  23. package/src/browser.test.ts +431 -0
  24. package/src/browser.ts +554 -0
  25. package/src/config.test.ts +81 -0
  26. package/src/config.ts +95 -0
  27. package/src/constants.ts +184 -0
  28. package/src/float.test.ts +332 -0
  29. package/src/float.ts +231 -0
  30. package/src/fullpage.test.ts +224 -0
  31. package/src/fullpage.ts +126 -0
  32. package/src/iframe-auth.test.ts +338 -0
  33. package/src/iframe.test.ts +1152 -0
  34. package/src/iframe.ts +598 -0
  35. package/src/index.ts +74 -0
  36. package/src/loading.ts +90 -0
  37. package/src/popup.test.ts +344 -0
  38. package/src/popup.ts +157 -0
  39. package/src/slider.test.ts +277 -0
  40. package/src/slider.ts +158 -0
  41. package/src/styles.ts +395 -0
  42. package/src/triggers.test.ts +272 -0
  43. package/src/triggers.ts +127 -0
  44. package/src/types.ts +181 -0
  45. package/src/utils.test.ts +162 -0
  46. package/src/utils.ts +86 -0
  47. package/src/widget.test.ts +375 -0
  48. 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