-
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! 🥳 |
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 |
|
@merodiro will be stable since you cannot modify the type at runtime. If you need to modify it, you should add some state that stores metadata and can be modified. I would like to be able to work on an idea of dynamic metadata without being typesafe in the future to solve this |
@damianricobelli I'm trying to change the metadata dynamically for example changing the title based on the locale or changing something in the schema based on data from the server. Can I change them dynamically or do I need to call |
@merodiro if you need to change texts according to locale and you are using a library for this, I recommend using the keys of the terms instead of the text in each of your steps |
@stepperize/react v5 is out! Dynamic data with the new Metadata API 🔥 cc: @merodiro |
I think this design can help you if you need it...https://www.figma.com/design/EaDyK1l09bi7mxaSl5stv4/Untitled?node-id=0-1&p=f&t=dG2WqjbwIsXssRio-0 |
@damianricobelli Thanks for your work on this. I'll review and make an official component once I'm done with the Tailwind v4 upgrade. |
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