@formique/semantq 1.0.5 → 1.0.7

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 (2) hide show
  1. package/formique-semantq.js +290 -189
  2. package/package.json +1 -1
@@ -60,6 +60,23 @@ class Formique extends FormBuilder {
60
60
  asteriskHtml: '<span aria-hidden="true" style="color: red;">*</span>',
61
61
  ...formSettings
62
62
  };
63
+
64
+ this.themeColor = formSettings.themeColor || null;
65
+
66
+ this.themeColorMap = {
67
+ 'primary': {
68
+ '--formique-base-bg': '#ffffff',
69
+ '--formique-base-text': '#333333',
70
+ '--formique-base-shadow': '0 10px 30px rgba(0, 0, 0, 0.1)',
71
+ '--formique-base-label': '#555555',
72
+ '--formique-input-border': '#dddddd',
73
+ '--formique-focus-color': null, // Will be set to themeColor
74
+ '--formique-btn-bg': null, // Will be set to themeColor
75
+ '--formique-btn-text': '#ffffff',
76
+ '--formique-btn-shadow': null // Will be calculated from themeColor
77
+ }
78
+ };
79
+
63
80
  this.divClass = 'input-block';
64
81
  this.inputClass = 'form-input';
65
82
  this.radioGroupClass = 'radio-group';
@@ -82,8 +99,9 @@ class Formique extends FormBuilder {
82
99
  ];
83
100
  this.formiqueEndpoint = "https://formiqueapi.onrender.com/api/send-email";
84
101
 
102
+ // DISABLE DOM LISTENER
85
103
 
