@product7/product7-js 0.1.0

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.
Files changed (58) hide show
  1. package/README.md +1025 -0
  2. package/dist/README.md +1025 -0
  3. package/dist/product7-js.js +14658 -0
  4. package/dist/product7-js.js.map +1 -0
  5. package/dist/product7-js.min.js +2 -0
  6. package/dist/product7-js.min.js.map +1 -0
  7. package/package.json +114 -0
  8. package/src/api/mock-data/index.js +360 -0
  9. package/src/api/services/ChangelogService.js +28 -0
  10. package/src/api/services/FeedbackService.js +44 -0
  11. package/src/api/services/HelpService.js +50 -0
  12. package/src/api/services/MessengerService.js +279 -0
  13. package/src/api/services/SurveyService.js +127 -0
  14. package/src/api/utils/helpers.js +30 -0
  15. package/src/core/APIService.js +303 -0
  16. package/src/core/BaseAPIService.js +298 -0
  17. package/src/core/EventBus.js +54 -0
  18. package/src/core/Product7.js +812 -0
  19. package/src/core/WebSocketService.js +275 -0
  20. package/src/docs/api.md +226 -0
  21. package/src/docs/example.md +461 -0
  22. package/src/docs/framework-integrations.md +714 -0
  23. package/src/docs/installation.md +281 -0
  24. package/src/index.js +894 -0
  25. package/src/styles/base.js +50 -0
  26. package/src/styles/changelog.js +665 -0
  27. package/src/styles/components.js +553 -0
  28. package/src/styles/design-tokens.js +124 -0
  29. package/src/styles/feedback.js +325 -0
  30. package/src/styles/messenger-components.js +632 -0
  31. package/src/styles/messenger-core.js +233 -0
  32. package/src/styles/messenger-features.js +169 -0
  33. package/src/styles/messenger-views.js +877 -0
  34. package/src/styles/messenger.js +17 -0
  35. package/src/styles/messengerCustomStyles.js +114 -0
  36. package/src/styles/styles.js +26 -0
  37. package/src/styles/survey.js +894 -0
  38. package/src/utils/errors.js +142 -0
  39. package/src/utils/helpers.js +219 -0
  40. package/src/widgets/BaseWidget.js +548 -0
  41. package/src/widgets/ButtonWidget.js +104 -0
  42. package/src/widgets/ChangelogWidget.js +615 -0
  43. package/src/widgets/InlineWidget.js +148 -0
  44. package/src/widgets/MessengerWidget.js +979 -0
  45. package/src/widgets/SurveyWidget.js +1325 -0
  46. package/src/widgets/TabWidget.js +45 -0
  47. package/src/widgets/WidgetFactory.js +70 -0
  48. package/src/widgets/messenger/MessengerState.js +323 -0
  49. package/src/widgets/messenger/components/MessengerLauncher.js +124 -0
  50. package/src/widgets/messenger/components/MessengerPanel.js +111 -0
  51. package/src/widgets/messenger/components/NavigationTabs.js +130 -0
  52. package/src/widgets/messenger/views/ChangelogView.js +167 -0
  53. package/src/widgets/messenger/views/ChatView.js +592 -0
  54. package/src/widgets/messenger/views/ConversationsView.js +244 -0
  55. package/src/widgets/messenger/views/HelpView.js +239 -0
  56. package/src/widgets/messenger/views/HomeView.js +300 -0
  57. package/src/widgets/messenger/views/PreChatFormView.js +109 -0
  58. package/types/index.d.ts +341 -0
