@m4l/components 9.3.16 → 9.3.17-JT25092025.beta.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 (54) hide show
  1. package/components/Stepper/Stepper.styles.js +17 -14
  2. package/components/Stepper/helpers/getInitialFieldValues/index.d.ts +12 -0
  3. package/components/Stepper/helpers/getInitialFieldValues/index.js +14 -0
  4. package/components/Stepper/helpers/index.d.ts +2 -0
  5. package/components/Stepper/helpers/parseWatchedValues/index.d.ts +17 -0
  6. package/components/Stepper/helpers/parseWatchedValues/index.js +12 -0
  7. package/components/Stepper/hooks/useDynamicValidation/index.d.ts +11 -0
  8. package/components/Stepper/hooks/useDynamicValidation/index.js +69 -0
  9. package/components/Stepper/hooks/useStepperActions/index.js +19 -3
  10. package/components/Stepper/store/StepperStore/index.js +20 -1
  11. package/components/Stepper/subcomponents/StepArea/index.js +41 -25
  12. package/components/Stepper/subcomponents/StepArea/subcomponents/Inidicator/index.js +18 -10
  13. package/components/Stepper/subcomponents/StepperButtons/StepperCancelButton/index.d.ts +2 -1
  14. package/components/Stepper/subcomponents/StepperButtons/StepperCancelButton/index.js +39 -6
  15. package/components/Stepper/subcomponents/StepperButtons/StepperNextButton/index.d.ts +2 -1
  16. package/components/Stepper/subcomponents/StepperButtons/StepperNextButton/index.js +5 -3
  17. package/components/Stepper/subcomponents/StepperButtons/StepperPrevButton/index.d.ts +2 -1
  18. package/components/Stepper/subcomponents/StepperButtons/StepperPrevButton/index.js +5 -3
  19. package/components/Stepper/subcomponents/StepperButtons/StepperSubmitButton/index.d.ts +2 -1
  20. package/components/Stepper/subcomponents/StepperButtons/StepperSubmitButton/index.js +5 -3
  21. package/components/Stepper/subcomponents/StepperContent/subcomponents/Step/index.js +30 -11
  22. package/components/Stepper/subcomponents/StepperFooter/subcomponents/StepperFooterRightActions/index.js +20 -10
  23. package/components/Stepper/types.d.ts +7 -0
  24. package/components/areas/icons.js +1 -1
  25. package/components/hook-form/RHFAutocomplete/RHFAutocomplete.js +3 -35
  26. package/components/hook-form/RHFAutocomplete/types.d.ts +1 -6
  27. package/components/hook-form/RHFormContext/index.d.ts +1 -1
  28. package/components/hook-form/RHFormContext/index.js +29 -4
  29. package/components/index.d.ts +1 -0
  30. package/components/mui_extended/Autocomplete/Autocomplete.js +12 -6
  31. package/components/mui_extended/Autocomplete/Autocomplete.styles.js +48 -5
  32. package/components/mui_extended/Autocomplete/hooks/useEndAdornments.d.ts +1 -0
  33. package/components/mui_extended/Autocomplete/hooks/useEndAdornments.js +4 -3
  34. package/components/mui_extended/Autocomplete/hooks/useStartAdornments.js +4 -4
  35. package/components/mui_extended/Autocomplete/hooks/useValuesAndHandlers.js +39 -4
  36. package/components/mui_extended/Autocomplete/slots/AutocompleteEnum.d.ts +3 -1
  37. package/components/mui_extended/Autocomplete/slots/AutocompleteEnum.js +2 -0
  38. package/components/mui_extended/Autocomplete/slots/AutocompleteSlots.d.ts +6 -0
  39. package/components/mui_extended/Autocomplete/slots/AutocompleteSlots.js +11 -1
  40. package/components/mui_extended/Autocomplete/types.d.ts +1 -1
  41. package/components/mui_extended/Button/ButtonStyles.js +3 -6
  42. package/components/mui_extended/Popper/Popper.js +9 -2
  43. package/components/mui_extended/Popper/types.d.ts +1 -0
  44. package/components/mui_extended/Select/Select.js +17 -10
  45. package/components/mui_extended/Select/Select.styles.js +17 -10
  46. package/components/mui_extended/Select/types.d.ts +1 -1
  47. package/components/mui_extended/TextField/TextField.d.ts +2 -1
  48. package/components/mui_extended/TextField/TextField.js +25 -4
  49. package/components/mui_extended/TextField/TextField.styles.js +132 -125
  50. package/components/mui_extended/TextField/slots/TextFieldSlots.d.ts +3 -9
  51. package/components/mui_extended/TextField/slots/TextFieldSlots.js +2 -1
  52. package/components/mui_extended/Typography/Typography.js +1 -1
  53. package/package.json +1 -1
  54. package/test/mocks/dictionary-mock.d.ts +433 -0
