({
inputParam,
data,
disabled = false,
onDataChange,
itemParameters: itemParametersProp,
AsyncInputComponent,
ConfigInputComponent,
onConfigChange,
variableItems
}: ArrayInputProps)
| 53 | } |
| 54 | |
| 55 | export function ArrayInput({ |
| 56 | inputParam, |
| 57 | data, |
| 58 | disabled = false, |
| 59 | onDataChange, |
| 60 | itemParameters: itemParametersProp, |
| 61 | AsyncInputComponent, |
| 62 | ConfigInputComponent, |
| 63 | onConfigChange, |
| 64 | variableItems |
| 65 | }: ArrayInputProps) { |
| 66 | const theme = useTheme() |
| 67 | |
| 68 | // Derive array items directly from props (single source of truth) |
| 69 | // Memoized to prevent unnecessary re-renders of child hooks |
| 70 | const arrayItems = useMemo( |
| 71 | () => (Array.isArray(data.inputs?.[inputParam.name]) ? (data.inputs[inputParam.name] as Record<string, unknown>[]) : []), |
| 72 | [data.inputs, inputParam.name] |
| 73 | ) |
| 74 | |
| 75 | const { keys: effectiveKeys, removeKey } = useStableKeys(arrayItems.length, 'item') |
| 76 | |
| 77 | // Use pre-computed itemParameters |
| 78 | // Falls back to raw field definitions for nested arrays without show/hide conditions. |
| 79 | const itemParameters = useMemo<InputParam[][]>( |
| 80 | () => itemParametersProp ?? arrayItems.map(() => inputParam.array || []), |
| 81 | [itemParametersProp, arrayItems, inputParam.array] |
| 82 | ) |
| 83 | |
| 84 | // Handle changes to individual fields within array items |
| 85 | const handleItemInputChange = useCallback( |
| 86 | (itemIndex: number, changedParam: InputParam, newValue: unknown) => { |
| 87 | const updatedArrayItems = [...arrayItems] |
| 88 | const updatedItem = { ...updatedArrayItems[itemIndex] } |
| 89 | |
| 90 | // Update the specific field |
| 91 | updatedItem[changedParam.name] = newValue |
| 92 | updatedArrayItems[itemIndex] = updatedItem |
| 93 | |
| 94 | // Notify parent of change (parent will update props, causing re-render) |
| 95 | onDataChange?.({ inputParam, newValue: updatedArrayItems }) |
| 96 | }, |
| 97 | [arrayItems, inputParam, onDataChange] |
| 98 | ) |
| 99 | |
| 100 | // Add new array item |
| 101 | const handleAddItem = useCallback(() => { |
| 102 | // Initialize new item with type-appropriate default values |
| 103 | const newItem: Record<string, unknown> = {} |
| 104 | |
| 105 | if (inputParam.array) { |
| 106 | for (const field of inputParam.array) { |
| 107 | newItem[field.name] = getDefaultValueForType(field) |
| 108 | } |
| 109 | } |
| 110 | |
| 111 | const updatedArrayItems = [...arrayItems, newItem] |
| 112 |
nothing calls this directly
no test coverage detected