@bliptarjs/sdk 0.2.1 → 0.3.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,422 +1,154 @@
1
- # @bliptarjs/sdk
2
-
3
- Lightweight SDK for collecting in-app user feedback. Designed to be small (~7KB gzipped) and non-intrusive.
4
-
5
- ## Installation
6
-
7
- ```bash
8
- npm install @bliptarjs/sdk
9
- ```
10
-
11
- ```bash
12
- yarn add @bliptarjs/sdk
13
- ```
14
-
15
- ```bash
16
- pnpm add @bliptarjs/sdk
17
- ```
18
-
19
- ## Quick Start
20
-
21
- ```javascript
22
- import { createBliptar } from '@bliptarjs/sdk';
23
-
24
- const bliptar = createBliptar({
25
- apiKey: 'your-api-key',
26
- });
27
-
28
- bliptar.init();
29
- ```
30
-
31
- That's it! The SDK will automatically track page views and display forms based on your campaign rules configured in the Bliptar dashboard.
32
-
33
- ## Core Concepts
34
-
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
51
- import { createBliptar } from '@bliptarjs/sdk';
52
-
53
- const bliptar = createBliptar({
54
- apiKey: 'your-api-key',
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),
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 |
77
-
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();
86
- ```
1
+ <div align="center">
87
2
 
88
- > **Note:** Call this once after creating the instance, typically when your app loads.
3
+ # @bliptarjs/sdk
89
4
 
90
- ---
5
+ **Micro-feedback that users actually respond to.**
91
6
 
92
- ### `identify(userId, attributes?)`
7
+ [![npm version](https://img.shields.io/npm/v/@bliptarjs/sdk.svg?style=flat-square)](https://www.npmjs.com/package/@bliptarjs/sdk)
8
+ [![bundle size](https://img.shields.io/bundlephobia/minzip/@bliptarjs/sdk?style=flat-square&label=gzip)](https://bundlephobia.com/package/@bliptarjs/sdk)
9
+ [![license](https://img.shields.io/npm/l/@bliptarjs/sdk.svg?style=flat-square)](LICENSE)
93
10
 
94
- Associates feedback with a specific user. Call this when a user logs in.
11
+ [Website](https://bliptar.com) · [Documentation](https://app.bliptar.com/docs) · [Dashboard](https://app.bliptar.com)
95
12
 
96
- ```javascript
97
- // Basic identification
98
- bliptar.identify('user-123');
99
-
100
- // With attributes for targeting
101
- bliptar.identify('user-123', {
102
- email: 'user@example.com',
103
- plan: 'pro',
104
- company: 'Acme Inc',
105
- signupDate: '2024-01-15',
106
- });
107
- ```
108
-
109
- User attributes can be used in campaign targeting rules (e.g., only show to "pro" plan users).
13
+ </div>
110
14
 
111
15
  ---
112
16
 
113
- ### `track(event, data?)`
17
+ Users abandon your app, churn from your service, and leave features unused – **without ever telling you why**. Traditional surveys are too long. Pop-ups are annoying. You're left guessing.
114
18
 
115
- Tracks a custom event that may trigger a feedback form.
19
+ **Bliptar** captures real-time user sentiment with **nano feedback forms** – quick 1-2 question surveys that appear at exactly the right moment.
116
20
 
117
- ```javascript
118
- // Simple event
119
- bliptar.track('checkout_complete');
120
-
121
- // With event data
122
- bliptar.track('checkout_complete', {
123
- orderId: 'order-456',
124
- total: 99.99,
125
- items: 3,
126
- });
21
+ > One question. Two seconds. Real insights.
127
22
 
128
- // Feature usage
129
- bliptar.track('feature_used', {
130
- feature: 'export_pdf',
131
- duration: 5000,
132
- });
133
- ```
23
+ ## Features
134
24
 
135
- Configure campaigns in the dashboard to trigger forms based on these events.
25
+ - **Thumbs up/down** · **Emoji scales** · **Star ratings** · **NPS** · **Single choice** · **Text input**
26
+ - **Smart triggers** – Page view, scroll depth, time on page, exit intent, custom events
27
+ - **Dashboard controlled** – No code changes to update campaigns
28
+ - **Lightweight** – ~8KB gzipped, zero dependencies
29
+ - **Privacy first** – No cookies, GDPR friendly
136
30
 
137
31
  ---
138
32
 
139
- ### `trackClicks(options)`
140
-
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.
142
-
143
- ```javascript
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
- });
162
- ```
163
-
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:
175
-
176
- ```javascript
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)
33
+ ## Works With
34
+
35
+ <p align="center">
36
+ <img src="https://raw.githubusercontent.com/devicons/devicon/master/icons/react/react-original.svg" alt="React" width="40" height="40"/>
37
+ &nbsp;&nbsp;&nbsp;
38
+ <img src="https://raw.githubusercontent.com/devicons/devicon/master/icons/nextjs/nextjs-original.svg" alt="Next.js" width="40" height="40"/>
39
+ &nbsp;&nbsp;&nbsp;
40
+ <img src="https://raw.githubusercontent.com/devicons/devicon/master/icons/vuejs/vuejs-original.svg" alt="Vue" width="40" height="40"/>
41
+ &nbsp;&nbsp;&nbsp;
42
+ <img src="https://raw.githubusercontent.com/devicons/devicon/master/icons/angularjs/angularjs-original.svg" alt="Angular" width="40" height="40"/>
43
+ &nbsp;&nbsp;&nbsp;
44
+ <img src="https://raw.githubusercontent.com/devicons/devicon/master/icons/javascript/javascript-original.svg" alt="JavaScript" width="40" height="40"/>
45
+ &nbsp;&nbsp;&nbsp;
46
+ <img src="https://raw.githubusercontent.com/devicons/devicon/master/icons/typescript/typescript-original.svg" alt="TypeScript" width="40" height="40"/>
47
+ </p>
216
48
 
