releasebird-javascript-sdk 1.0.73 → 1.0.76

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.
@@ -0,0 +1,268 @@
1
+ // API is defined globally via webpack.DefinePlugin
2
+ /* global API */
3
+
4
+ export default class ReleasebirdFormViewer {
5
+
6
+ static showForm(formData, formId, chatId, apiKey, iframeRef) {
7
+ // Create modal overlay
8
+ const overlay = document.createElement('div');
9
+ overlay.id = 'rbirdFormModal';
10
+ overlay.className = 'rbird-form-modal-overlay';
11
+
12
+ // Create modal container
13
+ const modal = document.createElement('div');
14
+ modal.className = 'rbird-form-modal';
15
+
16
+ // Create form header
17
+ const header = document.createElement('div');
18
+ header.className = 'rbird-form-modal-header';
19
+
20
+ const title = document.createElement('h2');
21
+ title.className = 'rbird-form-modal-title';
22
+ title.textContent = formData.title || 'Form';
23
+
24
+ const closeBtn = document.createElement('button');
25
+ closeBtn.className = 'rbird-form-modal-close';
26
+ closeBtn.innerHTML = '×';
27
+ closeBtn.onclick = () => this.closeForm();
28
+
29
+ header.appendChild(title);
30
+ header.appendChild(closeBtn);
31
+
32
+ // Create form content
33
+ const content = document.createElement('div');
34
+ content.className = 'rbird-form-modal-content';
35
+
36
+ const formElement = document.createElement('form');
37
+ formElement.className = 'rbird-form-element';
38
+
39
+ // Render form fields
40
+ if (formData.fields && formData.fields.length > 0) {
41
+ formData.fields.forEach((field) => {
42
+ const fieldWrapper = this.createFormField(field, formData.theme);
43
+ formElement.appendChild(fieldWrapper);
44
+ });
45
+ }
46
+
47
+ // Submit button
48
+ const submitBtn = document.createElement('button');
49
+ submitBtn.type = 'submit';
50
+ submitBtn.className = 'rbird-form-submit-btn';
51
+ if (formData.theme?.primaryColor) {
52
+ submitBtn.style.backgroundColor = formData.theme.primaryColor;
53
+ }
54
+ submitBtn.textContent = formData.submitButtonText || 'Send';
55
+
56
+ formElement.appendChild(submitBtn);
57
+
58
+ formElement.onsubmit = async (e) => {
59
+ e.preventDefault();
60
+ submitBtn.disabled = true;
61
+ submitBtn.textContent = '...';
62
+
63
+ const formDataObj = new FormData(formElement);
64
+ const data = {};
65
+ formDataObj.forEach((value, key) => {
66
+ // Handle checkbox groups
67
+ if (data[key]) {
68
+ if (Array.isArray(data[key])) {
69
+ data[key].push(value);
70
+ } else {
71
+ data[key] = [data[key], value];
72
+ }
73
+ } else {
74
+ data[key] = value;
75
+ }
76
+ });
77
+
78
+ try {
79
+ const response = await fetch(`${API}/ewidget/forms/${formId}/submit`, {
80
+ method: 'POST',
81
+ headers: {
82
+ 'Content-Type': 'application/json',
83
+ 'apiKey': apiKey,
84
+ },
85
+ body: JSON.stringify({
86
+ data,
87
+ chatId: chatId
88
+ })
89
+ });
90
+
91
+ if (response.ok) {
92
+ this.closeForm();
93
+ // Notify iframe that form was submitted
94
+ if (iframeRef) {
95
+ iframeRef.contentWindow?.postMessage({
96
+ type: 'formSubmitted',
97
+ formId: formId
98
+ }, '*');
99
+ }
100
+ } else {
101
+ throw new Error('Submit failed');
102
+ }
103
+ } catch (error) {
104
+ console.error('Error submitting form:', error);
105
+ submitBtn.disabled = false;
106
+ submitBtn.textContent = formData.submitButtonText || 'Send';
107
+ }
108
+ };
109
+
110
+ content.appendChild(formElement);
111
+ modal.appendChild(header);
112
+ modal.appendChild(content);
113
+ overlay.appendChild(modal);
114
+
115
+ // Close on overlay click
116
+ overlay.onclick = (e) => {
117
+ if (e.target === overlay) {
118
+ this.closeForm();
119
+ }
120
+ };
121
+
122
+ // Close on Escape key
123
+ const escHandler = (e) => {
124
+ if (e.key === 'Escape') {
125
+ this.closeForm();
126
+ document.removeEventListener('keydown', escHandler);
127
+ }
128
+ };
129
+ document.addEventListener('keydown', escHandler);
130
+
131
+ document.body.appendChild(overlay);
132
+ document.body.style.overflow = 'hidden';
133
+ }
134
+
135
+ static closeForm() {
136
+ const modal = document.getElementById('rbirdFormModal');
137
+ if (modal) {
138
+ document.body.removeChild(modal);
139
+ document.body.style.overflow = '';
140
+ }
141
+ }
142
+
143
+ static createFormField(field, theme) {
144
+ const wrapper = document.createElement('div');
145
+ wrapper.className = 'rbird-form-field';
146
+
147
+ // Label
148
+ if (field.label) {
149
+ const label = document.createElement('label');
150
+ label.className = 'rbird-form-label';
151
+ label.textContent = field.label;
152
+ if (field.required) {
153
+ const asterisk = document.createElement('span');
154
+ asterisk.className = 'rbird-form-required';
155
+ asterisk.textContent = ' *';
156
+ label.appendChild(asterisk);
157
+ }
158
+ wrapper.appendChild(label);
159
+ }
160
+
161
+ const fieldId = field.id || field.label || 'field';
162
+
163
+ switch (field.type) {
164
+ case 'TEXT':
165
+ case 'EMAIL':
166
+ case 'PHONE':
167
+ case 'NUMBER':
168
+ const input = document.createElement('input');
169
+ input.type = field.type === 'EMAIL' ? 'email' : field.type === 'NUMBER' ? 'number' : 'text';
170
+ input.name = fieldId;
171
+ input.required = field.required || false;
172
+ input.placeholder = field.placeholder || '';
173
+ input.className = 'rbird-form-input';
174
+ wrapper.appendChild(input);
175
+ break;
176
+
177
+ case 'TEXTAREA':
178
+ const textarea = document.createElement('textarea');
179
+ textarea.name = fieldId;
180
+ textarea.required = field.required || false;
181
+ textarea.placeholder = field.placeholder || '';
182
+ textarea.rows = 4;
183
+ textarea.className = 'rbird-form-input rbird-form-textarea';
184
+ wrapper.appendChild(textarea);
185
+ break;
186
+
187
+ case 'DROPDOWN':
188
+ case 'SELECT':
189
+ const select = document.createElement('select');
190
+ select.name = fieldId;
191
+ select.required = field.required || false;
192
+ select.className = 'rbird-form-input rbird-form-select';
193
+
194
+ const defaultOption = document.createElement('option');
195
+ defaultOption.value = '';
196
+ defaultOption.textContent = field.placeholder || '-- Select --';
197
+ select.appendChild(defaultOption);
198
+
199
+ (field.options || []).forEach((opt) => {
200
+ const option = document.createElement('option');
201
+ option.value = opt;
202
+ option.textContent = opt;
203
+ select.appendChild(option);
204
+ });
205
+ wrapper.appendChild(select);
206
+ break;
207
+
208
+ case 'CHECKBOX':
209
+ const checkboxContainer = document.createElement('div');
210
+ checkboxContainer.className = 'rbird-form-checkbox-group';
211
+
212
+ (field.options || []).forEach((opt) => {
213
+ const optWrapper = document.createElement('label');
214
+ optWrapper.className = 'rbird-form-checkbox-label';
215
+
216
+ const checkbox = document.createElement('input');
217
+ checkbox.type = 'checkbox';
218
+ checkbox.name = fieldId;
219
+ checkbox.value = opt;
220
+ checkbox.className = 'rbird-form-checkbox';
221
+
222
+ const optLabel = document.createElement('span');
223
+ optLabel.textContent = opt;
224
+
225
+ optWrapper.appendChild(checkbox);
226
+ optWrapper.appendChild(optLabel);
227
+ checkboxContainer.appendChild(optWrapper);
228
+ });
229
+ wrapper.appendChild(checkboxContainer);
230
+ break;
231
+
232
+ case 'RADIO':
233
+ const radioContainer = document.createElement('div');
234
+ radioContainer.className = 'rbird-form-radio-group';
235
+
236
+ (field.options || []).forEach((opt) => {
237
+ const optWrapper = document.createElement('label');
238
+ optWrapper.className = 'rbird-form-radio-label';
239
+
240
+ const radio = document.createElement('input');
241
+ radio.type = 'radio';
242
+ radio.name = fieldId;
243
+ radio.value = opt;
244
+ radio.required = field.required || false;
245
+ radio.className = 'rbird-form-radio';
246
+
247
+ const optLabel = document.createElement('span');
248
+ optLabel.textContent = opt;
249
+
250
+ optWrapper.appendChild(radio);
251
+ optWrapper.appendChild(optLabel);
252
+ radioContainer.appendChild(optWrapper);
253
+ });
254
+ wrapper.appendChild(radioContainer);
255
+ break;
256
+
257
+ default:
258
+ const defaultInput = document.createElement('input');
259
+ defaultInput.type = 'text';
260
+ defaultInput.name = fieldId;
261
+ defaultInput.required = field.required || false;
262
+ defaultInput.className = 'rbird-form-input';
263
+ wrapper.appendChild(defaultInput);
264
+ }
265
+
266
+ return wrapper;
267
+ }
268
+ }
package/src/Styles.js CHANGED
@@ -170,27 +170,19 @@ export const injectStyledCSS = (
170
170
  }
