@plusscommunities/pluss-feature-builder-web-b 1.0.2-beta.6 → 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 ============
@@ -337,16 +332,14 @@ const selectIsStepAccessible = step => state => {
337
332
 
338
333
  // Get current sort method
339
334
  const selectSortBy = state => {
340
- var _listingsState$sortBy;
341
335
  const listingsState = selectListingsState(state);
342
- return (_listingsState$sortBy = listingsState === null || listingsState === void 0 ? void 0 : listingsState.sortBy) !== null && _listingsState$sortBy !== void 0 ? _listingsState$sortBy : "newest";
336
+ return (listingsState === null || listingsState === void 0 ? void 0 : listingsState.sortBy) || "newest";
343
337
  };
344
338
 
345
339
  // Get show deleted toggle state
346
340
  const selectShowDeleted = state => {
347
- var _listingsState$showDe;
348
341
  const listingsState = selectListingsState(state);
349
- return (_listingsState$showDe = listingsState === null || listingsState === void 0 ? void 0 : listingsState.showDeleted) !== null && _listingsState$showDe !== void 0 ? _listingsState$showDe : false;
342
+ return (listingsState === null || listingsState === void 0 ? void 0 : listingsState.showDeleted) || false;
350
343
  };
351
344
 
352
345
  // Get sorted and filtered listings
@@ -1781,10 +1774,10 @@ const BaseFieldConfig = props => {
1781
1774
  alwaysShowLabel: true
1782
1775
  }), setMaxImages && /*#__PURE__*/React__default["default"].createElement(GenericInput$1, {
1783
1776
  type: "number",
1784
- value: maxImages || 10,
1785
- placeholder: "10",
1777
+ value: maxImages || 16,
1778
+ placeholder: "16",
1786
1779
  label: "Maximum Images",
1787
- onChange: e => setMaxImages(parseInt(e.target.value) || 10),
1780
+ onChange: e => setMaxImages(parseInt(e.target.value) || 16),
1788
1781
  className: modules_18fc9e14.fieldSpacing,
1789
1782
  alwaysShowLabel: true
1790
1783
  }), setMaxFileSize && /*#__PURE__*/React__default["default"].createElement(GenericInput$1, {
@@ -1910,8 +1903,8 @@ var css$g = "/* Simple listing field styling - clean vertical layout */\n\n.List
1910
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"};
1911
1904
  n(css$g,{});
1912
1905
 
1913
- 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";
1914
- 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"};
1915
1908
  n(css$f,{});
1916
1909
 
1917
1910
  const ListingGalleryInput = _ref => {
@@ -2816,7 +2809,7 @@ const SideBarInner = props => {
2816
2809
 
2817
2810
  // Build sidebar items based on mode
2818
2811
  const buildSidebarItems = () => {
2819
- const isWizardMode = mode === "create" || mode === "edit";
2812
+ const isWizardMode = mode === "create";
2820
2813
  return steps.map((step, index) => {
2821
2814
  const isCompleted = selectIsStepComplete(step.key);
2822
2815
  const isAccessible = selectIsStepAccessible(step.key);
@@ -2835,8 +2828,8 @@ const SideBarInner = props => {
2835
2828
  isFontAwesome: true,
2836
2829
  // Enhanced completion indicator
2837
2830
  completed: isCompleted,
2838
- // Disable all navigation in wizard mode
2839
- disabled: isWizardMode || mode === "create" && !isAccessible
2831
+ // Disable all navigation in create mode, otherwise respect accessibility
2832
+ disabled: mode === "create" || !isAccessible
2840
2833
  };
2841
2834
  return itemProps;
2842
2835
  });
@@ -2860,7 +2853,7 @@ const SideBarInner = props => {
2860
2853
 
2861
2854
  // Add effect to manually attach click handlers since HubSidebar might not use onclick properly
2862
2855
  React.useEffect(() => {
2863
- const isWizardMode = mode === "create" || mode === "edit";
2856
+ const isWizardMode = mode === "create";
2864
2857
  const attachClickHandlers = () => {
2865
2858
  const stepsWithUrls = [{
2866
2859
  key: "overview",
@@ -5369,7 +5362,7 @@ const DEFAULT_NEW_FIELD = {
5369
5362
  // Default to not using as summary for description fields
5370
5363
  minImages: 1,
5371
5364
  // Gallery-specific default
5372
- maxImages: 10,
5365
+ maxImages: 16,
5373
5366
  // Gallery-specific default
5374
5367
  maxFileSize: "5MB",
5375
5368
  // Gallery-specific default
@@ -5422,7 +5415,7 @@ function createNewField(id) {
5422
5415
  baseField.values.label = "Image Gallery";
5423
5416
  baseField.values.helpText = "Upload multiple images to create a gallery";
5424
5417
  baseField.values.minImages = 1;
5425
- baseField.values.maxImages = 10;
5418
+ baseField.values.maxImages = 16;
5426
5419
  baseField.values.maxFileSize = "5MB";
5427
5420
  baseField.values.allowedTypes = ["image/jpeg", "image/png", "image/webp"];
5428
5421
  const _baseField$values2 = baseField.values,
@@ -5565,10 +5558,9 @@ const formReducer = function () {
5565
5558
  switch (type) {
5566
5559
  case actionsTypes.SET_INITIAL_VALUES:
5567
5560
  {
5568
- var _payload$featureDefin, _definitionWrapper$de;
5569
5561
  // The actual definition data is in payload.featureDefinition.definition
5570
- const definitionWrapper = (_payload$featureDefin = payload === null || payload === void 0 ? void 0 : payload.featureDefinition) !== null && _payload$featureDefin !== void 0 ? _payload$featureDefin : payload;
5571
- const definition = (_definitionWrapper$de = definitionWrapper === null || definitionWrapper === void 0 ? void 0 : definitionWrapper.definition) !== null && _definitionWrapper$de !== void 0 ? _definitionWrapper$de : definitionWrapper;
5562
+ const definitionWrapper = payload && payload.featureDefinition || payload;
5563
+ const definition = definitionWrapper && definitionWrapper.definition || definitionWrapper;
5572
5564
 
5573
5565
  // Validate and map definition data to form state structure
5574
5566
  const mappedValues = {
@@ -5784,12 +5776,12 @@ const definitionReducer = function () {
5784
5776
  let definitionId = values.featureId; // Always use hardcoded ID
5785
5777
 
5786
5778
  if (mode === "edit" && data) {
5787
- var _data$featureDefiniti, _featureDefinitionWra, _featureDefinitionWra2, _definition;
5779
+ var _definition;
5788
5780
  // Extract from API response for edit mode
5789
5781
  // Handle nested structure: data.featureDefinition.definition
5790
- const featureDefinitionWrapper = (_data$featureDefiniti = data === null || data === void 0 ? void 0 : data.featureDefinition) !== null && _data$featureDefiniti !== void 0 ? _data$featureDefiniti : data;
5791
- definition = (_featureDefinitionWra = featureDefinitionWrapper === null || featureDefinitionWrapper === void 0 ? void 0 : featureDefinitionWrapper.definition) !== null && _featureDefinitionWra !== void 0 ? _featureDefinitionWra : featureDefinitionWrapper;
5792
- definitionId = (_featureDefinitionWra2 = featureDefinitionWrapper === null || featureDefinitionWrapper === void 0 ? void 0 : featureDefinitionWrapper.id) !== null && _featureDefinitionWra2 !== void 0 ? _featureDefinitionWra2 : values.featureId;
5782
+ const featureDefinitionWrapper = data && data.featureDefinition || data;
5783
+ definition = featureDefinitionWrapper && featureDefinitionWrapper.definition || featureDefinitionWrapper;
5784
+ definitionId = featureDefinitionWrapper && featureDefinitionWrapper.id || values.featureId;
5793
5785
 
5794
5786
  // Ensure fields array exists and preserves order property
5795
5787
  if ((_definition = definition) !== null && _definition !== void 0 && _definition.fields) {
@@ -6642,8 +6634,8 @@ const ListingCTAInput = _ref => {
6642
6634
  }));
6643
6635
  };
6644
6636
 
6645
- 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";
6646
- 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"};
6647
6639
  n(css$6,{});
6648
6640
 
6649
6641
  const FileListItem = _ref => {
@@ -6733,109 +6725,153 @@ const ListingFileInput = _ref => {
6733
6725
  errorMessage,
6734
6726
  disabled = false
6735
6727
  } = _ref;
6736
- const fileInputRef = React.useRef(null);
6737
- const [internalFiles, setInternalFiles] = React.useState([]);
6728
+ const [inputs, setInputs] = React.useState([{
6729
+ id: 0,
6730
+ fileUrl: null
6731
+ }]);
6732
+ const nextIdRef = React.useRef(1);
6738
6733
 
6739
- // Normalize file data to enhanced structure - always handle as multiple files
6734
+ // Initialize inputs from value prop - map each existing file to an input
6740
6735
  React.useEffect(() => {
6741
6736
  if (value) {
6737
+ let fileData = [];
6738
+
6742
6739
  // Handle multiple files - could be array of URLs or array of file objects
6743
6740
  if (Array.isArray(value)) {
6744
- const normalizedFiles = value.map(file => {
6741
+ fileData = value.map(file => {
6745
6742
  if (typeof file === "string") {
6746
- // Backward compatibility: array of URLs
6747
6743
  const fileName = file.split("/").pop() || "Unknown File";
6748
6744
  return {
6749
6745
  url: file,
6750
6746
  name: fileName.replace(/\.[^/.]+$/, ""),
6751
- // Remove extension
6752
- originalName: fileName,
6753
- uploading: false
6747
+ originalName: fileName
6754
6748
  };
6755
6749
  } else if (file && typeof file === "object" && file.url) {
6756
- // Enhanced structure
6757
6750
  return {
6758
6751
  url: file.url,
6759
6752
  name: file.name || file.originalName || "Unknown File",
6760
- originalName: file.originalName || file.url.split("/").pop() || "Unknown File",
6761
- uploading: false
6753
+ originalName: file.originalName || file.url.split("/").pop() || "Unknown File"
6762
6754
  };
6763
6755
  }
6764
6756
  return null;
6765
6757
  }).filter(Boolean);
6766
- setInternalFiles(normalizedFiles);
6767
6758
  } else {
6768
- // Handle single file values - normalize to array
6759
+ // Handle single file values
6769
6760
  let singleFile = null;
6770
6761
  if (typeof value === "string") {
6771
- // Backward compatibility: single URL
6772
6762
  const fileName = value.split("/").pop() || "Unknown File";
6773
6763
  singleFile = {
6774
6764
  url: value,
6775
6765
  name: fileName.replace(/\.[^/.]+$/, ""),
6776
- originalName: fileName,
6777
- uploading: false
6766
+ originalName: fileName
6778
6767
  };
6779
6768
  } else if (value && typeof value === "object" && value.url) {
6780
- // Enhanced structure - preserve empty name if explicitly set
6781
6769
  singleFile = {
6782
6770
  url: value.url,
6783
6771
  name: value.name !== undefined ? value.name : value.originalName || "Unknown File",
6784
- originalName: value.originalName || value.url.split("/").pop() || "Unknown File",
6785
- uploading: false
6772
+ originalName: value.originalName || value.url.split("/").pop() || "Unknown File"
6786
6773
  };
6787
6774
  }
6788
- setInternalFiles(singleFile ? [singleFile] : []);
6775
+ fileData = singleFile ? [singleFile] : [];
6789
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++;
6790
6792
  } else {
6791
- setInternalFiles([]);
6793
+ setInputs([{
6794
+ id: 0,
6795
+ fileUrl: null
6796
+ }]);
6792
6797
  }
6793
6798
  }, [value]);
6794
6799
 
6795
6800
  // Handle new file upload from FileInput component
6796
- const handleFileUpload = uploadedUrl => {
6797
- // Handle case where uploadedUrl might be undefined
6801
+ const handleFileUpload = (inputId, uploadedUrl) => {
6798
6802
  if (!uploadedUrl) {
6799
6803
  return;
6800
6804
  }
6801
6805
  const fileName = uploadedUrl.split("/").pop() || "Unknown File";
6802
- const newFile = {
6803
- url: uploadedUrl,
6804
- name: "",
6805
- // Start with empty name as requested
6806
- originalName: fileName,
6807
- uploading: false
6808
- };
6809
6806
 
6810
- // Always add new file to existing array for multiple file support
6811
- const updatedFiles = [...internalFiles, newFile];
6812
- setInternalFiles(updatedFiles);
6813
- 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
+ });
6814
6828
  };
6815
6829
 
6816
6830
  // Handle file name change
6817
6831
  const handleNameChange = (url, newName) => {
6818
- 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), {}, {
6819
6833
  name: newName
6820
- }) : file);
6821
- setInternalFiles(updatedFiles);
6822
- notifyParent(updatedFiles);
6834
+ }) : input));
6823
6835
  };
6824
6836
 
6825
6837
  // Handle file removal
6826
6838
  const handleFileRemove = url => {
6827
- const updatedFiles = internalFiles.filter(file => file.url !== url);
6828
- setInternalFiles(updatedFiles);
6829
- 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
+ });
6830
6849
  };
6831
6850
 
6832
- // Notify parent component of changes
6833
- const notifyParent = files => {
6834
- if (onChange) {
6835
- // 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;
6836
6872
  onChange(field.id, files);
6837
6873
  }
6838
- };
6874
+ }, [inputs]);
6839
6875
 
6840
6876
  // Define acceptable file types for documents and common formats
6841
6877
  const acceptTypes = {
@@ -6850,8 +6886,11 @@ const ListingFileInput = _ref => {
6850
6886
  "image/png": [".png"]
6851
6887
  };
6852
6888
 
6853
- // 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);
6854
6891
 
6892
+ // Get uploaded files for display
6893
+ const uploadedFiles = getUploadedFiles();
6855
6894
  return /*#__PURE__*/React__default["default"].createElement("div", {
6856
6895
  className: modules_4fb4144d.listingFileInput
6857
6896
  }, /*#__PURE__*/React__default["default"].createElement("div", {
@@ -6876,39 +6915,22 @@ const ListingFileInput = _ref => {
6876
6915
  className: modules_2b7292f7.requiredAsterisk
6877
6916
  }, "*")), /*#__PURE__*/React__default["default"].createElement("div", {
6878
6917
  className: "".concat(modules_4fb4144d.listingFileInput__dropZone, " ").concat(showError ? modules_4fb4144d["listingFileInput__dropZone--error"] : "")
6879
- }, /*#__PURE__*/React__default["default"].createElement(FileInput, {
6880
- ref: fileInputRef,
6881
- className: "imageInputOuter-single",
6882
- refreshCallback: handleFileUpload,
6918
+ }, emptyInput && /*#__PURE__*/React__default["default"].createElement(FileInput, {
6919
+ key: emptyInput.id,
6920
+ refreshCallback: url => handleFileUpload(emptyInput.id, url),
6883
6921
  hasDefault: null,
6884
6922
  accept: acceptTypes,
6885
- multiple: false // Always handle one file at a time in the upload callback
6886
- ,
6923
+ multiple: false,
6887
6924
  disabled: disabled
6888
- })), internalFiles.length > 0 && /*#__PURE__*/React__default["default"].createElement("div", {
6925
+ })), uploadedFiles.length > 0 && /*#__PURE__*/React__default["default"].createElement("div", {
6889
6926
  className: modules_4fb4144d.listingFileInput__fileList
6890
- }, internalFiles.map(file => /*#__PURE__*/React__default["default"].createElement(FileListItem, {
6927
+ }, uploadedFiles.map(file => /*#__PURE__*/React__default["default"].createElement(FileListItem, {
6891
6928
  key: file.url,
6892
6929
  file: file,
6893
6930
  onNameChange: handleNameChange,
6894
6931
  onRemove: handleFileRemove,
6895
6932
  disabled: disabled
6896
- }))), internalFiles.length > 0 && /*#__PURE__*/React__default["default"].createElement("div", null, /*#__PURE__*/React__default["default"].createElement(FileInput, {
6897
- ref: fileInputRef,
6898
- className: "imageInputOuter-single",
6899
- refreshCallback: handleFileUpload,
6900
- hasDefault: null,
6901
- accept: acceptTypes,
6902
- multiple: false,
6903
- disabled: disabled,
6904
- customButton: /*#__PURE__*/React__default["default"].createElement(Button$4, {
6905
- buttonType: "secondary",
6906
- className: modules_4fb4144d.listingFileInput__addMoreButton,
6907
- disabled: disabled
6908
- }, /*#__PURE__*/React__default["default"].createElement(reactFontawesome.FontAwesomeIcon, {
6909
- icon: iconImports.plus
6910
- }), "Add More Files")
6911
- })), showError && errorMessage && /*#__PURE__*/React__default["default"].createElement(Text$8, {
6933
+ }))), showError && errorMessage && /*#__PURE__*/React__default["default"].createElement(Text$8, {
6912
6934
  type: "help",
6913
6935
  style: {
6914
6936
  color: "var(--colour-red)",
@@ -7215,9 +7237,11 @@ const ListingEditor = _ref => {
7215
7237
  // formData always has structure { fields: {...} } after our fixes
7216
7238
  const submissionData = isEditMode ? {
7217
7239
  id: listingId,
7218
- fields: formData.fields
7240
+ fields: formData.fields,
7241
+ site: auth.site
7219
7242
  } : {
7220
- fields: formData.fields
7243
+ fields: formData.fields,
7244
+ site: auth.site
7221
7245
  };
7222
7246
  const actionPromise = dispatch(isEditMode ? editListing(submissionData) : createListing(submissionData));
7223
7247
  actionPromise.then(result => {
@@ -7762,12 +7786,12 @@ const Reducers = (() => {
7762
7786
  })();
7763
7787
  const Screens = (() => {
7764
7788
  const screens = {};
7765
- screens["FormOverviewStep"] = FormOverviewStep;
7766
- screens["FormFieldsStep"] = FormFieldsStep;
7767
- screens["FormLayoutStep"] = FormLayoutStep;
7768
- screens["ListingScreen"] = ListingScreen$1;
7769
- screens["CreateListingPage"] = CreateListingPage;
7770
- screens["EditListingPage"] = EditListingPage;
7789
+ screens[values.screenFormOverviewStep] = FormOverviewStep;
7790
+ screens[values.screenFormFieldsStep] = FormFieldsStep;
7791
+ screens[values.screenFormLayoutStep] = FormLayoutStep;
7792
+ screens[values.screenListingScreen] = ListingScreen$1;
7793
+ screens[values.pageCreateListing] = CreateListingPage;
7794
+ screens[values.pageEditListing] = EditListingPage;
7771
7795
  return screens;
7772
7796
  })();
7773
7797
 
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@plusscommunities/pluss-feature-builder-web-b",
3
- "version": "1.0.2-beta.6",
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
  }
package/src/index.js CHANGED
@@ -18,12 +18,12 @@ export const Reducers = (() => {
18
18
  export const Screens = (() => {
19
19
  const screens = {};
20
20
 
21
- screens["FormOverviewStep"] = FormOverviewStep;
22
- screens["FormFieldsStep"] = FormFieldsStep;
23
- screens["FormLayoutStep"] = FormLayoutStep;
24
- screens["ListingScreen"] = ListingScreen;
25
- screens["CreateListingPage"] = CreateListingPage;
26
- screens["EditListingPage"] = EditListingPage;
21
+ screens[values.screenFormOverviewStep] = FormOverviewStep;
22
+ screens[values.screenFormFieldsStep] = FormFieldsStep;
23
+ screens[values.screenFormLayoutStep] = FormLayoutStep;
24
+ screens[values.screenListingScreen] = ListingScreen;
25
+ screens[values.pageCreateListing] = CreateListingPage;
26
+ screens[values.pageEditListing] = EditListingPage;
27
27
  return screens;
28
28
  })();
29
29
 
@@ -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 {
@@ -277,8 +277,8 @@ const formReducer = (state = INITIAL_FORM_STATE, action) => {
277
277
  switch (type) {
278
278
  case formActionTypes.SET_INITIAL_VALUES: {
279
279
  // The actual definition data is in payload.featureDefinition.definition
280
- const definitionWrapper = payload?.featureDefinition ?? payload;
281
- const definition = definitionWrapper?.definition ?? definitionWrapper;
280
+ const definitionWrapper = (payload && payload.featureDefinition) || payload;
281
+ const definition = (definitionWrapper && definitionWrapper.definition) || definitionWrapper;
282
282
 
283
283
  // Validate and map definition data to form state structure
284
284
  const mappedValues = {
@@ -511,10 +511,10 @@ const definitionReducer = (state = INITIAL_STATE.definition, action) => {
511
511
  // Extract from API response for edit mode
512
512
  // Handle nested structure: data.featureDefinition.definition
513
513
  const featureDefinitionWrapper =
514
- data?.featureDefinition ?? data;
514
+ (data && data.featureDefinition) || data;
515
515
  definition =
516
- featureDefinitionWrapper?.definition ?? featureDefinitionWrapper;
517
- definitionId = featureDefinitionWrapper?.id ?? values.featureId;
516
+ (featureDefinitionWrapper && featureDefinitionWrapper.definition) || featureDefinitionWrapper;
517
+ definitionId = (featureDefinitionWrapper && featureDefinitionWrapper.id) || values.featureId;
518
518
 
519
519
  // Ensure fields array exists and preserves order property
520
520
  if (definition?.fields) {
@@ -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 ============
@@ -431,13 +426,13 @@ export const selectIsStepAccessible = (step) => (state) => {
431
426
  // Get current sort method
432
427
  export const selectSortBy = (state) => {
433
428
  const listingsState = selectListingsState(state);
434
- return listingsState?.sortBy ?? "newest";
429
+ return listingsState?.sortBy || "newest";
435
430
  };
436
431
 
437
432
  // Get show deleted toggle state
438
433
  export const selectShowDeleted = (state) => {
439
434
  const listingsState = selectListingsState(state);
440
- return listingsState?.showDeleted ?? false;
435
+ return listingsState?.showDeleted || false;
441
436
  };
442
437
 
443
438
  // Get sorted and filtered listings