@m4l/components 9.4.25 → 9.4.26

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 (26) hide show
  1. package/components/Stepper/Stepper.js +1 -1
  2. package/components/Stepper/Stepper.styles.js +22 -9
  3. package/components/Stepper/helpers/findAllVisibleStepsBefore/index.d.ts +19 -0
  4. package/components/Stepper/helpers/findAllVisibleStepsBefore/index.js +22 -0
  5. package/components/Stepper/helpers/findStepIndexByKey/index.d.ts +8 -0
  6. package/components/Stepper/helpers/findStepIndexByKey/index.js +6 -0
  7. package/components/Stepper/helpers/index.d.ts +2 -0
  8. package/components/Stepper/hooks/useInitialStepKey/index.d.ts +5 -0
  9. package/components/Stepper/hooks/useInitialStepKey/index.js +44 -0
  10. package/components/Stepper/slots/StepperEnum.d.ts +1 -0
  11. package/components/Stepper/slots/StepperEnum.js +1 -0
  12. package/components/Stepper/slots/StepperSlot.d.ts +3 -0
  13. package/components/Stepper/slots/StepperSlot.js +16 -11
  14. package/components/Stepper/store/StepperContext/index.js +3 -1
  15. package/components/Stepper/store/StepperStore/index.js +70 -0
  16. package/components/Stepper/store/types.d.ts +12 -2
  17. package/components/Stepper/subcomponents/ContentArea/index.js +3 -1
  18. package/components/Stepper/subcomponents/ContentArea/subcomponents/WrapperIcon/index.js +1 -1
  19. package/components/Stepper/subcomponents/ContentArea/subcomponents/WrapperTitle/index.js +1 -1
  20. package/components/Stepper/subcomponents/StepArea/index.js +2 -2
  21. package/components/Stepper/subcomponents/StepperContent/subcomponents/Step/index.js +1 -1
  22. package/components/Stepper/subcomponents/StepperFooter/index.js +1 -1
  23. package/components/Stepper/subcomponents/StepperFooter/subcomponents/StepperFooterLeftActions/index.js +1 -1
  24. package/components/Stepper/subcomponents/StepperFooter/subcomponents/StepperFooterRightActions/index.js +1 -1
  25. package/components/Stepper/types.d.ts +22 -0
  26. package/package.json +1 -1
@@ -2,7 +2,7 @@ import { jsx, jsxs } from "react/jsx-runtime";
2
2
  import { useMemo, Children, isValidElement } from "react";
3
3
  import clsx from "clsx";
4
4
  import { useFlagsPresent, CommonFlags } from "@m4l/core";
5
- import { l as StepperRootStyled, m as ContentSectionStyled } from "./slots/StepperSlot.js";
5
+ import { m as StepperRootStyled, n as ContentSectionStyled } from "./slots/StepperSlot.js";
6
6
  import { g as getComponentSlotRoot } from "../../utils/getComponentSlotRoot.js";
7
7
  import { a as STEPPER_PREFIX_NAME } from "./constants.js";
8
8
  import { S as StepArea } from "./subcomponents/StepArea/index.js";
