@product7/feedback-sdk 1.4.4 → 1.4.7
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 +4 -7
- package/dist/README.md +4 -7
- package/dist/feedback-sdk.js +94 -69
- package/dist/feedback-sdk.js.map +1 -1
- package/dist/feedback-sdk.min.js +1 -1
- package/dist/feedback-sdk.min.js.map +1 -1
- package/package.json +1 -1
- package/src/docs/framework-integrations.md +707 -0
- package/src/styles/feedback.js +6 -1
- package/src/widgets/ButtonWidget.js +21 -9
- package/src/widgets/ChangelogWidget.js +52 -51
- package/src/widgets/MessengerWidget.js +16 -9
- package/src/widgets/messenger/MessengerState.js +1 -1
- package/src/widgets/messenger/views/ChangelogView.js +1 -1
- package/src/widgets/messenger/views/HelpView.js +1 -1
- package/src/widgets/messenger/views/HomeView.js +1 -1
package/src/styles/feedback.js
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
export const feedbackStyles = `
|
|
2
2
|
.feedback-widget-button {
|
|
3
3
|
position: fixed;
|
|
4
|
-
z-index: var(--z-
|
|
4
|
+
z-index: var(--z-notification);
|
|
5
5
|
}
|
|
6
6
|
|
|
7
7
|
.feedback-widget-button.position-bottom-right {
|
|
@@ -43,6 +43,8 @@ export const feedbackStyles = `
|
|
|
43
43
|
background: var(--color-primary);
|
|
44
44
|
box-shadow: var(--shadow-md);
|
|
45
45
|
width: fit-content;
|
|
46
|
+
touch-action: manipulation;
|
|
47
|
+
-webkit-tap-highlight-color: transparent;
|
|
46
48
|
}
|
|
47
49
|
|
|
48
50
|
.feedback-trigger-btn:hover:not(:disabled) {
|
|
@@ -81,6 +83,7 @@ export const feedbackStyles = `
|
|
|
81
83
|
transition: opacity var(--transition-base);
|
|
82
84
|
box-shadow: var(--shadow-sm);
|
|
83
85
|
cursor: pointer;
|
|
86
|
+
pointer-events: none;
|
|
84
87
|
}
|
|
85
88
|
|
|
86
89
|
.feedback-minimize-icon svg,
|
|
@@ -93,6 +96,7 @@ export const feedbackStyles = `
|
|
|
93
96
|
|
|
94
97
|
.feedback-widget-button:not(.minimized) .feedback-trigger-btn:hover .feedback-minimize-icon {
|
|
95
98
|
opacity: 1;
|
|
99
|
+
pointer-events: auto;
|
|
96
100
|
}
|
|
97
101
|
|
|
98
102
|
.feedback-widget-button.minimized .feedback-trigger-btn {
|
|
@@ -112,6 +116,7 @@ export const feedbackStyles = `
|
|
|
112
116
|
|
|
113
117
|
.feedback-widget-button.minimized .feedback-trigger-btn:hover .feedback-expand-icon {
|
|
114
118
|
opacity: 1;
|
|
119
|
+
pointer-events: auto;
|
|
115
120
|
}
|
|
116
121
|
|
|
117
122
|
.feedback-panel {
|
|
@@ -41,6 +41,21 @@ export class ButtonWidget extends BaseWidget {
|
|
|
41
41
|
const button = this.element.querySelector('.feedback-trigger-btn');
|
|
42
42
|
const minimizeIcon = this.element.querySelector('.feedback-minimize-icon');
|
|
43
43
|
const expandIcon = this.element.querySelector('.feedback-expand-icon');
|
|
44
|
+
const isControlIcon = (target) => {
|
|
45
|
+
if (!(target instanceof Element)) return false;
|
|
46
|
+
return Boolean(
|
|
47
|
+
target.closest('.feedback-minimize-icon') ||
|
|
48
|
+
target.closest('.feedback-expand-icon')
|
|
49
|
+
);
|
|
50
|
+
};
|
|
51
|
+
const openIfAllowed = (target) => {
|
|
52
|
+
if (isControlIcon(target)) {
|
|
53
|
+
return;
|
|
54
|
+
}
|
|
55
|
+
if (!this.isMinimized) {
|
|
56
|
+
this.openPanel();
|
|
57
|
+
}
|
|
58
|
+
};
|
|
44
59
|
|
|
45
60
|
minimizeIcon.addEventListener('click', (e) => {
|
|
46
61
|
e.stopPropagation();
|
|
@@ -55,16 +70,13 @@ export class ButtonWidget extends BaseWidget {
|
|
|
55
70
|
});
|
|
56
71
|
|
|
57
72
|
button.addEventListener('click', (e) => {
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
e.target.closest('.feedback-expand-icon')
|
|
61
|
-
) {
|
|
62
|
-
return;
|
|
63
|
-
}
|
|
73
|
+
openIfAllowed(e.target);
|
|
74
|
+
});
|
|
64
75
|
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
76
|
+
// Pointer events improve consistency across touch and mouse devices.
|
|
77
|
+
button.addEventListener('pointerup', (e) => {
|
|
78
|
+
if (e.pointerType === 'mouse') return;
|
|
79
|
+
openIfAllowed(e.target);
|
|
68
80
|
});
|
|
69
81
|
}
|
|
70
82
|
|
|
@@ -109,18 +109,14 @@ export class ChangelogWidget extends BaseWidget {
|
|
|
109
109
|
|
|
110
110
|
this.modalElement
|
|
111
111
|
.querySelector('.changelog-modal-container')
|
|
112
|
-
.addEventListener('click', (e) =>
|
|
113
|
-
e.stopPropagation();
|
|
114
|
-
});
|
|
112
|
+
.addEventListener('click', (e) => e.stopPropagation());
|
|
115
113
|
|
|
116
114
|
this.modalElement
|
|
117
115
|
.querySelector('.changelog-modal-close')
|
|
118
116
|
.addEventListener('click', () => this.closeModal());
|
|
119
117
|
|
|
120
118
|
this._escapeHandler = (e) => {
|
|
121
|
-
if (e.key === 'Escape')
|
|
122
|
-
this.closeModal();
|
|
123
|
-
}
|
|
119
|
+
if (e.key === 'Escape') this.closeModal();
|
|
124
120
|
};
|
|
125
121
|
document.addEventListener('keydown', this._escapeHandler);
|
|
126
122
|
}
|
|
@@ -198,9 +194,7 @@ export class ChangelogWidget extends BaseWidget {
|
|
|
198
194
|
}
|
|
199
195
|
|
|
200
196
|
setTimeout(() => {
|
|
201
|
-
if (container.parentNode)
|
|
202
|
-
container.parentNode.removeChild(container);
|
|
203
|
-
}
|
|
197
|
+
if (container.parentNode) container.parentNode.removeChild(container);
|
|
204
198
|
}, 2500);
|
|
205
199
|
}
|
|
206
200
|
|
|
@@ -263,18 +257,14 @@ export class ChangelogWidget extends BaseWidget {
|
|
|
263
257
|
|
|
264
258
|
this.listModalElement
|
|
265
259
|
.querySelector('.changelog-list-modal-container')
|
|
266
|
-
.addEventListener('click', (e) =>
|
|
267
|
-
e.stopPropagation();
|
|
268
|
-
});
|
|
260
|
+
.addEventListener('click', (e) => e.stopPropagation());
|
|
269
261
|
|
|
270
262
|
this.listModalElement
|
|
271
263
|
.querySelector('.changelog-list-modal-close')
|
|
272
264
|
.addEventListener('click', () => this.closeSidebar());
|
|
273
265
|
|
|
274
266
|
this._listModalEscapeHandler = (e) => {
|
|
275
|
-
if (e.key === 'Escape')
|
|
276
|
-
this.closeSidebar();
|
|
277
|
-
}
|
|
267
|
+
if (e.key === 'Escape') this.closeSidebar();
|
|
278
268
|
};
|
|
279
269
|
document.addEventListener('keydown', this._listModalEscapeHandler);
|
|
280
270
|
}
|
|
@@ -284,9 +274,7 @@ export class ChangelogWidget extends BaseWidget {
|
|
|
284
274
|
'.changelog-list-modal-body'
|
|
285
275
|
);
|
|
286
276
|
|
|
287
|
-
if (this.isLoading)
|
|
288
|
-
return;
|
|
289
|
-
}
|
|
277
|
+
if (this.isLoading) return;
|
|
290
278
|
|
|
291
279
|
if (this.changelogs.length === 0) {
|
|
292
280
|
body.innerHTML = `
|
|
@@ -309,8 +297,7 @@ export class ChangelogWidget extends BaseWidget {
|
|
|
309
297
|
|
|
310
298
|
body.querySelectorAll('.changelog-list-item').forEach((item, index) => {
|
|
311
299
|
item.addEventListener('click', () => {
|
|
312
|
-
|
|
313
|
-
this._handleViewUpdate(changelog);
|
|
300
|
+
this._handleViewUpdate(this.changelogs[index]);
|
|
314
301
|
});
|
|
315
302
|
});
|
|
316
303
|
}
|
|
@@ -321,6 +308,10 @@ export class ChangelogWidget extends BaseWidget {
|
|
|
321
308
|
const date = changelog.published_at
|
|
322
309
|
? this._formatDate(changelog.published_at)
|
|
323
310
|
: '';
|
|
311
|
+
const description = this._truncateDescription(
|
|
312
|
+
changelog.excerpt || changelog.description,
|
|
313
|
+
120
|
|
314
|
+
);
|
|
324
315
|
|
|
325
316
|
return `
|
|
326
317
|
<div class="changelog-list-item" data-index="${index}">
|
|
@@ -352,13 +343,7 @@ export class ChangelogWidget extends BaseWidget {
|
|
|
352
343
|
: ''
|
|
353
344
|
}
|
|
354
345
|
<h3 class="changelog-list-item-title">${changelog.title}</h3>
|
|
355
|
-
${
|
|
356
|
-
changelog.excerpt || changelog.description
|
|
357
|
-
? `
|
|
358
|
-
<p class="changelog-list-item-description">${changelog.excerpt || changelog.description}</p>
|
|
359
|
-
`
|
|
360
|
-
: ''
|
|
361
|
-
}
|
|
346
|
+
${description ? `<p class="changelog-list-item-description">${description}</p>` : ''}
|
|
362
347
|
</div>
|
|
363
348
|
</div>
|
|
364
349
|
</div>
|
|
@@ -385,9 +370,7 @@ export class ChangelogWidget extends BaseWidget {
|
|
|
385
370
|
_renderCurrentChangelog() {
|
|
386
371
|
const content = this.modalElement.querySelector('.changelog-modal-content');
|
|
387
372
|
|
|
388
|
-
if (this.isLoading)
|
|
389
|
-
return;
|
|
390
|
-
}
|
|
373
|
+
if (this.isLoading) return;
|
|
391
374
|
|
|
392
375
|
if (this.changelogs.length === 0) {
|
|
393
376
|
content.innerHTML = `
|
|
@@ -406,6 +389,10 @@ export class ChangelogWidget extends BaseWidget {
|
|
|
406
389
|
const hasImage = changelog.cover_image || changelog.image;
|
|
407
390
|
const imageUrl = changelog.cover_image || changelog.image;
|
|
408
391
|
const hasMultiple = this.changelogs.length > 1;
|
|
392
|
+
const description = this._truncateDescription(
|
|
393
|
+
changelog.excerpt || changelog.description,
|
|
394
|
+
160
|
|
395
|
+
);
|
|
409
396
|
|
|
410
397
|
content.innerHTML = `
|
|
411
398
|
<div class="changelog-popup-item">
|
|
@@ -420,13 +407,7 @@ export class ChangelogWidget extends BaseWidget {
|
|
|
420
407
|
}
|
|
421
408
|
<div class="changelog-popup-body">
|
|
422
409
|
<h2 class="changelog-popup-title">${changelog.title}</h2>
|
|
423
|
-
${
|
|
424
|
-
changelog.excerpt || changelog.description
|
|
425
|
-
? `
|
|
426
|
-
<p class="changelog-popup-description">${changelog.excerpt || changelog.description}</p>
|
|
427
|
-
`
|
|
428
|
-
: ''
|
|
429
|
-
}
|
|
410
|
+
${description ? `<p class="changelog-popup-description">${description}</p>` : ''}
|
|
430
411
|
<button class="changelog-popup-btn" type="button">
|
|
431
412
|
${this.options.viewButtonText || 'View Update'}
|
|
432
413
|
</button>
|
|
@@ -473,8 +454,7 @@ export class ChangelogWidget extends BaseWidget {
|
|
|
473
454
|
if (hasMultiple) {
|
|
474
455
|
content.querySelectorAll('.changelog-dot').forEach((dot) => {
|
|
475
456
|
dot.addEventListener('click', (e) => {
|
|
476
|
-
|
|
477
|
-
this.currentIndex = index;
|
|
457
|
+
this.currentIndex = parseInt(e.target.dataset.index, 10);
|
|
478
458
|
this._renderCurrentChangelog();
|
|
479
459
|
});
|
|
480
460
|
});
|
|
@@ -484,10 +464,19 @@ export class ChangelogWidget extends BaseWidget {
|
|
|
484
464
|
_handleViewUpdate(changelog) {
|
|
485
465
|
this.sdk.eventBus.emit('changelog:view', { changelog });
|
|
486
466
|
|
|
487
|
-
|
|
488
|
-
|
|
489
|
-
|
|
490
|
-
|
|
467
|
+
const changelogBase = (this.options.changelogBaseUrl || '').replace(
|
|
468
|
+
/\/$/,
|
|
469
|
+
''
|
|
470
|
+
);
|
|
471
|
+
const url =
|
|
472
|
+
changelog.url ||
|
|
473
|
+
(changelog.slug && changelogBase
|
|
474
|
+
? `${changelogBase}/${changelog.slug}`
|
|
475
|
+
: null) ||
|
|
476
|
+
changelogBase ||
|
|
477
|
+
null;
|
|
478
|
+
|
|
479
|
+
if (url) {
|
|
491
480
|
if (this.options.openInNewTab !== false) {
|
|
492
481
|
window.open(url, '_blank', 'noopener,noreferrer');
|
|
493
482
|
} else {
|
|
@@ -500,10 +489,26 @@ export class ChangelogWidget extends BaseWidget {
|
|
|
500
489
|
}
|
|
501
490
|
}
|
|
502
491
|
|
|
492
|
+
_stripHtml(html) {
|
|
493
|
+
const tmp = document.createElement('div');
|
|
494
|
+
tmp.innerHTML = html;
|
|
495
|
+
return (tmp.textContent || tmp.innerText || '').trim();
|
|
496
|
+
}
|
|
497
|
+
|
|
498
|
+
_truncateDescription(html, maxLength = 120) {
|
|
499
|
+
if (!html) return '';
|
|
500
|
+
const plain = this._stripHtml(html);
|
|
501
|
+
if (plain.length <= maxLength) return plain;
|
|
502
|
+
return plain.substring(0, maxLength).trimEnd() + '...';
|
|
503
|
+
}
|
|
504
|
+
|
|
503
505
|
_formatDate(dateString) {
|
|
504
506
|
const date = new Date(dateString);
|
|
505
|
-
|
|
506
|
-
|
|
507
|
+
return date.toLocaleDateString('en-US', {
|
|
508
|
+
year: 'numeric',
|
|
509
|
+
month: 'short',
|
|
510
|
+
day: 'numeric',
|
|
511
|
+
});
|
|
507
512
|
}
|
|
508
513
|
|
|
509
514
|
_getContrastColor(hexColor) {
|
|
@@ -517,16 +522,12 @@ export class ChangelogWidget extends BaseWidget {
|
|
|
517
522
|
|
|
518
523
|
hideBadge() {
|
|
519
524
|
const badge = this.element?.querySelector('.changelog-badge');
|
|
520
|
-
if (badge)
|
|
521
|
-
badge.style.display = 'none';
|
|
522
|
-
}
|
|
525
|
+
if (badge) badge.style.display = 'none';
|
|
523
526
|
}
|
|
524
527
|
|
|
525
528
|
showBadge() {
|
|
526
529
|
const badge = this.element?.querySelector('.changelog-badge');
|
|
527
|
-
if (badge)
|
|
528
|
-
badge.style.display = 'block';
|
|
529
|
-
}
|
|
530
|
+
if (badge) badge.style.display = 'block';
|
|
530
531
|
}
|
|
531
532
|
|
|
532
533
|
nextChangelog() {
|
|
@@ -556,16 +556,20 @@ export class MessengerWidget extends BaseWidget {
|
|
|
556
556
|
const response = await this.apiService.getHelpCollections();
|
|
557
557
|
if (response.success && response.data) {
|
|
558
558
|
const collections = response.data.collections || response.data;
|
|
559
|
-
const helpBase = (this.messengerOptions.helpUrl || '').replace(
|
|
559
|
+
const helpBase = (this.messengerOptions.helpUrl || '').replace(
|
|
560
|
+
/\/$/,
|
|
561
|
+
''
|
|
562
|
+
);
|
|
560
563
|
|
|
561
564
|
return collections.map((collection) => ({
|
|
562
565
|
id: collection.id,
|
|
563
566
|
title: collection.title,
|
|
564
567
|
description: collection.description || '',
|
|
565
568
|
articleCount: collection.article_count || 0,
|
|
566
|
-
url:
|
|
567
|
-
|
|
568
|
-
|
|
569
|
+
url:
|
|
570
|
+
collection.url_slug && helpBase
|
|
571
|
+
? `${helpBase}/collections/${collection.url_slug}`
|
|
572
|
+
: helpBase || null,
|
|
569
573
|
}));
|
|
570
574
|
}
|
|
571
575
|
return [];
|
|
@@ -778,7 +782,9 @@ export class MessengerWidget extends BaseWidget {
|
|
|
778
782
|
|
|
779
783
|
if (response.success && response.data) {
|
|
780
784
|
const changelogs = Array.isArray(response.data) ? response.data : [];
|
|
781
|
-
const changelogBase = (
|
|
785
|
+
const changelogBase = (
|
|
786
|
+
this.messengerOptions.changelogUrl || ''
|
|
787
|
+
).replace(/\/$/, '');
|
|
782
788
|
|
|
783
789
|
const mappedItems = changelogs.map((item) => ({
|
|
784
790
|
id: item.id,
|
|
@@ -787,9 +793,10 @@ export class MessengerWidget extends BaseWidget {
|
|
|
787
793
|
tags: item.labels ? item.labels.map((label) => label.name) : [],
|
|
788
794
|
coverImage: item.cover_image || null,
|
|
789
795
|
publishedAt: item.published_at,
|
|
790
|
-
url:
|
|
791
|
-
|
|
792
|
-
|
|
796
|
+
url:
|
|
797
|
+
item.slug && changelogBase
|
|
798
|
+
? `${changelogBase}/${item.slug}`
|
|
799
|
+
: changelogBase || null,
|
|
793
800
|
}));
|
|
794
801
|
|
|
795
802
|
return {
|
|
@@ -848,4 +855,4 @@ export class MessengerWidget extends BaseWidget {
|
|
|
848
855
|
this.onDestroy();
|
|
849
856
|
super.destroy();
|
|
850
857
|
}
|
|
851
|
-
}
|
|
858
|
+
}
|