@m4l/components 9.4.27 → 9.4.28-BE20260210-1

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.
Files changed (59) hide show
  1. package/components/DynamicForm/DynamicForm.d.ts +28 -0
  2. package/components/DynamicForm/DynamicForm.js +126 -0
  3. package/components/DynamicForm/DynamicForm.styles.d.ts +2 -0
  4. package/components/DynamicForm/DynamicForm.styles.js +93 -0
  5. package/components/DynamicForm/constants.d.ts +14 -0
  6. package/components/DynamicForm/constants.js +18 -0
  7. package/components/DynamicForm/helpers/normalizeValidations.d.ts +15 -0
  8. package/components/DynamicForm/helpers/normalizeValidations.js +192 -0
  9. package/components/DynamicForm/helpers/resolveFieldComponent.d.ts +16 -0
  10. package/components/DynamicForm/helpers/resolveFieldComponent.js +118 -0
  11. package/components/DynamicForm/helpers/resolveInitialValue.d.ts +14 -0
  12. package/components/DynamicForm/helpers/resolveInitialValue.js +99 -0
  13. package/components/DynamicForm/hooks/useDynamicForm/useDynamicForm.d.ts +14 -0
  14. package/components/DynamicForm/hooks/useDynamicForm/useDynamicForm.js +38 -0
  15. package/components/DynamicForm/hooks/useDynamicFormConditionals/useDynamicFormConditionals.d.ts +12 -0
  16. package/components/DynamicForm/hooks/useDynamicFormConditionals/useDynamicFormConditionals.js +69 -0
  17. package/components/DynamicForm/hooks/useDynamicFormData/types.d.ts +18 -0
  18. package/components/DynamicForm/hooks/useDynamicFormData/useDynamicFormData.d.ts +12 -0
  19. package/components/DynamicForm/hooks/useDynamicFormData/useDynamicFormData.js +128 -0
  20. package/components/DynamicForm/index.d.ts +4 -0
  21. package/components/DynamicForm/index.js +1 -0
  22. package/components/DynamicForm/slots/DynamicFormEnum.d.ts +14 -0
  23. package/components/DynamicForm/slots/DynamicFormEnum.js +15 -0
  24. package/components/DynamicForm/slots/DynamicFormSlots.d.ts +14 -0
  25. package/components/DynamicForm/slots/DynamicFormSlots.js +51 -0
  26. package/components/DynamicForm/slots/index.d.ts +3 -0
  27. package/components/DynamicForm/slots/index.js +1 -0
  28. package/components/DynamicForm/subcomponents/DynamicFormContent/DynamicFormContent.d.ts +2 -0
  29. package/components/DynamicForm/subcomponents/DynamicFormContent/DynamicFormContent.js +71 -0
  30. package/components/DynamicForm/subcomponents/DynamicFormCoupled/DynamicFormCoupled.d.ts +32 -0
  31. package/components/DynamicForm/subcomponents/DynamicFormCoupled/DynamicFormCoupled.js +45 -0
  32. package/components/DynamicForm/subcomponents/DynamicFormCoupledInternal/DynamicFormCoupledInternal.d.ts +7 -0
  33. package/components/DynamicForm/subcomponents/DynamicFormCoupledInternal/DynamicFormCoupledInternal.js +86 -0
  34. package/components/DynamicForm/subcomponents/DynamicFormCoupledInternalContent/DynamicFormCoupledInternalContent.d.ts +9 -0
  35. package/components/DynamicForm/subcomponents/DynamicFormCoupledInternalContent/DynamicFormCoupledInternalContent.js +62 -0
  36. package/components/DynamicForm/subcomponents/index.d.ts +4 -0
  37. package/components/DynamicForm/subcomponents/index.js +1 -0
  38. package/components/DynamicForm/types.d.ts +313 -0
  39. package/components/extended/mui/Autocomplete/Autocomplete.test.d.ts +1 -0
  40. package/components/extended/mui/Autocomplete/constants.test.d.ts +1 -0
  41. package/components/extended/mui/Autocomplete/dictionary.test.d.ts +1 -0
  42. package/components/extended/mui/Autocomplete/hooks/useAutocomplete/useAutocomplete.test.d.ts +1 -0
  43. package/components/extended/mui/Autocomplete/hooks/useEndAdornments.test.d.ts +1 -0
  44. package/components/extended/mui/Autocomplete/hooks/useMultipleChips.js +13 -10
  45. package/components/extended/mui/Autocomplete/hooks/useMultipleChips.test.d.ts +1 -0
  46. package/components/extended/mui/Autocomplete/hooks/useValuesAndHandlers.js +0 -5
  47. package/components/extended/mui/Autocomplete/hooks/useValuesAndHandlers.test.d.ts +1 -0
  48. package/components/extended/mui/Autocomplete/icons.test.d.ts +1 -0
  49. package/components/extended/mui/Autocomplete/subcomponents/LoadingText/LoadingText.test.d.ts +1 -0
  50. package/components/extended/mui/Autocomplete/subcomponents/NoOptionsText/NoOptionsText.test.d.ts +1 -0
  51. package/components/extended/mui/Autocomplete/subcomponents/PopperComponent/PopperComponent.test.d.ts +1 -0
  52. package/components/extended/mui/Autocomplete/subcomponents/RenderAdornment/RenderAdornment.js +2 -1
  53. package/components/extended/mui/Autocomplete/subcomponents/RenderAdornment/RenderAdornment.test.d.ts +1 -0
  54. package/components/extended/mui/Autocomplete/subcomponents/renderOptions/renderOptions.test.d.ts +1 -0
  55. package/components/hook-form/RHFCheckbox/index.js +1 -0
  56. package/components/hook-form/RHFCheckbox/types.js +1 -0
  57. package/components/index.d.ts +1 -0
  58. package/index.js +66 -60
  59. package/package.json +1 -1
