@intentai/react 2.2.0 → 2.3.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 +315 -160
- package/dist/index.d.mts +297 -192
- package/dist/index.d.ts +297 -192
- package/dist/index.js +2 -2129
- package/dist/index.mjs +2 -2106
- package/package.json +21 -18
- package/dist/styles.css +0 -1047
package/README.md
CHANGED
|
@@ -1,252 +1,407 @@
|
|
|
1
|
-
# @
|
|
1
|
+
# @intentai/react
|
|
2
2
|
|
|
3
|
-
React
|
|
3
|
+
Official React SDK for [Intent AI](https://intent-ai.com) - AI-powered feedback collection widget.
|
|
4
4
|
|
|
5
5
|
## Installation
|
|
6
6
|
|
|
7
7
|
```bash
|
|
8
|
-
npm install @
|
|
8
|
+
npm install @intentai/react
|
|
9
9
|
# or
|
|
10
|
-
yarn add @
|
|
10
|
+
yarn add @intentai/react
|
|
11
11
|
# or
|
|
12
|
-
pnpm add @
|
|
12
|
+
pnpm add @intentai/react
|
|
13
13
|
```
|
|
14
14
|
|
|
15
15
|
## Quick Start
|
|
16
16
|
|
|
17
|
+
### 1. Get your Public Key
|
|
18
|
+
|
|
19
|
+
Get your public key (`pk_live_*` or `pk_test_*`) from the [Intent AI Dashboard](https://app.intent-ai.com/dashboard/settings).
|
|
20
|
+
|
|
21
|
+
### 2. Add the Provider
|
|
22
|
+
|
|
23
|
+
Wrap your app with `IntentAIProvider`:
|
|
24
|
+
|
|
17
25
|
```tsx
|
|
18
|
-
|
|
26
|
+
// app/layout.tsx (Next.js App Router)
|
|
27
|
+
import { IntentAIProvider } from '@intentai/react';
|
|
19
28
|
|
|
20
|
-
function
|
|
29
|
+
export default function RootLayout({ children }) {
|
|
21
30
|
return (
|
|
22
|
-
<
|
|
23
|
-
<
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
widgetUrl="https://your-app-url.com/widget/v1.js"
|
|
30
|
-
position="bottom-right"
|
|
31
|
-
theme="dark"
|
|
32
|
-
/>
|
|
33
|
-
</div>
|
|
31
|
+
<html>
|
|
32
|
+
<body>
|
|
33
|
+
<IntentAIProvider apiKey="pk_live_xxxxx">
|
|
34
|
+
{children}
|
|
35
|
+
</IntentAIProvider>
|
|
36
|
+
</body>
|
|
37
|
+
</html>
|
|
34
38
|
);
|
|
35
39
|
}
|
|
36
40
|
```
|
|
37
41
|
|
|
38
|
-
That's it! The widget will appear
|
|
42
|
+
That's it! The feedback widget will appear in the bottom-right corner.
|
|
39
43
|
|
|
40
|
-
|
|
44
|
+
## Environment Variables
|
|
41
45
|
|
|
42
|
-
|
|
46
|
+
The SDK automatically detects your API key from environment variables:
|
|
43
47
|
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
| `theme` | `'light' \| 'dark'` | `'light'` | Widget theme |
|
|
51
|
-
| `primaryColor` | `string` | `'#3B82F6'` | Primary color (hex) |
|
|
52
|
-
| `allowVoice` | `boolean` | `true` | Enable voice feedback |
|
|
53
|
-
| `allowText` | `boolean` | `true` | Enable text feedback |
|
|
54
|
-
| `allowScreenshot` | `boolean` | `true` | Enable screenshot capture |
|
|
55
|
-
| `customMetadata` | `object` | `{}` | Custom data to attach to feedback |
|
|
56
|
-
| `user` | `object` | `undefined` | User information |
|
|
48
|
+
```env
|
|
49
|
+
# Next.js
|
|
50
|
+
NEXT_PUBLIC_INTENT_AI_KEY=pk_live_xxxxx
|
|
51
|
+
|
|
52
|
+
# Create React App
|
|
53
|
+
REACT_APP_INTENT_AI_KEY=pk_live_xxxxx
|
|
57
54
|
|
|
58
|
-
|
|
55
|
+
# Vite
|
|
56
|
+
VITE_INTENT_AI_KEY=pk_live_xxxxx
|
|
57
|
+
```
|
|
59
58
|
|
|
60
|
-
|
|
59
|
+
With environment variables set, you can omit the `apiKey` prop:
|
|
61
60
|
|
|
62
61
|
```tsx
|
|
63
|
-
<
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
widgetUrl="https://your-app-url.com/widget/v1.js"
|
|
67
|
-
user={{
|
|
68
|
-
id: 'user-123',
|
|
69
|
-
email: 'user@example.com',
|
|
70
|
-
name: 'John Doe'
|
|
71
|
-
}}
|
|
72
|
-
/>
|
|
62
|
+
<IntentAIProvider>
|
|
63
|
+
{children}
|
|
64
|
+
</IntentAIProvider>
|
|
73
65
|
```
|
|
74
66
|
|
|
75
|
-
##
|
|
67
|
+
## Usage
|
|
76
68
|
|
|
77
|
-
|
|
69
|
+
### Basic Setup
|
|
78
70
|
|
|
79
71
|
```tsx
|
|
80
|
-
|
|
81
|
-
apiKey="your-api-key"
|
|
82
|
-
apiUrl="https://your-api-url.com"
|
|
83
|
-
widgetUrl="https://your-app-url.com/widget/v1.js"
|
|
84
|
-
customMetadata={{
|
|
85
|
-
page: 'checkout',
|
|
86
|
-
planType: 'premium',
|
|
87
|
-
version: '2.0.0'
|
|
88
|
-
}}
|
|
89
|
-
/>
|
|
90
|
-
```
|
|
72
|
+
import { IntentAIProvider } from '@intentai/react';
|
|
91
73
|
|
|
92
|
-
|
|
74
|
+
function App() {
|
|
75
|
+
return (
|
|
76
|
+
<IntentAIProvider
|
|
77
|
+
apiKey="pk_live_xxxxx"
|
|
78
|
+
position="bottom-right"
|
|
79
|
+
theme="auto"
|
|
80
|
+
>
|
|
81
|
+
<YourApp />
|
|
82
|
+
</IntentAIProvider>
|
|
83
|
+
);
|
|
84
|
+
}
|
|
85
|
+
```
|
|
93
86
|
|
|
94
|
-
|
|
87
|
+
### Custom Feedback Button
|
|
95
88
|
|
|
96
89
|
```tsx
|
|
97
|
-
import {
|
|
90
|
+
import { IntentAIProvider, FeedbackButton } from '@intentai/react';
|
|
98
91
|
|
|
99
92
|
function App() {
|
|
100
|
-
|
|
93
|
+
return (
|
|
94
|
+
<IntentAIProvider apiKey="pk_live_xxxxx" autoShow={false}>
|
|
95
|
+
<FeedbackButton className="btn btn-primary">
|
|
96
|
+
Send Feedback
|
|
97
|
+
</FeedbackButton>
|
|
98
|
+
</IntentAIProvider>
|
|
99
|
+
);
|
|
100
|
+
}
|
|
101
|
+
```
|
|
102
|
+
|
|
103
|
+
### Using the Hook
|
|
104
|
+
|
|
105
|
+
```tsx
|
|
106
|
+
import { useIntentAI } from '@intentai/react';
|
|
101
107
|
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
};
|
|
108
|
+
function MyComponent() {
|
|
109
|
+
const { open, close, isReady, error } = useIntentAI();
|
|
110
|
+
|
|
111
|
+
if (error) {
|
|
112
|
+
return <div>Failed to load feedback widget</div>;
|
|
113
|
+
}
|
|
109
114
|
|
|
110
115
|
return (
|
|
111
|
-
<
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
apiUrl="https://your-api-url.com"
|
|
115
|
-
widgetUrl="https://your-app-url.com/widget/v1.js"
|
|
116
|
-
/>
|
|
117
|
-
|
|
118
|
-
{/* Custom feedback button */}
|
|
119
|
-
<button onClick={open}>
|
|
120
|
-
Give Feedback
|
|
121
|
-
</button>
|
|
122
|
-
</div>
|
|
116
|
+
<button onClick={() => open()} disabled={!isReady}>
|
|
117
|
+
Give Feedback
|
|
118
|
+
</button>
|
|
123
119
|
);
|
|
124
120
|
}
|
|
125
121
|
```
|
|
126
122
|
|
|
127
|
-
|
|
123
|
+
### Identify Users
|
|
128
124
|
|
|
129
|
-
|
|
125
|
+
Using the `useIdentify` hook (recommended):
|
|
130
126
|
|
|
131
127
|
```tsx
|
|
132
|
-
|
|
133
|
-
|
|
128
|
+
import { useIdentify } from '@intentai/react';
|
|
129
|
+
|
|
130
|
+
function AuthenticatedApp({ user }) {
|
|
131
|
+
// Automatically identifies user when ready
|
|
132
|
+
useIdentify(user ? {
|
|
133
|
+
id: user.id,
|
|
134
|
+
email: user.email,
|
|
135
|
+
name: user.name,
|
|
136
|
+
plan: user.subscription.plan,
|
|
137
|
+
} : null);
|
|
138
|
+
|
|
139
|
+
return <YourApp />;
|
|
140
|
+
}
|
|
141
|
+
```
|
|
134
142
|
|
|
135
|
-
|
|
143
|
+
Using the `IdentifyUser` component:
|
|
144
|
+
|
|
145
|
+
```tsx
|
|
146
|
+
import { IntentAIProvider, IdentifyUser } from '@intentai/react';
|
|
147
|
+
|
|
148
|
+
function App({ user }) {
|
|
136
149
|
return (
|
|
137
|
-
<
|
|
138
|
-
<
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
</html>
|
|
150
|
+
<IntentAIProvider apiKey="pk_live_xxxxx">
|
|
151
|
+
<IdentifyUser user={{
|
|
152
|
+
id: user.id,
|
|
153
|
+
email: user.email,
|
|
154
|
+
name: user.name
|
|
155
|
+
}}>
|
|
156
|
+
<YourApp />
|
|
157
|
+
</IdentifyUser>
|
|
158
|
+
</IntentAIProvider>
|
|
147
159
|
);
|
|
148
160
|
}
|
|
149
161
|
```
|
|
150
162
|
|
|
151
|
-
|
|
163
|
+
Or using the hook directly:
|
|
164
|
+
|
|
165
|
+
```tsx
|
|
166
|
+
import { useIntentAI } from '@intentai/react';
|
|
167
|
+
|
|
168
|
+
function AuthenticatedApp({ user }) {
|
|
169
|
+
const { identify, isReady } = useIntentAI();
|
|
170
|
+
|
|
171
|
+
useEffect(() => {
|
|
172
|
+
if (isReady && user) {
|
|
173
|
+
identify({
|
|
174
|
+
id: user.id,
|
|
175
|
+
email: user.email,
|
|
176
|
+
name: user.name,
|
|
177
|
+
plan: user.subscription.plan, // Custom properties
|
|
178
|
+
});
|
|
179
|
+
}
|
|
180
|
+
}, [isReady, user]);
|
|
181
|
+
|
|
182
|
+
return <YourApp />;
|
|
183
|
+
}
|
|
184
|
+
```
|
|
185
|
+
|
|
186
|
+
### Add Metadata
|
|
187
|
+
|
|
188
|
+
```tsx
|
|
189
|
+
import { SetMetadata } from '@intentai/react';
|
|
190
|
+
|
|
191
|
+
function PricingPage() {
|
|
192
|
+
return (
|
|
193
|
+
<SetMetadata metadata={{ page: 'pricing', feature: 'comparison' }}>
|
|
194
|
+
<PricingContent />
|
|
195
|
+
</SetMetadata>
|
|
196
|
+
);
|
|
197
|
+
}
|
|
152
198
|
```
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
199
|
+
|
|
200
|
+
Or using the hook:
|
|
201
|
+
|
|
202
|
+
```tsx
|
|
203
|
+
const { setMetadata } = useIntentAI();
|
|
204
|
+
|
|
205
|
+
useEffect(() => {
|
|
206
|
+
setMetadata({
|
|
207
|
+
page: window.location.pathname,
|
|
208
|
+
viewport: `${window.innerWidth}x${window.innerHeight}`
|
|
209
|
+
});
|
|
210
|
+
}, []);
|
|
156
211
|
```
|
|
157
212
|
|
|
158
|
-
|
|
213
|
+
### Track Events
|
|
214
|
+
|
|
215
|
+
Using the `TrackEvent` component:
|
|
159
216
|
|
|
160
217
|
```tsx
|
|
161
|
-
|
|
162
|
-
import { IntentAIWidget } from '@intent-ai/react';
|
|
218
|
+
import { TrackEvent } from '@intentai/react';
|
|
163
219
|
|
|
164
|
-
|
|
220
|
+
function CheckoutPage() {
|
|
165
221
|
return (
|
|
166
|
-
|
|
167
|
-
<
|
|
168
|
-
|
|
169
|
-
apiKey={process.env.NEXT_PUBLIC_INTENT_AI_KEY!}
|
|
170
|
-
apiUrl={process.env.NEXT_PUBLIC_INTENT_AI_API_URL!}
|
|
171
|
-
widgetUrl={process.env.NEXT_PUBLIC_INTENT_AI_WIDGET_URL!}
|
|
172
|
-
/>
|
|
173
|
-
</>
|
|
222
|
+
<TrackEvent event="checkout_viewed" properties={{ items: 3 }}>
|
|
223
|
+
<CheckoutContent />
|
|
224
|
+
</TrackEvent>
|
|
174
225
|
);
|
|
175
226
|
}
|
|
176
227
|
```
|
|
177
228
|
|
|
178
|
-
|
|
229
|
+
Using the hook:
|
|
179
230
|
|
|
180
231
|
```tsx
|
|
181
|
-
|
|
182
|
-
|
|
232
|
+
const { track } = useIntentAI();
|
|
233
|
+
|
|
234
|
+
function handlePurchase(item) {
|
|
235
|
+
track('purchase', {
|
|
236
|
+
itemId: item.id,
|
|
237
|
+
price: item.price
|
|
238
|
+
});
|
|
239
|
+
}
|
|
240
|
+
```
|
|
241
|
+
|
|
242
|
+
### Custom Trigger with FeedbackTrigger
|
|
243
|
+
|
|
244
|
+
```tsx
|
|
245
|
+
import { FeedbackTrigger } from '@intentai/react';
|
|
183
246
|
|
|
184
247
|
function App() {
|
|
185
248
|
return (
|
|
186
|
-
<
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
</div>
|
|
249
|
+
<FeedbackTrigger>
|
|
250
|
+
{({ open, isReady }) => (
|
|
251
|
+
<MyCustomButton onClick={() => open()} disabled={!isReady}>
|
|
252
|
+
Feedback
|
|
253
|
+
</MyCustomButton>
|
|
254
|
+
)}
|
|
255
|
+
</FeedbackTrigger>
|
|
194
256
|
);
|
|
195
257
|
}
|
|
196
258
|
```
|
|
197
259
|
|
|
198
|
-
|
|
260
|
+
### Pre-fill Feedback
|
|
261
|
+
|
|
262
|
+
```tsx
|
|
263
|
+
const { open } = useIntentAI();
|
|
264
|
+
|
|
265
|
+
// Open with pre-selected type and prefilled text
|
|
266
|
+
open({
|
|
267
|
+
type: 'bug',
|
|
268
|
+
prefill: { text: 'I found an issue with...' },
|
|
269
|
+
metadata: { page: 'checkout' }
|
|
270
|
+
});
|
|
199
271
|
```
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
|
|
272
|
+
|
|
273
|
+
## Configuration
|
|
274
|
+
|
|
275
|
+
### IntentAIProvider Props
|
|
276
|
+
|
|
277
|
+
| Prop | Type | Default | Description |
|
|
278
|
+
|------|------|---------|-------------|
|
|
279
|
+
| `apiKey` | `string` | - | Your Intent AI public key (or use env vars) |
|
|
280
|
+
| `position` | `'bottom-right' \| 'bottom-left' \| 'top-right' \| 'top-left'` | `'bottom-right'` | Widget position |
|
|
281
|
+
| `theme` | `'light' \| 'dark' \| 'auto'` | `'auto'` | Color theme |
|
|
282
|
+
| `primaryColor` | `string` | `'#6366f1'` | Primary brand color (hex) |
|
|
283
|
+
| `autoShow` | `boolean` | `true` | Show widget button automatically |
|
|
284
|
+
| `user` | `UserIdentity` | - | Initial user identification |
|
|
285
|
+
| `metadata` | `Record<string, unknown>` | - | Custom metadata |
|
|
286
|
+
| `onReady` | `() => void` | - | Called when widget is ready |
|
|
287
|
+
| `onOpen` | `() => void` | - | Called when widget opens |
|
|
288
|
+
| `onClose` | `() => void` | - | Called when widget closes |
|
|
289
|
+
| `onSubmit` | `(data: FeedbackData) => void` | - | Called on feedback submission |
|
|
290
|
+
| `onError` | `(error: Error) => void` | - | Called on errors |
|
|
291
|
+
|
|
292
|
+
### useIntentAI Hook
|
|
293
|
+
|
|
294
|
+
```tsx
|
|
295
|
+
const {
|
|
296
|
+
isReady, // boolean - Widget loaded and ready
|
|
297
|
+
error, // Error | null - Error if widget failed to load
|
|
298
|
+
open, // (options?: OpenOptions) => void - Open the widget
|
|
299
|
+
close, // () => void - Close the widget
|
|
300
|
+
identify, // (user: UserIdentity) => void - Identify user
|
|
301
|
+
setMetadata,// (data: Record<string, unknown>) => void - Set metadata
|
|
302
|
+
track, // (event: string, properties?: Record<string, unknown>) => void - Track event
|
|
303
|
+
} = useIntentAI();
|
|
203
304
|
```
|
|
204
305
|
|
|
205
|
-
|
|
306
|
+
### useIdentify Hook
|
|
206
307
|
|
|
207
308
|
```tsx
|
|
208
|
-
|
|
209
|
-
|
|
210
|
-
|
|
211
|
-
|
|
212
|
-
|
|
213
|
-
|
|
214
|
-
|
|
215
|
-
|
|
216
|
-
|
|
309
|
+
// Automatically identifies user when widget is ready
|
|
310
|
+
useIdentify({
|
|
311
|
+
id: 'user_123',
|
|
312
|
+
email: 'user@example.com',
|
|
313
|
+
name: 'John Doe',
|
|
314
|
+
plan: 'pro',
|
|
315
|
+
company: 'Acme Inc',
|
|
316
|
+
});
|
|
317
|
+
|
|
318
|
+
// Pass null to skip identification
|
|
319
|
+
useIdentify(user ? { id: user.id, email: user.email } : null);
|
|
217
320
|
```
|
|
218
321
|
|
|
219
|
-
|
|
322
|
+
### OpenOptions
|
|
323
|
+
|
|
324
|
+
```tsx
|
|
325
|
+
interface OpenOptions {
|
|
326
|
+
type?: 'bug' | 'feature' | 'question' | 'praise' | 'other';
|
|
327
|
+
prefill?: { text?: string };
|
|
328
|
+
metadata?: Record<string, unknown>;
|
|
329
|
+
}
|
|
330
|
+
```
|
|
220
331
|
|
|
221
|
-
|
|
332
|
+
### UserIdentity
|
|
222
333
|
|
|
223
334
|
```tsx
|
|
224
|
-
|
|
335
|
+
interface UserIdentity {
|
|
336
|
+
id: string; // Required
|
|
337
|
+
email?: string;
|
|
338
|
+
name?: string;
|
|
339
|
+
avatar?: string;
|
|
340
|
+
plan?: string;
|
|
341
|
+
company?: string;
|
|
342
|
+
[key: string]: string | number | boolean | undefined; // Custom properties
|
|
343
|
+
}
|
|
344
|
+
```
|
|
225
345
|
|
|
226
|
-
|
|
227
|
-
id: '123',
|
|
228
|
-
email: 'user@example.com',
|
|
229
|
-
name: 'John'
|
|
230
|
-
};
|
|
346
|
+
## Next.js App Router
|
|
231
347
|
|
|
232
|
-
|
|
233
|
-
|
|
234
|
-
|
|
235
|
-
|
|
236
|
-
|
|
348
|
+
The SDK is fully compatible with Next.js App Router and Server Components:
|
|
349
|
+
|
|
350
|
+
```tsx
|
|
351
|
+
// app/providers.tsx
|
|
352
|
+
'use client';
|
|
353
|
+
|
|
354
|
+
import { IntentAIProvider } from '@intentai/react';
|
|
355
|
+
|
|
356
|
+
export function Providers({ children }) {
|
|
357
|
+
return (
|
|
358
|
+
<IntentAIProvider>
|
|
359
|
+
{children}
|
|
360
|
+
</IntentAIProvider>
|
|
361
|
+
);
|
|
362
|
+
}
|
|
363
|
+
|
|
364
|
+
// app/layout.tsx
|
|
365
|
+
import { Providers } from './providers';
|
|
366
|
+
|
|
367
|
+
export default function RootLayout({ children }) {
|
|
368
|
+
return (
|
|
369
|
+
<html>
|
|
370
|
+
<body>
|
|
371
|
+
<Providers>{children}</Providers>
|
|
372
|
+
</body>
|
|
373
|
+
</html>
|
|
374
|
+
);
|
|
375
|
+
}
|
|
237
376
|
```
|
|
238
377
|
|
|
239
|
-
##
|
|
378
|
+
## TypeScript
|
|
379
|
+
|
|
380
|
+
Full TypeScript support with exported types:
|
|
240
381
|
|
|
241
|
-
|
|
242
|
-
|
|
243
|
-
|
|
382
|
+
```tsx
|
|
383
|
+
import type {
|
|
384
|
+
UserIdentity,
|
|
385
|
+
IntentAIConfig,
|
|
386
|
+
FeedbackData,
|
|
387
|
+
OpenOptions,
|
|
388
|
+
FeedbackType,
|
|
389
|
+
} from '@intentai/react';
|
|
390
|
+
|
|
391
|
+
const user: UserIdentity = {
|
|
392
|
+
id: '123',
|
|
393
|
+
email: 'user@example.com',
|
|
394
|
+
name: 'John Doe',
|
|
395
|
+
};
|
|
396
|
+
```
|
|
244
397
|
|
|
245
|
-
## Support
|
|
398
|
+
## Browser Support
|
|
246
399
|
|
|
247
|
-
-
|
|
248
|
-
-
|
|
400
|
+
- Chrome (latest)
|
|
401
|
+
- Firefox (latest)
|
|
402
|
+
- Safari (latest)
|
|
403
|
+
- Edge (latest)
|
|
249
404
|
|
|
250
405
|
## License
|
|
251
406
|
|
|
252
|
-
MIT
|
|
407
|
+
MIT © [Intent AI](https://intent-ai.com)
|