11import * as React from "react" ;
22
3+ type BeforeNextGuard = ( ) => boolean | Promise < boolean > ;
4+
35interface IStepsContext {
46 current : number ;
57 setCurrent : React . Dispatch < React . SetStateAction < number > > ;
68 size : number ;
79 setSize : React . Dispatch < React . SetStateAction < number > > ;
10+ beforeNextRef : React . MutableRefObject < BeforeNextGuard | undefined > ;
811 isLast : boolean ;
912 isFirst : boolean ;
1013 hasPrev : boolean ;
1114 hasNext : boolean ;
1215 progress : number ;
13- next : ( ) => void ;
16+ next : ( ) => Promise < boolean > ;
1417 prev : ( ) => void ;
1518 jump : ( step : number ) => void ;
1619 reset : ( ) => void ;
1720}
1821
22+ const noop = ( ) => { } ;
23+ const noopRef = { current : undefined } as React . MutableRefObject <
24+ BeforeNextGuard | undefined
25+ > ;
26+
1927const StepsContext = React . createContext < IStepsContext > ( {
2028 current : 1 ,
21- setCurrent : ( ) => { } ,
29+ setCurrent : noop ,
2230 size : 0 ,
23- setSize : ( ) => { } ,
31+ setSize : noop ,
32+ beforeNextRef : noopRef ,
2433 isLast : false ,
2534 isFirst : false ,
2635 hasPrev : false ,
2736 hasNext : false ,
2837 progress : 0 ,
29- next : ( ) => { } ,
30- prev : ( ) => { } ,
31- jump : ( ) => { } ,
32- reset : ( ) => { } ,
38+ next : ( ) => Promise . resolve ( false ) ,
39+ prev : noop ,
40+ jump : noop ,
41+ reset : noop ,
3342} ) ;
3443
3544export const StepsProvider : React . FC < React . PropsWithChildren > = ( {
3645 children,
3746} ) => {
3847 const [ current , setCurrent ] = React . useState ( 1 ) ;
3948 const [ size , setSize ] = React . useState ( 0 ) ;
49+ const beforeNextRef = React . useRef < BeforeNextGuard | undefined > ( undefined ) ;
4050
41- const next = ( ) => {
51+ const next = async ( ) => {
52+ const guard = beforeNextRef . current ;
53+ if ( guard ) {
54+ const allowed = await guard ( ) ;
55+ if ( ! allowed ) return false ;
56+ }
4257 const nextStep = current + 1 ;
43- nextStep <= size && setCurrent ( nextStep ) ;
58+ if ( nextStep <= size ) {
59+ setCurrent ( nextStep ) ;
60+ return true ;
61+ }
62+ return false ;
4463 } ;
4564
4665 const prev = ( ) => {
@@ -68,6 +87,7 @@ export const StepsProvider: React.FC<React.PropsWithChildren> = ({
6887 setCurrent,
6988 size,
7089 setSize,
90+ beforeNextRef,
7191 isLast,
7292 isFirst,
7393 hasPrev,
@@ -94,15 +114,21 @@ export interface StepChangeContext {
94114export interface StepsProps {
95115 children : React . ReactNode ;
96116 onStepChange ?: ( context ?: StepChangeContext ) => void ;
117+ beforeNext ?: BeforeNextGuard ;
97118 startsFrom ?: number ;
98119}
99120
100121export const Steps : React . FC < StepsProps > = ( props ) => {
101122 const stepsContext = React . useContext ( StepsContext ) ;
102- const { current, setCurrent, setSize } = stepsContext ;
123+ const { current, setCurrent, setSize, beforeNextRef } = stepsContext ;
103124 const [ isInitialRender , setIsInitialRender ] = React . useState ( true ) ;
104125 const prevStepRef = React . useRef ( current ) ;
105126
127+ // Register the beforeNext guard into context
128+ React . useEffect ( ( ) => {
129+ beforeNextRef . current = props . beforeNext ;
130+ } , [ props . beforeNext ] ) ;
131+
106132 React . useEffect ( ( ) => {
107133 setIsInitialRender ( false ) ;
108134 const { startsFrom = 1 } = props ;
0 commit comments