@@ -0,0 +1,615 @@
1
+ import { BaseWidget } from './BaseWidget.js';
2
+
3
+ export class ChangelogWidget extends BaseWidget {
4
+ constructor(options) {
5
+ super({ ...options, type: 'changelog' });
6
+ this.changelogs = [];
7
+ this.isLoading = false;
8
+ this.modalElement = null;
9
+ this.sidebarElement = null;
10
+ this.listModalBackdropElement = null;
11
+ this.currentIndex = 0;
12
+ }
13
+
14
+ _hasTrigger() {
15
+ return this.options.trigger === true || this.options.trigger === undefined;
16
+ }
17
+
18
+ _render() {
19
+ if (!this._hasTrigger()) {
20
+ const placeholder = document.createElement('div');
21
+ placeholder.style.display = 'none';
22
+ return placeholder;
23
+ }
24
+
25
+ const trigger = document.createElement('div');
26
+ trigger.className = `changelog-widget position-${this.options.position} changelog-theme-${this.options.theme || 'light'}`;
27
+ trigger.innerHTML = `
28
+ <button class="changelog-trigger-btn" type="button" aria-label="View Updates">
29
+ <svg class="changelog-icon" width="18" height="18" viewBox="0 0 24 24" fill="currentColor">
30
+ <path d="M5.8 21L7.4 14L2 9.2L9.2 8.6L12 2L14.8 8.6L22 9.2L16.6 14L18.2 21L12 17.3L5.8 21Z"/>
31
+ </svg>
32
+ <span class="changelog-text">${this.options.triggerText || "What's New"}</span>
33
+ <span class="changelog-confetti-emoji">🎉</span>
34
+ ${this.options.showBadge ? '<span class="changelog-badge"></span>' : ''}
35
+ </button>
36
+ `;
37
+
38
+ if (this.options.customStyles) {
39
+ Object.assign(trigger.style, this.options.customStyles);
40
+ }
41
+
42
+ return trigger;
43
+ }
44
+
45
+ _attachEvents() {
46
+ if (!this._hasTrigger()) return;
47
+
48
+ const button = this.element.querySelector('.changelog-trigger-btn');
49
+ button.addEventListener('click', () => {
50
+ this.openSidebar();
51
+ });
52
+ }
53
+
54
+ async openModal() {
55
+ if (this.modalElement) return;
56
+
57
+ this.state.isOpen = true;
58
+ this._createModal();
59
+
60
+ if (this.changelogs.length === 0) {
61
+ await this._loadChangelogs();
62
+ }
63
+
64
+ this.currentIndex = 0;
65
+ this._renderCurrentChangelog();
66
+
67
+ document.body.style.overflow = 'hidden';
68
+
69
+ requestAnimationFrame(() => {
70
+ if (this.modalElement) {
71
+ this.modalElement.classList.add('open');
72
+ }
73
+ if (this.backdropElement) {
74
+ this.backdropElement.classList.add('show');
75
+ }
76
+ });
77
+ }
78
+
79
+ closeModal() {
80
+ document.body.style.overflow = '';
81
+
82
+ if (this.modalElement) {
83
+ this.modalElement.classList.remove('open');
84
+ }
85
+ if (this.backdropElement) {
86
+ this.backdropElement.classList.remove('show');
87
+ }
88
+
89
+ setTimeout(() => {
90
+ this.state.isOpen = false;
91
+ if (this.modalElement && this.modalElement.parentNode) {
92
+ this.modalElement.parentNode.removeChild(this.modalElement);
93
+ this.modalElement = null;
94
+ }
95
+ if (this.backdropElement && this.backdropElement.parentNode) {
96
+ this.backdropElement.parentNode.removeChild(this.backdropElement);
97
+ this.backdropElement = null;
98
+ }
99
+ }, 300);
100
+ }
101
+
102
+ _createModal() {
103
+ if (this.options.showBackdrop !== false) {
104
+ this.backdropElement = document.createElement('div');
105
+ this.backdropElement.className = `changelog-modal-backdrop changelog-theme-${this.options.theme || 'light'}`;
106
+ document.body.appendChild(this.backdropElement);
107
+ this.backdropElement.addEventListener('click', () => this.closeModal());
108
+ }
109
+
110
+ this.modalElement = document.createElement('div');
111
+ this.modalElement.className = `changelog-modal changelog-theme-${this.options.theme || 'light'}`;
112
+ this.modalElement.innerHTML = `
113
+ <div class="changelog-modal-container">
114
+ <button class="changelog-modal-close" type="button" aria-label="Close">
115
+ <iconify-icon icon="ph:x-duotone" width="18" height="18"></iconify-icon>
116
+ </button>
117
+ <div class="changelog-modal-content">
118
+ <div class="changelog-loading">
119
+ <div class="sdk-spinner"></div>
120
+ </div>
121
+ </div>
122
+ </div>
123
+ `;
124
+
125
+ document.body.appendChild(this.modalElement);
126
+
127
+ this.modalElement
128
+ .querySelector('.changelog-modal-container')
129
+ .addEventListener('click', (e) => e.stopPropagation());
130
+
131
+ this.modalElement
132
+ .querySelector('.changelog-modal-close')
133
+ .addEventListener('click', () => this.closeModal());
134
+
135
+ this._escapeHandler = (e) => {
136
+ if (e.key === 'Escape') this.closeModal();
137
+ };
138
+ document.addEventListener('keydown', this._escapeHandler);
139
+ }
140
+
141
+ async openSidebar() {
142
+ if (this.listModalElement) return;
143
+
144
+ if (this.modalElement) {
145
+ this.closeModal();
146
+ await new Promise((resolve) => setTimeout(resolve, 350));
147
+ }
148
+
149
+ this.state.isOpen = true;
150
+ this._createListModal();
151
+
152
+ if (this.changelogs.length === 0) {
153
+ await this._loadChangelogs();
154
+ }
155
+
156
+ this._renderChangelogList();
157
+
158
+ document.body.style.overflow = 'hidden';
159
+
160
+ requestAnimationFrame(() => {
161
+ if (this.listModalElement) {
162
+ this.listModalElement.classList.add('open');
163
+ this._showConfetti();
164
+ }
165
+ if (this.listModalBackdropElement) {
166
+ this.listModalBackdropElement.classList.add('show');
167
+ }
168
+ });
169
+ }
170
+
171
+ _showConfetti() {
172
+ const colors = [
173
+ '#FF6B6B',
174
+ '#4ECDC4',
175
+ '#FFE66D',
176
+ '#95E1D3',
177
+ '#F38181',
178
+ '#AA96DA',
179
+ '#FCBAD3',
180
+ '#A8D8EA',
181
+ ];
182
+ const confettiCount = 50;
183
+ const container = document.createElement('div');
184
+ container.className = 'changelog-confetti-container';
185
+ document.body.appendChild(container);
186
+
187
+ for (let i = 0; i < confettiCount; i++) {
188
+ const confetti = document.createElement('div');
189
+ confetti.className = 'changelog-confetti';
190
+ confetti.style.left = Math.random() * 100 + '%';
191
+ confetti.style.backgroundColor =
192
+ colors[Math.floor(Math.random() * colors.length)];
193
+ confetti.style.animationDelay = Math.random() * 0.5 + 's';
194
+ confetti.style.animationDuration = Math.random() * 1 + 1.5 + 's';
195
+
196
+ const shapes = ['circle', 'square', 'rectangle'];
197
+ const shape = shapes[Math.floor(Math.random() * shapes.length)];
198
+ if (shape === 'circle') {
199
+ confetti.style.borderRadius = '50%';
200
+ confetti.style.width = Math.random() * 8 + 4 + 'px';
201
+ confetti.style.height = confetti.style.width;
202
+ } else if (shape === 'rectangle') {
203
+ confetti.style.width = Math.random() * 4 + 3 + 'px';
204
+ confetti.style.height = Math.random() * 10 + 8 + 'px';
205
+ } else {
206
+ confetti.style.width = Math.random() * 8 + 4 + 'px';
207
+ confetti.style.height = confetti.style.width;
208
+ }
209
+
210
+ container.appendChild(confetti);
211
+ }
212
+
213
+ setTimeout(() => {
214
+ if (container.parentNode) container.parentNode.removeChild(container);
215
+ }, 2500);
216
+ }
217
+
218
+ closeSidebar() {
219
+ document.body.style.overflow = '';
220
+
221
+ if (this.listModalElement) {
222
+ this.listModalElement.classList.remove('open');
223
+ }
224
+ if (this.listModalBackdropElement) {
225
+ this.listModalBackdropElement.classList.remove('show');
226
+ }
227
+
228
+ setTimeout(() => {
229
+ this.state.isOpen = false;
230
+ if (this.listModalElement && this.listModalElement.parentNode) {
231
+ this.listModalElement.parentNode.removeChild(this.listModalElement);
232
+ this.listModalElement = null;
233
+ }
234
+ if (
235
+ this.listModalBackdropElement &&
236
+ this.listModalBackdropElement.parentNode
237
+ ) {
238
+ this.listModalBackdropElement.parentNode.removeChild(
239
+ this.listModalBackdropElement
240
+ );
241
+ this.listModalBackdropElement = null;
242
+ }
243
+ if (this._listModalEscapeHandler) {
244
+ document.removeEventListener('keydown', this._listModalEscapeHandler);
245
+ }
246
+ }, 300);
247
+ }
248
+
249
+ _createListModal() {
250
+ if (this.options.showBackdrop !== false) {
251
+ this.listModalBackdropElement = document.createElement('div');
252
+ this.listModalBackdropElement.className = `changelog-list-modal-backdrop changelog-theme-${this.options.theme || 'light'}`;
253
+ document.body.appendChild(this.listModalBackdropElement);
254
+ this.listModalBackdropElement.addEventListener('click', () =>
255
+ this.closeSidebar()
256
+ );
257
+ }
258
+
259
+ this.listModalElement = document.createElement('div');
260
+ this.listModalElement.className = `changelog-list-modal changelog-theme-${this.options.theme || 'light'}`;
261
+ this.listModalElement.innerHTML = `
262
+ <div class="changelog-list-modal-container">
263
+ <div class="changelog-list-modal-header">
264
+ <h2>${this.options.title || "What's New"} 🎉</h2>
265
+ <button class="changelog-list-modal-close" type="button" aria-label="Close">
266
+ <iconify-icon icon="ph:x-duotone" width="18" height="18"></iconify-icon>
267
+ </button>
268
+ </div>
269
+ <div class="changelog-list-modal-body">
270
+ <div class="changelog-loading">
271
+ <div class="sdk-spinner"></div>
272
+ </div>
273
+ </div>
274
+ </div>
275
+ `;
276
+
277
+ document.body.appendChild(this.listModalElement);
278
+
279
+ this.listModalElement
280
+ .querySelector('.changelog-list-modal-container')
281
+ .addEventListener('click', (e) => e.stopPropagation());
282
+
283
+ this.listModalElement
284
+ .querySelector('.changelog-list-modal-close')
285
+ .addEventListener('click', () => this.closeSidebar());
286
+
287
+ this._listModalEscapeHandler = (e) => {
288
+ if (e.key === 'Escape') this.closeSidebar();
289
+ };
290
+ document.addEventListener('keydown', this._listModalEscapeHandler);
291
+ }
292
+
293
+ _renderChangelogList() {
294
+ const body = this.listModalElement.querySelector(
295
+ '.changelog-list-modal-body'
296
+ );
297
+
298
+ if (this.isLoading) return;
299
+
300
+ if (this.changelogs.length === 0) {
301
+ body.innerHTML = `
302
+ <div class="changelog-empty">
303
+ <svg width="48" height="48" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.5">
304
+ <path d="M14.5 2H6a2 2 0 0 0-2 2v16a2 2 0 0 0 2 2h12a2 2 0 0 0 2-2V7.5L14.5 2z"/>
305
+ <polyline points="14,2 14,8 20,8"/>
306
+ </svg>
307
+ <p>No updates yet</p>
308
+ </div>
309
+ `;
310
+ return;
311
+ }
312
+
313
+ body.innerHTML = `
314
+ <div class="changelog-list">
315
+ ${this.changelogs.map((changelog, index) => this._renderChangelogListItem(changelog, index)).join('')}
316
+ </div>
317
+ `;
318
+
319
+ body.querySelectorAll('.changelog-list-item').forEach((item, index) => {
320
+ item.addEventListener('click', () => {
321
+ this._handleViewUpdate(this.changelogs[index]);
322
+ });
323
+ });
324
+ }
325
+
326
+ _renderChangelogListItem(changelog, index) {
327
+ const hasImage = changelog.cover_image || changelog.image;
328
+ const imageUrl = changelog.cover_image || changelog.image;
329
+ const date = changelog.published_at
330
+ ? this._formatDate(changelog.published_at)
331
+ : '';
332
+ const description = this._truncateDescription(
333
+ changelog.excerpt || changelog.description,
334
+ 100
335
+ );
336
+ const labelsHTML =
337
+ changelog.labels && changelog.labels.length > 0
338
+ ? `<div class="changelog-list-item-labels">
339
+ ${changelog.labels
340
+ .map(
341
+ (label) =>
342
+ `<span class="changelog-label" style="background-color: ${label.color || '#E5E7EB'}; color: ${this._getContrastColor(label.color || '#E5E7EB')}">${label.name}</span>`
343
+ )
344
+ .join('')}
345
+ </div>`
346
+ : '';
347
+
348
+ return `
349
+ <div class="changelog-list-item" data-index="${index}">
350
+ <div class="changelog-list-item-content">
351
+ <div class="changelog-list-item-meta">
352
+ ${date ? `<span class="changelog-list-item-date">${date}</span>` : ''}
353
+ ${labelsHTML}
354
+ </div>
355
+ <h3 class="changelog-list-item-title">${changelog.title}</h3>
356
+ ${description ? `<p class="changelog-list-item-description">${description}</p>` : ''}
357
+ </div>
358
+ ${hasImage ? `<div class="changelog-list-item-image"><img src="${imageUrl}" alt="${changelog.title}" loading="lazy" /></div>` : ''}
359
+ <iconify-icon icon="ph:caret-right" class="changelog-list-item-arrow" width="16" height="16"></iconify-icon>
360
+ </div>
361
+ `;
362
+ }
363
+
364
+ async _loadChangelogs() {
365
+ this.isLoading = true;
366
+
367
+ try {
368
+ const result = await this.apiService.getChangelogs();
369
+ this.changelogs = result.data || [];
370
+ this.sdk.eventBus.emit('changelog:loaded', {
371
+ changelogs: this.changelogs,
372
+ });
373
+ } catch (error) {
374
+ this.changelogs = [];
375
+ this.sdk.eventBus.emit('changelog:error', { error });
376
+ } finally {
377
+ this.isLoading = false;
378
+ }
379
+ }
380
+
381
+ _renderCurrentChangelog() {
382
+ const content = this.modalElement.querySelector('.changelog-modal-content');
383
+
384
+ if (this.isLoading) return;
385
+
386
+ if (this.changelogs.length === 0) {
387
+ content.innerHTML = `
388
+ <div class="changelog-empty">
389
+ <svg width="48" height="48" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.5">
390
+ <path d="M14.5 2H6a2 2 0 0 0-2 2v16a2 2 0 0 0 2 2h12a2 2 0 0 0 2-2V7.5L14.5 2z"/>
391
+ <polyline points="14,2 14,8 20,8"/>
392
+ </svg>
393
+ <p>No updates yet</p>
394
+ </div>
395
+ `;
396
+ return;
397
+ }
398
+
399
+ const changelog = this.changelogs[this.currentIndex];
400
+ const hasImage = changelog.cover_image || changelog.image;
401
+ const imageUrl = changelog.cover_image || changelog.image;
402
+ const hasMultiple = this.changelogs.length > 1;
403
+ const description = this._truncateDescription(
404
+ changelog.excerpt || changelog.description,
405
+ 160
406
+ );
407
+
408
+ content.innerHTML = `
409
+ <div class="changelog-popup-item">
410
+ ${
411
+ hasImage
412
+ ? `
413
+ <div class="changelog-popup-image">
414
+ <img src="${imageUrl}" alt="${changelog.title}" loading="lazy" />
415
+ </div>
416
+ `
417
+ : ''
418
+ }
419
+ <div class="changelog-popup-body">
420
+ <h2 class="changelog-popup-title">${changelog.title}</h2>
421
+ ${description ? `<p class="changelog-popup-description">${description}</p>` : ''}
422
+ <button class="changelog-popup-btn" type="button">
423
+ ${this.options.viewButtonText || 'View Update'}
424
+ </button>
425
+ </div>
426
+ <div class="changelog-popup-footer">
427
+ ${
428
+ hasMultiple
429
+ ? `
430
+ <div class="changelog-popup-dots">
431
+ ${this.changelogs
432
+ .map(
433
+ (_, i) => `
434
+ <span class="changelog-dot ${i === this.currentIndex ? 'active' : ''}" data-index="${i}"></span>
435
+ `
436
+ )
437
+ .join('')}
438
+ </div>
439
+ `
440
+ : ''
441
+ }
442
+ <button class="changelog-view-all-btn" type="button">
443
+ View all updates
444
+ <iconify-icon icon="ph:arrow-right" width="16" height="16"></iconify-icon>
445
+ </button>
446
+ </div>
447
+ </div>
448
+ `;
449
+
450
+ content
451
+ .querySelector('.changelog-popup-btn')
452
+ .addEventListener('click', () => {
453
+ this._handleViewUpdate(changelog);
454
+ });
455
+
456
+ content
457
+ .querySelector('.changelog-view-all-btn')
458
+ .addEventListener('click', () => {
459
+ this.closeModal();
460
+ setTimeout(() => this.openSidebar(), 350);
461
+ });
462
+
463
+ if (hasMultiple) {
464
+ content.querySelectorAll('.changelog-dot').forEach((dot) => {
465
+ dot.addEventListener('click', (e) => {
466
+ this.currentIndex = parseInt(e.target.dataset.index, 10);
467
+ this._renderCurrentChangelog();
468
+ });
469
+ });
470
+ }
471
+ }
472
+
473
+ _handleViewUpdate(changelog) {
474
+ this.sdk.eventBus.emit('changelog:view', { changelog });
475
+
476
+ const changelogBase = (this.options.changelogBaseUrl || '').replace(
477
+ /\/$/,
478
+ ''
479
+ );
480
+ const url =
481
+ changelog.url ||
482
+ (changelog.slug && changelogBase
483
+ ? `${changelogBase}/${changelog.slug}`
484
+ : null) ||
485
+ changelogBase ||
486
+ null;
487
+
488
+ if (url) {
489
+ if (this.options.openInNewTab !== false) {
490
+ window.open(url, '_blank', 'noopener,noreferrer');
491
+ } else {
492
+ window.location.href = url;
493
+ }
494
+ }
495
+
496
+ if (typeof this.options.onViewUpdate === 'function') {
497
+ this.options.onViewUpdate(changelog);
498
+ }
499
+ }
500
+
501
+ _stripHtml(html) {
502
+ const tmp = document.createElement('div');
503
+ tmp.innerHTML = html;
504
+ return (tmp.textContent || tmp.innerText || '').trim();
505
+ }
506
+
507
+ _truncateDescription(html, maxLength = 120) {
508
+ if (!html) return '';
509
+ const plain = this._stripHtml(html);
510
+ if (plain.length <= maxLength) return plain;
511
+ return plain.substring(0, maxLength).trimEnd() + '...';
512
+ }
513
+
514
+ _formatDate(dateString) {
515
+ const date = new Date(dateString);
516
+ return date.toLocaleDateString('en-US', {
517
+ year: 'numeric',
518
+ month: 'short',
519
+ day: 'numeric',
520
+ });
521
+ }
522
+
523
+ _getContrastColor(hexColor) {
524
+ const hex = hexColor.replace('#', '');
525
+ const r = parseInt(hex.substr(0, 2), 16);
526
+ const g = parseInt(hex.substr(2, 2), 16);
527
+ const b = parseInt(hex.substr(4, 2), 16);
528
+ const luminance = (0.299 * r + 0.587 * g + 0.114 * b) / 255;
529
+ return luminance > 0.5 ? '#1F2937' : '#FFFFFF';
530
+ }
531
+
532
+ hideBadge() {
533
+ const badge = this.element?.querySelector('.changelog-badge');
534
+ if (badge) badge.style.display = 'none';
535
+ }
536
+
537
+ showBadge() {
538
+ const badge = this.element?.querySelector('.changelog-badge');
539
+ if (badge) badge.style.display = 'block';
540
+ }
541
+
542
+ nextChangelog() {
543
+ if (this.currentIndex < this.changelogs.length - 1) {
544
+ this.currentIndex++;
545
+ this._renderCurrentChangelog();
546
+ }
547
+ }
548
+
549
+ prevChangelog() {
550
+ if (this.currentIndex > 0) {
551
+ this.currentIndex--;
552
+ this._renderCurrentChangelog();
553
+ }
554
+ }
555
+
556
+ async refresh() {
557
+ this.changelogs = [];
558
+ await this._loadChangelogs();
559
+ if (this.modalElement) {
560
+ this.currentIndex = 0;
561
+ this._renderCurrentChangelog();
562
+ }
563
+ if (this.listModalElement) {
564
+ this._renderChangelogList();
565
+ }
566
+ }
567
+
568
+ open() {
569
+ this.openSidebar();
570
+ return this;
571
+ }
572
+
573
+ close() {
574
+ this.closeSidebar();
575
+ return this;
576
+ }
577
+
578
+ toggle() {
579
+ if (this.state.isOpen) {
580
+ this.closeSidebar();
581
+ } else {
582
+ this.openSidebar();
583
+ }
584
+ return this;
585
+ }
586
+
587
+ mount(container) {
588
+ super.mount(container);
589
+
590
+ // Bind to a custom trigger element if provided
591
+ if (this.options.trigger && this.options.trigger !== true) {
592
+ const triggerEl =
593
+ typeof this.options.trigger === 'string'
594
+ ? document.querySelector(this.options.trigger)
595
+ : this.options.trigger instanceof Element
596
+ ? this.options.trigger
597
+ : null;
598
+ if (triggerEl) {
599
+ triggerEl.addEventListener('click', () => this.open());
600
+ }
601
+ }
602
+ }
603
+
604
+ destroy() {
605
+ if (this._escapeHandler) {
606
+ document.removeEventListener('keydown', this._escapeHandler);
607
+ }
608
+ if (this._listModalEscapeHandler) {
609
+ document.removeEventListener('keydown', this._listModalEscapeHandler);
610
+ }
611
+ this.closeModal();
612
+ this.closeSidebar();
613
+ super.destroy();
614
+ }
615
+ }