86
- document.addEventListener('DOMContentLoaded', () => {
104
+ // document.addEventListener('DOMContentLoaded', () => {
87
105
  // 1. Build the form's HTML in memory
88
106
  this.formMarkUp += this.renderFormElement(); // Adds opening <form> tag and any hidden inputs
89
107
 
@@ -156,15 +174,21 @@ class Formique extends FormBuilder {
156
174
  // Initialize dependency graph and observers after the form is rendered
157
175
  this.initDependencyGraph();
158
176
  this.registerObservers();
177
+ this.attachDynamicSelectListeners();
159
178
 
160
179
  // Apply theme
161
- if (this.formSettings.theme && this.themes.includes(this.formSettings.theme)) {
180
+ if (this.themeColor) {
181
+ this.applyCustomTheme(this.themeColor, this.formContainerId); // <--- NEW: Apply custom theme
182
+ } else if (this.formSettings.theme && this.themes.includes(this.formSettings.theme)) {
162
183
  let theme = this.formSettings.theme;
163
184
  this.applyTheme(theme, this.formContainerId);
164
185
  } else {
165
- this.applyTheme('dark', this.formContainerId);
186
+ // Fallback if no themeColor and no valid theme specified
187
+ this.applyTheme('dark', this.formContainerId); // Default to 'dark'
166
188
  }
167
- }); // DOM LISTENER WRAPPER
189
+
190
+ // DISABLE DOM LISTENER
191
+ //}); // DOM LISTENER WRAPPER
168
192
 
169
193
  // CONSTRUCTOR WRAPPER FOR FORMIQUE CLASS
170
194
  }
@@ -177,69 +201,69 @@ generateFormId() {
177
201
 
178
202
 
179
203
  initDependencyGraph() {
180
- this.dependencyGraph = {};
204
+ this.dependencyGraph = {};
205
+
206
+ this.formSchema.forEach((field) => {
207
+ const [type, name, label, validate, attributes = {}] = field;
208
+ const fieldId = attributes.id || name;
209
+
210
+ if (attributes.dependents) {
211
+ // Initialize dependency array for the parent field
212
+ this.dependencyGraph[fieldId] = attributes.dependents.map((dependentName) => {
213
+ const dependentField = this.formSchema.find(
214
+ ([, depName]) => depName === dependentName
215
+ );
216
+
217
+ if (dependentField) {
218
+ const dependentAttributes = dependentField[4] || {};
219
+ const dependentFieldId = dependentAttributes.id || dependentName; // Get dependent field ID
220
+
221
+ return {
222
+ dependent: dependentFieldId,
223
+ condition: dependentAttributes.condition || null,
224
+ };
225
+ } else {
226
+ console.warn(`Dependent field "${dependentName}" not found in schema.`);
227
+ }
228
+ });
181
229
 
182
- this.formSchema.forEach((field) => {
183
- const [type, name, label, validate, attributes = {}] = field;
184
- const fieldId = attributes.id || name;
230
+ // Add state tracking for the parent field
231
+ this.dependencyGraph[fieldId].push({ state: null });
185
232
 
186
- if (attributes.dependents) {
187
- // Initialize dependency array for the parent field
188
- this.dependencyGraph[fieldId] = attributes.dependents.map((dependentName) => {
189
- const dependentField = this.formSchema.find(
190
- ([, depName]) => depName === dependentName
191
- );
192
-
193
- if (dependentField) {
194
- const dependentAttributes = dependentField[4] || {};
195
- const dependentFieldId = dependentAttributes.id || dependentName; // Get dependent field ID
196
-
197
- return {
198
- dependent: dependentFieldId,
199
- condition: dependentAttributes.condition || null,
200
- };
201
- } else {
202
- console.warn(`Dependent field "${dependentName}" not found in schema.`);
233
+ // Attach the input change event listener to the parent field
234
+ this.attachInputChangeListener(fieldId);
203
235
  }
204
- });
205
-
206
- // Add state tracking for the parent field
207
- this.dependencyGraph[fieldId].push({ state: null });
208
-
209
- // console.log("Graph", this.dependencyGraph[fieldId]);
210
-
211
- // Attach the input change event listener to the parent field
212
- this.attachInputChangeListener(fieldId);
213
- }
214
-
215
- // Hide dependent fields initially
216
- if (attributes.dependents) {
217
-
218
- attributes.dependents.forEach((dependentName) => {
219
- const dependentField = this.formSchema.find(
220
- ([, depName]) => depName === dependentName
221
- );
222
- const dependentAttributes = dependentField ? dependentField[4] || {} : {};
223
- const dependentFieldId = dependentAttributes.id || dependentName;
224
236
 
225
- //alert(dependentFieldId);
226
-
227
- const inputBlock = document.querySelector(`#${dependentFieldId}-block`);
228
- //alert(inputBlock);
229
-
230
-
231
- if (inputBlock) {
232
- // alert(dependentName);
233
- inputBlock.style.display = 'none'; // Hide dependent field by default
237
+ // Hide dependent fields initially and set their required state
238
+ if (attributes.dependents) {
239
+ attributes.dependents.forEach((dependentName) => {
240
+ const dependentField = this.formSchema.find(
241
+ ([, depName]) => depName === dependentName
242
+ );
243
+ const dependentAttributes = dependentField ? dependentField[4] || {} : {};
244
+ const dependentFieldId = dependentAttributes.id || dependentName;
245
+
246
+ const inputBlock = document.querySelector(`#${dependentFieldId}-block`);
247
+
248
+ if (inputBlock) {
249
+ inputBlock.style.display = 'none'; // Hide dependent field by default
250
+ // Save original required state and set to false
251
+ const inputs = inputBlock.querySelectorAll('input, select, textarea');
252
+ inputs.forEach((input) => {
253
+ // Check if the input was originally required in the schema
254
+ if (input.hasAttribute('required') && input.required === true) {
255
+ input.setAttribute('data-original-required', 'true'); // Save original required state
256
+ input.required = false; // Remove required attribute when hiding
257
+ } else {
258
+ input.setAttribute('data-original-required', 'false'); // Explicitly mark as not originally required
259
+ }
260
+ });
261
+ }
262
+ });
234
263
  }
235
- });
236
- }
237
- });
238
-
239
- // console.log("Dependency Graph:", this.dependencyGraph);
264
+ });
240
265
  }
241
266
 
242
-
243
267
  // Attach Event Listeners
244
268
  attachInputChangeListener(parentField) {
245
269
  const fieldElement = document.getElementById(parentField);
@@ -341,6 +365,60 @@ registerObservers() {
341
365
  }
342
366
 
343
367
 
368
+ // --- NEW METHOD FOR DYNAMIC SELECT LISTENERS ---
369
+ attachDynamicSelectListeners() {
370
+ this.formSchema.forEach(field => {
371
+ const [type, name, label, validate, attributes = {}] = field;
372
+
373
+ if (type === 'dynamicSingleSelect') {
374
+ const mainSelectId = attributes.id || name;
375
+ const mainSelectElement = document.getElementById(mainSelectId);
376
+
377
+ if (mainSelectElement) {
378
+ mainSelectElement.addEventListener('change', (event) => {
379
+ const selectedCategory = event.target.value; // e.g., 'frontend', 'backend', 'server'
380
+
381
+ // Find all sub-category fieldsets related to this main select
382
+ const subCategoryFieldsets = document.querySelectorAll(`.${mainSelectId}-subcategory-group`);
383
+
384
+ subCategoryFieldsets.forEach(fieldset => {
385
+ const subSelect = fieldset.querySelector('select'); // Get the actual select element
386
+ if (subSelect) {
387
+ // Save original required state (if it was true) then set to false if hidden
388
+ subSelect.setAttribute('data-original-required', subSelect.required.toString());
389
+ subSelect.required = false; // Always set to false when hiding
390
+ }
391
+ fieldset.style.display = 'none'; // Hide all sub-category fieldsets initially
392
+ });
393
+
394
+ // Show the selected sub-category fieldset and manage its required state
395
+ const selectedFieldsetId = selectedCategory + '-options'; // Matches the ID format in renderSingleSelectField
396
+ const selectedFieldset = document.getElementById(selectedFieldsetId);
397
+
398
+ if (selectedFieldset) {
399
+ selectedFieldset.style.display = 'block'; // Show the selected one
400
+ const selectedSubSelect = selectedFieldset.querySelector('select');
401
+ if (selectedSubSelect) {
402
+ // Restore original required state for the visible select
403
+ selectedSubSelect.required = selectedSubSelect.getAttribute('data-original-required') === 'true';
404
+ }
405
+ }
406
+ });
407
+
408
+ // IMPORTANT: Trigger the change listener once on load if a default option is selected
409
+ // This ensures correct initial visibility and required states if there's a pre-selected main category.
410
+ // We do this by dispatching a 'change' event programmatically if the select has a value.
411
+ if (mainSelectElement.value) {
412
+ const event = new Event('change');
413
+ mainSelectElement.dispatchEvent(event);
414
+ }
415
+ } else {
416
+ console.warn(`Main dynamic select element with ID ${mainSelectId} not found.`);
417
+ }
418
+ }
419
+ });
420
+ }
421
+
344
422
  applyTheme(theme, formContainerId) {
345
423
  //const stylesheet = document.querySelector('link[formique-style]');
346
424
 
@@ -395,6 +473,67 @@ applyTheme(theme, formContainerId) {
395
473
  }
396
474
 
397
475
 
476
+
477
+ // New method to apply a custom theme based on a color
478
+ applyCustomTheme(color, formContainerId) {
479
+ const formContainer = document.getElementById(formContainerId);
480
+
481
+ if (!formContainer) {
482
+ console.error(`Form container with ID "${formContainerId}" not found. Cannot apply custom theme.`);
483
+ return;
484
+ }
485
+
486
+ // You can add 'formique' class here as well if not already added
487
+ formContainer.classList.add('formique');
488
+
489
+ // Generate a slightly darker shade for the button shadow if needed
490
+ // This is a simplified example; for robust color manipulation, consider a library
491
+ const darkenColor = (hex, percent) => {
492
+ const f = parseInt(hex.slice(1), 16);
493
+ const t = percent < 0 ? 0 : 255;
494
+ const p = percent < 0 ? percent * -1 : percent;
495
+ const R = f >> 16;
496
+ const G = (f >> 8) & 0x00FF;
497
+ const B = f & 0x0000FF;
498
+ return "#" + (0x1000000 + (Math.round((t - R) * p) + R) * 0x10000 + (Math.round((t - G) * p) + G) * 0x100 + (Math.round((t - B) * p) + B)).toString(16).slice(1);
499
+ };
500
+
501
+ const shadowColor = darkenColor(color, 0.2); // Darken the theme color by 20% for shadow
502
+
503
+ // Define the custom CSS variables, prioritizing the provided color
504
+ const customCssVars = {
505
+ '--formique-base-bg': '#ffffff', // Light theme base background
506
+ '--formique-base-text': '#333333', // Light theme base text
507
+ '--formique-base-shadow': '0 10px 30px rgba(0, 0, 0, 0.1)', // Light theme shadow
508
+ '--formique-base-label': '#555555', // Light theme label
509
+ '--formique-input-border': '#dddddd', // Light theme input border
510
+ '--formique-focus-color': color, // Set to the provided custom color
511
+ '--formique-btn-bg': color, // Set to the provided custom color
512
+ '--formique-btn-text': '#ffffff', // White text for buttons
513
+ '--formique-btn-shadow': `0 2px 10px ${shadowColor || 'rgba(0, 0, 0, 0.1)'}` // Dynamic button shadow
514
+ };
515
+
516
+ let styleContent = '';
517
+ for (const [prop, val] of Object.entries(customCssVars)) {
518
+ styleContent += ` ${prop}: ${val};\n`;
519
+ }
520
+
521
+ // Create a <style> tag for the custom theme
522
+ const styleElement = document.createElement('style');
523
+ styleElement.textContent = `
524
+ #${formContainerId}.formique {
525
+ ${styleContent}
526
+ }
527
+ `;
528
+
529
+ // Insert the style element into the head or before the form container
530
+ formContainer.parentNode.insertBefore(styleElement, formContainer);
531
+
532
+ console.log(`Applied custom theme with color: ${color} to form container: ${formContainerId}`);
533
+ }
534
+
535
+
536
+
398
537
  // renderFormElement method
399
538
  renderFormElement() {
400
539
  let formHTML = '<form';
@@ -3399,17 +3538,20 @@ this.renderSingleSelectField(type, name, label, validate, attributes, mainCatego
3399
3538
 
3400
3539
  renderSingleSelectField(type, name, label, validate, attributes, options, subCategoriesOptions, mode) {
3401
3540
 
3402
- console.log("Within");
3541
+ console.log("Within renderSingleSelectField");
3403
3542
  // Define valid validation attributes for select fields
3404
3543
  const selectValidationAttributes = ['required'];
3405
3544
 
3406
3545
  // Construct validation attributes
3407
3546
  let validationAttrs = '';
3547
+ // Store original required state for the main select
3548
+ let originalRequired = false; // <--- This variable tracks if the main select was originally required
3408
3549
  if (validate) {
3409
3550
  Object.entries(validate).forEach(([key, value]) => {
3410
3551
  if (selectValidationAttributes.includes(key)) {
3411
3552
  if (key === 'required') {
3412
3553
  validationAttrs += `${key} `;
3554
+ originalRequired = true; // Mark that it was originally required
3413
3555
  }
3414
3556
  } else {
3415
3557
  console.warn(`\x1b[31mUnsupported validation attribute '${key}' for field '${name}' of type '${type}'.\x1b[0m`);
@@ -3420,10 +3562,10 @@ console.log("Within");
3420
3562
  // Handle the binding syntax
3421
3563
  let bindingDirective = '';
3422
3564
  if (attributes.binding) {
3423
- if (typeof attributes.binding === 'string' && attributes.binding.startsWith('::')) {
3424
- bindingDirective = ` bind:value="${name}" `;
3565
+ if (typeof attributes.binding === 'string' && attributes.binding.startsWith('::')) {
3566
+ bindingDirective = ` bind:value="${name}" `;
3567
+ }
3425
3568
  }
3426
- }
3427
3569
 
3428
3570
  // Define attributes for the select field
3429
3571
  let id = attributes.id || name;
@@ -3432,7 +3574,8 @@ console.log("Within");
3432
3574
  // Handle additional attributes
3433
3575
  let additionalAttrs = '';
3434
3576
  for (const [key, value] of Object.entries(attributes)) {
3435
- if (key !== 'id' && key !== 'class' && key !== 'dependsOn' && key !== 'dependents' && value !== undefined) { if (key.startsWith('on')) {
3577
+ if (key !== 'id' && key !== 'class' && key !== 'dependsOn' && key !== 'dependents' && value !== undefined) {
3578
+ if (key.startsWith('on')) {
3436
3579
  // Handle event attributes
3437
3580
  const eventValue = value.endsWith('()') ? value.slice(0, -2) : value;
3438
3581
  additionalAttrs += ` @${key.replace(/^on/, '')}={${eventValue}}\n`;
@@ -3467,32 +3610,33 @@ console.log("Within");
3467
3610
 
3468
3611
  let inputClass = attributes.class || this.inputClass;
3469
3612
 
3470
- const onchangeAttr = (mode === 'dynamicSingleSelect' && subCategoriesOptions) ? ' onchange="handleDynamicSingleSelect(this.value,id)"' : '';
3471
-
3613
+ // Remove `onchange` from HTML; it will be handled by JavaScript event listeners
3614
+ const onchangeAttr = ''; // <--- Ensure this is an empty string
3615
+
3472
3616
  let labelDisplay;
3473
- let rawLabel;
3617
+ let rawLabel;
3474
3618
 
3475
3619
  if (mode === 'dynamicSingleSelect' && subCategoriesOptions) {
3476
- if (label.includes('-')) {
3477
- const [mainCategoryLabel] = label.split('-');
3478
- labelDisplay = mainCategoryLabel;
3479
- rawLabel = label;
3480
- } else {
3481
- labelDisplay = label;
3482
- rawLabel = label;
3483
- }
3620
+ if (label.includes('-')) {
3621
+ const [mainCategoryLabel] = label.split('-');
3622
+ labelDisplay = mainCategoryLabel;
3623
+ rawLabel = label;
3624
+ } else {
3625
+ labelDisplay = label;
3626
+ rawLabel = label;
3627
+ }
3484
3628
  } else {
3485
- labelDisplay = label;
3629
+ labelDisplay = label;
3486
3630
  }
3487
3631
 
3488
3632
 
3489
- // Construct the final HTML string
3633
+ // Construct the final HTML string for the main select
3490
3634
  let formHTML = `
3491
3635
  <fieldset class="${this.selectGroupClass}" id="${id + '-block'}">
3492
- <legend>${labelDisplay}
3636
+ <legend>${labelDisplay}
3493
3637
  ${validationAttrs.includes('required') && this.formSettings.requiredFieldIndicator ? this.formSettings.asteriskHtml : ''}
3494
3638
  </legend>
3495
- <label for="${id}"> Select ${labelDisplay}
3639
+ <label for="${id}"> Select ${labelDisplay}
3496
3640
  <select name="${name}"
3497
3641
  ${bindingDirective}
3498
3642
  ${dimensionAttrs}
@@ -3500,8 +3644,7 @@ console.log("Within");
3500
3644
  class="${inputClass}"
3501
3645
  ${additionalAttrs}
3502
3646
  ${validationAttrs}
3503
- ${onchangeAttr}
3504
- >
3647
+ data-original-required="${originalRequired}" >
3505
3648
  ${selectHTML}
3506
3649
  </select>
3507
3650
  </fieldset>
@@ -3521,122 +3664,89 @@ console.log("Within");
3521
3664
  return `\n${match}\n`;
3522
3665
  }).replace(/\n\s*\n/g, '\n'); // Remove extra blank lines
3523
3666
 
3524
- //console.log(formattedHtml);
3525
3667
  this.formMarkUp+=formattedHtml;
3526
- //return formattedHtml;
3527
-
3528
-
3529
- /* dynamicSingleSelect */
3530
3668
 
3531
- if (mode && mode ==='dynamicSingleSelect' && subCategoriesOptions) {
3532
3669
 
3670
+ /* dynamicSingleSelect - Sub-Category Generation Block */
3533
3671
 
3534
- // Find the target div with id this.formContainerId
3535
- const targetDiv = document.getElementById(this.formContainerId);
3672
+ if (mode && mode ==='dynamicSingleSelect' && subCategoriesOptions) {
3536
3673
 
3537
- let categoryId = attributes.id || name;
3674
+ const categoryId = attributes.id || name; // This is the ID of the main dynamic select ('languages')
3538
3675
 
3676
+ subCategoriesOptions.forEach(subCategory => {
3677
+ const { id, label, options: subOptions } = subCategory; // Renamed 'options' to 'subOptions' to avoid conflict
3539
3678
 
3540
- if (targetDiv) {
3541
- // Create a script element
3542
- const scriptElement = document.createElement('script');
3543
- scriptElement.textContent = `
3544
- window.handleDynamicSingleSelect = function(category, fieldsetid) {
3545
- //console.log("HERE", fieldsetid);
3679
+ // IMPORTANT: Sub-category selects are *initially hidden*
3680
+ // Therefore, by default, they are NOT required until they are revealed.
3681
+ // If your schema later allows specific sub-categories to be inherently required
3682
+ // when shown, you'd need to extract that validation from your schema here.
3683
+ // For now, they are considered non-required until JavaScript makes them required.
3684
+ let isSubCategoryRequired = false; // Default to false as they are hidden
3685
+ const subCategoryValidationAttrs = ''; // No direct 'required' in HTML initially
3546
3686
 
3547
- // Hide all subcategory fields
3548
- document.querySelectorAll(\`[class*="\${fieldsetid}"]\`).forEach(div => {
3549
- div.style.display = "none";
3550
- });
3687
+ // Build the select options HTML for sub-category
3688
+ const subSelectHTML = subOptions.map(option => {
3689
+ const isSelected = option.selected ? ' selected' : '';
3690
+ return `
3691
+ <option value="${option.value}"${isSelected}>${option.label}</option>
3692
+ `;
3693
+ }).join('');
3551
3694
 
3552
- // Show the selected category
3553
- const selectedCategoryFieldset = document.getElementById(category + '-options');
3554
- if (selectedCategoryFieldset) {
3555
- selectedCategoryFieldset.style.display = "block";
3556
- }
3557
- }
3558
- `;
3559
3695
 
3560
- // Append the script element to the target div
3561
- targetDiv.appendChild(scriptElement);
3562
- } else {
3563
- console.error(`Target div with id "${this.formContainerId}" not found.`);
3564
- }
3696
+ let subCategoryLabel;
3697
+ console.log('Label (rawLabel for sub-category):', rawLabel); // Debug log
3565
3698
 
3566
- subCategoriesOptions.forEach(subCategory => {
3567
- const { id, label, options } = subCategory;
3699
+ if (rawLabel.includes('-')) {
3700
+ subCategoryLabel = rawLabel.split('-')?.[1] + ' Options';
3701
+ } else {
3702
+ subCategoryLabel = 'options';
3703
+ }
3568
3704
 
3569
- // Build the select options HTML
3570
- const selectHTML = options.map(option => {
3571
- const isSelected = option.selected ? ' selected' : '';
3572
- return `
3573
- <option value="${option.value}"${isSelected}>${option.label}</option>
3574
- `;
3575
- }).join('');
3705
+ let optionsLabel;
3706
+ if (subCategoryLabel !== 'options') {
3707
+ optionsLabel = rawLabel.split('-')?.[1] + ' Option';
3708
+ } else {
3709
+ optionsLabel = subCategoryLabel;
3710
+ }
3576
3711
 
3577
3712
 
3578
- let subCategoryLabel;
3579
- console.log('Label:', rawLabel); // Debug log
3713
+ // Create the HTML for the sub-category fieldset and select elements
3714
+ // Added a class based on the main select's ID for easy grouping/selection
3715
+ let subFormHTML = `
3716
+ <fieldset class="${this.selectGroupClass} ${categoryId}-subcategory-group" id="${id}-options" style="display: none;"> <legend>${label} ${subCategoryLabel} ${isSubCategoryRequired && this.formSettings.requiredFieldIndicator ? this.formSettings.asteriskHtml : ''}
3717
+ </legend>
3718
+ <label for="${id}"> Select ${label} ${optionsLabel}
3719
+ </label>
3720
+ <select name="${id}"
3721
+ ${bindingDirective}
3722
+ ${dimensionAttrs}
3723
+ id="${id}"
3724
+ class="${inputClass}"
3725
+ ${additionalAttrs}
3726
+ ${subCategoryValidationAttrs}
3727
+ data-original-required="${isSubCategoryRequired}" >
3728
+ <option value="">Choose an option</option>
3729
+ ${subSelectHTML}
3730
+ </select>
3731
+ </fieldset>
3732
+ `.replace(/^\s*\n/gm, '').trim();
3733
+
3734
+ // Apply vertical layout to the <select> element and its children
3735
+ subFormHTML = subFormHTML.replace(/<select\s+([^>]*)>([\s\S]*?)<\/select>/g, (match, p1, p2) => {
3736
+ const attributes = p1.trim().split(/\s+/).map(attr => ` ${attr}`).join('\n');
3737
+ return `<select\n${attributes}\n>\n${p2.trim()}\n</select>`;
3738
+ });
3580
3739
 
3581
- if (rawLabel.includes('-')) {
3582
- subCategoryLabel = rawLabel.split('-')?.[1] + ' Options';
3583
- } else {
3584
- subCategoryLabel = 'options';
3585
- }
3740
+ // Ensure the <fieldset> block starts on a new line and remove extra blank lines
3741
+ subFormHTML = subFormHTML.replace(/(<fieldset\s+[^>]*>)/g, (match) => {
3742
+ return `\n${match}\n`;
3743
+ }).replace(/\n\s*\n/g, '\n');
3586
3744
 
3587
- let optionsLabel;
3588
- if (subCategoryLabel !== 'options') {
3589
- optionsLabel = rawLabel.split('-')?.[1] + ' Option';
3590
- } else {
3591
- optionsLabel = subCategoryLabel;
3745
+ // Append the generated HTML to formMarkUp
3746
+ this.formMarkUp += subFormHTML;
3747
+ });
3592
3748
  }
3593
-
3594
-
3595
- // Create the HTML for the fieldset and select elements
3596
- let formHTML = `
3597
- <fieldset class="${this.selectGroupClass} ${categoryId}" id="${id}-options" style="display: none;">
3598
- <legend> ${label} ${subCategoryLabel} ${this.formSettings.requiredFieldIndicator ? this.formSettings.asteriskHtml : ''}
3599
- </legend>
3600
- <label for="${id}"> Select ${label} ${optionsLabel}
3601
- </label>
3602
- <select name="${id}"
3603
- ${bindingDirective}
3604
- ${dimensionAttrs}
3605
- id="${id + '-block'}"
3606
- class="${inputClass}"
3607
- ${additionalAttrs}
3608
- ${validationAttrs}
3609
- >
3610
- <option value="">Choose an option</option>
3611
- ${selectHTML}
3612
- </select>
3613
- </fieldset>
3614
- `.replace(/^\s*\n/gm, '').trim();
3615
-
3616
- // Apply vertical layout to the <select> element and its children
3617
- formHTML = formHTML.replace(/<select\s+([^>]*)>([\s\S]*?)<\/select>/g, (match, p1, p2) => {
3618
- // Reformat attributes into a vertical layout
3619
- const attributes = p1.trim().split(/\s+/).map(attr => ` ${attr}`).join('\n');
3620
- return `<select\n${attributes}\n>\n${p2.trim()}\n</select>`;
3621
- });
3622
-
3623
- // Ensure the <fieldset> block starts on a new line and remove extra blank lines
3624
- formHTML = formHTML.replace(/(<fieldset\s+[^>]*>)/g, (match) => {
3625
- // Ensure <fieldset> starts on a new line
3626
- return `\n${match}\n`;
3627
- }).replace(/\n\s*\n/g, '\n'); // Remove extra blank lines
3628
-
3629
- // Append the generated HTML to formMarkUp
3630
- this.formMarkUp += formHTML;
3631
-
3632
- //return formHTML;
3633
- });
3634
-
3635
-
3636
3749
  }
3637
- }
3638
-
3639
-
3640
3750
 
3641
3751
  renderMultipleSelectField(type, name, label, validate, attributes, options) {
3642
3752
  // Define valid validation attributes for multiple select fields
@@ -4019,12 +4129,3 @@ const spinner = `<div id="formiqueSpinner" style="display: flex; align-items: ce
4019
4129
  export default Formique;
4020
4130
 
4021
4131
 
4022
-
4023
-
4024
-
4025
-
4026
-
4027
-
4028
-
4029
-
4030
-
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@formique/semantq",
3
- "version": "1.0.5",
3
+ "version": "1.0.7",
4
4
  "description": "Formique is a native form builder for the Semantq JS Framework",
5
5
  "main": "formique-semantq.js",
6
6
  "type": "module",