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.
- package/build/index.js +1 -1
- package/package.json +1 -1
- package/published/1.0.74/index.js +1 -0
- package/published/1.0.75/index.js +1 -0
- package/published/1.0.76/index.js +1 -0
- package/published/latest/index.js +1 -1
- package/src/RbirdFormManager.js +567 -0
- package/src/RbirdWebsiteWidget.js +361 -9
- package/src/ReleasebirdFormViewer.js +268 -0
- package/src/Styles.js +268 -23
- package/src/index.js +22 -0
|
@@ -0,0 +1,567 @@
|
|
|
1
|
+
import RbirdSessionManager from './RbirdSessionManager';
|
|
2
|
+
|
|
3
|
+
// API is defined globally via webpack.DefinePlugin
|
|
4
|
+
/* global API */
|
|
5
|
+
|
|
6
|
+
export class RbirdFormManager {
|
|
7
|
+
static instance;
|
|
8
|
+
|
|
9
|
+
constructor() {
|
|
10
|
+
this.displayedForms = new Set();
|
|
11
|
+
this.apiKey = null;
|
|
12
|
+
}
|
|
13
|
+
|
|
14
|
+
static getInstance() {
|
|
15
|
+
if (!RbirdFormManager.instance) {
|
|
16
|
+
RbirdFormManager.instance = new RbirdFormManager();
|
|
17
|
+
}
|
|
18
|
+
return RbirdFormManager.instance;
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
init(apiKey) {
|
|
22
|
+
if (typeof window === 'undefined') return;
|
|
23
|
+
this.apiKey = apiKey;
|
|
24
|
+
this.injectStyles();
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
/**
|
|
28
|
+
* Show a form by its ID
|
|
29
|
+
* @param {string} formId - The ID of the form to show
|
|
30
|
+
* @param {Object} options - Optional configuration
|
|
31
|
+
* @param {string} options.target - CSS selector for inline rendering (optional)
|
|
32
|
+
* @param {Function} options.onSubmit - Callback when form is submitted
|
|
33
|
+
* @param {Function} options.onClose - Callback when form is closed
|
|
34
|
+
*/
|
|
35
|
+
showForm(formId, options = {}) {
|
|
36
|
+
if (typeof window === 'undefined') return;
|
|
37
|
+
if (!this.apiKey) {
|
|
38
|
+
console.error('[RbirdFormManager] SDK not initialized. Call Rbird.initialize() first.');
|
|
39
|
+
return;
|
|
40
|
+
}
|
|
41
|
+
if (!formId) {
|
|
42
|
+
console.error('[RbirdFormManager] Form ID is required.');
|
|
43
|
+
return;
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
// Check if form is already displayed
|
|
47
|
+
if (this.displayedForms.has(formId)) {
|
|
48
|
+
console.warn('[RbirdFormManager] Form is already displayed:', formId);
|
|
49
|
+
return;
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
const sessionManager = RbirdSessionManager.getInstance();
|
|
53
|
+
const state = sessionManager.getState();
|
|
54
|
+
|
|
55
|
+
const http = new XMLHttpRequest();
|
|
56
|
+
http.open("GET", `${API}/ewidget/forms/${formId}`);
|
|
57
|
+
http.setRequestHeader("Content-Type", "application/json;charset=UTF-8");
|
|
58
|
+
http.setRequestHeader("apiKey", this.apiKey);
|
|
59
|
+
|
|
60
|
+
if (state?.identify?.people) {
|
|
61
|
+
http.setRequestHeader("peopleId", state.identify.people);
|
|
62
|
+
}
|
|
63
|
+
if (sessionManager.anonymousIdentifier) {
|
|
64
|
+
http.setRequestHeader("anonymousId", sessionManager.anonymousIdentifier);
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
const self = this;
|
|
68
|
+
http.onreadystatechange = function () {
|
|
69
|
+
if (http.readyState === 4) {
|
|
70
|
+
if (http.status === 200) {
|
|
71
|
+
try {
|
|
72
|
+
const form = JSON.parse(http.responseText);
|
|
73
|
+
if (options.target) {
|
|
74
|
+
self.renderInlineForm(form, options);
|
|
75
|
+
} else {
|
|
76
|
+
self.renderModalForm(form, options);
|
|
77
|
+
}
|
|
78
|
+
} catch (exp) {
|
|
79
|
+
console.error('[RbirdFormManager] Error parsing form response:', exp);
|
|
80
|
+
}
|
|
81
|
+
} else {
|
|
82
|
+
console.error('[RbirdFormManager] Failed to fetch form. Status:', http.status);
|
|
83
|
+
}
|
|
84
|
+
}
|
|
85
|
+
};
|
|
86
|
+
http.send();
|
|
87
|
+
}
|
|
88
|
+
|
|
89
|
+
renderInlineForm(form, options) {
|
|
90
|
+
const targetElement = document.querySelector(options.target);
|
|
91
|
+
if (!targetElement) {
|
|
92
|
+
console.error('[RbirdFormManager] Target element not found:', options.target);
|
|
93
|
+
return;
|
|
94
|
+
}
|
|
95
|
+
|
|
96
|
+
const formElement = this.createFormElement(form, false, options);
|
|
97
|
+
targetElement.innerHTML = '';
|
|
98
|
+
targetElement.appendChild(formElement);
|
|
99
|
+
this.displayedForms.add(form.id);
|
|
100
|
+
}
|
|
101
|
+
|
|
102
|
+
renderModalForm(form, options) {
|
|
103
|
+
const overlay = document.createElement('div');
|
|
104
|
+
overlay.className = 'rbird-form-overlay';
|
|
105
|
+
overlay.id = `rbird-form-overlay-${form.id}`;
|
|
106
|
+
|
|
107
|
+
const modal = this.createFormElement(form, true, options);
|
|
108
|
+
overlay.appendChild(modal);
|
|
109
|
+
|
|
110
|
+
// Close on overlay click
|
|
111
|
+
overlay.addEventListener('click', (e) => {
|
|
112
|
+
if (e.target === overlay) {
|
|
113
|
+
this.closeForm(form.id, options.onClose);
|
|
114
|
+
}
|
|
115
|
+
});
|
|
116
|
+
|
|
117
|
+
document.body.appendChild(overlay);
|
|
118
|
+
this.displayedForms.add(form.id);
|
|
119
|
+
|
|
120
|
+
// Animate in
|
|
121
|
+
requestAnimationFrame(() => {
|
|
122
|
+
overlay.classList.add('rbird-form-overlay-visible');
|
|
123
|
+
});
|
|
124
|
+
}
|
|
125
|
+
|
|
126
|
+
createFormElement(form, isModal, options) {
|
|
127
|
+
const container = document.createElement('div');
|
|
128
|
+
container.className = isModal ? 'rbird-form-modal' : 'rbird-form-inline';
|
|
129
|
+
container.id = `rbird-form-${form.id}`;
|
|
130
|
+
|
|
131
|
+
const theme = form.theme || {};
|
|
132
|
+
|
|
133
|
+
// Build form HTML
|
|
134
|
+
let fieldsHtml = '';
|
|
135
|
+
(form.fields || []).forEach(field => {
|
|
136
|
+
fieldsHtml += this.createFieldHtml(field, theme);
|
|
137
|
+
});
|
|
138
|
+
|
|
139
|
+
container.innerHTML = `
|
|
140
|
+
<div class="rbird-form-content" style="${this.getFormStyles(theme, isModal)}">
|
|
141
|
+
${isModal ? `
|
|
142
|
+
<button class="rbird-form-close" data-form-id="${form.id}" style="${this.getCloseButtonStyles()}">
|
|
143
|
+
×
|
|
144
|
+
</button>
|
|
145
|
+
` : ''}
|
|
146
|
+
<div class="rbird-form-body">
|
|
147
|
+
${form.title ? `<h3 class="rbird-form-title" style="${this.getTitleStyles(theme)}">${this.escapeHtml(form.title)}</h3>` : ''}
|
|
148
|
+
${form.description ? `<p class="rbird-form-description" style="${this.getDescriptionStyles()}">${this.escapeHtml(form.description)}</p>` : ''}
|
|
149
|
+
<form class="rbird-form-fields" data-form-id="${form.id}">
|
|
150
|
+
${fieldsHtml}
|
|
151
|
+
<button type="submit" class="rbird-form-submit" style="${this.getSubmitButtonStyles(theme)}">
|
|
152
|
+
${this.escapeHtml(form.submitButtonText || 'Submit')}
|
|
153
|
+
</button>
|
|
154
|
+
</form>
|
|
155
|
+
<div class="rbird-form-success" style="display: none;">
|
|
156
|
+
<p style="${this.getSuccessStyles()}">${this.escapeHtml(form.successMessage || 'Thank you for your submission!')}</p>
|
|
157
|
+
</div>
|
|
158
|
+
</div>
|
|
159
|
+
</div>
|
|
160
|
+
`;
|
|
161
|
+
|
|
162
|
+
// Add event listeners
|
|
163
|
+
if (isModal) {
|
|
164
|
+
const closeButton = container.querySelector('.rbird-form-close');
|
|
165
|
+
if (closeButton) {
|
|
166
|
+
closeButton.addEventListener('click', (e) => {
|
|
167
|
+
e.preventDefault();
|
|
168
|
+
this.closeForm(form.id, options.onClose);
|
|
169
|
+
});
|
|
170
|
+
}
|
|
171
|
+
}
|
|
172
|
+
|
|
173
|
+
const formElement = container.querySelector('form');
|
|
174
|
+
if (formElement) {
|
|
175
|
+
formElement.addEventListener('submit', (e) => {
|
|
176
|
+
e.preventDefault();
|
|
177
|
+
this.handleSubmit(form.id, formElement, options);
|
|
178
|
+
});
|
|
179
|
+
}
|
|
180
|
+
|
|
181
|
+
return container;
|
|
182
|
+
}
|
|
183
|
+
|
|
184
|
+
createFieldHtml(field, theme) {
|
|
185
|
+
const required = field.required ? 'required' : '';
|
|
186
|
+
const requiredMark = field.required ? '<span style="color: #dc2626;">*</span>' : '';
|
|
187
|
+
const inputStyle = this.getInputStyles(theme);
|
|
188
|
+
|
|
189
|
+
let html = `<div class="rbird-form-field" style="margin-bottom: 16px;">`;
|
|
190
|
+
|
|
191
|
+
if (field.label) {
|
|
192
|
+
html += `<label style="${this.getLabelStyles()}">${this.escapeHtml(field.label)} ${requiredMark}</label>`;
|
|
193
|
+
}
|
|
194
|
+
|
|
195
|
+
switch (field.type) {
|
|
196
|
+
case 'TEXT':
|
|
197
|
+
case 'EMAIL':
|
|
198
|
+
case 'PHONE':
|
|
199
|
+
case 'NUMBER':
|
|
200
|
+
case 'DATE':
|
|
201
|
+
html += `<input type="${this.getInputType(field.type)}" name="${field.id}"
|
|
202
|
+
placeholder="${this.escapeHtml(field.placeholder || '')}"
|
|
203
|
+
${required} style="${inputStyle}" />`;
|
|
204
|
+
break;
|
|
205
|
+
case 'TEXTAREA':
|
|
206
|
+
html += `<textarea name="${field.id}" rows="4"
|
|
207
|
+
placeholder="${this.escapeHtml(field.placeholder || '')}"
|
|
208
|
+
${required} style="${inputStyle}"></textarea>`;
|
|
209
|
+
break;
|
|
210
|
+
case 'CHECKBOX':
|
|
211
|
+
if (field.options && field.options.length > 0) {
|
|
212
|
+
field.options.forEach((option, index) => {
|
|
213
|
+
html += `<label style="${this.getCheckboxLabelStyles()}">
|
|
214
|
+
<input type="checkbox" name="${field.id}" value="${this.escapeHtml(option)}" />
|
|
215
|
+
${this.escapeHtml(option)}
|
|
216
|
+
</label>`;
|
|
217
|
+
});
|
|
218
|
+
} else {
|
|
219
|
+
html += `<label style="${this.getCheckboxLabelStyles()}">
|
|
220
|
+
<input type="checkbox" name="${field.id}" ${required} />
|
|
221
|
+
${this.escapeHtml(field.label || '')}
|
|
222
|
+
</label>`;
|
|
223
|
+
}
|
|
224
|
+
break;
|
|
225
|
+
case 'RADIO':
|
|
226
|
+
(field.options || []).forEach((option, index) => {
|
|
227
|
+
html += `<label style="${this.getCheckboxLabelStyles()}">
|
|
228
|
+
<input type="radio" name="${field.id}" value="${this.escapeHtml(option)}" ${required && index === 0 ? required : ''} />
|
|
229
|
+
${this.escapeHtml(option)}
|
|
230
|
+
</label>`;
|
|
231
|
+
});
|
|
232
|
+
break;
|
|
233
|
+
case 'DROPDOWN':
|
|
234
|
+
html += `<select name="${field.id}" ${required} style="${inputStyle}">
|
|
235
|
+
<option value="">${this.escapeHtml(field.placeholder || 'Select an option')}</option>
|
|
236
|
+
${(field.options || []).map(opt => `<option value="${this.escapeHtml(opt)}">${this.escapeHtml(opt)}</option>`).join('')}
|
|
237
|
+
</select>`;
|
|
238
|
+
break;
|
|
239
|
+
case 'FILE':
|
|
240
|
+
html += `<input type="file" name="${field.id}" ${required} style="${inputStyle}" />`;
|
|
241
|
+
break;
|
|
242
|
+
default:
|
|
243
|
+
html += `<input type="text" name="${field.id}"
|
|
244
|
+
placeholder="${this.escapeHtml(field.placeholder || '')}"
|
|
245
|
+
${required} style="${inputStyle}" />`;
|
|
246
|
+
}
|
|
247
|
+
|
|
248
|
+
if (field.helpText) {
|
|
249
|
+
html += `<small style="${this.getHelpTextStyles()}">${this.escapeHtml(field.helpText)}</small>`;
|
|
250
|
+
}
|
|
251
|
+
|
|
252
|
+
html += `</div>`;
|
|
253
|
+
return html;
|
|
254
|
+
}
|
|
255
|
+
|
|
256
|
+
getInputType(fieldType) {
|
|
257
|
+
const typeMap = {
|
|
258
|
+
'TEXT': 'text',
|
|
259
|
+
'EMAIL': 'email',
|
|
260
|
+
'PHONE': 'tel',
|
|
261
|
+
'NUMBER': 'number',
|
|
262
|
+
'DATE': 'date'
|
|
263
|
+
};
|
|
264
|
+
return typeMap[fieldType] || 'text';
|
|
265
|
+
}
|
|
266
|
+
|
|
267
|
+
handleSubmit(formId, formElement, options) {
|
|
268
|
+
const formData = new FormData(formElement);
|
|
269
|
+
const data = {};
|
|
270
|
+
|
|
271
|
+
formData.forEach((value, key) => {
|
|
272
|
+
if (data[key]) {
|
|
273
|
+
// Handle multiple values (checkboxes)
|
|
274
|
+
if (Array.isArray(data[key])) {
|
|
275
|
+
data[key].push(value);
|
|
276
|
+
} else {
|
|
277
|
+
data[key] = [data[key], value];
|
|
278
|
+
}
|
|
279
|
+
} else {
|
|
280
|
+
data[key] = value;
|
|
281
|
+
}
|
|
282
|
+
});
|
|
283
|
+
|
|
284
|
+
const sessionManager = RbirdSessionManager.getInstance();
|
|
285
|
+
const state = sessionManager.getState();
|
|
286
|
+
|
|
287
|
+
const http = new XMLHttpRequest();
|
|
288
|
+
http.open("POST", `${API}/ewidget/forms/${formId}/submit`);
|
|
289
|
+
http.setRequestHeader("Content-Type", "application/json;charset=UTF-8");
|
|
290
|
+
http.setRequestHeader("apiKey", this.apiKey);
|
|
291
|
+
|
|
292
|
+
if (state?.identify?.people) {
|
|
293
|
+
http.setRequestHeader("peopleId", state.identify.people);
|
|
294
|
+
}
|
|
295
|
+
if (sessionManager.anonymousIdentifier) {
|
|
296
|
+
http.setRequestHeader("anonymousId", sessionManager.anonymousIdentifier);
|
|
297
|
+
}
|
|
298
|
+
|
|
299
|
+
// Send browser language
|
|
300
|
+
const browserLang = navigator.language ? navigator.language.split('-')[0] : 'en';
|
|
301
|
+
http.setRequestHeader("languageCode", browserLang);
|
|
302
|
+
|
|
303
|
+
const self = this;
|
|
304
|
+
const submitButton = formElement.querySelector('button[type="submit"]');
|
|
305
|
+
if (submitButton) {
|
|
306
|
+
submitButton.disabled = true;
|
|
307
|
+
submitButton.textContent = 'Sending...';
|
|
308
|
+
}
|
|
309
|
+
|
|
310
|
+
http.onreadystatechange = function () {
|
|
311
|
+
if (http.readyState === 4) {
|
|
312
|
+
if (http.status === 200 || http.status === 201) {
|
|
313
|
+
// Show success message
|
|
314
|
+
const container = document.getElementById(`rbird-form-${formId}`);
|
|
315
|
+
if (container) {
|
|
316
|
+
const form = container.querySelector('form');
|
|
317
|
+
const successMessage = container.querySelector('.rbird-form-success');
|
|
318
|
+
if (form) form.style.display = 'none';
|
|
319
|
+
if (successMessage) successMessage.style.display = 'block';
|
|
320
|
+
}
|
|
321
|
+
|
|
322
|
+
if (options.onSubmit) {
|
|
323
|
+
options.onSubmit(data);
|
|
324
|
+
}
|
|
325
|
+
} else {
|
|
326
|
+
console.error('[RbirdFormManager] Failed to submit form. Status:', http.status);
|
|
327
|
+
if (submitButton) {
|
|
328
|
+
submitButton.disabled = false;
|
|
329
|
+
submitButton.textContent = 'Submit';
|
|
330
|
+
}
|
|
331
|
+
alert('Failed to submit form. Please try again.');
|
|
332
|
+
}
|
|
333
|
+
}
|
|
334
|
+
};
|
|
335
|
+
|
|
336
|
+
http.send(JSON.stringify({
|
|
337
|
+
data: data,
|
|
338
|
+
userEmail: state?.identify?.email || null,
|
|
339
|
+
userName: state?.identify?.name || null
|
|
340
|
+
}));
|
|
341
|
+
}
|
|
342
|
+
|
|
343
|
+
closeForm(formId, onClose) {
|
|
344
|
+
const overlay = document.getElementById(`rbird-form-overlay-${formId}`);
|
|
345
|
+
if (overlay) {
|
|
346
|
+
overlay.classList.remove('rbird-form-overlay-visible');
|
|
347
|
+
setTimeout(() => {
|
|
348
|
+
overlay.remove();
|
|
349
|
+
}, 300);
|
|
350
|
+
}
|
|
351
|
+
|
|
352
|
+
const inlineForm = document.getElementById(`rbird-form-${formId}`);
|
|
353
|
+
if (inlineForm && !overlay) {
|
|
354
|
+
inlineForm.remove();
|
|
355
|
+
}
|
|
356
|
+
|
|
357
|
+
this.displayedForms.delete(formId);
|
|
358
|
+
|
|
359
|
+
if (onClose) {
|
|
360
|
+
onClose();
|
|
361
|
+
}
|
|
362
|
+
}
|
|
363
|
+
|
|
364
|
+
// Styles
|
|
365
|
+
getFormStyles(theme, isModal) {
|
|
366
|
+
return `
|
|
367
|
+
background-color: ${theme.backgroundColor || '#ffffff'};
|
|
368
|
+
font-family: ${theme.fontFamily || "-apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, 'Helvetica Neue', Arial, sans-serif"};
|
|
369
|
+
border-radius: ${theme.borderRadius || '12px'};
|
|
370
|
+
padding: 24px;
|
|
371
|
+
min-width: min(400px, calc(100vw - 40px));
|
|
372
|
+
${isModal ? 'max-width: 500px; width: 100%; max-height: 90vh; overflow-y: auto;' : 'width: 100%;'}
|
|
373
|
+
box-sizing: border-box;
|
|
374
|
+
`;
|
|
375
|
+
}
|
|
376
|
+
|
|
377
|
+
getCloseButtonStyles() {
|
|
378
|
+
return `
|
|
379
|
+
position: absolute;
|
|
380
|
+
top: 12px;
|
|
381
|
+
right: 12px;
|
|
382
|
+
background: transparent;
|
|
383
|
+
border: none;
|
|
384
|
+
font-size: 24px;
|
|
385
|
+
line-height: 1;
|
|
386
|
+
cursor: pointer;
|
|
387
|
+
color: #6b7280;
|
|
388
|
+
opacity: 0.6;
|
|
389
|
+
padding: 0;
|
|
390
|
+
width: 32px;
|
|
391
|
+
height: 32px;
|
|
392
|
+
display: flex;
|
|
393
|
+
align-items: center;
|
|
394
|
+
justify-content: center;
|
|
395
|
+
transition: opacity 0.2s;
|
|
396
|
+
`;
|
|
397
|
+
}
|
|
398
|
+
|
|
399
|
+
getTitleStyles(theme) {
|
|
400
|
+
return `
|
|
401
|
+
margin: 0 0 8px 0;
|
|
402
|
+
font-size: 20px;
|
|
403
|
+
font-weight: 600;
|
|
404
|
+
color: ${theme.primaryColor || '#1f2937'};
|
|
405
|
+
`;
|
|
406
|
+
}
|
|
407
|
+
|
|
408
|
+
getDescriptionStyles() {
|
|
409
|
+
return `
|
|
410
|
+
margin: 0 0 20px 0;
|
|
411
|
+
font-size: 14px;
|
|
412
|
+
color: #6b7280;
|
|
413
|
+
line-height: 1.5;
|
|
414
|
+
`;
|
|
415
|
+
}
|
|
416
|
+
|
|
417
|
+
getLabelStyles() {
|
|
418
|
+
return `
|
|
419
|
+
display: block;
|
|
420
|
+
margin-bottom: 6px;
|
|
421
|
+
font-size: 14px;
|
|
422
|
+
font-weight: 500;
|
|
423
|
+
color: #374151;
|
|
424
|
+
`;
|
|
425
|
+
}
|
|
426
|
+
|
|
427
|
+
getInputStyles(theme) {
|
|
428
|
+
return `
|
|
429
|
+
width: 100%;
|
|
430
|
+
padding: 10px 12px;
|
|
431
|
+
border: 1px solid ${theme.inputBorderColor || '#d1d5db'};
|
|
432
|
+
border-radius: ${theme.borderRadius || '8px'};
|
|
433
|
+
font-size: 14px;
|
|
434
|
+
transition: border-color 0.2s, box-shadow 0.2s;
|
|
435
|
+
box-sizing: border-box;
|
|
436
|
+
outline: none;
|
|
437
|
+
`;
|
|
438
|
+
}
|
|
439
|
+
|
|
440
|
+
getCheckboxLabelStyles() {
|
|
441
|
+
return `
|
|
442
|
+
display: flex;
|
|
443
|
+
align-items: center;
|
|
444
|
+
gap: 8px;
|
|
445
|
+
margin-bottom: 8px;
|
|
446
|
+
font-size: 14px;
|
|
447
|
+
color: #374151;
|
|
448
|
+
cursor: pointer;
|
|
449
|
+
`;
|
|
450
|
+
}
|
|
451
|
+
|
|
452
|
+
getHelpTextStyles() {
|
|
453
|
+
return `
|
|
454
|
+
display: block;
|
|
455
|
+
margin-top: 4px;
|
|
456
|
+
font-size: 12px;
|
|
457
|
+
color: #6b7280;
|
|
458
|
+
`;
|
|
459
|
+
}
|
|
460
|
+
|
|
461
|
+
getSubmitButtonStyles(theme) {
|
|
462
|
+
return `
|
|
463
|
+
width: 100%;
|
|
464
|
+
padding: 12px 20px;
|
|
465
|
+
background-color: ${theme.buttonColor || '#667eea'};
|
|
466
|
+
color: ${theme.buttonTextColor || '#ffffff'};
|
|
467
|
+
border: none;
|
|
468
|
+
border-radius: ${theme.borderRadius || '8px'};
|
|
469
|
+
font-size: 14px;
|
|
470
|
+
font-weight: 600;
|
|
471
|
+
cursor: pointer;
|
|
472
|
+
transition: opacity 0.2s, transform 0.2s;
|
|
473
|
+
margin-top: 8px;
|
|
474
|
+
`;
|
|
475
|
+
}
|
|
476
|
+
|
|
477
|
+
getSuccessStyles() {
|
|
478
|
+
return `
|
|
479
|
+
text-align: center;
|
|
480
|
+
padding: 40px 20px;
|
|
481
|
+
font-size: 16px;
|
|
482
|
+
color: #10b981;
|
|
483
|
+
`;
|
|
484
|
+
}
|
|
485
|
+
|
|
486
|
+
escapeHtml(text) {
|
|
487
|
+
if (!text) return '';
|
|
488
|
+
const div = document.createElement('div');
|
|
489
|
+
div.textContent = text;
|
|
490
|
+
return div.innerHTML;
|
|
491
|
+
}
|
|
492
|
+
|
|
493
|
+
injectStyles() {
|
|
494
|
+
if (typeof window === 'undefined' || document.getElementById('rbird-form-styles')) return;
|
|
495
|
+
|
|
496
|
+
const style = document.createElement('style');
|
|
497
|
+
style.id = 'rbird-form-styles';
|
|
498
|
+
style.textContent = `
|
|
499
|
+
.rbird-form-overlay {
|
|
500
|
+
position: fixed;
|
|
501
|
+
top: 0;
|
|
502
|
+
left: 0;
|
|
503
|
+
right: 0;
|
|
504
|
+
bottom: 0;
|
|
505
|
+
background-color: rgba(0, 0, 0, 0);
|
|
506
|
+
display: flex;
|
|
507
|
+
align-items: center;
|
|
508
|
+
justify-content: center;
|
|
509
|
+
z-index: 10001;
|
|
510
|
+
padding: 20px;
|
|
511
|
+
opacity: 0;
|
|
512
|
+
transition: background-color 0.3s, opacity 0.3s;
|
|
513
|
+
}
|
|
514
|
+
|
|
515
|
+
.rbird-form-overlay-visible {
|
|
516
|
+
background-color: rgba(0, 0, 0, 0.5);
|
|
517
|
+
opacity: 1;
|
|
518
|
+
}
|
|
519
|
+
|
|
520
|
+
.rbird-form-modal {
|
|
521
|
+
position: relative;
|
|
522
|
+
animation: rbirdFormSlideIn 0.3s ease-out;
|
|
523
|
+
}
|
|
524
|
+
|
|
525
|
+
.rbird-form-inline {
|
|
526
|
+
width: 100%;
|
|
527
|
+
}
|
|
528
|
+
|
|
529
|
+
.rbird-form-content {
|
|
530
|
+
position: relative;
|
|
531
|
+
}
|
|
532
|
+
|
|
533
|
+
.rbird-form-close:hover {
|
|
534
|
+
opacity: 1 !important;
|
|
535
|
+
}
|
|
536
|
+
|
|
537
|
+
.rbird-form-submit:hover {
|
|
538
|
+
opacity: 0.9;
|
|
539
|
+
transform: translateY(-1px);
|
|
540
|
+
}
|
|
541
|
+
|
|
542
|
+
.rbird-form-submit:disabled {
|
|
543
|
+
opacity: 0.6;
|
|
544
|
+
cursor: not-allowed;
|
|
545
|
+
}
|
|
546
|
+
|
|
547
|
+
.rbird-form-fields input:focus,
|
|
548
|
+
.rbird-form-fields textarea:focus,
|
|
549
|
+
.rbird-form-fields select:focus {
|
|
550
|
+
border-color: #667eea;
|
|
551
|
+
box-shadow: 0 0 0 3px rgba(102, 126, 234, 0.1);
|
|
552
|
+
}
|
|
553
|
+
|
|
554
|
+
@keyframes rbirdFormSlideIn {
|
|
555
|
+
from {
|
|
556
|
+
opacity: 0;
|
|
557
|
+
transform: translateY(-20px) scale(0.95);
|
|
558
|
+
}
|
|
559
|
+
to {
|
|
560
|
+
opacity: 1;
|
|
561
|
+
transform: translateY(0) scale(1);
|
|
562
|
+
}
|
|
563
|
+
}
|
|
564
|
+
`;
|
|
565
|
+
document.head.appendChild(style);
|
|
566
|
+
}
|
|
567
|
+
}
|