@@ -0,0 +1,45 @@
1
+ import { jsx } from "react/jsx-runtime";
2
+ import { forwardRef } from "react";
3
+ import { useFormContext, Controller } from "react-hook-form";
4
+ import { D as DynamicFormCoupledInternal } from "../DynamicFormCoupledInternal/DynamicFormCoupledInternal.js";
5
+ const DynamicFormCoupled = forwardRef((props) => {
6
+ const {
7
+ name,
8
+ value,
9
+ initialValues,
10
+ validationSchema,
11
+ ownerState,
12
+ currentSize,
13
+ fieldWrapperClassName,
14
+ dataTestId,
15
+ className
16
+ } = props;
17
+ const { control } = useFormContext();
18
+ return /* @__PURE__ */ jsx(
19
+ Controller,
20
+ {
21
+ name,
22
+ control,
23
+ render: ({ field: { onChange } }) => {
24
+ return /* @__PURE__ */ jsx(
25
+ DynamicFormCoupledInternal,
26
+ {
27
+ value,
28
+ initialValues,
29
+ validationSchema,
30
+ ownerState,
31
+ currentSize,
32
+ fieldWrapperClassName,
33
+ dataTestId,
34
+ className,
35
+ onChange
36
+ }
37
+ );
38
+ }
39
+ }
40
+ );
41
+ });
42
+ DynamicFormCoupled.displayName = "DynamicFormCoupled";
43
+ export {
44
+ DynamicFormCoupled as D
45
+ };
@@ -0,0 +1,7 @@
1
+ import { DynamicFormCoupledInternalProps } from '../../types';
2
+ /**
3
+ * Formulario acoplado que se monta dentro de un Controller externo.
4
+ * Crea su propio estado de formulario y delega el render en el contenido interno.
5
+ * Se usa cuando coupled=true para exponer el formulario como un campo dentro de un formulario padre.
6
+ */
7
+ export declare const DynamicFormCoupledInternal: import('react').ForwardRefExoticComponent<DynamicFormCoupledInternalProps & import('react').RefAttributes<HTMLDivElement>>;
@@ -0,0 +1,86 @@
1
+ import { jsx } from "react/jsx-runtime";
2
+ import { forwardRef, useRef, useEffect } from "react";
3
+ import { useForm, FormProvider } from "react-hook-form";
4
+ import { yupResolver } from "@hookform/resolvers/yup";
5
+ import { D as DynamicFormCoupledInternalContent } from "../DynamicFormCoupledInternalContent/DynamicFormCoupledInternalContent.js";
6
+ const DynamicFormCoupledInternal = forwardRef((props) => {
7
+ const {
8
+ value,
9
+ initialValues,
10
+ validationSchema,
11
+ ownerState,
12
+ currentSize,
13
+ fieldWrapperClassName,
14
+ dataTestId,
15
+ className,
16
+ onChange
17
+ } = props;
18
+ const internalFormMethods = useForm({
19
+ resolver: yupResolver(validationSchema),
20
+ defaultValues: initialValues,
21
+ mode: "onTouched"
22
+ });
23
+ const lastSentValueRef = useRef(null);
24
+ useEffect(() => {
25
+ const keys = Object.keys(initialValues);
26
+ keys.forEach((key) => {
27
+ const fieldName = key;
28
+ const fieldValue = initialValues[key];
29
+ internalFormMethods.setValue(fieldName, fieldValue, {
30
+ /**
31
+ * Opciones de setValue para sincronización silenciosa:
32
+ *
33
+ * **shouldValidate: false**
34
+ * - Evita ejecutar las validaciones de Yup cuando se establecen los valores iniciales.
35
+ * - Razón: Los valores iniciales ya vienen validados del backend, no necesitan validarse
36
+ * nuevamente al sincronizarse. Además, validar todos los campos al cargar puede ser
37
+ * costoso en formularios grandes y mostrar errores antes de que el usuario interactúe.
38
+ * - Sin esto: Se ejecutarían todas las validaciones al cargar, mostrando posibles errores
39
+ * de campos que el usuario aún no ha tocado.
40
+ *
41
+ * **shouldDirty: false**
42
+ * - Evita marcar los campos como "sucios" (modificados) cuando se sincronizan valores iniciales.
43
+ * - Razón: Los valores iniciales no son modificaciones del usuario, son el estado base.
44
+ * Marcar campos como "dirty" haría que el formulario parezca modificado cuando en realidad
45
+ * solo se están cargando los datos iniciales.
46
+ * - Sin esto: El formulario se marcaría como "modificado" inmediatamente al cargar,
47
+ * lo que podría activar advertencias de "tienes cambios sin guardar" incorrectamente.
48
+ *
49
+ * **shouldTouch: false**
50
+ * - Evita marcar los campos como "tocados" (visitados) cuando se establecen valores iniciales.
51
+ * - Razón: Un campo "touched" normalmente significa que el usuario lo ha visitado/interactuado.
52
+ * Los valores iniciales no representan interacción del usuario, solo datos precargados.
53
+ * - Sin esto: Los campos se marcarían como "touched" al cargar, lo que podría mostrar
54
+ * mensajes de error o estilos de validación antes de que el usuario interactúe con ellos.
55
+ *
56
+ * **Resumen:**
57
+ * Estas opciones garantizan que la sincronización de valores iniciales sea "silenciosa",
58
+ * actualizando solo los valores sin afectar el estado de validación, modificación o
59
+ * interacción del formulario. El usuario solo verá validaciones y estados cuando
60
+ * realmente interactúe con los campos.
61
+ */
62
+ shouldValidate: false,
63
+ shouldDirty: false,
64
+ shouldTouch: false
65
+ });
66
+ });
67
+ }, [initialValues, internalFormMethods]);
68
+ return /* @__PURE__ */ jsx(FormProvider, { ...internalFormMethods, children: /* @__PURE__ */ jsx(
69
+ DynamicFormCoupledInternalContent,
70
+ {
71
+ value,
72
+ ownerState,
73
+ currentSize,
74
+ fieldWrapperClassName,
75
+ dataTestId,
76
+ className,
77
+ onChange,
78
+ lastSentValueRef,
79
+ internalFormMethods
80
+ }
81
+ ) });
82
+ });
83
+ DynamicFormCoupledInternal.displayName = "DynamicFormCoupledInternal";
84
+ export {
85
+ DynamicFormCoupledInternal as D
86
+ };
@@ -0,0 +1,9 @@
1
+ import { DynamicFormCoupledInternalContentProps } from '../../types';
2
+ /**
3
+ * Componente que se encarga de renderizar el contenido del formulario acoplado.
4
+ * Valida y notifica cambios solo en campos visibles al formulario padre.
5
+ */
6
+ export declare const DynamicFormCoupledInternalContent: {
7
+ (props: DynamicFormCoupledInternalContentProps): import("react/jsx-runtime").JSX.Element;
8
+ displayName: string;
9
+ };
@@ -0,0 +1,62 @@
1
+ import { jsx } from "react/jsx-runtime";
2
+ import { useEffect } from "react";
3
+ import { u as useDynamicFormConditionals } from "../../hooks/useDynamicFormConditionals/useDynamicFormConditionals.js";
4
+ import { D as DynamicFormContent } from "../DynamicFormContent/DynamicFormContent.js";
5
+ const DynamicFormCoupledInternalContent = (props) => {
6
+ const {
7
+ value,
8
+ ownerState,
9
+ currentSize,
10
+ fieldWrapperClassName,
11
+ dataTestId,
12
+ onChange,
13
+ lastSentValueRef,
14
+ internalFormMethods
15
+ } = props;
16
+ const { visibleFields } = useDynamicFormConditionals(value);
17
+ useEffect(() => {
18
+ const notifyChange = () => {
19
+ const visibleFieldNames = visibleFields.map((field) => field.name);
20
+ internalFormMethods.trigger(visibleFieldNames).then(() => {
21
+ const errors = internalFormMethods.formState.errors;
22
+ const visibleFieldsValid = visibleFieldNames.every((fieldName) => {
23
+ return !errors[fieldName];
24
+ });
25
+ const currentValues = internalFormMethods.getValues();
26
+ const visibleFieldValues = {};
27
+ visibleFieldNames.forEach((fieldName) => {
28
+ if (currentValues[fieldName] !== void 0) {
29
+ visibleFieldValues[fieldName] = currentValues[fieldName];
30
+ }
31
+ });
32
+ const formFieldsValue = {
33
+ ...visibleFieldValues,
34
+ isDynamicFormValidInternal: visibleFieldsValid
35
+ };
36
+ const serializedValue = JSON.stringify(formFieldsValue);
37
+ if (serializedValue !== lastSentValueRef.current) {
38
+ lastSentValueRef.current = serializedValue;
39
+ onChange(formFieldsValue);
40
+ }
41
+ });
42
+ };
43
+ const subscription = internalFormMethods.watch(notifyChange);
44
+ notifyChange();
45
+ return () => subscription.unsubscribe();
46
+ }, [internalFormMethods, visibleFields, onChange, lastSentValueRef]);
47
+ return /* @__PURE__ */ jsx(
48
+ DynamicFormContent,
49
+ {
50
+ data: value,
51
+ ownerState,
52
+ currentSize,
53
+ fieldWrapperClassName,
54
+ dataTestId,
55
+ coupled: true
56
+ }
57
+ );
58
+ };
59
+ DynamicFormCoupledInternalContent.displayName = "DynamicFormCoupledInternalContent";
60
+ export {
61
+ DynamicFormCoupledInternalContent as D
62
+ };
@@ -0,0 +1,4 @@
1
+ export { DynamicFormCoupled } from './DynamicFormCoupled/DynamicFormCoupled';
2
+ export { DynamicFormCoupledInternal } from './DynamicFormCoupledInternal/DynamicFormCoupledInternal';
3
+ export { DynamicFormCoupledInternalContent } from './DynamicFormCoupledInternalContent/DynamicFormCoupledInternalContent';
4
+ export { DynamicFormContent } from './DynamicFormContent/DynamicFormContent';
@@ -0,0 +1,313 @@
1
+ import { Theme } from '@mui/material/styles';
2
+ import { MutableRefObject, ReactNode } from 'react';
3
+ import { Sizes } from '@m4l/styles';
4
+ import { DynamicFormSlots } from './slots';
5
+ import { DYNAMIC_FORM_KEY_COMPONENT } from './constants';
6
+ import { M4LOverridesStyleRules } from '../../@types/augmentations';
7
+ import { RHFormValues, RHFormProviderRef } from '../hook-form/RHFormProvider/types';
8
+ import { ActionsFormIntroProps } from '../CommonActions/components/ActionFormIntro/types';
9
+ import { useForm } from 'react-hook-form';
10
+ /**
11
+ * Tipos del contrato API - FormMetadata
12
+ */
13
+ export interface FormMetadata {
14
+ id: number;
15
+ name: string;
16
+ version: number;
17
+ nameDictionaryId: number;
18
+ descriptionDictionaryId: number;
19
+ }
20
+ /**
21
+ * Tipos del contrato API - FieldType
22
+ */
23
+ export interface FieldType {
24
+ id: string;
25
+ name: string;
26
+ rhfComponent: string;
27
+ rhfComponentProps?: Record<string, unknown>;
28
+ supportsOptions: boolean;
29
+ nameDictionaryId: number;
30
+ supportsValidation: boolean;
31
+ }
32
+ /**
33
+ * Tipos del contrato API - ValidationType
34
+ */
35
+ export interface ValidationType {
36
+ id: string;
37
+ name: string;
38
+ requiresValue: boolean;
39
+ nameDictionaryId: number;
40
+ }
41
+ /**
42
+ * Tipos del contrato API - Validation
43
+ */
44
+ export interface FieldValidation {
45
+ id: string;
46
+ isActive: boolean;
47
+ displayOrder: number;
48
+ errorMessage: string;
49
+ validationType?: ValidationType;
50
+ type?: ValidationType;
51
+ value?: string;
52
+ }
53
+ /**
54
+ * Tipos del contrato API - FieldOption
55
+ */
56
+ export interface FieldOption {
57
+ id: number;
58
+ name: string | null;
59
+ value: string;
60
+ isDefault: boolean;
61
+ displayOrder: number;
62
+ nameDictionaryId: number;
63
+ }
64
+ /**
65
+ * Tipos del contrato API - FieldValue
66
+ */
67
+ export interface FieldValue {
68
+ id: number;
69
+ name: string | null;
70
+ value: string;
71
+ isVisible: boolean;
72
+ valueDouble: number | null;
73
+ valueString: string | null;
74
+ valueBoolean: boolean | null;
75
+ valueInteger: number | null;
76
+ valueTimestamp: string | null;
77
+ visibilityReason: string;
78
+ }
79
+ /**
80
+ * Tipos del contrato API - Field
81
+ */
82
+ export interface Field {
83
+ id: number;
84
+ name: string;
85
+ options: FieldOption[];
86
+ fieldType: FieldType;
87
+ helperText: string | null;
88
+ isRequired: boolean;
89
+ placeholder: string | null;
90
+ propertyId: string;
91
+ validations: FieldValidation[];
92
+ currentValue: FieldValue | null;
93
+ defaultValue: string | null;
94
+ displayOrder: number;
95
+ isConditional: boolean;
96
+ validationErrors: unknown[];
97
+ nameDictionaryId: number;
98
+ descriptionDictionaryId: number;
99
+ }
100
+ /**
101
+ * Tipos del contrato API - ConditionalRuleOperator
102
+ */
103
+ export interface ConditionalRuleOperator {
104
+ id: string;
105
+ name: string;
106
+ nameDictionaryId: number;
107
+ }
108
+ /**
109
+ * Tipos del contrato API - ConditionalRule
110
+ */
111
+ export interface ConditionalRule {
112
+ id: string;
113
+ operator: ConditionalRuleOperator;
114
+ isActive: boolean;
115
+ actionType: 'show' | 'hide';
116
+ displayOrder: number;
117
+ conditionValue: string;
118
+ sourceFieldId: number;
119
+ targetFieldId: number;
120
+ sourceFieldName: string;
121
+ targetFieldName: string;
122
+ }
123
+ /**
124
+ * Tipos del contrato API - FormInstance
125
+ */
126
+ export interface FormInstance {
127
+ id: number;
128
+ name: string | null;
129
+ createdAt: string;
130
+ updatedAt: string;
131
+ resourceTypeId: string;
132
+ resourceSerialId: string;
133
+ }
134
+ /**
135
+ * Tipos del contrato API - DynamicFormApiResponse
136
+ */
137
+ export interface DynamicFormApiResponse {
138
+ form: FormMetadata;
139
+ fields: Field[];
140
+ instance: FormInstance;
141
+ conditionalRules: ConditionalRule[];
142
+ }
143
+ /**
144
+ * Propiedades del componente DynamicForm.
145
+ */
146
+ export interface DynamicFormProps {
147
+ /**
148
+ * ID del formulario.
149
+ */
150
+ idForm?: number;
151
+ /**
152
+ * ID de la instancia del formulario.
153
+ */
154
+ idFormInstance?: number;
155
+ /**
156
+ * Endpoint de entrada.
157
+ */
158
+ inputEndpoint?: string;
159
+ /**
160
+ * Endpoint de salida.
161
+ */
162
+ outputEndpoint?: string;
163
+ /**
164
+ * Datos iniciales del formulario. Si se proporciona, se usarán en lugar de obtenerlos del endpoint.
165
+ */
166
+ data?: DynamicFormApiResponse | null;
167
+ /**
168
+ * Función que se ejecuta para formatear los datos de entrada.
169
+ */
170
+ formatInputData?: (data: Record<string, unknown>) => Record<string, unknown>;
171
+ /**
172
+ * Función que se ejecuta para formatear los datos de salida.
173
+ */
174
+ formatOutputData?: (data: Record<string, unknown>) => Record<string, unknown>;
175
+ /**
176
+ * Función que se ejecuta al enviar el formulario con los datos validados.
177
+ */
178
+ onSubmit: (data: Record<string, unknown>) => void | Promise<void>;
179
+ /**
180
+ * Función que se ejecuta cuando hay un error en la validación del formulario.
181
+ */
182
+ onSubmitError?: (errors: Record<string, unknown>) => void;
183
+ /**
184
+ * Tamaño del componente.
185
+ */
186
+ size?: Extract<Sizes, 'small' | 'medium'>;
187
+ /**
188
+ * Clase CSS adicional.
189
+ */
190
+ className?: string;
191
+ /**
192
+ * ID para testing.
193
+ */
194
+ dataTestId?: string;
195
+ /**
196
+ * Clase CSS adicional para el wrapper de cada campo.
197
+ */
198
+ fieldWrapperClassName?: string;
199
+ /**
200
+ * Si el formulario está acoplado (coupled=true), se expone como un campo de React Hook Form mediante Controller.
201
+ * Si está desacoplado (coupled=false), maneja el submit internamente con RHFormProvider.
202
+ * Por defecto es false (modo desacoplado con RHFormProvider interno).
203
+ */
204
+ coupled?: boolean;
205
+ /**
206
+ * Nombre del campo cuando el formulario está acoplado (coupled=true).
207
+ * Se usa para suscribir el DynamicForm a React Hook Form a través del Controller.
208
+ * Requerido cuando coupled es true.
209
+ */
210
+ name?: string;
211
+ /**
212
+ * Props para personalizar el ActionFormIntro.
213
+ * Solo se usa cuando coupled es false (modo desacoplado).
214
+ * Si no se proporciona, se usan los valores por defecto.
215
+ */
216
+ actionFormIntroProps?: Partial<ActionsFormIntroProps>;
217
+ /**
218
+ * Renderizado personalizado para las acciones del formulario.
219
+ * Solo se usa cuando coupled es false (modo desacoplado).
220
+ * Si se proporciona, reemplaza el ActionsContainer y ActionFormIntro por defecto.
221
+ */
222
+ renderActions?: () => ReactNode;
223
+ }
224
+ /**
225
+ * Owner state del componente usado para definir propiedades internas de estilo y comportamiento.
226
+ */
227
+ export interface DynamicFormOwnerState extends Pick<DynamicFormProps, 'size'> {
228
+ [key: string]: unknown;
229
+ }
230
+ /**
231
+ * Define los tipos de Slots disponibles para el componente.
232
+ */
233
+ export type DynamicFormSlotsType = keyof typeof DynamicFormSlots;
234
+ /**
235
+ * Estilos aplicables al componente usando temas y slots personalizados.
236
+ */
237
+ export type DynamicFormStyles = M4LOverridesStyleRules<DynamicFormSlotsType, typeof DYNAMIC_FORM_KEY_COMPONENT, Theme>;
238
+ /**
239
+ * Tipo para los valores del formulario dinámico.
240
+ */
241
+ export type DynamicFormValues = RHFormValues & Record<string, unknown>;
242
+ /**
243
+ * Tipo para el valor que se expone cuando el DynamicForm está acoplado (coupled=true).
244
+ * Contiene los valores de los campos y el estado de validación interno.
245
+ */
246
+ export interface DynamicFormFieldsValue {
247
+ [fieldName: string]: unknown;
248
+ isDynamicFormValidInternal: boolean;
249
+ }
250
+ /**
251
+ * Tipo que define los métodos expuestos a través de la ref del DynamicForm.
252
+ * Expone la API de RHFormProvider para acceso desde el componente padre.
253
+ */
254
+ export type DynamicFormRef = RHFormProviderRef<DynamicFormValues>;
255
+ /**
256
+ * Props del componente DynamicFormCoupled.
257
+ * Se usa cuando coupled=true y el formulario debe exponerse como un campo de React Hook Form mediante Controller.
258
+ */
259
+ export interface DynamicFormCoupledProps {
260
+ name: string;
261
+ value: DynamicFormApiResponse;
262
+ initialValues: DynamicFormValues;
263
+ validationSchema: any;
264
+ ownerState: DynamicFormOwnerState;
265
+ currentSize: 'small' | 'medium';
266
+ fieldWrapperClassName?: string;
267
+ dataTestId?: string;
268
+ className?: string;
269
+ }
270
+ /**
271
+ * Props del componente interno que maneja el formulario acoplado.
272
+ * El formulario interno funciona independientemente y expone sus valores a través del Controller.
273
+ */
274
+ export interface DynamicFormCoupledInternalProps {
275
+ value: DynamicFormApiResponse;
276
+ initialValues: DynamicFormValues;
277
+ validationSchema: any;
278
+ ownerState: DynamicFormOwnerState;
279
+ currentSize: 'small' | 'medium';
280
+ fieldWrapperClassName?: string;
281
+ dataTestId?: string;
282
+ className?: string;
283
+ onChange: (value: DynamicFormFieldsValue) => void;
284
+ }
285
+ /**
286
+ * Props del componente interno que valida y notifica cambios solo en campos visibles.
287
+ * Se usa cuando coupled=true.
288
+ */
289
+ export interface DynamicFormCoupledInternalContentProps {
290
+ value: DynamicFormApiResponse;
291
+ ownerState: DynamicFormOwnerState;
292
+ currentSize: 'small' | 'medium';
293
+ fieldWrapperClassName?: string;
294
+ dataTestId?: string;
295
+ className?: string;
296
+ onChange: (value: DynamicFormFieldsValue) => void;
297
+ lastSentValueRef: MutableRefObject<string | null>;
298
+ internalFormMethods: ReturnType<typeof useForm<DynamicFormValues>>;
299
+ }
300
+ /**
301
+ * Props del componente interno que renderiza los campos del formulario.
302
+ * Debe estar dentro del contexto de RHFormProvider para acceder a useFormContext.
303
+ */
304
+ export interface DynamicFormContentProps {
305
+ data: DynamicFormApiResponse;
306
+ ownerState: DynamicFormOwnerState;
307
+ currentSize: 'small' | 'medium';
308
+ fieldWrapperClassName?: string;
309
+ dataTestId?: string;
310
+ coupled?: boolean;
311
+ actionFormIntroProps?: Partial<DynamicFormProps['actionFormIntroProps']>;
312
+ renderActions?: DynamicFormProps['renderActions'];
313
+ }
@@ -15,7 +15,7 @@ function useMultipleChips(props) {
15
15
  getOptionStartAdornment,
16
16
  getOptionEndAdornment
17
17
  } = props;
