@product7/feedback-sdk 1.6.1 → 1.6.4

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.1",
3
+ "version": "1.6.4",
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",
@@ -505,7 +505,6 @@ export const messengerViewsStyles = `
505
505
  transform: translateY(-50%);
506
506
  }
507
507
 
508
- /* Search — back to normal style on light bg */
509
508
  .messenger-help-search-wrap {
510
509
  position: relative;
511
510
  width: 100%;
@@ -546,7 +545,6 @@ export const messengerViewsStyles = `
546
545
  color: var(--color-text-tertiary);
547
546
  }
548
547
 
549
- /* Body */
550
548
  .messenger-help-body {
551
549
  flex: 1;
552
550
  overflow-y: auto;
@@ -561,13 +559,11 @@ export const messengerViewsStyles = `
561
559
  padding: 0;
562
560
  }
563
561
 
564
- /* ── Collection item ─────────────────────────────── */
565
-
566
562
  .messenger-help-collection {
567
563
  display: flex;
568
564
  align-items: center;
569
565
  gap: var(--spacing-3);
570
- padding: var(--spacing-4) var(--spacing-5);
566
+ padding: var(--spacing-3) var(--spacing-5);
571
567
  cursor: pointer;
572
568
  transition: background var(--transition-base);
573
569
  border-bottom: 1px solid var(--color-border);
@@ -577,68 +573,63 @@ export const messengerViewsStyles = `
577
573
  background: var(--color-neutral-50);
578
574
  }
579
575
 
580
- /* Icon pill — tinted with primary colour */
581
576
  .messenger-help-collection-icon {
582
577
  flex-shrink: 0;
583
- width: 36px;
584
- height: 36px;
585
- border-radius: var(--radius-md);
586
- background: color-mix(in srgb, var(--color-primary) 10%, transparent);
587
- color: var(--color-primary);
578
+ width: 28px;
579
+ height: 28px;
588
580
  display: flex;
589
581
  align-items: center;
590
582
  justify-content: center;
583
+ color: var(--color-text-secondary);
591
584
  }
592
585
 
593
586
  .messenger-help-collection-icon svg,
594
587
  .messenger-help-collection-icon iconify-icon {
595
- width: 20px;
596
- height: 20px;
588
+ width: 18px;
589
+ height: 18px;
597
590
  display: block;
598
591
  }
599
592
 
600
- /* Content area */
601
593
  .messenger-help-collection-content {
602
594
  flex: 1;
603
595
  min-width: 0;
604
596
  }
605
597
 
606
598
  .messenger-help-collection-title {
607
- margin: 0 0 2px;
608
- font-size: var(--font-size-md);
609
- font-weight: var(--font-weight-bold);
599
+ font-size: var(--font-size-sm);
600
+ font-weight: var(--font-weight-medium);
610
601
  color: var(--color-text-primary);
611
602
  line-height: var(--line-height-snug);
603
+ white-space: nowrap;
604
+ overflow: hidden;
605
+ text-overflow: ellipsis;
612
606
  }
613
607
 
614
608
  .messenger-help-collection-desc {
615
- margin: 0 0 var(--spacing-2);
616
- font-size: var(--font-size-sm);
609
+ margin: 2px 0 var(--spacing-1);
610
+ font-size: var(--font-size-xs);
617
611
  color: var(--color-text-secondary);
618
612
  line-height: var(--line-height-normal);
619
- display: -webkit-box;
620
- -webkit-line-clamp: 2;
621
- -webkit-box-orient: vertical;
613
+ white-space: nowrap;
622
614
  overflow: hidden;
615
+ text-overflow: ellipsis;
623
616
  }
624
617
 
625
- /* Meta row: author avatar + article count */
626
618
  .messenger-help-collection-meta {
627
619
  display: flex;
628
620
  align-items: center;
629
621
  gap: var(--spacing-2);
622
+ margin-top: 2px;
630
623
  }
631
624
 
632
- /* Avatar — shared base */
633
625
  .messenger-help-collection-avatar {
634
- width: 18px;
635
- height: 18px;
626
+ width: 16px;
627
+ height: 16px;
636
628
  border-radius: var(--radius-full);
637
629
  flex-shrink: 0;
638
630
  object-fit: cover;
639
631
  }
640
632
 
