reactjs-multi-stepper 1.0.0 → 1.0.1

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.
package/dist/index.html DELETED
@@ -1,14 +0,0 @@
1
- <!doctype html>
2
- <html lang="en">
3
- <head>
4
- <meta charset="UTF-8" />
5
- <link rel="icon" type="image/svg+xml" href="/vite.svg" />
6
- <meta name="viewport" content="width=device-width, initial-scale=1.0" />
7
- <title>Vite + React + TS</title>
8
- <script type="module" crossorigin src="/assets/index-D0qN-L7R.js"></script>
9
- <link rel="stylesheet" crossorigin href="/assets/index-C_M5bBMw.css">
10
- </head>
11
- <body>
12
- <div id="root"></div>
13
- </body>
14
- </html>
@@ -1,23 +0,0 @@
1
- import React from 'react';
2
- import type { StepType } from './types';
3
- import { MultiStepperProvider } from './contexts';
4
- import { StepperHeader } from './components/StepperHeader';
5
- import { StepperFooter } from './components/StepperFooter';
6
- import { StepperContent } from './components/StepperContent';
7
-
8
- type StepperProps = {
9
- steps?: StepType[];
10
- }
11
-
12
- export const MultiStepper: React.FC<StepperProps> = ({
13
- steps,
14
- }) => {
15
- if (!steps) return <></>
16
- return (
17
- <MultiStepperProvider steppers={steps}>
18
- <StepperHeader />
19
- <StepperContent />
20
- <StepperFooter />
21
- </MultiStepperProvider>
22
- );
23
- };
@@ -1,16 +0,0 @@
1
- import React from 'react';
2
- import { useMultiStepper } from '../hooks';
3
-
4
-
5
- export const StepperContent: React.FC = () => {
6
- const { steps, currentStep } = useMultiStepper()
7
- return (
8
- <div className='w-full p-6 flex justify-center items-center'>
9
- {
10
- steps[currentStep] &&
11
- steps[currentStep].children &&
12
- steps[currentStep].children
13
- }
14
- </div>
15
- );
16
- };
@@ -1,31 +0,0 @@
1
- import React, { useMemo } from 'react';
2
- import { useMultiStepper } from '../hooks';
3
-
4
- export const StepperFooter: React.FC = () => {
5
- const { handleNextStep, handlePrevStep, currentStep, steps } = useMultiStepper();
6
- const isFinshed = currentStep === steps.length - 1
7
-
8
- const buttonClass = useMemo(() => ({
9
- button: ` px-8 py-1.5 text-md rounded-md border border-gray-400`,
10
- fill: ` border-blue-500 bg-blue-500 text-white`
11
- }), [])
12
-
13
- return (
14
- <div className='w-full flex justify-around items-center p-6'>
15
- {
16
- currentStep > 0 ?
17
- <button type="button"
18
- className={buttonClass.button}
19
- onClick={handlePrevStep} >Prev</button>
20
- : <div />
21
- }
22
- <button type="button"
23
- className={`${isFinshed ?
24
- buttonClass.button + buttonClass.fill :
25
- buttonClass.button} cursor-pointer`}
26
- onClick={handleNextStep}>
27
- {isFinshed ? `Finish` : `Next`}
28
- </button>
29
- </div>
30
- );
31
- };
@@ -1,35 +0,0 @@
1
- import React, { Fragment } from 'react';
2
- import { useMultiStepper } from '../hooks';
3
- import { Step } from './StepperIcon';
4
-
5
-
6
- export const StepperHeader: React.FC = () => {
7
- const { steps } = useMultiStepper()
8
-
9
- if (!steps.length) return <Fragment />
10
- return (
11
- <div className='app-container w-full'>
12
- <ol className='flex w-full justify-between'>
13
- {
14
- steps.map((step, i) => (
15
- <div
16
- key={i}
17
- className={`step-item ${step.active && "active"} ${step.completed && "complete"
18
- } `}
19
- >
20
-
21
- <Step index={i + 1} step={step} />
22
-
23
- <div className='text-center mt-4'>
24
- {step.title && <h3 className='text-md text-gray-900 font-medium mb-1'>{step.title}</h3>}
25
- {step.description && <h3 className='text-sm text-gray-600 font-light'>{step.description}</h3>}
26
- </div>
27
-
28
- </div>
29
- ))
30
- }
31
-
32
- </ol>
33
- </div>
34
- );
35
- };
@@ -1,51 +0,0 @@
1
- import React, { Fragment } from 'react';
2
- import { useMultiStepper } from '../hooks';
3
- import type { StepType } from '../types';
4
- import Icon from './icon';
5
- import Spinner from './spinner';
6
-
7
- type StepItemType = {
8
- step: StepType,
9
- index: number
10
- }
11
-
12
- export const Step: React.FC<StepItemType> = ({
13
- step, index
14
- }) => {
15
- const { steps } = useMultiStepper()
16
- if (!steps.length) return <Fragment />
17
-
18
- if (step.loading) return <div className='step step-active'>
19
- <Spinner />
20
- </div>
21
-
22
- if (step.error) return <div className='step bg-red-500'>
23
- <Icon name={"X"} className='text-white' />
24
- </div>
25
-
26
- if (step.completed) return <div className='step bg-green-500'>
27
- <Icon name={"Check"} className='text-white' />
28
- </div>
29
-
30
- if (step.finshed) return <div className='step bg-green-500'>
31
- <Icon name={"Check"} className='text-white' />
32
- </div>
33
-
34
- if (step.active) return <div className='step bg-blue-500'>
35
- {
36
- step.icon ?
37
- <Icon name={step.icon} className='text-white' />
38
- : <h2 className='text-white'>{index}</h2>
39
- }
40
-
41
- </div>
42
-
43
- return (
44
- <div className={`step border border-gray-300`}>
45
- {
46
- step.icon ? <Icon name={step.icon} className={`step-icon`} />
47
- : <h2>{index}</h2>
48
- }
49
- </div>
50
- );
51
- };
@@ -1,28 +0,0 @@
1
- // components/Icon.tsx
2
- import * as Icons from "lucide-react";
3
- import type { LucideProps } from "lucide-react";
4
-
5
- interface IconProps extends LucideProps {
6
- name: keyof typeof Icons;
7
- size?: number;
8
- color?: string;
9
- }
10
-
11
- const Icon = ({
12
- name,
13
- size = 20,
14
- color = "currentColor",
15
- ...props
16
- }: IconProps) => {
17
- const LucideIcon = Icons[name];
18
- if (
19
- typeof LucideIcon === "function" ||
20
- (LucideIcon && typeof LucideIcon === "object")
21
- ) {
22
- // @ts-expect-error: LucideIcon is a valid React component here
23
- return <LucideIcon size={size} color={color} {...props} />;
24
- }
25
- return null;
26
- };
27
-
28
- export default Icon;
@@ -1,36 +0,0 @@
1
- import React, { useMemo } from "react";
2
- import Icon from "./icon";
3
- // import { cn } from "@/lib/utils"; // or use 'clsx' if you prefer
4
-
5
- type SpinnerProps = {
6
- size?: "xs" | "sm" | "md" | "lg" | "xl" | number;
7
- className?: string;
8
- };
9
-
10
- const sizeMap: Record<string, string> = {
11
- xs: "w-2 h-2",
12
- sm: "w-4 h-4",
13
- md: "w-6 h-6",
14
- lg: "w-8 h-8",
15
- xl: "w-10 h-10",
16
- };
17
-
18
- const Spinner: React.FC<SpinnerProps> = ({ size = "md", className }) => {
19
- const sizeClass = useMemo(() => {
20
- return typeof size === "number"
21
- ? `w-[${size}px] h-[${size}px]`
22
- : sizeMap[size] || sizeMap["md"];
23
- }, [size]);
24
-
25
- return (
26
- <Icon
27
- name="Loader2Icon"
28
- aria-label="Loading"
29
- role="status"
30
- // className={cn("animate-spin text-muted", sizeClass, className)}
31
- className={sizeClass+className}
32
- />
33
- );
34
- };
35
-
36
- export default React.memo(Spinner);
@@ -1,78 +0,0 @@
1
- import { useCallback, useEffect, useMemo, useState } from "react";
2
- import type { MultiStepperProviderType, StepType } from '../types';
3
- import { MultiStepperContext } from "../hooks";
4
-
5
- export const MultiStepperProvider: React.FC<MultiStepperProviderType> = ({ children, steppers }) => {
6
-
7
- const [currentStep, setCurrentStep] = useState(0)
8
- const [steps, setSteps] = useState<StepType[]>([])
9
-
10
- useEffect(() => {
11
- if(steppers.length){
12
- const temp = [...steppers]
13
- temp[0].active = true
14
- setSteps(temp)
15
- }
16
- }, [steppers.length])
17
-
18
- const updateSteps = useCallback((newStep: number) => {
19
- setSteps((prev) => {
20
- const updated = [...prev]
21
-
22
- // if more than length of steps array return steps array as its
23
- if (newStep > prev.length - 1) return prev
24
-
25
- // deactivate current step
26
- if (updated[currentStep])
27
- updated[currentStep] = { ...updated[currentStep], active: false }
28
-
29
- // activate new step
30
- if (updated[newStep])
31
- updated[newStep] = { ...updated[newStep], active: true }
32
-
33
- // mark prev steps as completed
34
- for (let i = 0; i < newStep; i++) {
35
- updated[i] = { ...updated[i], completed: true }
36
- }
37
-
38
- // mark future steps as incompleted
39
- for (let i = newStep; i < updated.length; i++) {
40
- updated[i] = { ...updated[i], completed: false }
41
- }
42
-
43
- return updated
44
- })
45
- setCurrentStep(newStep)
46
- }, [currentStep])
47
-
48
- const handleNextStep = useCallback(() => {
49
- if (currentStep < steps.length -1) updateSteps(currentStep + 1)
50
- else setSteps((prev) => {
51
- const updated = [...prev]
52
- updated[currentStep] = { ...updated[currentStep], completed: true }
53
- return updated
54
- })
55
- }, [currentStep, steps.length, updateSteps])
56
-
57
-
58
-
59
- const handlePrevStep = useCallback(() => {
60
- if (currentStep > 0) updateSteps(currentStep-1)
61
- }, [currentStep, updateSteps])
62
-
63
- // ⚡️ Memoize the entire context value
64
- const contextValue = useMemo(
65
- () => ({
66
- currentStep,
67
- steps,
68
- handleNextStep,
69
- handlePrevStep,
70
- updateSteps,
71
- }),
72
- [currentStep, steps, handleNextStep, handlePrevStep, updateSteps]
73
- );
74
-
75
- return <MultiStepperContext.Provider value={contextValue}>
76
- {children}
77
- </MultiStepperContext.Provider>
78
- }
@@ -1,17 +0,0 @@
1
- import { createContext, useContext } from "react";
2
- import type { MultiStepperType } from "../types";
3
-
4
- // Multi stepper context
5
- export const MultiStepperContext = createContext<MultiStepperType | undefined>(
6
- undefined
7
- );
8
-
9
- // context consumer hook
10
- export const useMultiStepper = () => {
11
- const context = useContext(MultiStepperContext);
12
- if (!context)
13
- throw new Error(
14
- "useMultiStepperForm must be used within a MultiStepperProvider"
15
- );
16
- return context;
17
- };
package/src/index.css DELETED
@@ -1,27 +0,0 @@
1
- @import "tailwindcss";
2
-
3
- .app-container{
4
- @apply p-6
5
- }
6
-
7
- .step-item {
8
- @apply relative flex flex-col justify-center items-center w-full;
9
- }
10
- .step-item:not(:first-child):before {
11
- @apply content-[''] bg-slate-200 absolute w-[calc(100%-2.5rem)] h-[3px] right-[calc(50%+1.25rem)] top-4.5
12
- transition-all duration-200;
13
- }
14
- .step {
15
- @apply w-10 h-10 flex items-center justify-center z-10 relative rounded-full font-semibold text-black
16
- transition-all duration-200;
17
- }
18
- .active .step {
19
- @apply bg-sky-600;
20
- }
21
- .complete .step {
22
- @apply bg-green-600;
23
- }
24
- .complete:not(:first-child):before,
25
- .active:not(:first-child):before {
26
- @apply bg-green-600;
27
- }
package/src/main.tsx DELETED
@@ -1,10 +0,0 @@
1
- import { StrictMode } from 'react'
2
- import { createRoot } from 'react-dom/client'
3
- import './index.css'
4
- import { MultiStepper } from './MultiStepper.tsx'
5
-
6
- createRoot(document.getElementById('root')!).render(
7
- <StrictMode>
8
- <MultiStepper />
9
- </StrictMode>,
10
- )
@@ -1,35 +0,0 @@
1
- import type { ReactNode } from "react";
2
- import * as Icons from "lucide-react";
3
- type StepType = {
4
- id?: number;
5
- title?: string;
6
- description?: string;
7
- icon?: keyof typeof Icons;
8
- active?: boolean;
9
- finshed?:boolean;
10
- error?:boolean;
11
- loading?:boolean;
12
- completed?: boolean;
13
- children?: ReactNode
14
- }
15
-
16
- type StepStyleType = {
17
- activeBgColor?: string;
18
- activeTextColor?: string;
19
- completedBgColor?: string;
20
- completedTextColor?: string
21
- }
22
-
23
- type MultiStepperType = {
24
- currentStep: number;
25
- steps: StepType[];
26
- handleNextStep: () => void;
27
- handlePrevStep: () => void;
28
- updateSteps: (newStep: number) => void;
29
- }
30
-
31
- type MultiStepperProviderType = {
32
- children: ReactNode;
33
- steppers: StepType[]
34
- }
35
- export type { StepStyleType, StepType, MultiStepperType, MultiStepperProviderType }
package/src/vite-env.d.ts DELETED
@@ -1 +0,0 @@
1
- /// <reference types="vite/client" />
package/tsconfig.json DELETED
@@ -1,13 +0,0 @@
1
- {
2
- "files": [],
3
- "references": [
4
- { "path": "./tsconfig.app.json" },
5
- { "path": "./tsconfig.node.json" }
6
- ],
7
- "compilerOptions": {
8
- "baseUrl": ".",
9
- "paths": {
10
- "@/*": ["./src/*"]
11
- }
12
- },
13
- }