@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 CHANGED
@@ -86,13 +86,10 @@ widget.mount();
86
86
 
87
87
  ## Documentation
88
88
 
89
- - [Installation Guide](docs/installation.md)
90
- - [Widget Types](docs/widgets.md)
91
- - [Configuration](docs/configuration.md)
92
- - [API Reference](docs/api.md)
93
- - [Theming Guide](docs/theming.md)
94
- - [Examples](docs/examples.md)
95
- - [Migration Guide](docs/migration.md)
89
+ - [Installation Guide](src/docs/installation.md)
90
+ - [Framework Integrations](src/docs/framework-integrations.md)
91
+ - [API Reference](src/docs/api.md)
92
+ - [Examples](src/docs/example.md)
96
93
 
97
94
  ---
98
95
 
package/dist/README.md CHANGED
@@ -86,13 +86,10 @@ widget.mount();
86
86
 
87
87
  ## Documentation
88
88
 
89
- - [Installation Guide](docs/installation.md)
90
- - [Widget Types](docs/widgets.md)
91
- - [Configuration](docs/configuration.md)
92
- - [API Reference](docs/api.md)
93
- - [Theming Guide](docs/theming.md)
94
- - [Examples](docs/examples.md)
95
- - [Migration Guide](docs/migration.md)
89
+ - [Installation Guide](src/docs/installation.md)
90
+ - [Framework Integrations](src/docs/framework-integrations.md)
91
+ - [API Reference](src/docs/api.md)
92
+ - [Examples](src/docs/example.md)
96
93
 
97
94
  ---
98
95
 
@@ -2202,6 +2202,21 @@
2202
2202
  const button = this.element.querySelector('.feedback-trigger-btn');
2203
2203
  const minimizeIcon = this.element.querySelector('.feedback-minimize-icon');
2204
2204
  const expandIcon = this.element.querySelector('.feedback-expand-icon');
2205
+ const isControlIcon = (target) => {
2206
+ if (!(target instanceof Element)) return false;
2207
+ return Boolean(
2208
+ target.closest('.feedback-minimize-icon') ||
2209
+ target.closest('.feedback-expand-icon')
2210
+ );
2211
+ };
2212
+ const openIfAllowed = (target) => {
2213
+ if (isControlIcon(target)) {
2214
+ return;
2215
+ }
2216
+ if (!this.isMinimized) {
2217
+ this.openPanel();
2218
+ }
2219
+ };
2205
2220
 
2206
2221
  minimizeIcon.addEventListener('click', (e) => {
2207
2222
  e.stopPropagation();
@@ -2216,16 +2231,13 @@
2216
2231
  });
2217
2232
 
2218
2233
  button.addEventListener('click', (e) => {
2219
- if (
2220
- e.target.closest('.feedback-minimize-icon') ||
2221
- e.target.closest('.feedback-expand-icon')
2222
- ) {
2223
- return;
2224
- }
2234
+ openIfAllowed(e.target);
2235
+ });
2225
2236
 
2226
- if (!this.isMinimized) {
2227
- this.openPanel();
2228
- }
2237
+ // Pointer events improve consistency across touch and mouse devices.
2238
+ button.addEventListener('pointerup', (e) => {
2239
+ if (e.pointerType === 'mouse') return;
2240
+ openIfAllowed(e.target);
2229
2241
  });
2230
2242
  }
2231
2243
 
@@ -2370,18 +2382,14 @@
2370
2382
 
2371
2383
  this.modalElement
2372
2384
  .querySelector('.changelog-modal-container')
2373
- .addEventListener('click', (e) => {
2374
- e.stopPropagation();
2375
- });
2385
+ .addEventListener('click', (e) => e.stopPropagation());
2376
2386
 
2377
2387
  this.modalElement
2378
2388
  .querySelector('.changelog-modal-close')
2379
2389
  .addEventListener('click', () => this.closeModal());
2380
2390
 
2381
2391
  this._escapeHandler = (e) => {
2382
- if (e.key === 'Escape') {
2383
- this.closeModal();
2384
- }
2392
+ if (e.key === 'Escape') this.closeModal();
2385
2393
  };
