df-ae-forms-package 1.1.1 → 1.1.2

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
@@ -4241,6 +4241,33 @@ const ComponentSubmissionActions = ({ component }) => {
4241
4241
  return (jsx("div", { className: "component-submission-actions", children: jsxs("div", { className: "actions-content", children: [hasNotes && (jsx("div", { className: "notes-summary-section", children: jsxs("div", { className: "notes-full-text", children: [jsx("span", { className: "notes-label", children: "Notes:" }), " ", notes] }) })), hasAttachments && (jsx("div", { className: "attachments-section", children: jsx(SubmissionAttachmentThumbnails, { attachments: attachments }) }))] }) }));
4242
4242
  };
4243
4243
 
4244
+ // Helper to ensure an ID is a stable string, handling MongoDB-style object IDs
4245
+ // Helper to ensure an ID is a stable string, handling MongoDB-style object IDs
4246
+ function ensureStringId$2(id) {
4247
+ if (!id)
4248
+ return '';
4249
+ if (typeof id === 'string') {
4250
+ if (id.includes('[object Object]'))
4251
+ return '';
4252
+ return id;
4253
+ }
4254
+ if (typeof id === 'object' && id !== null) {
4255
+ if (id.$oid)
4256
+ return String(id.$oid);
4257
+ if (id._id)
4258
+ return ensureStringId$2(id._id);
4259
+ try {
4260
+ const str = id.toString();
4261
+ if (str && str !== '[object Object]')
4262
+ return str;
4263
+ return JSON.stringify(id);
4264
+ }
4265
+ catch (e) {
4266
+ return 'id-error';
4267
+ }
4268
+ }
4269
+ return String(id);
4270
+ }
4244
4271
  const DraggableGridComponent = ({ component, selectedComponent, mode, onComponentSelect, onComponentDelete, onComponentEdit, renderFormComponent, isOverlay = false, formData = {}, formTemplateId, onThresholdActionCompletion, onThresholdIssueRaised, onNotesChange, onAttachmentChange, shouldShowComponent }) => {
4245
4272
  const formValue = formData[component.id];
4246
4273
  const isVisible = shouldShowComponent ? shouldShowComponent(component.id) : true;
@@ -4492,7 +4519,7 @@ formTemplateId, onThresholdActionCompletion, onThresholdIssueRaised, onNotesChan
4492
4519
  let entryComponent = entry.components?.[componentIndex];
4493
4520
  if (!entryComponent) {
4494
4521
  // Use entry.id (which is unique) instead of entryIndex to prevent data collisions
4495
- const uniqueId = `${templateComponent.id || 'comp'}-${entry.id}-${componentIndex}`;
4522
+ const uniqueId = `${ensureStringId$2(templateComponent.id) || 'comp'}-${ensureStringId$2(entry.id)}-${componentIndex}`;
4496
4523
  entryComponent = {
4497
4524
  ...templateComponent,
4498
4525
  id: uniqueId,
@@ -4505,7 +4532,7 @@ formTemplateId, onThresholdActionCompletion, onThresholdIssueRaised, onNotesChan
4505
4532
  else {
4506
4533
  entryComponent = {
4507
4534
  ...entryComponent,
4508
- id: entryComponent.id || `${templateComponent.id || 'comp'}-${entry.id}-${componentIndex}`,
4535
+ id: ensureStringId$2(entryComponent.id) || `${ensureStringId$2(templateComponent.id) || 'comp'}-${ensureStringId$2(entry.id)}-${componentIndex}`,
4509
4536
  basic: {
4510
4537
  ...entryComponent.basic,
4511
4538
  showLabel: columnView // Show label in column view
@@ -4629,7 +4656,7 @@ formTemplateId, onThresholdActionCompletion, onThresholdIssueRaised, onNotesChan
4629
4656
  comp.basic?.label === templateComponent.basic?.label);
4630
4657
  }
4631
4658
  if (!entryComponent) {
4632
- const uniqueId = `${templateComponent.id || 'comp'}-${entry.id}-${componentIndex}`;
4659
+ const uniqueId = `${ensureStringId$2(templateComponent.id) || 'comp'}-${ensureStringId$2(entry.id)}-${componentIndex}`;
4633
4660
  entryComponent = {
4634
4661
  ...templateComponent,
4635
4662
  id: uniqueId,
@@ -4642,7 +4669,7 @@ formTemplateId, onThresholdActionCompletion, onThresholdIssueRaised, onNotesChan
4642
4669
  else {
4643
4670
  entryComponent = {
4644
4671
  ...entryComponent,
4645
- id: entryComponent.id || `${templateComponent.id || 'comp'}-${entry.id}-${componentIndex}`,
4672
+ id: ensureStringId$2(entryComponent.id) || `${ensureStringId$2(templateComponent.id) || 'comp'}-${ensureStringId$2(entry.id)}-${componentIndex}`,
4646
4673
  basic: {
4647
4674
  ...entryComponent.basic,
4648
4675
  showLabel: columnView // Show label in column view, hide in grid view
@@ -4710,10 +4737,11 @@ formTemplateId, onThresholdActionCompletion, onThresholdIssueRaised, onNotesChan
4710
4737
  const DfFormDataGrid = ({ id, properties, mode = 'edit', formData = {}, onValueChange, onSelect, isSelected = false, className = '', onDataGridSelect, onComponentSelect, onComponentDelete, onComponentEdit, onComponentUpdate, selectedComponent, renderFormComponent, onEntryAdd, onEntryRemove, formTemplateId, onThresholdActionCompletion, onThresholdIssueRaised, onNotesChange, onAttachmentChange, shouldShowComponent }) => {
4711
4738
  const [isCollapsed, setIsCollapsed] = useState(false);
4712
4739
  const hasInitialized = useRef(false);
4740
+ const gridId = ensureStringId$2(id);
4713
4741
  // Get all components in the grid and sanitize them to ensure no data leaks into templates
4714
4742
  let gridComponents = (properties.templateComponents || []).map((comp, index) => ({
4715
4743
  ...comp,
4716
- id: comp.id || `${id}-template-${index}`, // CRITICAL: Ensure template components have stable IDs
4744
+ id: ensureStringId$2(comp.id) || `${gridId}-template-${index}`, // CRITICAL: Ensure template components have stable string IDs
4717
4745
  basic: {
4718
4746
  ...comp.basic,
4719
4747
  // Use an empty string instead of undefined to satisfy component typing
@@ -4727,7 +4755,7 @@ const DfFormDataGrid = ({ id, properties, mode = 'edit', formData = {}, onValueC
4727
4755
  gridComponents = dataEntries[0].components.map((comp, index) => ({
4728
4756
  ...comp,
4729
4757
  // Remove entry suffix for template, use stable ID if missing
4730
- id: comp.id?.replace(/-entry-.*$/, '') || `${id}-template-${index}`,
4758
+ id: ensureStringId$2(comp.id).replace(/-entry-.*$/, '') || `${gridId}-template-${index}`,
4731
4759
  basic: {
4732
4760
  ...comp.basic,
4733
4761
  // Clear any data values while keeping types happy
@@ -4770,7 +4798,7 @@ const DfFormDataGrid = ({ id, properties, mode = 'edit', formData = {}, onValueC
4770
4798
  index: 0,
4771
4799
  components: gridComponents.map((comp, componentIndex) => ({
4772
4800
  ...comp,
4773
- id: `${comp.id}-${newEntryId}-${componentIndex}`,
4801
+ id: `${ensureStringId$2(comp.id)}-${newEntryId}-${componentIndex}`,
4774
4802
  basic: {
4775
4803
  ...comp.basic,
4776
4804
  showLabel: false // Hide label in datagrid cells
@@ -4825,8 +4853,10 @@ const DfFormDataGrid = ({ id, properties, mode = 'edit', formData = {}, onValueC
4825
4853
  // Update existing component with new template properties while ensuring unique ID and preserving form values
4826
4854
  const updatedComponent = {
4827
4855
  ...templateComp,
4828
- // Preserve existing ID or generate one if missing
4829
- id: existingComponent.id || `${templateComp.id}-${entry.id}-${componentIndex}`,
4856
+ // Preserve existing ID (ensure it's a string) or generate one if missing
4857
+ id: (existingComponent.id && typeof existingComponent.id === 'string')
4858
+ ? existingComponent.id
4859
+ : `${ensureStringId$2(templateComp.id)}-${ensureStringId$2(entry.id)}-${componentIndex}`,
4830
4860
  basic: {
4831
4861
  ...templateComp.basic,
4832
4862
  showLabel: false, // Hide label in datagrid cells
@@ -4840,7 +4870,7 @@ const DfFormDataGrid = ({ id, properties, mode = 'edit', formData = {}, onValueC
4840
4870
  // Create new component based on template
4841
4871
  // Only for NEW components in existing entries (e.g. column added) do we generate a new ID
4842
4872
  const uniqueSuffix = `${Date.now()}-${Math.random().toString(36).substr(2, 5)}`;
4843
- const newId = `${templateComp.id}-${uniqueSuffix}-${componentIndex}`;
4873
+ const newId = `${ensureStringId$2(templateComp.id)}-${uniqueSuffix}-${componentIndex}`;
4844
4874
  const newComponent = {
4845
4875
  ...templateComp,
4846
4876
  id: newId,
@@ -4946,7 +4976,7 @@ const DfFormDataGrid = ({ id, properties, mode = 'edit', formData = {}, onValueC
4946
4976
  id: newEntryId,
4947
4977
  index: properties.entries.length,
4948
4978
  components: gridComponents.map((comp, componentIndex) => {
4949
- const componentId = `${comp.id}-${newEntryId}-${componentIndex}`;
4979
+ const componentId = `${ensureStringId$2(comp.id)}-${newEntryId}-${componentIndex}`;
4950
4980
  return {
4951
4981
  ...comp,
4952
4982
  // Use the unique entry ID in the component ID to prevent collisions
@@ -5310,6 +5340,37 @@ const DfFormSection = ({ id, properties, mode = 'edit', formData = {}, onValueCh
5310
5340
 
5311
5341
  // Dynamic imports to avoid circular dependencies
5312
5342
  const DfFormTable$1 = React.lazy(() => Promise.resolve().then(function () { return dfFormTable; }));
5343
+ // Helper to ensure an ID is a stable string, handling MongoDB-style object IDs
5344
+ // This is used globally in this file to prevent [object Object] corruption
5345
+ const ensureStringId$1 = (id) => {
5346
+ if (!id)
5347
+ return '';
5348
+ if (typeof id === 'string') {
5349
+ // If the ID is already corrupted, return empty to trigger regeneration
5350
+ if (id.includes('[object Object]'))
5351
+ return '';
5352
+ return id;
5353
+ }
5354
+ if (typeof id === 'object' && id !== null) {
5355
+ if (id.$oid)
5356
+ return String(id.$oid);
5357
+ if (id._id)
5358
+ return ensureStringId$1(id._id);
5359
+ // Fallback for other object structures that might be IDs
5360
+ try {
5361
+ // If it has a toString that isn't the default, use it
5362
+ const str = id.toString();
5363
+ if (str && str !== '[object Object]')
5364
+ return str;
5365
+ // Otherwise, use a hash or just JSON
5366
+ return JSON.stringify(id);
5367
+ }
5368
+ catch (e) {
5369
+ return 'id-error';
5370
+ }
5371
+ }
5372
+ return String(id);
5373
+ };
5313
5374
  // Normalize a table row from API format (object with numeric keys) into a proper array.
5314
5375
  // The API may return cells as [{"0": {cell}, "1": {cell}}, ...] instead of [[cell, cell], ...].
5315
5376
  const normalizeTableRow = (row) => {
@@ -5355,16 +5416,17 @@ onComponentSelect, onComponentDelete, onComponentEdit, onComponentUpdate, select
5355
5416
  // Recursive function to initialize values from nested components
5356
5417
  const initializeComponentValues = (components, values) => {
5357
5418
  components.forEach(component => {
5358
- if (component.id) {
5419
+ const componentId = ensureStringId$1(component.id);
5420
+ if (componentId) {
5359
5421
  // ALWAYS prioritize existing form state (values param) if it exists
5360
- if (values[component.id] !== undefined) ;
5361
- // Then check initialFormData (if we are merging it) - handled by caller usually, but safe to check
5362
- else if (component.basic && 'value' in component.basic && component.basic.value !== undefined && component.basic.value !== '' && component.basic.value !== null) {
5363
- values[component.id] = component.basic.value;
5422
+ if (values[componentId] !== undefined) ;
5423
+ // Then use captured value in basic.value
5424
+ else if (component.basic && 'value' in component.basic && component.basic.value !== undefined) {
5425
+ values[componentId] = component.basic.value;
5364
5426
  }
5365
- // Then check defaultValue
5366
- else if (component.basic && 'defaultValue' in component.basic && component.basic.defaultValue !== undefined && component.basic.defaultValue !== '' && component.basic.defaultValue !== null) {
5367
- values[component.id] = component.basic.defaultValue;
5427
+ // Then use defaultValue
5428
+ else if (component.basic && 'defaultValue' in component.basic && component.basic.defaultValue !== undefined) {
5429
+ values[componentId] = component.basic.defaultValue;
5368
5430
  }
5369
5431
  // Only then default to empty
5370
5432
  else {
@@ -5434,12 +5496,13 @@ onComponentSelect, onComponentDelete, onComponentEdit, onComponentUpdate, select
5434
5496
  // Helper to extract notes and attachments recursively
5435
5497
  const extractNotesAndAttachments = (components) => {
5436
5498
  components.forEach(comp => {
5437
- if (comp.id) {
5499
+ const componentId = ensureStringId$1(comp.id);
5500
+ if (componentId) {
5438
5501
  if (comp.basic?.notes || comp.basic?.comments) {
5439
- initialNotes[comp.id] = comp.basic?.notes || comp.basic?.comments;
5502
+ initialNotes[componentId] = comp.basic?.notes || comp.basic?.comments;
5440
5503
  }
5441
5504
  if (comp.basic?.attachments) {
5442
- initialAttachments[comp.id] = comp.basic.attachments;
5505
+ initialAttachments[componentId] = comp.basic.attachments;
5443
5506
  }
5444
5507
  }
5445
5508
  // Recurse
@@ -5461,27 +5524,43 @@ onComponentSelect, onComponentDelete, onComponentEdit, onComponentUpdate, select
5461
5524
  };
5462
5525
  // Validate component IDs for uniqueness without mutating original props
5463
5526
  const getValidatedComponents = (components, parentId) => {
5527
+ const parentIdStr = parentId ? ensureStringId$1(parentId) : '';
5464
5528
  return components.map((component, index) => {
5465
5529
  let validatedComponent = { ...component };
5466
- // Ensure component has an ID
5467
- if (!validatedComponent.id || typeof validatedComponent.id !== 'string' || validatedComponent.id.trim() === '') {
5530
+ // Ensure component has a valid string ID
5531
+ let currentId = validatedComponent.id;
5532
+ // CRITICAL: Reject any ID that is not a string, is empty, or contains "[object Object]"
5533
+ let isIdValid = typeof currentId === 'string' &&
5534
+ currentId.trim() !== '' &&
5535
+ !currentId.includes('[object Object]');
5536
+ if (!isIdValid) {
5537
+ // If it's an object ID (but not a corrupted string), convert it to string
5538
+ if (currentId && typeof currentId === 'object') {
5539
+ const convertedId = ensureStringId$1(currentId);
5540
+ if (convertedId && !convertedId.includes('[object Object]')) {
5541
+ validatedComponent.id = convertedId;
5542
+ isIdValid = true;
5543
+ }
5544
+ }
5545
+ }
5546
+ if (!isIdValid) {
5468
5547
  // Determine a base name for the ID
5469
5548
  const name = validatedComponent.name || 'component';
5470
5549
  const label = validatedComponent.basic?.label || '';
5471
5550
  const safeLabel = label.replace(/[^a-zA-Z0-9]/g, '').toLowerCase().substring(0, 10);
5472
5551
  // Generate a stable unique ID if parentId is provided, otherwise fallback to semi-stable
5473
- if (parentId) {
5474
- validatedComponent.id = `${parentId}-${name}-${index}`;
5552
+ if (parentIdStr) {
5553
+ validatedComponent.id = `${parentIdStr}-${name}-${index}`;
5475
5554
  }
5476
5555
  else {
5477
5556
  // For root components, use label if available for stability
5478
5557
  const labelPart = safeLabel ? `-${safeLabel}` : '';
5479
5558
  validatedComponent.id = `${name}${labelPart}-${index}`;
5480
5559
  }
5481
- console.warn(`[DfFormPreview] Assigned missing ID: ${validatedComponent.id}`);
5560
+ console.warn(`[DfFormPreview] Fixed missing/invalid ID: ${validatedComponent.id}`);
5482
5561
  }
5483
5562
  else {
5484
- // Check for duplicates
5563
+ // ID is a valid string, check for duplicates
5485
5564
  if (seenIds.has(validatedComponent.id)) {
5486
5565
  console.error(`[DfFormPreview] Duplicate component ID detected: ${validatedComponent.id}`);
5487
5566
  // Generate a unique ID for duplicate - using index to keep it somewhat stable
@@ -5501,7 +5580,7 @@ onComponentSelect, onComponentDelete, onComponentEdit, onComponentUpdate, select
5501
5580
  return normalizedRow.map((cell, cellIndex) => {
5502
5581
  if (cell && cell.components && Array.isArray(cell.components)) {
5503
5582
  // Stable ID for table cells: tableId-row-X-cell-Y
5504
- const cellContextId = `${validatedComponent.id}-row-${rowIndex}-cell-${cellIndex}`;
5583
+ const cellContextId = `${ensureStringId$1(validatedComponent.id)}-row-${rowIndex}-cell-${cellIndex}`;
5505
5584
  return {
5506
5585
  ...cell,
5507
5586
  components: getValidatedComponents(cell.components, cellContextId)
@@ -5517,9 +5596,11 @@ onComponentSelect, onComponentDelete, onComponentEdit, onComponentUpdate, select
5517
5596
  validatedComponent.entries = validatedComponent.entries.map((entry) => {
5518
5597
  if (entry && entry.components && Array.isArray(entry.components)) {
5519
5598
  // Stable ID for datagrid entries: datagridId-entryId or using entry.id
5599
+ const entryId = entry.id ? ensureStringId$1(entry.id) : `${ensureStringId$1(validatedComponent.id)}-entry-${entry.index}`;
5520
5600
  return {
5521
5601
  ...entry,
5522
- components: getValidatedComponents(entry.components, entry.id || `${validatedComponent.id}-entry-${entry.index}`)
5602
+ id: entryId, // Ensure entry itself has a string ID
5603
+ components: getValidatedComponents(entry.components, entryId)
5523
5604
  };
5524
5605
  }
5525
5606
  return entry;
@@ -6312,13 +6393,10 @@ onComponentSelect, onComponentDelete, onComponentEdit, onComponentUpdate, select
6312
6393
  const componentIdCacheRef = useRef(new Map());
6313
6394
  const componentCounterRef = useRef(0);
6314
6395
  const renderFormComponent = (component) => {
6315
- // CRITICAL: Ensure component has a valid unique ID
6396
+ // CRITICAL: Ensure component has a valid unique string ID
6316
6397
  // NEVER regenerate IDs - always use existing or cached ID
6317
- let finalComponentId;
6318
- if (component.id && typeof component.id === 'string' && component.id.trim() !== '') {
6319
- // Component already has an ID - use it (most common case)
6320
- finalComponentId = component.id;
6321
- }
6398
+ let finalComponentId = ensureStringId$1(component.id);
6399
+ if (finalComponentId && finalComponentId.trim() !== '') ;
6322
6400
  else {
6323
6401
  // Component is missing an ID - need to generate and cache it
6324
6402
  // Create a stable cache key using component properties that don't change
@@ -6804,6 +6882,32 @@ const DfFormComments = ({ comment = '', onSave, placeholder = 'Enter your reason
6804
6882
  return (jsxs("div", { className: `df-form-comments ${className}`, children: [jsxs("div", { className: "df-form-comments__header", children: [jsx("h3", { className: "df-form-comments__title", children: "Comments" }), jsx("button", { className: "df-form-comments__toggle", type: "button", onClick: toggleComments, "aria-expanded": isExpanded, "aria-label": "Toggle comments section", disabled: disabled, children: isExpanded ? (jsx("span", { className: "df-form-comments__toggle-icon", children: "\u25BC" })) : (jsx("span", { className: "df-form-comments__toggle-icon", children: "\u25B6" })) })] }), jsx("div", { className: `df-form-comments__content ${isExpanded ? 'df-form-comments__content--expanded' : ''}`, children: jsx("div", { className: "df-form-comments__input-container", children: jsx("div", { className: "df-form-comments__input-line", children: jsx("input", { type: "text", id: "comment-input", className: "df-form-comments__input", value: currentComment, onChange: handleInputChange, onBlur: handleInputBlur, onFocus: handleInputFocus, placeholder: placeholder, disabled: disabled }) }) }) })] }));
6805
6883
  };
6806
6884
 
6885
+ // Helper to ensure an ID is a stable string, handling MongoDB-style object IDs
6886
+ const ensureStringId = (id) => {
6887
+ if (!id)
6888
+ return '';
6889
+ if (typeof id === 'string') {
6890
+ if (id.includes('[object Object]'))
6891
+ return '';
6892
+ return id;
6893
+ }
6894
+ if (typeof id === 'object' && id !== null) {
6895
+ if (id.$oid)
6896
+ return String(id.$oid);
6897
+ if (id._id)
6898
+ return ensureStringId(id._id);
6899
+ try {
6900
+ const str = id.toString();
6901
+ if (str && str !== '[object Object]')
6902
+ return str;
6903
+ return JSON.stringify(id);
6904
+ }
6905
+ catch (e) {
6906
+ return 'id-error';
6907
+ }
6908
+ }
6909
+ return String(id);
6910
+ };
6807
6911
  // Normalize a row from the API format (object with numeric keys) into a proper TableCell array.
6808
6912
  // The API may return cells as [{"0": {cell}, "1": {cell}}, ...] instead of [[cell, cell], ...].
6809
6913
  const normalizeRow = (row) => {
@@ -6998,13 +7102,15 @@ const DfFormTable = ({ id, properties, mode = 'edit', formData = {}, validationE
6998
7102
  ? cell.components.map((comp, compIndex) => {
6999
7103
  // CRITICAL: Only generate ID if it's missing - never regenerate existing IDs
7000
7104
  // This prevents component remounting and losing input state
7001
- if (comp.id && typeof comp.id === 'string' && comp.id.trim() !== '') {
7002
- // ID already exists - keep it as is
7003
- return comp;
7105
+ const existingId = ensureStringId(comp.id);
7106
+ if (existingId) {
7107
+ // ID already exists and is valid - keep it but ensure it's a string
7108
+ return { ...comp, id: existingId };
7004
7109
  }
7005
7110
  // Generate unique ID that includes table ID, row, cell, and component index
7006
7111
  // This ensures no conflicts with other components
7007
- const uniqueId = `${comp.name || 'component'}-table-${id}-row-${rowIndex}-cell-${cellIndex}-comp-${compIndex}`;
7112
+ const sanitizedTableId = ensureStringId(id);
7113
+ const uniqueId = `${comp.name || 'component'}-table-${sanitizedTableId}-row-${rowIndex}-cell-${cellIndex}-comp-${compIndex}`;
7008
7114
  return {
7009
7115
  ...comp,
7010
7116
  id: uniqueId