Skip to content

Commit

Permalink
Fix FormStepper compatibility and new onChange handler for Stepper
Browse files Browse the repository at this point in the history
  • Loading branch information
Pagebakers committed Jun 8, 2022
1 parent d74748e commit 9e9c601
Show file tree
Hide file tree
Showing 5 changed files with 75 additions and 36 deletions.
6 changes: 6 additions & 0 deletions .changeset/mighty-swans-check.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
---
'@saas-ui/react': patch
'@saas-ui/stepper': patch
---

Stepper now accepts an onChange handler.
15 changes: 11 additions & 4 deletions packages/saas-ui-forms/src/step-form.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -6,8 +6,8 @@ import {
chakra,
HTMLChakraProps,
useMultiStyleConfig,
StylesProvider,
SystemStyleObject,
createStylesContext,
} from '@chakra-ui/system'

import { callAllHandlers, runIfFn, cx, __DEV__ } from '@chakra-ui/utils'
Expand All @@ -18,6 +18,7 @@ import {
StepperStepsProps,
StepperStep,
useStepperContext,
StepperContainer,
} from '@saas-ui/stepper'
import { Button, ButtonProps } from '@saas-ui/button'

Expand All @@ -32,6 +33,8 @@ import {
UseStepFormReturn,
} from './use-step-form'

const [StylesProvider, useStyles] = createStylesContext('StepForm')

export interface StepFormProps<TFieldValues extends FieldValues = FieldValues>
extends UseStepFormProps<TFieldValues> {}

Expand Down Expand Up @@ -80,7 +83,7 @@ export interface FormStepOptions {
}

export const FormStepper: React.FC<StepperStepsProps> = (props) => {
const styles = useMultiStyleConfig('Stepper', props)
const { activeIndex, setIndex } = useStepperContext()

const { children } = props

Expand All @@ -100,12 +103,16 @@ export const FormStepper: React.FC<StepperStepsProps> = (props) => {
return child
})

const onChange = React.useCallback((name: string, i: number) => {
setIndex(i)
}, [])

return (
<StylesProvider value={styles}>
<StepperContainer step={activeIndex} onChange={onChange}>
<StepperSteps mb="4" {...props}>
{elements}
</StepperSteps>
</StylesProvider>
</StepperContainer>
)
}

Expand Down
2 changes: 1 addition & 1 deletion packages/saas-ui-forms/stories/step-form.stories.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -218,8 +218,8 @@ export const WithStepper = () => {
autoFocus
autoComplete="off"
/>
<StepperNav />
</FormLayout>
<StepperNav />
</FormStep>

<FormStep name="confirmation" title="Confirmation">
Expand Down
79 changes: 50 additions & 29 deletions packages/saas-ui-stepper/src/stepper.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,7 @@ const [StylesProvider, useStyles] = createStylesContext('Stepper')

export interface StepperProps
extends UseStepperProps,
HTMLChakraProps<'div'>,
Omit<HTMLChakraProps<'div'>, 'onChange'>,
ThemingProps<'Stepper'> {
orientation?: 'horizontal' | 'vertical'
}
Expand All @@ -40,42 +40,63 @@ export interface StepperProps
* Can be controlled or uncontrolled.
*/
export const Stepper = forwardRef<StepperProps, 'div'>((props, ref) => {
const { children, orientation = 'horizontal', step, ...rest } = props

const styles = useMultiStyleConfig('Stepper', {
...rest,
orientation,
})
const containerProps = omitThemingProps(rest)

const context = useStepper(props)

const containerStyles: SystemStyleObject = {
display: 'flex',
flexDirection: 'column',
...styles.container,
}

const { orientation, children, ...containerProps } = props
return (
<StylesProvider value={styles}>
<StepperProvider value={context}>
<chakra.div
ref={ref}
__css={containerStyles}
{...containerProps}
className={cx('saas-stepper', props.className)}
>
<StepperSteps orientation={orientation}>{children}</StepperSteps>
</chakra.div>
</StepperProvider>
</StylesProvider>
<StepperContainer ref={ref} orientation={orientation} {...containerProps}>
<StepperSteps orientation={orientation}>{children}</StepperSteps>
</StepperContainer>
)
})

if (__DEV__) {
Stepper.displayName = 'Stepper'
}

export const StepperContainer = forwardRef<StepperProps, 'div'>(
(props, ref) => {
const {
children,
orientation = 'horizontal',
step,
onChange,
...rest
} = props

const styles = useMultiStyleConfig('Stepper', {
...rest,
orientation,
})
const containerProps = omitThemingProps(rest)

const context = useStepper(props)

const containerStyles: SystemStyleObject = {
display: 'flex',
flexDirection: 'column',
...styles.container,
}

return (
<StylesProvider value={styles}>
<StepperProvider value={context}>
<chakra.div
ref={ref}
__css={containerStyles}
{...containerProps}
className={cx('saas-stepper', props.className)}
>
{children}
</chakra.div>
</StepperProvider>
</StylesProvider>
)
}
)

if (__DEV__) {
StepperContainer.displayName = 'StepperContainer'
}

export interface StepperStepsProps extends HTMLChakraProps<'div'> {
orientation?: 'horizontal' | 'vertical'
stepComponent?: React.JSXElementConstructor<any>
Expand Down
9 changes: 7 additions & 2 deletions packages/saas-ui-stepper/src/use-stepper.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -11,10 +11,12 @@ export const [StepperProvider, useStepperContext] =

export interface UseStepperProps {
step?: number | string
isCompleted?: boolean
onChange?(name: string, index: number): void
}

export function useStepper(props: UseStepperProps) {
const { step } = props
const { step, onChange } = props

const [activeIndex, setIndex] = React.useState(-1) // Set to -1 by default to prevent any initial transitions.

Expand Down Expand Up @@ -42,7 +44,6 @@ export function useStepper(props: UseStepperProps) {

const setStep = (name: string) => {
const i = stepsRef.current.indexOf(name)

if (i !== -1) {
setIndex(i)
}
Expand All @@ -66,6 +67,10 @@ export function useStepper(props: UseStepperProps) {
}
}, [step])

React.useEffect(() => {
onChange?.(stepsRef.current[activeIndex], activeIndex)
}, [activeIndex, onChange])

const context = {
stepsRef,
activeStep: stepsRef.current[activeIndex],
Expand Down

0 comments on commit 9e9c601

Please sign in to comment.