217
49
  ---
218
50
 
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.
51
+ ## Installation
239
52
 
240
- ```javascript
241
- bliptar.destroy();
53
+ ```bash
54
+ npm install @bliptarjs/sdk
242
55
  ```
243
56
 
244
- ---
245
-
246
- ## Usage Examples
247
-
248
- ### Basic Setup
57
+ ## Quick Start
249
58
 
250
59
  ```javascript
251
60
  import { createBliptar } from '@bliptarjs/sdk';
252
61
 
253
62
  const bliptar = createBliptar({
254
- apiKey: 'blip_live_xxxxxxxx',
63
+ apiKey: 'your-api-key',
255
64
  });
256
65
 
257
66
  bliptar.init();
258
67
  ```
259
68
 
260
- ### With User Identification
69
+ That's it! The SDK automatically fetches your campaigns and sets up triggers.
261
70
 
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
- ```
71
+ ---
280
72
 
281
- ### E-commerce Checkout Feedback
73
+ ## How It Works
282
74
 
283
- ```javascript
284
- import { createBliptar } from '@bliptarjs/sdk';
75
+ 1. **Create campaigns** in the [Bliptar Dashboard](https://app.bliptar.com)
76
+ 2. **Configure triggers** page view, scroll depth, time on page, exit intent, or custom events
77
+ 3. **Add the SDK** to your app with your API key
78
+ 4. **Done** – forms appear automatically based on your campaign rules
285
79
 
286
- const bliptar = createBliptar({
287
- apiKey: 'blip_live_xxxxxxxx',
288
- onSubmit: (answers) => {
289
- // Send to your analytics
290
- analytics.track('feedback_submitted', answers);
291
- },
292
- });
293
-
294
- bliptar.init();
80
+ ---
295
81
 
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
- }
304
- ```
82
+ ## Core API
305
83
 
306
- ### Exit Intent Survey
84
+ | Method | Description |
85
+ |--------|-------------|
86
+ | `init()` | Initialize SDK and fetch campaigns |
87
+ | `identify(userId, attributes?)` | Associate feedback with a user |
88
+ | `track(event, data?)` | Trigger custom events |
89
+ | `destroy()` | Cleanup listeners and timers |
307
90
 
308
91
  ```javascript
309
- import { createBliptar } from '@bliptarjs/sdk';
310
-
311
- const bliptar = createBliptar({
312
- apiKey: 'blip_live_xxxxxxxx',
313
- });
314
-
315
- bliptar.init();
92
+ // Identify user when they log in
93
+ bliptar.identify('user-123', { plan: 'pro' });
316
94
 
317
- // Enable exit intent on pricing page
318
- if (window.location.pathname === '/pricing') {
319
- bliptar.enableExitIntent({
320
- once: true, // Only show once
321
- });
322
- }
95
+ // Track custom events
96
+ bliptar.track('checkout_complete', { total: 99.99 });
323
97
  ```
324
98
 
325
- ### Button Click Feedback
326
-
327
- ```javascript
328
- import { createBliptar } from '@bliptarjs/sdk';
329
-
330
- const bliptar = createBliptar({
331
- apiKey: 'blip_live_xxxxxxxx',
332
- });
99
+ For the full API reference, see the [Documentation](https://app.bliptar.com/docs).
333
100
 
334
- bliptar.init();
101
+ ---
335
102
 
336
- // Track clicks on upgrade buttons
337
- bliptar.trackClicks({
338
- selector: '[data-track="upgrade"]',
339
- name: 'upgrade-button',
340
- });
103
+ ## Framework Examples
341
104
 
342
- // Track clicks on help buttons
343
- bliptar.trackClicks({
344
- selector: '.help-button',
345
- name: 'help-click',
346
- });
347
- ```
348
-
349
- ### React Integration
105
+ <details>
106
+ <summary><strong>React</strong></summary>
350
107
 
351
108
  ```jsx
352
109
  import { useEffect } from 'react';
353
110
  import { createBliptar } from '@bliptarjs/sdk';
354
111
 
355
112
  const bliptar = createBliptar({
356
- apiKey: 'blip_live_xxxxxxxx',
113
+ apiKey: process.env.REACT_APP_BLIPTAR_KEY,
357
114
  });
358
115
 
359
116
  function App() {
360
117
  useEffect(() => {
361
118
  bliptar.init();
362
-
363
- return () => {
364
- bliptar.destroy();
365
- };
119
+ return () => bliptar.destroy();
366
120
  }, []);
367
121
 
368
122
  return <div>Your app</div>;
369
123
  }
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
124
  ```
125
+ </details>
385
126
 
386
- ### Next.js Integration
127
+ <details>
128
+ <summary><strong>Next.js</strong></summary>
387
129
 
