Skip to content

Commit

Permalink
Merge pull request #205 from reaviz/stepper
Browse files Browse the repository at this point in the history
Stepper
  • Loading branch information
amcdnl authored May 21, 2024
2 parents 32bff68 + 81a9f6d commit ad29aec
Show file tree
Hide file tree
Showing 7 changed files with 390 additions and 3 deletions.
17 changes: 17 additions & 0 deletions src/layout/Stepper/Step.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
import React, { FC, PropsWithChildren } from 'react';

export interface StepProps extends PropsWithChildren {
/**
* Optional Text of the marker
*/
markerLabel?: string;

/**
* CSS Classname to applied to the step
*/
className?: string;
}

export const Step: FC<StepProps> = ({ children, className }) => (
<div className={className}>{children}</div>
);
231 changes: 231 additions & 0 deletions src/layout/Stepper/Stepper.story.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,231 @@
import { Stepper } from './Stepper';
import { Step } from './Step';

export default {
title: 'Components/Layout/Stepper',
component: Stepper
};

export const Markers = () => (
<Stepper activeStep={2}>
<Step>
<div className="flex flex-col gap-1">
<span className="text-sm text-gray-400 light:text-gray-600">
03/01/2024, 8:00 AM
</span>
<span>
Austin{' '}
<span className="text-gray-400 light:text-gray-600">
created ticket
</span>
</span>
</div>
</Step>
<Step>
<div className="flex flex-col gap-1">
<span className="text-sm text-gray-400 light:text-gray-600">
03/01/2024, 8:00 AM
</span>
<span>
Austin
<span className="text-gray-400 light:text-gray-600">
{' '}
changed statues from{' '}
</span>
Backlog
<span className="text-gray-400 light:text-gray-600"> to </span>In
Progress
</span>
<div className="px-4 py-2 border border-solid border-blue-700 bg-surface rounded-md">
This looks fine, might've missed it but maybe we can add a link to the
website where we also have the video of how to use the plug in?
Otherwise this is a nice addition.
</div>
</div>
</Step>
<Step>
<div className="flex flex-col gap-1">
<span className="text-sm text-gray-400 light:text-gray-600">
03/01/2024, 8:00 AM
</span>
<span>
Austin
<span className="text-gray-400 light:text-gray-600">
{' '}
changed statues from{' '}
</span>
In Progress
<span className="text-gray-400 light:text-gray-600"> to </span>Done
</span>
</div>
</Step>
</Stepper>
);

export const Numbered = () => (
<Stepper numbered activeStep={2}>
<Step>
<div className="flex flex-col gap-1">
<span className="text-sm text-gray-400 light:text-gray-600">
03/01/2024, 8:00 AM
</span>
<span>
Austin{' '}
<span className="text-gray-400 light:text-gray-600">
created ticket
</span>
</span>
</div>
</Step>
<Step>
<div className="flex flex-col gap-1">
<span className="text-sm text-gray-400 light:text-gray-600">
03/01/2024, 8:00 AM
</span>
<span>
Austin
<span className="text-gray-400 light:text-gray-600">
{' '}
changed statues from{' '}
</span>
Backlog
<span className="text-gray-400 light:text-gray-600"> to </span>In
Progress
</span>
<div className="px-4 py-2 border border-solid border-blue-700 bg-surface rounded-md">
This looks fine, might've missed it but maybe we can add a link to the
website where we also have the video of how to use the plug in?
Otherwise this is a nice addition.
</div>
</div>
</Step>
<Step>
<div className="flex flex-col gap-1">
<span className="text-sm text-gray-400 light:text-gray-600">
03/01/2024, 8:00 AM
</span>
<span>
Austin
<span className="text-gray-400 light:text-gray-600">
{' '}
changed statues from{' '}
</span>
In Progress
<span className="text-gray-400 light:text-gray-600"> to </span>Done
</span>
</div>
</Step>
</Stepper>
);

export const Labels = () => (
<Stepper>
<Step markerLabel="v6.8">
<div className="flex flex-col gap-1">
<span className="text-sm text-gray-400 light:text-gray-600">
03/01/2024, 8:00 AM
</span>
<span>
Austin{' '}
<span className="text-gray-400 light:text-gray-600">
created ticket
</span>
</span>
</div>
</Step>
<Step markerLabel="v6.9">
<div className="flex flex-col gap-1">
<span className="text-sm text-gray-400 light:text-gray-600">
03/01/2024, 8:00 AM
</span>
<span>
Austin
<span className="text-gray-400 light:text-gray-600">
{' '}
changed statues from{' '}
</span>
Backlog
<span className="text-gray-400 light:text-gray-600"> to </span>In
Progress
</span>
<div className="px-4 py-2 border border-solid border-blue-700 bg-surface rounded-md">
This looks fine, might've missed it but maybe we can add a link to the
website where we also have the video of how to use the plug in?
Otherwise this is a nice addition.
</div>
</div>
</Step>
<Step markerLabel="v7.0">
<div className="flex flex-col gap-1">
<span className="text-sm text-gray-400 light:text-gray-600">
03/01/2024, 8:00 AM
</span>
<span>
Austin
<span className="text-gray-400 light:text-gray-600">
{' '}
changed statues from{' '}
</span>
In Progress
<span className="text-gray-400 light:text-gray-600"> to </span>Done
</span>
</div>
</Step>
</Stepper>
);

