@product7/feedback-sdk 1.6.6 → 1.6.8

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/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@product7/feedback-sdk",
3
- "version": "1.6.6",
3
+ "version": "1.6.8",
4
4
  "description": "JavaScript SDK for integrating Product7 feedback widgets into any website",
5
5
  "main": "dist/feedback-sdk.js",
6
6
  "module": "src/index.js",
@@ -1,4 +1,4 @@
1
- import { MOCK_CHANGELOGS } from '../mock-data';
1
+ import { MOCK_CHANGELOGS } from '../mock-data/index.js';
2
2
  import { delay } from '../utils/helpers.js';
3
3
 
4
4
  export class ChangelogService {
@@ -1,4 +1,4 @@
1
- import { MOCK_HELP_COLLECTIONS } from '../mock-data';
1
+ import { MOCK_HELP_COLLECTIONS } from '../mock-data/index.js';
2
2
  import { delay } from '../utils/helpers.js';
3
3
 
4
4
  export class HelpService {
@@ -1,4 +1,4 @@
1
- import { MOCK_CONVERSATIONS, MOCK_MESSAGES } from '../mock-data';
1
+ import { MOCK_CONVERSATIONS, MOCK_MESSAGES } from '../mock-data/index.js';
2
2
  import { delay } from '../utils/helpers.js';
3
3
 
4
4
  export class MessengerService {
@@ -1,5 +1,5 @@
1
1
  import { APIError } from '../../utils/errors.js';
2
- import { MOCK_SURVEYS } from '../mock-data';
2
+ import { MOCK_SURVEYS } from '../mock-data/index.js';
3
3
  import { delay, getDeviceInfo } from '../utils/helpers.js';
4
4
 
5
5
  export class SurveyService {
@@ -90,15 +90,19 @@ export class BaseAPIService {
90
90
  body: JSON.stringify(payload),
91
91
  headers: { 'Content-Type': 'application/json' },
92
92
  });
93
+ const initData = this._extractInitResponseData(response);
93
94
 
94
- this.sessionToken = response.session_token;
95
- this.sessionExpiry = new Date(Date.now() + response.expires_in * 1000);
95
+ this.sessionToken = initData.sessionToken;
96
+ this.sessionExpiry = new Date(Date.now() + initData.expiresIn * 1000);
96
97
  this._storeSession();
97
98
 
98
99
  return {
99
100
  sessionToken: this.sessionToken,
100
- config: response.config || {},
101
- expiresIn: response.expires_in,
101
+ config: initData.config,
102
+ expiresIn: initData.expiresIn,
103
+ status: initData.status,
104
+ message: initData.message,
105
+ configVersion: initData.configVersion,
102
106
  };
103
107
  } catch (error) {
104
108
  throw new APIError(
@@ -109,6 +113,34 @@ export class BaseAPIService {
109
113
  }
110
114
  }
111
115
 
116
+ _extractInitResponseData(response) {
117
+ const payload =
118
+ response && typeof response.data === 'object' ? response.data : response || {};
119
+
120
+ const sessionToken = payload.session_token || payload.sessionToken;
121
+ const expiresIn = Number(payload.expires_in ?? payload.expiresIn);
122
+
123
+ if (!sessionToken) {
124
+ throw new APIError(500, 'Invalid init response: missing session_token');
125
+ }
126
+
127
+ if (!Number.isFinite(expiresIn) || expiresIn <= 0) {
128
+ throw new APIError(500, 'Invalid init response: missing expires_in');
129
+ }
130
+
131
+ return {
132
+ sessionToken,
133
+ expiresIn,
134
+ config:
135
+ payload.config && typeof payload.config === 'object'
136
+ ? payload.config
137
+ : {},
138
+ configVersion: payload.config_version ?? payload.configVersion ?? null,
139
+ status: response?.status ?? payload?.status ?? true,
140
+ message: response?.message ?? payload?.message ?? null,
141
+ };
142
+ }
143
+
112
144
  async _ensureSession() {
113
145
  if (!this.isSessionValid()) {
114
146
  await this.init();
@@ -65,6 +65,10 @@ export class FeedbackSDK {
65
65
  const widgetId = generateId('widget');
66
66
  const widgetConfig = this._getWidgetTypeConfig(type);
67
67
  const explicitOptions = this._omitUndefined(options);
68
+ const widgetEnabled = this._isWidgetEnabled(type, {
69
+ ...widgetConfig,
70
+ ...explicitOptions,
71
+ });
68
72
  const widgetOptions = {
69
73
  id: widgetId,
70
74
  sdk: this,
@@ -72,6 +76,7 @@ export class FeedbackSDK {
72
76
  ...this.config,
73
77
  ...widgetConfig,
74
78
  ...explicitOptions,
79
+ enabled: widgetEnabled,
75
80
  };
76
81
 
77
82
  try {
@@ -162,6 +167,7 @@ export class FeedbackSDK {
162
167
  surveyConfig.showDescription ?? surveyConfig.show_description,
163
168
  customQuestions: surveyConfig.customQuestions || surveyConfig.questions,
164
169
  pages: surveyConfig.pages,
170
+ enabled: surveyConfig.enabled,
165
171
  ...displayOptions,
166
172
  });
167
173
  }
@@ -184,6 +190,17 @@ export class FeedbackSDK {
184
190
 
185
191
  const normalizedOptions = this._normalizeSurveyConfig(options);
186
192
  const surveyConfigDefaults = this._getWidgetTypeConfig('survey');
193
+ const surveyEnabled = this._isWidgetEnabled('survey', normalizedOptions);
194
+
195
+ if (!surveyEnabled) {
196
+ this.eventBus.emit('survey:suppressed', {
197
+ surveyId:
198
+ normalizedOptions.surveyId || normalizedOptions.id || options.id || null,
199
+ reason: 'disabled',
200
+ survey: normalizedOptions,
201
+ });
202
+ return null;
203
+ }
187
204
 
188
205
  const surveyWidget = this.createWidget('survey', {
189
206
  surveyId: normalizedOptions.surveyId,
@@ -215,6 +232,7 @@ export class FeedbackSDK {
215
232
  email: normalizedOptions.email,
216
233
  onSubmit: normalizedOptions.onSubmit,
217
234
  onDismiss: normalizedOptions.onDismiss,
235
+ enabled: surveyEnabled,
218
236
  });
219
237
 
220
238
  surveyWidget.mount();
@@ -308,13 +326,19 @@ export class FeedbackSDK {
308
326
  : {};
309
327
 
310
328
  const inferredType =
311
- survey.type || this._inferSurveyTypeFromPage(firstPage) || 'nps';
329
+ survey.surveyType ||
330
+ survey.survey_type ||
331
+ survey.type ||
332
+ this._inferSurveyTypeFromPage(firstPage) ||
333
+ 'nps';
312
334
 
313
335
  return {
314
336
  ...survey,
315
- surveyId: survey.surveyId || survey.id || null,
316
- surveyType: survey.surveyType || inferredType,
317
- type: survey.type || inferredType,
337
+ surveyId: survey.surveyId || survey.survey_id || survey.id || null,
338
+ surveyType: survey.surveyType || survey.survey_type || inferredType,
339
+ type: survey.type || survey.survey_type || inferredType,
340
+ enabled:
341
+ typeof survey.enabled === 'boolean' ? survey.enabled : undefined,
318
342
  should_show:
319
343
  survey.should_show ??
320
344
  (survey.eligibility ? survey.eligibility.should_show : undefined),
@@ -343,7 +367,11 @@ export class FeedbackSDK {
343
367
  showTitle: survey.showTitle ?? survey.show_title ?? null,
344
368
  showDescription:
345
369
  survey.showDescription ?? survey.show_description ?? null,
346
- customQuestions: survey.customQuestions || survey.questions || [],
370
+ customQuestions:
371
+ survey.customQuestions ||
372
+ survey.custom_questions ||
373
+ survey.questions ||
374
+ [],
347
375
  pages: this._normalizeSurveyPages(survey.pages || []),
348
376
  };
349
377
  }
@@ -418,6 +446,23 @@ export class FeedbackSDK {
418
446
  return this._toCamelCaseObject(mergedTypeConfig);
419
447
  }
420
448
 
449
+ _isWidgetEnabled(type, options = {}) {
450
+ const typeConfig = this._getWidgetTypeConfig(type);
451
+ if (typeConfig.enabled === false) {
452
+ return false;
453
+ }
454
+
455
+ if (typeof options.enabled === 'boolean') {
456
+ return options.enabled;
457
+ }
458
+
459
+ if (typeof typeConfig.enabled === 'boolean') {
460
+ return typeConfig.enabled;
461
+ }
462
+
463
+ return true;
464
+ }
465
+
421
466
  _isPlainObject(value) {
422
467
  return Object.prototype.toString.call(value) === '[object Object]';
423
468
  }
@@ -471,11 +516,21 @@ export class FeedbackSDK {
471
516
 
472
517
  const configDefaults = this._getWidgetTypeConfig('changelog');
473
518
  const explicitOptions = this._omitUndefined(options);
519
+ const changelogEnabled = this._isWidgetEnabled('changelog', explicitOptions);
520
+
521
+ if (!changelogEnabled) {
522
+ this.eventBus.emit('widget:suppressed', {
523
+ type: 'changelog',
524
+ reason: 'disabled',
525
+ });
526
+ return null;
527
+ }
474
528
 
475
529
  const changelogWidget = this.createWidget('changelog', {
476
530
  ...defaults,
477
531
  ...configDefaults,
478
532
  ...explicitOptions,
533
+ enabled: changelogEnabled,
479
534
  });
480
535
 
481
536
  changelogWidget.mount();
@@ -130,6 +130,23 @@ export const changelogStyles = `
130
130
  font-family: inherit;
131
131
  }
132
132
 
133
+ .changelog-modal-backdrop,
134
+ .changelog-list-modal-backdrop {
135
+ position: fixed;
136
+ inset: 0;
137
+ background: rgba(0, 0, 0, 0.5);
138
+ opacity: 0;
139
+ pointer-events: none;
140
+ transition: opacity var(--transition-slow);
141
+ z-index: var(--z-modal-backdrop);
142
+ }
143
+
144
+ .changelog-modal-backdrop.show,
145
+ .changelog-list-modal-backdrop.show {
146
+ opacity: 1;
147
+ pointer-events: auto;
148
+ }
149
+
133
150
  .changelog-modal.open {
134
151
  pointer-events: auto;
135
152
  }
@@ -393,6 +410,53 @@ export const changelogStyles = `
393
410
  opacity: 1;
394
411
  }
395
412
 
413
+ .changelog-theme-dark.changelog-widget .changelog-trigger-btn {
414
+ background: #0F172A;
415
+ color: #E2E8F0;
416
+ border: 1px solid #334155;
417
+ }
418
+
419
+ .changelog-theme-dark.changelog-modal-backdrop,
420
+ .changelog-theme-dark.changelog-list-modal-backdrop {
421
+ background: rgba(2, 6, 23, 0.72);
422
+ }
423
+
424
+ .changelog-theme-dark .changelog-modal-container,
425
+ .changelog-theme-dark .changelog-list-modal-container {
426
+ background: #111827;
427
+ border: 1px solid #334155;
428
+ }
429
+
430
+ .changelog-theme-dark .changelog-list-modal-header {
431
+ background: #111827;
432
+ border-bottom-color: #334155;
433
+ }
434
+
435
+ .changelog-theme-dark .changelog-list-modal-header h2,
436
+ .changelog-theme-dark .changelog-list-item-title,
437
+ .changelog-theme-dark .changelog-popup-title,
438
+ .changelog-theme-dark .changelog-view-all-btn {
439
+ color: #F3F4F6;
440
+ }
441
+
442
+ .changelog-theme-dark .changelog-list-item-description,
443
+ .changelog-theme-dark .changelog-popup-description,
444
+ .changelog-theme-dark .changelog-list-item-date {
445
+ color: #9CA3AF;
446
+ }
447
+
448
+ .changelog-theme-dark .changelog-list-item {
449
+ border-bottom-color: #334155;
450
+ }
451
+
452
+ .changelog-theme-dark .changelog-list-item:hover {
453
+ background: #1F2937;
454
+ }
455
+
456
+ .changelog-theme-dark .changelog-popup-btn {
457
+ color: #FFFFFF;
458
+ }
459
+
396
460
  .changelog-list-modal-header {
397
461
  display: flex;
398
462
  align-items: center;
@@ -136,8 +136,26 @@ export const feedbackStyles = `
136
136
  transform: translateX(0);
137
137
  }
138
138
 
139
+ .feedback-modal {
140
+ position: fixed;
141
+ top: 50%;
142
+ left: 50%;
143
+ transform: translate(-50%, -50%) scale(0.96);
144
+ width: min(460px, calc(100vw - (var(--spacing-5) * 2)));
145
+ max-height: min(560px, calc(100vh - (var(--spacing-6) * 2)));
146
+ z-index: var(--z-popover);
147
+ transition: transform var(--transition-slow);
148
+ font-family: inherit;
149
+ box-shadow: rgba(50, 50, 93, 0.25) 0px 2px 5px -1px, rgba(0, 0, 0, 0.3) 0px 1px 3px -1px;
150
+ }
151
+
152
+ .feedback-modal.open {
153
+ transform: translate(-50%, -50%) scale(1);
154
+ }
155
+
139
156
  .feedback-panel-content {
140
- background: var(--color-white);
157
+ background: var(--feedback-panel-bg, var(--color-white));
158
+ color: var(--feedback-panel-text, var(--color-text-primary));
141
159
  height: 100%;
142
160
  display: flex;
143
161
  flex-direction: column;
@@ -157,7 +175,7 @@ export const feedbackStyles = `
157
175
  margin: 0;
158
176
  font-size: var(--font-size-xl);
159
177
  font-weight: var(--font-weight-semibold);
160
- color: var(--color-text-primary);
178
+ color: var(--feedback-panel-text, var(--color-text-primary));
161
179
  }
162
180
 
163
181
  .feedback-panel-body {
@@ -196,6 +214,51 @@ export const feedbackStyles = `
196
214
  display: block;
197
215
  }
198
216
 
217
+ .feedback-panel.theme-dark .feedback-panel-content,
218
+ .feedback-modal.theme-dark .feedback-panel-content {
219
+ background: #111827;
220
+ color: #E2E8F0;
221
+ }
222
+
223
+ .feedback-panel.theme-dark .feedback-panel-header,
224
+ .feedback-modal.theme-dark .feedback-panel-header {
225
+ border-bottom-color: #374151;
226
+ }
227
+
228
+ .feedback-panel.theme-dark .sdk-label,
229
+ .feedback-panel.theme-dark .feedback-panel-header h3,
230
+ .feedback-modal.theme-dark .sdk-label,
231
+ .feedback-modal.theme-dark .feedback-panel-header h3 {
232
+ color: #E2E8F0;
233
+ }
234
+
235
+ .feedback-panel.theme-dark .sdk-input,
236
+ .feedback-panel.theme-dark .sdk-textarea,
237
+ .feedback-modal.theme-dark .sdk-input,
238
+ .feedback-modal.theme-dark .sdk-textarea {
239
+ background: #1F2937;
240
+ border-color: #374151;
241
+ color: #E2E8F0;
242
+ }
243
+
244
+ .feedback-panel.theme-dark .sdk-input::placeholder,
245
+ .feedback-panel.theme-dark .sdk-textarea::placeholder,
246
+ .feedback-modal.theme-dark .sdk-input::placeholder,
247
+ .feedback-modal.theme-dark .sdk-textarea::placeholder {
248
+ color: #9CA3AF;
249
+ }
250
+
251
+ .feedback-panel.theme-dark .sdk-close-btn,
252
+ .feedback-modal.theme-dark .sdk-close-btn {
253
+ color: #9CA3AF;
254
+ }
255
+
256
+ .feedback-panel.theme-dark .sdk-close-btn:hover,
257
+ .feedback-modal.theme-dark .sdk-close-btn:hover {
258
+ background: #1F2937;
259
+ color: #E2E8F0;
260
+ }
261
+
199
262
  @media (max-width: 768px) {
200
263
  .feedback-widget-button {
201
264
  bottom: var(--spacing-4);
@@ -17,7 +17,12 @@ export function applyMessengerCustomStyles(options = {}) {
17
17
  }
18
18
 
19
19
  const adjustColor = (hex, percent, alpha = 1) => {
20
- const num = parseInt(hex.replace('#', ''), 16);
20
+ const normalized = String(hex || '').trim();
21
+ if (!/^#?[0-9a-fA-F]{6}$/.test(normalized)) {
22
+ return normalized || '#000000';
23
+ }
24
+
25
+ const num = parseInt(normalized.replace('#', ''), 16);
21
26
  const r = Math.max(0, Math.min(255, (num >> 16) + percent));
22
27
  const g = Math.max(0, Math.min(255, ((num >> 8) & 0x00ff) + percent));
23
28
  const b = Math.max(0, Math.min(255, (num & 0x0000ff) + percent));
@@ -29,6 +34,10 @@ export function applyMessengerCustomStyles(options = {}) {
29
34
  return '#' + ((r << 16) | (g << 8) | b).toString(16).padStart(6, '0');
30
35
  };
31
36
 
37
+ const darkSurface = adjustColor(backgroundColor, 12);
38
+ const darkSurfaceAlt = adjustColor(backgroundColor, 20);
39
+ const darkBorder = adjustColor(backgroundColor, 34);
40
+
32
41
  styleElement.textContent = `
33
42
  #product7-messenger-widget {
34
43
  --color-primary: ${primaryColor} !important;
@@ -90,6 +99,77 @@ export function applyMessengerCustomStyles(options = {}) {
90
99
  `
91
100
  : ''
92
101
  }
102
+
103
+ ${
104
+ theme === 'dark'
105
+ ? `
106
+ .messenger-widget.theme-dark .messenger-panel-content,
107
+ .messenger-widget.theme-dark .messenger-home-view,
108
+ .messenger-widget.theme-dark .messenger-nav,
109
+ .messenger-widget.theme-dark .messenger-chat-compose,
110
+ .messenger-widget.theme-dark .messenger-compose-attachments-preview,
111
+ .messenger-widget.theme-dark .messenger-home-featured,
112
+ .messenger-widget.theme-dark .messenger-chat-header {
113
+ background: ${backgroundColor} !important;
114
+ border-color: ${darkBorder} !important;
115
+ }
116
+
117
+ .messenger-widget.theme-dark .messenger-view,
118
+ .messenger-widget.theme-dark .messenger-chat-title,
119
+ .messenger-widget.theme-dark .messenger-home-greeting,
120
+ .messenger-widget.theme-dark .messenger-home-question,
121
+ .messenger-widget.theme-dark .messenger-home-featured-content h3,
122
+ .messenger-widget.theme-dark .messenger-home-featured-content p,
123
+ .messenger-widget.theme-dark .messenger-home-changelog-card-title,
124
+ .messenger-widget.theme-dark .messenger-home-changelog-card-desc,
125
+ .messenger-widget.theme-dark .messenger-conversation-title,
126
+ .messenger-widget.theme-dark .messenger-article-title,
127
+ .messenger-widget.theme-dark .messenger-compose-input,
128
+ .messenger-widget.theme-dark .messenger-message-sender,
129
+ .messenger-widget.theme-dark .messenger-message-time,
130
+ .messenger-widget.theme-dark .messenger-nav-label {
131
+ color: ${textColor} !important;
132
+ }
133
+
134
+ .messenger-widget.theme-dark .messenger-home-view {
135
+ background: linear-gradient(180deg, ${adjustColor(backgroundColor, 10)} 0%, ${backgroundColor} 55%) !important;
136
+ }
137
+
138
+ .messenger-widget.theme-dark .messenger-home-view::before {
139
+ background: radial-gradient(circle, ${adjustColor(primaryColor, 0, 0.12)} 0%, transparent 70%) !important;
140
+ }
141
+
142
+ .messenger-widget.theme-dark .messenger-home-message-btn,
143
+ .messenger-widget.theme-dark .messenger-home-changelog-card,
144
+ .messenger-widget.theme-dark .messenger-compose-input-wrapper,
145
+ .messenger-widget.theme-dark .messenger-message-received .messenger-message-bubble,
146
+ .messenger-widget.theme-dark .messenger-message-file,
147
+ .messenger-widget.theme-dark .messenger-prechat-card,
148
+ .messenger-widget.theme-dark .messenger-list-item,
149
+ .messenger-widget.theme-dark .messenger-article-item {
150
+ background: ${darkSurface} !important;
151
+ border-color: ${darkBorder} !important;
152
+ }
153
+
154
+ .messenger-widget.theme-dark .messenger-home-message-btn:hover,
155
+ .messenger-widget.theme-dark .messenger-home-changelog-card:hover,
156
+ .messenger-widget.theme-dark .messenger-list-item:hover,
157
+ .messenger-widget.theme-dark .messenger-article-item:hover {
158
+ background: ${darkSurfaceAlt} !important;
159
+ }
160
+
161
+ .messenger-widget.theme-dark .messenger-message-own .messenger-message-bubble,
162
+ .messenger-widget.theme-dark .messenger-compose-send,
163
+ .messenger-widget.theme-dark .messenger-launcher-btn,
164
+ .messenger-widget.theme-dark .messenger-nav-badge,
165
+ .messenger-widget.theme-dark .messenger-launcher-badge,
166
+ .messenger-widget.theme-dark .messenger-home-changelog-cover-text,
167
+ .messenger-widget.theme-dark .messenger-attachment-remove {
168
+ color: #FFFFFF !important;
169
+ }
170
+ `
171
+ : ''
172
+ }
93
173
  `;
94
174
 
95
175
  console.log('✅ Custom messenger styles applied:', { primaryColor, theme });
@@ -14,6 +14,10 @@ export const surveyStyles = `
14
14
  animation: fadeIn var(--transition-slow);
15
15
  }
16
16
 
17
+ .feedback-survey-backdrop-dark {
18
+ background: rgba(2, 6, 23, 0.72);
19
+ }
20
+
17
21
  /* ========================================
18
22
  SURVEY CARD
19
23
  ======================================== */
@@ -31,6 +35,79 @@ export const surveyStyles = `
31
35
  font-family: inherit;
32
36
  }
33
37
 
38
+ .feedback-survey-theme-dark {
39
+ background: #111827;
40
+ border-color: #374151;
41
+ }
42
+
43
+ .feedback-survey-theme-dark .feedback-survey-title,
44
+ .feedback-survey-theme-dark .feedback-survey-description-primary .feedback-survey-description {
45
+ color: #F3F4F6;
46
+ }
47
+
48
+ .feedback-survey-theme-dark .feedback-survey-description,
49
+ .feedback-survey-theme-dark .feedback-survey-labels,
50
+ .feedback-survey-theme-dark .feedback-survey-progress {
51
+ color: #9CA3AF;
52
+ }
53
+
54
+ .feedback-survey-theme-dark .feedback-survey-close {
55
+ color: #9CA3AF;
56
+ }
57
+
58
+ .feedback-survey-theme-dark .feedback-survey-close:hover {
59
+ background: #1F2937;
60
+ color: #F3F4F6;
61
+ }
62
+
63
+ .feedback-survey-theme-dark .feedback-survey-rating-scale {
64
+ border-color: #374151;
65
+ background: #1F2937;
66
+ }
67
+
68
+ .feedback-survey-theme-dark .feedback-survey-rating-scale-btn {
69
+ background: #1F2937;
70
+ border-right-color: #374151;
71
+ color: #F3F4F6;
72
+ }
73
+
74
+ .feedback-survey-theme-dark .feedback-survey-rating-scale-btn:hover,
75
+ .feedback-survey-theme-dark .feedback-survey-nps-btn:hover,
76
+ .feedback-survey-theme-dark .feedback-survey-ces-btn:hover,
77
+ .feedback-survey-theme-dark .feedback-survey-page-choice-btn:hover {
78
+ background: #273549;
79
+ }
80
+
81
+ .feedback-survey-theme-dark .feedback-survey-nps-btn,
82
+ .feedback-survey-theme-dark .feedback-survey-ces-btn,
83
+ .feedback-survey-theme-dark .feedback-survey-freq-btn,
84
+ .feedback-survey-theme-dark .feedback-survey-page-choice-btn {
85
+ background: #1F2937;
86
+ border-color: #374151;
87
+ color: #E5E7EB;
88
+ }
89
+
90
+ .feedback-survey-theme-dark .feedback-survey-page-textarea,
91
+ .feedback-survey-theme-dark .feedback-survey-select,
92
+ .feedback-survey-theme-dark .feedback-survey-input,
93
+ .feedback-survey-theme-dark .feedback-survey-textarea {
94
+ background: #1F2937;
95
+ border-color: #374151;
96
+ color: #F3F4F6;
97
+ }
98
+
99
+ .feedback-survey-theme-dark .feedback-survey-page-textarea::placeholder,
100
+ .feedback-survey-theme-dark .feedback-survey-input::placeholder,
101
+ .feedback-survey-theme-dark .feedback-survey-textarea::placeholder {
102
+ color: #9CA3AF;
103
+ }
104
+
105
+ .feedback-survey-theme-dark .feedback-survey-back {
106
+ background: #111827;
107
+ border-color: #374151;
108
+ color: #E5E7EB;
109
+ }
110
+
34
111
  .feedback-survey-bottom-right {
35
112
  bottom: var(--spacing-6);
36
113
  right: var(--spacing-6);
@@ -18,7 +18,7 @@ export class BaseWidget {
18
18
  backgroundColor: options.backgroundColor || '#ffffff',
19
19
  textColor: options.textColor || '#1F2937',
20
20
  autoShow: false,
21
- showBackdrop: false,
21
+ showBackdrop: true,
22
22
  customStyles: {},
23
23
  suppressAfterSubmission: true,
24
24
  suppressionDays: BaseWidget.DEFAULT_COOLDOWN_DAYS,
@@ -48,6 +48,15 @@ export class BaseWidget {
48
48
  mount(container) {
49
49
  if (this.mounted || this.destroyed) return this;
50
50
 
51
+ if (this.options.enabled === false) {
52
+ this.sdk.eventBus.emit('widget:suppressed', {
53
+ widget: this,
54
+ type: this.type,
55
+ reason: 'disabled',
56
+ });
57
+ return this;
58
+ }
59
+
51
60
  if (this.options.suppressAfterSubmission && this._hasRecentlySubmitted()) {
52
61
  this.sdk.eventBus.emit('widget:suppressed', {
53
62
  widget: this,
@@ -127,9 +136,11 @@ export class BaseWidget {
127
136
  _showLoadingModal() {
128
137
  this.state.isLoading = true;
129
138
 
130
- this.backdropElement = document.createElement('div');
131
- this.backdropElement.className = 'sdk-modal-backdrop';
132
- document.body.appendChild(this.backdropElement);
139
+ if (this.options.showBackdrop) {
140
+ this.backdropElement = document.createElement('div');
141
+ this.backdropElement.className = 'sdk-modal-backdrop';
142
+ document.body.appendChild(this.backdropElement);
143
+ }
133
144
 
134
145
  this.loadingElement = document.createElement('div');
135
146
  this.loadingElement.className = 'feedback-loading-modal';
@@ -139,7 +150,9 @@ export class BaseWidget {
139
150
  document.body.appendChild(this.loadingElement);
140
151
 
141
152
  requestAnimationFrame(() => {
142
- this.backdropElement.classList.add('show');
153
+ if (this.backdropElement) {
154
+ this.backdropElement.classList.add('show');
155
+ }
143
156
  this.loadingElement.classList.add('show');
144
157
  });
145
158
  }
@@ -334,16 +347,17 @@ export class BaseWidget {
334
347
  : 'feedback-panel';
335
348
  const sizeClass = `size-${this.options.size}`;
336
349
  this.panelElement = document.createElement('div');
337
- this.panelElement.className = `${modeClass} ${sizeClass}`;
350
+ const themeClass = `theme-${this.options.theme || 'light'}`;
351
+ this.panelElement.className = `${modeClass} ${sizeClass} ${themeClass}`;
352
+ this.panelElement.style.setProperty('--color-primary', this.options.primaryColor);
338
353
  this.panelElement.style.setProperty(
339
- '--primary-color',
340
- this.options.primaryColor
354
+ '--feedback-panel-bg',
355
+ this.options.backgroundColor
341
356
  );
342
357
  this.panelElement.style.setProperty(
343
- '--bg-color',
344
- this.options.backgroundColor
358
+ '--feedback-panel-text',
359
+ this.options.textColor
345
360
  );
346
- this.panelElement.style.setProperty('--text-color', this.options.textColor);
347
361
  this.panelElement.innerHTML = this._getPanelHTML();
348
362
 
349
363
  document.body.appendChild(this.panelElement);