2386
2394
  document.addEventListener('keydown', this._escapeHandler);
2387
2395
  }
@@ -2459,9 +2467,7 @@
2459
2467
  }
2460
2468
 
2461
2469
  setTimeout(() => {
2462
- if (container.parentNode) {
2463
- container.parentNode.removeChild(container);
2464
- }
2470
+ if (container.parentNode) container.parentNode.removeChild(container);
2465
2471
  }, 2500);
2466
2472
  }
2467
2473
 
@@ -2524,18 +2530,14 @@
2524
2530
 
2525
2531
  this.listModalElement
2526
2532
  .querySelector('.changelog-list-modal-container')
2527
- .addEventListener('click', (e) => {
2528
- e.stopPropagation();
2529
- });
2533
+ .addEventListener('click', (e) => e.stopPropagation());
2530
2534
 
2531
2535
  this.listModalElement
2532
2536
  .querySelector('.changelog-list-modal-close')
2533
2537
  .addEventListener('click', () => this.closeSidebar());
2534
2538
 
2535
2539
  this._listModalEscapeHandler = (e) => {
2536
- if (e.key === 'Escape') {
2537
- this.closeSidebar();
2538
- }
2540
+ if (e.key === 'Escape') this.closeSidebar();
2539
2541
  };
2540
2542
  document.addEventListener('keydown', this._listModalEscapeHandler);
2541
2543
  }
@@ -2545,9 +2547,7 @@
2545
2547
  '.changelog-list-modal-body'
2546
2548
  );
2547
2549
 
2548
- if (this.isLoading) {
2549
- return;
2550
- }
2550
+ if (this.isLoading) return;
2551
2551
 
2552
2552
  if (this.changelogs.length === 0) {
2553
2553
  body.innerHTML = `
@@ -2570,8 +2570,7 @@
2570
2570
 
2571
2571
  body.querySelectorAll('.changelog-list-item').forEach((item, index) => {
2572
2572
  item.addEventListener('click', () => {
2573
- const changelog = this.changelogs[index];
2574
- this._handleViewUpdate(changelog);
2573
+ this._handleViewUpdate(this.changelogs[index]);
2575
2574
  });
2576
2575
  });
2577
2576
  }
@@ -2582,6 +2581,10 @@
2582
2581
  const date = changelog.published_at
2583
2582
  ? this._formatDate(changelog.published_at)
2584
2583
  : '';
2584
+ const description = this._truncateDescription(
2585
+ changelog.excerpt || changelog.description,
2586
+ 120
2587
+ );
2585
2588
 
2586
2589
  return `
2587
2590
  <div class="changelog-list-item" data-index="${index}">
@@ -2613,13 +2616,7 @@
2613
2616
  : ''
2614
2617
  }
2615
2618
  <h3 class="changelog-list-item-title">${changelog.title}</h3>
2616
- ${
2617
- changelog.excerpt || changelog.description
2618
- ? `
2619
- <p class="changelog-list-item-description">${changelog.excerpt || changelog.description}</p>
2620
- `
2621
- : ''
2622
- }
2619
+ ${description ? `<p class="changelog-list-item-description">${description}</p>` : ''}
2623
2620
  </div>
2624
2621
  </div>
2625
2622
  </div>