@@ -24,8 +24,13 @@ const stepperStyles = {
24
24
  flexDirection: ownerState?.orientation === "vertical" || theme.generalSettings.isMobile ? "column" : "row",
25
25
  gap: theme.vars.size.baseSpacings.sp8
26
26
  }),
27
+ /**
28
+ * Estilos para el contenido del paso dentro del Stepper.
29
+ */
27
30
  stepContent: ({ ownerState }) => ({
28
- display: ownerState?.isStepVisible ? "block" : "none"
31
+ height: "100%",
32
+ display: ownerState?.isStepVisible ? "flex" : "none",
33
+ flexDirection: "column"
29
34
  }),
30
35
  /**
31
36
  * Estilos para la sección que contiene los botones de acción del Stepper.
@@ -71,8 +76,7 @@ const stepperStyles = {
71
76
  const isLastStep = step === totalSteps - 1;
72
77
  return {
73
78
  cursor: "pointer",
74
- display: "flex",
75
- visibility: ownerState?.isStepVisible ? "visible" : "hidden",
79
+ display: ownerState?.isStepVisible ? "flex" : "none",
76
80
  flexDirection: ownerState?.orientation === "vertical" || theme.generalSettings.isMobile ? "column" : "row",
77
81
  alignItems: ownerState?.orientation === "vertical" || theme.generalSettings.isMobile ? "center" : "start",
78
82
  justifyContent: ownerState?.visibleTitle ? "space-between" : "center",
@@ -126,7 +130,7 @@ const stepperStyles = {
126
130
  whiteSpace: "normal",
127
131
  order: ownerState?.orientation === "vertical" || theme.generalSettings.isMobile ? 1 : 0,
128
132
  "&.M4LTypography-root": {
129
- color: (ownerState?.currentStep ?? 0) > (ownerState?.step ?? 0) ? theme.vars.palette.primary.semanticText : (ownerState?.currentStep ?? 0) === (ownerState?.step ?? 0) ? theme.vars.palette.text.primary : theme.vars.palette.text.secondary,
133
+ color: ownerState?.originalStepIndex !== void 0 && typeof ownerState.originalStepIndex === "number" ? (ownerState.currentStep ?? 0) > ownerState.originalStepIndex ? theme.vars.palette.primary.semanticText : (ownerState.currentStep ?? 0) === ownerState.originalStepIndex ? theme.vars.palette.text.primary : theme.vars.palette.text.secondary : theme.vars.palette.text.secondary,
130
134
  textAlign: ownerState?.orientation === "vertical" || theme.generalSettings.isMobile ? "center" : "right"
131
135
  }
132
136
  }),
@@ -134,13 +138,12 @@ const stepperStyles = {
134
138
  * Estilos para el indicador numérico de cada paso del Stepper.
135
139
  */
