-
Notifications
You must be signed in to change notification settings - Fork 5.2k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
feat(stepper): new stepper component #318
base: main
Are you sure you want to change the base?
Conversation
@damianricobelli is attempting to deploy a commit to the shadcn-pro Team on Vercel. A member of the Team first needs to authorize it. |
The latest updates on your projects. Learn more about Vercel for Git ↗︎
1 Ignored Deployment
|
love it 👀 |
This looks incredible @damianricobelli I'll review. |
Looks amazing 😍 Unfortunately I don't have time to review and research about this component. However, look what I recently found: https://saas-ui.dev/docs/components/navigation/stepper. This can serve as reference to improve or borrow ideas to simplify the implementation. From what I can suggest it is to rename Step to StepperStep and useSteps to useStepper to comply with the general API conventions of the components and it will be more unique name to prevent conflicts. |
Thank you very much for your feedback! I'll be reviewing tomorrow what you just shared and your suggestions 🫶 |
@shadcn What do you think about this component? Do you think we should adjust anything so that it can be launched on prod? |
Is this is still in progress? |
@destino92 From my side the component is ready. Just need to know if @shadcn agrees to move forward and add it to the CLI that brings and details that you think are missing in terms of documentation. |
This looks good! |
Hi @damianricobelli, this component looks very good. Could you please update it to the new version (different themes, registry, docs, etc.)? |
@dan5py yes of course. Between today and Monday I will be making the necessary changes so that the component allows the last addition you mention. |
@shadcn Could you check this? I've already updated the code with all the latest stuff in the main branch. There are already several people watching the release of this component 🤩 🚀 |
Done @dan5py! 🥳 |
I am cleaning up the branch to initialize the new changes with the final version using |
- Introduced a new UI component "stepper" with its dependencies and file path. - Added an example component "stepper-demo" that utilizes the "stepper". - Updated registry files to include both components in the respective JSON and TypeScript files.
@damianricobelli hi! It's looking awesome, thank you for your effort. Have you thought before about bind popstate event to this component? You know, some user would want to back to prev step when click to browser back button. |
Hey @damianricobelli and @resatyildiz, I think stepper component shouldn't get bind to routes internally. Instead, we should use a stepper in a controlled way and define routes for each step. When the routes change, pass the relevant step index or ID to the stepper. When the stepper goes to the next or previous step, update the route of the page. |
@ImanMahmoudinasab yea, you're right. The component should not handle anything related to routing. Also, it is much simpler to handle query params instead of routes for something like a stepper. |
Estimated date for review of the PR by the entire community and @shadcn -> tomorrow 👀 |
@ImanMahmoudinasab actually I agree with you. Already it can bind to window history with query params. You can think this feature @damianricobelli |
All documentation and component ready for review! @shadcn 👍 |
Agreed. I'm having quite a bit of difficulty with step control with the underlying stepperize library. Either external control or alternatively an My use case is a multi-step form where each step must be validated prior to allowing progression to later steps. I'm having a surprising amount of difficulty synchronizing this component with a zustand store. Right now I've resorted to manually implementing the "canPrevious", "canNext" logic in the zustand store, with a subscription to call the import { CardContent, CardFooter, CardHeader } from '@repo/ui/components/card'
import {
defineStepper,
Stepper,
StepperAction,
StepperControls,
StepperNavigation,
StepperPanel,
StepperStep,
StepperTitle,
} from '@repo/ui/components/stepper'
import { SellPassStepOne } from './sell-pass-step-one'
import { SellPassStepThree } from './sell-pass-step-three'
import { SellPassStepTwo } from './sell-pass-step-two'
import { sellProductStore, useSellProductStore } from './sell-product.store'
import { useEffect } from 'react'
const stepper = defineStepper(
{
id: 'step1',
title: 'Type',
header: 'Sell a Pass or Enforcement?',
Component: SellPassStepOne,
},
{
id: 'step2',
title: 'Customer',
header: 'Please enter the customer details',
Component: SellPassStepTwo,
},
{
id: 'step3',
title: 'Payment',
header: 'Please enter the payment details',
Component: SellPassStepThree,
},
)
export const SellForm = () => {
const s = stepper.useStepper()
const store = useSellProductStore()
const steps = s.all
useEffect(() => {
sellProductStore.subscribe((state) => {
s.goTo(state.stepId)
})
}, [s])
return (
<Stepper instance={stepper}>
<CardHeader>
<StepperNavigation>
{({ methods }) =>
steps.map((step) => {
return (
<StepperStep
key={step.id}
of={step}
disabled={!store.enabledSteps.includes(step.id)}
onClick={() => store.setStep(step.id)}
>
<StepperTitle>{step.title}</StepperTitle>
</StepperStep>
)
})
}
</StepperNavigation>
</CardHeader>
<CardContent>
{steps.map(({ Component, ...step }) => (
<StepperPanel key={step.id} when={step}>
<Component />
</StepperPanel>
))}
</CardContent>
<CardFooter>
<StepperControls className="flex justify-items-end w-full">
<StepperAction action="prev" disabled={!store.canPrev}>
Previous
</StepperAction>
<StepperAction action="next" disabled={!store.canNext}>
Next
</StepperAction>
<StepperAction action="reset" disabled={!store.canReset}>
Reset
</StepperAction>
</StepperControls>
</CardFooter>
</Stepper>
)
} |
@JoelVenable I have added in the PR an example of a form with react hook form. And I have updated a little the final logic of methods, where they are now obtained as part of the children of to maintain the typesafe API. Remember that the useStepper hook will work in these components if you use it within the Stepper component since it is a Provider. |
@JoelVenable @resatyildiz @ImanMahmoudinasab I have been thinking about this and have released version 4.2.0 of @stepperize/react which adds functions Check the docs here --> https://stepperize.vercel.app/docs/react/api-references/hook#beforeafter-functions |
Logic and updated examples to maintain two things:
cc: @shadcn |
Appreciate the new callback hooks; that's a big improvement to the API. Personally I went a different direction ("dumb" components fully controlled by the zustand store) so I no longer have skin in the game, but I think affordances to conditionally disable steps entirely would make a lot of sense. Then both the StepperAction and StepperStep components could be disabled based on a single source of truth. |
@JoelVenable Thanks for your comment! Please check the PR again as the examples and code have been simplified a bit. StepperAction is no longer necessary as it limits the DX a bit. Instead, the developer can be free to create their button logic. And to maintain the composition, we simply have a which has no functionality, just for composition purposes. As for the idea of disabling steps, I think I would leave that detail in the hands of the developer and not the component |
@damianricobelli Thank you for your amazing contribution. I have two questions?
|
Is it possible to call |
Hi! In this opportunity I present a new component: Stepper.
The idea of this in its beginnings was to make it as modular and flexible as possible for development.
A basic example of the application is this:
Here is a complete video of the different use cases:
Grabacion.de.pantalla.2023-05-08.a.la.s.13.14.45.mov