18
- const startAdornmentClone = useMemo(() => {
18
+ const externalStartAdornment = useMemo(() => {
19
19
  if (!startAdornment) {
20
20
  return null;
21
21
  }
@@ -53,7 +53,7 @@ function useMultipleChips(props) {
53
53
  getOptionEndAdornment,
54
54
  adjustedSize
55
55
  ]);
56
- const memoizedStartAdornment = useMemo(() => {
56
+ const selectedOptionStartAdornment = useMemo(() => {
57
57
  if (multiple || !selectedValue || Array.isArray(selectedValue) && selectedValue.length === 0) {
58
58
  return null;
59
59
  }
@@ -69,7 +69,7 @@ function useMultipleChips(props) {
69
69
  getOptionStartAdornment,
70
70
  adjustedSize
71
71
  ]);
72
- const internalAdornments = useMemo(() => {
72
+ const multipleSelectionChips = useMemo(() => {
73
73
  if (!(Array.isArray(selectedValue) && multiple && selectedValue.length > 0)) {
74
74
  return null;
75
75
  }
@@ -100,18 +100,21 @@ function useMultipleChips(props) {
100
100
  ownerState,
101
101
  memoizedIcons
102
102
  ]);
103
- if (startAdornmentClone && internalAdornments) {
103
+ if (externalStartAdornment && multipleSelectionChips) {
104
104
  return /* @__PURE__ */ jsxs(Fragment, { children: [
105
- /* @__PURE__ */ jsx(WrapperStartAdornmentStyled, { role: "img", "aria-hidden": "true", ownerState, children: startAdornmentClone }),
106
- internalAdornments
105
+ /* @__PURE__ */ jsx(WrapperStartAdornmentStyled, { role: "img", "aria-hidden": "true", ownerState, children: externalStartAdornment }),
106
+ multipleSelectionChips
107
107
  ] });
108
108
  }
109
- if (startAdornmentClone) {
109
+ if (externalStartAdornment) {
110
110
  return /* @__PURE__ */ jsxs(WrapperStartAdornmentStyled, { role: "img", "aria-hidden": "true", ownerState, children: [
111
- startAdornmentClone,
112
- !multiple && memoizedStartAdornment
111
+ externalStartAdornment,
112
+ !multiple && selectedOptionStartAdornment
113
113
  ] });
114
114
  }
115
+ if (!multiple && selectedOptionStartAdornment && !externalStartAdornment) {
116
+ return /* @__PURE__ */ jsx(WrapperStartAdornmentStyled, { role: "img", "aria-hidden": "true", ownerState, children: selectedOptionStartAdornment });
117
+ }
115
118
  if (!getOptionLabelLocal) {
116
119
  console.error("useStartAdornments: getOptionLabelLocal is required");
117
120
  return null;
@@ -120,7 +123,7 @@ function useMultipleChips(props) {
120
123
  console.error("useStartAdornments: handleDelete is required");
121
124
  return null;
122
125
  }
123
- return internalAdornments;
126
+ return multipleSelectionChips;
124
127
  }
125
128
  export {
126
129
  useMultipleChips as u
@@ -126,11 +126,6 @@ function useValuesAndHandlers(props) {
126
126
  }
127
127
  }
128
128
  }, [readOnly, value, getOptionLabelLocal, multiple, inputValue]);
129
- useEffect(() => {
130
- if (open === false && value === null && inputValue !== "") {
131
- setInputValue("");
132
- }
133
- }, [value, open, inputValue]);
134
129
  const checkKeyDown = (e) => {
135
130
  if (e.code === "Enter") {
136
131
  e.preventDefault();
@@ -24,7 +24,8 @@ const renderAdornment = (propsResource, adjustedSize) => {
24
24
  {
25
25
  src: resource,
26
26
  width: 14,
27
- height: 14
27
+ height: 14,
28
+ enableIntersectionObserver: false
28
29
  }
29
30
  );
30
31
  } else {