@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.
@@ -1,7 +1,7 @@
1
1
  export const feedbackStyles = `
2
2
  .feedback-widget-button {
3
3
  position: fixed;
4
- z-index: var(--z-modal);
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
- if (
59
- e.target.closest('.feedback-minimize-icon') ||
60
- e.target.closest('.feedback-expand-icon')
61
- ) {
62
- return;
63
- }
73
+ openIfAllowed(e.target);
74
+ });
64
75
 
65
- if (!this.isMinimized) {
66
- this.openPanel();
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
- const changelog = this.changelogs[index];
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
- const index = parseInt(e.target.dataset.index, 10);
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
- if (changelog.url || changelog.slug) {
488
- const url =
489
- changelog.url ||
490
- `${this.options.changelogBaseUrl || ''}/${changelog.slug}`;
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
- const options = { year: 'numeric', month: 'short', day: 'numeric' };
506
- return date.toLocaleDateString('en-US', options);
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: collection.url_slug && helpBase
567
- ? `${helpBase}/collections/${collection.url_slug}`
568
- : helpBase || null,
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 = (this.messengerOptions.changelogUrl || '').replace(/\/$/, '');
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: item.slug && changelogBase
791
- ? `${changelogBase}/${item.slug}`
792
- : changelogBase || null,
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
+ }
@@ -202,4 +202,4 @@ export class MessengerState {
202
202
  this.helpSearchQuery = '';
203
203
  this._notify('reset', {});
204
204
  }
205
- }
205
+ }
@@ -170,4 +170,4 @@ export class ChangelogView {
170
170
  this.element.parentNode.removeChild(this.element);
171
171
  }
172
172
  }
173
- }
173
+ }
@@ -178,4 +178,4 @@ export class HelpView {
178
178
  this.element.parentNode.removeChild(this.element);
179
179
  }
180
180
  }
181
- }
181
+ }
@@ -314,4 +314,4 @@ export class HomeView {
314
314
  this.element.parentNode.removeChild(this.element);
315
315
  }
316
316
  }
317
- }
317
+ }