df-ae-forms-package 1.1.3 → 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 +150 -58
- package/dist/index.esm.js.map +1 -1
- package/dist/index.js +150 -58
- package/dist/index.js.map +1 -1
- package/package.json +1 -1
package/dist/index.js
CHANGED
|
@@ -1004,20 +1004,15 @@ const DfFormInput = ({ id, properties, validationErrors = {}, formValue = '', in
|
|
|
1004
1004
|
touchedFields[id] = true;
|
|
1005
1005
|
}
|
|
1006
1006
|
}, [isTouched, id, touchedFields]);
|
|
1007
|
-
// Reset touched state
|
|
1007
|
+
// Reset touched state when switching modes
|
|
1008
1008
|
React.useEffect(() => {
|
|
1009
|
+
setIsTouched(false);
|
|
1010
|
+
// Only reset value when explicitly moving to edit mode to show current default
|
|
1009
1011
|
if (mode === 'edit') {
|
|
1010
|
-
setIsTouched(false);
|
|
1011
|
-
// Reset value to default value when switching to edit mode
|
|
1012
1012
|
const defaultValue = properties?.basic?.defaultValue || '';
|
|
1013
1013
|
setValue(defaultValue);
|
|
1014
1014
|
}
|
|
1015
|
-
|
|
1016
|
-
setIsTouched(false);
|
|
1017
|
-
// Reset value to empty when switching to test mode for fresh start
|
|
1018
|
-
setValue('');
|
|
1019
|
-
}
|
|
1020
|
-
}, [mode, properties?.basic?.defaultValue]);
|
|
1015
|
+
}, [mode]);
|
|
1021
1016
|
// Update value when formValue prop changes (but don't override user input)
|
|
1022
1017
|
// CRITICAL: Only update if formValue is actually for THIS component's ID
|
|
1023
1018
|
// Use componentIdRef to ensure we're checking against the correct component ID
|
|
@@ -2409,6 +2404,7 @@ const DfFormFileUpload = ({ id, properties, validationErrors = {}, formValue = n
|
|
|
2409
2404
|
const [isDragOver, setIsDragOver] = React.useState(false);
|
|
2410
2405
|
const [isTouched, setIsTouched] = React.useState(false);
|
|
2411
2406
|
const fileInputRef = React.useRef(null);
|
|
2407
|
+
const lastFormValueRef = React.useRef(null); // Track the last formValue to prevent unnecessary resets
|
|
2412
2408
|
// Convert FileList or File[] to IFilePreview[]
|
|
2413
2409
|
const convertToFilePreviews = React.useCallback((fileList, startIndex = 0) => {
|
|
2414
2410
|
if (!fileList)
|
|
@@ -2501,12 +2497,20 @@ const DfFormFileUpload = ({ id, properties, validationErrors = {}, formValue = n
|
|
|
2501
2497
|
if (fileObject.url || fileObject.path) {
|
|
2502
2498
|
preview = fileObject.url || fileObject.path;
|
|
2503
2499
|
}
|
|
2504
|
-
else if (
|
|
2505
|
-
// 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';
|
|
2506
2503
|
const fileData = fileObject.data;
|
|
2507
|
-
|
|
2508
|
-
|
|
2509
|
-
|
|
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
|
+
}
|
|
2510
2514
|
}
|
|
2511
2515
|
// Use the original object to preserve data
|
|
2512
2516
|
fileObj = fileObject;
|
|
@@ -2691,10 +2695,35 @@ const DfFormFileUpload = ({ id, properties, validationErrors = {}, formValue = n
|
|
|
2691
2695
|
}
|
|
2692
2696
|
}, [mode]);
|
|
2693
2697
|
// Update value when formValue prop changes or on mount
|
|
2698
|
+
// CRITICAL: Use a stable reference check to prevent unnecessary resets
|
|
2694
2699
|
React.useEffect(() => {
|
|
2695
|
-
//
|
|
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
|
|
2696
2722
|
const newFiles = convertToFilePreviews(formValue);
|
|
2697
|
-
|
|
2723
|
+
if (newFiles.length > 0) {
|
|
2724
|
+
setFiles(newFiles);
|
|
2725
|
+
lastFormValueRef.current = formValue;
|
|
2726
|
+
}
|
|
2698
2727
|
}, [formValue, convertToFilePreviews]);
|
|
2699
2728
|
// Mark as touched when form is submitted
|
|
2700
2729
|
React.useEffect(() => {
|
|
@@ -4967,8 +4996,7 @@ const DfFormDataGrid = ({ id, properties, mode = 'edit', formData = {}, onValueC
|
|
|
4967
4996
|
// This allows the form data to be updated for interactive components
|
|
4968
4997
|
if (onValueChange) {
|
|
4969
4998
|
onValueChange({
|
|
4970
|
-
|
|
4971
|
-
value: change.value
|
|
4999
|
+
...change
|
|
4972
5000
|
});
|
|
4973
5001
|
}
|
|
4974
5002
|
}
|
|
@@ -5439,7 +5467,38 @@ onComponentSelect, onComponentDelete, onComponentEdit, onComponentUpdate, select
|
|
|
5439
5467
|
const initializeComponentValues = (components, values) => {
|
|
5440
5468
|
components.forEach(component => {
|
|
5441
5469
|
const componentId = ensureStringId$1(component.id);
|
|
5442
|
-
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 {
|
|
5443
5502
|
// ALWAYS prioritize existing form state (values param) if it exists
|
|
5444
5503
|
if (values[componentId] !== undefined) ;
|
|
5445
5504
|
// Then use captured value in basic.value
|
|
@@ -5454,10 +5513,10 @@ onComponentSelect, onComponentDelete, onComponentEdit, onComponentUpdate, select
|
|
|
5454
5513
|
else {
|
|
5455
5514
|
// For checkbox and multi-select, empty array
|
|
5456
5515
|
if (component.name === 'checkbox' || component.name === 'select') {
|
|
5457
|
-
values[
|
|
5516
|
+
values[componentId] = [];
|
|
5458
5517
|
}
|
|
5459
5518
|
else {
|
|
5460
|
-
values[
|
|
5519
|
+
values[componentId] = '';
|
|
5461
5520
|
}
|
|
5462
5521
|
}
|
|
5463
5522
|
}
|
|
@@ -5479,31 +5538,10 @@ onComponentSelect, onComponentDelete, onComponentEdit, onComponentUpdate, select
|
|
|
5479
5538
|
}
|
|
5480
5539
|
});
|
|
5481
5540
|
}
|
|
5482
|
-
// Handle file component - initialize with file data if present
|
|
5483
|
-
if (component.name === 'file' && component.basic) {
|
|
5484
|
-
const fileData = component.basic.files || component.basic.attachments || component.basic.value;
|
|
5485
|
-
if (fileData) {
|
|
5486
|
-
values[component.id] = fileData;
|
|
5487
|
-
}
|
|
5488
|
-
}
|
|
5489
5541
|
// Initialize notes and attachments
|
|
5490
|
-
if (
|
|
5542
|
+
if (componentId && component.basic) {
|
|
5491
5543
|
if (component.basic.notes) ;
|
|
5492
5544
|
}
|
|
5493
|
-
// Handle instructions component - ensure instructions array exists and initialize formValue
|
|
5494
|
-
if (component.name === 'instructions' && component.basic) {
|
|
5495
|
-
if (!component.basic.instructions) {
|
|
5496
|
-
// Initialize empty instructions array if not present
|
|
5497
|
-
component.basic.instructions = [];
|
|
5498
|
-
}
|
|
5499
|
-
// CRITICAL: Initialize formValue for instructions from API data
|
|
5500
|
-
// Check if component has value from API (could be in basic.value, basic.instructions, or formData)
|
|
5501
|
-
const instructionValue = component.basic.value || component.basic.instructions;
|
|
5502
|
-
if (instructionValue) {
|
|
5503
|
-
// Store instruction data in formValues so it can be passed to DfFormInstruction
|
|
5504
|
-
values[component.id] = instructionValue;
|
|
5505
|
-
}
|
|
5506
|
-
}
|
|
5507
5545
|
// Handle nested components in section children
|
|
5508
5546
|
if (component.children && Array.isArray(component.children)) {
|
|
5509
5547
|
initializeComponentValues(component.children, values);
|
|
@@ -5663,8 +5701,34 @@ onComponentSelect, onComponentDelete, onComponentEdit, onComponentUpdate, select
|
|
|
5663
5701
|
}
|
|
5664
5702
|
// Set the state
|
|
5665
5703
|
setFormValues(prev => {
|
|
5666
|
-
//
|
|
5667
|
-
|
|
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;
|
|
5668
5732
|
});
|
|
5669
5733
|
// Initialize notes and attachments state
|
|
5670
5734
|
setComponentNotes(prev => ({ ...initialNotes, ...prev }));
|
|
@@ -5684,9 +5748,35 @@ onComponentSelect, onComponentDelete, onComponentEdit, onComponentUpdate, select
|
|
|
5684
5748
|
return;
|
|
5685
5749
|
}
|
|
5686
5750
|
// CRITICAL: Check if multiple components share this ID (ID collision detection)
|
|
5687
|
-
|
|
5751
|
+
// Use recursive search for accurate detection across all levels
|
|
5752
|
+
const checkIdCollision = (components, targetId) => {
|
|
5753
|
+
let matches = [];
|
|
5754
|
+
components.forEach(comp => {
|
|
5755
|
+
if (ensureStringId$1(comp.id) === targetId)
|
|
5756
|
+
matches.push(comp);
|
|
5757
|
+
if (comp.name === 'section' && comp.children) {
|
|
5758
|
+
matches = [...matches, ...checkIdCollision(comp.children, targetId)];
|
|
5759
|
+
}
|
|
5760
|
+
if (comp.name === 'table' && comp.cells) {
|
|
5761
|
+
comp.cells.forEach((row) => {
|
|
5762
|
+
normalizeTableRow(row).forEach((cell) => {
|
|
5763
|
+
if (cell.components)
|
|
5764
|
+
matches = [...matches, ...checkIdCollision(cell.components, targetId)];
|
|
5765
|
+
});
|
|
5766
|
+
});
|
|
5767
|
+
}
|
|
5768
|
+
if (comp.name === 'datagrid' && comp.entries) {
|
|
5769
|
+
comp.entries.forEach((entry) => {
|
|
5770
|
+
if (entry.components)
|
|
5771
|
+
matches = [...matches, ...checkIdCollision(entry.components, targetId)];
|
|
5772
|
+
});
|
|
5773
|
+
}
|
|
5774
|
+
});
|
|
5775
|
+
return matches;
|
|
5776
|
+
};
|
|
5777
|
+
const componentsWithSameId = checkIdCollision(localFormComponents, change.id);
|
|
5688
5778
|
if (componentsWithSameId.length > 1) {
|
|
5689
|
-
console.error(`[DfFormPreview] ID COLLISION DETECTED! Multiple components share ID "${change.id}":`, componentsWithSameId.map(c => ({ id: c.id, name: c.name, label: c.basic?.label })));
|
|
5779
|
+
console.error(`[DfFormPreview] ID COLLISION DETECTED! Multiple components share ID "${change.id}":`, componentsWithSameId.map(c => ({ id: ensureStringId$1(c.id), name: c.name, label: c.basic?.label })));
|
|
5690
5780
|
// Don't update - this would cause all components with this ID to get the same value
|
|
5691
5781
|
return;
|
|
5692
5782
|
}
|
|
@@ -5705,7 +5795,7 @@ onComponentSelect, onComponentDelete, onComponentEdit, onComponentUpdate, select
|
|
|
5705
5795
|
}
|
|
5706
5796
|
// Clear raised issues for this component when value changes
|
|
5707
5797
|
// This ensures that if threshold condition changes, user must raise issue again
|
|
5708
|
-
const component = localFormComponents
|
|
5798
|
+
const component = findComponentById(localFormComponents, change.id);
|
|
5709
5799
|
if (component) {
|
|
5710
5800
|
const threshold = component?.threshold;
|
|
5711
5801
|
if (threshold && threshold.conditions && threshold.conditions.length > 0) {
|
|
@@ -5721,7 +5811,8 @@ onComponentSelect, onComponentDelete, onComponentEdit, onComponentUpdate, select
|
|
|
5721
5811
|
// Recursive function to update component values
|
|
5722
5812
|
const updateComponentValue = (components) => {
|
|
5723
5813
|
return components.map(component => {
|
|
5724
|
-
|
|
5814
|
+
const componentId = ensureStringId$1(component.id);
|
|
5815
|
+
if (componentId === change.id) {
|
|
5725
5816
|
// CRITICAL: Handle table/datagrid structure updates (cells, entries, etc.)
|
|
5726
5817
|
// When a table sends onValueChange with cells data, update the whole component structure
|
|
5727
5818
|
if (change.value && typeof change.value === 'object' && 'cells' in change.value) {
|
|
@@ -5737,13 +5828,12 @@ onComponentSelect, onComponentDelete, onComponentEdit, onComponentUpdate, select
|
|
|
5737
5828
|
...change.value
|
|
5738
5829
|
};
|
|
5739
5830
|
}
|
|
5740
|
-
if ('defaultValue' in component.basic) {
|
|
5831
|
+
if ('value' in component.basic || 'defaultValue' in component.basic) {
|
|
5741
5832
|
return {
|
|
5742
5833
|
...component,
|
|
5743
5834
|
basic: {
|
|
5744
5835
|
...component.basic,
|
|
5745
|
-
value: change.value
|
|
5746
|
-
defaultValue: change.value
|
|
5836
|
+
value: change.value
|
|
5747
5837
|
}
|
|
5748
5838
|
};
|
|
5749
5839
|
}
|
|
@@ -6797,12 +6887,14 @@ onComponentSelect, onComponentDelete, onComponentEdit, onComponentUpdate, select
|
|
|
6797
6887
|
} }));
|
|
6798
6888
|
case 'file':
|
|
6799
6889
|
// Get file value from formValues, or from component basic properties
|
|
6800
|
-
// CRITICAL:
|
|
6801
|
-
const
|
|
6802
|
-
|
|
6803
|
-
|
|
6804
|
-
component.basic?.
|
|
6805
|
-
|
|
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);
|
|
6806
6898
|
return (jsxRuntime.jsx(DfFormFileUpload, { ...commonProps, properties: component, formValue: fileFormValue }));
|
|
6807
6899
|
default:
|
|
6808
6900
|
return (jsxRuntime.jsx("div", { className: "form-group", children: jsxRuntime.jsxs("div", { className: "form-group-label", children: ["Unsupported Component: ", component.name] }) }));
|