@@ -111,35 +111,47 @@ const stepperStyles = {
111
111
  * Estilos para el nombre del paso dentro del Stepper.
112
112
  */
113
113
  stepName: ({ theme, ownerState }) => ({
114
- ...ownerState?.orientation === "horizontal" && {
115
- height: theme.generalSettings.isMobile ? theme.vars.size.mobile.medium.action : theme.vars.size.desktop.medium.action
114
+ ...ownerState?.orientation === "horizontal" && !theme.generalSettings.isMobile && {
115
+ minHeight: theme.vars.size.desktop.medium.action,
116
+ maxWidth: "120px",
117
+ width: "100%"
116
118
  },
117
119
  ...(ownerState?.orientation === "vertical" || theme.generalSettings.isMobile) && {
118
120
  maxWidth: "120px",
119
121
  width: "100%",
120
- lineHeight: "1.2",
121
122
  marginTop: theme.vars.size.baseSpacings.sp1
122
123
  },
123
124
  alignContent: "center",
124
125
  cursor: "pointer",
125
- overflow: "hidden",
126
126
  ...theme.generalSettings.isMobile ? {
127
127
  display: "none"
128
128
  } : {
129
- display: ownerState?.visibleTitle ? "-webkit-box" : "none"
129
+ display: ownerState?.visibleTitle ? "block" : "none"
130
130
  },
131
- WebkitBoxOrient: "vertical",
132
- WebkitLineClamp: 2,
133
- textOverflow: "ellipsis",
134
131
  flex: 1,
135
132
  minWidth: 0,
136
- whiteSpace: "normal",
137
133
  order: ownerState?.orientation === "vertical" || theme.generalSettings.isMobile ? 1 : 0,
138
134
  "&.M4LTypography-root": {
139
135
  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,
140
136
  textAlign: ownerState?.orientation === "vertical" || theme.generalSettings.isMobile ? "center" : "right"
141
137
  }
142
138
  }),
139
+ /**
140
+ * Estilos para el texto del nombre del paso con truncado (line-clamp).
141
+ */
142
+ stepNameText: ({ theme, ownerState }) => ({
143
+ display: "-webkit-box",
144
+ "-webkit-box-orient": "vertical",
145
+ "-webkit-line-clamp": "2",
146
+ overflow: "hidden",
147
+ textOverflow: "ellipsis",
148
+ wordBreak: "break-word",
149
+ whiteSpace: "normal",
150
+ width: "100%",
151
+ direction: "ltr",
152
+ lineHeight: 1.2,
153
+ textAlign: ownerState?.orientation === "vertical" || theme.generalSettings.isMobile ? "center" : "left"
154
+ }),
143
155
  /**
144
156
  * Estilos para el indicador numérico de cada paso del Stepper.
145
157
  */
@@ -228,6 +240,7 @@ const stepperStyles = {
228
240
  display: "flex",
229
241
  alignItems: "center",
230
242
  justifyContent: "center",
243
+ flexShrink: 0,
231
244
  background: theme.vars.palette.primary.enabledOpacity,
232
245
  borderRadius: theme.vars.size.borderRadius["r1-5"],
233
246
  ...getSizeStyles(theme, ownerState?.size || "medium", "box", (size) => ({
@@ -0,0 +1,19 @@
1
+ import { FormData, Step, StepWithIndex, VisibilityData } from '../../types';
2
+ /**
3
+ * Obtiene todos los steps visibles que están antes de un step específico.
4
+ *
5
+ * Esta función es utilizada por la feature `initialStepKey` para determinar
6
+ * qué steps deben ser validados antes de poder navegar al step inicial deseado.
7
+ * @example
8
+ * // Si tenemos steps: [A, B (oculto), C, D] y queremos iniciar en D (índice 3)
9
+ * // Esta función retornará: [{ step: A, originalIndex: 0 }, { step: C, originalIndex: 2 }]
10
+ * // El step B se omite porque está oculto por su visibilityCondition
11
+ * @param initialStepIndex - El índice del step donde se desea iniciar.
12
+ * Los steps en este índice y posteriores NO se incluyen en el resultado.
13
+ * @param steps - Array completo de steps configurados en el Stepper.
14
+ * @param formData - Valores actuales del formulario para evaluar las condiciones de visibilidad.
15
+ * @param visibilityData - Datos adicionales para evaluar visibilidad (ej: objectId, accountId).
16
+ * @returns Array de steps visibles con su índice original, ordenados de menor a mayor índice.
17
+ * Retorna array vacío si initialStepIndex es 0 o no hay steps visibles antes.
18
+ */
19
+ export declare const findAllVisibleStepsBefore: (initialStepIndex: number, steps: Step[], formData?: FormData, visibilityData?: VisibilityData) => StepWithIndex[];
@@ -0,0 +1,22 @@
1
+ import { e as evaluateVisibilityStepCondition } from "../evaluateVisibilityStepCondition/index.js";
2
+ const findAllVisibleStepsBefore = (initialStepIndex, steps, formData, visibilityData) => {
3
+ const visibleStepsBefore = [];
4
+ for (let currentIndex = 0; currentIndex < initialStepIndex && currentIndex < steps.length; currentIndex++) {
5
+ const currentStep = steps[currentIndex];
6
+ const isStepVisible = evaluateVisibilityStepCondition(
7
+ currentStep,
8
+ formData || {},
9
+ visibilityData
10
+ );
11
+ if (isStepVisible) {
12
+ visibleStepsBefore.push({
13
+ step: currentStep,
14
+ originalIndex: currentIndex
15
+ });
16
+ }
17
+ }
18
+ return visibleStepsBefore;
19
+ };
20
+ export {
21
+ findAllVisibleStepsBefore as f
22
+ };
@@ -0,0 +1,8 @@
1
+ import { Step } from '../../types';
2
+ /**
3
+ * findStepIndexByKey - Encuentra el índice de un step por su key
4
+ * @param stepKey - La key del step a buscar
5
+ * @param steps - Array de steps
6
+ * @returns El índice del step, o -1 si no se encuentra
7
+ */
8
+ export declare const findStepIndexByKey: (stepKey: string, steps: Step[]) => number;
@@ -0,0 +1,6 @@
1
+ const findStepIndexByKey = (stepKey, steps) => {
2
+ return steps.findIndex((step) => step.key === stepKey);
3
+ };
4
+ export {
5
+ findStepIndexByKey as f
6
+ };
@@ -6,3 +6,5 @@ export { isElementInViewport } from './isElementInViewport';
6
6
  export { isLastVisibleValidStep } from './isLastVisibleValidStep';
7
7
  export { parseWatchedValues } from './parseWatchedValues';
8
8
  export { getInitialFieldValues } from './getInitialFieldValues';
9
+ export { findStepIndexByKey } from './findStepIndexByKey';
10
+ export { findAllVisibleStepsBefore } from './findAllVisibleStepsBefore';
@@ -0,0 +1,5 @@
1
+ /**
2
+ * Hook que aplica initialStepKey cuando el formulario está en estado 'ready'.
3
+ * Valida los steps anteriores y navega al step inicial o al primer step con errores.
4
+ */
5
+ export declare function useInitialStepKey(): void;
@@ -0,0 +1,44 @@
1
+ import { useRef, useEffect } from "react";
2
+ import { useFormContext, useWatch } from "react-hook-form";
3
+ import { shallow } from "zustand/shallow";
4
+ import { u as useStepper } from "../useStepper/index.js";
5
+ function useInitialStepKey() {
6
+ const { trigger, getValues } = useFormContext();
7
+ const hasAttemptedRef = useRef(false);
8
+ const statusLoad = useWatch({ name: "statusLoad" });
9
+ const { initialStepKey, initialStepKeyApplied, applyInitialStepKey } = useStepper(
10
+ (state) => ({
11
+ initialStepKey: state.initialStepKey,
12
+ initialStepKeyApplied: state.initialStepKeyApplied,
13
+ applyInitialStepKey: state.actions.applyInitialStepKey
14
+ }),
15
+ shallow
16
+ );
17
+ useEffect(() => {
18
+ if (statusLoad !== "ready" || !initialStepKey || initialStepKeyApplied || hasAttemptedRef.current) {
19
+ return;
20
+ }
21
+ hasAttemptedRef.current = true;
22
+ const executeInitialStepKey = async () => {
23
+ const validateFieldsFn = async (fields) => {
24
+ if (fields.length === 0) {
25
+ return true;
26
+ }
27
+ return trigger(fields);
28
+ };
29
+ const formData = getValues();
30
+ await applyInitialStepKey(validateFieldsFn, formData);
31
+ };
32
+ executeInitialStepKey();
33
+ }, [
34
+ statusLoad,
35
+ initialStepKey,
36
+ initialStepKeyApplied,
37
+ applyInitialStepKey,
38
+ trigger,
39
+ getValues
40
+ ]);
41
+ }
42
+ export {
43
+ useInitialStepKey as u
44
+ };
@@ -6,6 +6,7 @@ export declare enum ContentSlots {
6
6
  stepArea = "stepArea",
7
7
  step = "step",
8
8
  stepName = "stepName",
9
+ stepNameText = "stepNameText",
9
10
  indicator = "indicator",
10
11
  textNumber = "textNumber"
11
12
  }
@@ -7,6 +7,7 @@ var ContentSlots = /* @__PURE__ */ ((ContentSlots2) => {
7
7
  ContentSlots2["stepArea"] = "stepArea";
8
8
  ContentSlots2["step"] = "step";
9
9
  ContentSlots2["stepName"] = "stepName";
10
+ ContentSlots2["stepNameText"] = "stepNameText";
10
11
  ContentSlots2["indicator"] = "indicator";
11
12
  ContentSlots2["textNumber"] = "textNumber";
12
13
  return ContentSlots2;
@@ -22,6 +22,9 @@ export declare const StepStyled: import('@emotion/styled').StyledComponent<impor
22
22
  export declare const StepNameStyled: import('@emotion/styled').StyledComponent<Pick<Omit<import('../../mui_extended/Typography/types').TypographyProps, "ref"> & import('react').RefAttributes<HTMLSpanElement>, "size" | "children" | "title" | "component" | "zIndex" | "id" | "disabled" | "paragraph" | "border" | "fontWeight" | "lineHeight" | "letterSpacing" | "fontSize" | "textTransform" | "fontFamily" | "typography" | "flex" | "variant" | "color" | "dataTestid" | "alignContent" | "alignItems" | "alignSelf" | "bottom" | "boxShadow" | "boxSizing" | "columnGap" | "content" | "display" | "flexBasis" | "flexDirection" | "flexGrow" | "flexShrink" | "flexWrap" | "fontStyle" | "gridAutoColumns" | "gridAutoFlow" | "gridAutoRows" | "gridTemplateAreas" | "gridTemplateColumns" | "gridTemplateRows" | "height" | "justifyContent" | "justifyItems" | "justifySelf" | "left" | "marginBlockEnd" | "marginBlockStart" | "marginBottom" | "marginInlineEnd" | "marginInlineStart" | "marginLeft" | "marginRight" | "marginTop" | "maxHeight" | "maxWidth" | "minHeight" | "minWidth" | "order" | "paddingBlockEnd" | "paddingBlockStart" | "paddingBottom" | "paddingInlineEnd" | "paddingInlineStart" | "paddingLeft" | "paddingRight" | "paddingTop" | "position" | "right" | "rowGap" | "textAlign" | "textOverflow" | "top" | "translate" | "visibility" | "whiteSpace" | "width" | "borderBottom" | "borderColor" | "borderLeft" | "borderRadius" | "borderRight" | "borderTop" | "gap" | "gridArea" | "gridColumn" | "gridRow" | "margin" | "marginBlock" | "marginInline" | "overflow" | "padding" | "paddingBlock" | "paddingInline" | "className" | "style" | "classes" | "sx" | "p" | "slot" | "defaultChecked" | "defaultValue" | "suppressContentEditableWarning" | "suppressHydrationWarning" | "accessKey" | "autoCapitalize" | "autoFocus" | "contentEditable" | "contextMenu" | "dir" | "draggable" | "enterKeyHint" | "hidden" | "lang" | "nonce" | "spellCheck" | "tabIndex" | "radioGroup" | "role" | "about" | "datatype" | "inlist" | "prefix" | "property" | "rel" | "resource" | "rev" | "typeof" | "vocab" | "autoCorrect" | "autoSave" | "itemProp" | "itemScope" | "itemType" | "itemID" | "itemRef" | "results" | "security" | "unselectable" | "inputMode" | "is" | "exportparts" | "part" | "aria-activedescendant" | "aria-atomic" | "aria-autocomplete" | "aria-braillelabel" | "aria-brailleroledescription" | "aria-busy" | "aria-checked" | "aria-colcount" | "aria-colindex" | "aria-colindextext" | "aria-colspan" | "aria-controls" | "aria-current" | "aria-describedby" | "aria-description" | "aria-details" | "aria-disabled" | "aria-dropeffect" | "aria-errormessage" | "aria-expanded" | "aria-flowto" | "aria-grabbed" | "aria-haspopup" | "aria-hidden" | "aria-invalid" | "aria-keyshortcuts" | "aria-label" | "aria-labelledby" | "aria-level" | "aria-live" | "aria-modal" | "aria-multiline" | "aria-multiselectable" | "aria-orientation" | "aria-owns" | "aria-placeholder" | "aria-posinset" | "aria-pressed" | "aria-readonly" | "aria-relevant" | "aria-required" | "aria-roledescription" | "aria-rowcount" | "aria-rowindex" | "aria-rowindextext" | "aria-rowspan" | "aria-selected" | "aria-setsize" | "aria-sort" | "aria-valuemax" | "aria-valuemin" | "aria-valuenow" | "aria-valuetext" | "dangerouslySetInnerHTML" | "onCopy" | "onCopyCapture" | "onCut" | "onCutCapture" | "onPaste" | "onPasteCapture" | "onCompositionEnd" | "onCompositionEndCapture" | "onCompositionStart" | "onCompositionStartCapture" | "onCompositionUpdate" | "onCompositionUpdateCapture" | "onFocus" | "onFocusCapture" | "onBlur" | "onBlurCapture" | "onChange" | "onChangeCapture" | "onBeforeInput" | "onBeforeInputCapture" | "onInput" | "onInputCapture" | "onReset" | "onResetCapture" | "onSubmit" | "onSubmitCapture" | "onInvalid" | "onInvalidCapture" | "onLoad" | "onLoadCapture" | "onError" | "onErrorCapture" | "onKeyDown" | "onKeyDownCapture" | "onKeyPress" | "onKeyPressCapture" | "onKeyUp" | "onKeyUpCapture" | "onAbort" | "onAbortCapture" | "onCanPlay" | "onCanPlayCapture" | "onCanPlayThrough" | "onCanPlayThroughCapture" | "onDurationChange" | "onDurationChangeCapture" | "onEmptied" | "onEmptiedCapture" | "onEncrypted" | "onEncryptedCapture" | "onEnded" | "onEndedCapture" | "onLoadedData" | "onLoadedDataCapture" | "onLoadedMetadata" | "onLoadedMetadataCapture" | "onLoadStart" | "onLoadStartCapture" | "onPause" | "onPauseCapture" | "onPlay" | "onPlayCapture" | "onPlaying" | "onPlayingCapture" | "onProgress" | "onProgressCapture" | "onRateChange" | "onRateChangeCapture" | "onSeeked" | "onSeekedCapture" | "onSeeking" | "onSeekingCapture" | "onStalled" | "onStalledCapture" | "onSuspend" | "onSuspendCapture" | "onTimeUpdate" | "onTimeUpdateCapture" | "onVolumeChange" | "onVolumeChangeCapture" | "onWaiting" | "onWaitingCapture" | "onAuxClick" | "onAuxClickCapture" | "onClick" | "onClickCapture" | "onContextMenu" | "onContextMenuCapture" | "onDoubleClick" | "onDoubleClickCapture" | "onDrag" | "onDragCapture" | "onDragEnd" | "onDragEndCapture" | "onDragEnter" | "onDragEnterCapture" | "onDragExit" | "onDragExitCapture" | "onDragLeave" | "onDragLeaveCapture" | "onDragOver" | "onDragOverCapture" | "onDragStart" | "onDragStartCapture" | "onDrop" | "onDropCapture" | "onMouseDown" | "onMouseDownCapture" | "onMouseEnter" | "onMouseLeave" | "onMouseMove" | "onMouseMoveCapture" | "onMouseOut" | "onMouseOutCapture" | "onMouseOver" | "onMouseOverCapture" | "onMouseUp" | "onMouseUpCapture" | "onSelect" | "onSelectCapture" | "onTouchCancel" | "onTouchCancelCapture" | "onTouchEnd" | "onTouchEndCapture" | "onTouchMove" | "onTouchMoveCapture" | "onTouchStart" | "onTouchStartCapture" | "onPointerDown" | "onPointerDownCapture" | "onPointerMove" | "onPointerMoveCapture" | "onPointerUp" | "onPointerUpCapture" | "onPointerCancel" | "onPointerCancelCapture" | "onPointerEnter" | "onPointerLeave" | "onPointerOver" | "onPointerOverCapture" | "onPointerOut" | "onPointerOutCapture" | "onGotPointerCapture" | "onGotPointerCaptureCapture" | "onLostPointerCapture" | "onLostPointerCaptureCapture" | "onScroll" | "onScrollCapture" | "onWheel" | "onWheelCapture" | "onAnimationStart" | "onAnimationStartCapture" | "onAnimationEnd" | "onAnimationEndCapture" | "onAnimationIteration" | "onAnimationIterationCapture" | "onTransitionEnd" | "onTransitionEndCapture" | "bgcolor" | "m" | "mt" | "mr" | "mb" | "ml" | "mx" | "marginX" | "my" | "marginY" | "pt" | "pr" | "pb" | "pl" | "px" | "paddingX" | "py" | "paddingY" | "displayPrint" | "align" | "htmlFor" | "gutterBottom" | "noWrap" | "variantMapping" | "skeletonWidth" | "skeletonRows" | "ellipsis" | keyof import('react').RefAttributes<HTMLSpanElement>> & import('@mui/system').MUIStyledCommonProps<import('@mui/material/styles').Theme> & Record<string, unknown> & {
23
23
  ownerState?: (Partial<import('../types').StepperOwnerState> & Record<string, unknown>) | undefined;
24
24
  }, {}, {}>;
25
+ export declare const StepNameTextStyled: import('@emotion/styled').StyledComponent<import('@mui/system').MUIStyledCommonProps<import('@mui/material/styles').Theme> & Record<string, unknown> & {
26
+ ownerState?: (Partial<import('../types').StepperOwnerState> & Record<string, unknown>) | undefined;
27
+ }, Pick<import('react').DetailedHTMLProps<import('react').HTMLAttributes<HTMLDivElement>, HTMLDivElement>, keyof import('react').ClassAttributes<HTMLDivElement> | keyof import('react').HTMLAttributes<HTMLDivElement>>, {}>;
25
28
  export declare const IndicatorStyled: import('@emotion/styled').StyledComponent<import('@mui/system').MUIStyledCommonProps<import('@mui/material/styles').Theme> & Record<string, unknown> & {
26
29
  ownerState?: (Partial<import('../types').StepperOwnerState> & Record<string, unknown>) | undefined;
27
30
  }, Pick<import('react').DetailedHTMLProps<import('react').HTMLAttributes<HTMLDivElement>, HTMLDivElement>, keyof import('react').ClassAttributes<HTMLDivElement> | keyof import('react').HTMLAttributes<HTMLDivElement>>, {}>;
@@ -32,6 +32,10 @@ const StepNameStyled = styled(Typography, {
32
32
  name: STEPPER_PREFIX_NAME,
33
33
  slot: ContentSlots.stepName
34
34
  })(stepperStyles.stepName);
35
+ const StepNameTextStyled = styled("div", {
36
+ name: STEPPER_PREFIX_NAME,
37
+ slot: ContentSlots.stepNameText
38
+ })(stepperStyles.stepNameText);
35
39
  const IndicatorStyled = styled("div", {
36
40
  name: STEPPER_PREFIX_NAME,
37
41
  slot: ContentSlots.indicator
@@ -93,15 +97,16 @@ export {
93
97
  WrapperIconStyled as W,
94
98
  StepStyled as a,
95
99
  StepNameStyled as b,
96
- IconStyled as c,
97
- WrapperTitleStyled as d,
98
- TitleStyled as e,
99
- ContentAreaHeaderStyled as f,
100
- ContentAreaBodyStyled as g,
101
- StepperFooterLeftActionsStyled as h,
102
- StepperFooterRightActionsStyled as i,
103
- StepperFooterSectionStyled as j,
104
- StepContentStyled as k,
105
- StepperRootStyled as l,
106
- ContentSectionStyled as m
100
+ StepNameTextStyled as c,
101
+ IconStyled as d,
102
+ WrapperTitleStyled as e,
103
+ TitleStyled as f,
104
+ ContentAreaHeaderStyled as g,
105
+ ContentAreaBodyStyled as h,
106
+ StepperFooterLeftActionsStyled as i,
107
+ StepperFooterRightActionsStyled as j,
108
+ StepperFooterSectionStyled as k,
109
+ StepContentStyled as l,
110
+ StepperRootStyled as m,
111
+ ContentSectionStyled as n
107
112
  };
@@ -12,6 +12,7 @@ const StepperProvider = (props) => {
12
12
  indicatorType = "number",
13
13
  orientation = "horizontal",
14
14
  visibilityData,
15
+ initialStepKey,
15
16
  children
16
17
  } = props;
17
18
  const stepperStoreRef = useRef();
@@ -25,7 +26,8 @@ const StepperProvider = (props) => {
25
26
  ownerState: {},
26
27
  indicatorType,
27
28
  orientation,
28
- visibilityData
29
+ visibilityData,
30
+ initialStepKey
29
31
  },
30
32
  storeDevtoolsEnabled
31
33
  );
@@ -2,6 +2,9 @@ import { createStore } from "zustand";
2
2
  import { devtools } from "zustand/middleware";
3
3
  import { immer } from "zustand/middleware/immer";
4
4
  import { S as STEPPER_STORE_ID } from "../../constants.js";
5
+ import { f as findStepIndexByKey } from "../../helpers/findStepIndexByKey/index.js";
6
+ import { e as evaluateVisibilityStepCondition } from "../../helpers/evaluateVisibilityStepCondition/index.js";
7
+ import { f as findAllVisibleStepsBefore } from "../../helpers/findAllVisibleStepsBefore/index.js";
5
8
  import { f as findNextVisibleValidStep } from "../../helpers/findNextVisibleValidStep/index.js";
6
9
  import { f as findPrevVisibleValidStep } from "../../helpers/findPrevVisibleValidStep/index.js";
7
10
  const createDevtools = (immerMiddlewere, config) => {
@@ -16,6 +19,7 @@ const createStepperStore = (initProps, storeDevtoolsEnabled = false) => {
16
19
  currentStep: 0,
17
20
  stepValidationStatus: {},
18
21
  isValidating: false,
22
+ initialStepKeyApplied: false,
19
23
  ...initProps
20
24
  };
21
25
  return createStore(
@@ -128,6 +132,7 @@ const createStepperStore = (initProps, storeDevtoolsEnabled = false) => {
128
132
  set((state) => {
129
133
  state.stepValidationStatus = {};
130
134
  state.isValidating = false;
135
+ state.initialStepKeyApplied = false;
131
136
  const firstVisibleStepIndex = findNextVisibleValidStep(
132
137
  -1,
133
138
  // Comenzar desde -1 para encontrar el primer step visible
@@ -137,6 +142,71 @@ const createStepperStore = (initProps, storeDevtoolsEnabled = false) => {
137
142
  );
138
143
  state.currentStep = firstVisibleStepIndex < state.steps.length ? firstVisibleStepIndex : 0;
139
144
  });
145
+ },
146
+ /**
147
+ * applyInitialStepKey - Valida los steps anteriores y navega al step indicado por initialStepKey.
148
+ * Si algún step anterior tiene errores, navega al primer step con errores.
149
+ */
150
+ applyInitialStepKey: async (validateFieldsFn, formData) => {
151
+ const state = get();
152
+ const { initialStepKey, steps, visibilityData, initialStepKeyApplied } = state;
153
+ if (!initialStepKey || initialStepKey.trim() === "" || initialStepKeyApplied) {
154
+ return;
155
+ }
156
+ const initialStepIndex = findStepIndexByKey(initialStepKey, steps);
157
+ if (initialStepIndex === -1) {
158
+ const availableKeys = steps.map((s) => s.key).join(", ");
159
+ throw new Error(
160
+ `Stepper: initialStepKey "${initialStepKey}" no corresponde a ningún step. Keys disponibles: [${availableKeys}]`
161
+ );
162
+ }
163
+ const initialStep = steps[initialStepIndex];
164
+ if (!evaluateVisibilityStepCondition(initialStep, formData, visibilityData)) {
165
+ console.warn(
166
+ `Stepper: initialStepKey "${initialStepKey}" apunta a un step oculto. Iniciando en step 0.`
167
+ );
168
+ set((draft) => {
169
+ draft.initialStepKeyApplied = true;
170
+ });
171
+ return;
172
+ }
173
+ if (initialStepIndex === 0) {
174
+ set((draft) => {
175
+ draft.initialStepKeyApplied = true;
176
+ });
177
+ return;
178
+ }
179
+ const previousVisibleSteps = findAllVisibleStepsBefore(
180
+ initialStepIndex,
181
+ steps,
182
+ formData,
183
+ visibilityData
184
+ );
185
+ for (const { step, originalIndex } of previousVisibleSteps) {
186
+ const fieldsToValidate = step.validationFields || [];
187
+ if (fieldsToValidate.length === 0) {
188
+ set((draft) => {
189
+ draft.stepValidationStatus[originalIndex] = true;
190
+ });
191
+ continue;
192
+ }
193
+ const isValid = await validateFieldsFn(fieldsToValidate);
194
+ if (!isValid) {
195
+ set((draft) => {
196
+ draft.currentStep = originalIndex;
197
+ draft.stepValidationStatus[originalIndex] = false;
198
+ draft.initialStepKeyApplied = true;
199
+ });
200
+ return;
201
+ }
202
+ set((draft) => {
203
+ draft.stepValidationStatus[originalIndex] = true;
204
+ });
205
+ }
206
+ set((draft) => {
207
+ draft.currentStep = initialStepIndex;
208
+ draft.initialStepKeyApplied = true;
209
+ });
140
210
  }
141
211
  }
142
212
  })),
@@ -1,6 +1,6 @@
1
1
  import { ReactNode } from 'react';
2
2
  import { Step, StepperOwnerState, StepperProps } from '../types';
3
- export interface StepperState extends Pick<StepperProps, 'storeId' | 'visibleTitle' | 'steps' | 'indicatorType' | 'orientation' | 'size' | 'visibilityData'> {
3
+ export interface StepperState extends Pick<StepperProps, 'storeId' | 'visibleTitle' | 'steps' | 'indicatorType' | 'orientation' | 'size' | 'visibilityData' | 'initialStepKey'> {
4
4
  /**
5
5
  * "ownerState" estado a nivel de clases del componente
6
6
  */
@@ -18,6 +18,10 @@ export interface StepperState extends Pick<StepperProps, 'storeId' | 'visibleTit
18
18
  * "isValidating" indica si el stepper está en proceso de validación
19
19
  */
20
20
  isValidating: boolean;
21
+ /**
22
+ * Indica si initialStepKey ya fue aplicado. Previene re-aplicación después de navegación.
23
+ */
24
+ initialStepKeyApplied: boolean;
21
25
  }
22
26
  export interface StepperStateWithActions extends StepperState {
23
27
  actions: {
@@ -55,9 +59,15 @@ export interface StepperStateWithActions extends StepperState {
55
59
  * resetStepper - Resetea el Stepper a su estado inicial
56
60
  */
57
61
  resetStepper: () => void;
62
+ /**
63
+ * Aplica initialStepKey validando los steps anteriores.
64
+ * @param validateFieldsFn - Función que valida campos específicos usando RHF trigger()
65
+ * @param formData - Valores actuales del formulario
66
+ */
67
+ applyInitialStepKey: (validateFieldsFn: (fields: string[]) => Promise<boolean>, formData: Record<string, any>) => Promise<void>;
58
68
  };
59
69
  }
60
70
  export interface StepperContextProps extends StepperProps {
61
71
  children: ReactNode;
62
72
  }
63
- export type InitialStoreProps = Pick<StepperState, 'ownerState' | 'storeId' | 'steps' | 'visibleTitle' | 'indicatorType' | 'orientation' | 'visibilityData'>;
73
+ export type InitialStoreProps = Pick<StepperState, 'ownerState' | 'storeId' | 'steps' | 'visibleTitle' | 'indicatorType' | 'orientation' | 'visibilityData' | 'initialStepKey'>;
@@ -1,6 +1,7 @@
1
1
  import { jsxs, jsx } from "react/jsx-runtime";
2
2
  import { u as useStepper } from "../../hooks/useStepper/index.js";
3
- import { C as ContentAreaStyled, f as ContentAreaHeaderStyled, g as ContentAreaBodyStyled } from "../../slots/StepperSlot.js";
3
+ import { u as useInitialStepKey } from "../../hooks/useInitialStepKey/index.js";
4
+ import { C as ContentAreaStyled, g as ContentAreaHeaderStyled, h as ContentAreaBodyStyled } from "../../slots/StepperSlot.js";
4
5
  import { W as WrapperIcon } from "./subcomponents/WrapperIcon/index.js";
5
6
  import { W as WrapperTitle } from "./subcomponents/WrapperTitle/index.js";
6
7
  function ContentArea(props) {
@@ -8,6 +9,7 @@ function ContentArea(props) {
8
9
  const { orientation } = useStepper((state) => ({
9
10
  orientation: state.orientation
10
11
  }));
12
+ useInitialStepKey();
11
13
  const ownerState = {
12
14
  orientation
13
15
  };
@@ -1,6 +1,6 @@
1
1
  import { jsx } from "react/jsx-runtime";
2
2
  import { useMemo } from "react";
3
- import { W as WrapperIconStyled, c as IconStyled } from "../../../../slots/StepperSlot.js";
3
+ import { W as WrapperIconStyled, d as IconStyled } from "../../../../slots/StepperSlot.js";
4
4
  import { p as pathIcons } from "../../../../icons.js";
5
5
  import { u as useStepper } from "../../../../hooks/useStepper/index.js";
6
6
  import { useEnvironment } from "@m4l/core";
@@ -1,7 +1,7 @@
1
1
  import { jsxs, jsx } from "react/jsx-runtime";
2
2
  import { useMemo } from "react";
3
3
  import { u as useStepper } from "../../../../hooks/useStepper/index.js";
4
- import { d as WrapperTitleStyled, e as TitleStyled, D as DescriptionStyled } from "../../../../slots/StepperSlot.js";
4
+ import { e as WrapperTitleStyled, f as TitleStyled, D as DescriptionStyled } from "../../../../slots/StepperSlot.js";
5
5
  function WrapperTitle() {
6
6
  const { steps, currentStep } = useStepper((state) => ({
7
7
  steps: state.steps,
@@ -1,5 +1,5 @@
1
1
  import { jsx, jsxs } from "react/jsx-runtime";
2
- import { S as StepAreaStyled, a as StepStyled, b as StepNameStyled } from "../../slots/StepperSlot.js";
2
+ import { S as StepAreaStyled, a as StepStyled, b as StepNameStyled, c as StepNameTextStyled } from "../../slots/StepperSlot.js";
3
3
  import { I as Indicator } from "./subcomponents/Inidicator/index.js";
4
4
  import { u as useStepArea } from "./hooks/useStepArea.js";
5
5
  import { u as useVisibileSteps } from "./hooks/useVisibileSteps.js";
@@ -39,7 +39,7 @@ function StepArea() {
39
39
  originalStepIndex: originalIndex,
40
40
  isStepVisible
41
41
  },
42
- children: step.title
42
+ children: /* @__PURE__ */ jsx(StepNameTextStyled, { ownerState: { orientation }, children: step.title })
43
43
  }
44
44
  ),
45
45
  /* @__PURE__ */ jsx(
@@ -1,5 +1,5 @@
1
1
  import { jsx } from "react/jsx-runtime";
2
- import { k as StepContentStyled } from "../../../../slots/StepperSlot.js";
2
+ import { l as StepContentStyled } from "../../../../slots/StepperSlot.js";
3
3
  import { u as useIsStepVisible } from "./hooks/useIsStepVisible.js";
4
4
  function Step(props) {
5
5
  const { stepKey, children } = props;
@@ -1,6 +1,6 @@
1
1
  import { jsxs } from "react/jsx-runtime";
2
2
  import { useMemo, Children, isValidElement } from "react";
3
- import { j as StepperFooterSectionStyled } from "../../slots/StepperSlot.js";
3
+ import { k as StepperFooterSectionStyled } from "../../slots/StepperSlot.js";
4
4
  import { S as StepperFooterLeftActions } from "./subcomponents/StepperFooterLeftActions/index.js";
5
5
  import { S as StepperFooterRightActions } from "./subcomponents/StepperFooterRightActions/index.js";
6
6
  function StepperFooter(props) {
@@ -1,5 +1,5 @@
1
1
  import { jsx } from "react/jsx-runtime";
2
- import { h as StepperFooterLeftActionsStyled } from "../../../../slots/StepperSlot.js";
2
+ import { i as StepperFooterLeftActionsStyled } from "../../../../slots/StepperSlot.js";
3
3
  function StepperFooterLeftActions(props) {
4
4
  const { children } = props;
5
5
  return /* @__PURE__ */ jsx(StepperFooterLeftActionsStyled, { children });
@@ -1,7 +1,7 @@
1
1
  import { jsx, jsxs } from "react/jsx-runtime";
2
2
  import React, { useState, useEffect, useMemo } from "react";
3
3
  import { u as useIsLastVisibleValidStep } from "../../../../hooks/useIsLastVisibleValidStep/index.js";
4
- import { i as StepperFooterRightActionsStyled } from "../../../../slots/StepperSlot.js";
4
+ import { j as StepperFooterRightActionsStyled } from "../../../../slots/StepperSlot.js";
5
5
  import { S as StepperSubmitButton } from "../../../StepperButtons/StepperSubmitButton/index.js";
6
6
  import { S as StepperNextButton } from "../../../StepperButtons/StepperNextButton/index.js";
7
7
  function StepperFooterRightActions(props) {
@@ -83,6 +83,13 @@ export interface StepperProps {
83
83
  * Clase personalizada para el Stepper.
84
84
  */
85
85
  className?: string;
86
+ /**
87
+ * Key del step en el que se desea iniciar el Stepper.
88
+ * Si se proporciona, valida los steps anteriores antes de navegar al step indicado.
89
+ * Si algún step anterior tiene errores, inicia en el primer step con errores.
90
+ * Lanza Error si la key no corresponde a ningún step.
91
+ */
92
+ initialStepKey?: string;
86
93
  }
87
94
  /**
88
95
  * Props del StepperContent
@@ -172,5 +179,20 @@ export interface StepperOwnerState extends Pick<StepperProps, 'visibleTitle'>, R
172
179
  stepValidationStatus?: Record<number, boolean>;
173
180
  isStepVisible?: boolean;
174
181
  }
182
+ /**
183
+ * Representa un step junto con su posición original en el array de steps.
184
+ * Se usa para mantener la referencia al índice original después de filtrar steps ocultos.
185
+ */
186
+ export interface StepWithIndex {
187
+ /**
188
+ * El objeto Step con toda su configuración (key, title, validationFields, etc.)
189
+ */
190
+ step: Step;
191
+ /**
192
+ * El índice del step en el array original de steps.
193
+ * Es necesario para actualizar correctamente el stepValidationStatus del store.
194
+ */
195
+ originalIndex: number;
196
+ }
175
197
  export type StepperSlotsType = StepperSlots | ContentSlots | ContentAreaSlots | StepperFooterSlots;
176
198
  export type StepperStyles = M4LOverridesStyleRules<StepperSlotsType, typeof STEPPER_PREFIX_NAME, Theme>;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@m4l/components",
3
- "version": "9.4.25",
3
+ "version": "9.4.26",
4
4
  "license": "UNLICENSED",
5
5
  "description": "M4L Components",
6
6
  "lint-staged": {