@plusscommunities/pluss-feature-builder-web-a 1.0.2-beta.7 → 1.0.2-beta.8

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/dist/index.cjs.js CHANGED
@@ -206,14 +206,9 @@ const selectDefinitionMode = state => {
206
206
 
207
207
  // Check if we have a definition loaded or if we've determined the mode
208
208
  // This is used by hiddenFromFeaturePicker to determine if feature should be shown
209
- // When mode is "create", definition is null but we've determined the feature doesn't exist
210
- // When mode is "edit", definition exists and we've determined the feature exists
211
209
  const selectHasDefinition = state => {
212
210
  const definition = selectDefinition(state);
213
- const mode = selectDefinitionMode(state);
214
- // Consider feature "loaded" if definition exists OR mode is set
215
- // Mode being set means we've successfully fetched and determined the state
216
- return !!definition || !!mode;
211
+ return !!definition;
217
212
  };
218
213
 
219
214
  // ============ LISTINGS SELECTORS ============
@@ -1779,10 +1774,10 @@ const BaseFieldConfig = props => {
1779
1774
  alwaysShowLabel: true
1780
1775
  }), setMaxImages && /*#__PURE__*/React__default["default"].createElement(GenericInput$1, {
1781
1776
  type: "number",
1782
- value: maxImages || 10,
1783
- placeholder: "10",
1777
+ value: maxImages || 16,
1778
+ placeholder: "16",
1784
1779
  label: "Maximum Images",
1785
- onChange: e => setMaxImages(parseInt(e.target.value) || 10),
1780
+ onChange: e => setMaxImages(parseInt(e.target.value) || 16),
1786
1781
  className: modules_18fc9e14.fieldSpacing,
1787
1782
  alwaysShowLabel: true
1788
1783
  }), setMaxFileSize && /*#__PURE__*/React__default["default"].createElement(GenericInput$1, {
@@ -1908,8 +1903,8 @@ var css$g = "/* Simple listing field styling - clean vertical layout */\n\n.List
1908
1903
  var modules_2b7292f7 = {"listingField":"ListingField_module_listingField__19044565","listingField__header":"ListingField_module_listingField__header__19044565","listingField__icon":"ListingField_module_listingField__icon__19044565","listingField__content":"ListingField_module_listingField__content__19044565","listingField__title":"ListingField_module_listingField__title__19044565","listingField__description":"ListingField_module_listingField__description__19044565","listingField--error":"ListingField_module_listingField_Error__19044565","requiredAsterisk":"ListingField_module_requiredAsterisk__19044565","listingField__error":"ListingField_module_listingField__error__19044565","hasError":"ListingField_module_hasError__19044565","genericInput":"ListingField_module_genericInput__19044565","imageInputOuter-single":"ListingField_module_imageInputOuterSingle__19044565","imageInputOuter-grid":"ListingField_module_imageInputOuterGrid__19044565","FileInput":"ListingField_module_FileInput__19044565","imageInput":"ListingField_module_imageInput__19044565","file-input":"ListingField_module_fileInput__19044565","image-container":"ListingField_module_imageContainer__19044565","image-grid":"ListingField_module_imageGrid__19044565"};
1909
1904
  n(css$g,{});
1910
1905
 
1911
- var css$f = "/* ListingGalleryInput BEM CSS Module */\n\n/* Gallery container styles */\n.ListingGalleryInput_module_galleryContainer__7d5a44db {\n\tmargin-top: 0.75rem;\n}\n\n/* Error border wrapper */\n.ListingGalleryInput_module_galleryErrorWrapper__7d5a44db {\n\tborder: 1px solid var(--colour-error);\n\tborder-radius: var(--border-radius-base);\n\tpadding: 0.25rem;\n\tbackground-color: var(--colour-error-light, rgba(220, 53, 69, 0.05));\n}\n\n/* Image preview grid container */\n.ListingGalleryInput_module_imagePreviewContainer__7d5a44db {\n\tmargin-top: 1rem;\n}\n\n.ListingGalleryInput_module_imageGrid__7d5a44db {\n\tdisplay: grid;\n\tgrid-template-columns: repeat(var(--columns, 4), 1fr);\n\tgap: 1rem;\n\tmargin-top: 0.5rem;\n}\n\n/* Responsive grid for different screen sizes */\n@media (max-width: 768px) {\n\t.ListingGalleryInput_module_imageGrid__7d5a44db {\n\t\tgrid-template-columns: repeat(3, 1fr);\n\t\tgap: 0.75rem;\n\t}\n}\n\n@media (max-width: 480px) {\n\t.ListingGalleryInput_module_imageGrid__7d5a44db {\n\t\tgrid-template-columns: repeat(2, 1fr);\n\t\tgap: 0.5rem;\n\t}\n}\n\n/* Individual image item */\n.ListingGalleryInput_module_imageItem__7d5a44db {\n\tposition: relative;\n\tborder-radius: var(--border-radius-lg);\n\toverflow: hidden;\n\tbackground-color: var(--bg-bluegrey);\n\ttransition:\n\t\ttransform var(--transition-base) ease,\n\t\tbox-shadow var(--transition-base) ease;\n}\n\n.ListingGalleryInput_module_imageItem__7d5a44db:hover {\n\ttransform: translateY(-2px);\n\tbox-shadow: var(--shadow-lg);\n}\n\n.ListingGalleryInput_module_imageThumbnail__7d5a44db {\n\twidth: 100%;\n\theight: 100px;\n\tobject-fit: cover;\n\tdisplay: block;\n\taspect-ratio: 1;\n}\n\n/* Remove image button */\n.ListingGalleryInput_module_removeImageButton__7d5a44db {\n\tposition: absolute;\n\ttop: 0.5rem;\n\tright: 0.5rem;\n\tbackground: transparent;\n\tcolor: var(--colour-branding-primary);\n\tborder: none;\n\tborder-radius: var(--border-radius-full);\n\twidth: 1.75rem;\n\theight: 1.75rem;\n\tdisplay: flex;\n\talign-items: center;\n\tjustify-content: center;\n\tcursor: pointer;\n\topacity: 0;\n\ttransition: opacity var(--transition-base) ease;\n}\n\n.ListingGalleryInput_module_imageItem__7d5a44db:hover .ListingGalleryInput_module_removeImageButton__7d5a44db {\n\topacity: 1;\n}\n\n.ListingGalleryInput_module_removeImageButton__7d5a44db:hover:not(:disabled) {\n\tcolor: var(--colour-branding-light);\n}\n\n.ListingGalleryInput_module_removeImageButton__7d5a44db:disabled {\n\topacity: 0.5;\n\tcursor: not-allowed;\n}\n\n/* Error message styling */\n.ListingGalleryInput_module_errorMessage__7d5a44db {\n\tcolor: var(--colour-red);\n\tmargin-top: 0.5rem;\n\tdisplay: block;\n}\n\n/* Help text styling */\n.ListingGalleryInput_module_helpText__7d5a44db {\n\tcolor: var(--text-bluegrey);\n\tmargin-top: 0.5rem;\n\tdisplay: block;\n}\n\n/* Validation hints */\n.ListingGalleryInput_module_validationHint__7d5a44db {\n\tcolor: var(--text-bluegrey);\n\tmargin-top: 0.25rem;\n\tdisplay: block;\n\tfont-size: var(--font-size-xxs);\n}\n\n/* Form label styling */\n.ListingGalleryInput_module_formLabel__7d5a44db {\n\tdisplay: block;\n\tmargin-bottom: 8px;\n}\n\n/* Help text for image count */\n.ListingGalleryInput_module_imageCountText__7d5a44db {\n\tmargin-bottom: 0.5rem;\n\tdisplay: block;\n}\n";
1912
- var modules_2a7847a1 = {"galleryContainer":"ListingGalleryInput_module_galleryContainer__7d5a44db","galleryErrorWrapper":"ListingGalleryInput_module_galleryErrorWrapper__7d5a44db","imagePreviewContainer":"ListingGalleryInput_module_imagePreviewContainer__7d5a44db","imageGrid":"ListingGalleryInput_module_imageGrid__7d5a44db","imageItem":"ListingGalleryInput_module_imageItem__7d5a44db","imageThumbnail":"ListingGalleryInput_module_imageThumbnail__7d5a44db","removeImageButton":"ListingGalleryInput_module_removeImageButton__7d5a44db","errorMessage":"ListingGalleryInput_module_errorMessage__7d5a44db","helpText":"ListingGalleryInput_module_helpText__7d5a44db","validationHint":"ListingGalleryInput_module_validationHint__7d5a44db","formLabel":"ListingGalleryInput_module_formLabel__7d5a44db","imageCountText":"ListingGalleryInput_module_imageCountText__7d5a44db"};
1906
+ var css$f = "/* ListingGalleryInput BEM CSS Module */\n\n/* Gallery container styles */\n.ListingGalleryInput_module_galleryContainer__b1316031 {\n\tmargin-top: 0.75rem;\n\t\tmax-width:200px;\n}\n\n/* Error border wrapper */\n.ListingGalleryInput_module_galleryErrorWrapper__b1316031 {\n\tborder: 1px solid var(--colour-error);\n\tborder-radius: var(--border-radius-base);\n\tpadding: 0.25rem;\n\tbackground-color: var(--colour-error-light, rgba(220, 53, 69, 0.05));\n}\n\n/* Image preview grid container */\n.ListingGalleryInput_module_imagePreviewContainer__b1316031 {\n\tmargin-top: 1rem;\n}\n\n.ListingGalleryInput_module_imageGrid__b1316031 {\n\tdisplay: grid;\n grid-template-columns: repeat(4, 160px);\n\tgap: 1rem;\n\tmargin-top: 0.5rem;\n}\n\n/* Responsive grid for different screen sizes */\n@media (max-width: 768px) {\n\t.ListingGalleryInput_module_imageGrid__b1316031 {\n\t\tgrid-template-columns: repeat(3, 1fr);\n\t\tgap: 0.75rem;\n\t}\n}\n\n@media (max-width: 480px) {\n\t.ListingGalleryInput_module_imageGrid__b1316031 {\n\t\tgrid-template-columns: repeat(2, 1fr);\n\t\tgap: 0.5rem;\n\t}\n}\n\n/* Individual image item */\n.ListingGalleryInput_module_imageItem__b1316031 {\n\tposition: relative;\n\tborder-radius: var(--border-radius-lg);\n\toverflow: hidden;\n\tbackground-color: var(--bg-bluegrey);\n\ttransition:\n\t\ttransform var(--transition-base) ease,\n\t\tbox-shadow var(--transition-base) ease;\n}\n\n.ListingGalleryInput_module_imageItem__b1316031:hover {\n\ttransform: translateY(-2px);\n\tbox-shadow: var(--shadow-lg);\n}\n\n.ListingGalleryInput_module_imageThumbnail__b1316031 {\n\twidth: 100%;\n\theight: 100px;\n\tobject-fit: cover;\n\tdisplay: block;\n\taspect-ratio: 1;\n}\n\n/* Remove image button */\n.ListingGalleryInput_module_removeImageButton__b1316031 {\n\tposition: absolute;\n\ttop: 0.5rem;\n\tright: 0.5rem;\n\tbackground: transparent;\n\tcolor: var(--colour-branding-primary);\n\tborder: none;\n\tborder-radius: var(--border-radius-full);\n\twidth: 1.75rem;\n\theight: 1.75rem;\n\tdisplay: flex;\n\talign-items: center;\n\tjustify-content: center;\n\tcursor: pointer;\n\topacity: 0;\n\ttransition: opacity var(--transition-base) ease;\n}\n\n.ListingGalleryInput_module_imageItem__b1316031:hover .ListingGalleryInput_module_removeImageButton__b1316031 {\n\topacity: 1;\n}\n\n.ListingGalleryInput_module_removeImageButton__b1316031:hover:not(:disabled) {\n\tcolor: var(--colour-branding-light);\n}\n\n.ListingGalleryInput_module_removeImageButton__b1316031:disabled {\n\topacity: 0.5;\n\tcursor: not-allowed;\n}\n\n/* Error message styling */\n.ListingGalleryInput_module_errorMessage__b1316031 {\n\tcolor: var(--colour-red);\n\tmargin-top: 0.5rem;\n\tdisplay: block;\n}\n\n/* Help text styling */\n.ListingGalleryInput_module_helpText__b1316031 {\n\tcolor: var(--text-bluegrey);\n\tmargin-top: 0.5rem;\n\tdisplay: block;\n}\n\n/* Validation hints */\n.ListingGalleryInput_module_validationHint__b1316031 {\n\tcolor: var(--text-bluegrey);\n\tmargin-top: 0.25rem;\n\tdisplay: block;\n\tfont-size: var(--font-size-xxs);\n}\n\n/* Form label styling */\n.ListingGalleryInput_module_formLabel__b1316031 {\n\tdisplay: block;\n\tmargin-bottom: 8px;\n}\n\n/* Help text for image count */\n.ListingGalleryInput_module_imageCountText__b1316031 {\n\tmargin-bottom: 0.5rem;\n\tdisplay: block;\n}\n";
1907
+ var modules_2a7847a1 = {"galleryContainer":"ListingGalleryInput_module_galleryContainer__b1316031","galleryErrorWrapper":"ListingGalleryInput_module_galleryErrorWrapper__b1316031","imagePreviewContainer":"ListingGalleryInput_module_imagePreviewContainer__b1316031","imageGrid":"ListingGalleryInput_module_imageGrid__b1316031","imageItem":"ListingGalleryInput_module_imageItem__b1316031","imageThumbnail":"ListingGalleryInput_module_imageThumbnail__b1316031","removeImageButton":"ListingGalleryInput_module_removeImageButton__b1316031","errorMessage":"ListingGalleryInput_module_errorMessage__b1316031","helpText":"ListingGalleryInput_module_helpText__b1316031","validationHint":"ListingGalleryInput_module_validationHint__b1316031","formLabel":"ListingGalleryInput_module_formLabel__b1316031","imageCountText":"ListingGalleryInput_module_imageCountText__b1316031"};
1913
1908
  n(css$f,{});
1914
1909
 
1915
1910
  const ListingGalleryInput = _ref => {
@@ -2814,7 +2809,7 @@ const SideBarInner = props => {
2814
2809
 
2815
2810
  // Build sidebar items based on mode
2816
2811
  const buildSidebarItems = () => {
2817
- const isWizardMode = mode === "create" || mode === "edit";
2812
+ const isWizardMode = mode === "create";
2818
2813
  return steps.map((step, index) => {
2819
2814
  const isCompleted = selectIsStepComplete(step.key);
2820
2815
  const isAccessible = selectIsStepAccessible(step.key);
@@ -2833,8 +2828,8 @@ const SideBarInner = props => {
2833
2828
  isFontAwesome: true,
2834
2829
  // Enhanced completion indicator
2835
2830
  completed: isCompleted,
2836
- // Disable all navigation in wizard mode
2837
- disabled: isWizardMode || mode === "create" && !isAccessible
2831
+ // Disable all navigation in create mode, otherwise respect accessibility
2832
+ disabled: mode === "create" || !isAccessible
2838
2833
  };
2839
2834
  return itemProps;
2840
2835
  });
@@ -2858,7 +2853,7 @@ const SideBarInner = props => {
2858
2853
 
2859
2854
  // Add effect to manually attach click handlers since HubSidebar might not use onclick properly
2860
2855
  React.useEffect(() => {
2861
- const isWizardMode = mode === "create" || mode === "edit";
2856
+ const isWizardMode = mode === "create";
2862
2857
  const attachClickHandlers = () => {
2863
2858
  const stepsWithUrls = [{
2864
2859
  key: "overview",
@@ -5367,7 +5362,7 @@ const DEFAULT_NEW_FIELD = {
5367
5362
  // Default to not using as summary for description fields
5368
5363
  minImages: 1,
5369
5364
  // Gallery-specific default
5370
- maxImages: 10,
5365
+ maxImages: 16,
5371
5366
  // Gallery-specific default
5372
5367
  maxFileSize: "5MB",
5373
5368
  // Gallery-specific default
@@ -5420,7 +5415,7 @@ function createNewField(id) {
5420
5415
  baseField.values.label = "Image Gallery";
5421
5416
  baseField.values.helpText = "Upload multiple images to create a gallery";
5422
5417
  baseField.values.minImages = 1;
5423
- baseField.values.maxImages = 10;
5418
+ baseField.values.maxImages = 16;
5424
5419
  baseField.values.maxFileSize = "5MB";
5425
5420
  baseField.values.allowedTypes = ["image/jpeg", "image/png", "image/webp"];
5426
5421
  const _baseField$values2 = baseField.values,
@@ -6639,8 +6634,8 @@ const ListingCTAInput = _ref => {
6639
6634
  }));
6640
6635
  };
6641
6636
 
6642
- var css$6 = "/* Enhanced File Input Styles - Based on existing PlussCore FileInput styling */\n\n/* Main container for enhanced file input */\n.ListingFileInput_module_listingFileInput__bc8e3553 {\n\twidth: 100%;\n}\n\n/* Drop zone area - reusing existing imageInput styling */\n.ListingFileInput_module_listingFileInput__dropZone__bc8e3553 {\n\twidth: 100%;\n\tmargin-bottom: 1rem;\n}\n\n/* Drop zone error state */\n.ListingFileInput_module_listingFileInput__dropZone_Error__bc8e3553 {\n\tborder: 1px solid var(--colour-error);\n\tborder-radius: var(--border-radius-base);\n\tpadding: 0.25rem;\n\tbackground-color: var(--colour-error-light, rgba(220, 53, 69, 0.05));\n}\n\n.ListingFileInput_module_listingFileInput__dropZone__bc8e3553 .ListingFileInput_module_imageInputOuterSingle__bc8e3553 {\n\twidth: 100%;\n}\n\n.ListingFileInput_module_listingFileInput__dropZone__bc8e3553 .ListingFileInput_module_imageInput__bc8e3553 {\n\twidth: 100%;\n\tmargin-right: 0;\n}\n\n/* File list container */\n.ListingFileInput_module_listingFileInput__fileList__bc8e3553 {\n\tmargin-top: 1rem;\n}\n\n/* Individual file item */\n.ListingFileInput_module_fileListItem__bc8e3553 {\n\tdisplay: flex;\n\talign-items: center;\n\tgap: 0.75rem;\n\tpadding: 0.75rem;\n\tbackground-color: var(--bg-white);\n\tmargin-bottom: 0.5rem;\n\ttransition: all var(--transition-base) ease-in-out;\n}\n\n.ListingFileInput_module_fileListItem__bc8e3553:hover {\n\tbox-shadow: 0 0 4px var(--colour-branding-action-alpha20);\n}\n\n.ListingFileInput_module_fileListItem__icon__bc8e3553 {\n\tcolor: var(--text-bluegrey);\n\tfont-size: var(--font-size-base);\n\tflex-shrink: 0;\n\twidth: 1.5rem;\n\ttext-align: center;\n}\n\n.ListingFileInput_module_fileListItem__input__bc8e3553 {\n\tmin-width: 0;\n\tflex-grow: 1;\n}\n\n.ListingFileInput_module_fileListItem__nameInput__bc8e3553 {\n}\n\n.ListingFileInput_module_fileListItem__originalName__bc8e3553 {\n\tflex: 0 1 200px;\n\tcolor: var(--text-bluegrey);\n\tfont-size: 16px;\n\twhite-space: nowrap;\n\toverflow: hidden;\n\ttext-overflow: ellipsis;\n}\n\n.ListingFileInput_module_fileListItem__actions__bc8e3553 {\n\tflex-shrink: 0;\n}\n\n.ListingFileInput_module_fileListItem__removeButton__bc8e3553 {\n\tfont-size: 16px;\n\twidth: 1.75rem;\n\theight: 1.75rem;\n\tborder-radius: var(--border-radius-full);\n\tbackground-color: transparent;\n\tborder: none;\n\tdisplay: flex;\n\tcolor: var(--colour-branding-main);\n\talign-items: center;\n\tjustify-content: center;\n\tpadding: 0;\n\tmin-height: auto;\n\ttransition: all var(--transition-base) ease-in-out;\n}\n\n.ListingFileInput_module_fileListItem__removeButton__bc8e3553:hover:not(:disabled) {\n\tcolor: var(--colour-branding-light);\n}\n\n.ListingFileInput_module_fileListItem__removeButton__bc8e3553:disabled {\n\topacity: 0.5;\n\tcursor: not-allowed;\n}\n\n/* Add more files button */\n.ListingFileInput_module_listingFileInput__addMore__bc8e3553 {\n\tmargin-top: 0.75rem;\n\ttext-align: center;\n}\n\n.ListingFileInput_module_listingFileInput__addMoreButton__bc8e3553 {\n\tfont-size: var(--font-size-sm);\n\tpadding: 0.5rem 1rem;\n}\n\n/* Upload progress styling */\n.ListingFileInput_module_fileListItem_Uploading__bc8e3553 {\n\tbackground-color: var(--colour-branding-secondary-light);\n\tborder-color: var(--colour-branding-action);\n}\n\n.ListingFileInput_module_fileListItem__progress__bc8e3553 {\n\tdisplay: flex;\n\talign-items: center;\n\tgap: 0.5rem;\n\tfont-size: var(--font-size-xs);\n\tcolor: var(--colour-branding-action);\n}\n\n.ListingFileInput_module_fileListItem__spinner__bc8e3553 {\n\tcolor: var(--colour-branding-action);\n\tanimation: ListingFileInput_module_spin__bc8e3553 1s linear infinite;\n}\n\n@keyframes ListingFileInput_module_spin__bc8e3553 {\n\t0% {\n\t\ttransform: rotate(0deg);\n\t}\n\t100% {\n\t\ttransform: rotate(360deg);\n\t}\n}\n\n/* Responsive design */\n@media (max-width: 768px) {\n\t.ListingFileInput_module_fileListItem__bc8e3553 {\n\t\tflex-direction: column;\n\t\talign-items: stretch;\n\t\tgap: 0.5rem;\n\t}\n\n\t.ListingFileInput_module_fileListItem__icon__bc8e3553 {\n\t\ttext-align: center;\n\t}\n\n\t.ListingFileInput_module_fileListItem__actions__bc8e3553 {\n\t\ttext-align: center;\n\t}\n}\n\n/* Integration with existing field styling */\n.ListingFileInput_module_listingFileInput__dropZone__bc8e3553 .ListingFileInput_module_imageInput_upload__bc8e3553 {\n\tbackground-color: var(--bg-white);\n\ttransition: all var(--transition-base) ease-in-out;\n}\n\n.ListingFileInput_module_listingFileInput__dropZone__bc8e3553 .ListingFileInput_module_imageInput_upload__bc8e3553:hover {\n\tbackground-color: var(--bg-bluegrey);\n}\n\n.ListingFileInput_module_listingFileInput__dropZone__bc8e3553 .ListingFileInput_module_imageInput_dropZoneActive__bc8e3553 {\n\tbackground-color: var(--bg-bluegrey);\n}\n\n.ListingFileInput_module_listingFileInput__dropZone__bc8e3553 .ListingFileInput_module_imageInput_icon__bc8e3553 {\n\twidth: 1.5rem;\n\theight: 2rem;\n\tmargin: 0 auto;\n\tdisplay: block;\n}\n\n.ListingFileInput_module_listingFileInput__dropZone__bc8e3553 .ListingFileInput_module_imageInput_helpText__bc8e3553 {\n\tfont-size: var(--font-size-base);\n\tcolor: var(--colour-lightgrey);\n\tmargin-top: 1.25rem;\n\ttext-align: center;\n}\n\n.ListingFileInput_module_listingFileInput__dropZone__bc8e3553 .ListingFileInput_module_imageInput_button__bc8e3553 {\n\ttext-align: center;\n\tmargin-top: 1rem;\n}\n";
6643
- var modules_4fb4144d = {"listingFileInput":"ListingFileInput_module_listingFileInput__bc8e3553","listingFileInput__dropZone":"ListingFileInput_module_listingFileInput__dropZone__bc8e3553","listingFileInput__dropZone--error":"ListingFileInput_module_listingFileInput__dropZone_Error__bc8e3553","imageInputOuter-single":"ListingFileInput_module_imageInputOuterSingle__bc8e3553","imageInput":"ListingFileInput_module_imageInput__bc8e3553","listingFileInput__fileList":"ListingFileInput_module_listingFileInput__fileList__bc8e3553","fileListItem":"ListingFileInput_module_fileListItem__bc8e3553","fileListItem__icon":"ListingFileInput_module_fileListItem__icon__bc8e3553","fileListItem__input":"ListingFileInput_module_fileListItem__input__bc8e3553","fileListItem__nameInput":"ListingFileInput_module_fileListItem__nameInput__bc8e3553","fileListItem__originalName":"ListingFileInput_module_fileListItem__originalName__bc8e3553","fileListItem__actions":"ListingFileInput_module_fileListItem__actions__bc8e3553","fileListItem__removeButton":"ListingFileInput_module_fileListItem__removeButton__bc8e3553","listingFileInput__addMore":"ListingFileInput_module_listingFileInput__addMore__bc8e3553","listingFileInput__addMoreButton":"ListingFileInput_module_listingFileInput__addMoreButton__bc8e3553","fileListItem--uploading":"ListingFileInput_module_fileListItem_Uploading__bc8e3553","fileListItem__progress":"ListingFileInput_module_fileListItem__progress__bc8e3553","fileListItem__spinner":"ListingFileInput_module_fileListItem__spinner__bc8e3553","spin":"ListingFileInput_module_spin__bc8e3553","imageInput_upload":"ListingFileInput_module_imageInput_upload__bc8e3553","imageInput_dropZoneActive":"ListingFileInput_module_imageInput_dropZoneActive__bc8e3553","imageInput_icon":"ListingFileInput_module_imageInput_icon__bc8e3553","imageInput_helpText":"ListingFileInput_module_imageInput_helpText__bc8e3553","imageInput_button":"ListingFileInput_module_imageInput_button__bc8e3553"};
6637
+ var css$6 = "/* Enhanced File Input Styles - Based on existing PlussCore FileInput styling */\n\n/* Main container for enhanced file input */\n.ListingFileInput_module_listingFileInput__cb175742 {\n\twidth: 100%;\n}\n\n/* Drop zone area - reusing existing imageInput styling */\n.ListingFileInput_module_listingFileInput__dropZone__cb175742 {\n\twidth: 100%;\n\tmargin-bottom: 1rem;\n}\n\n/* Drop zone error state */\n.ListingFileInput_module_listingFileInput__dropZone_Error__cb175742 {\n\tborder: 1px solid var(--colour-error);\n\tborder-radius: var(--border-radius-base);\n\tpadding: 0.25rem;\n\tbackground-color: var(--colour-error-light, rgba(220, 53, 69, 0.05));\n}\n\n.ListingFileInput_module_listingFileInput__dropZone__cb175742 .ListingFileInput_module_imageInputOuterSingle__cb175742 {\n\twidth: 100%;\n}\n\n.ListingFileInput_module_listingFileInput__dropZone__cb175742 .ListingFileInput_module_imageInput__cb175742 {\n\twidth: 100%;\n\tmargin-right: 0;\n}\n\n/* File list container */\n.ListingFileInput_module_listingFileInput__fileList__cb175742 {\n\tmargin-top: 1rem;\n}\n\n/* Individual file item */\n.ListingFileInput_module_fileListItem__cb175742 {\n\tdisplay: flex;\n\talign-items: center;\n\tgap: 0.75rem;\n\tbackground-color: var(--bg-white);\n\ttransition: all var(--transition-base) ease-in-out;\n}\n\n.ListingFileInput_module_fileListItem__cb175742:hover {\n\tbox-shadow: 0 0 4px var(--colour-branding-action-alpha20);\n}\n\n.ListingFileInput_module_fileListItem__icon__cb175742 {\n\tcolor: var(--text-bluegrey);\n\t\tfont-size: 2rem;\n\tflex-shrink: 0;\n\ttext-align: center;\n}\n\n.ListingFileInput_module_fileListItem__input__cb175742 {\n\tmin-width: 0;\n\tflex-grow: 1;\n}\n\n.ListingFileInput_module_fileListItem__nameInput__cb175742 {\n}\n\n.ListingFileInput_module_fileListItem__originalName__cb175742 {\n\tflex: 0 1 200px;\n\tcolor: var(--text-bluegrey);\n\tfont-size: 16px;\n\twhite-space: nowrap;\n\toverflow: hidden;\n\ttext-overflow: ellipsis;\n}\n\n.ListingFileInput_module_fileListItem__actions__cb175742 {\n\tflex-shrink: 0;\n}\n\n.ListingFileInput_module_fileListItem__removeButton__cb175742 {\n\tfont-size: 16px;\n\twidth: 1.75rem;\n\theight: 1.75rem;\n\tborder-radius: var(--border-radius-full);\n\tbackground-color: transparent;\n\tborder: none;\n\tdisplay: flex;\n\tcolor: var(--colour-branding-main);\n\talign-items: center;\n\tjustify-content: center;\n\tpadding: 0;\n\tmin-height: auto;\n\ttransition: all var(--transition-base) ease-in-out;\n}\n\n.ListingFileInput_module_fileListItem__removeButton__cb175742:hover:not(:disabled) {\n\tcolor: var(--colour-branding-light);\n}\n\n.ListingFileInput_module_fileListItem__removeButton__cb175742:disabled {\n\topacity: 0.5;\n\tcursor: not-allowed;\n}\n\n/* Add more files button */\n.ListingFileInput_module_listingFileInput__addMore__cb175742 {\n\tmargin-top: 0.75rem;\n\ttext-align: center;\n}\n\n.ListingFileInput_module_listingFileInput__addMoreButton__cb175742 {\n\tfont-size: var(--font-size-sm);\n\tpadding: 0.5rem 1rem;\n}\n\n/* Upload progress styling */\n.ListingFileInput_module_fileListItem_Uploading__cb175742 {\n\tbackground-color: var(--colour-branding-secondary-light);\n\tborder-color: var(--colour-branding-action);\n}\n\n.ListingFileInput_module_fileListItem__progress__cb175742 {\n\tdisplay: flex;\n\talign-items: center;\n\tgap: 0.5rem;\n\tfont-size: var(--font-size-xs);\n\tcolor: var(--colour-branding-action);\n}\n\n.ListingFileInput_module_fileListItem__spinner__cb175742 {\n\tcolor: var(--colour-branding-action);\n\tanimation: ListingFileInput_module_spin__cb175742 1s linear infinite;\n}\n\n@keyframes ListingFileInput_module_spin__cb175742 {\n\t0% {\n\t\ttransform: rotate(0deg);\n\t}\n\t100% {\n\t\ttransform: rotate(360deg);\n\t}\n}\n\n/* Responsive design */\n@media (max-width: 768px) {\n\t.ListingFileInput_module_fileListItem__cb175742 {\n\t\tflex-direction: column;\n\t\talign-items: stretch;\n\t\tgap: 0.5rem;\n\t}\n\n\t.ListingFileInput_module_fileListItem__icon__cb175742 {\n\t\ttext-align: center;\n\t}\n\n\t.ListingFileInput_module_fileListItem__actions__cb175742 {\n\t\ttext-align: center;\n\t}\n}\n\n/* Integration with existing field styling */\n.ListingFileInput_module_listingFileInput__dropZone__cb175742 .ListingFileInput_module_imageInput_upload__cb175742 {\n\tbackground-color: var(--bg-white);\n\ttransition: all var(--transition-base) ease-in-out;\n}\n\n.ListingFileInput_module_listingFileInput__dropZone__cb175742 .ListingFileInput_module_imageInput_upload__cb175742:hover {\n\tbackground-color: var(--bg-bluegrey);\n}\n\n.ListingFileInput_module_listingFileInput__dropZone__cb175742 .ListingFileInput_module_imageInput_dropZoneActive__cb175742 {\n\tbackground-color: var(--bg-bluegrey);\n}\n\n.ListingFileInput_module_listingFileInput__dropZone__cb175742 .ListingFileInput_module_imageInput_icon__cb175742 {\n\twidth: 1.5rem;\n\theight: 2rem;\n\tmargin: 0 auto;\n\tdisplay: block;\n}\n\n.ListingFileInput_module_listingFileInput__dropZone__cb175742 .ListingFileInput_module_imageInput_helpText__cb175742 {\n\tfont-size: var(--font-size-base);\n\tcolor: var(--colour-lightgrey);\n\tmargin-top: 1.25rem;\n\ttext-align: center;\n}\n\n.ListingFileInput_module_listingFileInput__dropZone__cb175742 .ListingFileInput_module_imageInput_button__cb175742 {\n\ttext-align: center;\n\tmargin-top: 1rem;\n}\n";
6638
+ var modules_4fb4144d = {"listingFileInput":"ListingFileInput_module_listingFileInput__cb175742","listingFileInput__dropZone":"ListingFileInput_module_listingFileInput__dropZone__cb175742","listingFileInput__dropZone--error":"ListingFileInput_module_listingFileInput__dropZone_Error__cb175742","imageInputOuter-single":"ListingFileInput_module_imageInputOuterSingle__cb175742","imageInput":"ListingFileInput_module_imageInput__cb175742","listingFileInput__fileList":"ListingFileInput_module_listingFileInput__fileList__cb175742","fileListItem":"ListingFileInput_module_fileListItem__cb175742","fileListItem__icon":"ListingFileInput_module_fileListItem__icon__cb175742","fileListItem__input":"ListingFileInput_module_fileListItem__input__cb175742","fileListItem__nameInput":"ListingFileInput_module_fileListItem__nameInput__cb175742","fileListItem__originalName":"ListingFileInput_module_fileListItem__originalName__cb175742","fileListItem__actions":"ListingFileInput_module_fileListItem__actions__cb175742","fileListItem__removeButton":"ListingFileInput_module_fileListItem__removeButton__cb175742","listingFileInput__addMore":"ListingFileInput_module_listingFileInput__addMore__cb175742","listingFileInput__addMoreButton":"ListingFileInput_module_listingFileInput__addMoreButton__cb175742","fileListItem--uploading":"ListingFileInput_module_fileListItem_Uploading__cb175742","fileListItem__progress":"ListingFileInput_module_fileListItem__progress__cb175742","fileListItem__spinner":"ListingFileInput_module_fileListItem__spinner__cb175742","spin":"ListingFileInput_module_spin__cb175742","imageInput_upload":"ListingFileInput_module_imageInput_upload__cb175742","imageInput_dropZoneActive":"ListingFileInput_module_imageInput_dropZoneActive__cb175742","imageInput_icon":"ListingFileInput_module_imageInput_icon__cb175742","imageInput_helpText":"ListingFileInput_module_imageInput_helpText__cb175742","imageInput_button":"ListingFileInput_module_imageInput_button__cb175742"};
6644
6639
  n(css$6,{});
6645
6640
 
6646
6641
  const FileListItem = _ref => {
@@ -6730,109 +6725,153 @@ const ListingFileInput = _ref => {
6730
6725
  errorMessage,
6731
6726
  disabled = false
6732
6727
  } = _ref;
6733
- const fileInputRef = React.useRef(null);
6734
- const [internalFiles, setInternalFiles] = React.useState([]);
6728
+ const [inputs, setInputs] = React.useState([{
6729
+ id: 0,
6730
+ fileUrl: null
6731
+ }]);
6732
+ const nextIdRef = React.useRef(1);
6735
6733
 
6736
- // Normalize file data to enhanced structure - always handle as multiple files
6734
+ // Initialize inputs from value prop - map each existing file to an input
6737
6735
  React.useEffect(() => {
6738
6736
  if (value) {
6737
+ let fileData = [];
6738
+
6739
6739
  // Handle multiple files - could be array of URLs or array of file objects
6740
6740
  if (Array.isArray(value)) {
6741
- const normalizedFiles = value.map(file => {
6741
+ fileData = value.map(file => {
6742
6742
  if (typeof file === "string") {
6743
- // Backward compatibility: array of URLs
6744
6743
  const fileName = file.split("/").pop() || "Unknown File";
6745
6744
  return {
6746
6745
  url: file,
6747
6746
  name: fileName.replace(/\.[^/.]+$/, ""),
6748
- // Remove extension
6749
- originalName: fileName,
6750
- uploading: false
6747
+ originalName: fileName
6751
6748
  };
6752
6749
  } else if (file && typeof file === "object" && file.url) {
6753
- // Enhanced structure
6754
6750
  return {
6755
6751
  url: file.url,
6756
6752
  name: file.name || file.originalName || "Unknown File",
6757
- originalName: file.originalName || file.url.split("/").pop() || "Unknown File",
6758
- uploading: false
6753
+ originalName: file.originalName || file.url.split("/").pop() || "Unknown File"
6759
6754
  };
6760
6755
  }
6761
6756
  return null;
6762
6757
  }).filter(Boolean);
6763
- setInternalFiles(normalizedFiles);
6764
6758
  } else {
6765
- // Handle single file values - normalize to array
6759
+ // Handle single file values
6766
6760
  let singleFile = null;
6767
6761
  if (typeof value === "string") {
6768
- // Backward compatibility: single URL
6769
6762
  const fileName = value.split("/").pop() || "Unknown File";
6770
6763
  singleFile = {
6771
6764
  url: value,
6772
6765
  name: fileName.replace(/\.[^/.]+$/, ""),
6773
- originalName: fileName,
6774
- uploading: false
6766
+ originalName: fileName
6775
6767
  };
6776
6768
  } else if (value && typeof value === "object" && value.url) {
6777
- // Enhanced structure - preserve empty name if explicitly set
6778
6769
  singleFile = {
6779
6770
  url: value.url,
6780
6771
  name: value.name !== undefined ? value.name : value.originalName || "Unknown File",
6781
- originalName: value.originalName || value.url.split("/").pop() || "Unknown File",
6782
- uploading: false
6772
+ originalName: value.originalName || value.url.split("/").pop() || "Unknown File"
6783
6773
  };
6784
6774
  }
6785
- setInternalFiles(singleFile ? [singleFile] : []);
6775
+ fileData = singleFile ? [singleFile] : [];
6786
6776
  }
6777
+
6778
+ // Create inputs for each existing file
6779
+ const existingInputs = fileData.map((file, index) => ({
6780
+ id: index,
6781
+ fileUrl: file.url,
6782
+ name: file.name,
6783
+ originalName: file.originalName
6784
+ }));
6785
+ // Add one empty input at the end
6786
+ nextIdRef.current = fileData.length;
6787
+ setInputs([...existingInputs, {
6788
+ id: nextIdRef.current,
6789
+ fileUrl: null
6790
+ }]);
6791
+ nextIdRef.current++;
6787
6792
  } else {
6788
- setInternalFiles([]);
6793
+ setInputs([{
6794
+ id: 0,
6795
+ fileUrl: null
6796
+ }]);
6789
6797
  }
6790
6798
  }, [value]);
6791
6799
 
6792
6800
  // Handle new file upload from FileInput component
6793
- const handleFileUpload = uploadedUrl => {
6794
- // Handle case where uploadedUrl might be undefined
6801
+ const handleFileUpload = (inputId, uploadedUrl) => {
6795
6802
  if (!uploadedUrl) {
6796
6803
  return;
6797
6804
  }
6798
6805
  const fileName = uploadedUrl.split("/").pop() || "Unknown File";
6799
- const newFile = {
6800
- url: uploadedUrl,
6801
- name: "",
6802
- // Start with empty name as requested
6803
- originalName: fileName,
6804
- uploading: false
6805
- };
6806
6806
 
6807
- // Always add new file to existing array for multiple file support
6808
- const updatedFiles = [...internalFiles, newFile];
6809
- setInternalFiles(updatedFiles);
6810
- notifyParent(updatedFiles);
6807
+ // Find the input that triggered this upload and update it
6808
+ setInputs(prevInputs => {
6809
+ const updatedInputs = prevInputs.map(input => {
6810
+ if (input.id === inputId) {
6811
+ return _objectSpread$1(_objectSpread$1({}, input), {}, {
6812
+ fileUrl: uploadedUrl,
6813
+ name: "",
6814
+ originalName: fileName
6815
+ });
6816
+ }
6817
+ return input;
6818
+ });
6819
+
6820
+ // Add a new empty input for the next upload
6821
+ updatedInputs.push({
6822
+ id: nextIdRef.current,
6823
+ fileUrl: null
6824
+ });
6825
+ nextIdRef.current++;
6826
+ return updatedInputs;
6827
+ });
6811
6828
  };
6812
6829
 
6813
6830
  // Handle file name change
6814
6831
  const handleNameChange = (url, newName) => {
6815
- const updatedFiles = internalFiles.map(file => file.url === url ? _objectSpread$1(_objectSpread$1({}, file), {}, {
6832
+ setInputs(prevInputs => prevInputs.map(input => input.fileUrl === url ? _objectSpread$1(_objectSpread$1({}, input), {}, {
6816
6833
  name: newName
6817
- }) : file);
6818
- setInternalFiles(updatedFiles);
6819
- notifyParent(updatedFiles);
6834
+ }) : input));
6820
6835
  };
6821
6836
 
6822
6837
  // Handle file removal
6823
6838
  const handleFileRemove = url => {
6824
- const updatedFiles = internalFiles.filter(file => file.url !== url);
6825
- setInternalFiles(updatedFiles);
6826
- notifyParent(updatedFiles);
6839
+ setInputs(prevInputs => {
6840
+ return prevInputs.map(input => {
6841
+ if (input.fileUrl === url) {
6842
+ return _objectSpread$1(_objectSpread$1({}, input), {}, {
6843
+ fileUrl: null
6844
+ });
6845
+ }
6846
+ return input;
6847
+ });
6848
+ });
6827
6849
  };
6828
6850
 
6829
- // Notify parent component of changes
6830
- const notifyParent = files => {
6831
- if (onChange) {
6832
- // Always return array of files for multiple file support
6851
+ // Get all uploaded files from inputs
6852
+ const getUploadedFiles = () => {
6853
+ return inputs.filter(input => input.fileUrl !== null).map(input => ({
6854
+ url: input.fileUrl,
6855
+ name: input.name,
6856
+ originalName: input.originalName
6857
+ }));
6858
+ };
6859
+
6860
+ // Track previous uploaded files to prevent infinite loops
6861
+ const prevFilesRef = React.useRef([]);
6862
+
6863
+ // Sync with parent when uploaded files actually change
6864
+ React.useEffect(() => {
6865
+ const files = getUploadedFiles();
6866
+ const currentUrls = files.map(f => f.url).join(",");
6867
+ const prevUrls = prevFilesRef.current.map(f => f.url).join(",");
6868
+
6869
+ // Only call onChange if the file list actually changed
6870
+ if (currentUrls !== prevUrls && onChange) {
6871
+ prevFilesRef.current = files;
6833
6872
  onChange(field.id, files);
6834
6873
  }
6835
- };
6874
+ }, [inputs]);
6836
6875
 
6837
6876
  // Define acceptable file types for documents and common formats
6838
6877
  const acceptTypes = {
@@ -6847,8 +6886,11 @@ const ListingFileInput = _ref => {
6847
6886
  "image/png": [".png"]
6848
6887
  };
6849
6888
 
6850
- // Always show drop zone regardless of existing files
6889
+ // Get the last empty input (the one to show)
6890
+ const emptyInput = inputs.find(input => input.fileUrl === null);
6851
6891
 
6892
+ // Get uploaded files for display
6893
+ const uploadedFiles = getUploadedFiles();
6852
6894
  return /*#__PURE__*/React__default["default"].createElement("div", {
6853
6895
  className: modules_4fb4144d.listingFileInput
6854
6896
  }, /*#__PURE__*/React__default["default"].createElement("div", {
@@ -6873,39 +6915,22 @@ const ListingFileInput = _ref => {
6873
6915
  className: modules_2b7292f7.requiredAsterisk
6874
6916
  }, "*")), /*#__PURE__*/React__default["default"].createElement("div", {
6875
6917
  className: "".concat(modules_4fb4144d.listingFileInput__dropZone, " ").concat(showError ? modules_4fb4144d["listingFileInput__dropZone--error"] : "")
6876
- }, /*#__PURE__*/React__default["default"].createElement(FileInput, {
6877
- ref: fileInputRef,
6878
- className: "imageInputOuter-single",
6879
- refreshCallback: handleFileUpload,
6918
+ }, emptyInput && /*#__PURE__*/React__default["default"].createElement(FileInput, {
6919
+ key: emptyInput.id,
6920
+ refreshCallback: url => handleFileUpload(emptyInput.id, url),
6880
6921
  hasDefault: null,
6881
6922
  accept: acceptTypes,
6882
- multiple: false // Always handle one file at a time in the upload callback
6883
- ,
6923
+ multiple: false,
6884
6924
  disabled: disabled
6885
- })), internalFiles.length > 0 && /*#__PURE__*/React__default["default"].createElement("div", {
6925
+ })), uploadedFiles.length > 0 && /*#__PURE__*/React__default["default"].createElement("div", {
6886
6926
  className: modules_4fb4144d.listingFileInput__fileList
6887
- }, internalFiles.map(file => /*#__PURE__*/React__default["default"].createElement(FileListItem, {
6927
+ }, uploadedFiles.map(file => /*#__PURE__*/React__default["default"].createElement(FileListItem, {
6888
6928
  key: file.url,
6889
6929
  file: file,
6890
6930
  onNameChange: handleNameChange,
6891
6931
  onRemove: handleFileRemove,
6892
6932
  disabled: disabled
6893
- }))), internalFiles.length > 0 && /*#__PURE__*/React__default["default"].createElement("div", null, /*#__PURE__*/React__default["default"].createElement(FileInput, {
6894
- ref: fileInputRef,
6895
- className: "imageInputOuter-single",
6896
- refreshCallback: handleFileUpload,
6897
- hasDefault: null,
6898
- accept: acceptTypes,
6899
- multiple: false,
6900
- disabled: disabled,
6901
- customButton: /*#__PURE__*/React__default["default"].createElement(Button$4, {
6902
- buttonType: "secondary",
6903
- className: modules_4fb4144d.listingFileInput__addMoreButton,
6904
- disabled: disabled
6905
- }, /*#__PURE__*/React__default["default"].createElement(reactFontawesome.FontAwesomeIcon, {
6906
- icon: iconImports.plus
6907
- }), "Add More Files")
6908
- })), showError && errorMessage && /*#__PURE__*/React__default["default"].createElement(Text$8, {
6933
+ }))), showError && errorMessage && /*#__PURE__*/React__default["default"].createElement(Text$8, {
6909
6934
  type: "help",
6910
6935
  style: {
6911
6936
  color: "var(--colour-red)",
@@ -7212,9 +7237,11 @@ const ListingEditor = _ref => {
7212
7237
  // formData always has structure { fields: {...} } after our fixes
7213
7238
  const submissionData = isEditMode ? {
7214
7239
  id: listingId,
7215
- fields: formData.fields
7240
+ fields: formData.fields,
7241
+ site: auth.site
7216
7242
  } : {
7217
- fields: formData.fields
7243
+ fields: formData.fields,
7244
+ site: auth.site
7218
7245
  };
7219
7246
  const actionPromise = dispatch(isEditMode ? editListing(submissionData) : createListing(submissionData));
7220
7247
  actionPromise.then(result => {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@plusscommunities/pluss-feature-builder-web-a",
3
- "version": "1.0.2-beta.7",
3
+ "version": "1.0.2-beta.8",
4
4
  "description": "Contains the feature builder extension for the pluss communities ",
5
5
  "main": "dist/index.cjs.js",
6
6
  "scripts": {
@@ -241,10 +241,10 @@ export const BaseFieldConfig = (props) => {
241
241
  {setMaxImages && (
242
242
  <GenericInput
243
243
  type="number"
244
- value={maxImages || 10}
245
- placeholder="10"
244
+ value={maxImages || 16}
245
+ placeholder="16"
246
246
  label="Maximum Images"
247
- onChange={(e) => setMaxImages(parseInt(e.target.value) || 10)}
247
+ onChange={(e) => setMaxImages(parseInt(e.target.value) || 16)}
248
248
  className={styles.fieldSpacing}
249
249
  alwaysShowLabel
250
250
  />
@@ -168,8 +168,8 @@ const ListingEditor = ({ mode = "create", listingId, onSuccess, onCancel }) => {
168
168
 
169
169
  // formData always has structure { fields: {...} } after our fixes
170
170
  const submissionData = isEditMode
171
- ? { id: listingId, fields: formData.fields }
172
- : { fields: formData.fields };
171
+ ? { id: listingId, fields: formData.fields, site: auth.site }
172
+ : { fields: formData.fields, site: auth.site };
173
173
 
174
174
  const actionPromise = dispatch(
175
175
  isEditMode ? editListing(submissionData) : createListing(submissionData),
@@ -84,7 +84,7 @@ const SideBarInner = (props) => {
84
84
 
85
85
  // Build sidebar items based on mode
86
86
  const buildSidebarItems = () => {
87
- const isWizardMode = mode === "create" || mode === "edit";
87
+ const isWizardMode = mode === "create";
88
88
 
89
89
  return steps.map((step, index) => {
90
90
  const isCompleted = selectIsStepComplete(step.key);
@@ -109,8 +109,8 @@ const SideBarInner = (props) => {
109
109
  isFontAwesome: true,
110
110
  // Enhanced completion indicator
111
111
  completed: isCompleted,
112
- // Disable all navigation in wizard mode
113
- disabled: isWizardMode || (mode === "create" && !isAccessible),
112
+ // Disable all navigation in create mode, otherwise respect accessibility
113
+ disabled: mode === "create" || !isAccessible,
114
114
  };
115
115
 
116
116
  return itemProps;
@@ -137,7 +137,7 @@ const SideBarInner = (props) => {
137
137
 
138
138
  // Add effect to manually attach click handlers since HubSidebar might not use onclick properly
139
139
  useEffect(() => {
140
- const isWizardMode = mode === "create" || mode === "edit";
140
+ const isWizardMode = mode === "create";
141
141
 
142
142
  const attachClickHandlers = () => {
143
143
  const stepsWithUrls = [
@@ -14,27 +14,26 @@ const ListingFileInput = ({
14
14
  errorMessage,
15
15
  disabled = false,
16
16
  }) => {
17
- const fileInputRef = useRef(null);
18
- const [internalFiles, setInternalFiles] = useState([]);
17
+ const [inputs, setInputs] = useState([{ id: 0, fileUrl: null }]);
18
+ const nextIdRef = useRef(1);
19
19
 
20
- // Normalize file data to enhanced structure - always handle as multiple files
20
+ // Initialize inputs from value prop - map each existing file to an input
21
21
  useEffect(() => {
22
22
  if (value) {
23
+ let fileData = [];
24
+
23
25
  // Handle multiple files - could be array of URLs or array of file objects
24
26
  if (Array.isArray(value)) {
25
- const normalizedFiles = value
27
+ fileData = value
26
28
  .map((file) => {
27
29
  if (typeof file === "string") {
28
- // Backward compatibility: array of URLs
29
30
  const fileName = file.split("/").pop() || "Unknown File";
30
31
  return {
31
32
  url: file,
32
- name: fileName.replace(/\.[^/.]+$/, ""), // Remove extension
33
+ name: fileName.replace(/\.[^/.]+$/, ""),
33
34
  originalName: fileName,
34
- uploading: false,
35
35
  };
36
36
  } else if (file && typeof file === "object" && file.url) {
37
- // Enhanced structure
38
37
  return {
39
38
  url: file.url,
40
39
  name: file.name || file.originalName || "Unknown File",
@@ -42,27 +41,22 @@ const ListingFileInput = ({
42
41
  file.originalName ||
43
42
  file.url.split("/").pop() ||
44
43
  "Unknown File",
45
- uploading: false,
46
44
  };
47
45
  }
48
46
  return null;
49
47
  })
50
48
  .filter(Boolean);
51
- setInternalFiles(normalizedFiles);
52
49
  } else {
53
- // Handle single file values - normalize to array
50
+ // Handle single file values
54
51
  let singleFile = null;
55
52
  if (typeof value === "string") {
56
- // Backward compatibility: single URL
57
53
  const fileName = value.split("/").pop() || "Unknown File";
58
54
  singleFile = {
59
55
  url: value,
60
56
  name: fileName.replace(/\.[^/.]+$/, ""),
61
57
  originalName: fileName,
62
- uploading: false,
63
58
  };
64
59
  } else if (value && typeof value === "object" && value.url) {
65
- // Enhanced structure - preserve empty name if explicitly set
66
60
  singleFile = {
67
61
  url: value.url,
68
62
  name:
@@ -73,60 +67,104 @@ const ListingFileInput = ({
73
67
  value.originalName ||
74
68
  value.url.split("/").pop() ||
75
69
  "Unknown File",
76
- uploading: false,
77
70
  };
78
71
  }
79
- setInternalFiles(singleFile ? [singleFile] : []);
72
+ fileData = singleFile ? [singleFile] : [];
80
73
  }
74
+
75
+ // Create inputs for each existing file
76
+ const existingInputs = fileData.map((file, index) => ({
77
+ id: index,
78
+ fileUrl: file.url,
79
+ name: file.name,
80
+ originalName: file.originalName,
81
+ }));
82
+ // Add one empty input at the end
83
+ nextIdRef.current = fileData.length;
84
+ setInputs([...existingInputs, { id: nextIdRef.current, fileUrl: null }]);
85
+ nextIdRef.current++;
81
86
  } else {
82
- setInternalFiles([]);
87
+ setInputs([{ id: 0, fileUrl: null }]);
83
88
  }
84
89
  }, [value]);
85
90
 
86
91
  // Handle new file upload from FileInput component
87
- const handleFileUpload = (uploadedUrl) => {
88
- // Handle case where uploadedUrl might be undefined
92
+ const handleFileUpload = (inputId, uploadedUrl) => {
89
93
  if (!uploadedUrl) {
90
94
  return;
91
95
  }
92
96
 
93
97
  const fileName = uploadedUrl.split("/").pop() || "Unknown File";
94
- const newFile = {
95
- url: uploadedUrl,
96
- name: "", // Start with empty name as requested
97
- originalName: fileName,
98
- uploading: false,
99
- };
100
-
101
- // Always add new file to existing array for multiple file support
102
- const updatedFiles = [...internalFiles, newFile];
103
- setInternalFiles(updatedFiles);
104
- notifyParent(updatedFiles);
98
+
99
+ // Find the input that triggered this upload and update it
100
+ setInputs((prevInputs) => {
101
+ const updatedInputs = prevInputs.map((input) => {
102
+ if (input.id === inputId) {
103
+ return {
104
+ ...input,
105
+ fileUrl: uploadedUrl,
106
+ name: "",
107
+ originalName: fileName,
108
+ };
109
+ }
110
+ return input;
111
+ });
112
+
113
+ // Add a new empty input for the next upload
114
+ updatedInputs.push({ id: nextIdRef.current, fileUrl: null });
115
+ nextIdRef.current++;
116
+
117
+ return updatedInputs;
118
+ });
105
119
  };
106
120
 
107
121
  // Handle file name change
108
122
  const handleNameChange = (url, newName) => {
109
- const updatedFiles = internalFiles.map((file) =>
110
- file.url === url ? { ...file, name: newName } : file,
123
+ setInputs((prevInputs) =>
124
+ prevInputs.map((input) =>
125
+ input.fileUrl === url ? { ...input, name: newName } : input,
126
+ ),
111
127
  );
112
- setInternalFiles(updatedFiles);
113
- notifyParent(updatedFiles);
114
128
  };
115
129
 
116
130
  // Handle file removal
117
131
  const handleFileRemove = (url) => {
118
- const updatedFiles = internalFiles.filter((file) => file.url !== url);
119
- setInternalFiles(updatedFiles);
120
- notifyParent(updatedFiles);
132
+ setInputs((prevInputs) => {
133
+ return prevInputs.map((input) => {
134
+ if (input.fileUrl === url) {
135
+ return { ...input, fileUrl: null };
136
+ }
137
+ return input;
138
+ });
139
+ });
121
140
  };
122
141
 
123
- // Notify parent component of changes
124
- const notifyParent = (files) => {
125
- if (onChange) {
126
- // Always return array of files for multiple file support
142
+ // Get all uploaded files from inputs
143
+ const getUploadedFiles = () => {
144
+ return inputs
145
+ .filter((input) => input.fileUrl !== null)
146
+ .map((input) => ({
147
+ url: input.fileUrl,
148
+ name: input.name,
149
+ originalName: input.originalName,
150
+ }));
151
+ };
152
+
153
+ // Track previous uploaded files to prevent infinite loops
154
+ const prevFilesRef = useRef([]);
155
+
156
+ // Sync with parent when uploaded files actually change
157
+ useEffect(() => {
158
+ const files = getUploadedFiles();
159
+ const currentUrls = files.map((f) => f.url).join(",");
160
+ const prevUrls = prevFilesRef.current.map((f) => f.url).join(",");
161
+
162
+ // Only call onChange if the file list actually changed
163
+ if (currentUrls !== prevUrls && onChange) {
164
+ prevFilesRef.current = files;
127
165
  onChange(field.id, files);
128
166
  }
129
- };
167
+ }, [inputs]);
130
168
 
131
169
  // Define acceptable file types for documents and common formats
132
170
  const acceptTypes = {
@@ -145,7 +183,11 @@ const ListingFileInput = ({
145
183
  "image/png": [".png"],
146
184
  };
147
185
 
148
- // Always show drop zone regardless of existing files
186
+ // Get the last empty input (the one to show)
187
+ const emptyInput = inputs.find((input) => input.fileUrl === null);
188
+
189
+ // Get uploaded files for display
190
+ const uploadedFiles = getUploadedFiles();
149
191
 
150
192
  return (
151
193
  <div className={styles.listingFileInput}>
@@ -169,25 +211,26 @@ const ListingFileInput = ({
169
211
  )}
170
212
  </Text>
171
213
 
172
- {/* Drop zone */}
214
+ {/* Drop zone - always show exactly one empty input */}
173
215
  <div
174
216
  className={`${styles.listingFileInput__dropZone} ${showError ? styles["listingFileInput__dropZone--error"] : ""}`}
175
217
  >
176
- <FileInput
177
- ref={fileInputRef}
178
- className="imageInputOuter-single"
179
- refreshCallback={handleFileUpload}
180
- hasDefault={null}
181
- accept={acceptTypes}
182
- multiple={false} // Always handle one file at a time in the upload callback
183
- disabled={disabled}
184
- />
218
+ {emptyInput && (
219
+ <FileInput
220
+ key={emptyInput.id}
221
+ refreshCallback={(url) => handleFileUpload(emptyInput.id, url)}
222
+ hasDefault={null}
223
+ accept={acceptTypes}
224
+ multiple={false}
225
+ disabled={disabled}
226
+ />
227
+ )}
185
228
  </div>
186
229
 
187
230
  {/* File list */}
188
- {internalFiles.length > 0 && (
231
+ {uploadedFiles.length > 0 && (
189
232
  <div className={styles.listingFileInput__fileList}>
190
- {internalFiles.map((file) => (
233
+ {uploadedFiles.map((file) => (
191
234
  <FileListItem
192
235
  key={file.url}
193
236
  file={file}
@@ -199,31 +242,6 @@ const ListingFileInput = ({
199
242
  </div>
200
243
  )}
201
244
 
202
- {/* Add more files button - always show when files exist */}
203
- {internalFiles.length > 0 && (
204
- <div>
205
- <FileInput
206
- ref={fileInputRef}
207
- className="imageInputOuter-single"
208
- refreshCallback={handleFileUpload}
209
- hasDefault={null}
210
- accept={acceptTypes}
211
- multiple={false}
212
- disabled={disabled}
213
- customButton={
214
- <Button
215
- buttonType="secondary"
216
- className={styles.listingFileInput__addMoreButton}
217
- disabled={disabled}
218
- >
219
- <FontAwesomeIcon icon={iconImports.plus} />
220
- Add More Files
221
- </Button>
222
- }
223
- />
224
- </div>
225
- )}
226
-
227
245
  {showError && errorMessage && (
228
246
  <Text
229
247
  type="help"
@@ -38,9 +38,7 @@
38
38
  display: flex;
39
39
  align-items: center;
40
40
  gap: 0.75rem;
41
- padding: 0.75rem;
42
41
  background-color: var(--bg-white);
43
- margin-bottom: 0.5rem;
44
42
  transition: all var(--transition-base) ease-in-out;
45
43
  }
46
44
 
@@ -50,9 +48,8 @@
50
48
 
51
49
  .fileListItem__icon {
52
50
  color: var(--text-bluegrey);
53
- font-size: var(--font-size-base);
51
+ font-size: 2rem;
54
52
  flex-shrink: 0;
55
- width: 1.5rem;
56
53
  text-align: center;
57
54
  }
58
55
 
@@ -3,6 +3,7 @@
3
3
  /* Gallery container styles */
4
4
  .galleryContainer {
5
5
  margin-top: 0.75rem;
6
+ max-width:200px;
6
7
  }
7
8
 
8
9
  /* Error border wrapper */
@@ -20,7 +21,7 @@
20
21
 
21
22
  .imageGrid {
22
23
  display: grid;
23
- grid-template-columns: repeat(var(--columns, 4), 1fr);
24
+ grid-template-columns: repeat(4, 160px);
24
25
  gap: 1rem;
25
26
  margin-top: 0.5rem;
26
27
  }
@@ -86,7 +86,7 @@ const DEFAULT_NEW_FIELD = {
86
86
  allowCaption: false, // Default to not allowing captions for image fields
87
87
  useAsSummary: false, // Default to not using as summary for description fields
88
88
  minImages: 1, // Gallery-specific default
89
- maxImages: 10, // Gallery-specific default
89
+ maxImages: 16, // Gallery-specific default
90
90
  maxFileSize: "5MB", // Gallery-specific default
91
91
  allowedTypes: [], // Gallery-specific default
92
92
  },
@@ -138,7 +138,7 @@ function createNewField(id, type = "text", existingFields = []) {
138
138
  baseField.values.label = "Image Gallery";
139
139
  baseField.values.helpText = "Upload multiple images to create a gallery";
140
140
  baseField.values.minImages = 1;
141
- baseField.values.maxImages = 10;
141
+ baseField.values.maxImages = 16;
142
142
  baseField.values.maxFileSize = "5MB";
143
143
  baseField.values.allowedTypes = ["image/jpeg", "image/png", "image/webp"];
144
144
  const {
@@ -131,14 +131,9 @@ export const selectDefinitionMode = (state) => {
131
131
 
132
132
  // Check if we have a definition loaded or if we've determined the mode
133
133
  // This is used by hiddenFromFeaturePicker to determine if feature should be shown
134
- // When mode is "create", definition is null but we've determined the feature doesn't exist
135
- // When mode is "edit", definition exists and we've determined the feature exists
136
134
  export const selectHasDefinition = (state) => {
137
135
  const definition = selectDefinition(state);
138
- const mode = selectDefinitionMode(state);
139
- // Consider feature "loaded" if definition exists OR mode is set
140
- // Mode being set means we've successfully fetched and determined the state
141
- return !!definition || !!mode;
136
+ return !!definition;
142
137
  };
143
138
 
144
139
  // ============ LISTINGS SELECTORS ============