136
140
  indicator: ({ theme, ownerState }) => {
137
- const currentStep = ownerState?.currentStep ?? 0;
138
141
  const step = ownerState?.step ?? 0;
139
142
  const totalSteps = ownerState?.totalSteps ?? 0;
140
- const isCompleted = currentStep > step;
141
- const isCurrent = currentStep === step;
143
+ const isCompleted = ownerState?.isCompleted ?? false;
144
+ const isCurrent = ownerState?.isCurrent ?? false;
145
+ const isValidStep = ownerState?.isValidStep ?? true;
142
146
  const isLastStep = step === totalSteps - 1;
143
- const isValidStep = ownerState?.stepValidationStatus?.[step] ?? true;
144
147
  return {
145
148
  ...ownerState?.orientation === "horizontal" ? {
146
149
  marginTop: theme.generalSettings.isMobile ? "6px" : theme.vars.size.baseSpacings.sp1
@@ -150,7 +153,7 @@ const stepperStyles = {
150
153
  justifyContent: "center",
151
154
  flexShrink: 0,
152
155
  order: ownerState?.orientation === "vertical" || theme.generalSettings.isMobile ? 0 : 1,
153
- background: isCompleted ? ownerState?.indicatorType === "dot" || theme.generalSettings.isMobile ? theme.vars.palette.background.default : theme.vars.palette.primary.toneOpacity : !isValidStep ? theme.vars.palette.error.enabled : ownerState?.indicatorType === "dot" || theme.generalSettings.isMobile ? theme.vars.palette.background.default : isCurrent ? theme.vars.palette.primary.enabled : theme.vars.palette.default.enabled,
156
+ background: !isValidStep && ownerState?.hasBeenValidated ? theme.vars.palette.error.enabled : isCompleted && isValidStep ? ownerState?.indicatorType === "dot" || theme.generalSettings.isMobile ? theme.vars.palette.background.default : theme.vars.palette.primary.toneOpacity : isCurrent ? ownerState?.indicatorType === "dot" || theme.generalSettings.isMobile ? theme.vars.palette.background.default : theme.vars.palette.primary.enabled : ownerState?.indicatorType === "dot" || theme.generalSettings.isMobile ? theme.vars.palette.background.default : theme.vars.palette.default.enabled,
154
157
  borderRadius: theme.vars.size.borderRadius.r2,
155
158
  ...ownerState?.indicatorType === "number" && !theme.generalSettings.isMobile && {
156
159
  boxShadow: isCurrent ? "0 2px 8px 0 rgb(0, 100, 255, 0.16)" : "none"
@@ -178,13 +181,13 @@ const stepperStyles = {
178
181
  * Estilos para el número de texto dentro del indicador numérico del Stepper.
179
182
  */
180
183
  textNumber: ({ theme, ownerState }) => {
181
- const currentStep = ownerState?.currentStep ?? 0;
182
- const step = ownerState?.step ?? 0;
183
- const isCompleted = currentStep > step;
184
- const isCurrent = currentStep === step;
184
+ const isCompleted = ownerState?.isCompleted ?? false;
185
+ const isCurrent = ownerState?.isCurrent ?? false;
186
+ const isValidStep = ownerState?.isValidStep ?? true;
187
+ const hasBeenValidated = ownerState?.hasBeenValidated ?? false;
185
188
  return {
186
189
  "&.M4LTypography-root": {
187
- color: isCompleted || isCurrent ? theme.vars.palette.primary.contrastText : theme.vars.palette.text.primary
190
+ color: !isValidStep && hasBeenValidated ? theme.vars.palette.error.contrastText : isCompleted || isCurrent ? theme.vars.palette.primary.contrastText : theme.vars.palette.text.primary
188
191
  }
189
192
  };
190
193
  },
@@ -0,0 +1,12 @@
1
+ /**
2
+ * Obtiene los valores iniciales de campos específicos del formulario.
3
+ * Se usa para inicializar el ref que trackea cambios en los campos.
4
+ * @param allValues - Todos los valores del formulario (de getValues())
5
+ * @param fields - Lista de nombres de campos de los que queremos obtener valores
6
+ * @returns Objeto con solo los valores de los campos especificados
7
+ * @example
8
+ * const formValues = { name: 'John', age: 25, city: 'NY', country: 'USA' };
9
+ * getInitialFieldValues(formValues, ['name', 'age'])
10
+ * // Retorna: { name: 'John', age: 25 }
11
+ */
12
+ export declare function getInitialFieldValues(allValues: Record<string, any>, fields?: string[]): Record<string, any>;
@@ -0,0 +1,14 @@
1
+ function getInitialFieldValues(allValues, fields = []) {
2
+ if (fields.length === 0) {
3
+ return {};
4
+ }
5
+ return fields.reduce((acc, field) => {
6
+ if (field in allValues) {
7
+ acc[field] = allValues[field];
8
+ }
9
+ return acc;
10
+ }, {});
11
+ }
12
+ export {
13
+ getInitialFieldValues as g
14
+ };
@@ -2,3 +2,5 @@ export { evaluateVisibilityStepCondition } from './evaluateVisibilityStepConditi
2
2
  export { findNextVisibleValidStep } from './findNextVisibleValidStep';
3
3
  export { findPrevVisibleValidStep } from './findPrevVisibleValidStep';
4
4
  export { isLastVisibleValidStep } from './isLastVisibleValidStep';
5
+ export { parseWatchedValues } from './parseWatchedValues';
6
+ export { getInitialFieldValues } from './getInitialFieldValues';
@@ -0,0 +1,17 @@
1
+ /**
2
+ * Convierte los valores observados de useWatch en un objeto estructurado con los nombres de campos como keys.
3
+ *
4
+ * useWatch de react-hook-form retorna diferentes estructuras según la cantidad de campos observados:
5
+ * - Un solo campo: retorna el valor directamente
6
+ * - Múltiples campos: retorna un array con los valores en el mismo orden de los campos
7
+ * @param watchValues - Valores observados de useWatch (puede ser un valor único o un array)
8
+ * @param fields - Lista de nombres de campos que se están observando
9
+ * @returns Objeto con los valores actuales mapeados a sus respectivos nombres de campo
10
+ * @example
11
+ * // Para un solo campo
12
+ * parseWatchedValues('John', ['name']) // { name: 'John' }
13
+ *
14
+ * // Para múltiples campos
15
+ * parseWatchedValues(['John', 25], ['name', 'age']) // { name: 'John', age: 25 }
16
+ */
17
+ export declare function parseWatchedValues(watchValues: any, fields: string[]): Record<string, any>;
@@ -0,0 +1,12 @@
1
+ function parseWatchedValues(watchValues, fields) {
2
+ if (fields.length === 1) {
3
+ return { [fields[0]]: watchValues };
4
+ }
5
+ return fields.reduce((acc, field, index) => {
6
+ acc[field] = Array.isArray(watchValues) ? watchValues[index] : watchValues;
7
+ return acc;
8
+ }, {});
9
+ }
10
+ export {
11
+ parseWatchedValues as p
12
+ };
@@ -0,0 +1,11 @@
1
+ /**
2
+ * Hook que simula validación onChange de campos específicos del Stepper, manteniendo el formulario en modo onSubmit para preservar el rendimiento.
3
+ * @returns Objeto con funciones para manejar la validación dinámica
4
+ */
5
+ export declare function useDynamicValidation(): {
6
+ activateFieldsValidation: (fields: string[], skipIfValidating?: boolean) => void;
7
+ clearAllValidation: () => void;
8
+ activeFields: string[];
9
+ startExternalValidation: () => void;
10
+ endExternalValidation: () => void;
11
+ };
@@ -0,0 +1,69 @@
1
+ import { useState, useRef, useEffect, useCallback } from "react";
2
+ import { useFormContext, useWatch } from "react-hook-form";
3
+ import { p as parseWatchedValues } from "../../helpers/parseWatchedValues/index.js";
4
+ import { g as getInitialFieldValues } from "../../helpers/getInitialFieldValues/index.js";
5
+ function useDynamicValidation() {
6
+ const { trigger, getValues } = useFormContext();
7
+ const [activeFields, setActiveFields] = useState([]);
8
+ const [isValidating, setIsValidating] = useState(false);
9
+ const statusLoad = useWatch({
10
+ name: "statusLoad"
11
+ });
12
+ const watchValues = useWatch({
13
+ name: activeFields.length > 0 ? activeFields : ["__dummy__"]
14
+ });
15
+ const lastValuesRef = useRef({});
16
+ useEffect(() => {
17
+ if (activeFields.length === 0 || statusLoad !== "ready" || isValidating) {
18
+ return;
19
+ }
20
+ const currentValues = parseWatchedValues(watchValues, activeFields);
21
+ const changedFields = activeFields.filter((field) => {
22
+ const currentValue = currentValues[field];
23
+ const lastValue = lastValuesRef.current[field];
24
+ const hasChanged = JSON.stringify(currentValue) !== JSON.stringify(lastValue);
25
+ if (hasChanged) {
26
+ lastValuesRef.current[field] = currentValue;
27
+ }
28
+ return hasChanged;
29
+ });
30
+ if (changedFields.length > 0) {
31
+ const timeoutId = setTimeout(() => {
32
+ trigger(changedFields);
33
+ }, 100);
34
+ return () => clearTimeout(timeoutId);
35
+ }
36
+ }, [activeFields, trigger, watchValues, statusLoad, isValidating]);
37
+ const startExternalValidation = useCallback(() => {
38
+ setIsValidating(true);
39
+ }, []);
40
+ const endExternalValidation = useCallback(() => {
41
+ setIsValidating(false);
42
+ }, []);
43
+ const activateFieldsValidation = useCallback(
44
+ (fields, skipIfValidating = true) => {
45
+ if (skipIfValidating && isValidating) {
46
+ return;
47
+ }
48
+ const formValues = getValues();
49
+ setActiveFields(fields);
50
+ const initialValues = getInitialFieldValues(formValues, fields);
51
+ lastValuesRef.current = initialValues;
52
+ },
53
+ [getValues, isValidating]
54
+ );
55
+ const clearAllValidation = useCallback(() => {
56
+ setActiveFields([]);
57
+ lastValuesRef.current = {};
58
+ }, []);
59
+ return {
60
+ activateFieldsValidation,
61
+ clearAllValidation,
62
+ activeFields,
63
+ startExternalValidation,
64
+ endExternalValidation
65
+ };
66
+ }
67
+ export {
68
+ useDynamicValidation as u
69
+ };
@@ -2,8 +2,10 @@ import { useCallback } from "react";
2
2
  import { u as useStepper } from "../useStepper/index.js";
3
3
  import { useFormContext } from "react-hook-form";
4
4
  import { shallow } from "zustand/shallow";
5
+ import { u as useDynamicValidation } from "../useDynamicValidation/index.js";
5
6
  function useStepperActions() {
6
7
  const { trigger, clearErrors, getValues, reset } = useFormContext();
8
+ const { activateFieldsValidation, clearAllValidation } = useDynamicValidation();
7
9
  const {
8
10
  nextStep,
9
11
  prevStep,
@@ -41,9 +43,20 @@ function useStepperActions() {
41
43
  if (fieldsToValidate.length === 0) {
42
44
  return true;
43
45
  }
44
- return await trigger(fieldsToValidate);
46
+ const result = await trigger(fieldsToValidate);
47
+ if (!result) {
48
+ activateFieldsValidation(fieldsToValidate);
49
+ }
50
+ return result;
45
51
  };
46
52
  const success = await nextStep(validateFn, formData);
53
+ if (success) {
54
+ const currentStepData = steps[currentStep - 1];
55
+ const fieldsJustValidated = currentStepData?.validationFields || [];
56
+ if (fieldsJustValidated.length > 0) {
57
+ clearAllValidation();
58
+ }
59
+ }
47
60
  if (success && futureFields.length > 0) {
48
61
  clearErrors(futureFields);
49
62
  setTimeout(() => {
@@ -62,13 +75,16 @@ function useStepperActions() {
62
75
  steps,
63
76
  currentStep,
64
77
  trigger,
65
- getValues
78
+ getValues,
79
+ activateFieldsValidation,
80
+ clearAllValidation
66
81
  ]);
67
82
  const cancelAction = useCallback(() => {
68
83
  reset();
69
84
  clearErrors();
85
+ clearAllValidation();
70
86
  resetStepper();
71
- }, [reset, clearErrors, resetStepper]);
87
+ }, [reset, clearErrors, clearAllValidation, resetStepper]);
72
88
  return { prevStepAction, nextStepAction, cancelAction };
73
89
  }
74
90
  export {
@@ -35,6 +35,18 @@ const createStepperStore = (initProps, storeDevtoolsEnabled = false) => {
35
35
  if (!preserveStepValidationStatus) {
36
36
  state.stepValidationStatus = {};
37
37
  }
38
+ if (!preserveStepValidationStatus) {
39
+ const firstVisibleStepIndex = findNextVisibleValidStep(
40
+ -1,
41
+ // Comenzar desde -1 para encontrar el primer step visible
42
+ steps,
43
+ {},
44
+ state.visibilityData
45
+ );
46
+ if (firstVisibleStepIndex !== 0 && firstVisibleStepIndex < steps.length) {
47
+ state.currentStep = firstVisibleStepIndex;
48
+ }
49
+ }
38
50
  });
39
51
  },
40
52
  /**
@@ -114,9 +126,16 @@ const createStepperStore = (initProps, storeDevtoolsEnabled = false) => {
114
126
  */
115
127
  resetStepper: () => {
116
128
  set((state) => {
117
- state.currentStep = 0;
118
129
  state.stepValidationStatus = {};
119
130
  state.isValidating = false;
131
+ const firstVisibleStepIndex = findNextVisibleValidStep(
132
+ -1,
133
+ // Comenzar desde -1 para encontrar el primer step visible
134
+ state.steps,
135
+ {},
136
+ state.visibilityData
137
+ );
138
+ state.currentStep = firstVisibleStepIndex < state.steps.length ? firstVisibleStepIndex : 0;
120
139
  });
121
140
  }
122
141
  }
@@ -5,10 +5,12 @@ import { u as useStepper } from "../../hooks/useStepper/index.js";
5
5
  import { e as StepAreaStyled, f as StepStyled, g as StepNameStyled } from "../../slots/StepperSlot.js";
6
6
  import { I as Indicator } from "./subcomponents/Inidicator/index.js";
7
7
  import { shallow } from "zustand/shallow";
8
+ import { u as useDynamicValidation } from "../../hooks/useDynamicValidation/index.js";
8
9
  import { e as evaluateVisibilityStepCondition } from "../../helpers/evaluateVisibilityStepCondition/index.js";
9
10
  function StepArea() {
10
11
  const { trigger, clearErrors } = useFormContext();
11
12
  const formValues = useWatch();
13
+ const { activateFieldsValidation, startExternalValidation, endExternalValidation } = useDynamicValidation();
12
14
  const {
13
15
  currentStep,
14
16
  steps,
@@ -32,16 +34,19 @@ function StepArea() {
32
34
  }),
33
35
  shallow
34
36
  );
35
- const validSteps = useMemo(() => {
36
- return steps;
37
- }, [steps]);
37
+ const allSteps = steps;
38
+ const visibleSteps = useMemo(() => {
39
+ return steps.filter(
40
+ (step) => evaluateVisibilityStepCondition(step, formValues || {}, visibilityData)
41
+ );
42
+ }, [steps, formValues, visibilityData]);
38
43
  const ownerState = {
39
44
  visibleTitle,
40
45
  orientation,
41
- totalSteps: validSteps.length
46
+ totalSteps: visibleSteps.length
42
47
  };
43
48
  const handleStepClick = async (targetIndex) => {
44
- const currentIndex = validSteps.findIndex(
49
+ const currentIndex = visibleSteps.findIndex(
45
50
  (step) => step.key === steps[currentStep].key
46
51
  );
47
52
  if (targetIndex === currentIndex) {
@@ -49,7 +54,7 @@ function StepArea() {
49
54
  }
50
55
  const isNavigatingForward = targetIndex > currentIndex;
51
56
  const targetOriginalIndex = steps.findIndex(
52
- (s) => s.key === validSteps[targetIndex].key
57
+ (s) => s.key === visibleSteps[targetIndex].key
53
58
  );
54
59
  if (!isNavigatingForward) {
55
60
  setCurrentStep(targetOriginalIndex);
@@ -58,37 +63,43 @@ function StepArea() {
58
63
  const isSkippingSteps = targetIndex > currentIndex + 1;
59
64
  if (isSkippingSteps) {
60
65
  for (let i = currentIndex; i < targetIndex; i++) {
61
- const step = validSteps[i];
66
+ const step = visibleSteps[i];
62
67
  const stepOriginalIndex = steps.findIndex((s) => s.key === step.key);
68
+ startExternalValidation();
63
69
  const isValid = await trigger(step.validationFields);
70
+ endExternalValidation();
64
71
  if (!isValid) {
65
72
  setCurrentStep(stepOriginalIndex);
66
73
  setStepValidationStatus(stepOriginalIndex, false);
74
+ activateFieldsValidation(step.validationFields || []);
67
75
  return;
68
76
  }
69
77
  setStepValidationStatus(stepOriginalIndex, true);
70
78
  }
71
79
  } else {
72
- const currentStepData = validSteps[currentIndex];
80
+ const currentStepData = visibleSteps[currentIndex];
73
81
  const currentStepOriginalIndex = steps.findIndex(
74
82
  (s) => s.key === currentStepData.key
75
83
  );
84
+ startExternalValidation();
76
85
  const isCurrentValid = await trigger(currentStepData.validationFields);
86
+ endExternalValidation();
77
87
  if (!isCurrentValid) {
78
88
  setStepValidationStatus(currentStepOriginalIndex, false);
89
+ activateFieldsValidation(currentStepData.validationFields || []);
79
90
  return;
80
91
  }
81
92
  setStepValidationStatus(currentStepOriginalIndex, true);
82
93
  }
83
94
  setCurrentStep(targetOriginalIndex);
84
95
  if (isNavigatingForward) {
85
- const currentStepData = validSteps[currentIndex];
96
+ const currentStepData = visibleSteps[currentIndex];
86
97
  const currentStepOriginalIndex = steps.findIndex(
87
98
  (s) => s.key === currentStepData.key
88
99
  );
89
100
  const isCurrentStepValid = stepValidationStatus[currentStepOriginalIndex] !== false;
90
101
  if (isCurrentStepValid) {
91
- const targetStep = validSteps[targetIndex];
102
+ const targetStep = visibleSteps[targetIndex];
92
103
  const targetStepFields = targetStep.validationFields || [];
93
104
  if (targetStepFields.length > 0) {
94
105
  clearErrors(targetStepFields);
@@ -100,32 +111,37 @@ function StepArea() {
100
111
  }
101
112
  }
102
113
  };
103
- return /* @__PURE__ */ jsx(StepAreaStyled, { ownerState, children: validSteps.map((step, validIndex) => {
104
- const originalIndex = steps.findIndex((s) => s.key === step.key);
105
- const totalVisibleSteps = validSteps.filter(
106
- (s) => evaluateVisibilityStepCondition(s, formValues || {}, visibilityData)
107
- ).length;
114
+ return /* @__PURE__ */ jsx(StepAreaStyled, { ownerState, children: allSteps.map((step, originalIndex) => {
115
+ const isStepVisible = evaluateVisibilityStepCondition(
116
+ step,
117
+ formValues || {},
118
+ visibilityData
119
+ );
120
+ const visibleStepIndex = isStepVisible ? visibleSteps.findIndex((visStep) => visStep.key === step.key) : -1;
108
121
  return /* @__PURE__ */ jsxs(
109
122
  StepStyled,
110
123
  {
111
124
  role: "button",
112
- onClick: () => handleStepClick(validIndex),
125
+ onClick: () => isStepVisible ? handleStepClick(visibleStepIndex) : void 0,
113
126
  ownerState: {
114
127
  ...ownerState,
115
128
  currentStep,
116
- step: validIndex,
117
- isStepVisible: evaluateVisibilityStepCondition(
118
- step,
119
- formValues || {},
120
- visibilityData
121
- )
129
+ step: visibleStepIndex,
130
+ // Usa el índice en la secuencia visible
131
+ isStepVisible
122
132
  },
123
133
  children: [
124
134
  visibleTitle && /* @__PURE__ */ jsx(
125
135
  StepNameStyled,
126
136
  {
127
137
  variant: "body",
128
- ownerState: { ...ownerState, currentStep, step: validIndex },
138
+ ownerState: {
139
+ ...ownerState,
140
+ currentStep,
141
+ step: visibleStepIndex,
142
+ originalStepIndex: originalIndex,
143
+ isStepVisible
144
+ },
129
145
  children: step.title
130
146
  }
131
147
  ),
@@ -133,8 +149,8 @@ function StepArea() {
133
149
  Indicator,
134
150
  {
135
151
  currentStep,
136
- step: validIndex,
137
- totalSteps: totalVisibleSteps,
152
+ step: visibleStepIndex,
153
+ totalSteps: visibleSteps.length,
138
154
  originalStepIndex: originalIndex
139
155
  }
140
156
  )
@@ -21,15 +21,6 @@ function Indicator(props) {
21
21
  );
22
22
  const { host_static_assets, environment_assets } = useEnvironment();
23
23
  const { currentSize } = useComponentSize(size);
24
- const ownerState = {
25
- size: currentSize,
26
- currentStep,
27
- step,
28
- totalSteps,
29
- orientation,
30
- indicatorType,
31
- stepValidationStatus
32
- };
33
24
  const isMobile = useIsMobile();
34
25
  const effectiveIndicatorType = useMemo(() => {
35
26
  return isMobile ? "dot" : indicatorType;
@@ -45,6 +36,20 @@ function Indicator(props) {
45
36
  hasBeenValidated: validated
46
37
  };
47
38
  }, [currentStep, originalStepIndex, stepValidationStatus]);
39
+ const ownerState = {
40
+ size: currentSize,
41
+ currentStep,
42
+ step,
43
+ totalSteps,
44
+ orientation,
45
+ indicatorType,
46
+ stepValidationStatus,
47
+ originalStepIndex,
48
+ isCompleted,
49
+ isCurrent: currentStep === originalStepIndex,
50
+ isValidStep,
51
+ hasBeenValidated
52
+ };
48
53
  return /* @__PURE__ */ jsx(IndicatorStyled, { ownerState, children: hasBeenValidated && !isValidStep ? (
49
54
  // Mostrar error solo si ha sido validado y es inválido
50
55
  /* @__PURE__ */ jsx(
@@ -67,7 +72,10 @@ function Indicator(props) {
67
72
  )
68
73
  ) : (
69
74
  // Mostrar estado normal (número o dot) para pasos no validados o actuales
70
- /* @__PURE__ */ jsx(TextNumberStyled, { variant: "body", ownerState: { currentStep, step }, children: effectiveIndicatorType === "number" ? step + 1 : /* @__PURE__ */ jsx(
75
+ /* @__PURE__ */ jsx(TextNumberStyled, { variant: "body", ownerState, children: effectiveIndicatorType === "number" ? (
76
+ // Solo mostrar número si el step es visible (step >= 0)
77
+ step >= 0 ? step + 1 : ""
78
+ ) : /* @__PURE__ */ jsx(
71
79
  Icon,
72
80
  {
73
81
  src: `${host_static_assets}/${environment_assets}/${currentStep === originalStepIndex ? pathIcons.dotSelected : pathIcons.dotOutline}`,
@@ -1,4 +1,5 @@
1
+ import { StepperButtonProps } from '../../../types';
1
2
  /**
2
3
  * Botón modular para cancelar el proceso del Stepper
3
4
  */
4
- export declare function StepperCancelButton(): import("react/jsx-runtime").JSX.Element;
5
+ export declare function StepperCancelButton(props: StepperButtonProps): import("react/jsx-runtime").JSX.Element;
@@ -1,22 +1,55 @@
1
1
  import { jsx } from "react/jsx-runtime";
2
+ import { useCallback } from "react";
3
+ import { useFormContext, useFormState } from "react-hook-form";
2
4
  import { u as useStepperActions } from "../../../hooks/useStepperActions/index.js";
3
- import { D as DICTIONARY } from "../../../dictionary.js";
5
+ import { D as DICTIONARY$1 } from "../../../dictionary.js";
6
+ import { D as DICTIONARY } from "../../../../CommonActions/dictionary.js";
4
7
  import { useModuleDictionary } from "@m4l/core";
8
+ import { u as useModal } from "../../../../../hooks/useModal/index.js";
9
+ import { u as useWindowToolsMF } from "../../../../WindowBase/hooks/useWindowToolsMF/index.js";
10
+ import { W as WindowConfirm } from "../../../../WindowConfirm/WindowConfirm.js";
5
11
  import { B as Button } from "../../../../mui_extended/Button/Button.js";
6
- function StepperCancelButton() {
12
+ function StepperCancelButton(props) {
13
+ const { label, ...rest } = props;
7
14
  const { getLabel } = useModuleDictionary();
8
15
  const { cancelAction } = useStepperActions();
9
- const handleCancel = () => {
16
+ const { openModal } = useModal();
17
+ const { close: closeWindow } = useWindowToolsMF();
18
+ const { control } = useFormContext();
19
+ const { isDirty } = useFormState({
20
+ control
21
+ });
22
+ const onConfirmQuit = useCallback(() => {
10
23
  cancelAction();
11
- };
24
+ closeWindow();
25
+ }, [cancelAction, closeWindow]);
26
+ const handleCancel = useCallback(() => {
27
+ if (isDirty) {
28
+ openModal({
29
+ window: /* @__PURE__ */ jsx(
30
+ WindowConfirm,
31
+ {
32
+ variant: "warning",
33
+ title: getLabel(DICTIONARY.CONFIRM_QUIT_TITLE),
34
+ msg: getLabel(DICTIONARY.CONFIRM_QUIT_MSG),
35
+ onClickIntro: onConfirmQuit
36
+ }
37
+ ),
38
+ variant: "warning"
39
+ });
40
+ } else {
41
+ onConfirmQuit();
42
+ }
43
+ }, [getLabel, isDirty, openModal, onConfirmQuit]);
12
44
  return /* @__PURE__ */ jsx(
13
45
  Button,
14
46
  {
15
47
  type: "button",
16
- label: getLabel(DICTIONARY.LABEL_CANCEL_BUTTON),
48
+ label: label || getLabel(DICTIONARY$1.LABEL_CANCEL_BUTTON),
17
49
  variant: "outlined",
18
50
  color: "default",
19
- onClick: handleCancel
51
+ onClick: handleCancel,
52
+ ...rest
20
53
  }
21
54
  );
22
55
  }
@@ -1,4 +1,5 @@
1
+ import { StepperButtonProps } from '../../../types';
1
2
  /**
2
3
  * Botón modular para avanzar al siguiente step del Stepper
3
4
  */
4
- export declare function StepperNextButton(): import("react/jsx-runtime").JSX.Element;
5
+ export declare function StepperNextButton(props: StepperButtonProps): import("react/jsx-runtime").JSX.Element;
@@ -6,7 +6,8 @@ import { D as DICTIONARY } from "../../../dictionary.js";
6
6
  import { useModuleDictionary, useEnvironment } from "@m4l/core";
7
7
  import { I as IconButton } from "../../../../mui_extended/IconButton/IconButton.js";
8
8
  import { B as Button } from "../../../../mui_extended/Button/Button.js";
9
- function StepperNextButton() {
9
+ function StepperNextButton(props) {
10
+ const { label, ...rest } = props;
10
11
  const { nextStepAction } = useStepperActions();
11
12
  const isMobile = useIsMobile();
12
13
  const { getLabel } = useModuleDictionary();
@@ -28,12 +29,13 @@ function StepperNextButton() {
28
29
  Button,
29
30
  {
30
31
  type: "button",
31
- label: getLabel(DICTIONARY.LABEL_NEXT_BUTTON),
32
+ label: label || getLabel(DICTIONARY.LABEL_NEXT_BUTTON),
32
33
  variant: "contained",
33
34
  color: "primary",
34
35
  onClick: handleNext,
35
36
  endIcon: `${host_static_assets}/${environment_assets}/${pathIcons.arrowRight}`,
36
- "data-testid": "stepper-next-button"
37
+ "data-testid": "stepper-next-button",
38
+ ...rest
37
39
  }
38
40
  );
39
41
  }
@@ -1,4 +1,5 @@
1
+ import { StepperButtonProps } from '../../../types';
1
2
  /**
2
3
  * Botón modular para ir al step anterior del Stepper
3
4
  */
4
- export declare function StepperPrevButton(): import("react/jsx-runtime").JSX.Element | null;
5
+ export declare function StepperPrevButton(props: StepperButtonProps): import("react/jsx-runtime").JSX.Element | null;