DynamicListField
DynamicListField gestiona un array de objetos. Cada item del array se renderiza como una fila cuyas celdas están definidas por la prop slots. Los tipos de slot soportados son text, number, longText, radio, object, autocomplete, counter, calculated y template. Los items pueden agregarse via botón, via un selector autocomplete, o ambos. Las filas pueden reordenarse opcionalmente con flechas arriba/abajo.
Props
| Prop | Tipo | Requerido | Por defecto | Descripción |
|------|------|-----------|-------------|-------------|
| value | any[] | Sí | — | El array actual de objetos item. |
| onChange | (items: any[]) => void | Sí | — | Llamado con el array actualizado ante cualquier mutación. |
| slots | Slot[] | Sí | — | Definiciones de columna/celda para cada fila (ver forma Slot más abajo). |
| label | string | No | — | Etiqueta mostrada en el encabezado del campo. |
| description | string | No | — | Texto de ayuda mostrado debajo del campo. |
| canAddItems | boolean | No | true | Si se muestra el botón "Agregar item". |
| canRemoveItems | boolean | No | true | Si se muestra el botón de eliminar en cada fila. |
| isSortable | boolean | No | false | Si se muestran botones de flecha arriba/abajo en cada fila. |
| addItemMode | 'button' \| 'autocomplete' \| 'both' | No | — | Controla qué mecanismos de agregar se muestran. |
| addItemPickerConfig | AddItemPickerConfig | No | — | Configuración del selector autocomplete. Ver forma más abajo. |
| getDefaultItem | (ctx: { slots: Slot[]; items: any[] }) => Record<string, any> | No | — | Función fábrica que devuelve el valor inicial para un item nuevo. |
| breakpoint | number | No | 800 | Ancho de viewport (px) por debajo del cual el layout de fila cambia a columna. |
| forceMobileView | boolean | No | false | Fuerza el layout de columna independientemente del ancho de viewport. |
| itemStyle | React.CSSProperties | No | — | Estilos aplicados a cada contenedor de fila. |
| containerStyle | React.CSSProperties | No | — | Estilos del FieldContainer exterior. |
| headerStyle | React.CSSProperties | No | — | Estilos del área de encabezado del campo. |
| bodyStyle | React.CSSProperties | No | — | Estilos del área de cuerpo del campo. |
| labelStyle | React.CSSProperties | No | — | Estilos del elemento de etiqueta. |
| descriptionStyle | React.CSSProperties | No | — | Estilos del párrafo de descripción. |
| className | string | No | — | Clase CSS del contenedor exterior. |
| id | string | No | — | Atributo id del contenedor. |
Forma de Slot
interface Slot {
type: 'text' | 'number' | 'longText' | 'radio' | 'object' | 'autocomplete' | 'counter' | 'calculated' | 'template';
name: string; // Clave para leer/escribir el valor en cada objeto item
label?: string; // Etiqueta de columna opcional
config?: Record<string, any>; // Configuración específica del tipo
}
Uso
Lista básica con slots de texto y número
import React, { useState } from 'react';
import DynamicListField from '@/components/fields/DynamicListField';
const slots = [
{ type: 'text', name: 'description', label: 'Descripción', config: { placeholder: 'Ingresa descripción' } },
{ type: 'number', name: 'quantity', label: 'Cant.', config: { min: 1 } },
{ type: 'number', name: 'price', label: 'Precio', config: { step: 0.01 } },
];
export default function Example() {
const [items, setItems] = useState([]);
return (
<DynamicListField
label="Líneas del pedido"
slots={slots}
value={items}
onChange={setItems}
/>
);
}
Con selector autocomplete y ordenamiento
<DynamicListField
label="Productos"
slots={[
{ type: 'text', name: 'name', label: 'Nombre' },
{ type: 'counter', name: 'qty', label: 'Cant.', config: { minValue: 1 } },
]}
value={lines}
onChange={setLines}
isSortable={true}
addItemMode="both"
addItemPickerConfig={{
apiBaseUrl: 'https://api.example.com',
path: '/v1/products',
searchParam: 'q',
mapOptionToItem: (opt) => ({ name: opt.name, qty: 1 }),
getOptionId: (opt) => opt.id,
getItemId: (item) => item.id,
}}
/>