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