@bliptarjs/sdk 0.1.0 → 0.2.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
  # @bliptarjs/sdk
2
2
 
3
- Lightweight SDK for collecting in-app user feedback. Designed to be small (~5KB gzipped) and non-intrusive.
3
+ Lightweight SDK for collecting in-app user feedback. Designed to be small (~7KB gzipped) and non-intrusive.
4
4
 
5
5
  ## Installation
6
6
 
@@ -8,123 +8,560 @@ Lightweight SDK for collecting in-app user feedback. Designed to be small (~5KB
8
8
  npm install @bliptarjs/sdk
9
9
  ```
10
10
 
11
+ ```bash
12
+ yarn add @bliptarjs/sdk
13
+ ```
14
+
15
+ ```bash
16
+ pnpm add @bliptarjs/sdk
17
+ ```
18
+
11
19
  ## Quick Start
12
20
 
13
21
  ```javascript
14
22
  import { createBliptar } from '@bliptarjs/sdk';
15
23
 
16
- const blip = createBliptar({
24
+ const bliptar = createBliptar({
17
25
  apiKey: 'your-api-key',
18
26
  });
19
27
 
20
- blip.init();
28
+ bliptar.init();
21
29
  ```
22
30
 
23
- ## Usage
31
+ That's it! The SDK will automatically track page views and display forms based on your campaign rules configured in the Bliptar dashboard.
24
32
 
25
- ### Initialize
33
+ ## Core Concepts
26
34
 
27
- ```javascript
35
+ Bliptar uses **campaigns** to determine when to show feedback forms. Campaigns can be triggered by:
36
+
37
+ - **Page View** - When a user visits a page
38
+ - **Button Click** - When a user clicks a specific element
39
+ - **Scroll Depth** - When a user scrolls to a certain percentage
40
+ - **Time on Page** - After a user spends time on a page
41
+ - **Exit Intent** - When a user is about to leave
42
+ - **Custom Events** - Triggered programmatically via SDK
43
+
44
+ ## API Reference
45
+
46
+ ### `createBliptar(config)`
47
+
48
+ Creates a new Bliptar instance.
49
+
50
+ ```typescript
28
51
  import { createBliptar } from '@bliptarjs/sdk';
29
52
 
30
- const blip = createBliptar({
53
+ const bliptar = createBliptar({
31
54
  apiKey: 'your-api-key',
32
- apiUrl: 'https://api.bliptar.com', // optional, defaults to production
33
- debug: false, // optional, enables console logging
55
+ apiUrl: 'https://api.bliptar.com', // optional
56
+ debug: false, // optional
57
+ userId: 'user-123', // optional
58
+ userAttributes: { plan: 'pro' }, // optional
59
+ onShow: (form) => console.log('Showing form:', form.formId),
60
+ onSubmit: (answers) => console.log('Submitted:', answers),
61
+ onDismiss: () => console.log('Form dismissed'),
62
+ onError: (error) => console.error('Error:', error),
34
63
  });
64
+ ```
65
+
66
+ #### Configuration Options
67
+
68
+ | Option | Type | Default | Description |
69
+ |--------|------|---------|-------------|
70
+ | `apiKey` | `string` | **required** | Your Bliptar API key |
71
+ | `apiUrl` | `string` | `https://api.bliptar.com` | API endpoint URL |
72
+ | `debug` | `boolean` | `false` | Enable console logging for debugging |
73
+ | `userId` | `string` | - | Pre-set user ID for attribution |
74
+ | `userAttributes` | `object` | - | Pre-set user attributes for targeting |
75
+ | `onShow` | `function` | - | Callback when a form is displayed |
76
+ | `onSubmit` | `function` | - | Callback when a response is submitted |
77
+ | `onDismiss` | `function` | - | Callback when a form is dismissed |
78
+ | `onError` | `function` | - | Callback when an error occurs |
35
79
 
36
- blip.init();
80
+ ---
81
+
82
+ ### `init()`
83
+
84
+ Initializes the SDK. This sets up event listeners and triggers a `page_view` event.
85
+
86
+ ```javascript
87
+ bliptar.init();
37
88
  ```
38
89
 
39
- ### Identify Users
90
+ > **Note:** Call this once after creating the instance, typically when your app loads.
91
+
92
+ ---
40
93
 
41
- Associate feedback with specific users:
94
+ ### `identify(userId, attributes?)`
95
+
96
+ Associates feedback with a specific user. Call this when a user logs in.
42
97
 
43
98
  ```javascript
44
- blip.identify('user-123', {
99
+ // Basic identification
100
+ bliptar.identify('user-123');
101
+
102
+ // With attributes for targeting
103
+ bliptar.identify('user-123', {
104
+ email: 'user@example.com',
45
105
  plan: 'pro',
46
106
  company: 'Acme Inc',
107
+ signupDate: '2024-01-15',
47
108
  });
48
109
  ```
49
110
 
50
- ### Track Events
111
+ User attributes can be used in campaign targeting rules (e.g., only show to "pro" plan users).
112
+
113
+ ---
51
114
 
52
- Track events that may trigger feedback forms:
115
+ ### `track(event, data?)`
116
+
117
+ Tracks a custom event that may trigger a feedback form.
53
118
 
54
119
  ```javascript
55
- blip.track('checkout_complete', {
120
+ // Simple event
121
+ bliptar.track('checkout_complete');
122
+
123
+ // With event data
124
+ bliptar.track('checkout_complete', {
56
125
  orderId: 'order-456',
57
126
  total: 99.99,
127
+ items: 3,
128
+ });
129
+
130
+ // Feature usage
131
+ bliptar.track('feature_used', {
132
+ feature: 'export_pdf',
133
+ duration: 5000,
58
134
  });
59
135
  ```
60
136
 
61
- ### Show Forms Manually
137
+ Configure campaigns in the dashboard to trigger forms based on these events.
138
+
139
+ ---
140
+
141
+ ### `trackClicks(options)`
62
142
 
63
- Display a specific form programmatically:
143
+ Sets up click tracking on specific elements. When a user clicks a matching element, it fires a `button_click` event that can trigger campaigns.
64
144
 
65
145
  ```javascript
66
- await blip.showForm('form-id');
146
+ // Track clicks on a specific button
147
+ bliptar.trackClicks({
148
+ selector: '#upgrade-button',
149
+ name: 'upgrade-cta',
150
+ });
151
+
152
+ // Track clicks on all pricing buttons
153
+ bliptar.trackClicks({
154
+ selector: '.pricing-cta',
155
+ name: 'pricing-click',
156
+ });
157
+
158
+ // Track only the first click
159
+ bliptar.trackClicks({
160
+ selector: '.signup-button',
161
+ name: 'signup-click',
162
+ once: true,
163
+ });
67
164
  ```
68
165
 
69
- ### Lifecycle Callbacks
166
+ #### Options
167
+
168
+ | Option | Type | Default | Description |
169
+ |--------|------|---------|-------------|
170
+ | `selector` | `string` | **required** | CSS selector for elements to track |
171
+ | `name` | `string` | `selector` | Friendly name for the click target |
172
+ | `once` | `boolean` | `false` | Only track the first click per session |
173
+
174
+ #### Event Data Sent
175
+
176
+ When a click is detected, the following data is sent:
70
177
 
71
178
  ```javascript
72
- const blip = createBliptar({
73
- apiKey: 'your-api-key',
74
- onShow: (form) => {
75
- console.log('Form displayed:', form.formId);
76
- },
179
+ {
180
+ selector: '.pricing-cta',
181
+ name: 'pricing-click',
182
+ element_text: 'Get Started',
183
+ element_id: 'cta-btn',
184
+ element_class: 'pricing-cta btn-primary'
185
+ }
186
+ ```
187
+
188
+ ---
189
+
190
+ ### `enableExitIntent(options?)`
191
+
192
+ Enables exit intent detection. Triggers an `exit_intent` event when a user appears to be leaving the page.
193
+
194
+ ```javascript
195
+ // Basic usage (triggers once per session)
196
+ bliptar.enableExitIntent();
197
+
198
+ // Custom configuration
199
+ bliptar.enableExitIntent({
200
+ threshold: 50, // Pixels from top of viewport
201
+ cooldown: 10000, // Ms before can trigger again
202
+ once: true, // Only trigger once per session
203
+ });
204
+ ```
205
+
206
+ #### Options
207
+
208
+ | Option | Type | Default | Description |
209
+ |--------|------|---------|-------------|
210
+ | `threshold` | `number` | `50` | Distance in pixels from top of viewport to trigger |
211
+ | `cooldown` | `number` | `10000` | Milliseconds before exit intent can trigger again |
212
+ | `once` | `boolean` | `true` | Only trigger once per session |
213
+
214
+ #### How It Works
215
+
216
+ - **Desktop:** Detects when the mouse cursor leaves the viewport from the top (user moving to close tab, click back, or navigate away)
217
+ - **Mobile:** Detects when the page visibility changes (user switching apps or tabs)
218
+
219
+ ---
220
+
221
+ ### `showForm(formId)`
222
+
223
+ Manually displays a specific form, bypassing campaign rules.
224
+
225
+ ```javascript
226
+ // Show a form programmatically
227
+ await bliptar.showForm('form_abc123');
228
+
229
+ // Example: Show after completing onboarding
230
+ function completeOnboarding() {
231
+ // ... onboarding logic
232
+ bliptar.showForm('form_onboarding_feedback');
233
+ }
234
+ ```
235
+
236
+ ---
237
+
238
+ ### `destroy()`
239
+
240
+ Removes all event listeners and cleans up the SDK. Call this when unmounting your app or when done collecting feedback.
241
+
242
+ ```javascript
243
+ bliptar.destroy();
244
+ ```
245
+
246
+ ---
247
+
248
+ ## Usage Examples
249
+
250
+ ### Basic Setup
251
+
252
+ ```javascript
253
+ import { createBliptar } from '@bliptarjs/sdk';
254
+
255
+ const bliptar = createBliptar({
256
+ apiKey: 'blip_live_xxxxxxxx',
257
+ });
258
+
259
+ bliptar.init();
260
+ ```
261
+
262
+ ### With User Identification
263
+
264
+ ```javascript
265
+ import { createBliptar } from '@bliptarjs/sdk';
266
+
267
+ const bliptar = createBliptar({
268
+ apiKey: 'blip_live_xxxxxxxx',
269
+ });
270
+
271
+ bliptar.init();
272
+
273
+ // When user logs in
274
+ function onUserLogin(user) {
275
+ bliptar.identify(user.id, {
276
+ email: user.email,
277
+ plan: user.subscription.plan,
278
+ createdAt: user.createdAt,
279
+ });
280
+ }
281
+ ```
282
+
283
+ ### E-commerce Checkout Feedback
284
+
285
+ ```javascript
286
+ import { createBliptar } from '@bliptarjs/sdk';
287
+
288
+ const bliptar = createBliptar({
289
+ apiKey: 'blip_live_xxxxxxxx',
77
290
  onSubmit: (answers) => {
78
- console.log('Response submitted:', answers);
79
- },
80
- onDismiss: () => {
81
- console.log('Form dismissed');
82
- },
83
- onError: (error) => {
84
- console.error('Error:', error);
291
+ // Send to your analytics
292
+ analytics.track('feedback_submitted', answers);
85
293
  },
86
294
  });
295
+
296
+ bliptar.init();
297
+
298
+ // Track successful purchase
299
+ function onPurchaseComplete(order) {
300
+ bliptar.track('purchase_complete', {
301
+ orderId: order.id,
302
+ total: order.total,
303
+ itemCount: order.items.length,
304
+ });
305
+ }
87
306
  ```
88
307
 
89
- ### Cleanup
308
+ ### Exit Intent Survey
309
+
310
+ ```javascript
311
+ import { createBliptar } from '@bliptarjs/sdk';
312
+
313
+ const bliptar = createBliptar({
314
+ apiKey: 'blip_live_xxxxxxxx',
315
+ });
316
+
317
+ bliptar.init();
90
318
 
91
- Remove event listeners and clean up when done:
319
+ // Enable exit intent on pricing page
320
+ if (window.location.pathname === '/pricing') {
321
+ bliptar.enableExitIntent({
322
+ once: true, // Only show once
323
+ });
324
+ }
325
+ ```
326
+
327
+ ### Button Click Feedback
92
328
 
93
329
  ```javascript
94
- blip.destroy();
330
+ import { createBliptar } from '@bliptarjs/sdk';
331
+
332
+ const bliptar = createBliptar({
333
+ apiKey: 'blip_live_xxxxxxxx',
334
+ });
335
+
336
+ bliptar.init();
337
+
338
+ // Track clicks on upgrade buttons
339
+ bliptar.trackClicks({
340
+ selector: '[data-track="upgrade"]',
341
+ name: 'upgrade-button',
342
+ });
343
+
344
+ // Track clicks on help buttons
345
+ bliptar.trackClicks({
346
+ selector: '.help-button',
347
+ name: 'help-click',
348
+ });
95
349
  ```
96
350
 
97
- ## Configuration
351
+ ### React Integration
98
352
 
99
- | Option | Type | Default | Description |
100
- |--------|------|---------|-------------|
101
- | `apiKey` | `string` | required | Your Bliptar API key |
102
- | `apiUrl` | `string` | `https://api.bliptar.com` | API endpoint |
103
- | `debug` | `boolean` | `false` | Enable debug logging |
104
- | `userId` | `string` | - | Pre-set user ID |
105
- | `userAttributes` | `object` | - | Pre-set user attributes |
353
+ ```jsx
354
+ import { useEffect } from 'react';
355
+ import { createBliptar } from '@bliptarjs/sdk';
356
+
357
+ const bliptar = createBliptar({
358
+ apiKey: 'blip_live_xxxxxxxx',
359
+ });
360
+
361
+ function App() {
362
+ useEffect(() => {
363
+ bliptar.init();
364
+
365
+ return () => {
366
+ bliptar.destroy();
367
+ };
368
+ }, []);
369
+
370
+ return <div>Your app</div>;
371
+ }
372
+
373
+ // In a component that needs to identify users
374
+ function UserProfile({ user }) {
375
+ useEffect(() => {
376
+ if (user) {
377
+ bliptar.identify(user.id, {
378
+ email: user.email,
379
+ plan: user.plan,
380
+ });
381
+ }
382
+ }, [user]);
383
+
384
+ return <div>Welcome, {user.name}</div>;
385
+ }
386
+ ```
387
+
388
+ ### Next.js Integration
389
+
390
+ ```jsx
391
+ // lib/bliptar.js
392
+ import { createBliptar } from '@bliptarjs/sdk';
393
+
394
+ export const bliptar = typeof window !== 'undefined'
395
+ ? createBliptar({ apiKey: process.env.NEXT_PUBLIC_BLIPTAR_API_KEY })
396
+ : null;
397
+
398
+ // app/layout.js or pages/_app.js
399
+ 'use client';
400
+
401
+ import { useEffect } from 'react';
402
+ import { bliptar } from '@/lib/bliptar';
403
+
404
+ export default function RootLayout({ children }) {
405
+ useEffect(() => {
406
+ bliptar?.init();
407
+
408
+ return () => {
409
+ bliptar?.destroy();
410
+ };
411
+ }, []);
412
+
413
+ return (
414
+ <html>
415
+ <body>{children}</body>
416
+ </html>
417
+ );
418
+ }
419
+ ```
420
+
421
+ ### Vue Integration
422
+
423
+ ```vue
424
+ <script setup>
425
+ import { onMounted, onUnmounted } from 'vue';
426
+ import { createBliptar } from '@bliptarjs/sdk';
427
+
428
+ const bliptar = createBliptar({
429
+ apiKey: 'blip_live_xxxxxxxx',
430
+ });
431
+
432
+ onMounted(() => {
433
+ bliptar.init();
434
+ });
435
+
436
+ onUnmounted(() => {
437
+ bliptar.destroy();
438
+ });
439
+ </script>
440
+ ```
441
+
442
+ ---
443
+
444
+ ## Automatic Tracking
445
+
446
+ The SDK automatically tracks the following without any additional code:
447
+
448
+ | Data | Description |
449
+ |------|-------------|
450
+ | `page_view` | Fired on `init()` |
451
+ | `scroll_depth` | Percentage scrolled (0-100%) |
452
+ | `time_on_page` | Seconds spent on page |
453
+ | `device_type` | `desktop`, `mobile`, or `tablet` |
454
+ | `page_url` | Current page URL |
455
+ | `referrer` | Previous page URL |
456
+
457
+ This data is sent with every trigger request and can be used in campaign conditions.
458
+
459
+ ---
106
460
 
107
461
  ## Form Types
108
462
 
109
463
  The SDK supports multiple feedback form types:
110
464
 
111
- - **Binary** - Thumbs up/down, Yes/No
112
- - **Star Rating** - 1-5 star ratings
113
- - **Emoji Scale** - 3 or 5 point emoji scales
114
- - **NPS** - Net Promoter Score (0-10)
115
- - **Single Choice** - Multiple choice questions
116
- - **Text Input** - Free-form text responses
465
+ | Type | Description |
466
+ |------|-------------|
467
+ | **Binary** | Thumbs up/down, Yes/No questions |
468
+ | **Star Rating** | 1-5 star ratings with optional half stars |
469
+ | **Emoji Scale** | 3 or 5 point emoji scales |
470
+ | **NPS** | Net Promoter Score (0-10) |
471
+ | **Single Choice** | Multiple choice questions |
472
+ | **Text Input** | Free-form text responses |
473
+
474
+ Forms are configured in the Bliptar dashboard and automatically rendered by the SDK.
475
+
476
+ ---
477
+
478
+ ## TypeScript Support
479
+
480
+ The SDK is written in TypeScript and includes full type definitions.
481
+
482
+ ```typescript
483
+ import {
484
+ createBliptar,
485
+ BliptarInstance,
486
+ BliptarConfig,
487
+ ClickTrackingOptions,
488
+ ExitIntentOptions,
489
+ } from '@bliptarjs/sdk';
490
+
491
+ const config: BliptarConfig = {
492
+ apiKey: 'blip_live_xxxxxxxx',
493
+ debug: true,
494
+ onSubmit: (answers) => {
495
+ console.log(answers);
496
+ },
497
+ };
498
+
499
+ const bliptar: BliptarInstance = createBliptar(config);
500
+
501
+ // Type-safe click tracking
502
+ const clickOptions: ClickTrackingOptions = {
503
+ selector: '.cta-button',
504
+ name: 'main-cta',
505
+ once: true,
506
+ };
507
+ bliptar.trackClicks(clickOptions);
508
+
509
+ // Type-safe exit intent
510
+ const exitOptions: ExitIntentOptions = {
511
+ threshold: 50,
512
+ once: true,
513
+ };
514
+ bliptar.enableExitIntent(exitOptions);
515
+ ```
516
+
517
+ ---
117
518
 
118
519
  ## Browser Support
119
520
 
120
- - Chrome (latest)
121
- - Firefox (latest)
122
- - Safari (latest)
123
- - Edge (latest)
521
+ | Browser | Supported |
522
+ |---------|-----------|
523
+ | Chrome | Latest 2 versions |
524
+ | Firefox | Latest 2 versions |
525
+ | Safari | Latest 2 versions |
526
+ | Edge | Latest 2 versions |
527
+
528
+ ---
124
529
 
125
530
  ## Bundle Size
126
531
 
127
- ~7KB gzipped
532
+ - **ESM:** ~25KB (minified)
533
+ - **Gzipped:** ~7KB
534
+
535
+ The SDK has zero dependencies.
536
+
537
+ ---
538
+
539
+ ## Troubleshooting
540
+
541
+ ### Forms not showing?
542
+
543
+ 1. **Check your API key** - Ensure it's valid and for the correct environment
544
+ 2. **Check campaign rules** - Verify your campaign is active and targeting rules match
545
+ 3. **Enable debug mode** - Set `debug: true` to see console logs
546
+ 4. **Check throttling** - Campaigns have frequency limits to avoid annoying users
547
+
548
+ ### Debug Mode
549
+
550
+ ```javascript
551
+ const bliptar = createBliptar({
552
+ apiKey: 'blip_live_xxxxxxxx',
553
+ debug: true, // Enables console logging
554
+ });
555
+ ```
556
+
557
+ This will log:
558
+ - SDK initialization
559
+ - Events being tracked
560
+ - Form display triggers
561
+ - API responses
562
+ - Errors
563
+
564
+ ---
128
565
 
129
566
  ## License
130
567
 
package/dist/index.cjs CHANGED
@@ -1,4 +1,4 @@
1
- "use strict";var _=Object.defineProperty;var I=Object.getOwnPropertyDescriptor;var L=Object.getOwnPropertyNames;var P=Object.prototype.hasOwnProperty;var A=(i,r)=>{for(var t in r)_(i,t,{get:r[t],enumerable:!0})},j=(i,r,t,e)=>{if(r&&typeof r=="object"||typeof r=="function")for(let a of L(r))!P.call(i,a)&&a!==t&&_(i,a,{get:()=>r[a],enumerable:!(e=I(r,a))||e.enumerable});return i};var B=i=>j(_({},"__esModule",{value:!0}),i);var Y={};A(Y,{Bliptar:()=>b,createBliptar:()=>y});module.exports=B(Y);var u={mode:"light",backgroundColor:"#ffffff",surfaceColor:"#f5f5f5",textPrimary:"#1a1a1a",textSecondary:"#666666",primaryColor:"#3b82f6",primaryHover:"#2563eb",borderColor:"#e0e0e0",shadowColor:"rgba(0, 0, 0, 0.15)",starColor:"#fbbf24"},h={mode:"dark",backgroundColor:"#1a1a1a",surfaceColor:"#2a2a2a",textPrimary:"#ffffff",textSecondary:"#a0a0a0",primaryColor:"#3b82f6",primaryHover:"#60a5fa",borderColor:"#333333",shadowColor:"rgba(0, 0, 0, 0.4)",starColor:"#fbbf24"};function D(i,r){try{let e=window.getComputedStyle(i).getPropertyValue(r);return e&&e!=="rgba(0, 0, 0, 0)"?e:null}catch{return null}}function H(i){try{return getComputedStyle(document.documentElement).getPropertyValue(i).trim()||null}catch{return null}}function k(i){let r=i.match(/^#?([a-f\d]{2})([a-f\d]{2})([a-f\d]{2})$/i);if(r)return{r:parseInt(r[1],16),g:parseInt(r[2],16),b:parseInt(r[3],16)};let t=i.match(/rgba?\((\d+),\s*(\d+),\s*(\d+)/);return t?{r:parseInt(t[1],10),g:parseInt(t[2],10),b:parseInt(t[3],10)}:null}function z(i,r,t){let[e,a,s]=[i,r,t].map(o=>(o=o/255,o<=.03928?o/12.92:Math.pow((o+.055)/1.055,2.4)));return .2126*e+.7152*a+.0722*s}function v(i){let r=k(i);return r?z(r.r,r.g,r.b)<.5:!1}function f(i,r){let t=k(i);if(!t)return i;let e=a=>Math.min(255,Math.max(0,Math.round(a+r/100*255)));return`rgb(${e(t.r)}, ${e(t.g)}, ${e(t.b)})`}function M(i){return v(i)?"#ffffff":"#1a1a1a"}function R(i,r){let t={},e=null;i&&(e=document.querySelector(i)),e||(e=document.body);let a=D(e,"background-color");if(a){let s=v(a);t.mode=s?"dark":"light",t.backgroundColor=a,t.surfaceColor=f(a,s?10:-5),t.textPrimary=M(a),t.textSecondary=f(t.textPrimary,s?-30:30),t.borderColor=f(a,s?20:-15),t.shadowColor=s?"rgba(0, 0, 0, 0.4)":"rgba(0, 0, 0, 0.15)"}if(r){let s={"--primary":"primaryColor","--primary-color":"primaryColor","--accent":"primaryColor","--accent-color":"primaryColor","--brand":"primaryColor","--brand-color":"primaryColor","--color-primary":"primaryColor","--background":"backgroundColor","--bg":"backgroundColor","--bg-color":"backgroundColor","--text":"textPrimary","--text-color":"textPrimary","--foreground":"textPrimary","--border":"borderColor","--border-color":"borderColor"};for(let[o,p]of Object.entries(s)){let c=H(o);c&&(t[p]=c)}}return t.primaryColor&&(t.primaryHover=f(t.primaryColor,t.mode==="dark"?15:-10)),Object.keys(t).length>0?t:null}function C(i){let{theme:r,customTheme:t,adaptiveOptions:e}=i;if(r==="custom"&&t)return{mode:v(t.backgroundColor)?"dark":"light",backgroundColor:t.backgroundColor,surfaceColor:t.surfaceColor,textPrimary:t.textPrimary,textSecondary:t.textSecondary,primaryColor:t.primaryColor,primaryHover:t.primaryHover,borderColor:t.borderColor,shadowColor:t.shadowColor,starColor:"#fbbf24"};if(r==="adaptive"){let a=e||{fallback:"light",autoContrast:!0},s=R(a.sourceElement,a.inheritCssVars);return s?{...s.mode==="dark"?h:u,...s}:a.fallback==="dark"?h:u}return r==="auto"?window.matchMedia("(prefers-color-scheme: dark)").matches?h:u:r==="dark"?h:u}function w(i){return`
1
+ "use strict";var v=Object.defineProperty;var S=Object.getOwnPropertyDescriptor;var L=Object.getOwnPropertyNames;var P=Object.prototype.hasOwnProperty;var A=(i,e)=>{for(var t in e)v(i,t,{get:e[t],enumerable:!0})},B=(i,e,t,r)=>{if(e&&typeof e=="object"||typeof e=="function")for(let o of L(e))!P.call(i,o)&&o!==t&&v(i,o,{get:()=>e[o],enumerable:!(r=S(e,o))||r.enumerable});return i};var j=i=>B(v({},"__esModule",{value:!0}),i);var Y={};A(Y,{Bliptar:()=>b,createBliptar:()=>k});module.exports=j(Y);var u={mode:"light",backgroundColor:"#ffffff",surfaceColor:"#f5f5f5",textPrimary:"#1a1a1a",textSecondary:"#666666",primaryColor:"#3b82f6",primaryHover:"#2563eb",borderColor:"#e0e0e0",shadowColor:"rgba(0, 0, 0, 0.15)",starColor:"#fbbf24"},h={mode:"dark",backgroundColor:"#1a1a1a",surfaceColor:"#2a2a2a",textPrimary:"#ffffff",textSecondary:"#a0a0a0",primaryColor:"#3b82f6",primaryHover:"#60a5fa",borderColor:"#333333",shadowColor:"rgba(0, 0, 0, 0.4)",starColor:"#fbbf24"};function D(i,e){try{let r=window.getComputedStyle(i).getPropertyValue(e);return r&&r!=="rgba(0, 0, 0, 0)"?r:null}catch{return null}}function H(i){try{return getComputedStyle(document.documentElement).getPropertyValue(i).trim()||null}catch{return null}}function C(i){let e=i.match(/^#?([a-f\d]{2})([a-f\d]{2})([a-f\d]{2})$/i);if(e)return{r:parseInt(e[1],16),g:parseInt(e[2],16),b:parseInt(e[3],16)};let t=i.match(/rgba?\((\d+),\s*(\d+),\s*(\d+)/);return t?{r:parseInt(t[1],10),g:parseInt(t[2],10),b:parseInt(t[3],10)}:null}function M(i,e,t){let[r,o,a]=[i,e,t].map(n=>(n=n/255,n<=.03928?n/12.92:Math.pow((n+.055)/1.055,2.4)));return .2126*r+.7152*o+.0722*a}function _(i){let e=C(i);return e?M(e.r,e.g,e.b)<.5:!1}function f(i,e){let t=C(i);if(!t)return i;let r=o=>Math.min(255,Math.max(0,Math.round(o+e/100*255)));return`rgb(${r(t.r)}, ${r(t.g)}, ${r(t.b)})`}function z(i){return _(i)?"#ffffff":"#1a1a1a"}function R(i,e){let t={},r=null;i&&(r=document.querySelector(i)),r||(r=document.body);let o=D(r,"background-color");if(o){let a=_(o);t.mode=a?"dark":"light",t.backgroundColor=o,t.surfaceColor=f(o,a?10:-5),t.textPrimary=z(o),t.textSecondary=f(t.textPrimary,a?-30:30),t.borderColor=f(o,a?20:-15),t.shadowColor=a?"rgba(0, 0, 0, 0.4)":"rgba(0, 0, 0, 0.15)"}if(e){let a={"--primary":"primaryColor","--primary-color":"primaryColor","--accent":"primaryColor","--accent-color":"primaryColor","--brand":"primaryColor","--brand-color":"primaryColor","--color-primary":"primaryColor","--background":"backgroundColor","--bg":"backgroundColor","--bg-color":"backgroundColor","--text":"textPrimary","--text-color":"textPrimary","--foreground":"textPrimary","--border":"borderColor","--border-color":"borderColor"};for(let[n,l]of Object.entries(a)){let p=H(n);p&&(t[l]=p)}}return t.primaryColor&&(t.primaryHover=f(t.primaryColor,t.mode==="dark"?15:-10)),Object.keys(t).length>0?t:null}function w(i){let{theme:e,customTheme:t,adaptiveOptions:r}=i;if(e==="custom"&&t)return{mode:_(t.backgroundColor)?"dark":"light",backgroundColor:t.backgroundColor,surfaceColor:t.surfaceColor,textPrimary:t.textPrimary,textSecondary:t.textSecondary,primaryColor:t.primaryColor,primaryHover:t.primaryHover,borderColor:t.borderColor,shadowColor:t.shadowColor,starColor:"#fbbf24"};if(e==="adaptive"){let o=r||{fallback:"light",autoContrast:!0},a=R(o.sourceElement,o.inheritCssVars);return a?{...a.mode==="dark"?h:u,...a}:o.fallback==="dark"?h:u}return e==="auto"?window.matchMedia("(prefers-color-scheme: dark)").matches?h:u:e==="dark"?h:u}function $(i){return`
2
2
  --bliptar-bg: ${i.backgroundColor};
3
3
  --bliptar-surface: ${i.surfaceColor};
4
4
  --bliptar-text: ${i.textPrimary};
@@ -8,8 +8,8 @@
8
8
  --bliptar-border: ${i.borderColor};
9
9
  --bliptar-shadow: ${i.shadowColor};
10
10
  --bliptar-star: ${i.starColor};
11
- `}var g=class{constructor(r,t){this.container=null;this.currentIndex=0;this.answers={};this.form=r,this.options=t,this.theme=C(r.appearance)}render(){this.createContainer(),this.injectStyles(),this.renderQuestion()}destroy(){if(this.container){let r=this.container.querySelector(".bliptar__card");r?(r.classList.add("bliptar__card--exit"),setTimeout(()=>{this.container?.remove(),this.container=null},200)):(this.container.remove(),this.container=null)}}createContainer(){this.container=document.createElement("div"),this.container.id="bliptar-form",this.container.className=`bliptar bliptar--${this.form.appearance.position}`,document.body.appendChild(this.container)}injectStyles(){let r=document.getElementById("bliptar-styles");r&&r.remove();let t=document.createElement("style");t.id="bliptar-styles",t.textContent=this.getStyles(),document.head.appendChild(t)}getStyles(){let{appearance:r}=this.form,t=this.theme,e=r.animation||"slide-up";return`
12
- :root { ${w(t)} }
11
+ `}var g=class{constructor(e,t){this.container=null;this.currentIndex=0;this.answers={};this.form=e,this.options=t,this.theme=w(e.appearance)}render(){this.createContainer(),this.injectStyles(),this.renderQuestion()}destroy(){if(this.container){let e=this.container.querySelector(".bliptar__card");e?(e.classList.add("bliptar__card--exit"),setTimeout(()=>{this.container?.remove(),this.container=null},200)):(this.container.remove(),this.container=null)}}createContainer(){this.container=document.createElement("div"),this.container.id="bliptar-form",this.container.className=`bliptar bliptar--${this.form.appearance.position}`,document.body.appendChild(this.container)}injectStyles(){let e=document.getElementById("bliptar-styles");e&&e.remove();let t=document.createElement("style");t.id="bliptar-styles",t.textContent=this.getStyles(),document.head.appendChild(t)}getStyles(){let{appearance:e}=this.form,t=this.theme,r=e.animation||"slide-up";return`
12
+ :root { ${$(t)} }
13
13
 
14
14
  .bliptar {
15
15
  position: fixed;
@@ -28,19 +28,19 @@
28
28
  inset: 0;
29
29
  background: rgba(0, 0, 0, 0.5);
30
30
  animation: bliptar-fade-in 0.2s ease-out;
31
- ${r.backdropBlur?"backdrop-filter: blur(8px); -webkit-backdrop-filter: blur(8px);":""}
31
+ ${e.backdropBlur?"backdrop-filter: blur(8px); -webkit-backdrop-filter: blur(8px);":""}
32
32
  }
33
33
 
34
34
  .bliptar__card {
35
35
  background: ${t.backgroundColor};
36
36
  color: ${t.textPrimary};
37
- border-radius: ${r.borderRadius}px;
37
+ border-radius: ${e.borderRadius}px;
38
38
  box-shadow: 0 8px 32px ${t.shadowColor}, 0 2px 8px ${t.shadowColor};
39
- max-width: ${r.maxWidth}px;
39
+ max-width: ${e.maxWidth}px;
40
40
  width: calc(100vw - 40px);
41
41
  padding: 24px;
42
42
  position: relative;
43
- ${this.getAnimationStyles(e)}
43
+ ${this.getAnimationStyles(r)}
44
44
  transition: transform 0.2s ease, box-shadow 0.2s ease;
45
45
  }
46
46
 
@@ -49,7 +49,7 @@
49
49
  }
50
50
 
51
51
  .bliptar__card--exit {
52
- animation: bliptar-${e}-out 0.2s ease-in forwards;
52
+ animation: bliptar-${r}-out 0.2s ease-in forwards;
53
53
  }
54
54
 
55
55
  @keyframes bliptar-fade-in { from { opacity: 0; } to { opacity: 1; } }
@@ -372,20 +372,20 @@
372
372
  }
373
373
 
374
374
  @media print { .bliptar { display: none !important; } }
375
- `}getAnimationStyles(r){switch(r){case"slide-up":return"animation: bliptar-slide-up 0.35s cubic-bezier(0.16, 1, 0.3, 1);";case"fade":return"animation: bliptar-fade 0.3s ease-out;";case"scale":return"animation: bliptar-scale 0.3s cubic-bezier(0.34, 1.56, 0.64, 1);";case"none":return"";default:return"animation: bliptar-slide-up 0.35s cubic-bezier(0.16, 1, 0.3, 1);"}}renderQuestion(){if(!this.container)return;let{questions:r,appearance:t,behavior:e}=this.form,a=r[this.currentIndex],s=this.currentIndex===r.length-1,o="";if(t.backdrop&&(o+='<div class="bliptar__backdrop"></div>'),o+='<div class="bliptar__card">',e.allowDismiss&&(o+=`<button class="bliptar__close" aria-label="Close">
375
+ `}getAnimationStyles(e){switch(e){case"slide-up":return"animation: bliptar-slide-up 0.35s cubic-bezier(0.16, 1, 0.3, 1);";case"fade":return"animation: bliptar-fade 0.3s ease-out;";case"scale":return"animation: bliptar-scale 0.3s cubic-bezier(0.34, 1.56, 0.64, 1);";case"none":return"";default:return"animation: bliptar-slide-up 0.35s cubic-bezier(0.16, 1, 0.3, 1);"}}renderQuestion(){if(!this.container)return;let{questions:e,appearance:t,behavior:r}=this.form,o=e[this.currentIndex],a=this.currentIndex===e.length-1,n="";if(t.backdrop&&(n+='<div class="bliptar__backdrop"></div>'),n+='<div class="bliptar__card">',r.allowDismiss&&(n+=`<button class="bliptar__close" aria-label="Close">
376
376
  <svg width="14" height="14" viewBox="0 0 14 14" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round">
377
377
  <path d="M1 1l12 12M1 13L13 1"/>
378
378
  </svg>
379
- </button>`),e.showProgress&&r.length>1){o+='<div class="bliptar__progress">';for(let p=0;p<r.length;p++)o+=`<div class="bliptar__progress-bar${p<=this.currentIndex?" bliptar__progress-bar--active":""}"></div>`;o+="</div>"}o+=`<div class="bliptar__question">${this.escapeHtml(a.question)}</div>`,o+=this.renderAnswerOptions(a),(!e.autoAdvance||a.type==="text-input")&&(o+='<div class="bliptar__nav">',o+=this.currentIndex>0?'<button class="bliptar__nav-btn bliptar__nav-btn--back">Back</button>':"<div></div>",o+=`<button class="bliptar__nav-btn bliptar__nav-btn--next">${s?"Submit":"Continue"}</button>`,o+="</div>"),o+="</div>",this.container.innerHTML=o,this.attachEventListeners()}escapeHtml(r){let t=document.createElement("div");return t.textContent=r,t.innerHTML}renderAnswerOptions(r){let t=`q${this.currentIndex}`,e=this.answers[t];switch(r.type){case"binary":return`<div class="bliptar__options">
380
- <button class="bliptar__btn${e===!0?" bliptar__btn--selected":""}" data-value="true">
381
- ${r.style==="thumbs"?"\u{1F44D} ":""}${this.escapeHtml(r.positiveLabel)}
379
+ </button>`),r.showProgress&&e.length>1){n+='<div class="bliptar__progress">';for(let l=0;l<e.length;l++)n+=`<div class="bliptar__progress-bar${l<=this.currentIndex?" bliptar__progress-bar--active":""}"></div>`;n+="</div>"}n+=`<div class="bliptar__question">${this.escapeHtml(o.question)}</div>`,n+=this.renderAnswerOptions(o),(!r.autoAdvance||o.type==="text-input")&&(n+='<div class="bliptar__nav">',n+=this.currentIndex>0?'<button class="bliptar__nav-btn bliptar__nav-btn--back">Back</button>':"<div></div>",n+=`<button class="bliptar__nav-btn bliptar__nav-btn--next">${a?"Submit":"Continue"}</button>`,n+="</div>"),n+="</div>",this.container.innerHTML=n,this.attachEventListeners()}escapeHtml(e){let t=document.createElement("div");return t.textContent=e,t.innerHTML}renderAnswerOptions(e){let t=`q${this.currentIndex}`,r=this.answers[t];switch(e.type){case"binary":return`<div class="bliptar__options">
380
+ <button class="bliptar__btn${r===!0?" bliptar__btn--selected":""}" data-value="true">
381
+ ${e.style==="thumbs"?"\u{1F44D} ":""}${this.escapeHtml(e.positiveLabel)}
382
382
  </button>
383
- <button class="bliptar__btn${e===!1?" bliptar__btn--selected":""}" data-value="false">
384
- ${r.style==="thumbs"?"\u{1F44E} ":""}${this.escapeHtml(r.negativeLabel)}
383
+ <button class="bliptar__btn${r===!1?" bliptar__btn--selected":""}" data-value="false">
384
+ ${e.style==="thumbs"?"\u{1F44E} ":""}${this.escapeHtml(e.negativeLabel)}
385
385
  </button>
386
- </div>`;case"star-rating":let a='<div class="bliptar__stars">';for(let n=1;n<=r.maxStars;n++)a+=`<span class="bliptar__star${e>=n?" bliptar__star--active":""}" data-value="${n}">\u2605</span>`;return a+"</div>";case"emoji-scale":let s=["\u{1F61E}","\u{1F615}","\u{1F610}","\u{1F642}","\u{1F60A}"],o=["\u{1F61E}","\u{1F610}","\u{1F60A}"],p=r.scale===3?o:s,c='<div class="bliptar__emojis">';return p.forEach((n,l)=>{c+=`<span class="bliptar__emoji${e===l+1?" bliptar__emoji--active":""}" data-value="${l+1}" title="${r.labels?.[l]||""}">${n}</span>`}),c+"</div>";case"nps":let d='<div class="bliptar__nps">';for(let n=0;n<=10;n++)d+=`<button class="bliptar__nps-btn${e===n?" bliptar__nps-btn--selected":""}" data-value="${n}">${n}</button>`;return d+=`</div><div class="bliptar__nps-labels"><span>${this.escapeHtml(r.lowLabel)}</span><span>${this.escapeHtml(r.highLabel)}</span></div>`,d;case"single-choice":let m='<div class="bliptar__options">';return r.options.forEach(n=>{m+=`<button class="bliptar__btn${e===n?" bliptar__btn--selected":""}" data-value="${this.escapeHtml(n)}">${this.escapeHtml(n)}</button>`}),m+"</div>";case"text-input":return`<textarea class="bliptar__textarea" placeholder="${this.escapeHtml(r.placeholder)}" maxlength="${r.maxLength}">${e||""}</textarea>`;default:return""}}attachEventListeners(){if(!this.container)return;let r=this.form.questions[this.currentIndex],{behavior:t}=this.form,e=this.container.querySelector(".bliptar__close");e&&e.addEventListener("click",()=>this.options.onDismiss());let a=this.container.querySelector(".bliptar__backdrop");a&&t.allowDismiss&&a.addEventListener("click",()=>this.options.onDismiss());let s=n=>{this.answers[`q${this.currentIndex}`]=n,t.autoAdvance&&r.type!=="text-input"?setTimeout(()=>this.goNext(),t.autoAdvanceDelay||300):this.renderQuestion()};this.container.querySelectorAll(".bliptar__btn, .bliptar__nps-btn").forEach(n=>{n.addEventListener("click",()=>{let l=n.dataset.value;r.type==="binary"?s(l==="true"):r.type==="nps"?s(parseInt(l,10)):s(l)})});let o=this.container.querySelectorAll(".bliptar__star");o.forEach((n,l)=>{n.addEventListener("mouseenter",()=>{o.forEach((x,E)=>x.classList.toggle("bliptar__star--active",E<=l))}),n.addEventListener("click",()=>s(parseInt(n.dataset.value,10)))});let p=this.container.querySelector(".bliptar__stars");p&&p.addEventListener("mouseleave",()=>{let n=this.answers[`q${this.currentIndex}`];o.forEach((l,x)=>l.classList.toggle("bliptar__star--active",n?x<n:!1))}),this.container.querySelectorAll(".bliptar__emoji").forEach(n=>{n.addEventListener("click",()=>s(parseInt(n.dataset.value,10)))});let c=this.container.querySelector(".bliptar__textarea");c&&(c.addEventListener("input",()=>{this.answers[`q${this.currentIndex}`]=c.value}),setTimeout(()=>c.focus(),100));let d=this.container.querySelector(".bliptar__nav-btn--back");d&&d.addEventListener("click",()=>this.goBack());let m=this.container.querySelector(".bliptar__nav-btn--next");m&&m.addEventListener("click",()=>this.goNext())}goBack(){this.currentIndex>0&&(this.currentIndex--,this.renderQuestion())}async goNext(){this.currentIndex===this.form.questions.length-1?await this.submit():(this.currentIndex++,this.renderQuestion())}async submit(){if(this.container){let r=this.container.querySelector(".bliptar__card");r&&(r.innerHTML='<div class="bliptar__loading"><div class="bliptar__spinner"></div></div>')}try{await this.options.onSubmit(this.answers),this.form.behavior.showThankYou?(this.renderThankYou(),setTimeout(()=>this.options.onDismiss(),this.form.behavior.thankYouDuration||2e3)):this.options.onDismiss()}catch{this.options.onDismiss()}}renderThankYou(){if(!this.container)return;let{appearance:r,behavior:t}=this.form,e="";r.backdrop&&(e+='<div class="bliptar__backdrop"></div>'),e+=`<div class="bliptar__card">
386
+ </div>`;case"star-rating":let o='<div class="bliptar__stars">';for(let s=1;s<=e.maxStars;s++)o+=`<span class="bliptar__star${r>=s?" bliptar__star--active":""}" data-value="${s}">\u2605</span>`;return o+"</div>";case"emoji-scale":let a=["\u{1F61E}","\u{1F615}","\u{1F610}","\u{1F642}","\u{1F60A}"],n=["\u{1F61E}","\u{1F610}","\u{1F60A}"],l=e.scale===3?n:a,p='<div class="bliptar__emojis">';return l.forEach((s,d)=>{p+=`<span class="bliptar__emoji${r===d+1?" bliptar__emoji--active":""}" data-value="${d+1}" title="${e.labels?.[d]||""}">${s}</span>`}),p+"</div>";case"nps":let c='<div class="bliptar__nps">';for(let s=0;s<=10;s++)c+=`<button class="bliptar__nps-btn${r===s?" bliptar__nps-btn--selected":""}" data-value="${s}">${s}</button>`;return c+=`</div><div class="bliptar__nps-labels"><span>${this.escapeHtml(e.lowLabel)}</span><span>${this.escapeHtml(e.highLabel)}</span></div>`,c;case"single-choice":let m='<div class="bliptar__options">';return e.options.forEach(s=>{m+=`<button class="bliptar__btn${r===s?" bliptar__btn--selected":""}" data-value="${this.escapeHtml(s)}">${this.escapeHtml(s)}</button>`}),m+"</div>";case"text-input":return`<textarea class="bliptar__textarea" placeholder="${this.escapeHtml(e.placeholder)}" maxlength="${e.maxLength}">${r||""}</textarea>`;default:return""}}attachEventListeners(){if(!this.container)return;let e=this.form.questions[this.currentIndex],{behavior:t}=this.form,r=this.container.querySelector(".bliptar__close");r&&r.addEventListener("click",()=>this.options.onDismiss());let o=this.container.querySelector(".bliptar__backdrop");o&&t.allowDismiss&&o.addEventListener("click",()=>this.options.onDismiss());let a=s=>{this.answers[`q${this.currentIndex}`]=s,t.autoAdvance&&e.type!=="text-input"?setTimeout(()=>this.goNext(),t.autoAdvanceDelay||300):this.renderQuestion()};this.container.querySelectorAll(".bliptar__btn, .bliptar__nps-btn").forEach(s=>{s.addEventListener("click",()=>{let d=s.dataset.value;e.type==="binary"?a(d==="true"):e.type==="nps"?a(parseInt(d,10)):a(d)})});let n=this.container.querySelectorAll(".bliptar__star");n.forEach((s,d)=>{s.addEventListener("mouseenter",()=>{n.forEach((x,I)=>x.classList.toggle("bliptar__star--active",I<=d))}),s.addEventListener("click",()=>a(parseInt(s.dataset.value,10)))});let l=this.container.querySelector(".bliptar__stars");l&&l.addEventListener("mouseleave",()=>{let s=this.answers[`q${this.currentIndex}`];n.forEach((d,x)=>d.classList.toggle("bliptar__star--active",s?x<s:!1))}),this.container.querySelectorAll(".bliptar__emoji").forEach(s=>{s.addEventListener("click",()=>a(parseInt(s.dataset.value,10)))});let p=this.container.querySelector(".bliptar__textarea");p&&(p.addEventListener("input",()=>{this.answers[`q${this.currentIndex}`]=p.value}),setTimeout(()=>p.focus(),100));let c=this.container.querySelector(".bliptar__nav-btn--back");c&&c.addEventListener("click",()=>this.goBack());let m=this.container.querySelector(".bliptar__nav-btn--next");m&&m.addEventListener("click",()=>this.goNext())}goBack(){this.currentIndex>0&&(this.currentIndex--,this.renderQuestion())}async goNext(){this.currentIndex===this.form.questions.length-1?await this.submit():(this.currentIndex++,this.renderQuestion())}async submit(){if(this.container){let e=this.container.querySelector(".bliptar__card");e&&(e.innerHTML='<div class="bliptar__loading"><div class="bliptar__spinner"></div></div>')}try{await this.options.onSubmit(this.answers),this.form.behavior.showThankYou?(this.renderThankYou(),setTimeout(()=>this.options.onDismiss(),this.form.behavior.thankYouDuration||2e3)):this.options.onDismiss()}catch{this.options.onDismiss()}}renderThankYou(){if(!this.container)return;let{appearance:e,behavior:t}=this.form,r="";e.backdrop&&(r+='<div class="bliptar__backdrop"></div>'),r+=`<div class="bliptar__card">
387
387
  <div class="bliptar__thankyou">
388
388
  <div class="bliptar__thankyou-emoji">\u{1F389}</div>
389
389
  <div class="bliptar__thankyou-text">${this.escapeHtml(t.thankYouMessage||"Thank you for your feedback!")}</div>
390
390
  </div>
391
- </div>`,this.container.innerHTML=e}};function $(){let i="ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789",r="";for(let t=0;t<16;t++)r+=i.charAt(Math.floor(Math.random()*i.length));return`sess_${r}`}function T(){let i=navigator.userAgent;return/tablet|ipad|playbook|silk/i.test(i)?"tablet":/mobile|iphone|ipod|android|blackberry|opera mini|iemobile/i.test(i)?"mobile":"desktop"}function S(i,r){let t;return(...e)=>{clearTimeout(t),t=setTimeout(()=>i(...e),r)}}var O="https://api.bliptar.com",b=class{constructor(r){this.renderer=null;this.scrollDepth=0;this.isInitialized=!1;this.eventListeners=[];this.config={apiUrl:O,debug:!1,onShow:()=>{},onSubmit:()=>{},onDismiss:()=>{},onError:()=>{},...r},this.sessionId=this.loadOrCreateSessionId(),this.pageLoadTime=Date.now()}init(){if(this.isInitialized)return;this.isInitialized=!0,this.log("Initializing Bliptar SDK");let r=S(()=>{let t=document.documentElement,e=window.scrollY||t.scrollTop,a=t.scrollHeight-t.clientHeight;this.scrollDepth=a>0?e/a:0},100);this.addEventListener(window,"scroll",r),this.track("page_view")}identify(r,t){this.config.userId=r,this.config.userAttributes={...this.config.userAttributes,...t},this.log("User identified:",r)}async track(r,t){this.log("Tracking event:",r,t);let e=this.getContext();try{let a=await fetch(`${this.config.apiUrl}/api/sdk/trigger`,{method:"POST",headers:{"Content-Type":"application/json",Authorization:`Bearer ${this.config.apiKey}`},body:JSON.stringify({session_id:this.sessionId,user_id:this.config.userId,event:r,event_data:t||{},context:e})});if(!a.ok)throw new Error(`API error: ${a.status}`);let s=await a.json();s.show_form&&s.form&&await this.displayForm(s.form,s.campaign_id)}catch(a){this.handleError(a)}}async showForm(r){this.log("Manually showing form:",r);try{let t=await fetch(`${this.config.apiUrl}/api/sdk/form/${r}`,{headers:{Authorization:`Bearer ${this.config.apiKey}`}});if(!t.ok)throw new Error(`Failed to fetch form: ${t.status}`);let e=await t.json();await this.displayForm(e)}catch(t){this.handleError(t)}}destroy(){this.log("Destroying Bliptar SDK"),this.eventListeners.forEach(({target:r,type:t,handler:e})=>{r.removeEventListener(t,e)}),this.eventListeners=[],this.renderer&&(this.renderer.destroy(),this.renderer=null),this.isInitialized=!1}async displayForm(r,t){this.log("Displaying form:",r.formId),this.config.onShow?.(r),this.renderer=new g(r,{onSubmit:async e=>{await this.submitResponse(r.formId,e,t),this.config.onSubmit?.(e)},onDismiss:()=>{this.config.onDismiss?.(),this.renderer?.destroy(),this.renderer=null}}),this.renderer.render()}async submitResponse(r,t,e){this.log("Submitting response:",r,t);let a=this.getContext(),s=new Date().toISOString();try{await fetch(`${this.config.apiUrl}/api/sdk/submit`,{method:"POST",headers:{"Content-Type":"application/json",Authorization:`Bearer ${this.config.apiKey}`},body:JSON.stringify({session_id:this.sessionId,user_id:this.config.userId,form_id:r,campaign_id:e,answers:t,context:a,completed_at:s})})}catch(o){this.handleError(o)}}getContext(){return{pageUrl:window.location.href,referrer:document.referrer,timeOnPage:Math.floor((Date.now()-this.pageLoadTime)/1e3),scrollDepth:Math.round(this.scrollDepth*100)/100,deviceType:T()}}loadOrCreateSessionId(){let r="bliptar_session",t=sessionStorage.getItem(r);return t||(t=$(),sessionStorage.setItem(r,t)),t}addEventListener(r,t,e){r.addEventListener(t,e),this.eventListeners.push({target:r,type:t,handler:e})}log(...r){this.config.debug&&console.log("[Bliptar]",...r)}handleError(r){this.log("Error:",r),this.config.onError?.(r)}};function y(i){return new b(i)}if(typeof window<"u"){let i=document.currentScript;if(i?.dataset.apiKey){let r=y({apiKey:i.dataset.apiKey,debug:i.dataset.debug==="true"});window.bliptar=r,r.init()}}0&&(module.exports={Bliptar,createBliptar});
391
+ </div>`,this.container.innerHTML=r}};function T(){let i="ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789",e="";for(let t=0;t<16;t++)e+=i.charAt(Math.floor(Math.random()*i.length));return`sess_${e}`}function y(){let i=navigator.userAgent;return/tablet|ipad|playbook|silk/i.test(i)?"tablet":/mobile|iphone|ipod|android|blackberry|opera mini|iemobile/i.test(i)?"mobile":"desktop"}function E(i,e){let t;return(...r)=>{clearTimeout(t),t=setTimeout(()=>i(...r),e)}}var O="https://api.bliptar.com",b=class{constructor(e){this.renderer=null;this.scrollDepth=0;this.isInitialized=!1;this.eventListeners=[];this.trackedClicks=new Set;this.exitIntentTriggered=!1;this.exitIntentCooldownTimer=null;this.config={apiUrl:O,debug:!1,onShow:()=>{},onSubmit:()=>{},onDismiss:()=>{},onError:()=>{},...e},this.sessionId=this.loadOrCreateSessionId(),this.pageLoadTime=Date.now()}init(){if(this.isInitialized)return;this.isInitialized=!0,this.log("Initializing Bliptar SDK");let e=E(()=>{let t=document.documentElement,r=window.scrollY||t.scrollTop,o=t.scrollHeight-t.clientHeight;this.scrollDepth=o>0?r/o:0},100);this.addEventListener(window,"scroll",e),this.track("page_view")}identify(e,t){this.config.userId=e,this.config.userAttributes={...this.config.userAttributes,...t},this.log("User identified:",e)}async track(e,t){this.log("Tracking event:",e,t);let r=this.getContext();try{let o=await fetch(`${this.config.apiUrl}/api/sdk/trigger`,{method:"POST",headers:{"Content-Type":"application/json",Authorization:`Bearer ${this.config.apiKey}`},body:JSON.stringify({session_id:this.sessionId,user_id:this.config.userId,event:e,event_data:t||{},context:r})});if(!o.ok)throw new Error(`API error: ${o.status}`);let a=await o.json();a.show_form&&a.form&&await this.displayForm(a.form,a.campaign_id)}catch(o){this.handleError(o)}}async showForm(e){this.log("Manually showing form:",e);try{let t=await fetch(`${this.config.apiUrl}/api/sdk/form/${e}`,{headers:{Authorization:`Bearer ${this.config.apiKey}`}});if(!t.ok)throw new Error(`Failed to fetch form: ${t.status}`);let r=await t.json();await this.displayForm(r)}catch(t){this.handleError(t)}}trackClicks(e){let{selector:t,name:r,once:o=!1}=e,a=r||t;this.log("Setting up click tracking for:",t);let n=l=>{let c=l.target.closest(t);c&&(o&&this.trackedClicks.has(a)||(this.log("Button click detected:",a),o&&this.trackedClicks.add(a),this.track("button_click",{selector:t,name:a,element_text:c.textContent?.trim().slice(0,100)||"",element_id:c.id||null,element_class:c.className||null})))};this.addEventListener(document,"click",n)}enableExitIntent(e={}){let{threshold:t=50,cooldown:r=1e4,once:o=!0}=e;this.log("Enabling exit intent detection");let a=l=>{l.clientY>t||o&&this.exitIntentTriggered||this.exitIntentCooldownTimer||(this.log("Exit intent detected"),this.exitIntentTriggered=!0,this.track("exit_intent",{trigger:"mouse_leave",mouse_y:l.clientY}),o||(this.exitIntentCooldownTimer=setTimeout(()=>{this.exitIntentCooldownTimer=null},r)))};this.addEventListener(document,"mouseleave",a);let n=()=>{if(document.visibilityState==="hidden"){if(o&&this.exitIntentTriggered)return;this.log("Exit intent detected (visibility change)"),this.exitIntentTriggered=!0,this.track("exit_intent",{trigger:"visibility_change"})}};y()!=="desktop"&&this.addEventListener(document,"visibilitychange",n)}destroy(){this.log("Destroying Bliptar SDK"),this.eventListeners.forEach(({target:e,type:t,handler:r})=>{e.removeEventListener(t,r)}),this.eventListeners=[],this.renderer&&(this.renderer.destroy(),this.renderer=null),this.exitIntentCooldownTimer&&(clearTimeout(this.exitIntentCooldownTimer),this.exitIntentCooldownTimer=null),this.trackedClicks.clear(),this.exitIntentTriggered=!1,this.isInitialized=!1}async displayForm(e,t){this.log("Displaying form:",e.formId),this.config.onShow?.(e),this.renderer=new g(e,{onSubmit:async r=>{await this.submitResponse(e.formId,r,t),this.config.onSubmit?.(r)},onDismiss:()=>{this.config.onDismiss?.(),this.renderer?.destroy(),this.renderer=null}}),this.renderer.render()}async submitResponse(e,t,r){this.log("Submitting response:",e,t);let o=this.getContext(),a=new Date().toISOString();try{await fetch(`${this.config.apiUrl}/api/sdk/submit`,{method:"POST",headers:{"Content-Type":"application/json",Authorization:`Bearer ${this.config.apiKey}`},body:JSON.stringify({session_id:this.sessionId,user_id:this.config.userId,form_id:e,campaign_id:r,answers:t,context:o,completed_at:a})})}catch(n){this.handleError(n)}}getContext(){return{pageUrl:window.location.href,referrer:document.referrer,timeOnPage:Math.floor((Date.now()-this.pageLoadTime)/1e3),scrollDepth:Math.round(this.scrollDepth*100)/100,deviceType:y()}}loadOrCreateSessionId(){let e="bliptar_session",t=sessionStorage.getItem(e);return t||(t=T(),sessionStorage.setItem(e,t)),t}addEventListener(e,t,r){e.addEventListener(t,r),this.eventListeners.push({target:e,type:t,handler:r})}log(...e){this.config.debug&&console.log("[Bliptar]",...e)}handleError(e){this.log("Error:",e),this.config.onError?.(e)}};function k(i){return new b(i)}if(typeof window<"u"){let i=document.currentScript;if(i?.dataset.apiKey){let e=k({apiKey:i.dataset.apiKey,debug:i.dataset.debug==="true"});window.bliptar=e,e.init()}}0&&(module.exports={Bliptar,createBliptar});
package/dist/index.d.cts CHANGED
@@ -9,11 +9,31 @@ interface BliptarConfig {
9
9
  onDismiss?: () => void;
10
10
  onError?: (error: Error) => void;
11
11
  }
12
+ interface ClickTrackingOptions {
13
+ /** CSS selector for elements to track */
14
+ selector: string;
15
+ /** Optional name for this click target (defaults to selector) */
16
+ name?: string;
17
+ /** Only track once per session */
18
+ once?: boolean;
19
+ }
20
+ interface ExitIntentOptions {
21
+ /** Sensitivity threshold in pixels from top of viewport (default: 50) */
22
+ threshold?: number;
23
+ /** Delay before exit intent can trigger again in ms (default: 10000) */
24
+ cooldown?: number;
25
+ /** Only trigger once per session (default: true) */
26
+ once?: boolean;
27
+ }
12
28
  interface BliptarInstance {
13
29
  init: () => void;
14
30
  identify: (userId: string, attributes?: Record<string, unknown>) => void;
15
31
  track: (event: string, data?: Record<string, unknown>) => void;
16
32
  showForm: (formId: string) => Promise<void>;
33
+ /** Track clicks on elements matching the selector */
34
+ trackClicks: (options: ClickTrackingOptions) => void;
35
+ /** Enable exit intent detection */
36
+ enableExitIntent: (options?: ExitIntentOptions) => void;
17
37
  destroy: () => void;
18
38
  }
19
39
  interface Form {
@@ -110,11 +130,16 @@ declare class Bliptar implements BliptarInstance {
110
130
  private scrollDepth;
111
131
  private isInitialized;
112
132
  private eventListeners;
133
+ private trackedClicks;
134
+ private exitIntentTriggered;
135
+ private exitIntentCooldownTimer;
113
136
  constructor(config: BliptarConfig);
114
137
  init(): void;
115
138
  identify(userId: string, attributes?: Record<string, unknown>): void;
116
139
  track(event: string, data?: Record<string, unknown>): Promise<void>;
117
140
  showForm(formId: string): Promise<void>;
141
+ trackClicks(options: ClickTrackingOptions): void;
142
+ enableExitIntent(options?: ExitIntentOptions): void;
118
143
  destroy(): void;
119
144
  private displayForm;
120
145
  private submitResponse;
@@ -148,4 +173,4 @@ declare class Bliptar implements BliptarInstance {
148
173
  */
149
174
  declare function createBliptar(config: BliptarConfig): BliptarInstance;
150
175
 
151
- export { type Answer, Bliptar, type BliptarConfig, type BliptarInstance, type Form, type Question, createBliptar };
176
+ export { type Answer, Bliptar, type BliptarConfig, type BliptarInstance, type ClickTrackingOptions, type ExitIntentOptions, type Form, type Question, createBliptar };
package/dist/index.d.ts CHANGED
@@ -9,11 +9,31 @@ interface BliptarConfig {
9
9
  onDismiss?: () => void;
10
10
  onError?: (error: Error) => void;
11
11
  }
12
+ interface ClickTrackingOptions {
13
+ /** CSS selector for elements to track */
14
+ selector: string;
15
+ /** Optional name for this click target (defaults to selector) */
16
+ name?: string;
17
+ /** Only track once per session */
18
+ once?: boolean;
19
+ }
20
+ interface ExitIntentOptions {
21
+ /** Sensitivity threshold in pixels from top of viewport (default: 50) */
22
+ threshold?: number;
23
+ /** Delay before exit intent can trigger again in ms (default: 10000) */
24
+ cooldown?: number;
25
+ /** Only trigger once per session (default: true) */
26
+ once?: boolean;
27
+ }
12
28
  interface BliptarInstance {
13
29
  init: () => void;
14
30
  identify: (userId: string, attributes?: Record<string, unknown>) => void;
15
31
  track: (event: string, data?: Record<string, unknown>) => void;
16
32
  showForm: (formId: string) => Promise<void>;
33
+ /** Track clicks on elements matching the selector */
34
+ trackClicks: (options: ClickTrackingOptions) => void;
35
+ /** Enable exit intent detection */
36
+ enableExitIntent: (options?: ExitIntentOptions) => void;
17
37
  destroy: () => void;
18
38
  }
19
39
  interface Form {
@@ -110,11 +130,16 @@ declare class Bliptar implements BliptarInstance {
110
130
  private scrollDepth;
111
131
  private isInitialized;
112
132
  private eventListeners;
133
+ private trackedClicks;
134
+ private exitIntentTriggered;
135
+ private exitIntentCooldownTimer;
113
136
  constructor(config: BliptarConfig);
114
137
  init(): void;
115
138
  identify(userId: string, attributes?: Record<string, unknown>): void;
116
139
  track(event: string, data?: Record<string, unknown>): Promise<void>;
117
140
  showForm(formId: string): Promise<void>;
141
+ trackClicks(options: ClickTrackingOptions): void;
142
+ enableExitIntent(options?: ExitIntentOptions): void;
118
143
  destroy(): void;
119
144
  private displayForm;
120
145
  private submitResponse;
@@ -148,4 +173,4 @@ declare class Bliptar implements BliptarInstance {
148
173
  */
149
174
  declare function createBliptar(config: BliptarConfig): BliptarInstance;
150
175
 
151
- export { type Answer, Bliptar, type BliptarConfig, type BliptarInstance, type Form, type Question, createBliptar };
176
+ export { type Answer, Bliptar, type BliptarConfig, type BliptarInstance, type ClickTrackingOptions, type ExitIntentOptions, type Form, type Question, createBliptar };
package/dist/index.js CHANGED
@@ -1,4 +1,4 @@
1
- var u={mode:"light",backgroundColor:"#ffffff",surfaceColor:"#f5f5f5",textPrimary:"#1a1a1a",textSecondary:"#666666",primaryColor:"#3b82f6",primaryHover:"#2563eb",borderColor:"#e0e0e0",shadowColor:"rgba(0, 0, 0, 0.15)",starColor:"#fbbf24"},h={mode:"dark",backgroundColor:"#1a1a1a",surfaceColor:"#2a2a2a",textPrimary:"#ffffff",textSecondary:"#a0a0a0",primaryColor:"#3b82f6",primaryHover:"#60a5fa",borderColor:"#333333",shadowColor:"rgba(0, 0, 0, 0.4)",starColor:"#fbbf24"};function E(i,r){try{let e=window.getComputedStyle(i).getPropertyValue(r);return e&&e!=="rgba(0, 0, 0, 0)"?e:null}catch{return null}}function I(i){try{return getComputedStyle(document.documentElement).getPropertyValue(i).trim()||null}catch{return null}}function v(i){let r=i.match(/^#?([a-f\d]{2})([a-f\d]{2})([a-f\d]{2})$/i);if(r)return{r:parseInt(r[1],16),g:parseInt(r[2],16),b:parseInt(r[3],16)};let t=i.match(/rgba?\((\d+),\s*(\d+),\s*(\d+)/);return t?{r:parseInt(t[1],10),g:parseInt(t[2],10),b:parseInt(t[3],10)}:null}function L(i,r,t){let[e,a,s]=[i,r,t].map(o=>(o=o/255,o<=.03928?o/12.92:Math.pow((o+.055)/1.055,2.4)));return .2126*e+.7152*a+.0722*s}function _(i){let r=v(i);return r?L(r.r,r.g,r.b)<.5:!1}function f(i,r){let t=v(i);if(!t)return i;let e=a=>Math.min(255,Math.max(0,Math.round(a+r/100*255)));return`rgb(${e(t.r)}, ${e(t.g)}, ${e(t.b)})`}function P(i){return _(i)?"#ffffff":"#1a1a1a"}function A(i,r){let t={},e=null;i&&(e=document.querySelector(i)),e||(e=document.body);let a=E(e,"background-color");if(a){let s=_(a);t.mode=s?"dark":"light",t.backgroundColor=a,t.surfaceColor=f(a,s?10:-5),t.textPrimary=P(a),t.textSecondary=f(t.textPrimary,s?-30:30),t.borderColor=f(a,s?20:-15),t.shadowColor=s?"rgba(0, 0, 0, 0.4)":"rgba(0, 0, 0, 0.15)"}if(r){let s={"--primary":"primaryColor","--primary-color":"primaryColor","--accent":"primaryColor","--accent-color":"primaryColor","--brand":"primaryColor","--brand-color":"primaryColor","--color-primary":"primaryColor","--background":"backgroundColor","--bg":"backgroundColor","--bg-color":"backgroundColor","--text":"textPrimary","--text-color":"textPrimary","--foreground":"textPrimary","--border":"borderColor","--border-color":"borderColor"};for(let[o,p]of Object.entries(s)){let c=I(o);c&&(t[p]=c)}}return t.primaryColor&&(t.primaryHover=f(t.primaryColor,t.mode==="dark"?15:-10)),Object.keys(t).length>0?t:null}function y(i){let{theme:r,customTheme:t,adaptiveOptions:e}=i;if(r==="custom"&&t)return{mode:_(t.backgroundColor)?"dark":"light",backgroundColor:t.backgroundColor,surfaceColor:t.surfaceColor,textPrimary:t.textPrimary,textSecondary:t.textSecondary,primaryColor:t.primaryColor,primaryHover:t.primaryHover,borderColor:t.borderColor,shadowColor:t.shadowColor,starColor:"#fbbf24"};if(r==="adaptive"){let a=e||{fallback:"light",autoContrast:!0},s=A(a.sourceElement,a.inheritCssVars);return s?{...s.mode==="dark"?h:u,...s}:a.fallback==="dark"?h:u}return r==="auto"?window.matchMedia("(prefers-color-scheme: dark)").matches?h:u:r==="dark"?h:u}function k(i){return`
1
+ var u={mode:"light",backgroundColor:"#ffffff",surfaceColor:"#f5f5f5",textPrimary:"#1a1a1a",textSecondary:"#666666",primaryColor:"#3b82f6",primaryHover:"#2563eb",borderColor:"#e0e0e0",shadowColor:"rgba(0, 0, 0, 0.15)",starColor:"#fbbf24"},h={mode:"dark",backgroundColor:"#1a1a1a",surfaceColor:"#2a2a2a",textPrimary:"#ffffff",textSecondary:"#a0a0a0",primaryColor:"#3b82f6",primaryHover:"#60a5fa",borderColor:"#333333",shadowColor:"rgba(0, 0, 0, 0.4)",starColor:"#fbbf24"};function I(i,e){try{let r=window.getComputedStyle(i).getPropertyValue(e);return r&&r!=="rgba(0, 0, 0, 0)"?r:null}catch{return null}}function S(i){try{return getComputedStyle(document.documentElement).getPropertyValue(i).trim()||null}catch{return null}}function y(i){let e=i.match(/^#?([a-f\d]{2})([a-f\d]{2})([a-f\d]{2})$/i);if(e)return{r:parseInt(e[1],16),g:parseInt(e[2],16),b:parseInt(e[3],16)};let t=i.match(/rgba?\((\d+),\s*(\d+),\s*(\d+)/);return t?{r:parseInt(t[1],10),g:parseInt(t[2],10),b:parseInt(t[3],10)}:null}function L(i,e,t){let[r,o,a]=[i,e,t].map(n=>(n=n/255,n<=.03928?n/12.92:Math.pow((n+.055)/1.055,2.4)));return .2126*r+.7152*o+.0722*a}function v(i){let e=y(i);return e?L(e.r,e.g,e.b)<.5:!1}function f(i,e){let t=y(i);if(!t)return i;let r=o=>Math.min(255,Math.max(0,Math.round(o+e/100*255)));return`rgb(${r(t.r)}, ${r(t.g)}, ${r(t.b)})`}function P(i){return v(i)?"#ffffff":"#1a1a1a"}function A(i,e){let t={},r=null;i&&(r=document.querySelector(i)),r||(r=document.body);let o=I(r,"background-color");if(o){let a=v(o);t.mode=a?"dark":"light",t.backgroundColor=o,t.surfaceColor=f(o,a?10:-5),t.textPrimary=P(o),t.textSecondary=f(t.textPrimary,a?-30:30),t.borderColor=f(o,a?20:-15),t.shadowColor=a?"rgba(0, 0, 0, 0.4)":"rgba(0, 0, 0, 0.15)"}if(e){let a={"--primary":"primaryColor","--primary-color":"primaryColor","--accent":"primaryColor","--accent-color":"primaryColor","--brand":"primaryColor","--brand-color":"primaryColor","--color-primary":"primaryColor","--background":"backgroundColor","--bg":"backgroundColor","--bg-color":"backgroundColor","--text":"textPrimary","--text-color":"textPrimary","--foreground":"textPrimary","--border":"borderColor","--border-color":"borderColor"};for(let[n,l]of Object.entries(a)){let p=S(n);p&&(t[l]=p)}}return t.primaryColor&&(t.primaryHover=f(t.primaryColor,t.mode==="dark"?15:-10)),Object.keys(t).length>0?t:null}function k(i){let{theme:e,customTheme:t,adaptiveOptions:r}=i;if(e==="custom"&&t)return{mode:v(t.backgroundColor)?"dark":"light",backgroundColor:t.backgroundColor,surfaceColor:t.surfaceColor,textPrimary:t.textPrimary,textSecondary:t.textSecondary,primaryColor:t.primaryColor,primaryHover:t.primaryHover,borderColor:t.borderColor,shadowColor:t.shadowColor,starColor:"#fbbf24"};if(e==="adaptive"){let o=r||{fallback:"light",autoContrast:!0},a=A(o.sourceElement,o.inheritCssVars);return a?{...a.mode==="dark"?h:u,...a}:o.fallback==="dark"?h:u}return e==="auto"?window.matchMedia("(prefers-color-scheme: dark)").matches?h:u:e==="dark"?h:u}function C(i){return`
2
2
  --bliptar-bg: ${i.backgroundColor};
3
3
  --bliptar-surface: ${i.surfaceColor};
4
4
  --bliptar-text: ${i.textPrimary};
@@ -8,8 +8,8 @@ var u={mode:"light",backgroundColor:"#ffffff",surfaceColor:"#f5f5f5",textPrimary
8
8
  --bliptar-border: ${i.borderColor};
9
9
  --bliptar-shadow: ${i.shadowColor};
10
10
  --bliptar-star: ${i.starColor};
11
- `}var g=class{constructor(r,t){this.container=null;this.currentIndex=0;this.answers={};this.form=r,this.options=t,this.theme=y(r.appearance)}render(){this.createContainer(),this.injectStyles(),this.renderQuestion()}destroy(){if(this.container){let r=this.container.querySelector(".bliptar__card");r?(r.classList.add("bliptar__card--exit"),setTimeout(()=>{this.container?.remove(),this.container=null},200)):(this.container.remove(),this.container=null)}}createContainer(){this.container=document.createElement("div"),this.container.id="bliptar-form",this.container.className=`bliptar bliptar--${this.form.appearance.position}`,document.body.appendChild(this.container)}injectStyles(){let r=document.getElementById("bliptar-styles");r&&r.remove();let t=document.createElement("style");t.id="bliptar-styles",t.textContent=this.getStyles(),document.head.appendChild(t)}getStyles(){let{appearance:r}=this.form,t=this.theme,e=r.animation||"slide-up";return`
12
- :root { ${k(t)} }
11
+ `}var g=class{constructor(e,t){this.container=null;this.currentIndex=0;this.answers={};this.form=e,this.options=t,this.theme=k(e.appearance)}render(){this.createContainer(),this.injectStyles(),this.renderQuestion()}destroy(){if(this.container){let e=this.container.querySelector(".bliptar__card");e?(e.classList.add("bliptar__card--exit"),setTimeout(()=>{this.container?.remove(),this.container=null},200)):(this.container.remove(),this.container=null)}}createContainer(){this.container=document.createElement("div"),this.container.id="bliptar-form",this.container.className=`bliptar bliptar--${this.form.appearance.position}`,document.body.appendChild(this.container)}injectStyles(){let e=document.getElementById("bliptar-styles");e&&e.remove();let t=document.createElement("style");t.id="bliptar-styles",t.textContent=this.getStyles(),document.head.appendChild(t)}getStyles(){let{appearance:e}=this.form,t=this.theme,r=e.animation||"slide-up";return`
12
+ :root { ${C(t)} }
13
13
 
14
14
  .bliptar {
15
15
  position: fixed;
@@ -28,19 +28,19 @@ var u={mode:"light",backgroundColor:"#ffffff",surfaceColor:"#f5f5f5",textPrimary
28
28
  inset: 0;
29
29
  background: rgba(0, 0, 0, 0.5);
30
30
  animation: bliptar-fade-in 0.2s ease-out;
31
- ${r.backdropBlur?"backdrop-filter: blur(8px); -webkit-backdrop-filter: blur(8px);":""}
31
+ ${e.backdropBlur?"backdrop-filter: blur(8px); -webkit-backdrop-filter: blur(8px);":""}
32
32
  }
33
33
 
34
34
  .bliptar__card {
35
35
  background: ${t.backgroundColor};
36
36
  color: ${t.textPrimary};
37
- border-radius: ${r.borderRadius}px;
37
+ border-radius: ${e.borderRadius}px;
38
38
  box-shadow: 0 8px 32px ${t.shadowColor}, 0 2px 8px ${t.shadowColor};
39
- max-width: ${r.maxWidth}px;
39
+ max-width: ${e.maxWidth}px;
40
40
  width: calc(100vw - 40px);
41
41
  padding: 24px;
42
42
  position: relative;
43
- ${this.getAnimationStyles(e)}
43
+ ${this.getAnimationStyles(r)}
44
44
  transition: transform 0.2s ease, box-shadow 0.2s ease;
45
45
  }
46
46
 
@@ -49,7 +49,7 @@ var u={mode:"light",backgroundColor:"#ffffff",surfaceColor:"#f5f5f5",textPrimary
49
49
  }
50
50
 
51
51
  .bliptar__card--exit {
52
- animation: bliptar-${e}-out 0.2s ease-in forwards;
52
+ animation: bliptar-${r}-out 0.2s ease-in forwards;
53
53
  }
54
54
 
55
55
  @keyframes bliptar-fade-in { from { opacity: 0; } to { opacity: 1; } }
@@ -372,20 +372,20 @@ var u={mode:"light",backgroundColor:"#ffffff",surfaceColor:"#f5f5f5",textPrimary
372
372
  }
373
373
 
374
374
  @media print { .bliptar { display: none !important; } }
375
- `}getAnimationStyles(r){switch(r){case"slide-up":return"animation: bliptar-slide-up 0.35s cubic-bezier(0.16, 1, 0.3, 1);";case"fade":return"animation: bliptar-fade 0.3s ease-out;";case"scale":return"animation: bliptar-scale 0.3s cubic-bezier(0.34, 1.56, 0.64, 1);";case"none":return"";default:return"animation: bliptar-slide-up 0.35s cubic-bezier(0.16, 1, 0.3, 1);"}}renderQuestion(){if(!this.container)return;let{questions:r,appearance:t,behavior:e}=this.form,a=r[this.currentIndex],s=this.currentIndex===r.length-1,o="";if(t.backdrop&&(o+='<div class="bliptar__backdrop"></div>'),o+='<div class="bliptar__card">',e.allowDismiss&&(o+=`<button class="bliptar__close" aria-label="Close">
375
+ `}getAnimationStyles(e){switch(e){case"slide-up":return"animation: bliptar-slide-up 0.35s cubic-bezier(0.16, 1, 0.3, 1);";case"fade":return"animation: bliptar-fade 0.3s ease-out;";case"scale":return"animation: bliptar-scale 0.3s cubic-bezier(0.34, 1.56, 0.64, 1);";case"none":return"";default:return"animation: bliptar-slide-up 0.35s cubic-bezier(0.16, 1, 0.3, 1);"}}renderQuestion(){if(!this.container)return;let{questions:e,appearance:t,behavior:r}=this.form,o=e[this.currentIndex],a=this.currentIndex===e.length-1,n="";if(t.backdrop&&(n+='<div class="bliptar__backdrop"></div>'),n+='<div class="bliptar__card">',r.allowDismiss&&(n+=`<button class="bliptar__close" aria-label="Close">
376
376
  <svg width="14" height="14" viewBox="0 0 14 14" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round">
377
377
  <path d="M1 1l12 12M1 13L13 1"/>
378
378
  </svg>
379
- </button>`),e.showProgress&&r.length>1){o+='<div class="bliptar__progress">';for(let p=0;p<r.length;p++)o+=`<div class="bliptar__progress-bar${p<=this.currentIndex?" bliptar__progress-bar--active":""}"></div>`;o+="</div>"}o+=`<div class="bliptar__question">${this.escapeHtml(a.question)}</div>`,o+=this.renderAnswerOptions(a),(!e.autoAdvance||a.type==="text-input")&&(o+='<div class="bliptar__nav">',o+=this.currentIndex>0?'<button class="bliptar__nav-btn bliptar__nav-btn--back">Back</button>':"<div></div>",o+=`<button class="bliptar__nav-btn bliptar__nav-btn--next">${s?"Submit":"Continue"}</button>`,o+="</div>"),o+="</div>",this.container.innerHTML=o,this.attachEventListeners()}escapeHtml(r){let t=document.createElement("div");return t.textContent=r,t.innerHTML}renderAnswerOptions(r){let t=`q${this.currentIndex}`,e=this.answers[t];switch(r.type){case"binary":return`<div class="bliptar__options">
380
- <button class="bliptar__btn${e===!0?" bliptar__btn--selected":""}" data-value="true">
381
- ${r.style==="thumbs"?"\u{1F44D} ":""}${this.escapeHtml(r.positiveLabel)}
379
+ </button>`),r.showProgress&&e.length>1){n+='<div class="bliptar__progress">';for(let l=0;l<e.length;l++)n+=`<div class="bliptar__progress-bar${l<=this.currentIndex?" bliptar__progress-bar--active":""}"></div>`;n+="</div>"}n+=`<div class="bliptar__question">${this.escapeHtml(o.question)}</div>`,n+=this.renderAnswerOptions(o),(!r.autoAdvance||o.type==="text-input")&&(n+='<div class="bliptar__nav">',n+=this.currentIndex>0?'<button class="bliptar__nav-btn bliptar__nav-btn--back">Back</button>':"<div></div>",n+=`<button class="bliptar__nav-btn bliptar__nav-btn--next">${a?"Submit":"Continue"}</button>`,n+="</div>"),n+="</div>",this.container.innerHTML=n,this.attachEventListeners()}escapeHtml(e){let t=document.createElement("div");return t.textContent=e,t.innerHTML}renderAnswerOptions(e){let t=`q${this.currentIndex}`,r=this.answers[t];switch(e.type){case"binary":return`<div class="bliptar__options">
380
+ <button class="bliptar__btn${r===!0?" bliptar__btn--selected":""}" data-value="true">
381
+ ${e.style==="thumbs"?"\u{1F44D} ":""}${this.escapeHtml(e.positiveLabel)}
382
382
  </button>
383
- <button class="bliptar__btn${e===!1?" bliptar__btn--selected":""}" data-value="false">
384
- ${r.style==="thumbs"?"\u{1F44E} ":""}${this.escapeHtml(r.negativeLabel)}
383
+ <button class="bliptar__btn${r===!1?" bliptar__btn--selected":""}" data-value="false">
384
+ ${e.style==="thumbs"?"\u{1F44E} ":""}${this.escapeHtml(e.negativeLabel)}
385
385
  </button>
386
- </div>`;case"star-rating":let a='<div class="bliptar__stars">';for(let n=1;n<=r.maxStars;n++)a+=`<span class="bliptar__star${e>=n?" bliptar__star--active":""}" data-value="${n}">\u2605</span>`;return a+"</div>";case"emoji-scale":let s=["\u{1F61E}","\u{1F615}","\u{1F610}","\u{1F642}","\u{1F60A}"],o=["\u{1F61E}","\u{1F610}","\u{1F60A}"],p=r.scale===3?o:s,c='<div class="bliptar__emojis">';return p.forEach((n,l)=>{c+=`<span class="bliptar__emoji${e===l+1?" bliptar__emoji--active":""}" data-value="${l+1}" title="${r.labels?.[l]||""}">${n}</span>`}),c+"</div>";case"nps":let d='<div class="bliptar__nps">';for(let n=0;n<=10;n++)d+=`<button class="bliptar__nps-btn${e===n?" bliptar__nps-btn--selected":""}" data-value="${n}">${n}</button>`;return d+=`</div><div class="bliptar__nps-labels"><span>${this.escapeHtml(r.lowLabel)}</span><span>${this.escapeHtml(r.highLabel)}</span></div>`,d;case"single-choice":let b='<div class="bliptar__options">';return r.options.forEach(n=>{b+=`<button class="bliptar__btn${e===n?" bliptar__btn--selected":""}" data-value="${this.escapeHtml(n)}">${this.escapeHtml(n)}</button>`}),b+"</div>";case"text-input":return`<textarea class="bliptar__textarea" placeholder="${this.escapeHtml(r.placeholder)}" maxlength="${r.maxLength}">${e||""}</textarea>`;default:return""}}attachEventListeners(){if(!this.container)return;let r=this.form.questions[this.currentIndex],{behavior:t}=this.form,e=this.container.querySelector(".bliptar__close");e&&e.addEventListener("click",()=>this.options.onDismiss());let a=this.container.querySelector(".bliptar__backdrop");a&&t.allowDismiss&&a.addEventListener("click",()=>this.options.onDismiss());let s=n=>{this.answers[`q${this.currentIndex}`]=n,t.autoAdvance&&r.type!=="text-input"?setTimeout(()=>this.goNext(),t.autoAdvanceDelay||300):this.renderQuestion()};this.container.querySelectorAll(".bliptar__btn, .bliptar__nps-btn").forEach(n=>{n.addEventListener("click",()=>{let l=n.dataset.value;r.type==="binary"?s(l==="true"):r.type==="nps"?s(parseInt(l,10)):s(l)})});let o=this.container.querySelectorAll(".bliptar__star");o.forEach((n,l)=>{n.addEventListener("mouseenter",()=>{o.forEach((x,S)=>x.classList.toggle("bliptar__star--active",S<=l))}),n.addEventListener("click",()=>s(parseInt(n.dataset.value,10)))});let p=this.container.querySelector(".bliptar__stars");p&&p.addEventListener("mouseleave",()=>{let n=this.answers[`q${this.currentIndex}`];o.forEach((l,x)=>l.classList.toggle("bliptar__star--active",n?x<n:!1))}),this.container.querySelectorAll(".bliptar__emoji").forEach(n=>{n.addEventListener("click",()=>s(parseInt(n.dataset.value,10)))});let c=this.container.querySelector(".bliptar__textarea");c&&(c.addEventListener("input",()=>{this.answers[`q${this.currentIndex}`]=c.value}),setTimeout(()=>c.focus(),100));let d=this.container.querySelector(".bliptar__nav-btn--back");d&&d.addEventListener("click",()=>this.goBack());let b=this.container.querySelector(".bliptar__nav-btn--next");b&&b.addEventListener("click",()=>this.goNext())}goBack(){this.currentIndex>0&&(this.currentIndex--,this.renderQuestion())}async goNext(){this.currentIndex===this.form.questions.length-1?await this.submit():(this.currentIndex++,this.renderQuestion())}async submit(){if(this.container){let r=this.container.querySelector(".bliptar__card");r&&(r.innerHTML='<div class="bliptar__loading"><div class="bliptar__spinner"></div></div>')}try{await this.options.onSubmit(this.answers),this.form.behavior.showThankYou?(this.renderThankYou(),setTimeout(()=>this.options.onDismiss(),this.form.behavior.thankYouDuration||2e3)):this.options.onDismiss()}catch{this.options.onDismiss()}}renderThankYou(){if(!this.container)return;let{appearance:r,behavior:t}=this.form,e="";r.backdrop&&(e+='<div class="bliptar__backdrop"></div>'),e+=`<div class="bliptar__card">
386
+ </div>`;case"star-rating":let o='<div class="bliptar__stars">';for(let s=1;s<=e.maxStars;s++)o+=`<span class="bliptar__star${r>=s?" bliptar__star--active":""}" data-value="${s}">\u2605</span>`;return o+"</div>";case"emoji-scale":let a=["\u{1F61E}","\u{1F615}","\u{1F610}","\u{1F642}","\u{1F60A}"],n=["\u{1F61E}","\u{1F610}","\u{1F60A}"],l=e.scale===3?n:a,p='<div class="bliptar__emojis">';return l.forEach((s,d)=>{p+=`<span class="bliptar__emoji${r===d+1?" bliptar__emoji--active":""}" data-value="${d+1}" title="${e.labels?.[d]||""}">${s}</span>`}),p+"</div>";case"nps":let c='<div class="bliptar__nps">';for(let s=0;s<=10;s++)c+=`<button class="bliptar__nps-btn${r===s?" bliptar__nps-btn--selected":""}" data-value="${s}">${s}</button>`;return c+=`</div><div class="bliptar__nps-labels"><span>${this.escapeHtml(e.lowLabel)}</span><span>${this.escapeHtml(e.highLabel)}</span></div>`,c;case"single-choice":let b='<div class="bliptar__options">';return e.options.forEach(s=>{b+=`<button class="bliptar__btn${r===s?" bliptar__btn--selected":""}" data-value="${this.escapeHtml(s)}">${this.escapeHtml(s)}</button>`}),b+"</div>";case"text-input":return`<textarea class="bliptar__textarea" placeholder="${this.escapeHtml(e.placeholder)}" maxlength="${e.maxLength}">${r||""}</textarea>`;default:return""}}attachEventListeners(){if(!this.container)return;let e=this.form.questions[this.currentIndex],{behavior:t}=this.form,r=this.container.querySelector(".bliptar__close");r&&r.addEventListener("click",()=>this.options.onDismiss());let o=this.container.querySelector(".bliptar__backdrop");o&&t.allowDismiss&&o.addEventListener("click",()=>this.options.onDismiss());let a=s=>{this.answers[`q${this.currentIndex}`]=s,t.autoAdvance&&e.type!=="text-input"?setTimeout(()=>this.goNext(),t.autoAdvanceDelay||300):this.renderQuestion()};this.container.querySelectorAll(".bliptar__btn, .bliptar__nps-btn").forEach(s=>{s.addEventListener("click",()=>{let d=s.dataset.value;e.type==="binary"?a(d==="true"):e.type==="nps"?a(parseInt(d,10)):a(d)})});let n=this.container.querySelectorAll(".bliptar__star");n.forEach((s,d)=>{s.addEventListener("mouseenter",()=>{n.forEach((x,E)=>x.classList.toggle("bliptar__star--active",E<=d))}),s.addEventListener("click",()=>a(parseInt(s.dataset.value,10)))});let l=this.container.querySelector(".bliptar__stars");l&&l.addEventListener("mouseleave",()=>{let s=this.answers[`q${this.currentIndex}`];n.forEach((d,x)=>d.classList.toggle("bliptar__star--active",s?x<s:!1))}),this.container.querySelectorAll(".bliptar__emoji").forEach(s=>{s.addEventListener("click",()=>a(parseInt(s.dataset.value,10)))});let p=this.container.querySelector(".bliptar__textarea");p&&(p.addEventListener("input",()=>{this.answers[`q${this.currentIndex}`]=p.value}),setTimeout(()=>p.focus(),100));let c=this.container.querySelector(".bliptar__nav-btn--back");c&&c.addEventListener("click",()=>this.goBack());let b=this.container.querySelector(".bliptar__nav-btn--next");b&&b.addEventListener("click",()=>this.goNext())}goBack(){this.currentIndex>0&&(this.currentIndex--,this.renderQuestion())}async goNext(){this.currentIndex===this.form.questions.length-1?await this.submit():(this.currentIndex++,this.renderQuestion())}async submit(){if(this.container){let e=this.container.querySelector(".bliptar__card");e&&(e.innerHTML='<div class="bliptar__loading"><div class="bliptar__spinner"></div></div>')}try{await this.options.onSubmit(this.answers),this.form.behavior.showThankYou?(this.renderThankYou(),setTimeout(()=>this.options.onDismiss(),this.form.behavior.thankYouDuration||2e3)):this.options.onDismiss()}catch{this.options.onDismiss()}}renderThankYou(){if(!this.container)return;let{appearance:e,behavior:t}=this.form,r="";e.backdrop&&(r+='<div class="bliptar__backdrop"></div>'),r+=`<div class="bliptar__card">
387
387
  <div class="bliptar__thankyou">
388
388
  <div class="bliptar__thankyou-emoji">\u{1F389}</div>
389
389
  <div class="bliptar__thankyou-text">${this.escapeHtml(t.thankYouMessage||"Thank you for your feedback!")}</div>
390
390
  </div>
391
- </div>`,this.container.innerHTML=e}};function C(){let i="ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789",r="";for(let t=0;t<16;t++)r+=i.charAt(Math.floor(Math.random()*i.length));return`sess_${r}`}function w(){let i=navigator.userAgent;return/tablet|ipad|playbook|silk/i.test(i)?"tablet":/mobile|iphone|ipod|android|blackberry|opera mini|iemobile/i.test(i)?"mobile":"desktop"}function $(i,r){let t;return(...e)=>{clearTimeout(t),t=setTimeout(()=>i(...e),r)}}var j="https://api.bliptar.com",m=class{constructor(r){this.renderer=null;this.scrollDepth=0;this.isInitialized=!1;this.eventListeners=[];this.config={apiUrl:j,debug:!1,onShow:()=>{},onSubmit:()=>{},onDismiss:()=>{},onError:()=>{},...r},this.sessionId=this.loadOrCreateSessionId(),this.pageLoadTime=Date.now()}init(){if(this.isInitialized)return;this.isInitialized=!0,this.log("Initializing Bliptar SDK");let r=$(()=>{let t=document.documentElement,e=window.scrollY||t.scrollTop,a=t.scrollHeight-t.clientHeight;this.scrollDepth=a>0?e/a:0},100);this.addEventListener(window,"scroll",r),this.track("page_view")}identify(r,t){this.config.userId=r,this.config.userAttributes={...this.config.userAttributes,...t},this.log("User identified:",r)}async track(r,t){this.log("Tracking event:",r,t);let e=this.getContext();try{let a=await fetch(`${this.config.apiUrl}/api/sdk/trigger`,{method:"POST",headers:{"Content-Type":"application/json",Authorization:`Bearer ${this.config.apiKey}`},body:JSON.stringify({session_id:this.sessionId,user_id:this.config.userId,event:r,event_data:t||{},context:e})});if(!a.ok)throw new Error(`API error: ${a.status}`);let s=await a.json();s.show_form&&s.form&&await this.displayForm(s.form,s.campaign_id)}catch(a){this.handleError(a)}}async showForm(r){this.log("Manually showing form:",r);try{let t=await fetch(`${this.config.apiUrl}/api/sdk/form/${r}`,{headers:{Authorization:`Bearer ${this.config.apiKey}`}});if(!t.ok)throw new Error(`Failed to fetch form: ${t.status}`);let e=await t.json();await this.displayForm(e)}catch(t){this.handleError(t)}}destroy(){this.log("Destroying Bliptar SDK"),this.eventListeners.forEach(({target:r,type:t,handler:e})=>{r.removeEventListener(t,e)}),this.eventListeners=[],this.renderer&&(this.renderer.destroy(),this.renderer=null),this.isInitialized=!1}async displayForm(r,t){this.log("Displaying form:",r.formId),this.config.onShow?.(r),this.renderer=new g(r,{onSubmit:async e=>{await this.submitResponse(r.formId,e,t),this.config.onSubmit?.(e)},onDismiss:()=>{this.config.onDismiss?.(),this.renderer?.destroy(),this.renderer=null}}),this.renderer.render()}async submitResponse(r,t,e){this.log("Submitting response:",r,t);let a=this.getContext(),s=new Date().toISOString();try{await fetch(`${this.config.apiUrl}/api/sdk/submit`,{method:"POST",headers:{"Content-Type":"application/json",Authorization:`Bearer ${this.config.apiKey}`},body:JSON.stringify({session_id:this.sessionId,user_id:this.config.userId,form_id:r,campaign_id:e,answers:t,context:a,completed_at:s})})}catch(o){this.handleError(o)}}getContext(){return{pageUrl:window.location.href,referrer:document.referrer,timeOnPage:Math.floor((Date.now()-this.pageLoadTime)/1e3),scrollDepth:Math.round(this.scrollDepth*100)/100,deviceType:w()}}loadOrCreateSessionId(){let r="bliptar_session",t=sessionStorage.getItem(r);return t||(t=C(),sessionStorage.setItem(r,t)),t}addEventListener(r,t,e){r.addEventListener(t,e),this.eventListeners.push({target:r,type:t,handler:e})}log(...r){this.config.debug&&console.log("[Bliptar]",...r)}handleError(r){this.log("Error:",r),this.config.onError?.(r)}};function T(i){return new m(i)}if(typeof window<"u"){let i=document.currentScript;if(i?.dataset.apiKey){let r=T({apiKey:i.dataset.apiKey,debug:i.dataset.debug==="true"});window.bliptar=r,r.init()}}export{m as Bliptar,T as createBliptar};
391
+ </div>`,this.container.innerHTML=r}};function w(){let i="ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789",e="";for(let t=0;t<16;t++)e+=i.charAt(Math.floor(Math.random()*i.length));return`sess_${e}`}function _(){let i=navigator.userAgent;return/tablet|ipad|playbook|silk/i.test(i)?"tablet":/mobile|iphone|ipod|android|blackberry|opera mini|iemobile/i.test(i)?"mobile":"desktop"}function $(i,e){let t;return(...r)=>{clearTimeout(t),t=setTimeout(()=>i(...r),e)}}var B="https://api.bliptar.com",m=class{constructor(e){this.renderer=null;this.scrollDepth=0;this.isInitialized=!1;this.eventListeners=[];this.trackedClicks=new Set;this.exitIntentTriggered=!1;this.exitIntentCooldownTimer=null;this.config={apiUrl:B,debug:!1,onShow:()=>{},onSubmit:()=>{},onDismiss:()=>{},onError:()=>{},...e},this.sessionId=this.loadOrCreateSessionId(),this.pageLoadTime=Date.now()}init(){if(this.isInitialized)return;this.isInitialized=!0,this.log("Initializing Bliptar SDK");let e=$(()=>{let t=document.documentElement,r=window.scrollY||t.scrollTop,o=t.scrollHeight-t.clientHeight;this.scrollDepth=o>0?r/o:0},100);this.addEventListener(window,"scroll",e),this.track("page_view")}identify(e,t){this.config.userId=e,this.config.userAttributes={...this.config.userAttributes,...t},this.log("User identified:",e)}async track(e,t){this.log("Tracking event:",e,t);let r=this.getContext();try{let o=await fetch(`${this.config.apiUrl}/api/sdk/trigger`,{method:"POST",headers:{"Content-Type":"application/json",Authorization:`Bearer ${this.config.apiKey}`},body:JSON.stringify({session_id:this.sessionId,user_id:this.config.userId,event:e,event_data:t||{},context:r})});if(!o.ok)throw new Error(`API error: ${o.status}`);let a=await o.json();a.show_form&&a.form&&await this.displayForm(a.form,a.campaign_id)}catch(o){this.handleError(o)}}async showForm(e){this.log("Manually showing form:",e);try{let t=await fetch(`${this.config.apiUrl}/api/sdk/form/${e}`,{headers:{Authorization:`Bearer ${this.config.apiKey}`}});if(!t.ok)throw new Error(`Failed to fetch form: ${t.status}`);let r=await t.json();await this.displayForm(r)}catch(t){this.handleError(t)}}trackClicks(e){let{selector:t,name:r,once:o=!1}=e,a=r||t;this.log("Setting up click tracking for:",t);let n=l=>{let c=l.target.closest(t);c&&(o&&this.trackedClicks.has(a)||(this.log("Button click detected:",a),o&&this.trackedClicks.add(a),this.track("button_click",{selector:t,name:a,element_text:c.textContent?.trim().slice(0,100)||"",element_id:c.id||null,element_class:c.className||null})))};this.addEventListener(document,"click",n)}enableExitIntent(e={}){let{threshold:t=50,cooldown:r=1e4,once:o=!0}=e;this.log("Enabling exit intent detection");let a=l=>{l.clientY>t||o&&this.exitIntentTriggered||this.exitIntentCooldownTimer||(this.log("Exit intent detected"),this.exitIntentTriggered=!0,this.track("exit_intent",{trigger:"mouse_leave",mouse_y:l.clientY}),o||(this.exitIntentCooldownTimer=setTimeout(()=>{this.exitIntentCooldownTimer=null},r)))};this.addEventListener(document,"mouseleave",a);let n=()=>{if(document.visibilityState==="hidden"){if(o&&this.exitIntentTriggered)return;this.log("Exit intent detected (visibility change)"),this.exitIntentTriggered=!0,this.track("exit_intent",{trigger:"visibility_change"})}};_()!=="desktop"&&this.addEventListener(document,"visibilitychange",n)}destroy(){this.log("Destroying Bliptar SDK"),this.eventListeners.forEach(({target:e,type:t,handler:r})=>{e.removeEventListener(t,r)}),this.eventListeners=[],this.renderer&&(this.renderer.destroy(),this.renderer=null),this.exitIntentCooldownTimer&&(clearTimeout(this.exitIntentCooldownTimer),this.exitIntentCooldownTimer=null),this.trackedClicks.clear(),this.exitIntentTriggered=!1,this.isInitialized=!1}async displayForm(e,t){this.log("Displaying form:",e.formId),this.config.onShow?.(e),this.renderer=new g(e,{onSubmit:async r=>{await this.submitResponse(e.formId,r,t),this.config.onSubmit?.(r)},onDismiss:()=>{this.config.onDismiss?.(),this.renderer?.destroy(),this.renderer=null}}),this.renderer.render()}async submitResponse(e,t,r){this.log("Submitting response:",e,t);let o=this.getContext(),a=new Date().toISOString();try{await fetch(`${this.config.apiUrl}/api/sdk/submit`,{method:"POST",headers:{"Content-Type":"application/json",Authorization:`Bearer ${this.config.apiKey}`},body:JSON.stringify({session_id:this.sessionId,user_id:this.config.userId,form_id:e,campaign_id:r,answers:t,context:o,completed_at:a})})}catch(n){this.handleError(n)}}getContext(){return{pageUrl:window.location.href,referrer:document.referrer,timeOnPage:Math.floor((Date.now()-this.pageLoadTime)/1e3),scrollDepth:Math.round(this.scrollDepth*100)/100,deviceType:_()}}loadOrCreateSessionId(){let e="bliptar_session",t=sessionStorage.getItem(e);return t||(t=w(),sessionStorage.setItem(e,t)),t}addEventListener(e,t,r){e.addEventListener(t,r),this.eventListeners.push({target:e,type:t,handler:r})}log(...e){this.config.debug&&console.log("[Bliptar]",...e)}handleError(e){this.log("Error:",e),this.config.onError?.(e)}};function T(i){return new m(i)}if(typeof window<"u"){let i=document.currentScript;if(i?.dataset.apiKey){let e=T({apiKey:i.dataset.apiKey,debug:i.dataset.debug==="true"});window.bliptar=e,e.init()}}export{m as Bliptar,T as createBliptar};
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@bliptarjs/sdk",
3
- "version": "0.1.0",
3
+ "version": "0.2.0",
4
4
  "description": "Bliptar SDK - Lightweight micro-feedback for web apps",
5
5
  "type": "module",
6
6
  "main": "./dist/index.cjs",
@@ -14,8 +14,17 @@
14
14
  }
15
15
  },
16
16
  "files": [
17
- "dist"
17
+ "dist",
18
+ "README.md"
18
19
  ],
20
+ "repository": {
21
+ "type": "git",
22
+ "url": "https://github.com/bliptar/sdk"
23
+ },
24
+ "bugs": {
25
+ "url": "https://github.com/bliptar/sdk/issues"
26
+ },
27
+ "homepage": "https://bliptar.com/docs/sdk",
19
28
  "scripts": {
20
29
  "build": "tsup src/index.ts --format esm,cjs --dts --minify",
21
30
  "dev": "tsup src/index.ts --format esm,cjs --dts --watch",