@@ -2646,9 +2643,7 @@
2646
2643
  _renderCurrentChangelog() {
2647
2644
  const content = this.modalElement.querySelector('.changelog-modal-content');
2648
2645
 
2649
- if (this.isLoading) {
2650
- return;
2651
- }
2646
+ if (this.isLoading) return;
2652
2647
 
2653
2648
  if (this.changelogs.length === 0) {
2654
2649
  content.innerHTML = `
@@ -2667,6 +2662,10 @@
2667
2662
  const hasImage = changelog.cover_image || changelog.image;
2668
2663
  const imageUrl = changelog.cover_image || changelog.image;
2669
2664
  const hasMultiple = this.changelogs.length > 1;
2665
+ const description = this._truncateDescription(
2666
+ changelog.excerpt || changelog.description,
2667
+ 160
2668
+ );
2670
2669
 
2671
2670
  content.innerHTML = `
2672
2671
  <div class="changelog-popup-item">
@@ -2681,13 +2680,7 @@
2681
2680
  }
2682
2681
  <div class="changelog-popup-body">
2683
2682
  <h2 class="changelog-popup-title">${changelog.title}</h2>
2684
- ${
2685
- changelog.excerpt || changelog.description
2686
- ? `
2687
- <p class="changelog-popup-description">${changelog.excerpt || changelog.description}</p>
2688
- `
2689
- : ''
2690
- }
2683
+ ${description ? `<p class="changelog-popup-description">${description}</p>` : ''}
2691
2684
  <button class="changelog-popup-btn" type="button">
2692
2685
  ${this.options.viewButtonText || 'View Update'}
2693
2686
  </button>
@@ -2734,8 +2727,7 @@
2734
2727
  if (hasMultiple) {
2735
2728
  content.querySelectorAll('.changelog-dot').forEach((dot) => {
2736
2729
  dot.addEventListener('click', (e) => {
2737
- const index = parseInt(e.target.dataset.index, 10);
2738
- this.currentIndex = index;
2730
+ this.currentIndex = parseInt(e.target.dataset.index, 10);
2739
2731
  this._renderCurrentChangelog();
2740
2732
  });
2741
2733
  });
@@ -2745,10 +2737,19 @@
2745
2737
  _handleViewUpdate(changelog) {
2746
2738
  this.sdk.eventBus.emit('changelog:view', { changelog });
2747
2739
 
2748
- if (changelog.url || changelog.slug) {
2749
- const url =
2750
- changelog.url ||
2751
- `${this.options.changelogBaseUrl || ''}/${changelog.slug}`;
2740
+ const changelogBase = (this.options.changelogBaseUrl || '').replace(
2741
+ /\/$/,
2742
+ ''
2743
+ );
2744
+ const url =
2745
+ changelog.url ||
2746
+ (changelog.slug && changelogBase
2747
+ ? `${changelogBase}/${changelog.slug}`
2748
+ : null) ||
2749
+ changelogBase ||
2750
+ null;
2751
+
2752
+ if (url) {
2752
2753
  if (this.options.openInNewTab !== false) {
2753
2754
  window.open(url, '_blank', 'noopener,noreferrer');
2754
2755
  } else {
@@ -2761,10 +2762,26 @@
2761
2762
  }
2762
2763
  }
2763
2764
 
2765
+ _stripHtml(html) {
2766
+ const tmp = document.createElement('div');
2767
+ tmp.innerHTML = html;
2768
+ return (tmp.textContent || tmp.innerText || '').trim();
2769
+ }
2770
+
2771
+ _truncateDescription(html, maxLength = 120) {
2772
+ if (!html) return '';
2773
+ const plain = this._stripHtml(html);
2774
+ if (plain.length <= maxLength) return plain;
2775
+ return plain.substring(0, maxLength).trimEnd() + '...';
2776
+ }
2777
+
2764
2778
  _formatDate(dateString) {
2765
2779
  const date = new Date(dateString);
2766
- const options = { year: 'numeric', month: 'short', day: 'numeric' };
2767
- return date.toLocaleDateString('en-US', options);
2780
+ return date.toLocaleDateString('en-US', {
2781
+ year: 'numeric',
2782
+ month: 'short',
2783
+ day: 'numeric',
2784
+ });
2768
2785
  }
2769
2786
 
2770
2787
  _getContrastColor(hexColor) {
@@ -2778,16 +2795,12 @@
2778
2795
 
2779
2796
  hideBadge() {
2780
2797
  const badge = this.element?.querySelector('.changelog-badge');
2781
- if (badge) {
2782
- badge.style.display = 'none';
2783
- }
2798
+ if (badge) badge.style.display = 'none';
2784
2799
  }
2785
2800
 
2786
2801
  showBadge() {
2787
2802
  const badge = this.element?.querySelector('.changelog-badge');
2788
- if (badge) {
2789
- badge.style.display = 'block';
2790
- }
2803
+ if (badge) badge.style.display = 'block';
2791
2804
  }
2792
2805
 
2793
2806
  nextChangelog() {
@@ -6234,16 +6247,20 @@
6234
6247
  const response = await this.apiService.getHelpCollections();
6235
6248
  if (response.success && response.data) {
6236
6249
  const collections = response.data.collections || response.data;
6237
- const helpBase = (this.messengerOptions.helpUrl || '').replace(/\/$/, '');
6250
+ const helpBase = (this.messengerOptions.helpUrl || '').replace(
6251
+ /\/$/,
6252
+ ''
6253
+ );
6238
6254
 
6239
6255
  return collections.map((collection) => ({
6240
6256
  id: collection.id,
6241
6257
  title: collection.title,
6242
6258
  description: collection.description || '',
6243
6259
  articleCount: collection.article_count || 0,
6244
- url: collection.url_slug && helpBase
6245
- ? `${helpBase}/collections/${collection.url_slug}`
6246
- : helpBase || null,
6260
+ url:
6261
+ collection.url_slug && helpBase
6262
+ ? `${helpBase}/collections/${collection.url_slug}`
6263
+ : helpBase || null,
6247
6264
  }));
6248
6265
  }
6249
6266
  return [];
@@ -6456,7 +6473,9 @@
6456
6473
 
6457
6474
  if (response.success && response.data) {
6458
6475
  const changelogs = Array.isArray(response.data) ? response.data : [];
6459
- const changelogBase = (this.messengerOptions.changelogUrl || '').replace(/\/$/, '');
6476
+ const changelogBase = (
6477
+ this.messengerOptions.changelogUrl || ''
6478
+ ).replace(/\/$/, '');
6460
6479
 
6461
6480
  const mappedItems = changelogs.map((item) => ({
6462
6481
  id: item.id,
@@ -6465,9 +6484,10 @@
6465
6484
  tags: item.labels ? item.labels.map((label) => label.name) : [],
6466
6485
  coverImage: item.cover_image || null,
6467
6486
  publishedAt: item.published_at,
6468
- url: item.slug && changelogBase
6469
- ? `${changelogBase}/${item.slug}`
6470
- : changelogBase || null,
6487
+ url:
6488
+ item.slug && changelogBase
6489
+ ? `${changelogBase}/${item.slug}`
6490
+ : changelogBase || null,
6471
6491
  }));
6472
6492
 
6473
6493
  return {
@@ -8854,7 +8874,7 @@
8854
8874
  const feedbackStyles = `
8855
8875
  .feedback-widget-button {
8856
8876
  position: fixed;
8857
- z-index: var(--z-modal);
8877
+ z-index: var(--z-notification);
8858
8878
  }
8859
8879
 
8860
8880
  .feedback-widget-button.position-bottom-right {
@@ -8896,6 +8916,8 @@
8896
8916
  background: var(--color-primary);
8897
8917
  box-shadow: var(--shadow-md);
8898
8918
  width: fit-content;
8919
+ touch-action: manipulation;
8920
+ -webkit-tap-highlight-color: transparent;
8899
8921
  }
8900
8922
 
8901
8923
  .feedback-trigger-btn:hover:not(:disabled) {
@@ -8934,6 +8956,7 @@
8934
8956
  transition: opacity var(--transition-base);
8935
8957
  box-shadow: var(--shadow-sm);
8936
8958
  cursor: pointer;
8959
+ pointer-events: none;
8937
8960
  }
8938
8961
 
8939
8962
  .feedback-minimize-icon svg,
@@ -8946,6 +8969,7 @@
8946
8969
 
8947
8970
  .feedback-widget-button:not(.minimized) .feedback-trigger-btn:hover .feedback-minimize-icon {
8948
8971
  opacity: 1;
8972
+ pointer-events: auto;
8949
8973
  }
8950
8974
 
8951
8975
  .feedback-widget-button.minimized .feedback-trigger-btn {
@@ -8965,6 +8989,7 @@
8965
8989
 
8966
8990
  .feedback-widget-button.minimized .feedback-trigger-btn:hover .feedback-expand-icon {
8967
8991
  opacity: 1;
8992
+ pointer-events: auto;
8968
8993
  }
8969
8994
 
8970
8995
  .feedback-panel {