388
130
  ```jsx
389
- // lib/bliptar.js
131
+ // app/providers.js
132
+ 'use client';
133
+ import { useEffect } from 'react';
390
134
  import { createBliptar } from '@bliptarjs/sdk';
391
135
 
392
- export const bliptar = typeof window !== 'undefined'
393
- ? createBliptar({ apiKey: process.env.NEXT_PUBLIC_BLIPTAR_API_KEY })
136
+ const bliptar = typeof window !== 'undefined'
137
+ ? createBliptar({ apiKey: process.env.NEXT_PUBLIC_BLIPTAR_KEY })
394
138
  : null;
395
139
 
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 }) {
140
+ export function BliptarProvider({ children }) {
403
141
  useEffect(() => {
404
142
  bliptar?.init();
405
-
406
- return () => {
407
- bliptar?.destroy();
408
- };
143
+ return () => bliptar?.destroy();
409
144
  }, []);
410
-
411
- return (
412
- <html>
413
- <body>{children}</body>
414
- </html>
415
- );
145
+ return children;
416
146
  }
417
147
  ```
148
+ </details>
418
149
 
419
- ### Vue Integration
150
+ <details>
151
+ <summary><strong>Vue</strong></summary>
420
152
 
421
153
  ```vue
422
154
  <script setup>
@@ -424,142 +156,57 @@ import { onMounted, onUnmounted } from 'vue';
424
156
  import { createBliptar } from '@bliptarjs/sdk';
425
157
 
426
158
  const bliptar = createBliptar({
427
- apiKey: 'blip_live_xxxxxxxx',
428
- });
429
-
430
- onMounted(() => {
431
- bliptar.init();
159
+ apiKey: import.meta.env.VITE_BLIPTAR_KEY,
432
160
  });
433
161
 
434
- onUnmounted(() => {
435
- bliptar.destroy();
436
- });
162
+ onMounted(() => bliptar.init());
163
+ onUnmounted(() => bliptar.destroy());
437
164
  </script>
438
165
  ```
166
+ </details>
439
167
 
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
- ---
458
-
459
- ## Form Types
460
-
461
- The SDK supports multiple feedback form types:
462
-
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.
168
+ <details>
169
+ <summary><strong>Angular</strong></summary>
479
170
 
480
171
  ```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);
172
+ // bliptar.service.ts
173
+ import { Injectable, OnDestroy } from '@angular/core';
174
+ import { createBliptar, BliptarInstance } from '@bliptarjs/sdk';
175
+
176
+ @Injectable({ providedIn: 'root' })
177
+ export class BliptarService implements OnDestroy {
178
+ private bliptar: BliptarInstance;
179
+
180
+ constructor() {
181
+ this.bliptar = createBliptar({ apiKey: environment.bliptarKey });
182
+ this.bliptar.init();
183
+ }
184
+
185
+ ngOnDestroy() {
186
+ this.bliptar.destroy();
187
+ }
188
+ }
513
189
  ```
190
+ </details>
514
191
 
515
192
  ---
516
193
 
517
- ## Browser Support
518
-
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
- ---
527
-
528
- ## Bundle Size
194
+ ## TypeScript
529
195
 
530
- - **ESM:** ~25KB (minified)
531
- - **Gzipped:** ~7KB
196
+ Full TypeScript support included.
532
197
 
533
- The SDK has zero dependencies.
198
+ ```typescript
199
+ import { createBliptar, BliptarConfig, BliptarInstance } from '@bliptarjs/sdk';
200
+ ```
534
201
 
535
202
  ---
536
203
 
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
204
+ ## Links
561
205
 
