carconnect-gatherleads-ui-lib 2.2.5 → 2.4.0

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/README.md CHANGED
@@ -1315,6 +1315,145 @@ interface GatherFormBuilderProps {
1315
1315
  onSubmit={(data) => console.log(data)}
1316
1316
  />
1317
1317
 
1318
+ // EJEMPLOS CON ONCHANGE
1319
+
1320
+ // Ejemplo 1:
1321
+ <GatherFormBuilder
1322
+ config={{
1323
+ fields: [
1324
+ { name: 'user.firstName', label: 'Nombre', type: 'text' },
1325
+ { name: 'user.email', label: 'Email', type: 'email' },
1326
+ { name: 'phone', label: 'Telefono', type: 'tel' },
1327
+ { name: 'address.country', label: 'País', type: 'select' },
1328
+ ]
1329
+ }}
1330
+ watchFields={['user.email','phone']}
1331
+ onChange={(data, changedField, formMethods) => {
1332
+ // ✅ Funciona con datos anidados
1333
+ if (changedField.name === 'address.country') {
1334
+ formMethods.setValue('address.city', '');
1335
+ }
1336
+ }}
1337
+ defaultValues={{
1338
+ user: { firstName: '', email: '' },
1339
+ address: { country: '', city: '' }
1340
+ }}
1341
+ onSubmit={(data) => console.log(data)}
1342
+ />
1343
+
1344
+
1345
+
1346
+ // Ejemplo 2:
1347
+ const nestedFormConfig = {
1348
+ fields: [
1349
+ { name: 'user.firstName', label: 'Nombre', type: 'text' },
1350
+ { name: 'user.lastName', label: 'Apellido', type: 'text' },
1351
+ { name: 'user.email', label: 'Email', type: 'email' },
1352
+ { name: 'address.country', label: 'País', type: 'select' },
1353
+ { name: 'address.city', label: 'Ciudad', type: 'select' },
1354
+ { name: 'address.street', label: 'Calle', type: 'text' },
1355
+ { name: 'preferences.notifications', label: 'Notificaciones', type: 'switch' },
1356
+ ]
1357
+ };
1358
+
1359
+ <GatherFormBuilder
1360
+ config={nestedFormConfig}
1361
+ watchFields={['address.country','preferences.notifications']}
1362
+ onChange={(data, changedField, formMethods) => {
1363
+ console.log('Campo que cambió:', changedField.name); // ej: 'user.firstName'
1364
+ console.log('Nuevo valor:', changedField.value);
1365
+ console.log('Datos completos:', data); // { user: { firstName: '...', lastName: '...' }, address: { ... } }
1366
+
1367
+ // Validación condicional con campos anidados
1368
+ if (changedField.name === 'address.country') {
1369
+ // Limpiar ciudad cuando cambia país
1370
+ formMethods.setValue('address.city', '');
1371
+ formMethods.clearErrors('address.city');
1372
+ }
1373
+
1374
+ // Lógica basada en preferencias anidadas
1375
+ if (changedField.name === 'preferences.notifications' && !changedField.value) {
1376
+ // Si deshabilita notificaciones, limpiar campos relacionados
1377
+ formMethods.setValue('preferences.emailFrequency', 'never');
1378
+ }
1379
+ }}
1380
+ defaultValues={{
1381
+ user: {
1382
+ firstName: '',
1383
+ lastName: '',
1384
+ email: ''
1385
+ },
1386
+ address: {
1387
+ country: '',
1388
+ city: '',
1389
+ street: ''
1390
+ },
1391
+ preferences: {
1392
+ notifications: true
1393
+ }
1394
+ }}
1395
+ onSubmit={(data) => console.log('Submit:', data)}
1396
+ />
1397
+
1398
+ // Ejemplo 3:
1399
+ <GatherFormBuilder
1400
+ config={nestedFormConfig}
1401
+ onChange={(data, changedField, formMethods) => {
1402
+ if (changedField.name === 'user.email') {
1403
+ // Validar email en tiempo real
1404
+ validateEmail(changedField.value).then(isValid => {
1405
+ if (!isValid) {
1406
+ formMethods.setError('user.email', { message: 'Email inválido' });
1407
+ }
1408
+ });
1409
+ }
1410
+ }}
1411
+ watchFields={['user.email', 'address.country']} // Solo observa estos campos anidados
1412
+ debounceMs={300}
1413
+ onSubmit={(data) => submitForm(data)}
1414
+ />
1415
+
1416
+ // Ejemplo 3:
1417
+ const calculatorFormConfig = {
1418
+ fields: [
1419
+ { name: 'invoice.items[0].quantity', label: 'Cantidad Item 1', type: 'number' },
1420
+ { name: 'invoice.items[0].price', label: 'Precio Item 1', type: 'number' },
1421
+ { name: 'invoice.items[1].quantity', label: 'Cantidad Item 2', type: 'number' },
1422
+ { name: 'invoice.items[1].price', label: 'Precio Item 2', type: 'number' },
1423
+ { name: 'invoice.discount', label: 'Descuento %', type: 'number' },
1424
+ { name: 'invoice.total', label: 'Total', type: 'number', disabled: true },
1425
+ ]
1426
+ };
1427
+
1428
+ <GatherFormBuilder
1429
+ config={calculatorFormConfig}
1430
+ onChange={(data, changedField, formMethods) => {
1431
+ // Recalcular total cuando cambien items o descuento
1432
+ if (changedField.name.startsWith('invoice.items') || changedField.name === 'invoice.discount') {
1433
+ const items = data.invoice?.items || [];
1434
+ const subtotal = items.reduce((sum: number, item: any) => {
1435
+ return sum + ((item?.quantity || 0) * (item?.price || 0));
1436
+ }, 0);
1437
+
1438
+ const discount = (data.invoice?.discount || 0) / 100;
1439
+ const total = subtotal * (1 - discount);
1440
+
1441
+ formMethods.setValue('invoice.total', total.toFixed(2));
1442
+ }
1443
+ }}
1444
+ defaultValues={{
1445
+ invoice: {
1446
+ items: [
1447
+ { quantity: 0, price: 0 },
1448
+ { quantity: 0, price: 0 }
1449
+ ],
1450
+ discount: 0,
1451
+ total: 0
1452
+ }
1453
+ }}
1454
+ onSubmit={(data) => console.log('Invoice:', data)}
1455
+ />
1456
+
1318
1457
  // EJEMPLO CON TODAS LAS PROPS
1319
1458
  <GatherFormBuilder
1320
1459
  // CONFIG: Configuración del formulario (requerida)
@@ -1361,6 +1500,17 @@ interface GatherFormBuilderProps {
1361
1500
  // VALIDATIONMODE: Cuándo validar (opcional)
1362
1501
  validationMode="onChange" // Valida en cada cambio
1363
1502
 
1503
+ // DEBOUCEMS: tiempo de respuesta para cualquier cambio en el form
1504
+ debouceMs={100}
1505
+
1506
+ // WATCHFIELDS: campos del form que se vizualizaran en tiempo real
1507
+ watchFields={['nombre', 'pais']}
1508
+
1509
+ // ONCHANGE: cambios en tiempo real del form
1510
+ onChange={(data,changedField, formMethods )=> {
1511
+ console.log({data,changedField,formMethods})
1512
+ }}
1513
+
1364
1514
  // LOADINGCOMPONENT: Componente de carga (opcional)
1365
1515
  loadingComponent={<CustomSpinner />}
1366
1516
  />
@@ -203,6 +203,21 @@ export declare const createColumns: <T>(columns: GatherTableColumn<T>[]) => Gath
203
203
  */
204
204
  export declare const createFlexibleColumns: (columns: BaseGatherTableColumn[]) => BaseGatherTableColumn[];
205
205
 
206
+ /**
207
+ * Función debounce para limitar la frecuencia de ejecución
208
+ */
209
+ export declare const debounce: <T extends (...args: any[]) => void>(func: T, wait: number) => ((...args: Parameters<T>) => void);
210
+
211
+ /**
212
+ * Clona un objeto de forma profunda
213
+ */
214
+ export declare const deepClone: (obj: any) => any;
215
+
216
+ /**
217
+ * Compara dos valores de forma profunda, incluyendo objetos y arrays anidados
218
+ */
219
+ export declare const deepEqual: (obj1: any, obj2: any) => boolean;
220
+
206
221
  /**
207
222
  * Tipo unión de todas las configuraciones de campo posibles
208
223
  */
@@ -525,18 +540,28 @@ export declare interface GatherDateFieldConfig extends BaseFieldConfig {
525
540
  }
526
541
 
527
542
  /**
528
- * Componente que construye un formulario dinámico en base a una configuración declarativa.
543
+ * Componente que construye un formulario dinámico a partir de una configuración declarativa.
544
+ *
545
+ * Se apoya en **React Hook Form** para la gestión del estado, validaciones
546
+ * y envío del formulario. Permite definir campos, layout, validaciones,
547
+ * botones y callbacks personalizados para diferentes acciones.
529
548
  *
530
549
  * @component
531
- * @param {GatherFormBuilderProps} props - Propiedades para configurar el formulario.
532
- *
533
- * @property {Object} config - Configuración del formulario (campos, botones, layout, título, etc).
534
- * @property {Function} onSubmit - Función asíncrona que se ejecuta al enviar el formulario.
535
- * @property {Function} [onAction] - Función que se ejecuta al presionar el botón de acción (ej: limpiar).
536
- * @property {boolean} [resetData=true] - Si `true`, resetea los datos después de enviar el formulario exitosamente.
537
- * @property {Object} [defaultValues={}] - Valores iniciales para los campos del formulario.
538
- * @property {boolean} [isLoading=false] - Indica si el formulario está en estado de carga.
539
- * @property {string} [className=""] - Clases adicionales para el contenedor principal.
550
+ * @param {GatherFormBuilderProps} props - Propiedades del componente.
551
+ *
552
+ * @property {Object} config - Configuración principal del formulario (campos, layout, título, botones, etc).
553
+ * @property {Function} onSubmit - Función asíncrona ejecutada al enviar el formulario.
554
+ * @property {Function} [onAction] - Callback para el botón de acción secundaria (ej: limpiar).
555
+ * @property {Function} [onChange] - Callback ejecutado cuando cambia el valor de un campo observado.
556
+ * Recibe `(data, changedField, formMethods)`, donde `changedField` incluye `{ name, value, previousValue }`
557
+ * y `formMethods` expone utilidades de React Hook Form (`setValue`, `getValues`, `reset`, `clearErrors`, `setError`, `watch`).
558
+ * @property {string[]} [watchFields=[]] - Lista de nombres de campos que deben ser observados por `onChange`.
559
+ * @property {number} [debounceMs=0] - Tiempo en milisegundos para aplicar `debounce` al callback `onChange`.
560
+ * @property {boolean} [resetData=true] - Si es `true`, el formulario se resetea tras un submit exitoso.
561
+ * @property {Object} [defaultValues={}] - Valores iniciales de los campos.
562
+ * @property {boolean} [isLoading=false] - Indica si el formulario está en estado de carga (bloquea inputs y botones).
563
+ * @property {boolean} [disabled=false] - Deshabilita todos los campos independientemente del estado de carga.
564
+ * @property {string} [className=""] - Clases CSS adicionales para el contenedor principal.
540
565
  * @property {'onBlur' | 'onChange' | 'onSubmit' | 'onTouched' | 'all'} [validationMode='onChange'] - Modo de validación usado por React Hook Form.
541
566
  *
542
567
  * @example
@@ -561,6 +586,9 @@ export declare interface GatherDateFieldConfig extends BaseFieldConfig {
561
586
  * }
562
587
  * }}
563
588
  * onSubmit={(data) => console.log("Datos enviados:", data)}
589
+ * onChange={(data, changedField, formMethods ) => console.log("Cambio:", changedField)}
590
+ * watchFields={["nombre", "email"]}
591
+ * debounceMs={500}
564
592
  * />
565
593
  * ```
566
594
  */
@@ -600,6 +628,55 @@ export declare interface GatherFormBuilderProps {
600
628
  * @example onAction={() => navigate('/home')}
601
629
  */
602
630
  onAction?: () => void;
631
+ /**
632
+ * Función que se ejecuta cada vez que cambia algún campo del formulario.
633
+ * Útil para validaciones en tiempo real, cálculos dinámicos, o sincronización con estado externo.
634
+ *
635
+ * @param data - Valores actuales de todos los campos del formulario
636
+ * @param changedField - Información sobre el campo que cambió
637
+ * @param formMethods - Métodos de React Hook Form para manipular el formulario
638
+ *
639
+ * @example
640
+ * onChange={(data, changedField, formMethods) => {
641
+ * if (changedField.name === 'country') {
642
+ * // Limpiar campo ciudad cuando cambia país
643
+ * formMethods.setValue('city', '');
644
+ * }
645
+ *
646
+ * // Auto-guardar borrador
647
+ * saveDraft(data);
648
+ * }}
649
+ */
650
+ onChange?: (data: Record<string, any>, changedField: {
651
+ name: string;
652
+ value: any;
653
+ previousValue?: any;
654
+ }, formMethods: {
655
+ setValue: (name: string, value: any) => void;
656
+ getValues: (name?: string) => any;
657
+ reset: (values?: any) => void;
658
+ clearErrors: (name?: string) => void;
659
+ setError: (name: string, error: {
660
+ message: string;
661
+ }) => void;
662
+ watch: (name?: string) => any;
663
+ }) => void;
664
+ /**
665
+ * Lista de campos específicos a observar para el onChange.
666
+ * Si no se especifica, observa todos los campos.
667
+ * Útil para optimizar performance en formularios grandes.
668
+ *
669
+ * @example watchFields: ['country', 'state'] // Solo observa estos campos
670
+ */
671
+ watchFields?: string[];
672
+ /**
673
+ * Debounce en milisegundos para el onChange.
674
+ * Útil para evitar muchas llamadas en campos de texto.
675
+ *
676
+ * @default 0 (sin debounce)
677
+ * @example debounceMs: 300 // Espera 300ms después del último cambio
678
+ */
679
+ debounceMs?: number;
603
680
  /**
604
681
  * Valores iniciales para los campos del formulario.
605
682
  * Se asignan según la propiedad `name` de cada campo.
@@ -697,8 +774,10 @@ export declare interface GatherInputFieldConfig extends BaseFieldConfig {
697
774
  maxLength?: number;
698
775
  /** Expresión regular para validar el formato del valor */
699
776
  pattern?: string;
777
+ /** Funcion para validar el formato del valor */
778
+ validateFn?: (value: string) => boolean | string;
700
779
  /** Mensaje que se muestra cuando el patrón no es válido */
701
- patternMessage?: string;
780
+ errorMessage?: string;
702
781
  /** Valor numérico mínimo permitido (para inputs number) */
703
782
  min?: number;
704
783
  /** Valor numérico máximo permitido (para inputs number) */
@@ -1781,6 +1860,23 @@ export declare interface GatherTextareaFieldConfig extends BaseFieldConfig {
1781
1860
  */
1782
1861
  export declare const generateValidationRules: (field: FieldConfig) => ValidationRule;
1783
1862
 
1863
+ export declare const getAllPaths: (obj: any, prefix?: string) => string[];
1864
+
1865
+ /**
1866
+ * Determina las clases de layout dinámicamente en base al tipo (`grid`, `horizontal`, `stack`, etc).
1867
+ */
1868
+ export declare const getLayoutClasses: (config: FormConfig) => string;
1869
+
1870
+ /**
1871
+ * Busca campos anidados en estructuras complejas de objetos (ej: direcciones.calle).
1872
+ */
1873
+ export declare const getNestedField: (obj: any, path: string) => any;
1874
+
1875
+ /**
1876
+ * Ordena los campos en base al array `orderFields` definido en la config.
1877
+ */
1878
+ export declare const getOrderedFields: (fields: FieldConfig[], orderFields?: string[]) => FieldConfig[];
1879
+
1784
1880
  /**
1785
1881
  * Tipo de opción para el componente MultiSelect
1786
1882
  * @interface OptionType
@@ -1819,7 +1915,7 @@ export declare interface SelectInputOption {
1819
1915
  value: string;
1820
1916
  /** Patrón de expresión regular para validar el input asociado */
1821
1917
  validationPattern?: RegExp;
1822
- validateFn?: (value: string) => boolean;
1918
+ validateFn?: (value: string) => boolean | string;
1823
1919
  /** Mensaje de error personalizado cuando la validación falla */
1824
1920
  errorMessage?: string;
1825
1921
  /** Texto placeholder específico para esta opción */