@bliptarjs/sdk 0.1.0 → 0.2.1

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,558 @@ 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
+ debug: false, // optional
56
+ userId: 'user-123', // optional
57
+ userAttributes: { plan: 'pro' }, // optional
58
+ onShow: (form) => console.log('Showing form:', form.formId),
59
+ onSubmit: (answers) => console.log('Submitted:', answers),
60
+ onDismiss: () => console.log('Form dismissed'),
61
+ onError: (error) => console.error('Error:', error),
34
62
  });
63
+ ```
64
+
65
+ #### Configuration Options
66
+
67
+ | Option | Type | Default | Description |
68
+ |--------|------|---------|-------------|
69
+ | `apiKey` | `string` | **required** | Your Bliptar API key |
70
+ | `debug` | `boolean` | `false` | Enable console logging for debugging |
71
+ | `userId` | `string` | - | Pre-set user ID for attribution |
72
+ | `userAttributes` | `object` | - | Pre-set user attributes for targeting |
73
+ | `onShow` | `function` | - | Callback when a form is displayed |
74
+ | `onSubmit` | `function` | - | Callback when a response is submitted |
75
+ | `onDismiss` | `function` | - | Callback when a form is dismissed |
76
+ | `onError` | `function` | - | Callback when an error occurs |
35
77
 
36
- blip.init();
78
+ ---
79
+
80
+ ### `init()`
81
+
82
+ Initializes the SDK. This sets up event listeners and triggers a `page_view` event.
83
+
84
+ ```javascript
85
+ bliptar.init();
37
86
  ```
38
87
 
39
- ### Identify Users
88
+ > **Note:** Call this once after creating the instance, typically when your app loads.
89
+
90
+ ---
40
91
 
41
- Associate feedback with specific users:
92
+ ### `identify(userId, attributes?)`
93
+
94
+ Associates feedback with a specific user. Call this when a user logs in.
42
95
 
43
96
  ```javascript
