df-ae-forms-package 1.1.4 → 1.1.5

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.esm.js CHANGED
@@ -2402,6 +2402,7 @@ const DfFormFileUpload = ({ id, properties, validationErrors = {}, formValue = n
2402
2402
  const [isDragOver, setIsDragOver] = useState(false);
2403
2403
  const [isTouched, setIsTouched] = useState(false);
2404
2404
  const fileInputRef = useRef(null);
2405
+ const lastFormValueRef = useRef(null); // Track the last formValue to prevent unnecessary resets
2405
2406
  // Convert FileList or File[] to IFilePreview[]
2406
2407
  const convertToFilePreviews = useCallback((fileList, startIndex = 0) => {
2407
2408
  if (!fileList)
@@ -2494,12 +2495,20 @@ const DfFormFileUpload = ({ id, properties, validationErrors = {}, formValue = n
2494
2495
  if (fileObject.url || fileObject.path) {
2495
2496
  preview = fileObject.url || fileObject.path;
2496
2497
  }
2497
- else if (fileType.startsWith('image/') && fileObject.data) {
2498
- // Handle base64 data
2498
+ else if (fileObject.data) {
2499
+ // Handle base64 data - works for all file types with data
2500
+ const resolvedType = fileType || 'application/octet-stream';
2499
2501
  const fileData = fileObject.data;
2500
- preview = typeof fileData === 'string'
2501
- ? (fileData.startsWith('data:') ? fileData : `data:${fileType};base64,${fileData}`)
2502
- : undefined;
2502
+ if (typeof fileData === 'string') {
2503
+ if (fileData.startsWith('data:')) {
2504
+ // Already a full data URI
2505
+ preview = fileData;
2506
+ }
2507
+ else {
2508
+ // Raw base64 - construct data URI
2509
+ preview = `data:${resolvedType};base64,${fileData}`;
2510
+ }
2511
+ }
2503
2512
  }
2504
2513
  // Use the original object to preserve data
2505
2514
  fileObj = fileObject;
@@ -2684,10 +2693,35 @@ const DfFormFileUpload = ({ id, properties, validationErrors = {}, formValue = n
2684
2693
  }
2685
2694
  }, [mode]);
2686
2695
  // Update value when formValue prop changes or on mount
2696
+ // CRITICAL: Use a stable reference check to prevent unnecessary resets
2687
2697
  useEffect(() => {
2688
- // Always convert formValue, even if it's null/undefined (will return empty array)
2698
+ // Skip if formValue is null/undefined (no data)
2699
+ if (formValue === null || formValue === undefined || (typeof formValue === 'string' && formValue === '')) {
2700
+ // Only clear files if we previously had files from formValue
2701
+ // Don't clear files that were added by user interaction
2702
+ if (lastFormValueRef.current !== null && lastFormValueRef.current !== undefined && lastFormValueRef.current !== '') {
2703
+ setFiles([]);
2704
+ lastFormValueRef.current = null;
2705
+ }
2706
+ return;
2707
+ }
2708
+ // Check if formValue actually changed (deep comparison for arrays)
2709
+ try {
2710
+ const currentStr = JSON.stringify(formValue);
2711
+ const prevStr = JSON.stringify(lastFormValueRef.current);
2712
+ if (currentStr === prevStr) {
2713
+ return; // No change, skip
2714
+ }
2715
+ }
2716
+ catch {
2717
+ // If stringify fails, proceed with update
2718
+ }
2719
+ // Convert and set new files
2689
2720
  const newFiles = convertToFilePreviews(formValue);
2690
- setFiles(newFiles);
2721
+ if (newFiles.length > 0) {
2722
+ setFiles(newFiles);
2723
+ lastFormValueRef.current = formValue;
2724
+ }
2691
2725
  }, [formValue, convertToFilePreviews]);
2692
2726
  // Mark as touched when form is submitted
2693
2727
  useEffect(() => {
@@ -5431,7 +5465,38 @@ onComponentSelect, onComponentDelete, onComponentEdit, onComponentUpdate, select
5431
5465
  const initializeComponentValues = (components, values) => {
5432
5466
  components.forEach(component => {
5433
5467
  const componentId = ensureStringId$1(component.id);
5434
- if (componentId) {
5468
+ if (!componentId)
5469
+ return; // Skip components without valid IDs
5470
+ // CRITICAL: Handle file component FIRST — file data is an array, not a simple string
5471
+ // The general handler below would misinterpret an empty file array
5472
+ if (component.name === 'file' && component.basic) {
5473
+ // Don't overwrite if already initialized
5474
+ if (values[componentId] !== undefined && values[componentId] !== '' && values[componentId] !== null) ;
5475
+ else {
5476
+ // Check all possible locations where file data could be stored
5477
+ const fileData = component.basic.value ||
5478
+ component.basic.files ||
5479
+ component.basic.attachments;
5480
+ if (fileData && (Array.isArray(fileData) ? fileData.length > 0 : true)) {
5481
+ values[componentId] = fileData;
5482
+ }
5483
+ else {
5484
+ values[componentId] = null; // Use null, not empty string, for file components
5485
+ }
5486
+ }
5487
+ }
5488
+ // Handle instructions component
5489
+ else if (component.name === 'instructions' && component.basic) {
5490
+ if (!component.basic.instructions) {
5491
+ component.basic.instructions = [];
5492
+ }
5493
+ const instructionValue = component.basic.value || component.basic.instructions;
5494
+ if (instructionValue) {
5495
+ values[componentId] = instructionValue;
5496
+ }
5497
+ }
5498
+ // General handler for all other components
5499
+ else {
5435
5500
  // ALWAYS prioritize existing form state (values param) if it exists
5436
5501
  if (values[componentId] !== undefined) ;
5437
5502
  // Then use captured value in basic.value
@@ -5446,10 +5511,10 @@ onComponentSelect, onComponentDelete, onComponentEdit, onComponentUpdate, select
5446
5511
  else {
5447
5512
  // For checkbox and multi-select, empty array
5448
5513
  if (component.name === 'checkbox' || component.name === 'select') {
5449
- values[component.id] = [];
5514
+ values[componentId] = [];
5450
5515
  }
5451
5516
  else {
5452
- values[component.id] = '';
5517
+ values[componentId] = '';
5453
5518
  }
5454
5519
  }
5455
5520
  }
@@ -5471,31 +5536,10 @@ onComponentSelect, onComponentDelete, onComponentEdit, onComponentUpdate, select
5471
5536
  }
5472
5537
  });
5473
5538
  }
5474
- // Handle file component - initialize with file data if present
5475
- if (component.name === 'file' && component.basic) {
5476
- const fileData = component.basic.files || component.basic.attachments || component.basic.value;
5477
- if (fileData) {
5478
- values[component.id] = fileData;
5479
- }
5480
- }
5481
5539
  // Initialize notes and attachments
5482
- if (component.id && component.basic) {
5540
+ if (componentId && component.basic) {
5483
5541
  if (component.basic.notes) ;
5484
5542
  }
5485
- // Handle instructions component - ensure instructions array exists and initialize formValue
5486
- if (component.name === 'instructions' && component.basic) {
5487
- if (!component.basic.instructions) {
5488
- // Initialize empty instructions array if not present
5489
- component.basic.instructions = [];
5490
- }
5491
- // CRITICAL: Initialize formValue for instructions from API data
5492
- // Check if component has value from API (could be in basic.value, basic.instructions, or formData)
5493
- const instructionValue = component.basic.value || component.basic.instructions;
5494
- if (instructionValue) {
5495
- // Store instruction data in formValues so it can be passed to DfFormInstruction
5496
- values[component.id] = instructionValue;
5497
- }
5498
- }
5499
5543
  // Handle nested components in section children
5500
5544
  if (component.children && Array.isArray(component.children)) {
5501
5545
  initializeComponentValues(component.children, values);
@@ -5655,8 +5699,34 @@ onComponentSelect, onComponentDelete, onComponentEdit, onComponentUpdate, select
5655
5699
  }
5656
5700
  // Set the state
5657
5701
  setFormValues(prev => {
5658
- // Merge with previous state to avoid blowing away user input on re-renders
5659
- return { ...initialValues, ...prev };
5702
+ // Smart merge: initial values should win over empty/stale prev values
5703
+ // but user-entered values in prev should win over initial defaults
5704
+ const merged = { ...initialValues };
5705
+ Object.keys(prev).forEach(key => {
5706
+ const prevVal = prev[key];
5707
+ const initVal = initialValues[key];
5708
+ // If prev has a meaningful value (not empty/null/undefined), keep it
5709
+ if (prevVal !== undefined && prevVal !== null && prevVal !== '') {
5710
+ // But if initVal is an array (like file data) and prevVal is a simple empty value,
5711
+ // prefer the initialValue
5712
+ if (Array.isArray(initVal) && initVal.length > 0 && !Array.isArray(prevVal)) {
5713
+ // initialValue is a populated array but prev is not — keep initial
5714
+ merged[key] = initVal;
5715
+ }
5716
+ else {
5717
+ merged[key] = prevVal;
5718
+ }
5719
+ }
5720
+ // If prev has empty string but initial has actual data, use initial
5721
+ else if (initVal !== undefined && initVal !== null && initVal !== '') {
5722
+ merged[key] = initVal;
5723
+ }
5724
+ // Otherwise keep prev (even if empty — preserves user clearing a field)
5725
+ else {
5726
+ merged[key] = prevVal;
5727
+ }
5728
+ });
5729
+ return merged;
5660
5730
  });
5661
5731
  // Initialize notes and attachments state
5662
5732
  setComponentNotes(prev => ({ ...initialNotes, ...prev }));
@@ -6815,12 +6885,14 @@ onComponentSelect, onComponentDelete, onComponentEdit, onComponentUpdate, select
6815
6885
  } }));
6816
6886
  case 'file':
6817
6887
  // Get file value from formValues, or from component basic properties
6818
- // CRITICAL: Check basic.value first (API data structure), then formValue
6819
- const fileFormValue = formValue ||
6820
- component.basic?.value ||
6821
- component.basic?.files ||
6822
- component.basic?.attachments ||
6823
- null;
6888
+ // CRITICAL: formValue could be '' (empty string) which is falsy — check explicitly
6889
+ const hasFormValue = formValue !== undefined && formValue !== null && formValue !== '';
6890
+ const fileFormValue = hasFormValue
6891
+ ? formValue
6892
+ : (component.basic?.value ||
6893
+ component.basic?.files ||
6894
+ component.basic?.attachments ||
6895
+ null);
6824
6896
  return (jsx(DfFormFileUpload, { ...commonProps, properties: component, formValue: fileFormValue }));
6825
6897
  default:
6826
6898
  return (jsx("div", { className: "form-group", children: jsxs("div", { className: "form-group-label", children: ["Unsupported Component: ", component.name] }) }));