@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 +131 -0
- package/dist/index.cjs +391 -0
- package/dist/index.d.cts +151 -0
- package/dist/index.d.ts +151 -0
- package/dist/index.js +391 -0
- package/package.json +54 -0
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});
|
package/dist/index.d.cts
ADDED
|
@@ -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.d.ts
ADDED
|
@@ -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
|
+
}
|