562
- ---
206
+ - [Website](https://bliptar.com)
207
+ - [Documentation](https://app.bliptar.com/docs)
208
+ - [Dashboard](https://app.bliptar.com)
209
+ - [npm](https://www.npmjs.com/package/@bliptarjs/sdk)
563
210
 
564
211
  ## License
565
212
 
package/dist/index.cjs CHANGED
@@ -1,14 +1,14 @@
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
- --bliptar-bg: ${i.backgroundColor};
3
- --bliptar-surface: ${i.surfaceColor};
4
- --bliptar-text: ${i.textPrimary};
5
- --bliptar-text-secondary: ${i.textSecondary};
6
- --bliptar-primary: ${i.primaryColor};
7
- --bliptar-primary-hover: ${i.primaryHover};
8
- --bliptar-border: ${i.borderColor};
9
- --bliptar-shadow: ${i.shadowColor};
10
- --bliptar-star: ${i.starColor};
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`
1
+ "use strict";var x=Object.defineProperty;var I=Object.getOwnPropertyDescriptor;var L=Object.getOwnPropertyNames;var P=Object.prototype.hasOwnProperty;var D=(o,e)=>{for(var t in e)x(o,t,{get:e[t],enumerable:!0})},A=(o,e,t,r)=>{if(e&&typeof e=="object"||typeof e=="function")for(let i of L(e))!P.call(o,i)&&i!==t&&x(o,i,{get:()=>e[i],enumerable:!(r=I(e,i))||r.enumerable});return o};var B=o=>A(x({},"__esModule",{value:!0}),o);var F={};D(F,{Bliptar:()=>h,createBliptar:()=>C});module.exports=B(F);var b={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"},u={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 j(o,e){try{let r=window.getComputedStyle(o).getPropertyValue(e);return r&&r!=="rgba(0, 0, 0, 0)"?r:null}catch{return null}}function H(o){try{return getComputedStyle(document.documentElement).getPropertyValue(o).trim()||null}catch{return null}}function w(o){let e=o.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=o.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(o,e,t){let[r,i,a]=[o,e,t].map(n=>(n=n/255,n<=.03928?n/12.92:Math.pow((n+.055)/1.055,2.4)));return .2126*r+.7152*i+.0722*a}function _(o){let e=w(o);return e?M(e.r,e.g,e.b)<.5:!1}function g(o,e){let t=w(o);if(!t)return o;let r=i=>Math.min(255,Math.max(0,Math.round(i+e/100*255)));return`rgb(${r(t.r)}, ${r(t.g)}, ${r(t.b)})`}function z(o){return _(o)?"#ffffff":"#1a1a1a"}function R(o,e){let t={},r=null;o&&(r=document.querySelector(o)),r||(r=document.body);let i=j(r,"background-color");if(i){let a=_(i);t.mode=a?"dark":"light",t.backgroundColor=i,t.surfaceColor=g(i,a?10:-5),t.textPrimary=z(i),t.textSecondary=g(t.textPrimary,a?-30:30),t.borderColor=g(i,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 c=H(n);c&&l!=="mode"&&(t[l]=c)}}return t.primaryColor&&(t.primaryHover=g(t.primaryColor,t.mode==="dark"?15:-10)),Object.keys(t).length>0?t:null}function T(o){let{theme:e,customTheme:t,adaptiveOptions:r}=o;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 i=r||{fallback:"light",autoContrast:!0},a=R(i.sourceElement,i.inheritCssVars);return a?{...a.mode==="dark"?u:b,...a}:i.fallback==="dark"?u:b}return e==="auto"?window.matchMedia("(prefers-color-scheme: dark)").matches?u:b:e==="dark"?u:b}function $(o){return`
2
+ --bliptar-bg: ${o.backgroundColor};
3
+ --bliptar-surface: ${o.surfaceColor};
4
+ --bliptar-text: ${o.textPrimary};
5
+ --bliptar-text-secondary: ${o.textSecondary};
6
+ --bliptar-primary: ${o.primaryColor};
7
+ --bliptar-primary-hover: ${o.primaryHover};
8
+ --bliptar-border: ${o.borderColor};
9
+ --bliptar-shadow: ${o.shadowColor};
10
+ --bliptar-star: ${o.starColor};
11
+ `}var f=class{constructor(e,t){this.container=null;this.currentIndex=0;this.answers={};this.form=e,this.options=t,this.theme=T(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
12
  :root { ${$(t)} }
13
13
 
14
14
  .bliptar {
@@ -372,20 +372,20 @@
372
372
  }
373
373
 
374
374
  @media print { .bliptar { display: none !important; } }
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">
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,i=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>`),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">
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(i.question)}</div>`,n+=this.renderAnswerOptions(i),(!r.autoAdvance||i.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
380
  <button class="bliptar__btn${r===!0?" bliptar__btn--selected":""}" data-value="true">
381
381
  ${e.style==="thumbs"?"\u{1F44D} ":""}${this.escapeHtml(e.positiveLabel)}
382
382
  </button>
383
383
  <button class="bliptar__btn${r===!1?" bliptar__btn--selected":""}" data-value="false">
384
384
  ${e.style==="thumbs"?"\u{1F44E} ":""}${this.escapeHtml(e.negativeLabel)}
385
385
  </button>
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">
386
+ </div>`;case"star-rating":let i='<div class="bliptar__stars">';for(let s=1;s<=e.maxStars;s++)i+=`<span class="bliptar__star${r>=s?" bliptar__star--active":""}" data-value="${s}">\u2605</span>`;return i+"</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,c='<div class="bliptar__emojis">';return l.forEach((s,d)=>{c+=`<span class="bliptar__emoji${r===d+1?" bliptar__emoji--active":""}" data-value="${d+1}" title="${e.labels?.[d]||""}">${s}</span>`}),c+"</div>";case"nps":let p='<div class="bliptar__nps">';for(let s=0;s<=10;s++)p+=`<button class="bliptar__nps-btn${r===s?" bliptar__nps-btn--selected":""}" data-value="${s}">${s}</button>`;return p+=`</div><div class="bliptar__nps-labels"><span>${this.escapeHtml(e.lowLabel)}</span><span>${this.escapeHtml(e.highLabel)}</span></div>`,p;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 i=this.container.querySelector(".bliptar__backdrop");i&&t.allowDismiss&&i.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((v,E)=>v.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,v)=>d.classList.toggle("bliptar__star--active",s?v<s:!1))}),this.container.querySelectorAll(".bliptar__emoji").forEach(s=>{s.addEventListener("click",()=>a(parseInt(s.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 p=this.container.querySelector(".bliptar__nav-btn--back");p&&p.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=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});
391
+ </div>`,this.container.innerHTML=r}};function y(){let o="ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789",e="";for(let t=0;t<16;t++)e+=o.charAt(Math.floor(Math.random()*o.length));return`sess_${e}`}function k(){if(typeof navigator>"u")return"desktop";let o=navigator.userAgent;return/tablet|ipad|playbook|silk/i.test(o)?"tablet":/mobile|iphone|ipod|android|blackberry|opera mini|iemobile/i.test(o)?"mobile":"desktop"}function S(o,e){let t;return(...r)=>{clearTimeout(t),t=setTimeout(()=>o(...r),e)}}var O="https://api.bliptar.com",h=class{constructor(e){this.renderer=null;this.scrollDepth=0;this.maxScrollDepth=0;this.isInitialized=!1;this.eventListeners=[];this.trackedClicks=new Set;this.exitIntentTriggered=!1;this.exitIntentCooldownTimer=null;this.timeOnPageTimers=[];this.scrollDepthThresholds=new Set;this.triggeredScrollThresholds=new Set;this.campaigns=[];this.config={apiUrl:O,debug:!1,onShow:()=>{},onSubmit:()=>{},onDismiss:()=>{},onError:()=>{},...e},this.sessionId=this.loadOrCreateSessionId(),this.pageLoadTime=Date.now()}async init(){if(typeof window>"u"||this.isInitialized)return;this.isInitialized=!0,this.log("Initializing Bliptar SDK"),await this.fetchConfigAndSetupTriggers();let e=S(()=>{let t=document.documentElement,r=window.scrollY||t.scrollTop,i=t.scrollHeight-t.clientHeight;this.scrollDepth=i>0?r/i:0;let a=Math.round(this.scrollDepth*100);a>this.maxScrollDepth&&(this.maxScrollDepth=a,this.checkScrollThresholds(a))},100);this.addEventListener(window,"scroll",e),this.track("page_view")}async fetchConfigAndSetupTriggers(){try{let e=await fetch(`${this.config.apiUrl}/api/sdk/config`,{headers:{Authorization:`Bearer ${this.config.apiKey}`}});if(!e.ok){this.log("Failed to fetch config:",e.status);return}let t=await e.json();this.campaigns=t.campaigns||[],this.log("Loaded campaigns:",this.campaigns.length),this.setupTriggersFromCampaigns()}catch(e){this.handleError(e)}}setupTriggersFromCampaigns(){let e=new Set;for(let t of this.campaigns){if(e.add(t.trigger_event),t.trigger_event==="scroll_depth"){let r=t.trigger_conditions?.find(i=>i.field==="scroll_depth_percent");r?.value&&this.scrollDepthThresholds.add(Number(r.value))}if(t.trigger_event==="time_on_page"){let r=t.trigger_conditions?.find(i=>i.field==="time_on_page_seconds");if(r?.value){let i=Number(r.value);this.setupTimeOnPageTrigger(i)}}}this.log("Active trigger types:",Array.from(e)),e.has("exit_intent")&&(this.log("Auto-enabling exit intent detection"),this.enableExitIntent({once:!0})),this.scrollDepthThresholds.size>0&&this.log("Scroll depth thresholds:",Array.from(this.scrollDepthThresholds))}setupTimeOnPageTrigger(e){this.log("Setting up time on page trigger:",e,"seconds");let t=setTimeout(()=>{this.track("time_on_page",{seconds:e,actual_time:Math.floor((Date.now()-this.pageLoadTime)/1e3)})},e*1e3);this.timeOnPageTimers.push(t)}checkScrollThresholds(e){for(let t of this.scrollDepthThresholds)e>=t&&!this.triggeredScrollThresholds.has(t)&&(this.triggeredScrollThresholds.add(t),this.log("Scroll threshold reached:",t+"%"),this.track("scroll_depth",{threshold:t,actual_depth:e}))}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 i=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(!i.ok)throw new Error(`API error: ${i.status}`);let a=await i.json();a.show_form&&a.form&&await this.displayForm(a.form,a.campaign_id)}catch(i){this.handleError(i)}}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:i=!1}=e,a=r||t;this.log("Setting up click tracking for:",t);let n=l=>{let p=l.target.closest(t);p&&(i&&this.trackedClicks.has(a)||(this.log("Button click detected:",a),i&&this.trackedClicks.add(a),this.track("button_click",{selector:t,name:a,element_text:p.textContent?.trim().slice(0,100)||"",element_id:p.id||null,element_class:p.className||null})))};this.addEventListener(document,"click",n)}enableExitIntent(e={}){let{threshold:t=50,cooldown:r=1e4,once:i=!0}=e;this.log("Enabling exit intent detection");let a=l=>{l.clientY>t||i&&this.exitIntentTriggered||this.exitIntentCooldownTimer||(this.log("Exit intent detected"),this.exitIntentTriggered=!0,this.track("exit_intent",{trigger:"mouse_leave",mouse_y:l.clientY}),i||(this.exitIntentCooldownTimer=setTimeout(()=>{this.exitIntentCooldownTimer=null},r)))};this.addEventListener(document,"mouseleave",a);let n=()=>{if(document.visibilityState==="hidden"){if(i&&this.exitIntentTriggered)return;this.log("Exit intent detected (visibility change)"),this.exitIntentTriggered=!0,this.track("exit_intent",{trigger:"visibility_change"})}};k()!=="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.timeOnPageTimers.forEach(e=>clearTimeout(e)),this.timeOnPageTimers=[],this.trackedClicks.clear(),this.exitIntentTriggered=!1,this.scrollDepthThresholds.clear(),this.triggeredScrollThresholds.clear(),this.campaigns=[],this.maxScrollDepth=0,this.isInitialized=!1}async displayForm(e,t){this.log("Displaying form:",e.formId),this.config.onShow?.(e),this.renderer=new f(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 i=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:i,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:k()}}loadOrCreateSessionId(){let e="bliptar_session";if(typeof sessionStorage>"u")return y();let t=sessionStorage.getItem(e);return t||(t=y(),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 C(o){return new h(o)}if(typeof window<"u"){let o=document.currentScript;if(o?.dataset.apiKey){let e=C({apiKey:o.dataset.apiKey,debug:o.dataset.debug==="true"});window.bliptar=e,e.init()}}0&&(module.exports={Bliptar,createBliptar});
package/dist/index.d.cts CHANGED
@@ -26,7 +26,7 @@ interface ExitIntentOptions {
26
26
  once?: boolean;
27
27
  }
28
28
  interface BliptarInstance {
29
- init: () => void;
29
+ init: () => Promise<void>;
30
30
  identify: (userId: string, attributes?: Record<string, unknown>) => void;
31
31
  track: (event: string, data?: Record<string, unknown>) => void;
32
32
  showForm: (formId: string) => Promise<void>;
@@ -128,13 +128,22 @@ declare class Bliptar implements BliptarInstance {
128
128
  private renderer;
129
129
  private pageLoadTime;
130
130
  private scrollDepth;
131
+ private maxScrollDepth;
131
132
  private isInitialized;
132
133
  private eventListeners;
133
134
  private trackedClicks;
134
135
  private exitIntentTriggered;
135
136
  private exitIntentCooldownTimer;
137
+ private timeOnPageTimers;
138
+ private scrollDepthThresholds;
139
+ private triggeredScrollThresholds;
140
+ private campaigns;
136
141
  constructor(config: BliptarConfig);
137
- init(): void;
142
+ init(): Promise<void>;
143
+ private fetchConfigAndSetupTriggers;
144
+ private setupTriggersFromCampaigns;
145
+ private setupTimeOnPageTrigger;
146
+ private checkScrollThresholds;
138
147
  identify(userId: string, attributes?: Record<string, unknown>): void;
139
148
  track(event: string, data?: Record<string, unknown>): Promise<void>;
140
149
  showForm(formId: string): Promise<void>;
package/dist/index.d.ts CHANGED
@@ -26,7 +26,7 @@ interface ExitIntentOptions {
26
26
  once?: boolean;
27
27
  }
28
28
  interface BliptarInstance {
29
- init: () => void;
29
+ init: () => Promise<void>;
30
30
  identify: (userId: string, attributes?: Record<string, unknown>) => void;
31
31
  track: (event: string, data?: Record<string, unknown>) => void;
32
32
  showForm: (formId: string) => Promise<void>;
@@ -128,13 +128,22 @@ declare class Bliptar implements BliptarInstance {
128
128
  private renderer;
129
129
  private pageLoadTime;
130
130
  private scrollDepth;
131
+ private maxScrollDepth;
131
132
  private isInitialized;
132
133
  private eventListeners;
133
134
  private trackedClicks;
134
135
  private exitIntentTriggered;
135
136
  private exitIntentCooldownTimer;
137
+ private timeOnPageTimers;
138
+ private scrollDepthThresholds;
139
+ private triggeredScrollThresholds;
140
+ private campaigns;
136
141
  constructor(config: BliptarConfig);
137
- init(): void;
142
+ init(): Promise<void>;
143
+ private fetchConfigAndSetupTriggers;
144
+ private setupTriggersFromCampaigns;
145
+ private setupTimeOnPageTrigger;
146
+ private checkScrollThresholds;
138
147
  identify(userId: string, attributes?: Record<string, unknown>): void;
139
148
  track(event: string, data?: Record<string, unknown>): Promise<void>;
140
149
  showForm(formId: string): Promise<void>;
package/dist/index.js CHANGED
@@ -1,15 +1,15 @@
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
- --bliptar-bg: ${i.backgroundColor};
3
- --bliptar-surface: ${i.surfaceColor};
4
- --bliptar-text: ${i.textPrimary};
5
- --bliptar-text-secondary: ${i.textSecondary};
6
- --bliptar-primary: ${i.primaryColor};
7
- --bliptar-primary-hover: ${i.primaryHover};
8
- --bliptar-border: ${i.borderColor};
9
- --bliptar-shadow: ${i.shadowColor};
10
- --bliptar-star: ${i.starColor};
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)} }
1
+ var b={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"},u={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(o,e){try{let r=window.getComputedStyle(o).getPropertyValue(e);return r&&r!=="rgba(0, 0, 0, 0)"?r:null}catch{return null}}function I(o){try{return getComputedStyle(document.documentElement).getPropertyValue(o).trim()||null}catch{return null}}function k(o){let e=o.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=o.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(o,e,t){let[r,i,a]=[o,e,t].map(n=>(n=n/255,n<=.03928?n/12.92:Math.pow((n+.055)/1.055,2.4)));return .2126*r+.7152*i+.0722*a}function x(o){let e=k(o);return e?L(e.r,e.g,e.b)<.5:!1}function g(o,e){let t=k(o);if(!t)return o;let r=i=>Math.min(255,Math.max(0,Math.round(i+e/100*255)));return`rgb(${r(t.r)}, ${r(t.g)}, ${r(t.b)})`}function P(o){return x(o)?"#ffffff":"#1a1a1a"}function D(o,e){let t={},r=null;o&&(r=document.querySelector(o)),r||(r=document.body);let i=E(r,"background-color");if(i){let a=x(i);t.mode=a?"dark":"light",t.backgroundColor=i,t.surfaceColor=g(i,a?10:-5),t.textPrimary=P(i),t.textSecondary=g(t.textPrimary,a?-30:30),t.borderColor=g(i,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 c=I(n);c&&l!=="mode"&&(t[l]=c)}}return t.primaryColor&&(t.primaryHover=g(t.primaryColor,t.mode==="dark"?15:-10)),Object.keys(t).length>0?t:null}function C(o){let{theme:e,customTheme:t,adaptiveOptions:r}=o;if(e==="custom"&&t)return{mode:x(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 i=r||{fallback:"light",autoContrast:!0},a=D(i.sourceElement,i.inheritCssVars);return a?{...a.mode==="dark"?u:b,...a}:i.fallback==="dark"?u:b}return e==="auto"?window.matchMedia("(prefers-color-scheme: dark)").matches?u:b:e==="dark"?u:b}function w(o){return`
2
+ --bliptar-bg: ${o.backgroundColor};
3
+ --bliptar-surface: ${o.surfaceColor};
4
+ --bliptar-text: ${o.textPrimary};
5
+ --bliptar-text-secondary: ${o.textSecondary};
6
+ --bliptar-primary: ${o.primaryColor};
7
+ --bliptar-primary-hover: ${o.primaryHover};
8
+ --bliptar-border: ${o.borderColor};
9
+ --bliptar-shadow: ${o.shadowColor};
10
+ --bliptar-star: ${o.starColor};
11
+ `}var f=class{constructor(e,t){this.container=null;this.currentIndex=0;this.answers={};this.form=e,this.options=t,this.theme=C(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 { ${w(t)} }
13
13
 
14
14
  .bliptar {
15
15
  position: fixed;
@@ -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(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">
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,i=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>`),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">
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(i.question)}</div>`,n+=this.renderAnswerOptions(i),(!r.autoAdvance||i.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
380
  <button class="bliptar__btn${r===!0?" bliptar__btn--selected":""}" data-value="true">
381
381
  ${e.style==="thumbs"?"\u{1F44D} ":""}${this.escapeHtml(e.positiveLabel)}
382
382
  </button>
383
383
  <button class="bliptar__btn${r===!1?" bliptar__btn--selected":""}" data-value="false">
384
384
  ${e.style==="thumbs"?"\u{1F44E} ":""}${this.escapeHtml(e.negativeLabel)}
385
385
  </button>
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">
386
+ </div>`;case"star-rating":let i='<div class="bliptar__stars">';for(let s=1;s<=e.maxStars;s++)i+=`<span class="bliptar__star${r>=s?" bliptar__star--active":""}" data-value="${s}">\u2605</span>`;return i+"</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,c='<div class="bliptar__emojis">';return l.forEach((s,d)=>{c+=`<span class="bliptar__emoji${r===d+1?" bliptar__emoji--active":""}" data-value="${d+1}" title="${e.labels?.[d]||""}">${s}</span>`}),c+"</div>";case"nps":let p='<div class="bliptar__nps">';for(let s=0;s<=10;s++)p+=`<button class="bliptar__nps-btn${r===s?" bliptar__nps-btn--selected":""}" data-value="${s}">${s}</button>`;return p+=`</div><div class="bliptar__nps-labels"><span>${this.escapeHtml(e.lowLabel)}</span><span>${this.escapeHtml(e.highLabel)}</span></div>`,p;case"single-choice":let h='<div class="bliptar__options">';return e.options.forEach(s=>{h+=`<button class="bliptar__btn${r===s?" bliptar__btn--selected":""}" data-value="${this.escapeHtml(s)}">${this.escapeHtml(s)}</button>`}),h+"</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 i=this.container.querySelector(".bliptar__backdrop");i&&t.allowDismiss&&i.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((v,S)=>v.classList.toggle("bliptar__star--active",S<=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,v)=>d.classList.toggle("bliptar__star--active",s?v<s:!1))}),this.container.querySelectorAll(".bliptar__emoji").forEach(s=>{s.addEventListener("click",()=>a(parseInt(s.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 p=this.container.querySelector(".bliptar__nav-btn--back");p&&p.addEventListener("click",()=>this.goBack());let h=this.container.querySelector(".bliptar__nav-btn--next");h&&h.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=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};
391
+ </div>`,this.container.innerHTML=r}};function _(){let o="ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789",e="";for(let t=0;t<16;t++)e+=o.charAt(Math.floor(Math.random()*o.length));return`sess_${e}`}function y(){if(typeof navigator>"u")return"desktop";let o=navigator.userAgent;return/tablet|ipad|playbook|silk/i.test(o)?"tablet":/mobile|iphone|ipod|android|blackberry|opera mini|iemobile/i.test(o)?"mobile":"desktop"}function T(o,e){let t;return(...r)=>{clearTimeout(t),t=setTimeout(()=>o(...r),e)}}var A="https://api.bliptar.com",m=class{constructor(e){this.renderer=null;this.scrollDepth=0;this.maxScrollDepth=0;this.isInitialized=!1;this.eventListeners=[];this.trackedClicks=new Set;this.exitIntentTriggered=!1;this.exitIntentCooldownTimer=null;this.timeOnPageTimers=[];this.scrollDepthThresholds=new Set;this.triggeredScrollThresholds=new Set;this.campaigns=[];this.config={apiUrl:A,debug:!1,onShow:()=>{},onSubmit:()=>{},onDismiss:()=>{},onError:()=>{},...e},this.sessionId=this.loadOrCreateSessionId(),this.pageLoadTime=Date.now()}async init(){if(typeof window>"u"||this.isInitialized)return;this.isInitialized=!0,this.log("Initializing Bliptar SDK"),await this.fetchConfigAndSetupTriggers();let e=T(()=>{let t=document.documentElement,r=window.scrollY||t.scrollTop,i=t.scrollHeight-t.clientHeight;this.scrollDepth=i>0?r/i:0;let a=Math.round(this.scrollDepth*100);a>this.maxScrollDepth&&(this.maxScrollDepth=a,this.checkScrollThresholds(a))},100);this.addEventListener(window,"scroll",e),this.track("page_view")}async fetchConfigAndSetupTriggers(){try{let e=await fetch(`${this.config.apiUrl}/api/sdk/config`,{headers:{Authorization:`Bearer ${this.config.apiKey}`}});if(!e.ok){this.log("Failed to fetch config:",e.status);return}let t=await e.json();this.campaigns=t.campaigns||[],this.log("Loaded campaigns:",this.campaigns.length),this.setupTriggersFromCampaigns()}catch(e){this.handleError(e)}}setupTriggersFromCampaigns(){let e=new Set;for(let t of this.campaigns){if(e.add(t.trigger_event),t.trigger_event==="scroll_depth"){let r=t.trigger_conditions?.find(i=>i.field==="scroll_depth_percent");r?.value&&this.scrollDepthThresholds.add(Number(r.value))}if(t.trigger_event==="time_on_page"){let r=t.trigger_conditions?.find(i=>i.field==="time_on_page_seconds");if(r?.value){let i=Number(r.value);this.setupTimeOnPageTrigger(i)}}}this.log("Active trigger types:",Array.from(e)),e.has("exit_intent")&&(this.log("Auto-enabling exit intent detection"),this.enableExitIntent({once:!0})),this.scrollDepthThresholds.size>0&&this.log("Scroll depth thresholds:",Array.from(this.scrollDepthThresholds))}setupTimeOnPageTrigger(e){this.log("Setting up time on page trigger:",e,"seconds");let t=setTimeout(()=>{this.track("time_on_page",{seconds:e,actual_time:Math.floor((Date.now()-this.pageLoadTime)/1e3)})},e*1e3);this.timeOnPageTimers.push(t)}checkScrollThresholds(e){for(let t of this.scrollDepthThresholds)e>=t&&!this.triggeredScrollThresholds.has(t)&&(this.triggeredScrollThresholds.add(t),this.log("Scroll threshold reached:",t+"%"),this.track("scroll_depth",{threshold:t,actual_depth:e}))}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 i=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(!i.ok)throw new Error(`API error: ${i.status}`);let a=await i.json();a.show_form&&a.form&&await this.displayForm(a.form,a.campaign_id)}catch(i){this.handleError(i)}}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:i=!1}=e,a=r||t;this.log("Setting up click tracking for:",t);let n=l=>{let p=l.target.closest(t);p&&(i&&this.trackedClicks.has(a)||(this.log("Button click detected:",a),i&&this.trackedClicks.add(a),this.track("button_click",{selector:t,name:a,element_text:p.textContent?.trim().slice(0,100)||"",element_id:p.id||null,element_class:p.className||null})))};this.addEventListener(document,"click",n)}enableExitIntent(e={}){let{threshold:t=50,cooldown:r=1e4,once:i=!0}=e;this.log("Enabling exit intent detection");let a=l=>{l.clientY>t||i&&this.exitIntentTriggered||this.exitIntentCooldownTimer||(this.log("Exit intent detected"),this.exitIntentTriggered=!0,this.track("exit_intent",{trigger:"mouse_leave",mouse_y:l.clientY}),i||(this.exitIntentCooldownTimer=setTimeout(()=>{this.exitIntentCooldownTimer=null},r)))};this.addEventListener(document,"mouseleave",a);let n=()=>{if(document.visibilityState==="hidden"){if(i&&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.timeOnPageTimers.forEach(e=>clearTimeout(e)),this.timeOnPageTimers=[],this.trackedClicks.clear(),this.exitIntentTriggered=!1,this.scrollDepthThresholds.clear(),this.triggeredScrollThresholds.clear(),this.campaigns=[],this.maxScrollDepth=0,this.isInitialized=!1}async displayForm(e,t){this.log("Displaying form:",e.formId),this.config.onShow?.(e),this.renderer=new f(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 i=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:i,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";if(typeof sessionStorage>"u")return _();let t=sessionStorage.getItem(e);return 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 $(o){return new m(o)}if(typeof window<"u"){let o=document.currentScript;if(o?.dataset.apiKey){let e=$({apiKey:o.dataset.apiKey,debug:o.dataset.debug==="true"});window.bliptar=e,e.init()}}export{m as Bliptar,$ as createBliptar};
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@bliptarjs/sdk",
3
- "version": "0.2.1",
3
+ "version": "0.3.1",
4
4
  "description": "Bliptar SDK - Lightweight micro-feedback for web apps",
5
5
  "type": "module",
6
6
  "main": "./dist/index.cjs",
@@ -41,7 +41,10 @@
41
41
  "micro-feedback",
42
42
  "nps",
43
43
  "user-feedback",
44
- "analytics"
44
+ "analytics",
45
+ "angular",
46
+ "react",
47
+ "vue"
45
48
  ],
46
49
  "author": "",
47
50
  "license": "MIT",