171
171
 
172
172
  .launcherButton {
173
- backgroundColor:transparent;
173
+ background-color:transparent;
174
174
  width:50px;
175
175
  height:50px;
176
- z-index: 10000000;
177
- position:fixed;
178
- bottom:${spaceBottom}px;
179
- right:${launcherPosition === 'right' ? spaceLeftRight + 'px' : 'unset'};
180
- left:${launcherPosition === 'left' ? spaceLeftRight + 'px' : 'unset'};
181
176
  cursor:pointer;
177
+ position: relative;
182
178
  }
183
179
 
184
180
  .launcherButton5 {
185
- backgroundColor:transparent;
181
+ background-color:transparent;
186
182
  width:70px;
187
183
  height:50px;
188
- z-index: 10000000;
189
- position:fixed;
190
- bottom:${spaceBottom}px;
191
- right:${launcherPosition === 'right' ? spaceLeftRight + 'px' : 'unset'};
192
- left:${launcherPosition === 'left' ? spaceLeftRight + 'px' : 'unset'};
193
184
  cursor:pointer;
185
+ position: relative;
194
186
  }
195
187
 
196
188
  .rbird_badge {
@@ -322,9 +314,9 @@ height: 15px;
322
314
  position: fixed;
323
315
  cursor: pointer;
324
316
  bottom: ${spaceBottom + 45}px;
325
- right: ${launcherPosition === 'right' ? (spaceLeftRight -15) + 'px' : 'unset'};
326
- left: ${launcherPosition === 'left' ? (spaceLeftRight -15) + 'px' : 'unset'};
327
- z-index: 10000000;
317
+ right: ${launcherPosition === 'right' ? (spaceLeftRight - 5) + 'px' : 'unset'};
318
+ left: ${launcherPosition === 'left' ? (spaceLeftRight + 55) + 'px' : 'unset'};
319
+ z-index: 10000001;
328
320
  }
