@formique/semantq 1.1.1 → 1.1.3

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.
@@ -782,51 +782,48 @@ renderForm() {
782
782
 
783
783
  // renderField method - No change needed here for this issue, but ensure it handles 'submit' type correctly if called directly
784
784
  renderField(type, name, label, validate, attributes, options, subOptions = undefined) {
785
- const fieldRenderMap = {
786
- 'text': this.renderTextField,
787
- 'email': this.renderEmailField,
788
- 'number': this.renderNumberField,
789
- 'password': this.renderPasswordField,
790
- 'textarea': this.renderTextAreaField,
791
- 'tel': this.renderTelField,
792
- 'date': this.renderDateField,
793
- 'time': this.renderTimeField,
794
- 'datetime-local': this.renderDateTimeField,
795
- 'month': this.renderMonthField,
796
- 'week': this.renderWeekField,
797
- 'url': this.renderUrlField,
798
- 'search': this.renderSearchField,
799
- 'color': this.renderColorField,
800
- 'checkbox': this.renderCheckboxField,
801
- 'radio': this.renderRadioField,
802
- 'file': this.renderFileField,
803
- 'hidden': this.renderHiddenField,
804
- 'image': this.renderImageField,
805
- 'singleSelect': this.renderSingleSelectField,
806
- 'multipleSelect': this.renderMultipleSelectField,
807
- 'dynamicSingleSelect': this.renderDynamicSingleSelectField,
808
- 'range': this.renderRangeField,
809
- 'recaptcha': this.renderRecaptchaField,
810
- 'submit': this.renderSubmitButton, // Keep this for completeness, but renderSubmitButtonElement will now handle it
811
- };
812
-
813
- const renderMethod = fieldRenderMap[type];
785
+ const fieldRenderMap = {
786
+ 'text': this.renderTextField,
787
+ 'email': this.renderEmailField,
788
+ 'number': this.renderNumberField,
789
+ 'password': this.renderPasswordField,
790
+ 'textarea': this.renderTextAreaField,
791
+ 'tel': this.renderTelField,
792
+ 'date': this.renderDateField,
793
+ 'time': this.renderTimeField,
794
+ 'datetime-local': this.renderDateTimeField,
795
+ 'month': this.renderMonthField,
796
+ 'week': this.renderWeekField,
797
+ 'url': this.renderUrlField,
798
+ 'search': this.renderSearchField,
799
+ 'color': this.renderColorField,
800
+ 'checkbox': this.renderCheckboxField,
801
+ 'radio': this.renderRadioField,
802
+ 'file': this.renderFileField,
803
+ 'hidden': this.renderHiddenField,
804
+ 'image': this.renderImageField,
805
+ 'singleSelect': this.renderSingleSelectField,
806
+ 'multipleSelect': this.renderMultipleSelectField,
807
+ 'dynamicSingleSelect': this.renderDynamicSingleSelectField,
808
+ 'range': this.renderRangeField,
809
+ 'recaptcha': this.renderRecaptchaField,
810
+ 'html': this.renderHtmlField,
811
+ 'submit': this.renderSubmitButton,
812
+ };
814
813
 
815
- if (renderMethod) {
816
- // If the type is 'submit', ensure we use the specific renderSubmitButtonElement
817
- // Although, with the filter in renderForm(), this branch for 'submit' type
818
- // might not be hit in the primary rendering flow, it's good practice.
819
- return renderMethod.call(this, type, name, label, validate, attributes, options,subOptions);
814
+ const renderMethod = fieldRenderMap[type];
820
815
 
821
- if (type === 'submit') {
822
- return this.renderSubmitButton(type, name, label, validate, attributes, options);
823
- }
824
- //return renderMethod.call(this, type, name, label, validate, attributes, options);
825
- } else {
826
- console.warn(`Unsupported field type '${type}' encountered.`);
827
- return '';
828
- }
816
+ if (renderMethod) {
817
+ // IMPORTANT: Pass ALL arguments including subOptions
818
+ return renderMethod.call(this, type, name, label, validate, attributes, options, subOptions);
819
+ } else {
820
+ console.warn(`Unsupported field type '${type}' encountered.`);
821
+ return '';
829
822
  }
823
+ }
824
+
825
+
826
+
830
827
 
831
828
 
832
829
 
@@ -3641,244 +3638,227 @@ renderCheckboxField(type, name, label, validate, attributes, options) {
3641
3638
  /* DYNAMIC SINGLE SELECT BLOCK */
3642
3639
 
3643
3640
  // Function to render the dynamic select field and update based on user selection
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
- }
3673
-
3674
- renderSingleSelectField(type, name, label, validate, attributes, options, subCategoriesOptions, mode) {
3675
-
3676
- // Define valid validation attributes for select fields
3677
- const selectValidationAttributes = ['required'];
3678
-
3679
- // Construct validation attributes
3680
- let validationAttrs = '';
3681
- // Store original required state for the main select
3682
- let originalRequired = false; // <--- This variable tracks if the main select was originally required
3683
- if (validate) {
3684
- Object.entries(validate).forEach(([key, value]) => {
3685
- if (selectValidationAttributes.includes(key)) {
3686
- if (key === 'required') {
3687
- validationAttrs += `${key} `;
3688
- originalRequired = true; // Mark that it was originally required
3689
- }
3690
- } else {
3691
- // Removed console.warn
3692
- }
3641
+ renderDynamicSingleSelectField(type, name, label, validate, attributes, options, subOptions) {
3642
+ console.log('DEBUG: renderDynamicSingleSelectField called', {
3643
+ type, name, label,
3644
+ options: options ? options.length : 'none',
3645
+ subOptions: subOptions ? subOptions.length : 'none'
3693
3646
  });
3694
- }
3695
-
3696
- // Handle the binding syntax
3697
- let bindingDirective = '';
3698
- if (attributes.binding) {
3699
- if (typeof attributes.binding === 'string' && attributes.binding.startsWith('::')) {
3700
- bindingDirective = ` bind:value="${name}" `;
3647
+
3648
+ // Check if options exist
3649
+ if (!options || !Array.isArray(options)) {
3650
+ console.warn('Dynamic single select field missing options:', name);
3651
+ options = [];
3701
3652
  }
3702
- }
3703
-
3704
- // Define attributes for the select field
3705
- let id = attributes.id || name;
3706
- let dimensionAttrs = ''; // No dimension attributes applicable for select fields
3707
-
3708
- // Handle additional attributes
3709
- let additionalAttrs = '';
3710
- for (const [key, value] of Object.entries(attributes)) {
3711
- if (key !== 'id' && key !== 'class' && key !== 'dependsOn' && key !== 'dependents' && value !== undefined) {
3712
- if (key.startsWith('on')) {
3713
- // Handle event attributes
3714
- const eventValue = value.endsWith('()') ? value.slice(0, -2) : value;
3715
- additionalAttrs += ` @${key.replace(/^on/, '')}={${eventValue}}\n`;
3716
- } else {
3717
- // Handle boolean attributes
3718
- if (value === true) {
3719
- additionalAttrs += ` ${key.replace(/_/g, '-')}\n`;
3720
- } else if (value !== false) {
3721
- // Convert underscores to hyphens and set the attribute
3722
- additionalAttrs += ` ${key.replace(/_/g, '-')}="${value}"\n`;
3653
+
3654
+ // Step 1: Extract main categories from options
3655
+ // Options should already be in the correct format from the parser
3656
+ const mainCategoryOptions = options.map(item => {
3657
+ // Handle both string and object formats
3658
+ if (typeof item === 'string') {
3659
+ return {
3660
+ value: item.toLowerCase().replace(/\s+/g, '-'),
3661
+ label: item
3662
+ };
3663
+ } else {
3664
+ // Already an object with value/label
3665
+ return {
3666
+ value: item.value || item.id || item,
3667
+ label: item.label || item.value || item
3668
+ };
3723
3669
  }
3724
- }
3670
+ });
3671
+
3672
+ // Step 2: Handle subCategoriesOptions (scenario blocks)
3673
+ let subCategoriesOptions = [];
3674
+
3675
+ if (subOptions && Array.isArray(subOptions)) {
3676
+ // Use the subOptions exactly as provided by the parser
3677
+ // They should already have the correct structure
3678
+ subCategoriesOptions = subOptions.map(item => {
3679
+ // Ensure each subCategory has the required structure
3680
+ return {
3681
+ id: item.id || item.value || '',
3682
+ label: item.label || item.id || '',
3683
+ options: Array.isArray(item.options) ? item.options : []
3684
+ };
3685
+ });
3725
3686
  }
3726
- }
3687
+
3688
+ console.log('Main categories:', mainCategoryOptions);
3689
+ console.log('Sub categories:', subCategoriesOptions);
3690
+
3691
+ // Pass both to the renderer with the mode flag
3692
+ this.renderSingleSelectField(
3693
+ type,
3694
+ name,
3695
+ label,
3696
+ validate,
3697
+ attributes,
3698
+ mainCategoryOptions,
3699
+ subCategoriesOptions,
3700
+ 'dynamicSingleSelect'
3701
+ );
3702
+ }
3727
3703
 
3728
- // Construct select options HTML based on options
3729
- let selectHTML = '';
3730
- if (Array.isArray(options)) {
3731
- // Add a default option
3732
- selectHTML += `
3733
- <option value="">Choose an option</option>
3734
- `;
3735
3704
 
3736
- // Add the provided options
3737
- selectHTML += options.map((option) => {
3738
- const isSelected = option.selected ? ' selected' : '';
3739
- return `
3740
- <option value="${option.value}"${isSelected}>${option.label}</option>
3741
- `;
3742
- }).join('');
3743
- }
3744
3705
 
3745
- let inputClass = attributes.class || this.inputClass;
3746
3706
 
3747
- // Remove `onchange` from HTML; it will be handled by JavaScript event listeners
3748
- const onchangeAttr = ''; // <--- Ensure this is an empty string
3749
3707
 
3750
- let labelDisplay;
3751
- let rawLabel;
3708
+ renderSingleSelectField(type, name, label, validate, attributes, options, subCategoriesOptions, mode) {
3709
+ // Define valid validation attributes for select fields
3710
+ const selectValidationAttributes = ['required'];
3752
3711
 
3753
- if (mode === 'dynamicSingleSelect' && subCategoriesOptions) {
3754
- if (label.includes('-')) {
3755
- const [mainCategoryLabel] = label.split('-');
3756
- labelDisplay = mainCategoryLabel;
3757
- rawLabel = label;
3758
- } else {
3759
- labelDisplay = label;
3760
- rawLabel = label;
3712
+ // Construct validation attributes
3713
+ let validationAttrs = '';
3714
+ let originalRequired = false;
3715
+ if (validate) {
3716
+ Object.entries(validate).forEach(([key, value]) => {
3717
+ if (selectValidationAttributes.includes(key)) {
3718
+ if (key === 'required') {
3719
+ validationAttrs += `${key} `;
3720
+ originalRequired = true;
3721
+ }
3722
+ }
3723
+ });
3761
3724
  }
3762
- } else {
3763
- labelDisplay = label;
3764
- }
3765
-
3766
- // Construct the final HTML string for the main select
3767
- let formHTML = `
3768
- <fieldset class="${this.selectGroupClass}" id="${id + '-block'}">
3769
- <legend>${labelDisplay}
3770
- ${validationAttrs.includes('required') && this.formSettings.requiredFieldIndicator ? this.formSettings.asteriskHtml : ''}
3771
- </legend>
3772
- <label for="${id}"> Select ${labelDisplay}
3773
- <select name="${name}"
3774
- ${bindingDirective}
3775
- ${dimensionAttrs}
3776
- id="${id}"
3777
- class="${inputClass}"
3778
- ${additionalAttrs}
3779
- ${validationAttrs}
3780
- data-original-required="${originalRequired}" >
3781
- ${selectHTML}
3782
- </select>
3783
- </fieldset>
3784
- `.replace(/^\s*\n/gm, '').trim();
3785
-
3786
- // FIXED: Apply vertical layout to the <select> element and its children
3787
- // Only split on actual attribute boundaries, not within attribute values
3788
- let formattedHtml = formHTML.replace(/<select\s+([^>]*)>([\s\S]*?)<\/select>/g, (match, p1, p2) => {
3789
- // Use regex to match complete attribute="value" pairs
3790
- const attributes = p1.match(/(\w+(?:-\w+)*=("[^"]*"|'[^']*'|\w+)|[^=\s]+(?!\s*=))/g) || [];
3791
- const formattedAttributes = attributes.map(attr => ` ${attr}`).join('\n');
3792
- return `<select\n${formattedAttributes}\n>\n${p2.trim()}\n</select>`;
3793
- });
3794
-
3795
- // Ensure the <fieldset> block starts on a new line and remove extra blank lines
3796
- formattedHtml = formattedHtml.replace(/(<fieldset\s+[^>]*>)/g, (match) => {
3797
- // Ensure <fieldset> starts on a new line
3798
- return `\n${match}\n`;
3799
- }).replace(/\n\s*\n/g, '\n'); // Remove extra blank lines
3800
-
3801
- this.formMarkUp+=formattedHtml;
3802
-
3803
3725
 
3804
- /* dynamicSingleSelect - Sub-Category Generation Block */
3805
-
3806
- if (mode && mode ==='dynamicSingleSelect' && subCategoriesOptions) {
3807
-
3808
- const categoryId = attributes.id || name; // This is the ID of the main dynamic select ('languages')
3726
+ // Handle the binding syntax
3727
+ let bindingDirective = '';
3728
+ if (attributes.binding) {
3729
+ if (typeof attributes.binding === 'string' && attributes.binding.startsWith('::')) {
3730
+ bindingDirective = ` bind:value="${name}" `;
3731
+ }
3732
+ }
3809
3733
 
3810
- subCategoriesOptions.forEach((subCategory) => {
3811
- const { id, label, options: subOptions } = subCategory; // Renamed 'options' to 'subOptions' to avoid conflict
3734
+ // Define attributes for the select field
3735
+ let id = attributes.id || name;
3736
+ let dimensionAttrs = '';
3812
3737
 
3813
- // IMPORTANT: Sub-category selects are *initially hidden*
3814
- // Therefore, by default, they are NOT required until they are revealed.
3815
- let isSubCategoryRequired = false; // Default to false as they are hidden
3816
- const subCategoryValidationAttrs = ''; // No direct 'required' in HTML initially
3738
+ // Handle additional attributes
3739
+ let additionalAttrs = '';
3740
+ for (const [key, value] of Object.entries(attributes)) {
3741
+ if (key !== 'id' && key !== 'class' && key !== 'dependsOn' && key !== 'dependents' && value !== undefined) {
3742
+ if (key.startsWith('on')) {
3743
+ const eventValue = value.endsWith('()') ? value.slice(0, -2) : value;
3744
+ additionalAttrs += ` @${key.replace(/^on/, '')}={${eventValue}}\n`;
3745
+ } else {
3746
+ if (value === true) {
3747
+ additionalAttrs += ` ${key.replace(/_/g, '-')}\n`;
3748
+ } else if (value !== false) {
3749
+ additionalAttrs += ` ${key.replace(/_/g, '-')}="${value}"\n`;
3750
+ }
3751
+ }
3752
+ }
3753
+ }
3817
3754
 
3818
- // Build the select options HTML for sub-category
3819
- const subSelectHTML = subOptions.map(option => {
3820
- const isSelected = option.selected ? ' selected' : '';
3821
- return `
3822
- <option value="${option.value}"${isSelected}>${option.label}</option>
3755
+ // Construct select options HTML based on options
3756
+ let selectHTML = '';
3757
+ if (Array.isArray(options) && options.length > 0) {
3758
+ // Add a default option
3759
+ selectHTML += `
3760
+ <option value="">Choose an option</option>
3823
3761
  `;
3824
- }).join('');
3825
-
3826
3762
 
3827
- let subCategoryLabel;
3828
-
3829
- if (rawLabel.includes('-')) {
3830
- subCategoryLabel = rawLabel.split('-')?.[1] + ' Options';
3831
- } else {
3832
- subCategoryLabel = 'options';
3833
- }
3834
-
3835
- let optionsLabel;
3836
- if (subCategoryLabel !== 'options') {
3837
- optionsLabel = rawLabel.split('-')?.[1] + ' Option';
3838
- } else {
3839
- optionsLabel = subCategoryLabel;
3840
- }
3763
+ // Add the provided options
3764
+ selectHTML += options.map((option) => {
3765
+ const optionValue = option.value || option;
3766
+ const optionLabel = option.label || option;
3767
+ const isSelected = option.selected ? ' selected' : '';
3768
+ return `
3769
+ <option value="${optionValue}"${isSelected}>${optionLabel}</option>
3770
+ `;
3771
+ }).join('');
3772
+ }
3841
3773
 
3774
+ let inputClass = attributes.class || this.inputClass;
3842
3775
 
3843
- // Create the HTML for the sub-category fieldset and select elements
3844
- // Added a class based on the main select's ID for easy grouping/selection
3845
- let subFormHTML = `
3846
- <fieldset class="${this.selectGroupClass} ${categoryId}" id="${id}" style="display: none;"> <legend>${label} ${subCategoryLabel} ${isSubCategoryRequired && this.formSettings.requiredFieldIndicator ? this.formSettings.asteriskHtml : ''}
3847
- </legend>
3848
- <label for="${id}"> Select ${label} ${optionsLabel}
3849
- </label>
3850
- <select name="${id}"
3776
+ // Construct the final HTML string for the main select
3777
+ let formHTML = `
3778
+ <fieldset class="${this.selectGroupClass}" id="${id + '-block'}">
3779
+ <legend>${label}
3780
+ ${validationAttrs.includes('required') && this.formSettings.requiredFieldIndicator ? this.formSettings.asteriskHtml : ''}
3781
+ </legend>
3782
+ <label for="${id}"> Select ${label}
3783
+ <select name="${name}"
3851
3784
  ${bindingDirective}
3852
3785
  ${dimensionAttrs}
3853
3786
  id="${id}"
3854
3787
  class="${inputClass}"
3855
3788
  ${additionalAttrs}
3856
- ${subCategoryValidationAttrs}
3857
- data-original-required="${isSubCategoryRequired}" >
3858
- <option value="">Choose an option</option>
3859
- ${subSelectHTML}
3860
- </select>
3861
- </fieldset>
3862
- `.replace(/^\s*\n/gm, '').trim();
3863
-
3864
- // FIXED: Apply the same corrected formatting to sub-category selects
3865
- subFormHTML = subFormHTML.replace(/<select\s+([^>]*)>([\s\S]*?)<\/select>/g, (match, p1, p2) => {
3789
+ ${validationAttrs}
3790
+ data-original-required="${originalRequired}" >
3791
+ ${selectHTML}
3792
+ </select>
3793
+ </fieldset>
3794
+ `.replace(/^\s*\n/gm, '').trim();
3795
+
3796
+ // Format the HTML
3797
+ let formattedHtml = formHTML.replace(/<select\s+([^>]*)>([\s\S]*?)<\/select>/g, (match, p1, p2) => {
3866
3798
  const attributes = p1.match(/(\w+(?:-\w+)*=("[^"]*"|'[^']*'|\w+)|[^=\s]+(?!\s*=))/g) || [];
3867
3799
  const formattedAttributes = attributes.map(attr => ` ${attr}`).join('\n');
3868
3800
  return `<select\n${formattedAttributes}\n>\n${p2.trim()}\n</select>`;
3869
- });
3801
+ });
3870
3802
 
3871
- // Ensure the <fieldset> block starts on a new line and remove extra blank lines
3872
- subFormHTML = subFormHTML.replace(/(<fieldset\s+[^>]*>)/g, (match) => {
3873
- return `\n${match}\n`;
3874
- }).replace(/\n\s*\n/g, '\n');
3803
+ this.formMarkUp += formattedHtml;
3875
3804
 
3876
- // Append the generated HTML to formMarkUp
3877
- this.formMarkUp += subFormHTML;
3878
- });
3879
- }
3880
- }
3805
+ /* dynamicSingleSelect - Sub-Category Generation Block */
3806
+ if (mode === 'dynamicSingleSelect' && subCategoriesOptions && Array.isArray(subCategoriesOptions) && subCategoriesOptions.length > 0) {
3807
+ const categoryId = attributes.id || name;
3808
+
3809
+ subCategoriesOptions.forEach((subCategory) => {
3810
+ // Skip invalid subCategories
3811
+ if (!subCategory || !subCategory.id) {
3812
+ console.warn('Invalid subCategory in dynamic select:', subCategory);
3813
+ return;
3814
+ }
3815
+
3816
+ const { id, label: subLabel, options: subOptions } = subCategory;
3817
+
3818
+ // Ensure subOptions is an array
3819
+ const subOptionArray = Array.isArray(subOptions) ? subOptions : [];
3820
+
3821
+ // Build the select options HTML for sub-category
3822
+ const subSelectHTML = subOptionArray.length > 0 ?
3823
+ subOptionArray.map(option => {
3824
+ const optionValue = option.value || option;
3825
+ const optionLabel = option.label || option;
3826
+ const isSelected = option.selected ? ' selected' : '';
3827
+ return `
3828
+ <option value="${optionValue}"${isSelected}>${optionLabel}</option>
3829
+ `;
3830
+ }).join('') :
3831
+ '<option value="">No options available</option>';
3832
+
3833
+ // Create the HTML for the sub-category fieldset
3834
+ let subFormHTML = `
3835
+ <fieldset class="${this.selectGroupClass} ${categoryId}" id="${id}" style="display: none;">
3836
+ <legend>${subLabel || id}</legend>
3837
+ <label for="${id}"> Select ${subLabel || id}</label>
3838
+ <select name="${id}"
3839
+ ${bindingDirective}
3840
+ ${dimensionAttrs}
3841
+ id="${id}"
3842
+ class="${inputClass}"
3843
+ ${additionalAttrs}
3844
+ data-original-required="false">
3845
+ <option value="">Choose an option</option>
3846
+ ${subSelectHTML}
3847
+ </select>
3848
+ </fieldset>
3849
+ `.replace(/^\s*\n/gm, '').trim();
3850
+
3851
+ // Format the HTML
3852
+ subFormHTML = subFormHTML.replace(/<select\s+([^>]*)>([\s\S]*?)<\/select>/g, (match, p1, p2) => {
3853
+ const attributes = p1.match(/(\w+(?:-\w+)*=("[^"]*"|'[^']*'|\w+)|[^=\s]+(?!\s*=))/g) || [];
3854
+ const formattedAttributes = attributes.map(attr => ` ${attr}`).join('\n');
3855
+ return `<select\n${formattedAttributes}\n>\n${p2.trim()}\n</select>`;
3856
+ });
3881
3857
 
3858
+ this.formMarkUp += subFormHTML;
3859
+ });
3860
+ }
3861
+ }
3882
3862
 
3883
3863
 
3884
3864
  renderMultipleSelectField(type, name, label, validate, attributes, options) {
@@ -4189,10 +4169,42 @@ renderRangeField(type, name, label, validate, attributes) {
4189
4169
 
4190
4170
 
4191
4171
 
4172
+ /* END DYNAMIC SINGLE SELECT BLOCK */
4192
4173
 
4193
4174
 
4194
-
4195
- /* END DYNAMIC SINGLE SELECT BLOCK */
4175
+ renderHtmlField(type, element, contents, validate, attributes) {
4176
+ // Get the id from attributes or generate one
4177
+ const id = attributes.id || `html-${Math.random().toString(36).substr(2, 9)}`;
4178
+
4179
+ // Build class string
4180
+ let elementClass = 'html-content';
4181
+ if ('class' in attributes) {
4182
+ elementClass = attributes.class;
4183
+ }
4184
+
4185
+ // Build additional attributes (excluding id and class)
4186
+ let additionalAttrs = '';
4187
+ for (const [key, value] of Object.entries(attributes)) {
4188
+ if (key !== 'id' && key !== 'class' && value !== undefined) {
4189
+ if (value === true) {
4190
+ additionalAttrs += ` ${key}`;
4191
+ } else if (value !== false) {
4192
+ additionalAttrs += ` ${key}="${value}"`;
4193
+ }
4194
+ }
4195
+ }
4196
+
4197
+ // Construct HTML with form-group wrapper
4198
+ const formHTML = `
4199
+ <div class="form-group" id="${id}-block">
4200
+ <${element} id="${id}" class="${elementClass}"${additionalAttrs}>
4201
+ ${contents}
4202
+ </${element}>
4203
+ </div>
4204
+ `;
4205
+
4206
+ this.formMarkUp += formHTML;
4207
+ }
4196
4208
 
4197
4209
 
4198
4210
 
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@formique/semantq",
3
- "version": "1.1.1",
3
+ "version": "1.1.3",
4
4
  "description": "Formique is a native form builder for the Semantq JS Framework",
5
5
  "main": "formique-semantq.js",
6
6
  "type": "module",