641
- /* Initials fallback */
642
633
  .messenger-help-collection-avatar--initials {
643
634
  display: inline-flex;
644
635
  align-items: center;
@@ -649,18 +640,10 @@ export const messengerViewsStyles = `
649
640
  }
650
641
 
651
642
  .messenger-help-collection-count {
652
- font-size: var(--font-size-sm);
653
- color: var(--color-text-tertiary);
654
- }
655
-
656
- .messenger-help-collection-arrow {
643
+ font-size: var(--font-size-xs);
657
644
  color: var(--color-text-tertiary);
658
- flex-shrink: 0;
659
- margin-left: auto;
660
645
  }
661
646
 
662
- /* ── Footer (kept for optional use) ─────────────── */
663
-
664
647
  .messenger-help-footer {
665
648
  padding: var(--spacing-4) var(--spacing-5);
666
649
  border-top: 1px solid var(--color-border);
@@ -27,6 +27,7 @@ export class MessengerWidget extends BaseWidget {
27
27
  logoUrl: options.logoUrl || 'https://product7.io/p7logo.svg',
28
28
  teamName: options.teamName || 'Support',
29
29
  teamAvatars: options.teamAvatars || [],
30
+ greetingMessage: options.greetingMessage || 'Hi there 👋',
30
31
  welcomeMessage: options.welcomeMessage || 'How can we help?',
31
32
  enableHelp: options.enableHelp !== false,
32
33
  enableChangelog: options.enableChangelog !== false,
@@ -44,6 +45,7 @@ export class MessengerWidget extends BaseWidget {
44
45
  this.messengerState = new MessengerState({
45
46
  teamName: this.messengerOptions.teamName,
46
47
  teamAvatars: this.messengerOptions.teamAvatars,
48
+ greetingMessage: this.messengerOptions.greetingMessage,
47
49
  welcomeMessage: this.messengerOptions.welcomeMessage,
48
50
  enableHelp: this.messengerOptions.enableHelp,
49
51
  enableChangelog: this.messengerOptions.enableChangelog,
@@ -16,6 +16,7 @@ export class MessengerState {
16
16
 
17
17
  this.teamName = options.teamName || 'Support';
18
18
  this.teamAvatars = options.teamAvatars || [];
19
+ this.greetingMessage = options.greetingMessage || 'Hi there 👋';
19
20
  this.welcomeMessage = options.welcomeMessage || 'How can we help?';
20
21
 
21
22
  this.userContext = options.userContext || null;
@@ -4,9 +4,6 @@ export class HelpView {
4
4
  this.options = options;
5
5
  this.element = null;
6
6
  this._unsubscribe = null;
7
-
8
- // Configurable header colour — defaults to Product7 blue
9
- this._headerBg = `linear-gradient(180deg, #f0f4ff 0%, #ffffff 100%)`;
10
7
  }
11
8
 
12
9
  render() {
@@ -49,7 +46,6 @@ export class HelpView {
49
46
  />
50
47
  </div>
51
48
  </div>
52
-
53
49
  <div class="messenger-help-body">
54
50
  <div class="messenger-help-collections"></div>
55
51
  </div>
@@ -60,13 +56,11 @@ export class HelpView {
60
56
  }
61
57
 
62
58
  _updateCollectionsList() {
63
- const collectionsContainer = this.element.querySelector(
64
- '.messenger-help-collections'
65
- );
59
+ const container = this.element.querySelector('.messenger-help-collections');
66
60
  const collections = this.state.helpArticles || [];
67
61
  const searchQuery = (this.state.helpSearchQuery || '').toLowerCase();
68
62
 
69
- const filteredCollections = searchQuery
63
+ const filtered = searchQuery
70
64
  ? collections.filter(
71
65
  (c) =>
72
66
  c.title.toLowerCase().includes(searchQuery) ||
@@ -74,20 +68,15 @@ export class HelpView {
74
68
  )
75
69
  : collections;
76
70
 
77
- if (filteredCollections.length === 0) {
78
- collectionsContainer.innerHTML = this._renderEmptyState();
71
+ if (filtered.length === 0) {
72
+ container.innerHTML = this._renderEmptyState();
79
73
  return;
80
74
  }
81
75
 
82
- collectionsContainer.innerHTML = filteredCollections
83
- .map((collection) => this._renderCollectionItem(collection))
84
- .join('');
85
-
76
+ container.innerHTML = filtered.map((c) => this._renderCollectionItem(c)).join('');
86
77
  this._attachCollectionEvents();
87
78
  }
88
79
 
89
- // ─── Avatar helpers ──────────────────────────────────────────────────────────
90
-
91
80
  _avatarColors = [
92
81
  { bg: '#EF4444', text: '#FFFFFF' },
93
82
  { bg: '#F97316', text: '#FFFFFF' },
@@ -100,50 +89,35 @@ export class HelpView {
100
89
  ];
101
90
 
102
91
  _getAvatarColor(id) {
103
- const hash = id
104
- .split('')
105
- .reduce((acc, char) => acc + char.charCodeAt(0), 0);
92
+ const hash = id.split('').reduce((acc, char) => acc + char.charCodeAt(0), 0);
106
93
  return this._avatarColors[hash % this._avatarColors.length];
107
94
  }
108
95
 
109
96
  _getInitials(name) {
110
97
  if (!name) return 'A';
111
- return name
112
- .split(' ')
113
- .map((n) => n[0])
114
- .join('')
115
- .toUpperCase()
116
- .slice(0, 2);
98
+ return name.split(' ').map((n) => n[0]).join('').toUpperCase().slice(0, 2);
117
99
  }
118
100
 
119
101
  _renderAuthorAvatar(collection) {
120
102
  if (collection.author?.picture) {
121
- return `
122
- <img
123
- src="${collection.author.picture}"
124
- alt="${collection.author.name || ''}"
125
- class="messenger-help-collection-avatar"
126
- title="${collection.author.name || ''}"
127
- />
128
- `;
103
+ return `<img
104
+ src="${collection.author.picture}"
105
+ alt="${collection.author.name || ''}"
106
+ class="messenger-help-collection-avatar"
107
+ title="${collection.author.name || ''}"
108
+ />`;
129
109
  }
130
110
 
131
111
  const { bg, text } = this._getAvatarColor(collection.id);
132
- const initials = collection.author?.name
133
- ? this._getInitials(collection.author.name)
134
- : 'A';
112
+ const initials = collection.author?.name ? this._getInitials(collection.author.name) : 'A';
135
113
 
136
- return `
137
- <span
138
- class="messenger-help-collection-avatar messenger-help-collection-avatar--initials"
139
- style="background-color: ${bg}; color: ${text};"
140
- title="${collection.author?.name || 'Author'}"
141
- >${initials}</span>
142
- `;
114
+ return `<span
115
+ class="messenger-help-collection-avatar messenger-help-collection-avatar--initials"
116
+ style="background-color: ${bg}; color: ${text};"
117
+ title="${collection.author?.name || 'Author'}"
118
+ >${initials}</span>`;
143
119
  }
144
120
 
145
- // ─── Icon resolution ─────────────────────────────────────────────────────────
146
-
147
121
  _resolveCollectionIcon(icon) {
148
122
  if (!icon) return this._defaultCollectionIcon();
149
123
 
@@ -152,53 +126,40 @@ export class HelpView {
152
126
  }
153
127
 
154
128
  if (icon.startsWith('ph:')) {
155
- return `
156
- <span class="messenger-help-collection-icon">
157
- <iconify-icon icon="${icon}" width="20" height="20"></iconify-icon>
158
- </span>
159
- `;
129
+ return `<span class="messenger-help-collection-icon">
130
+ <iconify-icon icon="${icon}" width="18" height="18"></iconify-icon>
131
+ </span>`;
160
132
  }
161
133
 
162
134
  return this._defaultCollectionIcon();
163
135
  }
164
136
 
165
137
  _defaultCollectionIcon() {
166
- return `
167
- <span class="messenger-help-collection-icon">
168
- <iconify-icon icon="ph:book-open-duotone" width="20" height="20"></iconify-icon>
169
- </span>
170
- `;
138
+ return `<span class="messenger-help-collection-icon">
139
+ <iconify-icon icon="ph:book-open-duotone" width="18" height="18"></iconify-icon>
140
+ </span>`;
171
141
  }
172
142
 
173
- // ─── Rendering ───────────────────────────────────────────────────────────────
174
-
175
143
  _renderCollectionItem(collection) {
176
144
  const articleCount = collection.articleCount || 0;
177
- const iconHtml = this._resolveCollectionIcon(collection.icon);
178
- const avatarHtml = this._renderAuthorAvatar(collection);
179
145
 
180
146
  return `
181
147
  <div class="messenger-help-collection" data-collection-id="${collection.id}">
182
- ${iconHtml}
148
+ ${this._resolveCollectionIcon(collection.icon)}
183
149
  <div class="messenger-help-collection-content">
184
- <h3 class="messenger-help-collection-title">${collection.title}</h3>
150
+ <div class="messenger-help-collection-title">${collection.title}</div>
185
151
  ${collection.description ? `<p class="messenger-help-collection-desc">${collection.description}</p>` : ''}
186
152
  <div class="messenger-help-collection-meta">
187
- ${avatarHtml}
153
+ ${this._renderAuthorAvatar(collection)}
188
154
  <span class="messenger-help-collection-count">
189
155
  ${articleCount} ${articleCount === 1 ? 'article' : 'articles'}
190
156
  </span>
191
157
  </div>
192
158
  </div>
193
- <svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" fill="currentColor" viewBox="0 0 256 256" class="messenger-help-collection-arrow">
194
- <path d="M181.66,133.66l-80,80a8,8,0,0,1-11.32-11.32L164.69,128,90.34,53.66a8,8,0,0,1,11.32-11.32l80,80A8,8,0,0,1,181.66,133.66Z"></path>
195
- </svg>
196
159
  </div>
197
160
  `;
198
161
  }
199
162
 
200
- // ─── Empty states ────────────────────────────────────────────────────────────
201
-
202
163
  _renderEmptyState() {
203
164
  if (this.state.helpSearchQuery) {
204
165
  return `
@@ -223,18 +184,12 @@ export class HelpView {
223
184
  `;
224
185
  }
225
186
 
226
- // ─── Events ──────────────────────────────────────────────────────────────────
227
-
228
187
  _attachEvents() {
229
- this.element
230
- .querySelector('.messenger-help-close-btn')
231
- .addEventListener('click', () => {
232
- this.state.setOpen(false);
233
- });
188
+ this.element.querySelector('.messenger-help-close-btn').addEventListener('click', () => {
189
+ this.state.setOpen(false);
190
+ });
234
191
 
235
- const searchInput = this.element.querySelector(
236
- '.messenger-help-search-input'
237
- );
192
+ const searchInput = this.element.querySelector('.messenger-help-search-input');
238
193
  let searchTimeout;
239
194
  searchInput.addEventListener('input', (e) => {
240
195
  clearTimeout(searchTimeout);
@@ -247,31 +202,22 @@ export class HelpView {
247
202
  }
248
203
 
249
204
  _attachCollectionEvents() {
250
- this.element
251
- .querySelectorAll('.messenger-help-collection')
252
- .forEach((item) => {
253
- item.addEventListener('click', () => {
254
- const collectionId = item.dataset.collectionId;
255
- const collection = this.state.helpArticles.find(
256
- (c) => c.id === collectionId
257
- );
258
- if (collection?.url) {
259
- window.open(collection.url, '_blank');
260
- } else if (this.options.onArticleClick) {
261
- this.options.onArticleClick(collection);
262
- }
263
- });
205
+ this.element.querySelectorAll('.messenger-help-collection').forEach((item) => {
206
+ item.addEventListener('click', () => {
207
+ const collection = this.state.helpArticles.find(
208
+ (c) => c.id === item.dataset.collectionId
209
+ );
210
+ if (collection?.url) {
211
+ window.open(collection.url, '_blank');
212
+ } else if (this.options.onArticleClick) {
213
+ this.options.onArticleClick(collection);
214
+ }
264
215
  });
216
+ });
265
217
  }
266
218
 
267
- // ─── Lifecycle ───────────────────────────────────────────────────────────────
268
-
269
219
  destroy() {
270
- if (this._unsubscribe) {
271
- this._unsubscribe();
272
- }
273
- if (this.element && this.element.parentNode) {
274
- this.element.parentNode.removeChild(this.element);
275
- }
220
+ if (this._unsubscribe) this._unsubscribe();
221
+ if (this.element?.parentNode) this.element.parentNode.removeChild(this.element);
276
222
  }
277
- }
223
+ }
@@ -44,7 +44,7 @@ export class HomeView {
44
44
  </button>
45
45
  </div>
46
46
  <div class="messenger-home-welcome">
47
- <span class="messenger-home-greeting">Hi there 👋</span>
47
+ <span class="messenger-home-greeting">${this.state.greetingMessage}</span>
48
48
  <span class="messenger-home-question">${this.state.welcomeMessage}</span>
49
49
  </div>
50
50
  </div>
package/types/index.d.ts CHANGED
@@ -213,6 +213,7 @@ declare module '@product7/feedback-sdk' {
213
213
  theme?: 'light' | 'dark';
214
214
  teamName?: string;
215
215
  teamAvatars?: string[];
216
+ greetingMessage?: string;
216
217
  welcomeMessage?: string;
217
218
  enableHelp?: boolean;
218
219
  enableChangelog?: boolean;