329
321
 
330
322
  .rbird_closeclose:hover,
@@ -523,6 +515,261 @@ background: transparent
523
515
  transform: translateY(20px) scale(0.95);
524
516
  }
525
517
  }
518
+
519
+ /* Drag Handle for Widget Button */
520
+ .rbird-drag-handle {
521
+ width: 14px;
522
+ height: 28px;
523
+ cursor: grab;
524
+ display: flex;
525
+ flex-direction: column;
526
+ justify-content: center;
527
+ align-items: center;
528
+ gap: 3px;
529
+ opacity: 0;
530
+ transition: opacity 0.3s ease;
531
+ pointer-events: auto;
532
+ background: transparent;
533
+ border-radius: 4px;
534
+ padding: 2px;
535
+ }
536
+
537
+ .rbird-drag-handle:hover {
538
+ background: rgba(0, 0, 0, 0.05);
539
+ }
540
+
541
+ .rbird-drag-handle:active {
542
+ cursor: grabbing;
543
+ }
544
+
545
+ .rbird-drag-handle-row {
546
+ display: flex;
547
+ gap: 2px;
548
+ }
549
+
550
+ .rbird-drag-handle-dot {
551
+ width: 3px;
552
+ height: 3px;
553
+ border-radius: 50%;
554
+ background-color: #b0b0b0;
555
+ }
556
+
557
+ .rbird-widget-wrapper {
558
+ position: fixed;
559
+ z-index: 10000000;
560
+ display: flex;
561
+ align-items: center;
562
+ gap: 8px;
563
+ }
564
+
565
+ .rbird-widget-wrapper:hover .rbird-drag-handle {
566
+ opacity: 1;
567
+ }
568
+
569
+ .rbird-widget-wrapper.rbird-dragging .rbird-drag-handle {
570
+ opacity: 1;
571
+ }
572
+
573
+ /* Form Modal Styles */
574
+ .rbird-form-modal-overlay {
575
+ position: fixed;
576
+ top: 0;
577
+ left: 0;
578
+ right: 0;
579
+ bottom: 0;
580
+ background: rgba(0, 0, 0, 0.6);
581
+ display: flex;
582
+ align-items: center;
583
+ justify-content: center;
584
+ z-index: 10000000001;
585
+ animation: rbird-form-fade-in 0.2s ease;
586
+ }
587
+
588
+ .rbird-form-modal {
589
+ background: white;
590
+ border-radius: 16px;
591
+ max-width: 500px;
592
+ width: 90%;
593
+ max-height: 85vh;
594
+ overflow-y: auto;
595
+ box-shadow: 0 25px 50px -12px rgba(0, 0, 0, 0.25);
596
+ animation: rbird-form-scale-in 0.3s ease;
597
+ }
598
+
599
+ .rbird-form-modal-header {
600
+ padding: 20px 24px;
601
+ border-bottom: 1px solid #e5e7eb;
602
+ display: flex;
603
+ justify-content: space-between;
604
+ align-items: center;
605
+ position: sticky;
606
+ top: 0;
607
+ background: white;
608
+ border-radius: 16px 16px 0 0;
609
+ }
610
+
611
+ .rbird-form-modal-title {
612
+ margin: 0;
613
+ font-size: 20px;
614
+ font-weight: 600;
615
+ color: #111827;
616
+ font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, sans-serif;
617
+ }
618
+
619
+ .rbird-form-modal-close {
620
+ background: none;
621
+ border: none;
622
+ font-size: 28px;
623
+ cursor: pointer;
624
+ color: #9ca3af;
625
+ line-height: 1;
626
+ padding: 0;
627
+ width: 32px;
628
+ height: 32px;
629
+ display: flex;
630
+ align-items: center;
631
+ justify-content: center;
632
+ border-radius: 8px;
633
+ transition: all 0.2s ease;
634
+ }
635
+
636
+ .rbird-form-modal-close:hover {
637
+ background: #f3f4f6;
638
+ color: #374151;
639
+ }
640
+
641
+ .rbird-form-modal-content {
642
+ padding: 24px;
643
+ }
644
+
645
+ .rbird-form-element {
646
+ display: flex;
647
+ flex-direction: column;
648
+ gap: 20px;
649
+ }
650
+
651
+ .rbird-form-field {
652
+ display: flex;
653
+ flex-direction: column;
654
+ gap: 8px;
655
+ }
656
+
657
+ .rbird-form-label {
658
+ font-size: 14px;
659
+ font-weight: 500;
660
+ color: #374151;
661
+ font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, sans-serif;
662
+ }
663
+
664
+ .rbird-form-required {
665
+ color: #ef4444;
666
+ }
667
+
668
+ .rbird-form-input {
669
+ padding: 12px 14px;
670
+ border: 1px solid #d1d5db;
671
+ border-radius: 10px;
672
+ font-size: 15px;
673
+ outline: none;
674
+ transition: border-color 0.2s ease, box-shadow 0.2s ease;
675
+ font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, sans-serif;
676
+ background: #fff;
677
+ }
678
+
679
+ .rbird-form-input:focus {
680
+ border-color: #4f46e5;
681
+ box-shadow: 0 0 0 3px rgba(79, 70, 229, 0.1);
682
+ }
683
+
684
+ .rbird-form-input::placeholder {
685
+ color: #9ca3af;
686
+ }
687
+
688
+ .rbird-form-textarea {
689
+ resize: vertical;
690
+ min-height: 100px;
691
+ }
692
+
693
+ .rbird-form-select {
694
+ cursor: pointer;
695
+ appearance: none;
696
+ background-image: url("data:image/svg+xml,%3csvg xmlns='http://www.w3.org/2000/svg' fill='none' viewBox='0 0 20 20'%3e%3cpath stroke='%236b7280' stroke-linecap='round' stroke-linejoin='round' stroke-width='1.5' d='M6 8l4 4 4-4'/%3e%3c/svg%3e");
697
+ background-position: right 12px center;
698
+ background-repeat: no-repeat;
699
+ background-size: 16px 16px;
700
+ padding-right: 40px;
701
+ }
702
+
703
+ .rbird-form-checkbox-group,
704
+ .rbird-form-radio-group {
705
+ display: flex;
706
+ flex-direction: column;
707
+ gap: 10px;
708
+ }
709
+
710
+ .rbird-form-checkbox-label,
711
+ .rbird-form-radio-label {
712
+ display: flex;
713
+ align-items: center;
714
+ gap: 10px;
715
+ cursor: pointer;
716
+ font-size: 14px;
717
+ color: #374151;
718
+ font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, sans-serif;
719
+ }
720
+
721
+ .rbird-form-checkbox,
722
+ .rbird-form-radio {
723
+ width: 18px;
724
+ height: 18px;
725
+ cursor: pointer;
726
+ accent-color: #4f46e5;
727
+ }
728
+
729
+ .rbird-form-submit-btn {
730
+ background: #4f46e5;
731
+ color: white;
732
+ border: none;
733
+ padding: 14px 24px;
734
+ border-radius: 10px;
735
+ font-size: 15px;
736
+ font-weight: 600;
737
+ cursor: pointer;
738
+ margin-top: 8px;
739
+ transition: all 0.2s ease;
740
+ font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, sans-serif;
741
+ }
742
+
743
+ .rbird-form-submit-btn:hover {
744
+ opacity: 0.9;
745
+ transform: translateY(-1px);
746
+ }
747
+
748
+ .rbird-form-submit-btn:disabled {
749
+ opacity: 0.7;
750
+ cursor: not-allowed;
751
+ transform: none;
752
+ }
753
+
754
+ @keyframes rbird-form-fade-in {
755
+ from {
756
+ opacity: 0;
757
+ }
758
+ to {
759
+ opacity: 1;
760
+ }
761
+ }
762
+
763
+ @keyframes rbird-form-scale-in {
764
+ from {
765
+ opacity: 0;
766
+ transform: scale(0.95);
767
+ }
768
+ to {
769
+ opacity: 1;
770
+ transform: scale(1);
771
+ }
772
+ }
526
773
  }`
527
774
 
528
775
  const oldNode = document.querySelector(".rbird-styles");
@@ -659,14 +906,12 @@ export function launcher5Open(launcherColor) {
659
906
  }
660
907
 
661
908
  export function launcherOpen(launcherColor) {
662
- return `<svg version="1.1" id="Capa_1" xmlns="http://www.w3.org/2000/svg"
663
- x="0px"
664
- y="0px"
665
- viewBox="0 0 494.08 494.08" style="enable-background:new 0 0 494.08 494.08;">
666
- <g>
667
- <path fill="${launcherColor}" d="M247.04,0C110.604,0,0,110.604,0,247.04s110.604,247.04,247.04,247.04s247.04-110.604,247.04-247.04
668
- C493.845,110.701,383.379,0.235,247.04,0z M247.04,298.667l-79.787-80.64l14.293-13.653l65.493,64l65.493-64l14.72,14.507
669
- L247.04,298.667z"/>
909
+ return `<svg version="1.1" xmlns="http://www.w3.org/2000/svg"
910
+ viewBox="0 0 494.08 494.08">
911
+ <circle fill="${launcherColor}" cx="247.04" cy="247.04" r="247.04"/>
912
+ <g transform="translate(247.04, 247.04) rotate(45)">
913
+ <rect fill="#ffffff" x="-100" y="-15" width="200" height="30" rx="8"/>
914
+ <rect fill="#ffffff" x="-15" y="-100" width="30" height="200" rx="8"/>
670
915
  </g>
671
916
  </svg>`
