@bliptarjs/sdk 0.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md ADDED
@@ -0,0 +1,131 @@
1
+ # @bliptarjs/sdk
2
+
3
+ Lightweight SDK for collecting in-app user feedback. Designed to be small (~5KB gzipped) and non-intrusive.
4
+
5
+ ## Installation
6
+
7
+ ```bash
8
+ npm install @bliptarjs/sdk
9
+ ```
10
+
11
+ ## Quick Start
12
+
13
+ ```javascript
14
+ import { createBliptar } from '@bliptarjs/sdk';
15
+
16
+ const blip = createBliptar({
17
+ apiKey: 'your-api-key',
18
+ });
19
+
20
+ blip.init();
21
+ ```
22
+
23
+ ## Usage
24
+
25
+ ### Initialize
26
+
27
+ ```javascript
28
+ import { createBliptar } from '@bliptarjs/sdk';
29
+
30
+ const blip = createBliptar({
31
+ apiKey: 'your-api-key',
32
+ apiUrl: 'https://api.bliptar.com', // optional, defaults to production
33
+ debug: false, // optional, enables console logging
34
+ });
35
+
36
+ blip.init();
37
+ ```
38
+
39
+ ### Identify Users
40
+
41
+ Associate feedback with specific users:
42
+
43
+ ```javascript
44
+ blip.identify('user-123', {
45
+ plan: 'pro',
46
+ company: 'Acme Inc',
47
+ });
48
+ ```
49
+
50
+ ### Track Events
51
+
52
+ Track events that may trigger feedback forms:
53
+
54
+ ```javascript
55
+ blip.track('checkout_complete', {
56
+ orderId: 'order-456',
57
+ total: 99.99,
58
+ });
59
+ ```
60
+
61
+ ### Show Forms Manually
62
+
63
+ Display a specific form programmatically:
64
+
65
+ ```javascript
66
+ await blip.showForm('form-id');
67
+ ```
68
+
69
+ ### Lifecycle Callbacks
70
+
71
+ ```javascript
72
+ const blip = createBliptar({
73
+ apiKey: 'your-api-key',
74
+ onShow: (form) => {
75
+ console.log('Form displayed:', form.formId);
76
+ },
77
+ 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);
85
+ },
86
+ });
87
+ ```
88
+
89
+ ### Cleanup
90
+
91
+ Remove event listeners and clean up when done:
92
+
93
+ ```javascript
94
+ blip.destroy();
95
+ ```
96
+
97
+ ## Configuration
98
+
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 |
106
+
107
+ ## Form Types
108
+
109
+ The SDK supports multiple feedback form types:
110
+
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
117
+
118
+ ## Browser Support
119
+
120
+ - Chrome (latest)
121
+ - Firefox (latest)
122
+ - Safari (latest)
123
+ - Edge (latest)
124
+
125
+ ## Bundle Size
126
+
127
+ ~7KB gzipped
128
+
129
+ ## License
130
+
131
+ MIT
package/dist/index.cjs ADDED
@@ -0,0 +1,391 @@
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`
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(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)} }
13
+
14
+ .bliptar {
15
+ position: fixed;
16
+ z-index: 999999;
17
+ font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, 'Helvetica Neue', sans-serif;
18
+ -webkit-font-smoothing: antialiased;
19
+ }
20
+
21
+ .bliptar--bottom-right { bottom: 20px; right: 20px; }
22
+ .bliptar--bottom-left { bottom: 20px; left: 20px; }
23
+ .bliptar--bottom-center { bottom: 20px; left: 50%; transform: translateX(-50%); }
24
+ .bliptar--center { top: 50%; left: 50%; transform: translate(-50%, -50%); }
25
+
26
+ .bliptar__backdrop {
27
+ position: fixed;
28
+ inset: 0;
29
+ background: rgba(0, 0, 0, 0.5);
30
+ animation: bliptar-fade-in 0.2s ease-out;
31
+ ${r.backdropBlur?"backdrop-filter: blur(8px); -webkit-backdrop-filter: blur(8px);":""}
32
+ }
33
+
34
+ .bliptar__card {
35
+ background: ${t.backgroundColor};
36
+ color: ${t.textPrimary};
37
+ border-radius: ${r.borderRadius}px;
38
+ box-shadow: 0 8px 32px ${t.shadowColor}, 0 2px 8px ${t.shadowColor};
39
+ max-width: ${r.maxWidth}px;
40
+ width: calc(100vw - 40px);
41
+ padding: 24px;
42
+ position: relative;
43
+ ${this.getAnimationStyles(e)}
44
+ transition: transform 0.2s ease, box-shadow 0.2s ease;
45
+ }
46
+
47
+ .bliptar__card:hover {
48
+ box-shadow: 0 12px 40px ${t.shadowColor}, 0 4px 12px ${t.shadowColor};
49
+ }
50
+
51
+ .bliptar__card--exit {
52
+ animation: bliptar-${e}-out 0.2s ease-in forwards;
53
+ }
54
+
55
+ @keyframes bliptar-fade-in { from { opacity: 0; } to { opacity: 1; } }
56
+ @keyframes bliptar-slide-up { from { opacity: 0; transform: translateY(24px); } to { opacity: 1; transform: translateY(0); } }
57
+ @keyframes bliptar-slide-up-out { from { opacity: 1; transform: translateY(0); } to { opacity: 0; transform: translateY(24px); } }
58
+ @keyframes bliptar-fade { from { opacity: 0; } to { opacity: 1; } }
59
+ @keyframes bliptar-fade-out { from { opacity: 1; } to { opacity: 0; } }
60
+ @keyframes bliptar-scale { from { opacity: 0; transform: scale(0.9); } to { opacity: 1; transform: scale(1); } }
61
+ @keyframes bliptar-scale-out { from { opacity: 1; transform: scale(1); } to { opacity: 0; transform: scale(0.9); } }
62
+ @keyframes bliptar-bounce { 0% { transform: scale(1); } 50% { transform: scale(1.05); } 100% { transform: scale(1); } }
63
+ @keyframes bliptar-shimmer { from { transform: translateX(-100%); } to { transform: translateX(100%); } }
64
+ @keyframes bliptar-spin { to { transform: rotate(360deg); } }
65
+
66
+ .bliptar__close {
67
+ position: absolute;
68
+ top: 12px;
69
+ right: 12px;
70
+ background: none;
71
+ border: none;
72
+ cursor: pointer;
73
+ padding: 8px;
74
+ color: ${t.textSecondary};
75
+ font-size: 20px;
76
+ line-height: 1;
77
+ border-radius: 8px;
78
+ transition: all 0.15s ease;
79
+ display: flex;
80
+ align-items: center;
81
+ justify-content: center;
82
+ width: 32px;
83
+ height: 32px;
84
+ }
85
+
86
+ .bliptar__close:hover {
87
+ background: ${t.surfaceColor};
88
+ color: ${t.textPrimary};
89
+ }
90
+
91
+ .bliptar__progress {
92
+ display: flex;
93
+ gap: 6px;
94
+ margin-bottom: 20px;
95
+ }
96
+
97
+ .bliptar__progress-bar {
98
+ height: 4px;
99
+ flex: 1;
100
+ border-radius: 2px;
101
+ background: ${t.borderColor};
102
+ overflow: hidden;
103
+ position: relative;
104
+ }
105
+
106
+ .bliptar__progress-bar--active {
107
+ background: ${t.primaryColor};
108
+ }
109
+
110
+ .bliptar__progress-bar--active::after {
111
+ content: '';
112
+ position: absolute;
113
+ inset: 0;
114
+ background: linear-gradient(90deg, transparent, rgba(255,255,255,0.3), transparent);
115
+ animation: bliptar-shimmer 1.5s infinite;
116
+ }
117
+
118
+ .bliptar__question {
119
+ font-size: 18px;
120
+ font-weight: 600;
121
+ margin-bottom: 24px;
122
+ line-height: 1.4;
123
+ animation: bliptar-fade 0.3s ease-out;
124
+ }
125
+
126
+ .bliptar__options {
127
+ display: flex;
128
+ gap: 10px;
129
+ flex-wrap: wrap;
130
+ animation: bliptar-fade 0.3s ease-out 0.1s both;
131
+ }
132
+
133
+ .bliptar__btn {
134
+ padding: 12px 20px;
135
+ border: 2px solid ${t.borderColor};
136
+ border-radius: 10px;
137
+ background: transparent;
138
+ color: ${t.textPrimary};
139
+ cursor: pointer;
140
+ font-size: 14px;
141
+ font-weight: 500;
142
+ transition: all 0.2s ease;
143
+ flex: 1;
144
+ min-width: 100px;
145
+ }
146
+
147
+ .bliptar__btn:hover {
148
+ border-color: ${t.primaryColor};
149
+ background: ${t.surfaceColor};
150
+ transform: translateY(-1px);
151
+ }
152
+
153
+ .bliptar__btn:active { transform: translateY(0); }
154
+
155
+ .bliptar__btn--selected {
156
+ background: ${t.primaryColor};
157
+ border-color: ${t.primaryColor};
158
+ color: white;
159
+ animation: bliptar-bounce 0.3s ease;
160
+ }
161
+
162
+ .bliptar__stars {
163
+ display: flex;
164
+ gap: 8px;
165
+ justify-content: center;
166
+ animation: bliptar-fade 0.3s ease-out 0.1s both;
167
+ }
168
+
169
+ .bliptar__star {
170
+ font-size: 36px;
171
+ cursor: pointer;
172
+ color: ${t.borderColor};
173
+ transition: all 0.2s ease;
174
+ transform-origin: center;
175
+ }
176
+
177
+ .bliptar__star:hover {
178
+ transform: scale(1.15);
179
+ color: ${t.starColor};
180
+ }
181
+
182
+ .bliptar__star--active {
183
+ color: ${t.starColor};
184
+ animation: bliptar-bounce 0.3s ease;
185
+ }
186
+
187
+ .bliptar__emojis {
188
+ display: flex;
189
+ gap: 12px;
190
+ justify-content: center;
191
+ animation: bliptar-fade 0.3s ease-out 0.1s both;
192
+ }
193
+
194
+ .bliptar__emoji {
195
+ font-size: 40px;
196
+ cursor: pointer;
197
+ padding: 10px;
198
+ border-radius: 16px;
199
+ transition: all 0.2s ease;
200
+ border: 2px solid transparent;
201
+ }
202
+
203
+ .bliptar__emoji:hover {
204
+ background: ${t.surfaceColor};
205
+ transform: scale(1.1);
206
+ }
207
+
208
+ .bliptar__emoji--active {
209
+ background: ${t.surfaceColor};
210
+ border-color: ${t.primaryColor};
211
+ transform: scale(1.15);
212
+ animation: bliptar-bounce 0.3s ease;
213
+ }
214
+
215
+ .bliptar__nps {
216
+ display: flex;
217
+ gap: 6px;
218
+ flex-wrap: wrap;
219
+ justify-content: center;
220
+ animation: bliptar-fade 0.3s ease-out 0.1s both;
221
+ }
222
+
223
+ .bliptar__nps-btn {
224
+ width: 36px;
225
+ height: 36px;
226
+ border: 2px solid ${t.borderColor};
227
+ border-radius: 8px;
228
+ background: transparent;
229
+ color: ${t.textPrimary};
230
+ cursor: pointer;
231
+ font-size: 13px;
232
+ font-weight: 500;
233
+ transition: all 0.15s ease;
234
+ }
235
+
236
+ .bliptar__nps-btn:hover {
237
+ border-color: ${t.primaryColor};
238
+ background: ${t.surfaceColor};
239
+ transform: translateY(-2px);
240
+ }
241
+
242
+ .bliptar__nps-btn--selected {
243
+ background: ${t.primaryColor};
244
+ border-color: ${t.primaryColor};
245
+ color: white;
246
+ transform: translateY(-2px);
247
+ }
248
+
249
+ .bliptar__nps-labels {
250
+ display: flex;
251
+ justify-content: space-between;
252
+ margin-top: 10px;
253
+ font-size: 12px;
254
+ color: ${t.textSecondary};
255
+ }
256
+
257
+ .bliptar__textarea {
258
+ width: 100%;
259
+ padding: 14px;
260
+ border: 2px solid ${t.borderColor};
261
+ border-radius: 10px;
262
+ background: transparent;
263
+ color: ${t.textPrimary};
264
+ font-size: 14px;
265
+ font-family: inherit;
266
+ resize: vertical;
267
+ min-height: 100px;
268
+ transition: all 0.2s ease;
269
+ animation: bliptar-fade 0.3s ease-out 0.1s both;
270
+ box-sizing: border-box;
271
+ }
272
+
273
+ .bliptar__textarea::placeholder { color: ${t.textSecondary}; }
274
+
275
+ .bliptar__textarea:focus {
276
+ outline: none;
277
+ border-color: ${t.primaryColor};
278
+ box-shadow: 0 0 0 3px ${t.primaryColor}20;
279
+ }
280
+
281
+ .bliptar__nav {
282
+ display: flex;
283
+ justify-content: space-between;
284
+ align-items: center;
285
+ margin-top: 24px;
286
+ gap: 12px;
287
+ }
288
+
289
+ .bliptar__nav-btn {
290
+ padding: 12px 24px;
291
+ border: none;
292
+ border-radius: 10px;
293
+ cursor: pointer;
294
+ font-size: 14px;
295
+ font-weight: 500;
296
+ transition: all 0.2s ease;
297
+ }
298
+
299
+ .bliptar__nav-btn--back {
300
+ background: transparent;
301
+ color: ${t.textSecondary};
302
+ padding: 12px 16px;
303
+ }
304
+
305
+ .bliptar__nav-btn--back:hover {
306
+ color: ${t.textPrimary};
307
+ background: ${t.surfaceColor};
308
+ }
309
+
310
+ .bliptar__nav-btn--next {
311
+ background: ${t.primaryColor};
312
+ color: white;
313
+ flex: 1;
314
+ max-width: 200px;
315
+ }
316
+
317
+ .bliptar__nav-btn--next:hover {
318
+ background: ${t.primaryHover};
319
+ transform: translateY(-1px);
320
+ box-shadow: 0 4px 12px ${t.primaryColor}40;
321
+ }
322
+
323
+ .bliptar__nav-btn--next:active { transform: translateY(0); }
324
+
325
+ .bliptar__thankyou {
326
+ text-align: center;
327
+ padding: 24px 0;
328
+ animation: bliptar-scale 0.4s ease-out;
329
+ }
330
+
331
+ .bliptar__thankyou-emoji {
332
+ font-size: 56px;
333
+ margin-bottom: 16px;
334
+ animation: bliptar-bounce 0.5s ease 0.2s;
335
+ }
336
+
337
+ .bliptar__thankyou-text {
338
+ font-size: 18px;
339
+ font-weight: 500;
340
+ color: ${t.textPrimary};
341
+ }
342
+
343
+ .bliptar__loading {
344
+ display: flex;
345
+ justify-content: center;
346
+ padding: 20px;
347
+ }
348
+
349
+ .bliptar__spinner {
350
+ width: 24px;
351
+ height: 24px;
352
+ border: 3px solid ${t.borderColor};
353
+ border-top-color: ${t.primaryColor};
354
+ border-radius: 50%;
355
+ animation: bliptar-spin 0.8s linear infinite;
356
+ }
357
+
358
+ @media (max-width: 480px) {
359
+ .bliptar--bottom-right, .bliptar--bottom-left { left: 10px; right: 10px; bottom: 10px; }
360
+ .bliptar__card { width: 100%; padding: 20px; }
361
+ .bliptar__question { font-size: 16px; }
362
+ .bliptar__star { font-size: 28px; }
363
+ .bliptar__emoji { font-size: 32px; padding: 8px; }
364
+ .bliptar__nps-btn { width: 28px; height: 28px; font-size: 11px; }
365
+ }
366
+
367
+ @media (prefers-reduced-motion: reduce) {
368
+ .bliptar__card, .bliptar__btn, .bliptar__star, .bliptar__emoji, .bliptar__nps-btn, .bliptar__nav-btn {
369
+ animation: none !important;
370
+ transition: none !important;
371
+ }
372
+ }
373
+
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">
376
+ <svg width="14" height="14" viewBox="0 0 14 14" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round">
377
+ <path d="M1 1l12 12M1 13L13 1"/>
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)}
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)}
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">
387
+ <div class="bliptar__thankyou">
388
+ <div class="bliptar__thankyou-emoji">\u{1F389}</div>
389
+ <div class="bliptar__thankyou-text">${this.escapeHtml(t.thankYouMessage||"Thank you for your feedback!")}</div>
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});
@@ -0,0 +1,151 @@
1
+ interface BliptarConfig {
2
+ apiKey: string;
3
+ apiUrl?: string;
4
+ debug?: boolean;
5
+ userId?: string;
6
+ userAttributes?: Record<string, unknown>;
7
+ onShow?: (form: Form) => void;
8
+ onSubmit?: (answers: Record<string, Answer>) => void;
9
+ onDismiss?: () => void;
10
+ onError?: (error: Error) => void;
11
+ }
12
+ interface BliptarInstance {
13
+ init: () => void;
14
+ identify: (userId: string, attributes?: Record<string, unknown>) => void;
15
+ track: (event: string, data?: Record<string, unknown>) => void;
16
+ showForm: (formId: string) => Promise<void>;
17
+ destroy: () => void;
18
+ }
19
+ interface Form {
20
+ formId: string;
21
+ name: string;
22
+ questions: Question[];
23
+ appearance: FormAppearance;
24
+ behavior: FormBehavior;
25
+ }
26
+ type ThemeMode = 'light' | 'dark' | 'auto' | 'adaptive' | 'custom';
27
+ interface CustomTheme {
28
+ backgroundColor: string;
29
+ surfaceColor: string;
30
+ textPrimary: string;
31
+ textSecondary: string;
32
+ primaryColor: string;
33
+ primaryHover: string;
34
+ borderColor: string;
35
+ shadowColor: string;
36
+ }
37
+ interface AdaptiveThemeOptions {
38
+ sourceElement?: string;
39
+ inheritCssVars?: boolean;
40
+ fallback: 'light' | 'dark';
41
+ autoContrast: boolean;
42
+ }
43
+ interface FormAppearance {
44
+ theme: ThemeMode;
45
+ customTheme?: CustomTheme;
46
+ adaptiveOptions?: AdaptiveThemeOptions;
47
+ position: 'bottom-right' | 'bottom-left' | 'bottom-center' | 'center';
48
+ animation: 'slide-up' | 'fade' | 'scale' | 'none';
49
+ backdrop: boolean;
50
+ backdropBlur: boolean;
51
+ borderRadius: number;
52
+ maxWidth: number;
53
+ }
54
+ interface FormBehavior {
55
+ showProgress: boolean;
56
+ allowSkip: boolean;
57
+ allowDismiss: boolean;
58
+ autoAdvance: boolean;
59
+ autoAdvanceDelay: number;
60
+ submitOnComplete: boolean;
61
+ showThankYou: boolean;
62
+ thankYouMessage: string;
63
+ thankYouDuration: number;
64
+ }
65
+ type Question = BinaryQuestion | StarRatingQuestion | EmojiScaleQuestion | NPSQuestion | SingleChoiceQuestion | TextInputQuestion;
66
+ interface BaseQuestion {
67
+ type: string;
68
+ question: string;
69
+ required: boolean;
70
+ }
71
+ interface BinaryQuestion extends BaseQuestion {
72
+ type: 'binary';
73
+ style: 'thumbs' | 'yesno' | 'custom';
74
+ positiveLabel: string;
75
+ negativeLabel: string;
76
+ }
77
+ interface StarRatingQuestion extends BaseQuestion {
78
+ type: 'star-rating';
79
+ maxStars: number;
80
+ allowHalf: boolean;
81
+ }
82
+ interface EmojiScaleQuestion extends BaseQuestion {
83
+ type: 'emoji-scale';
84
+ scale: 3 | 5;
85
+ labels?: string[];
86
+ }
87
+ interface NPSQuestion extends BaseQuestion {
88
+ type: 'nps';
89
+ lowLabel: string;
90
+ highLabel: string;
91
+ }
92
+ interface SingleChoiceQuestion extends BaseQuestion {
93
+ type: 'single-choice';
94
+ options: string[];
95
+ style: 'buttons' | 'radio' | 'dropdown';
96
+ }
97
+ interface TextInputQuestion extends BaseQuestion {
98
+ type: 'text-input';
99
+ placeholder: string;
100
+ maxLength: number;
101
+ multiline: boolean;
102
+ }
103
+ type Answer = boolean | number | string;
104
+
105
+ declare class Bliptar implements BliptarInstance {
106
+ private config;
107
+ private sessionId;
108
+ private renderer;
109
+ private pageLoadTime;
110
+ private scrollDepth;
111
+ private isInitialized;
112
+ private eventListeners;
113
+ constructor(config: BliptarConfig);
114
+ init(): void;
115
+ identify(userId: string, attributes?: Record<string, unknown>): void;
116
+ track(event: string, data?: Record<string, unknown>): Promise<void>;
117
+ showForm(formId: string): Promise<void>;
118
+ destroy(): void;
119
+ private displayForm;
120
+ private submitResponse;
121
+ private getContext;
122
+ private loadOrCreateSessionId;
123
+ private addEventListener;
124
+ private log;
125
+ private handleError;
126
+ }
127
+
128
+ /**
129
+ * Create a new Bliptar instance
130
+ *
131
+ * @example
132
+ * ```typescript
133
+ * import { createBliptar } from '@bliptar/sdk';
134
+ *
135
+ * const bliptar = createBliptar({
136
+ * apiKey: 'pk_xxx',
137
+ * debug: true,
138
+ * });
139
+ *
140
+ * bliptar.init();
141
+ *
142
+ * // Identify user (optional)
143
+ * bliptar.identify('user_123', { plan: 'pro' });
144
+ *
145
+ * // Track custom events
146
+ * bliptar.track('checkout_complete', { amount: 99.99 });
147
+ * ```
148
+ */
149
+ declare function createBliptar(config: BliptarConfig): BliptarInstance;
150
+
151
+ export { type Answer, Bliptar, type BliptarConfig, type BliptarInstance, type Form, type Question, createBliptar };
@@ -0,0 +1,151 @@
1
+ interface BliptarConfig {
2
+ apiKey: string;
3
+ apiUrl?: string;
4
+ debug?: boolean;
5
+ userId?: string;
6
+ userAttributes?: Record<string, unknown>;
7
+ onShow?: (form: Form) => void;
8
+ onSubmit?: (answers: Record<string, Answer>) => void;
9
+ onDismiss?: () => void;
10
+ onError?: (error: Error) => void;
11
+ }
12
+ interface BliptarInstance {
13
+ init: () => void;
14
+ identify: (userId: string, attributes?: Record<string, unknown>) => void;
15
+ track: (event: string, data?: Record<string, unknown>) => void;
16
+ showForm: (formId: string) => Promise<void>;
17
+ destroy: () => void;
18
+ }
19
+ interface Form {
20
+ formId: string;
21
+ name: string;
22
+ questions: Question[];
23
+ appearance: FormAppearance;
24
+ behavior: FormBehavior;
25
+ }
26
+ type ThemeMode = 'light' | 'dark' | 'auto' | 'adaptive' | 'custom';
27
+ interface CustomTheme {
28
+ backgroundColor: string;
29
+ surfaceColor: string;
30
+ textPrimary: string;
31
+ textSecondary: string;
32
+ primaryColor: string;
33
+ primaryHover: string;
34
+ borderColor: string;
35
+ shadowColor: string;
36
+ }
37
+ interface AdaptiveThemeOptions {
38
+ sourceElement?: string;
39
+ inheritCssVars?: boolean;
40
+ fallback: 'light' | 'dark';
41
+ autoContrast: boolean;
42
+ }
43
+ interface FormAppearance {
44
+ theme: ThemeMode;
45
+ customTheme?: CustomTheme;
46
+ adaptiveOptions?: AdaptiveThemeOptions;
47
+ position: 'bottom-right' | 'bottom-left' | 'bottom-center' | 'center';
48
+ animation: 'slide-up' | 'fade' | 'scale' | 'none';
49
+ backdrop: boolean;
50
+ backdropBlur: boolean;
51
+ borderRadius: number;
52
+ maxWidth: number;
53
+ }
54
+ interface FormBehavior {
55
+ showProgress: boolean;
56
+ allowSkip: boolean;
57
+ allowDismiss: boolean;
58
+ autoAdvance: boolean;
59
+ autoAdvanceDelay: number;
60
+ submitOnComplete: boolean;
61
+ showThankYou: boolean;
62
+ thankYouMessage: string;
63
+ thankYouDuration: number;
64
+ }
65
+ type Question = BinaryQuestion | StarRatingQuestion | EmojiScaleQuestion | NPSQuestion | SingleChoiceQuestion | TextInputQuestion;
66
+ interface BaseQuestion {
67
+ type: string;
68
+ question: string;
69
+ required: boolean;
70
+ }
71
+ interface BinaryQuestion extends BaseQuestion {
72
+ type: 'binary';
73
+ style: 'thumbs' | 'yesno' | 'custom';
74
+ positiveLabel: string;
75
+ negativeLabel: string;
76
+ }
77
+ interface StarRatingQuestion extends BaseQuestion {
78
+ type: 'star-rating';
79
+ maxStars: number;
80
+ allowHalf: boolean;
81
+ }
82
+ interface EmojiScaleQuestion extends BaseQuestion {
83
+ type: 'emoji-scale';
84
+ scale: 3 | 5;
85
+ labels?: string[];
86
+ }
87
+ interface NPSQuestion extends BaseQuestion {
88
+ type: 'nps';
89
+ lowLabel: string;
90
+ highLabel: string;
91
+ }
92
+ interface SingleChoiceQuestion extends BaseQuestion {
93
+ type: 'single-choice';
94
+ options: string[];
95
+ style: 'buttons' | 'radio' | 'dropdown';
96
+ }
97
+ interface TextInputQuestion extends BaseQuestion {
98
+ type: 'text-input';
99
+ placeholder: string;
100
+ maxLength: number;
101
+ multiline: boolean;
102
+ }
103
+ type Answer = boolean | number | string;
104
+
105
+ declare class Bliptar implements BliptarInstance {
106
+ private config;
107
+ private sessionId;
108
+ private renderer;
109
+ private pageLoadTime;
110
+ private scrollDepth;
111
+ private isInitialized;
112
+ private eventListeners;
113
+ constructor(config: BliptarConfig);
114
+ init(): void;
115
+ identify(userId: string, attributes?: Record<string, unknown>): void;
116
+ track(event: string, data?: Record<string, unknown>): Promise<void>;
117
+ showForm(formId: string): Promise<void>;
118
+ destroy(): void;
119
+ private displayForm;
120
+ private submitResponse;
121
+ private getContext;
122
+ private loadOrCreateSessionId;
123
+ private addEventListener;
124
+ private log;
125
+ private handleError;
126
+ }
127
+
128
+ /**
129
+ * Create a new Bliptar instance
130
+ *
131
+ * @example
132
+ * ```typescript
133
+ * import { createBliptar } from '@bliptar/sdk';
134
+ *
135
+ * const bliptar = createBliptar({
136
+ * apiKey: 'pk_xxx',
137
+ * debug: true,
138
+ * });
139
+ *
140
+ * bliptar.init();
141
+ *
142
+ * // Identify user (optional)
143
+ * bliptar.identify('user_123', { plan: 'pro' });
144
+ *
145
+ * // Track custom events
146
+ * bliptar.track('checkout_complete', { amount: 99.99 });
147
+ * ```
148
+ */
149
+ declare function createBliptar(config: BliptarConfig): BliptarInstance;
150
+
151
+ export { type Answer, Bliptar, type BliptarConfig, type BliptarInstance, type Form, type Question, createBliptar };
package/dist/index.js ADDED
@@ -0,0 +1,391 @@
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`
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(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)} }
13
+
14
+ .bliptar {
15
+ position: fixed;
16
+ z-index: 999999;
17
+ font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, 'Helvetica Neue', sans-serif;
18
+ -webkit-font-smoothing: antialiased;
19
+ }
20
+
21
+ .bliptar--bottom-right { bottom: 20px; right: 20px; }
22
+ .bliptar--bottom-left { bottom: 20px; left: 20px; }
23
+ .bliptar--bottom-center { bottom: 20px; left: 50%; transform: translateX(-50%); }
24
+ .bliptar--center { top: 50%; left: 50%; transform: translate(-50%, -50%); }
25
+
26
+ .bliptar__backdrop {
27
+ position: fixed;
28
+ inset: 0;
29
+ background: rgba(0, 0, 0, 0.5);
30
+ animation: bliptar-fade-in 0.2s ease-out;
31
+ ${r.backdropBlur?"backdrop-filter: blur(8px); -webkit-backdrop-filter: blur(8px);":""}
32
+ }
33
+
34
+ .bliptar__card {
35
+ background: ${t.backgroundColor};
36
+ color: ${t.textPrimary};
37
+ border-radius: ${r.borderRadius}px;
38
+ box-shadow: 0 8px 32px ${t.shadowColor}, 0 2px 8px ${t.shadowColor};
39
+ max-width: ${r.maxWidth}px;
40
+ width: calc(100vw - 40px);
41
+ padding: 24px;
42
+ position: relative;
43
+ ${this.getAnimationStyles(e)}
44
+ transition: transform 0.2s ease, box-shadow 0.2s ease;
45
+ }
46
+
47
+ .bliptar__card:hover {
48
+ box-shadow: 0 12px 40px ${t.shadowColor}, 0 4px 12px ${t.shadowColor};
49
+ }
50
+
51
+ .bliptar__card--exit {
52
+ animation: bliptar-${e}-out 0.2s ease-in forwards;
53
+ }
54
+
55
+ @keyframes bliptar-fade-in { from { opacity: 0; } to { opacity: 1; } }
56
+ @keyframes bliptar-slide-up { from { opacity: 0; transform: translateY(24px); } to { opacity: 1; transform: translateY(0); } }
57
+ @keyframes bliptar-slide-up-out { from { opacity: 1; transform: translateY(0); } to { opacity: 0; transform: translateY(24px); } }
58
+ @keyframes bliptar-fade { from { opacity: 0; } to { opacity: 1; } }
59
+ @keyframes bliptar-fade-out { from { opacity: 1; } to { opacity: 0; } }
60
+ @keyframes bliptar-scale { from { opacity: 0; transform: scale(0.9); } to { opacity: 1; transform: scale(1); } }
61
+ @keyframes bliptar-scale-out { from { opacity: 1; transform: scale(1); } to { opacity: 0; transform: scale(0.9); } }
62
+ @keyframes bliptar-bounce { 0% { transform: scale(1); } 50% { transform: scale(1.05); } 100% { transform: scale(1); } }
63
+ @keyframes bliptar-shimmer { from { transform: translateX(-100%); } to { transform: translateX(100%); } }
64
+ @keyframes bliptar-spin { to { transform: rotate(360deg); } }
65
+
66
+ .bliptar__close {
67
+ position: absolute;
68
+ top: 12px;
69
+ right: 12px;
70
+ background: none;
71
+ border: none;
72
+ cursor: pointer;
73
+ padding: 8px;
74
+ color: ${t.textSecondary};
75
+ font-size: 20px;
76
+ line-height: 1;
77
+ border-radius: 8px;
78
+ transition: all 0.15s ease;
79
+ display: flex;
80
+ align-items: center;
81
+ justify-content: center;
82
+ width: 32px;
83
+ height: 32px;
84
+ }
85
+
86
+ .bliptar__close:hover {
87
+ background: ${t.surfaceColor};
88
+ color: ${t.textPrimary};
89
+ }
90
+
91
+ .bliptar__progress {
92
+ display: flex;
93
+ gap: 6px;
94
+ margin-bottom: 20px;
95
+ }
96
+
97
+ .bliptar__progress-bar {
98
+ height: 4px;
99
+ flex: 1;
100
+ border-radius: 2px;
101
+ background: ${t.borderColor};
102
+ overflow: hidden;
103
+ position: relative;
104
+ }
105
+
106
+ .bliptar__progress-bar--active {
107
+ background: ${t.primaryColor};
108
+ }
109
+
110
+ .bliptar__progress-bar--active::after {
111
+ content: '';
112
+ position: absolute;
113
+ inset: 0;
114
+ background: linear-gradient(90deg, transparent, rgba(255,255,255,0.3), transparent);
115
+ animation: bliptar-shimmer 1.5s infinite;
116
+ }
117
+
118
+ .bliptar__question {
119
+ font-size: 18px;
120
+ font-weight: 600;
121
+ margin-bottom: 24px;
122
+ line-height: 1.4;
123
+ animation: bliptar-fade 0.3s ease-out;
124
+ }
125
+
126
+ .bliptar__options {
127
+ display: flex;
128
+ gap: 10px;
129
+ flex-wrap: wrap;
130
+ animation: bliptar-fade 0.3s ease-out 0.1s both;
131
+ }
132
+
133
+ .bliptar__btn {
134
+ padding: 12px 20px;
135
+ border: 2px solid ${t.borderColor};
136
+ border-radius: 10px;
137
+ background: transparent;
138
+ color: ${t.textPrimary};
139
+ cursor: pointer;
140
+ font-size: 14px;
141
+ font-weight: 500;
142
+ transition: all 0.2s ease;
143
+ flex: 1;
144
+ min-width: 100px;
145
+ }
146
+
147
+ .bliptar__btn:hover {
148
+ border-color: ${t.primaryColor};
149
+ background: ${t.surfaceColor};
150
+ transform: translateY(-1px);
151
+ }
152
+
153
+ .bliptar__btn:active { transform: translateY(0); }
154
+
155
+ .bliptar__btn--selected {
156
+ background: ${t.primaryColor};
157
+ border-color: ${t.primaryColor};
158
+ color: white;
159
+ animation: bliptar-bounce 0.3s ease;
160
+ }
161
+
162
+ .bliptar__stars {
163
+ display: flex;
164
+ gap: 8px;
165
+ justify-content: center;
166
+ animation: bliptar-fade 0.3s ease-out 0.1s both;
167
+ }
168
+
169
+ .bliptar__star {
170
+ font-size: 36px;
171
+ cursor: pointer;
172
+ color: ${t.borderColor};
173
+ transition: all 0.2s ease;
174
+ transform-origin: center;
175
+ }
176
+
177
+ .bliptar__star:hover {
178
+ transform: scale(1.15);
179
+ color: ${t.starColor};
180
+ }
181
+
182
+ .bliptar__star--active {
183
+ color: ${t.starColor};
184
+ animation: bliptar-bounce 0.3s ease;
185
+ }
186
+
187
+ .bliptar__emojis {
188
+ display: flex;
189
+ gap: 12px;
190
+ justify-content: center;
191
+ animation: bliptar-fade 0.3s ease-out 0.1s both;
192
+ }
193
+
194
+ .bliptar__emoji {
195
+ font-size: 40px;
196
+ cursor: pointer;
197
+ padding: 10px;
198
+ border-radius: 16px;
199
+ transition: all 0.2s ease;
200
+ border: 2px solid transparent;
201
+ }
202
+
203
+ .bliptar__emoji:hover {
204
+ background: ${t.surfaceColor};
205
+ transform: scale(1.1);
206
+ }
207
+
208
+ .bliptar__emoji--active {
209
+ background: ${t.surfaceColor};
210
+ border-color: ${t.primaryColor};
211
+ transform: scale(1.15);
212
+ animation: bliptar-bounce 0.3s ease;
213
+ }
214
+
215
+ .bliptar__nps {
216
+ display: flex;
217
+ gap: 6px;
218
+ flex-wrap: wrap;
219
+ justify-content: center;
220
+ animation: bliptar-fade 0.3s ease-out 0.1s both;
221
+ }
222
+
223
+ .bliptar__nps-btn {
224
+ width: 36px;
225
+ height: 36px;
226
+ border: 2px solid ${t.borderColor};
227
+ border-radius: 8px;
228
+ background: transparent;
229
+ color: ${t.textPrimary};
230
+ cursor: pointer;
231
+ font-size: 13px;
232
+ font-weight: 500;
233
+ transition: all 0.15s ease;
234
+ }
235
+
236
+ .bliptar__nps-btn:hover {
237
+ border-color: ${t.primaryColor};
238
+ background: ${t.surfaceColor};
239
+ transform: translateY(-2px);
240
+ }
241
+
242
+ .bliptar__nps-btn--selected {
243
+ background: ${t.primaryColor};
244
+ border-color: ${t.primaryColor};
245
+ color: white;
246
+ transform: translateY(-2px);
247
+ }
248
+
249
+ .bliptar__nps-labels {
250
+ display: flex;
251
+ justify-content: space-between;
252
+ margin-top: 10px;
253
+ font-size: 12px;
254
+ color: ${t.textSecondary};
255
+ }
256
+
257
+ .bliptar__textarea {
258
+ width: 100%;
259
+ padding: 14px;
260
+ border: 2px solid ${t.borderColor};
261
+ border-radius: 10px;
262
+ background: transparent;
263
+ color: ${t.textPrimary};
264
+ font-size: 14px;
265
+ font-family: inherit;
266
+ resize: vertical;
267
+ min-height: 100px;
268
+ transition: all 0.2s ease;
269
+ animation: bliptar-fade 0.3s ease-out 0.1s both;
270
+ box-sizing: border-box;
271
+ }
272
+
273
+ .bliptar__textarea::placeholder { color: ${t.textSecondary}; }
274
+
275
+ .bliptar__textarea:focus {
276
+ outline: none;
277
+ border-color: ${t.primaryColor};
278
+ box-shadow: 0 0 0 3px ${t.primaryColor}20;
279
+ }
280
+
281
+ .bliptar__nav {
282
+ display: flex;
283
+ justify-content: space-between;
284
+ align-items: center;
285
+ margin-top: 24px;
286
+ gap: 12px;
287
+ }
288
+
289
+ .bliptar__nav-btn {
290
+ padding: 12px 24px;
291
+ border: none;
292
+ border-radius: 10px;
293
+ cursor: pointer;
294
+ font-size: 14px;
295
+ font-weight: 500;
296
+ transition: all 0.2s ease;
297
+ }
298
+
299
+ .bliptar__nav-btn--back {
300
+ background: transparent;
301
+ color: ${t.textSecondary};
302
+ padding: 12px 16px;
303
+ }
304
+
305
+ .bliptar__nav-btn--back:hover {
306
+ color: ${t.textPrimary};
307
+ background: ${t.surfaceColor};
308
+ }
309
+
310
+ .bliptar__nav-btn--next {
311
+ background: ${t.primaryColor};
312
+ color: white;
313
+ flex: 1;
314
+ max-width: 200px;
315
+ }
316
+
317
+ .bliptar__nav-btn--next:hover {
318
+ background: ${t.primaryHover};
319
+ transform: translateY(-1px);
320
+ box-shadow: 0 4px 12px ${t.primaryColor}40;
321
+ }
322
+
323
+ .bliptar__nav-btn--next:active { transform: translateY(0); }
324
+
325
+ .bliptar__thankyou {
326
+ text-align: center;
327
+ padding: 24px 0;
328
+ animation: bliptar-scale 0.4s ease-out;
329
+ }
330
+
331
+ .bliptar__thankyou-emoji {
332
+ font-size: 56px;
333
+ margin-bottom: 16px;
334
+ animation: bliptar-bounce 0.5s ease 0.2s;
335
+ }
336
+
337
+ .bliptar__thankyou-text {
338
+ font-size: 18px;
339
+ font-weight: 500;
340
+ color: ${t.textPrimary};
341
+ }
342
+
343
+ .bliptar__loading {
344
+ display: flex;
345
+ justify-content: center;
346
+ padding: 20px;
347
+ }
348
+
349
+ .bliptar__spinner {
350
+ width: 24px;
351
+ height: 24px;
352
+ border: 3px solid ${t.borderColor};
353
+ border-top-color: ${t.primaryColor};
354
+ border-radius: 50%;
355
+ animation: bliptar-spin 0.8s linear infinite;
356
+ }
357
+
358
+ @media (max-width: 480px) {
359
+ .bliptar--bottom-right, .bliptar--bottom-left { left: 10px; right: 10px; bottom: 10px; }
360
+ .bliptar__card { width: 100%; padding: 20px; }
361
+ .bliptar__question { font-size: 16px; }
362
+ .bliptar__star { font-size: 28px; }
363
+ .bliptar__emoji { font-size: 32px; padding: 8px; }
364
+ .bliptar__nps-btn { width: 28px; height: 28px; font-size: 11px; }
365
+ }
366
+
367
+ @media (prefers-reduced-motion: reduce) {
368
+ .bliptar__card, .bliptar__btn, .bliptar__star, .bliptar__emoji, .bliptar__nps-btn, .bliptar__nav-btn {
369
+ animation: none !important;
370
+ transition: none !important;
371
+ }
372
+ }
373
+
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">
376
+ <svg width="14" height="14" viewBox="0 0 14 14" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round">
377
+ <path d="M1 1l12 12M1 13L13 1"/>
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)}
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)}
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">
387
+ <div class="bliptar__thankyou">
388
+ <div class="bliptar__thankyou-emoji">\u{1F389}</div>
389
+ <div class="bliptar__thankyou-text">${this.escapeHtml(t.thankYouMessage||"Thank you for your feedback!")}</div>
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};
package/package.json ADDED
@@ -0,0 +1,54 @@
1
+ {
2
+ "name": "@bliptarjs/sdk",
3
+ "version": "0.1.0",
4
+ "description": "Bliptar SDK - Lightweight micro-feedback for web apps",
5
+ "type": "module",
6
+ "main": "./dist/index.cjs",
7
+ "module": "./dist/index.js",
8
+ "types": "./dist/index.d.ts",
9
+ "exports": {
10
+ ".": {
11
+ "types": "./dist/index.d.ts",
12
+ "import": "./dist/index.js",
13
+ "require": "./dist/index.cjs"
14
+ }
15
+ },
16
+ "files": [
17
+ "dist"
18
+ ],
19
+ "scripts": {
20
+ "build": "tsup src/index.ts --format esm,cjs --dts --minify",
21
+ "dev": "tsup src/index.ts --format esm,cjs --dts --watch",
22
+ "typecheck": "tsc --noEmit",
23
+ "test": "vitest run",
24
+ "test:watch": "vitest",
25
+ "test:coverage": "vitest run --coverage",
26
+ "size": "size-limit",
27
+ "release": "./scripts/publish-to-npm.sh"
28
+ },
29
+ "keywords": [
30
+ "feedback",
31
+ "survey",
32
+ "micro-feedback",
33
+ "nps",
34
+ "user-feedback",
35
+ "analytics"
36
+ ],
37
+ "author": "",
38
+ "license": "MIT",
39
+ "devDependencies": {
40
+ "@size-limit/preset-small-lib": "^11.0.0",
41
+ "@vitest/coverage-v8": "^2.1.0",
42
+ "happy-dom": "^15.0.0",
43
+ "size-limit": "^11.0.0",
44
+ "tsup": "^8.0.0",
45
+ "typescript": "^5.3.0",
46
+ "vitest": "^2.1.0"
47
+ },
48
+ "size-limit": [
49
+ {
50
+ "path": "dist/index.js",
51
+ "limit": "8 KB"
52
+ }
53
+ ]
54
+ }