export const Mixed = () => (
<Stepper activeStep={3}>
<Step markerLabel="v6.8">
<div className="flex flex-col gap-1">
<span className="text-sm text-gray-400 light:text-gray-600">
03/01/2024, 8:00 AM
</span>
<span>
Austin{' '}
<span className="text-gray-400 light:text-gray-600">
created ticket
</span>
</span>
</div>
</Step>
<Step>
<div className="flex flex-col gap-1">
<span className="text-sm text-gray-400 light:text-gray-600">
03/01/2024, 8:00 AM
</span>
<span>
Austin
<span className="text-gray-400 light:text-gray-600">
{' '}
changed statues from{' '}
</span>
Backlog
<span className="text-gray-400 light:text-gray-600"> to </span>In
Progress
</span>
<div className="px-4 py-2 border border-solid border-blue-700 bg-surface rounded-md">
This looks fine, might've missed it but maybe we can add a link to the
website where we also have the video of how to use the plug in?
Otherwise this is a nice addition.
</div>
</div>
</Step>
<Step markerLabel="v7.0">
<div className="flex flex-col gap-1">
<span className="text-sm text-gray-400 light:text-gray-600">
03/01/2024, 8:00 AM
</span>
<span>
Austin
<span className="text-gray-400 light:text-gray-600">
{' '}
changed statues from{' '}
</span>
In Progress
<span className="text-gray-400 light:text-gray-600"> to </span>Done
</span>
</div>
</Step>
</Stepper>
);
92 changes: 92 additions & 0 deletions src/layout/Stepper/Stepper.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,92 @@
import { StepperTheme } from '@/layout';
import { cn, useComponentTheme } from '@/utils';
import React, { Children, FC, Fragment, PropsWithChildren } from 'react';

import { Step, StepProps } from './Step';

export interface StepperProps extends PropsWithChildren {
/**
* Currently active step
*/
activeStep?: number;

/**
* Theme for the Stepper.
*/
theme?: StepperTheme;

/**
* Show number for every step
*/
numbered?: boolean;
}

export const Stepper: FC<StepperProps> = ({
activeStep = 0,
children,
numbered = false,
theme: customTheme
}) => {
const theme: StepperTheme = useComponentTheme('stepper', customTheme);

const childrenStepProps = Children.toArray(children)
.filter((child: any) => child.type?.name === Step.name)
.map((child: any) => child.props);

const totalSteps = childrenStepProps.length - 1;

return (
<div className={theme.base}>
{childrenStepProps.map((props: StepProps, index) => (
<Fragment key={index}>
<div
className={cn(theme.step.base, {
'border-transparent': index === totalSteps,
[theme.step.active]: index < activeStep - 1
})}
>
<div className={theme.step.marker.container}>
{/* Numbered marker */}
{numbered && (
<div
className={cn(theme.step.marker.label.base, {
[theme.step.marker.label.active]: index < activeStep
})}
>
{index + 1}
</div>
)}
{/* Labeled marker */}
{!numbered && props.markerLabel && (
<div
className={cn(theme.step.marker.label.base, {
[theme.step.marker.label.active]: index < activeStep
})}
>
<div
className={cn(theme.step.marker.base, {
[theme.step.marker.active]: index < activeStep
})}
/>
{props.markerLabel}
</div>
)}
{/* Dot marker */}
{!numbered && !props.markerLabel && (
<div
className={cn(theme.step.marker.base, {
[theme.step.marker.active]: index < activeStep
})}
/>
)}
</div>
</div>
<Step
className={cn(theme.step.content, props.className)}
{...props}
/>
</Fragment>
))}
</div>
);
};
38 changes: 38 additions & 0 deletions src/layout/Stepper/StepperTheme.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
export interface StepperTheme {
base: string;
step: {
base: string;
marker: {
container: string;
base: string;
active: string;
label: {
base: string;
active: string;
};
};
active: string;
content: string;
};
}

export const stepperTheme: StepperTheme = {
base: 'grid grid-cols-[min-content_1fr] gap-x-3',
step: {
base: 'border-l border-solid border-panel-accent translate-x-1/2',
marker: {
base: 'rounded-full w-[9px] h-[9px] bg-surface',
container:
'w-max pt-1 pb-0.5 backdrop-blur-md -translate-x-[calc(50%+0.5px)]',
active: 'bg-info',
label: {
base: 'flex flex-row items-center gap-1 border border-solid border-surface px-3 py-1 rounded-[20px]',
active: 'border-info bg-info-background'
}
},
active: 'border-primary',
content: 'pb-6'
}
};

export const legacyStepperTheme: StepperTheme = stepperTheme;
2 changes: 2 additions & 0 deletions src/layout/Stepper/index.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
export * from './Stepper';
export * from './StepperTheme';
1 change: 1 addition & 0 deletions src/layout/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -9,3 +9,4 @@ export * from './Tree';
export * from './VerticalSpacer';
export * from './Tabs';
export * from './Breadcrumbs';
export * from './Stepper';
Loading

0 comments on commit ad29aec

Please sign in to comment.