44
- blip.identify('user-123', {
97
+ // Basic identification
98
+ bliptar.identify('user-123');
99
+
100
+ // With attributes for targeting
101
+ bliptar.identify('user-123', {
102
+ email: 'user@example.com',
45
103
  plan: 'pro',
46
104
  company: 'Acme Inc',
105
+ signupDate: '2024-01-15',
47
106
  });
48
107
  ```
49
108
 
50
- ### Track Events
109
+ User attributes can be used in campaign targeting rules (e.g., only show to "pro" plan users).
110
+
111
+ ---
51
112
 
52
- Track events that may trigger feedback forms:
113
+ ### `track(event, data?)`
114
+
115
+ Tracks a custom event that may trigger a feedback form.
53
116
 
54
117
  ```javascript
55
- blip.track('checkout_complete', {
118
+ // Simple event
119
+ bliptar.track('checkout_complete');
120
+
121
+ // With event data
122
+ bliptar.track('checkout_complete', {
56
123
  orderId: 'order-456',
57
124
  total: 99.99,
125
+ items: 3,
126
+ });
127
+
128
+ // Feature usage
129
+ bliptar.track('feature_used', {
130
+ feature: 'export_pdf',
131
+ duration: 5000,
58
132
  });
59
133
  ```
60
134
 
61
- ### Show Forms Manually
135
+ Configure campaigns in the dashboard to trigger forms based on these events.
136
+
137
+ ---
138
+
139
+ ### `trackClicks(options)`
62
140
 
63
- Display a specific form programmatically:
141
+ 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
142
 
65
143
  ```javascript
66
- await blip.showForm('form-id');
144
+ // Track clicks on a specific button
145
+ bliptar.trackClicks({
146
+ selector: '#upgrade-button',
147
+ name: 'upgrade-cta',
148
+ });
149
+
150
+ // Track clicks on all pricing buttons
151
+ bliptar.trackClicks({
152
+ selector: '.pricing-cta',
153
+ name: 'pricing-click',
154
+ });
155
+
156
+ // Track only the first click
157
+ bliptar.trackClicks({
158
+ selector: '.signup-button',
159
+ name: 'signup-click',
160
+ once: true,
161
+ });
67
162
  ```
68
163
 
69
- ### Lifecycle Callbacks
164
+ #### Options
165
+
166
+ | Option | Type | Default | Description |
167
+ |--------|------|---------|-------------|
168
+ | `selector` | `string` | **required** | CSS selector for elements to track |
169
+ | `name` | `string` | `selector` | Friendly name for the click target |
170
+ | `once` | `boolean` | `false` | Only track the first click per session |
171
+
172
+ #### Event Data Sent
173
+
174
+ When a click is detected, the following data is sent:
70
175
 
71
176
  ```javascript
72
- const blip = createBliptar({
73
- apiKey: 'your-api-key',
74
- onShow: (form) => {
75
- console.log('Form displayed:', form.formId);
76
- },
177
+ {
178
+ selector: '.pricing-cta',
179
+ name: 'pricing-click',
180
+ element_text: 'Get Started',
181
+ element_id: 'cta-btn',
182
+ element_class: 'pricing-cta btn-primary'
183
+ }
184
+ ```
185
+
186
+ ---
187
+
188
+ ### `enableExitIntent(options?)`
189
+
190
+ Enables exit intent detection. Triggers an `exit_intent` event when a user appears to be leaving the page.
191
+
192
+ ```javascript
193
+ // Basic usage (triggers once per session)
194
+ bliptar.enableExitIntent();
195
+
196
+ // Custom configuration
197
+ bliptar.enableExitIntent({
198
+ threshold: 50, // Pixels from top of viewport
199
+ cooldown: 10000, // Ms before can trigger again
200
+ once: true, // Only trigger once per session
201
+ });
202
+ ```
203
+
204
+ #### Options
205
+
206
+ | Option | Type | Default | Description |
207
+ |--------|------|---------|-------------|
208
+ | `threshold` | `number` | `50` | Distance in pixels from top of viewport to trigger |
209
+ | `cooldown` | `number` | `10000` | Milliseconds before exit intent can trigger again |
210
+ | `once` | `boolean` | `true` | Only trigger once per session |
211
+
212
+ #### How It Works
213
+
214
+ - **Desktop:** Detects when the mouse cursor leaves the viewport from the top (user moving to close tab, click back, or navigate away)
215
+ - **Mobile:** Detects when the page visibility changes (user switching apps or tabs)
216
+
217
+ ---
218
+
219
+ ### `showForm(formId)`
220
+
221
+ Manually displays a specific form, bypassing campaign rules.
222
+
223
+ ```javascript
224
+ // Show a form programmatically
225
+ await bliptar.showForm('form_abc123');
226
+
227
+ // Example: Show after completing onboarding
228
+ function completeOnboarding() {
229
+ // ... onboarding logic
230
+ bliptar.showForm('form_onboarding_feedback');
231
+ }
232
+ ```
233
+
234
+ ---
235
+
236
+ ### `destroy()`
237
+
238
+ Removes all event listeners and cleans up the SDK. Call this when unmounting your app or when done collecting feedback.
239
+
240
+ ```javascript
241
+ bliptar.destroy();
242
+ ```
243
+
244
+ ---
245
+
246
+ ## Usage Examples
247
+
248
+ ### Basic Setup
249
+
250
+ ```javascript
251
+ import { createBliptar } from '@bliptarjs/sdk';
252
+
253
+ const bliptar = createBliptar({
254
+ apiKey: 'blip_live_xxxxxxxx',
255
+ });
256
+
257
+ bliptar.init();
258
+ ```
259
+
260
+ ### With User Identification
261
+
262
+ ```javascript
263
+ import { createBliptar } from '@bliptarjs/sdk';
264
+
265
+ const bliptar = createBliptar({
266
+ apiKey: 'blip_live_xxxxxxxx',
267
+ });
268
+
269
+ bliptar.init();
270
+
271
+ // When user logs in
272
+ function onUserLogin(user) {
273
+ bliptar.identify(user.id, {
274
+ email: user.email,
275
+ plan: user.subscription.plan,
276
+ createdAt: user.createdAt,
277
+ });
278
+ }
279
+ ```
280
+
281
+ ### E-commerce Checkout Feedback
282
+
283
+ ```javascript
284
+ import { createBliptar } from '@bliptarjs/sdk';
285
+
286
+ const bliptar = createBliptar({
287
+ apiKey: 'blip_live_xxxxxxxx',
77
288
  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);
289
+ // Send to your analytics
290
+ analytics.track('feedback_submitted', answers);
85
291
  },
86
292
  });
293
+
294
+ bliptar.init();
295
+
296
+ // Track successful purchase
297
+ function onPurchaseComplete(order) {
298
+ bliptar.track('purchase_complete', {
299
+ orderId: order.id,
300
+ total: order.total,
301
+ itemCount: order.items.length,
302
+ });
303
+ }
87
304
  ```
88
305
 
89
- ### Cleanup
306
+ ### Exit Intent Survey
307
+
308
+ ```javascript
309
+ import { createBliptar } from '@bliptarjs/sdk';
310
+
311
+ const bliptar = createBliptar({
312
+ apiKey: 'blip_live_xxxxxxxx',
313
+ });
314
+
315
+ bliptar.init();
90
316
 
91
- Remove event listeners and clean up when done:
317
+ // Enable exit intent on pricing page
318
+ if (window.location.pathname === '/pricing') {
319
+ bliptar.enableExitIntent({
320
+ once: true, // Only show once
321
+ });
322
+ }
323
+ ```
324
+
325
+ ### Button Click Feedback
92
326
 
93
327
  ```javascript
94
- blip.destroy();
328
+ import { createBliptar } from '@bliptarjs/sdk';
329
+
330
+ const bliptar = createBliptar({
331
+ apiKey: 'blip_live_xxxxxxxx',
332
+ });
333
+
334
+ bliptar.init();
335
+
336
+ // Track clicks on upgrade buttons
337
+ bliptar.trackClicks({
338
+ selector: '[data-track="upgrade"]',
339
+ name: 'upgrade-button',
340
+ });
341
+
342
+ // Track clicks on help buttons
343
+ bliptar.trackClicks({
344
+ selector: '.help-button',
345
+ name: 'help-click',
346
+ });
95
347
  ```
96
348
 
97
- ## Configuration
349
+ ### React Integration
98
350
 
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 |
351
+ ```jsx
352
+ import { useEffect } from 'react';
353
+ import { createBliptar } from '@bliptarjs/sdk';
354
+
355
+ const bliptar = createBliptar({
356
+ apiKey: 'blip_live_xxxxxxxx',
357
+ });
358
+
359
+ function App() {
360
+ useEffect(() => {
361
+ bliptar.init();
362
+
363
+ return () => {
364
+ bliptar.destroy();
365
+ };
366
+ }, []);
367
+
368
+ return <div>Your app</div>;
369
+ }
370
+
371
+ // In a component that needs to identify users
372
+ function UserProfile({ user }) {
373
+ useEffect(() => {
374
+ if (user) {
375
+ bliptar.identify(user.id, {
376
+ email: user.email,
377
+ plan: user.plan,
378
+ });
379
+ }
380
+ }, [user]);
381
+
382
+ return <div>Welcome, {user.name}</div>;
383
+ }
384
+ ```
385
+
386
+ ### Next.js Integration
387
+
388
+ ```jsx
389
+ // lib/bliptar.js
390
+ import { createBliptar } from '@bliptarjs/sdk';
391
+
392
+ export const bliptar = typeof window !== 'undefined'
393
+ ? createBliptar({ apiKey: process.env.NEXT_PUBLIC_BLIPTAR_API_KEY })
394
+ : null;
395
+
396
+ // app/layout.js or pages/_app.js
397
+ 'use client';
398
+
399
+ import { useEffect } from 'react';
400
+ import { bliptar } from '@/lib/bliptar';
401
+
402
+ export default function RootLayout({ children }) {
403
+ useEffect(() => {
404
+ bliptar?.init();
405
+
406
+ return () => {
407
+ bliptar?.destroy();
408
+ };
409
+ }, []);
410
+
411
+ return (
412
+ <html>
413
+ <body>{children}</body>
414
+ </html>
415
+ );
416
+ }
417
+ ```
418
+
419
+ ### Vue Integration
420
+
421
+ ```vue
422
+ <script setup>
423
+ import { onMounted, onUnmounted } from 'vue';
424
+ import { createBliptar } from '@bliptarjs/sdk';
425
+
426
+ const bliptar = createBliptar({
427
+ apiKey: 'blip_live_xxxxxxxx',
428
+ });
429
+
430
+ onMounted(() => {
431
+ bliptar.init();
432
+ });
433
+
434
+ onUnmounted(() => {
435
+ bliptar.destroy();
436
+ });
437
+ </script>
438
+ ```
439
+
440
+ ---
441
+
442
+ ## Automatic Tracking
443
+
444
+ The SDK automatically tracks the following without any additional code:
445
+
446
+ | Data | Description |
447
+ |------|-------------|
448
+ | `page_view` | Fired on `init()` |
449
+ | `scroll_depth` | Percentage scrolled (0-100%) |
450
+ | `time_on_page` | Seconds spent on page |
451
+ | `device_type` | `desktop`, `mobile`, or `tablet` |
452
+ | `page_url` | Current page URL |
453
+ | `referrer` | Previous page URL |
454
+
455
+ This data is sent with every trigger request and can be used in campaign conditions.
456
+
457
+ ---
106
458
 
107
459
  ## Form Types
108
460
 
109
461
  The SDK supports multiple feedback form types:
110
462
 
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
463
+ | Type | Description |
464
+ |------|-------------|
465
+ | **Binary** | Thumbs up/down, Yes/No questions |
466
+ | **Star Rating** | 1-5 star ratings with optional half stars |
467
+ | **Emoji Scale** | 3 or 5 point emoji scales |
468
+ | **NPS** | Net Promoter Score (0-10) |
469
+ | **Single Choice** | Multiple choice questions |
470
+ | **Text Input** | Free-form text responses |
471
+
472
+ Forms are configured in the Bliptar dashboard and automatically rendered by the SDK.
473
+
474
+ ---
475
+
476
+ ## TypeScript Support
477
+
478
+ The SDK is written in TypeScript and includes full type definitions.
479
+
480
+ ```typescript
481
+ import {
482
+ createBliptar,
483
+ BliptarInstance,
484
+ BliptarConfig,
485
+ ClickTrackingOptions,
486
+ ExitIntentOptions,
487
+ } from '@bliptarjs/sdk';
488
+
489
+ const config: BliptarConfig = {
490
+ apiKey: 'blip_live_xxxxxxxx',
491
+ debug: true,
492
+ onSubmit: (answers) => {
493
+ console.log(answers);
494
+ },
495
+ };
496
+
497
+ const bliptar: BliptarInstance = createBliptar(config);
498
+
499
+ // Type-safe click tracking
500
+ const clickOptions: ClickTrackingOptions = {
501
+ selector: '.cta-button',
502
+ name: 'main-cta',
503
+ once: true,
504
+ };
505
+ bliptar.trackClicks(clickOptions);
506
+
507
+ // Type-safe exit intent
508
+ const exitOptions: ExitIntentOptions = {
509
+ threshold: 50,
510
+ once: true,
511
+ };
512
+ bliptar.enableExitIntent(exitOptions);
513
+ ```
514
+
515
+ ---
117
516
 
118
517
  ## Browser Support
119
518
 
120
- - Chrome (latest)
121
- - Firefox (latest)
122
- - Safari (latest)
123
- - Edge (latest)
519
+ | Browser | Supported |
520
+ |---------|-----------|
521
+ | Chrome | Latest 2 versions |
522
+ | Firefox | Latest 2 versions |
523
+ | Safari | Latest 2 versions |
524
+ | Edge | Latest 2 versions |
525
+
526
+ ---
124
527
 
125
528
  ## Bundle Size
126
529
 
127
- ~7KB gzipped
530
+ - **ESM:** ~25KB (minified)
531
+ - **Gzipped:** ~7KB
532
+
533
+ The SDK has zero dependencies.
534
+
535
+ ---
536
+
537
+ ## Troubleshooting
538
+
539
+ ### Forms not showing?
540
+
541
+ 1. **Check your API key** - Ensure it's valid and for the correct environment
542
+ 2. **Check campaign rules** - Verify your campaign is active and targeting rules match
543
+ 3. **Enable debug mode** - Set `debug: true` to see console logs
544
+ 4. **Check throttling** - Campaigns have frequency limits to avoid annoying users
545
+
546
+ ### Debug Mode
547
+
548
+ ```javascript
549
+ const bliptar = createBliptar({
550
+ apiKey: 'blip_live_xxxxxxxx',
551
+ debug: true, // Enables console logging
552
+ });
553
+ ```
554
+
555
+ This will log:
556
+ - SDK initialization
557
+ - Events being tracked
558
+ - Form display triggers
559
+ - API responses
560
+ - Errors
561
+
562
+ ---
128
563
 
129
564
  ## License
130
565
 
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.1",
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",