Dynamic Form
import { DynamicForm, FormField } from "kamey-components";
const App = () => {
// Definimos los campos del formulario y podemos tiparlos con FormField const fields: FormField[] = [ { type: 'text', name: 'name', label: 'Nombre', validations: [ { required: { value: true, message: 'El nombre es requerido' } } ], }, { type: 'text', name: 'lastName', label: 'Apellido', validations: [ { required: { value: true, message: 'El apellido es requerido' } } ], }, { type: 'email', name: 'email', label: 'Correo', validations: [ { required: { value: true, message: 'El correo es requerido' } }, { email: { value: true, message: 'El correo no es válido' } } ], }, { type: 'password', name: 'password', label: 'Contraseña', validations: [ { required: { value: true, message: 'La contraseña es requerida' } } ], } ]
return ( <div> <DynamicForm title='Crear Usuario' description='Por favor, ingrese los datos del usuario' icon={<FaUser />} fields={fields} submitButtonText='Crear Usuario' /> </div> );
};
export default App;
Características Principales
- ✅ Configuración declarativa de campos
- ✅ Validaciones integradas y personalizables
- ✅ Soporte para layouts vertical/horizontal
- ✅ Integración con APIs (CRUD)
- ✅ Campos responsivos en múltiples columnas
- ✅ Modos creación/actualización
Uso Básico
// Ejemplo mínimo de implementación<DynamicForm fields={[{ type: "text", name: "example", label: "Ejemplo" }]} />
API Reference
Propiedades del Componente
Propiedad | Descripción | Tipo | Por defecto | Requerido |
---|---|---|---|---|
mode | Modo de operación (‘create’ para crear nuevos registros, ‘update’ para editar) | ‘create’ | ‘update' | 'create’ | Sí |
title | Título principal del formulario | string | - | No |
description | Texto descriptivo debajo del título | string | ReactElement | - | No |
icon | Icono que acompaña al título | ReactElement | - | No |
layout | Disposicíon de los campos | ’vertical’ | ‘horizontal' | 'vertical’ | No |
cols | Número de columnas para organización responsiva | number | 1 | No |
fields | Configuracíon de campos del formulario | FormField[] | FormField[][] | - | Sí |
submitButtonText | Texto personalizado para el botón de envío | string | ’Enviar’ | No |
onSubmit | Callback que se ejecuta al enviar el formulario | (data: Record<string, unknown>) => void | - | No |
apiConfig | Configuración para conexión con API | ApiConfig | - | No |
initialData | Datos iniciales para el modo de edición | Record<string, unknown> | - | No |
customCols | Habilita organización avanzada de columnas | boolean | false | No |
Tipos de Campos (FormField)
Cada campo debe contener estas propiedades básicas:
interface FormField { type: FieldType; name: string; label: string; // ... otras propiedades opcionales o que dependen del tipo de campo}
Tipos Disponibles (FieldType)
text
- Campo de texto simpleemail
- Campo de email con validación automáticapassword
- Campo de contraseña con visibilidad ocultablenumber
- Campo numéricodatepicker
- Selector de fecha, con soporte para formato de hora y fecharangepicker
- Selector de rango de fechasselect
- Selector de opciones, con soporte para opciones dinámicasradio
- Selector de opciones en radio buttonscheckbox
- Selector de opciones en checkboxestextarea
- Campo de texto multilíneaupload
- Selector de archivos, con soporte para múltiples archivosslider
- Selector de rango numéricoswitch
- Selector de estado binario
Ejemplo Completo de Campo
{ type: 'select', name: 'country', label: 'País', options: [ { label: 'México', value: 'MX' }, { label: 'España', value: 'ES' } ], validations: [ { required: { value: true, message: 'Selecciona tu país' } } ]}
Sistema de validación
Configura reglas de validación por campo usando el formato
{ validations: [ { required: true // requerido con mensaje por defecto }, { required: { // requerido con mensaje personalizado value: true, message: 'Este campo es requerido' } }, { email: { value: true, message: 'Correo no válido' } } { minLength: { value: 5, message: 'Mínimo 5 caracteres' } }, { maxLength: { value: 10, message: 'Máximo 10 caracteres' } }, { pattern: { value: /^[A-Za-z]+$/, message: 'Solo letras' } }, ]}
Ejemplos Avanzados
Formularios con Columnas Personalizadas
// Puedes configurar los campos a tu antojo, en una fila tener 4, en otras 2, etc.const fields: FormField[][] = [ // Nota que este tipado es diferente, es un arreglo de arreglos [ { type: "text", name: "name", label: "Nombre" }, { type: "text", name: "lastName", label: "Apellido" }, { type: "number", name: "age", label: "Edad" }, ], [ { type: "email", name: "email", label: "Correo" }, { type: "password", name: "password", label: "Contraseña" }, ],]
<DynamicForm layout='horizontal' cols={2} customCols // Debes habilitar esta propiedad para usar campos personalizados fields={fields}/>
Usando la propiedad Cols
// Esta configuración es más sencilla y automática, defines los campos como siempreconst fields: FormField[] = [ { type: "text", name: "name", label: "Nombre" }, { type: "text", name: "lastName", label: "Apellido" }, { type: "number", name: "age", label: "Edad" }, { type: "email", name: "email", label: "Correo" }, { type: "password", name: "password", label: "Contraseña" },]
<DynamicForm cols={2} // Indicas cuántas columnas quieres, y el componente se encarga de distribuirlos fields={fields}/>
Recibir datos iniciales para edición
Imagina que tienes una vista de edición de usuario, recibes los datos del usuario ya sea de una API, por props, etc.
Cuando tengas este caso, debes asegurarte que el campo name
de cada FormField
coincida con la clave del objeto de datos iniciales.
const initialData = { name: "Juan", lastName: "Perez", email: "juan@gmail.com",};
const fields: FormField[] = [ { type: "text", name: "name", label: "Nombre" }, { type: "text", name: "lastName", label: "Apellido" }, { type: "email", name: "email", label: "Correo" }, { type: "password", name: "password", label: "Contraseña" },];
<DynamicForm mode="update" title="Editar Usuario" description="Actualiza los datos del usuario" icon={<FaUser />} fields={fields} initialData={initialData} submitButtonText="Actualizar Usuario"/>;
Envío de datos a una API
La forma más común de enviar datos de un formulario a una API es usando la propiedad onSubmit
, que recibe un objeto con los valores de los campos.
const fields: FormField[] = [ { type: "text", name: "name", label: "Nombre" }, { type: "text", name: "lastName", label: "Apellido" }, { type: "email", name: "email", label: "Correo" }, { type: "password", name: "password", label: "Contraseña" },];
const handleSubmit = (data: Record<string, unknown>) => { // Aquí puedes enviar los datos a tu API console.log(data);};
<DynamicForm fields={fields} onSubmit={handleSubmit} />;
Buenas Prácticas
- 🔒 Tipado de Campos: Usa la interfaz
FormField
para tipar los campos del formulario. - 📝 Validaciones Contextuales: Ajusta las validaciones según el modo (create/update) y tipo de campo.
- 📦 Organización de Campos: Agrupa campos relacionados usando el sistema de columnas.
- 🐛 Manejo de Errores: Implementa lógica de notificación en el callback
onSubmit
.
Configuración Avanzada de Campos
Selects
1. // Pasar opciones predefinidas a un campo select{ type: 'select', name: 'country', label: 'País', options: [ { label: 'México', value: 'MX' }, { label: 'España', value: 'ES' } ]}
2. // Consumir opciones de una API{ type: 'select', name: 'city', label: 'Ciudad', selectConfig: { apiConfig: { // Configuración de la API url: 'https://api.thecompaniesapi.com/v2/locations/continents', // URL de la API valueKey: 'code', // Clave del valor, será el valor del campo, y será el valor enviado al servidor labelKey: 'name', // Clave de la etiqueta, será el texto mostrado en el selector responseDataPath: 'continents', // Ruta de los datos en la respuesta de la API, muchas veces los datos vienen en .data pero puede variar } }}
2.1 // También puedes consumir datos desde funciones asíncronas en lugar de una URL{ type: 'select', name: 'city', label: 'Ciudad', selectConfig: { apiConfig: { getterMethod: async () => getContinents(), valueKey: 'code', labelKey: 'name', responseDataPath: 'countries',
} }}
3. // Selects dependientes: Llenar un select con base en la selección de otro{ type: 'select', name: 'drink', label: 'Bebida', selectConfig: { apiConfig: { url: 'https://www.thecocktaildb.com/api/json/v1/1/random.php', valueKey: 'idDrink', // Clave del valor en la respuesta API labelKey: 'strDrink', // Clave del texto a mostrar responseDataPath: 'drinks' // Ruta donde están los datos en la respuesta }, onChange: (value) => { console.log('Selected drink:', value); } }},{ type: 'select', name: 'drink_info', label: 'Información de la bebida', selectConfig: { dependsOn: { field: 'drink', // Nombre del campo padre del que depende apiUrl: 'https://www.thecocktaildb.com/api/json/v1/1/search.php?s=:strDrink', method: 'GET', labelKey: 'strDrink', // Clave para el texto de las opciones valueKey: 'idDrink', // Clave para el valor de las opciones idPlaceholder: ':strDrink', // Marcador a reemplazar en la URLs } }}
Datepickers
1. // Selector de fecha simple{ type: 'datepicker', name: 'birthday', label: 'Fecha de Nacimiento'}
2. // Formateo de fecha{ type: 'datepicker', name: 'birthday', label: 'Fecha de Nacimiento', datepickerConfig: { format: 'DD/MM/YYYY' // Puedes configurar otras opciones como 'MM/DD/YYYY', 'YYYY-MM-DD', etc. }}
3. // Selector de fecha y hora{ type: 'datepicker', name: 'birthday', label: 'Fecha de Nacimiento', datepickerConfig: { format: 'DD/MM/YYYY HH:mm' // Puedes configurar otras opciones como 'DD/MM/YYYY HH:mm:ss', etc. showTime: true }}
4. // Rango de fechas{ type: 'rangepicker', name: 'dates', label: 'Rango de Fechas'}