@formique/semantq 1.0.12 → 1.1.1
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/formique-semantq.js +750 -278
- package/package.json +1 -1
package/formique-semantq.js
CHANGED
|
@@ -54,6 +54,7 @@ class FormBuilder
|
|
|
54
54
|
class Formique extends FormBuilder {
|
|
55
55
|
constructor(formDefinition, formSettings = {}, formParams = {}) {
|
|
56
56
|
super();
|
|
57
|
+
|
|
57
58
|
let formSchema;
|
|
58
59
|
let finalSettings = formSettings;
|
|
59
60
|
let finalParams = formParams;
|
|
@@ -83,6 +84,11 @@ class Formique extends FormBuilder {
|
|
|
83
84
|
...finalSettings
|
|
84
85
|
};
|
|
85
86
|
|
|
87
|
+
// Only inject CSS if the user hasn't explicitly disabled it
|
|
88
|
+
if (this.formSettings.disableStyles !== true) {
|
|
89
|
+
this.injectInternalStyles();
|
|
90
|
+
}
|
|
91
|
+
|
|
86
92
|
//console.log("constructor",this.formSettings);
|
|
87
93
|
|
|
88
94
|
this.themeColor = this.formSettings.themeColor || null;
|
|
@@ -225,14 +231,49 @@ this.initDependencyGraph();
|
|
|
225
231
|
this.registerObservers();
|
|
226
232
|
this.attachDynamicSelectListeners();
|
|
227
233
|
|
|
228
|
-
|
|
229
|
-
|
|
230
|
-
|
|
231
|
-
|
|
232
|
-
|
|
233
|
-
|
|
234
|
+
|
|
235
|
+
// In your constructor, after attachDynamicSelectListeners:
|
|
236
|
+
//console.log('FORM SCHEMA FOR DYNAMIC SELECT:');
|
|
237
|
+
const dynamicField = this.formSchema.find(f => f[0] === 'dynamicSingleSelect');
|
|
238
|
+
if (dynamicField) {
|
|
239
|
+
//console.log('Main options:', dynamicField[5]);
|
|
240
|
+
//console.log('Sub options:', dynamicField[6]);
|
|
241
|
+
|
|
242
|
+
// Check the IDs
|
|
243
|
+
const mainOptions = dynamicField[5] || [];
|
|
244
|
+
mainOptions.forEach(opt => {
|
|
245
|
+
//console.log(`Option ID: ${opt.id}, Label: ${opt.label}`);
|
|
246
|
+
});
|
|
247
|
+
}
|
|
248
|
+
|
|
249
|
+
|
|
250
|
+
// --- CONDITIONAL CONSOLIDATED THEME LOGIC ---
|
|
251
|
+
if (this.formSettings.disableStyles !== true) {
|
|
252
|
+
const container = document.getElementById(this.formContainerId);
|
|
253
|
+
|
|
254
|
+
if (container) {
|
|
255
|
+
// Apply the base class regardless of theme choice
|
|
256
|
+
container.classList.add('formique');
|
|
257
|
+
|
|
258
|
+
if (this.themeColor) {
|
|
259
|
+
// Priority 1: Custom Hex Color Override
|
|
260
|
+
this.applyCustomTheme(this.themeColor, this.formContainerId);
|
|
261
|
+
} else {
|
|
262
|
+
// Priority 2: Named Theme (or fallback to 'dark')
|
|
263
|
+
const activeTheme = (this.formSettings.theme && this.themes.includes(this.formSettings.theme))
|
|
264
|
+
? this.formSettings.theme
|
|
265
|
+
: 'light';
|
|
266
|
+
this.applyTheme(activeTheme, this.formContainerId);
|
|
267
|
+
}
|
|
268
|
+
|
|
269
|
+
// Priority 3: Manual Inline Style Overrides (Highest Specificity)
|
|
270
|
+
if (this.formSettings.formContainerStyle) {
|
|
271
|
+
container.style.cssText += this.formSettings.formContainerStyle;
|
|
272
|
+
}
|
|
273
|
+
}
|
|
234
274
|
} else {
|
|
235
|
-
|
|
275
|
+
// Optional: Log that styles are being skipped for easier debugging
|
|
276
|
+
console.log("Formique: Internal styles disabled by user settings.");
|
|
236
277
|
}
|
|
237
278
|
|
|
238
279
|
|
|
@@ -244,6 +285,35 @@ if (this.themeColor) {
|
|
|
244
285
|
}
|
|
245
286
|
|
|
246
287
|
|
|
288
|
+
|
|
289
|
+
|
|
290
|
+
|
|
291
|
+
|
|
292
|
+
injectInternalStyles() {
|
|
293
|
+
if (document.getElementById('formique-internal-css')) return;
|
|
294
|
+
|
|
295
|
+
const style = document.createElement('style');
|
|
296
|
+
style.id = 'formique-internal-css';
|
|
297
|
+
style.textContent = FORMIQUE_INTERNAL_CSS;
|
|
298
|
+
document.head.appendChild(style);
|
|
299
|
+
}
|
|
300
|
+
|
|
301
|
+
|
|
302
|
+
|
|
303
|
+
applyCustomTheme(color, formContainerId) {
|
|
304
|
+
const container = document.getElementById(formContainerId);
|
|
305
|
+
if (!container) return;
|
|
306
|
+
|
|
307
|
+
// Set variables directly on the element (highest specificity)
|
|
308
|
+
container.style.setProperty('--formique-focus-color', color);
|
|
309
|
+
container.style.setProperty('--formique-btn-bg', color);
|
|
310
|
+
|
|
311
|
+
// Add a transparent shadow using the hex color
|
|
312
|
+
container.style.setProperty('--formique-btn-shadow', `0 4px 14px ${color}66`);
|
|
313
|
+
}
|
|
314
|
+
|
|
315
|
+
|
|
316
|
+
|
|
247
317
|
generateFormId() {
|
|
248
318
|
return `fmq-${Math.random().toString(36).substr(2, 10)}`;
|
|
249
319
|
}
|
|
@@ -450,48 +520,59 @@ registerObservers() {
|
|
|
450
520
|
|
|
451
521
|
// --- NEW METHOD FOR DYNAMIC SELECT LISTENERS ---
|
|
452
522
|
attachDynamicSelectListeners() {
|
|
523
|
+
//console.log('DEBUG: attachDynamicSelectListeners called');
|
|
524
|
+
|
|
453
525
|
this.formSchema.forEach(field => {
|
|
454
526
|
const [type, name, label, validate, attributes = {}] = field;
|
|
455
527
|
|
|
456
528
|
if (type === 'dynamicSingleSelect') {
|
|
457
529
|
const mainSelectId = attributes.id || name;
|
|
530
|
+
//console.log('Setting up dynamic select for:', mainSelectId);
|
|
531
|
+
|
|
458
532
|
const mainSelectElement = document.getElementById(mainSelectId);
|
|
459
533
|
|
|
460
534
|
if (mainSelectElement) {
|
|
535
|
+
//console.log('Found main select element:', mainSelectElement);
|
|
536
|
+
|
|
461
537
|
mainSelectElement.addEventListener('change', (event) => {
|
|
462
|
-
const selectedCategory = event.target.value;
|
|
463
|
-
|
|
538
|
+
const selectedCategory = event.target.value;
|
|
539
|
+
//console.log('Select changed to:', selectedCategory);
|
|
540
|
+
|
|
464
541
|
// Find all sub-category fieldsets related to this main select
|
|
465
542
|
const subCategoryFieldsets = document.querySelectorAll(`.${mainSelectId}`);
|
|
466
|
-
|
|
543
|
+
//console.log(`Found ${subCategoryFieldsets.length} fieldsets with class .${mainSelectId}`);
|
|
544
|
+
|
|
467
545
|
subCategoryFieldsets.forEach(fieldset => {
|
|
468
|
-
|
|
546
|
+
//console.log('Hiding fieldset:', fieldset.id);
|
|
547
|
+
const subSelect = fieldset.querySelector('select');
|
|
469
548
|
if (subSelect) {
|
|
470
|
-
// Save original required state (if it was true) then set to false if hidden
|
|
471
549
|
subSelect.setAttribute('data-original-required', subSelect.required.toString());
|
|
472
|
-
subSelect.required = false;
|
|
550
|
+
subSelect.required = false;
|
|
473
551
|
}
|
|
474
|
-
fieldset.style.display = 'none';
|
|
552
|
+
fieldset.style.display = 'none';
|
|
475
553
|
});
|
|
476
554
|
|
|
477
|
-
// Show the selected sub-category fieldset
|
|
478
|
-
const selectedFieldsetId = selectedCategory;
|
|
555
|
+
// Show the selected sub-category fieldset
|
|
556
|
+
const selectedFieldsetId = selectedCategory;
|
|
557
|
+
//console.log('Looking for fieldset with ID:', selectedFieldsetId);
|
|
558
|
+
|
|
479
559
|
const selectedFieldset = document.getElementById(selectedFieldsetId);
|
|
480
|
-
|
|
560
|
+
|
|
481
561
|
if (selectedFieldset) {
|
|
482
|
-
|
|
562
|
+
// console.log('Found selected fieldset, showing it:', selectedFieldset);
|
|
563
|
+
selectedFieldset.style.display = 'block';
|
|
483
564
|
const selectedSubSelect = selectedFieldset.querySelector('select');
|
|
484
565
|
if (selectedSubSelect) {
|
|
485
|
-
// Restore original required state for the visible select
|
|
486
566
|
selectedSubSelect.required = selectedSubSelect.getAttribute('data-original-required') === 'true';
|
|
487
567
|
}
|
|
568
|
+
} else {
|
|
569
|
+
console.warn('Selected fieldset not found with ID:', selectedFieldsetId);
|
|
488
570
|
}
|
|
489
571
|
});
|
|
490
572
|
|
|
491
|
-
//
|
|
492
|
-
// This ensures correct initial visibility and required states if there's a pre-selected main category.
|
|
493
|
-
// We do this by dispatching a 'change' event programmatically if the select has a value.
|
|
573
|
+
// Trigger initial state
|
|
494
574
|
if (mainSelectElement.value) {
|
|
575
|
+
console.log('Triggering initial change event for:', mainSelectId);
|
|
495
576
|
const event = new Event('change');
|
|
496
577
|
mainSelectElement.dispatchEvent(event);
|
|
497
578
|
}
|
|
@@ -502,61 +583,28 @@ attachDynamicSelectListeners() {
|
|
|
502
583
|
});
|
|
503
584
|
}
|
|
504
585
|
|
|
505
|
-
applyTheme(theme, formContainerId) {
|
|
506
|
-
//const stylesheet = document.querySelector('link[formique-style]');
|
|
507
|
-
|
|
508
|
-
const stylesheet = document.querySelector('link[href*="formique-css"]');
|
|
509
|
-
|
|
510
|
-
if (!stylesheet) {
|
|
511
|
-
console.error("Stylesheet with 'formique-css' in the name not found!");
|
|
512
|
-
return;
|
|
513
|
-
}
|
|
514
586
|
|
|
515
|
-
fetch(stylesheet.href)
|
|
516
|
-
.then(response => response.text())
|
|
517
|
-
.then(cssText => {
|
|
518
|
-
// Extract theme-specific CSS rules
|
|
519
|
-
const themeRules = cssText.match(new RegExp(`\\.${theme}-theme\\s*{([^}]*)}`, 'i'));
|
|
520
587
|
|
|
521
|
-
|
|
522
|
-
|
|
588
|
+
applyTheme(theme, formContainerId) {
|
|
589
|
+
// Safety Guard: If styles are disabled, exit immediately
|
|
590
|
+
if (this.formSettings.disableStyles === true) {
|
|
591
|
+
// console.warn('applyTheme ignored because disableStyles is true.');
|
|
523
592
|
return;
|
|
524
|
-
|
|
525
|
-
|
|
526
|
-
// Extract CSS rules for the theme
|
|
527
|
-
const themeCSS = themeRules[1].trim();
|
|
528
|
-
|
|
529
|
-
// Find the form container element
|
|
530
|
-
const formContainer = document.getElementById(formContainerId);
|
|
593
|
+
}
|
|
531
594
|
|
|
532
|
-
|
|
533
|
-
|
|
595
|
+
const formContainer = document.getElementById(formContainerId);
|
|
596
|
+
if (formContainer) {
|
|
597
|
+
// Apply classes for backward compatibility
|
|
534
598
|
formContainer.classList.add(`${theme}-theme`, 'formique');
|
|
535
599
|
|
|
536
|
-
|
|
537
|
-
|
|
538
|
-
|
|
539
|
-
clonedStyle.textContent = `
|
|
540
|
-
#${formContainerId} {
|
|
541
|
-
${themeCSS}
|
|
542
|
-
}
|
|
543
|
-
`;
|
|
544
|
-
|
|
545
|
-
// Insert the <style> tag above the form container
|
|
546
|
-
formContainer.parentNode.insertBefore(clonedStyle, formContainer);
|
|
547
|
-
|
|
548
|
-
// console.log(`Applied ${theme} theme to form container: ${formContainerId}`);
|
|
549
|
-
} else {
|
|
600
|
+
// Set the data attribute for our internal CSS variables
|
|
601
|
+
formContainer.setAttribute('data-theme', theme);
|
|
602
|
+
} else {
|
|
550
603
|
console.error(`Form container with ID ${formContainerId} not found.`);
|
|
551
|
-
|
|
552
|
-
})
|
|
553
|
-
.catch(error => {
|
|
554
|
-
console.error('Error loading the stylesheet:', error);
|
|
555
|
-
});
|
|
604
|
+
}
|
|
556
605
|
}
|
|
557
606
|
|
|
558
607
|
|
|
559
|
-
|
|
560
608
|
// New method to apply a custom theme based on a color
|
|
561
609
|
applyCustomTheme(color, formContainerId) {
|
|
562
610
|
const formContainer = document.getElementById(formContainerId);
|
|
@@ -612,7 +660,7 @@ applyCustomTheme(color, formContainerId) {
|
|
|
612
660
|
// Insert the style element into the head or before the form container
|
|
613
661
|
formContainer.parentNode.insertBefore(styleElement, formContainer);
|
|
614
662
|
|
|
615
|
-
console.log(`Applied custom theme with color: ${color} to form container: ${formContainerId}`);
|
|
663
|
+
//console.log(`Applied custom theme with color: ${color} to form container: ${formContainerId}`);
|
|
616
664
|
}
|
|
617
665
|
|
|
618
666
|
|
|
@@ -1680,12 +1728,10 @@ if (attributes.binding === 'bind:value' && name) {
|
|
|
1680
1728
|
// Textarea field rendering
|
|
1681
1729
|
|
|
1682
1730
|
renderTextAreaField(type, name, label, validate, attributes) {
|
|
1683
|
-
const textInputValidationAttributes = [
|
|
1684
|
-
|
|
1685
|
-
|
|
1686
|
-
'
|
|
1687
|
-
'pattern',
|
|
1688
|
-
];
|
|
1731
|
+
const textInputValidationAttributes = ['required', 'minlength', 'maxlength', 'pattern'];
|
|
1732
|
+
|
|
1733
|
+
// 1. Extract content value to place between tags later
|
|
1734
|
+
const textareaValue = attributes.value || '';
|
|
1689
1735
|
|
|
1690
1736
|
// Construct validation attributes
|
|
1691
1737
|
let validationAttrs = '';
|
|
@@ -1695,115 +1741,74 @@ renderTextAreaField(type, name, label, validate, attributes) {
|
|
|
1695
1741
|
if (typeof value === 'boolean' && value) {
|
|
1696
1742
|
validationAttrs += ` ${key}\n`;
|
|
1697
1743
|
} else {
|
|
1698
|
-
|
|
1699
|
-
case 'pattern':
|
|
1700
|
-
case 'minlength':
|
|
1701
|
-
case 'maxlength':
|
|
1702
|
-
validationAttrs += ` ${key}="${value}"\n`;
|
|
1703
|
-
break;
|
|
1704
|
-
default:
|
|
1705
|
-
if (!textInputValidationAttributes.includes(key)) {
|
|
1706
|
-
console.warn(`\x1b[31mUnsupported validation attribute '${key}' for field '${name}' of type 'number'.\x1b[0m`);
|
|
1707
|
-
}
|
|
1708
|
-
break;
|
|
1709
|
-
}
|
|
1744
|
+
validationAttrs += ` ${key}="${value}"\n`;
|
|
1710
1745
|
}
|
|
1711
1746
|
} else {
|
|
1712
|
-
console.warn(`\x1b[31mUnsupported validation attribute '${key}' for field '${name}' of type '
|
|
1747
|
+
console.warn(`\x1b[31mUnsupported validation attribute '${key}' for field '${name}' of type 'textarea'.\x1b[0m`);
|
|
1713
1748
|
}
|
|
1714
1749
|
});
|
|
1715
1750
|
}
|
|
1716
1751
|
|
|
1717
|
-
|
|
1718
|
-
|
|
1719
1752
|
// Handle the binding syntax
|
|
1720
1753
|
let bindingDirective = '';
|
|
1721
|
-
if (attributes.binding) {
|
|
1722
|
-
if (attributes.binding === 'bind:value' && name) {
|
|
1754
|
+
if (attributes.binding && name) {
|
|
1723
1755
|
bindingDirective = `bind:value="${name}"\n`;
|
|
1724
1756
|
}
|
|
1725
|
-
if (attributes.binding.startsWith('::') && name) {
|
|
1726
|
-
bindingDirective = `bind:value="${name}"\n`;
|
|
1727
|
-
}
|
|
1728
|
-
if (attributes.binding && !name) {
|
|
1729
|
-
console.log(`\x1b[31m%s\x1b[0m`, `You cannot set binding value when there is no name attribute defined in ${name} ${type} field.`);
|
|
1730
|
-
return;
|
|
1731
|
-
}
|
|
1732
|
-
}
|
|
1733
1757
|
|
|
1734
|
-
|
|
1735
|
-
|
|
1736
|
-
// Get the id from attributes or fall back to name
|
|
1737
1758
|
let id = attributes.id || name;
|
|
1738
|
-
// Determine if semanti is true based on formSettings
|
|
1739
1759
|
const framework = this.formSettings?.framework || false;
|
|
1740
1760
|
|
|
1741
|
-
// Construct additional attributes
|
|
1761
|
+
// Construct additional attributes (excluding internal keys and the 'value' content)
|
|
1742
1762
|
let additionalAttrs = '';
|
|
1743
1763
|
for (const [key, value] of Object.entries(attributes)) {
|
|
1744
|
-
|
|
1745
|
-
|
|
1746
|
-
|
|
1747
|
-
|
|
1748
|
-
additionalAttrs += ` @${key.replace(/^on/, '')}={${eventValue}}\n`;
|
|
1749
|
-
} else {
|
|
1750
|
-
// Add parentheses if not present
|
|
1751
|
-
const eventValue = value.endsWith('()') ? value : `${value}()`;
|
|
1752
|
-
additionalAttrs += ` ${key}="${eventValue}"\n`;
|
|
1753
|
-
}
|
|
1764
|
+
if (!['id', 'class', 'dependsOn', 'dependents', 'value', 'binding'].includes(key) && value !== undefined) {
|
|
1765
|
+
if (key.startsWith('on')) {
|
|
1766
|
+
const eventValue = value.endsWith('()') ? value : `${value}()`;
|
|
1767
|
+
additionalAttrs += ` ${key}="${eventValue}"\n`;
|
|
1754
1768
|
} else {
|
|
1755
|
-
|
|
1769
|
+
const attrName = key.replace(/_/g, '-');
|
|
1756
1770
|
if (value === true) {
|
|
1757
|
-
additionalAttrs += ` ${
|
|
1771
|
+
additionalAttrs += ` ${attrName}\n`;
|
|
1758
1772
|
} else if (value !== false) {
|
|
1759
|
-
|
|
1760
|
-
additionalAttrs += ` ${key.replace(/_/g, '-')}="${value}"\n`;
|
|
1773
|
+
additionalAttrs += ` ${attrName}="${value}"\n`;
|
|
1761
1774
|
}
|
|
1762
1775
|
}
|
|
1763
1776
|
}
|
|
1764
1777
|
}
|
|
1765
1778
|
|
|
1779
|
+
let inputClass = attributes.class || this.inputClass;
|
|
1766
1780
|
|
|
1781
|
+
// Build the raw HTML structure
|
|
1782
|
+
let formHTML = `
|
|
1783
|
+
<div class="${this.divClass}" id="${id + '-block'}">
|
|
1784
|
+
<label for="${id}">${label}
|
|
1785
|
+
${validationAttrs.includes('required') && this.formSettings.requiredFieldIndicator ? this.formSettings.asteriskHtml : ''}
|
|
1786
|
+
</label>
|
|
1787
|
+
<textarea
|
|
1788
|
+
name="${name}"
|
|
1789
|
+
${bindingDirective}
|
|
1790
|
+
id="${id}"
|
|
1791
|
+
class="${inputClass}"
|
|
1792
|
+
${additionalAttrs}
|
|
1793
|
+
${validationAttrs}
|
|
1794
|
+
${(additionalAttrs.includes('placeholder') || attributes.placeholder) ? '' : (this.formSettings.placeholders ? `placeholder="${label}"` : '')}>${textareaValue}</textarea>
|
|
1795
|
+
</div>`.replace(/^\s*\n/gm, '').trim();
|
|
1796
|
+
|
|
1797
|
+
// Vertical layout formatting for attributes while preserving content
|
|
1798
|
+
let formattedHtml = formHTML.replace(/<textarea\s+([\s\S]*?)>([\s\S]*?)<\/textarea>/, (match, attrPart, content) => {
|
|
1799
|
+
// Split by whitespace only if it is NOT inside quotes (prevents stacking text/placeholders)
|
|
1800
|
+
const attrs = attrPart.trim()
|
|
1801
|
+
.split(/\s+(?=(?:[^"]*"[^"]*")*[^"]*$)/)
|
|
1802
|
+
.filter(a => a.trim() !== '')
|
|
1803
|
+
.map(attr => ` ${attr.trim()}`)
|
|
1804
|
+
.join('\n');
|
|
1805
|
+
|
|
1806
|
+
return `<textarea\n${attrs}\n>${content}</textarea>`;
|
|
1807
|
+
});
|
|
1767
1808
|
|
|
1768
|
-
|
|
1769
|
-
if ('class' in attributes) {
|
|
1770
|
-
inputClass = attributes.class;
|
|
1771
|
-
} else {
|
|
1772
|
-
inputClass = this.inputClass;
|
|
1773
|
-
}
|
|
1774
|
-
|
|
1775
|
-
// Construct the final HTML string for textarea
|
|
1776
|
-
let formHTML = `
|
|
1777
|
-
<div class="${this.divClass}" id="${id + '-block'}">
|
|
1778
|
-
<label for="${id}">${label}
|
|
1779
|
-
${validationAttrs.includes('required') && this.formSettings.requiredFieldIndicator ? this.formSettings.asteriskHtml : ''}
|
|
1780
|
-
</label>
|
|
1781
|
-
<textarea
|
|
1782
|
-
name="${name}"
|
|
1783
|
-
${bindingDirective}
|
|
1784
|
-
id="${id}"
|
|
1785
|
-
class="${inputClass}"
|
|
1786
|
-
${additionalAttrs}
|
|
1787
|
-
${validationAttrs}
|
|
1788
|
-
${additionalAttrs.includes('placeholder') ? '' : (this.formSettings.placeholders ? `placeholder="${label}"` : '')}>
|
|
1789
|
-
</textarea>
|
|
1790
|
-
</div>
|
|
1791
|
-
`.replace(/^\s*\n/gm, '').trim();
|
|
1792
|
-
|
|
1793
|
-
let formattedHtml = formHTML;
|
|
1794
|
-
|
|
1795
|
-
// Apply vertical layout to the <textarea> element only
|
|
1796
|
-
formattedHtml = formattedHtml.replace(/<textarea\s+([^>]*)>\s*<\/textarea>/, (match, p1) => {
|
|
1797
|
-
// Reformat attributes into a vertical layout
|
|
1798
|
-
const attributes = p1.trim().split(/\s+/).map(attr => ` ${attr}`).join('\n');
|
|
1799
|
-
return `<textarea\n${attributes}\n></textarea>`;
|
|
1800
|
-
});
|
|
1801
|
-
|
|
1802
|
-
this.formMarkUp += formattedHtml;
|
|
1803
|
-
|
|
1809
|
+
this.formMarkUp += formattedHtml;
|
|
1804
1810
|
}
|
|
1805
1811
|
|
|
1806
|
-
|
|
1807
1812
|
// New method for rendering tel fields
|
|
1808
1813
|
renderTelField(type, name, label, validate, attributes) {
|
|
1809
1814
|
|
|
@@ -3361,101 +3366,11 @@ renderImageField(type, name, label, validate, attributes) {
|
|
|
3361
3366
|
|
|
3362
3367
|
|
|
3363
3368
|
|
|
3364
|
-
//
|
|
3365
|
-
renderTextAreaField(type, name, label, validate, attributes) {
|
|
3366
|
-
const textAreaValidationAttributes = [
|
|
3367
|
-
'required',
|
|
3368
|
-
'minlength',
|
|
3369
|
-
'maxlength'
|
|
3370
|
-
];
|
|
3371
|
-
|
|
3372
|
-
// Construct validation attributes
|
|
3373
|
-
let validationAttrs = '';
|
|
3374
|
-
if (validate) {
|
|
3375
|
-
Object.entries(validate).forEach(([key, value]) => {
|
|
3376
|
-
if (textAreaValidationAttributes.includes(key)) {
|
|
3377
|
-
if (typeof value === 'boolean' && value) {
|
|
3378
|
-
validationAttrs += ` ${key}\n`;
|
|
3379
|
-
} else {
|
|
3380
|
-
validationAttrs += ` ${key}="${value}"\n`;
|
|
3381
|
-
}
|
|
3382
|
-
} else {
|
|
3383
|
-
console.warn(`\x1b[31mUnsupported validation attribute '${key}' for field '${name}' of type '${type}'.\x1b[0m`);
|
|
3384
|
-
}
|
|
3385
|
-
});
|
|
3386
|
-
}
|
|
3387
|
-
|
|
3388
|
-
// Handle the binding syntax
|
|
3389
|
-
let bindingDirective = '';
|
|
3390
|
-
if (attributes.binding) {
|
|
3391
|
-
if (attributes.binding === 'bind:value' && name) {
|
|
3392
|
-
bindingDirective = `bind:value="${name}"\n`;
|
|
3393
|
-
}
|
|
3394
|
-
if (attributes.binding.startsWith('::') && name) {
|
|
3395
|
-
bindingDirective = `bind:value="${name}"\n`;
|
|
3396
|
-
}
|
|
3397
|
-
if (attributes.binding && !name) {
|
|
3398
|
-
console.log(`\x1b[31m%s\x1b[0m`, `You cannot set binding value when there is no name attribute defined in ${name} ${type} field.`);
|
|
3399
|
-
return;
|
|
3400
|
-
}
|
|
3401
|
-
}
|
|
3402
|
-
|
|
3403
|
-
// Get the id from attributes or fall back to name
|
|
3404
|
-
let id = attributes.id || name;
|
|
3405
|
-
|
|
3406
|
-
// Construct additional attributes dynamically
|
|
3407
|
-
let additionalAttrs = '';
|
|
3408
|
-
for (const [key, value] of Object.entries(attributes)) {
|
|
3409
|
-
if (key !== 'id' && key !== 'class' && key !== 'dependsOn' && key !== 'dependents' && value !== undefined) {
|
|
3410
|
-
if (key.startsWith('on')) {
|
|
3411
|
-
const eventValue = value.endsWith('()') ? value : `${value}()`;
|
|
3412
|
-
additionalAttrs += ` ${key}="${eventValue}"\n`;
|
|
3413
|
-
} else {
|
|
3414
|
-
if (value === true) {
|
|
3415
|
-
additionalAttrs += ` ${key.replace(/_/g, '-')}\n`;
|
|
3416
|
-
} else if (value !== false) {
|
|
3417
|
-
additionalAttrs += ` ${key.replace(/_/g, '-')}="${value}"\n`;
|
|
3418
|
-
}
|
|
3419
|
-
}
|
|
3420
|
-
}
|
|
3421
|
-
}
|
|
3422
|
-
|
|
3423
|
-
let inputClass = attributes.class || this.inputClass;
|
|
3424
|
-
|
|
3425
|
-
// Construct the final HTML string
|
|
3426
|
-
let formHTML = `
|
|
3427
|
-
<div class="${this.divClass}" id="${id + '-block'}">
|
|
3428
|
-
<label for="${id}">${label}
|
|
3429
|
-
${validationAttrs.includes('required') && this.formSettings.requiredFieldIndicator ? this.formSettings.asteriskHtml : ''}
|
|
3430
|
-
</label>
|
|
3431
|
-
<textarea
|
|
3432
|
-
name="${name}"
|
|
3433
|
-
${bindingDirective}
|
|
3434
|
-
id="${id}"
|
|
3435
|
-
class="${inputClass}"
|
|
3436
|
-
${additionalAttrs}
|
|
3437
|
-
${validationAttrs}
|
|
3438
|
-
${additionalAttrs.includes('placeholder') ? '' : (this.formSettings.placeholders ? `placeholder="${label}"` : '')}>
|
|
3439
|
-
</textarea>
|
|
3440
|
-
</div>
|
|
3441
|
-
`.replace(/^\s*\n/gm, '').trim();
|
|
3442
|
-
|
|
3443
|
-
let formattedHtml = formHTML;
|
|
3444
|
-
|
|
3445
|
-
// Apply vertical layout to the <textarea> element only
|
|
3446
|
-
formattedHtml = formattedHtml.replace(/<textarea\s+([^>]*)>\s*<\/textarea>/, (match, p1) => {
|
|
3447
|
-
const attributes = p1.trim().split(/\s+/).map(attr => ` ${attr}`).join('\n');
|
|
3448
|
-
return `<textarea\n${attributes}\n></textarea>`;
|
|
3449
|
-
});
|
|
3450
|
-
|
|
3451
|
-
this.formMarkUp += formattedHtml;
|
|
3452
|
-
}
|
|
3453
|
-
|
|
3454
|
-
|
|
3369
|
+
// Radio field rendering
|
|
3455
3370
|
|
|
3456
3371
|
renderRadioField(type, name, label, validate, attributes, options) {
|
|
3457
3372
|
// Define valid validation attributes for radio fields
|
|
3458
|
-
console.log("RADIO DEBUG - options:", JSON.stringify(options, null, 2));
|
|
3373
|
+
//console.log("RADIO DEBUG - options:", JSON.stringify(options, null, 2));
|
|
3459
3374
|
|
|
3460
3375
|
const radioValidationAttributes = ['required'];
|
|
3461
3376
|
|
|
@@ -3529,10 +3444,10 @@ renderRadioField(type, name, label, validate, attributes, options) {
|
|
|
3529
3444
|
// Check options array for selected: true
|
|
3530
3445
|
if (options && options.length) {
|
|
3531
3446
|
const selectedOption = options.find(opt => opt.selected === true);
|
|
3532
|
-
console.log("RADIO DEBUG - selectedOption:", selectedOption);
|
|
3447
|
+
//console.log("RADIO DEBUG - selectedOption:", selectedOption);
|
|
3533
3448
|
if (selectedOption) {
|
|
3534
3449
|
selectedValue = selectedOption.value;
|
|
3535
|
-
|
|
3450
|
+
// console.log("RADIO DEBUG - selectedValue:", selectedValue);
|
|
3536
3451
|
}
|
|
3537
3452
|
}
|
|
3538
3453
|
|
|
@@ -3542,7 +3457,7 @@ renderRadioField(type, name, label, validate, attributes, options) {
|
|
|
3542
3457
|
optionsHTML = options.map((option) => {
|
|
3543
3458
|
// Check if this option should be selected
|
|
3544
3459
|
const isSelected = (option.value === selectedValue);
|
|
3545
|
-
console.log("RADIO DEBUG - option:", option.value, "isSelected:", isSelected);
|
|
3460
|
+
//console.log("RADIO DEBUG - option:", option.value, "isSelected:", isSelected);
|
|
3546
3461
|
const checkedAttr = isSelected ? ' checked' : '';
|
|
3547
3462
|
|
|
3548
3463
|
return `
|
|
@@ -3596,7 +3511,7 @@ renderRadioField(type, name, label, validate, attributes, options) {
|
|
|
3596
3511
|
|
|
3597
3512
|
renderCheckboxField(type, name, label, validate, attributes, options) {
|
|
3598
3513
|
// Define valid validation attributes for checkbox fields
|
|
3599
|
-
console.log("CHECKBOX DEBUG - options:", JSON.stringify(options, null, 2));
|
|
3514
|
+
//console.log("CHECKBOX DEBUG - options:", JSON.stringify(options, null, 2));
|
|
3600
3515
|
|
|
3601
3516
|
const checkboxValidationAttributes = ['required'];
|
|
3602
3517
|
|
|
@@ -3663,7 +3578,7 @@ renderCheckboxField(type, name, label, validate, attributes, options) {
|
|
|
3663
3578
|
}
|
|
3664
3579
|
});
|
|
3665
3580
|
}
|
|
3666
|
-
console.log("CHECKBOX DEBUG - checkedValues:", checkedValues);
|
|
3581
|
+
//console.log("CHECKBOX DEBUG - checkedValues:", checkedValues);
|
|
3667
3582
|
|
|
3668
3583
|
// Construct checkbox HTML based on options
|
|
3669
3584
|
let optionsHTML = '';
|
|
@@ -3671,7 +3586,7 @@ renderCheckboxField(type, name, label, validate, attributes, options) {
|
|
|
3671
3586
|
optionsHTML = options.map((option) => {
|
|
3672
3587
|
const optionId = `${id}-${option.value}`;
|
|
3673
3588
|
const isChecked = checkedValues.includes(option.value);
|
|
3674
|
-
console.log("CHECKBOX DEBUG - option:", option.value, "isChecked:", isChecked);
|
|
3589
|
+
//console.log("CHECKBOX DEBUG - option:", option.value, "isChecked:", isChecked);
|
|
3675
3590
|
const checkedAttr = isChecked ? ' checked' : '';
|
|
3676
3591
|
|
|
3677
3592
|
return `
|
|
@@ -3726,30 +3641,35 @@ renderCheckboxField(type, name, label, validate, attributes, options) {
|
|
|
3726
3641
|
/* DYNAMIC SINGLE SELECT BLOCK */
|
|
3727
3642
|
|
|
3728
3643
|
// Function to render the dynamic select field and update based on user selection
|
|
3729
|
-
renderDynamicSingleSelectField(type, name, label, validate, attributes, options
|
|
3730
|
-
|
|
3731
|
-
|
|
3732
|
-
|
|
3733
|
-
|
|
3734
|
-
|
|
3735
|
-
|
|
3736
|
-
|
|
3737
|
-
|
|
3738
|
-
//
|
|
3739
|
-
|
|
3740
|
-
|
|
3741
|
-
|
|
3742
|
-
|
|
3743
|
-
|
|
3744
|
-
|
|
3745
|
-
|
|
3746
|
-
|
|
3747
|
-
|
|
3748
|
-
|
|
3749
|
-
|
|
3750
|
-
|
|
3751
|
-
|
|
3752
|
-
|
|
3644
|
+
renderDynamicSingleSelectField(type, name, label, validate, attributes, options) {
|
|
3645
|
+
//console.log('DEBUG: renderDynamicSingleSelectField called with options:', options);
|
|
3646
|
+
|
|
3647
|
+
// Step 1: Extract main categories from options
|
|
3648
|
+
const mainCategoryOptions = options.map(item => {
|
|
3649
|
+
// Use item.id as the value for the main select
|
|
3650
|
+
return {
|
|
3651
|
+
value: item.id, // ← FIXED: Use id, not value
|
|
3652
|
+
label: item.label,
|
|
3653
|
+
// You can add selected logic if needed
|
|
3654
|
+
};
|
|
3655
|
+
});
|
|
3656
|
+
|
|
3657
|
+
// Step 2: The nested options ARE your sub-categories!
|
|
3658
|
+
// Transform the structure
|
|
3659
|
+
const subCategoriesOptions = options.map(item => ({
|
|
3660
|
+
id: item.id, // Same as main category value
|
|
3661
|
+
label: item.label + ' Technologies', // Or customize
|
|
3662
|
+
options: item.options // The nested options array
|
|
3663
|
+
}));
|
|
3664
|
+
|
|
3665
|
+
//console.log('Main categories:', mainCategoryOptions);
|
|
3666
|
+
//console.log('Sub categories:', subCategoriesOptions);
|
|
3667
|
+
|
|
3668
|
+
const mode = 'dynamicSingleSelect';
|
|
3669
|
+
|
|
3670
|
+
// Pass both to the renderer
|
|
3671
|
+
this.renderSingleSelectField(type, name, label, validate, attributes, mainCategoryOptions, subCategoriesOptions, mode);
|
|
3672
|
+
}
|
|
3753
3673
|
|
|
3754
3674
|
renderSingleSelectField(type, name, label, validate, attributes, options, subCategoriesOptions, mode) {
|
|
3755
3675
|
|
|
@@ -4356,5 +4276,557 @@ const spinner = `<div id="formiqueSpinner" style="display: flex; align-items: ce
|
|
|
4356
4276
|
}
|
|
4357
4277
|
|
|
4358
4278
|
|
|
4279
|
+
const FORMIQUE_INTERNAL_CSS = `
|
|
4280
|
+
@import url('https://fonts.googleapis.com/css2?family=Montserrat:wght@400;500;600&display=swap');
|
|
4281
|
+
|
|
4282
|
+
/* ==================== */
|
|
4283
|
+
/* BASE FORM VARIABLES */
|
|
4284
|
+
/* ==================== */
|
|
4285
|
+
|
|
4286
|
+
:root {
|
|
4287
|
+
--formique-border-radius: 6px;
|
|
4288
|
+
--formique-padding: 2rem;
|
|
4289
|
+
}
|
|
4290
|
+
/*
|
|
4291
|
+
:root {
|
|
4292
|
+
--formique-base-bg: white;
|
|
4293
|
+
--formique-base-text: #333;
|
|
4294
|
+
--formique-base-shadow: 0 10px 30px rgba(0, 0, 0, 0.1);
|
|
4295
|
+
--formique-base-label: #555;
|
|
4296
|
+
--formique-input-border: #ddd;
|
|
4297
|
+
--formique-focus-color: #6a4fbf;
|
|
4298
|
+
--formique-btn-bg: #6a4fbf;
|
|
4299
|
+
--formique-btn-text: white;
|
|
4300
|
+
--formique-btn-shadow: 0 2px 10px rgba(106, 79, 191, 0.3);
|
|
4301
|
+
--formique-border-radius: 6px;
|
|
4302
|
+
--formique-max-width: 100%;
|
|
4303
|
+
--formique-padding: 2rem;
|
|
4304
|
+
}
|
|
4305
|
+
*/
|
|
4306
|
+
/* ==================== */
|
|
4307
|
+
/* BASE FORM STYLES */
|
|
4308
|
+
/* ==================== */
|
|
4309
|
+
.formique {
|
|
4310
|
+
width: 100%;
|
|
4311
|
+
max-width: var(--formique-max-width);
|
|
4312
|
+
margin: 2rem auto;
|
|
4313
|
+
padding: var(--formique-padding);
|
|
4314
|
+
background-color: var(--formique-base-bg);
|
|
4315
|
+
border-radius: var(--formique-border-radius);
|
|
4316
|
+
box-shadow: var(--formique-base-shadow);
|
|
4317
|
+
font-family: 'Montserrat', sans-serif;
|
|
4318
|
+
color: var(--formique-base-text);
|
|
4319
|
+
transition: all 0.3s ease;
|
|
4320
|
+
box-sizing: border-box;
|
|
4321
|
+
}
|
|
4322
|
+
|
|
4323
|
+
/* Input Block */
|
|
4324
|
+
.formique .input-block {
|
|
4325
|
+
margin-bottom: 1.5rem;
|
|
4326
|
+
position: relative;
|
|
4327
|
+
}
|
|
4328
|
+
|
|
4329
|
+
.formique .input-block label {
|
|
4330
|
+
display: block;
|
|
4331
|
+
margin-bottom: 0.5rem;
|
|
4332
|
+
font-weight: 500;
|
|
4333
|
+
color: var(--formique-base-label);
|
|
4334
|
+
font-size: 0.9rem;
|
|
4335
|
+
}
|
|
4336
|
+
|
|
4337
|
+
.formique .input-block .form-input,
|
|
4338
|
+
.formique .input-block .form-control {
|
|
4339
|
+
width: 100%;
|
|
4340
|
+
padding: 0.75rem 0;
|
|
4341
|
+
border: none;
|
|
4342
|
+
border-bottom: 1px solid var(--formique-input-border);
|
|
4343
|
+
background-color: transparent;
|
|
4344
|
+
color: var(--formique-base-text);
|
|
4345
|
+
box-sizing: border-box;
|
|
4346
|
+
font-size: 1rem;
|
|
4347
|
+
transition: all 0.3s ease;
|
|
4348
|
+
}
|
|
4349
|
+
|
|
4350
|
+
.formique .input-block .form-input:focus,
|
|
4351
|
+
.formique .input-block .form-control:focus {
|
|
4352
|
+
outline: none;
|
|
4353
|
+
border-bottom-width: 2px;
|
|
4354
|
+
border-bottom-color: var(--formique-focus-color);
|
|
4355
|
+
}
|
|
4356
|
+
|
|
4357
|
+
.formique .input-block .form-input:disabled {
|
|
4358
|
+
opacity: 0.6;
|
|
4359
|
+
cursor: not-allowed;
|
|
4360
|
+
}
|
|
4361
|
+
|
|
4362
|
+
/* Fieldset General Styling */
|
|
4363
|
+
.formique fieldset {
|
|
4364
|
+
border: 1px solid var(--formique-input-border);
|
|
4365
|
+
border-radius: var(--formique-border-radius);
|
|
4366
|
+
padding: 1rem;
|
|
4367
|
+
margin-bottom: 1.5rem;
|
|
4368
|
+
background-color: var(--formique-base-bg);
|
|
4369
|
+
transition: all 0.3s ease;
|
|
4370
|
+
}
|
|
4371
|
+
|
|
4372
|
+
.formique fieldset legend {
|
|
4373
|
+
font-weight: 600;
|
|
4374
|
+
color: var(--formique-base-label);
|
|
4375
|
+
font-size: 1rem;
|
|
4376
|
+
padding: 0 0.5rem;
|
|
4377
|
+
}
|
|
4378
|
+
|
|
4379
|
+
/* Radio Group */
|
|
4380
|
+
.formique .radio-group {
|
|
4381
|
+
/* Styles are now handled by the general fieldset or input-block if used outside fieldset */
|
|
4382
|
+
}
|
|
4383
|
+
|
|
4384
|
+
.formique .radio-group legend {
|
|
4385
|
+
display: block;
|
|
4386
|
+
margin-bottom: 0.75rem;
|
|
4387
|
+
font-weight: 500;
|
|
4388
|
+
color: var(--formique-base-label);
|
|
4389
|
+
font-size: 0.9rem;
|
|
4390
|
+
}
|
|
4391
|
+
|
|
4392
|
+
.formique .radio-group div {
|
|
4393
|
+
margin-bottom: 0.5rem;
|
|
4394
|
+
display: flex;
|
|
4395
|
+
align-items: center;
|
|
4396
|
+
}
|
|
4397
|
+
|
|
4398
|
+
.formique .radio-group .form-radio-input {
|
|
4399
|
+
margin-right: 0.75rem;
|
|
4400
|
+
width: 18px;
|
|
4401
|
+
height: 18px;
|
|
4402
|
+
accent-color: var(--formique-focus-color);
|
|
4403
|
+
cursor: pointer;
|
|
4404
|
+
}
|
|
4405
|
+
|
|
4406
|
+
/* Checkbox Group */
|
|
4407
|
+
.formique .checkbox-group {
|
|
4408
|
+
/* Styles are now handled by the general fieldset or input-block if used outside fieldset */
|
|
4409
|
+
}
|
|
4410
|
+
|
|
4411
|
+
.formique .checkbox-group legend {
|
|
4412
|
+
display: block;
|
|
4413
|
+
margin-bottom: 0.75rem;
|
|
4414
|
+
font-weight: 500;
|
|
4415
|
+
color: var(--formique-base-label);
|
|
4416
|
+
font-size: 0.9rem;
|
|
4417
|
+
}
|
|
4418
|
+
|
|
4419
|
+
.formique .checkbox-group div {
|
|
4420
|
+
margin-bottom: 0.5rem;
|
|
4421
|
+
display: flex;
|
|
4422
|
+
align-items: center;
|
|
4423
|
+
}
|
|
4424
|
+
|
|
4425
|
+
.formique .checkbox-group .form-checkbox-input {
|
|
4426
|
+
margin-right: 0.75rem;
|
|
4427
|
+
width: 18px;
|
|
4428
|
+
height: 18px;
|
|
4429
|
+
accent-color: var(--formique-focus-color);
|
|
4430
|
+
cursor: pointer;
|
|
4431
|
+
}
|
|
4432
|
+
|
|
4433
|
+
/* Select (Dropdowns) */
|
|
4434
|
+
.formique .form-select {
|
|
4435
|
+
margin-bottom: 1.5rem;
|
|
4436
|
+
}
|
|
4437
|
+
|
|
4438
|
+
.formique .form-select label {
|
|
4439
|
+
display: block;
|
|
4440
|
+
margin-bottom: 0.5rem;
|
|
4441
|
+
font-weight: 500;
|
|
4442
|
+
color: var(--formique-base-label);
|
|
4443
|
+
font-size: 0.9rem;
|
|
4444
|
+
}
|
|
4445
|
+
|
|
4446
|
+
.formique .form-select .form-input { /* Changed from .form-select-input to .form-input */
|
|
4447
|
+
width: 100%;
|
|
4448
|
+
padding: 0.75rem;
|
|
4449
|
+
border: 1px solid var(--formique-input-border);
|
|
4450
|
+
border-radius: var(--formique-border-radius);
|
|
4451
|
+
background-color: var(--formique-base-bg);
|
|
4452
|
+
color: var(--formique-base-text);
|
|
4453
|
+
box-sizing: border-box;
|
|
4454
|
+
font-size: 1rem;
|
|
4455
|
+
transition: all 0.3s ease;
|
|
4456
|
+
/* Custom arrow for select element */
|
|
4457
|
+
-webkit-appearance: none;
|
|
4458
|
+
-moz-appearance: none;
|
|
4459
|
+
appearance: none;
|
|
4460
|
+
background-image: url('data:image/svg+xml;charset=US-ASCII,%3Csvg%20xmlns%3D%22http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg%22%20viewBox%3D%220%200%20256%20256%22%3E%3Cpath%20fill%3D%22%23'+encodeURIComponent(var(--formique-base-text)).substring(1)+'%22%20d%3D%22M208.5%2084.5l-80%2080a12%2012%200%2001-17%200l-80-80a12%2012%200%200117-17L128%20139l71.5-71.5a12%2012%200%200117%2017z%22%2F%3E%3C%2Fsvg%3E');
|
|
4461
|
+
background-repeat: no-repeat;
|
|
4462
|
+
background-position: right 0.75rem center;
|
|
4463
|
+
background-size: 1rem;
|
|
4464
|
+
cursor: pointer;
|
|
4465
|
+
}
|
|
4466
|
+
|
|
4467
|
+
.formique .form-select .form-input:focus { /* Changed from .form-select-input to .form-input */
|
|
4468
|
+
outline: none;
|
|
4469
|
+
border-color: var(--formique-focus-color);
|
|
4470
|
+
box-shadow: 0 0 0 2px rgba(106, 79, 191, 0.1);
|
|
4471
|
+
}
|
|
4472
|
+
|
|
4473
|
+
/* Multiple Selects */
|
|
4474
|
+
.formique .form-select .form-input[multiple] {
|
|
4475
|
+
min-height: 100px; /* Adjust as needed */
|
|
4476
|
+
padding: 0.5rem;
|
|
4477
|
+
background-image: none; /* Remove custom arrow for multiselect */
|
|
4478
|
+
}
|
|
4479
|
+
|
|
4480
|
+
/* Submit Button */
|
|
4481
|
+
.formique .form-submit-btn {
|
|
4482
|
+
display: block;
|
|
4483
|
+
width: 100%;
|
|
4484
|
+
padding: 0.875rem 1.75rem;
|
|
4485
|
+
border: none;
|
|
4486
|
+
border-radius: var(--formique-border-radius);
|
|
4487
|
+
background-color: var(--formique-btn-bg);
|
|
4488
|
+
color: var(--formique-btn-text);
|
|
4489
|
+
font-size: 1rem;
|
|
4490
|
+
font-weight: 500;
|
|
4491
|
+
cursor: pointer;
|
|
4492
|
+
transition: all 0.3s ease;
|
|
4493
|
+
box-shadow: var(--formique-btn-shadow);
|
|
4494
|
+
box-sizing: border-box;
|
|
4495
|
+
}
|
|
4496
|
+
|
|
4497
|
+
.formique .form-submit-btn:hover {
|
|
4498
|
+
transform: translateY(-1px);
|
|
4499
|
+
box-shadow: 0 4px 15px var(--formique-btn-shadow);
|
|
4500
|
+
}
|
|
4501
|
+
|
|
4502
|
+
.formique .form-submit-btn:active {
|
|
4503
|
+
transform: translateY(0);
|
|
4504
|
+
}
|
|
4505
|
+
|
|
4506
|
+
/* ==================== */
|
|
4507
|
+
/* THEME DEFINITIONS */
|
|
4508
|
+
/* ==================== */
|
|
4509
|
+
.dark-theme {
|
|
4510
|
+
--formique-base-bg: #1e1e1e;
|
|
4511
|
+
--formique-base-text: #e0e0e0;
|
|
4512
|
+
--formique-base-shadow: 0 10px 30px rgba(0, 0, 0, 0.3);
|
|
4513
|
+
--formique-base-label: #b0b0b0;
|
|
4514
|
+
--formique-input-border: #444;
|
|
4515
|
+
--formique-focus-color: #b0b0b0;
|
|
4516
|
+
--formique-btn-bg: #b0b0b0;
|
|
4517
|
+
--formique-btn-text: #1e1e1e;
|
|
4518
|
+
--formique-btn-shadow: 0 2px 10px rgba(176, 176, 176, 0.3);
|
|
4519
|
+
}
|
|
4520
|
+
|
|
4521
|
+
.light-theme {
|
|
4522
|
+
--formique-base-bg: #ffffff;
|
|
4523
|
+
--formique-base-text: #333333;
|
|
4524
|
+
--formique-base-shadow: 0 10px 30px rgba(0, 0, 0, 0.1);
|
|
4525
|
+
--formique-base-label: #555555;
|
|
4526
|
+
--formique-input-border: #dddddd;
|
|
4527
|
+
--formique-focus-color: #555555;
|
|
4528
|
+
--formique-btn-bg: #777777;
|
|
4529
|
+
--formique-btn-text: #ffffff;
|
|
4530
|
+
--formique-btn-shadow: 0 2px 10px rgba(0, 0, 0, 0.1);
|
|
4531
|
+
}
|
|
4532
|
+
|
|
4533
|
+
.pink-theme {
|
|
4534
|
+
--formique-base-bg: #ffffff;
|
|
4535
|
+
--formique-base-text: #333333;
|
|
4536
|
+
--formique-base-shadow: 0 10px 30px rgba(0, 0, 0, 0.1);
|
|
4537
|
+
--formique-base-label: #555555;
|
|
4538
|
+
--formique-input-border: #dddddd;
|
|
4539
|
+
--formique-focus-color: #ff4081;
|
|
4540
|
+
--formique-btn-bg: #ff4081;
|
|
4541
|
+
--formique-btn-text: #ffffff;
|
|
4542
|
+
--formique-btn-shadow: 0 2px 10px rgba(255, 64, 129, 0.3);
|
|
4543
|
+
}
|
|
4544
|
+
|
|
4545
|
+
.indigo-theme {
|
|
4546
|
+
--formique-base-bg: #ffffff;
|
|
4547
|
+
--formique-base-text: #333333;
|
|
4548
|
+
--formique-base-shadow: 0 10px 30px rgba(0, 0, 0, 0.1);
|
|
4549
|
+
--formique-base-label: #555555;
|
|
4550
|
+
--formique-input-border: #dddddd;
|
|
4551
|
+
--formique-focus-color: #3f51b5;
|
|
4552
|
+
--formique-btn-bg: #3f51b5;
|
|
4553
|
+
--formique-btn-text: #ffffff;
|
|
4554
|
+
--formique-btn-shadow: 0 2px 10px rgba(63, 81, 181, 0.3);
|
|
4555
|
+
}
|
|
4556
|
+
|
|
4557
|
+
.dark-blue-theme {
|
|
4558
|
+
--formique-base-bg: #0a192f;
|
|
4559
|
+
--formique-base-text: #e6f1ff;
|
|
4560
|
+
--formique-base-shadow: 0 10px 30px rgba(0, 0, 0, 0.4);
|
|
4561
|
+
--formique-base-label: #a8b2d1;
|
|
4562
|
+
--formique-input-border: #233554;
|
|
4563
|
+
--formique-focus-color: #64ffda;
|
|
4564
|
+
--formique-btn-bg: #64ffda;
|
|
4565
|
+
--formique-btn-text: #0a192f;
|
|
4566
|
+
--formique-btn-shadow: 0 2px 10px rgba(100, 255, 218, 0.3);
|
|
4567
|
+
}
|
|
4568
|
+
|
|
4569
|
+
.light-blue-theme {
|
|
4570
|
+
--formique-base-bg: #f5f9ff;
|
|
4571
|
+
--formique-base-text: #2a4365;
|
|
4572
|
+
--formique-base-shadow: 0 10px 30px rgba(66, 153, 225, 0.1);
|
|
4573
|
+
--formique-base-label: #4299e1;
|
|
4574
|
+
--formique-input-border: #bee3f8;
|
|
4575
|
+
--formique-focus-color: #3182ce;
|
|
4576
|
+
--formique-btn-bg: #3182ce;
|
|
4577
|
+
--formique-btn-text: #ffffff;
|
|
4578
|
+
--formique-btn-shadow: 0 2px 10px rgba(49, 130, 206, 0.3);
|
|
4579
|
+
}
|
|
4580
|
+
|
|
4581
|
+
.dark-orange-theme {
|
|
4582
|
+
--formique-base-bg: #2d3748;
|
|
4583
|
+
--formique-base-text: #f7fafc;
|
|
4584
|
+
--formique-base-shadow: 0 10px 30px rgba(0, 0, 0, 0.3);
|
|
4585
|
+
--formique-base-label: #cbd5e0;
|
|
4586
|
+
--formique-input-border: #4a5568;
|
|
4587
|
+
--formique-focus-color: #ed8936;
|
|
4588
|
+
--formique-btn-bg: #ed8936;
|
|
4589
|
+
--formique-btn-text: #1a202c;
|
|
4590
|
+
--formique-btn-shadow: 0 2px 10px rgba(237, 137, 54, 0.3);
|
|
4591
|
+
}
|
|
4592
|
+
|
|
4593
|
+
.bright-yellow-theme {
|
|
4594
|
+
--formique-base-bg: #ffffff;
|
|
4595
|
+
--formique-base-text: #1a202c;
|
|
4596
|
+
--formique-base-shadow: 0 10px 30px rgba(0, 0, 0, 0.1);
|
|
4597
|
+
--formique-base-label: #4a5568;
|
|
4598
|
+
--formique-input-border: #e2e8f0;
|
|
4599
|
+
--formique-focus-color: #f6e05e;
|
|
4600
|
+
--formique-btn-bg: #f6e05e;
|
|
4601
|
+
--formique-btn-text: #1a202c;
|
|
4602
|
+
--formique-btn-shadow: 0 2px 10px rgba(246, 224, 94, 0.3);
|
|
4603
|
+
}
|
|
4604
|
+
|
|
4605
|
+
.green-theme {
|
|
4606
|
+
--formique-base-bg: #ffffff;
|
|
4607
|
+
--formique-base-text: #1a202c;
|
|
4608
|
+
--formique-base-shadow: 0 10px 30px rgba(0, 0, 0, 0.1);
|
|
4609
|
+
--formique-base-label: #4a5568;
|
|
4610
|
+
--formique-input-border: #e2e8f0;
|
|
4611
|
+
--formique-focus-color: #48bb78;
|
|
4612
|
+
--formique-btn-bg: #48bb78;
|
|
4613
|
+
--formique-btn-text: #ffffff;
|
|
4614
|
+
--formique-btn-shadow: 0 2px 10px rgba(72, 187, 120, 0.3);
|
|
4615
|
+
}
|
|
4616
|
+
|
|
4617
|
+
.purple-theme {
|
|
4618
|
+
--formique-base-bg: #ffffff;
|
|
4619
|
+
--formique-base-text: #1a202c;
|
|
4620
|
+
--formique-base-shadow: 0 10px 30px rgba(0, 0, 0, 0.1);
|
|
4621
|
+
--formique-base-label: #4a5568;
|
|
4622
|
+
--formique-input-border: #e2e8f0;
|
|
4623
|
+
--formique-focus-color: #9f7aea;
|
|
4624
|
+
--formique-btn-bg: #9f7aea;
|
|
4625
|
+
--formique-btn-text: #ffffff;
|
|
4626
|
+
--formique-btn-shadow: 0 2px 10px rgba(159, 122, 234, 0.3);
|
|
4627
|
+
}
|
|
4628
|
+
|
|
4629
|
+
.midnight-blush-theme {
|
|
4630
|
+
--formique-base-bg: #1a1a2e;
|
|
4631
|
+
--formique-base-text: #e6e6e6;
|
|
4632
|
+
--formique-base-shadow: 0 10px 30px rgba(0, 0, 0, 0.4);
|
|
4633
|
+
--formique-base-label: #b8b8b8;
|
|
4634
|
+
--formique-input-border: #4e4e6a;
|
|
4635
|
+
--formique-focus-color: #f67280;
|
|
4636
|
+
--formique-btn-bg: #f67280;
|
|
4637
|
+
--formique-btn-text: #1a1a2e;
|
|
4638
|
+
--formique-btn-shadow: 0 2px 10px rgba(246, 114, 128, 0.3);
|
|
4639
|
+
}
|
|
4640
|
+
|
|
4641
|
+
.deep-blue-theme {
|
|
4642
|
+
--formique-base-bg: #0f172a;
|
|
4643
|
+
--formique-base-text: #e2e8f0;
|
|
4644
|
+
--formique-base-shadow: 0 10px 30px rgba(0, 0, 0, 0.4);
|
|
4645
|
+
--formique-base-label: #94a3b8;
|
|
4646
|
+
--formique-input-border: #1e293b;
|
|
4647
|
+
--formique-focus-color: #60a5fa;
|
|
4648
|
+
--formique-btn-bg: #60a5fa;
|
|
4649
|
+
--formique-btn-text: #0f172a;
|
|
4650
|
+
--formique-btn-shadow: 0 2px 10px rgba(96, 165, 250, 0.3);
|
|
4651
|
+
}
|
|
4652
|
+
|
|
4653
|
+
.blue-theme {
|
|
4654
|
+
--formique-base-bg: #ffffff;
|
|
4655
|
+
--formique-base-text: #1e3a8a;
|
|
4656
|
+
--formique-base-shadow: 0 10px 30px rgba(29, 78, 216, 0.1);
|
|
4657
|
+
--formique-base-label: #3b82f6;
|
|
4658
|
+
--formique-input-border: #bfdbfe;
|
|
4659
|
+
--formique-focus-color: #2563eb;
|
|
4660
|
+
--formique-btn-bg: #2563eb;
|
|
4661
|
+
--formique-btn-text: #ffffff;
|
|
4662
|
+
--formique-btn-shadow: 0 2px 10px rgba(37, 99, 235, 0.3);
|
|
4663
|
+
}
|
|
4664
|
+
|
|
4665
|
+
.brown-theme {
|
|
4666
|
+
--formique-base-bg: #f5f5f5;
|
|
4667
|
+
--formique-base-text: #3e2723;
|
|
4668
|
+
--formique-base-shadow: 0 10px 30px rgba(0, 0, 0, 0.1);
|
|
4669
|
+
--formique-base-label: #5d4037;
|
|
4670
|
+
--formique-input-border: #d7ccc8;
|
|
4671
|
+
--formique-focus-color: #8d6e63;
|
|
4672
|
+
--formique-btn-bg: #6d4c41;
|
|
4673
|
+
--formique-btn-text: #ffffff;
|
|
4674
|
+
--formique-btn-shadow: 0 2px 10px rgba(109, 76, 65, 0.3);
|
|
4675
|
+
}
|
|
4676
|
+
|
|
4677
|
+
.orange-theme {
|
|
4678
|
+
--formique-base-bg: #ffffff;
|
|
4679
|
+
--formique-base-text: #7b341e;
|
|
4680
|
+
--formique-base-shadow: 0 10px 30px rgba(0, 0, 0, 0.1);
|
|
4681
|
+
--formique-base-label: #dd6b20;
|
|
4682
|
+
--formique-input-border: #fed7aa;
|
|
4683
|
+
--formique-focus-color: #ed8936;
|
|
4684
|
+
--formique-btn-bg: #ed8936;
|
|
4685
|
+
--formique-btn-text: #ffffff;
|
|
4686
|
+
--formique-btn-shadow: 0 2px 10px rgba(237, 137, 54, 0.3);
|
|
4687
|
+
}
|
|
4688
|
+
/* ==================== */
|
|
4689
|
+
/* WIDTH CONTROL CLASSES */
|
|
4690
|
+
/* ==================== */
|
|
4691
|
+
.formique {
|
|
4692
|
+
padding: 1rem;
|
|
4693
|
+
}
|
|
4694
|
+
.formique.width-full {
|
|
4695
|
+
--formique-max-width: 100%;
|
|
4696
|
+
}
|
|
4697
|
+
|
|
4698
|
+
.formique.width-half {
|
|
4699
|
+
--formique-max-width: 50%;
|
|
4700
|
+
}
|
|
4701
|
+
|
|
4702
|
+
.formique.width-medium {
|
|
4703
|
+
--formique-max-width: 600px;
|
|
4704
|
+
}
|
|
4705
|
+
|
|
4706
|
+
.formique.width-small {
|
|
4707
|
+
--formique-max-width: 400px;
|
|
4708
|
+
}
|
|
4709
|
+
|
|
4710
|
+
.formique.width-custom {
|
|
4711
|
+
/* To be set inline or via JS */
|
|
4712
|
+
}
|
|
4713
|
+
|
|
4714
|
+
/* Spinner Container */
|
|
4715
|
+
#formiqueSpinner {
|
|
4716
|
+
display: none;
|
|
4717
|
+
align-items: center;
|
|
4718
|
+
gap: 1rem;
|
|
4719
|
+
font-family: var(--formique-font-family, 'Montserrat, sans-serif');
|
|
4720
|
+
padding: 1rem;
|
|
4721
|
+
border-radius: var(--formique-border-radius, 6px);
|
|
4722
|
+
background-color: var(--formique-base-bg);
|
|
4723
|
+
color: var(--formique-base-text);
|
|
4724
|
+
margin-top: 1rem;
|
|
4725
|
+
}
|
|
4726
|
+
|
|
4727
|
+
/* Spinner Circle */
|
|
4728
|
+
.formique-spinner {
|
|
4729
|
+
width: 1.5rem;
|
|
4730
|
+
height: 1.5rem;
|
|
4731
|
+
border: 3px solid rgba(0, 0, 0, 0.1);
|
|
4732
|
+
border-radius: 50%;
|
|
4733
|
+
border-top-color: var(--formique-btn-bg);
|
|
4734
|
+
animation: formique-spin 1s ease-in-out infinite;
|
|
4735
|
+
}
|
|
4736
|
+
|
|
4737
|
+
/* Spinner Animation */
|
|
4738
|
+
@keyframes formique-spin {
|
|
4739
|
+
to { transform: rotate(360deg); }
|
|
4740
|
+
}
|
|
4741
|
+
|
|
4742
|
+
/* Message */
|
|
4743
|
+
#formiqueSpinner .message {
|
|
4744
|
+
margin: 0;
|
|
4745
|
+
font-size: 0.9rem;
|
|
4746
|
+
color: var(--formique-focus-color);
|
|
4747
|
+
}
|
|
4748
|
+
|
|
4749
|
+
|
|
4750
|
+
.formique-success, .formique-error {
|
|
4751
|
+
/* Background with opacity to work with both themes */
|
|
4752
|
+
background-color: var(--formique-base-bg); /* Based on --formique-btn-bg */
|
|
4753
|
+
|
|
4754
|
+
/* Text styling using theme variables */
|
|
4755
|
+
color: var(--formique-focus-color);
|
|
4756
|
+
font-family: inherit;
|
|
4757
|
+
font-size: 0.95rem;
|
|
4758
|
+
|
|
4759
|
+
/* Border using focus color with opacity */
|
|
4760
|
+
border: 1px solid var(--formique-focus-color); /* Based on --formique-btn-bg */
|
|
4761
|
+
border-radius: 4px;
|
|
4762
|
+
padding: 12px 16px;
|
|
4763
|
+
margin: 16px 0;
|
|
4764
|
+
|
|
4765
|
+
/* Layout */
|
|
4766
|
+
display: flex;
|
|
4767
|
+
align-items: center;
|
|
4768
|
+
gap: 8px;
|
|
4769
|
+
|
|
4770
|
+
/* Animation */
|
|
4771
|
+
animation: fadeIn 0.3s ease-in-out;
|
|
4772
|
+
|
|
4773
|
+
/* Shadow using theme variable */
|
|
4774
|
+
box-shadow: var(--formique-base-shadow);
|
|
4775
|
+
}
|
|
4776
|
+
|
|
4777
|
+
.formique-success::before {
|
|
4778
|
+
content: "✓";
|
|
4779
|
+
color: var(--formique-btn-bg); /* Using button background color for checkmark */
|
|
4780
|
+
font-weight: bold;
|
|
4781
|
+
font-size: 1.2rem;
|
|
4782
|
+
}
|
|
4783
|
+
|
|
4784
|
+
.formique-error::before {
|
|
4785
|
+
content: "✗";
|
|
4786
|
+
color: var(--formique-btn-bg); /* Using button background color for checkmark */
|
|
4787
|
+
font-weight: bold;
|
|
4788
|
+
font-size: 1.2rem;
|
|
4789
|
+
}
|
|
4790
|
+
|
|
4791
|
+
@keyframes fadeIn {
|
|
4792
|
+
from { opacity: 0; transform: translateY(-10px); }
|
|
4793
|
+
to { opacity: 1; transform: translateY(0); }
|
|
4794
|
+
}
|
|
4795
|
+
|
|
4796
|
+
|
|
4797
|
+
/* --- */
|
|
4798
|
+
/* Specific Styles for Color Input */
|
|
4799
|
+
.formique .input-block .form-color-input {
|
|
4800
|
+
/* Restore native appearance */
|
|
4801
|
+
-webkit-appearance: auto;
|
|
4802
|
+
-moz-appearance: auto;
|
|
4803
|
+
appearance: auto;
|
|
4804
|
+
|
|
4805
|
+
/* Reset properties that typically interfere with native color inputs */
|
|
4806
|
+
padding: 2px; /* Small padding to allow native swatch to show */
|
|
4807
|
+
border: 1px solid var(--formique-input-border); /* Visible border */
|
|
4808
|
+
background-color: var(--formique-base-bg); /* Ensure it has a background */
|
|
4809
|
+
width: 50px; /* A typical width for the color swatch */
|
|
4810
|
+
height: 30px; /* A typical height for the color swatch */
|
|
4811
|
+
cursor: pointer; /* Indicates it's interactive */
|
|
4812
|
+
|
|
4813
|
+
/* Ensure border-radius and vertical alignment blend with other inputs */
|
|
4814
|
+
border-radius: var(--formique-border-radius);
|
|
4815
|
+
vertical-align: middle; /* Aligns with text if label is inline */
|
|
4816
|
+
|
|
4817
|
+
/* Override any focus border-bottom rules from general .form-input if needed */
|
|
4818
|
+
border-bottom: 1px solid var(--formique-input-border); /* Keep consistent border for focus */
|
|
4819
|
+
}
|
|
4820
|
+
|
|
4821
|
+
.formique .input-block .form-color-input:focus {
|
|
4822
|
+
outline: none; /* Remove default browser outline */
|
|
4823
|
+
border-color: var(--formique-focus-color); /* Apply theme focus color */
|
|
4824
|
+
border-bottom-color: var(--formique-focus-color); /* Ensure bottom border matches on focus */
|
|
4825
|
+
box-shadow: 0 0 0 2px rgba(var(--formique-focus-color-rgb, 106, 79, 191), 0.1); /* Optional: subtle shadow */
|
|
4826
|
+
}
|
|
4827
|
+
|
|
4828
|
+
`;
|
|
4829
|
+
|
|
4830
|
+
|
|
4359
4831
|
|
|
4360
|
-
export default Formique;
|
|
4832
|
+
export default Formique;
|