672
917
  }
package/src/index.js CHANGED
@@ -3,6 +3,7 @@ import RbirdSessionManager from "./RbirdSessionManager";
3
3
  import RbirdWebsiteWidget from "./RbirdWebsiteWidget";
4
4
  import { ReleasebirdConsoleLogger } from "./ReleasebirdConsoleLogger";
5
5
  import { RbirdBannerManager } from "./RbirdBannerManager";
6
+ import { RbirdFormManager } from "./RbirdFormManager";
6
7
 
7
8
  class Rbird {
8
9
 
@@ -87,6 +88,10 @@ class Rbird {
87
88
  const bannerManager = RbirdBannerManager.getInstance();
88
89
  bannerManager.injectStyles();
89
90
  bannerManager.init(apiKey);
91
+
92
+ // Initialize form manager
93
+ const formManager = RbirdFormManager.getInstance();
94
+ formManager.init(apiKey);
90
95
  });
91
96
  })
92
97
 
@@ -135,6 +140,23 @@ class Rbird {
135
140
  }
136
141
  }
137
142
 
143
+ /**
144
+ * Show a form by its ID
145
+ * @param {string} formId - The ID of the form to show
146
+ * @param {Object} options - Optional configuration
147
+ * @param {string} options.target - CSS selector for inline rendering (optional, shows as modal if not provided)
148
+ * @param {Function} options.onSubmit - Callback when form is submitted
149
+ * @param {Function} options.onClose - Callback when form is closed
150
+ */
151
+ static showForm(formId, options = {}) {
152
+ if (typeof window === 'undefined') return;
153
+ try {
154
+ RbirdFormManager.getInstance().showForm(formId, options);
155
+ } catch (e) {
156
+ console.error(e);
157
+ }
158
+ }
159
+
138
160
  }
139
161
 
140
162
  export const runFunctionWhenDomIsReady = (callback) => {