Skip to content

Commit 4eaf4d6

Browse files
authored
Merge pull request #128 from buildo/3692848-implement_stepper
#3692848: Implement Stepper
2 parents cb0ad63 + 12476f6 commit 4eaf4d6

File tree

10 files changed

+169
-13
lines changed

10 files changed

+169
-13
lines changed

packages/bento-design-system/src/Icons/IconCheckCircleSolid.tsx

-10
This file was deleted.
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
import { IconProps } from "./IconProps";
2+
import { svgIconProps } from "./svgIconProps";
3+
4+
export function IconPositive(props: IconProps) {
5+
return (
6+
<svg {...svgIconProps(props)}>
7+
<path
8+
fillRule="evenodd"
9+
clipRule="evenodd"
10+
d="M12 24a12 12 0 1 0 0-24 12 12 0 0 0 0 24Zm5.56-13.94a1.5 1.5 0 0 0-2.12-2.12l-4.94 4.939-1.94-1.94a1.5 1.5 0 0 0-2.12 2.121l3 3a1.5 1.5 0 0 0 2.12 0l6-6Z"
11+
/>
12+
</svg>
13+
);
14+
}

packages/bento-design-system/src/Icons/index.ts

+1-1
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,4 @@
11
export * from "./IconCheck";
2-
export * from "./IconCheckCircleSolid";
32
export * from "./IconChevronDown";
43
export * from "./IconChevronRight";
54
export * from "./IconChevronUp";
@@ -9,6 +8,7 @@ export * from "./IconInformative";
98
export * from "./IconMinus";
109
export * from "./IconNegative";
1110
export * from "./IconPlaceholder";
11+
export * from "./IconPositive";
1212
export * from "./IconProps";
1313
export * from "./IconSearch";
1414
export * from "./IconUser";
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
import { FunctionComponent } from "react";
2+
import { IconProps } from "../Icons";
3+
import { BentoSprinkles } from "../internal";
4+
import { LabelProps } from "../Typography/Label/Label";
5+
6+
export type StepperConfig = {
7+
spaceBetweenSteps: BentoSprinkles["gap"];
8+
internalSpacing: BentoSprinkles["gap"];
9+
labelSize: LabelProps["size"];
10+
numberSize: LabelProps["size"];
11+
labelUppercase: boolean;
12+
doneIcon: FunctionComponent<IconProps>;
13+
};
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,44 @@
1+
import { bentoSprinkles } from "../internal";
2+
import { strictRecipe } from "../util/strictRecipe";
3+
4+
export const stepRecipe = strictRecipe({
5+
variants: {
6+
status: {
7+
todo: bentoSprinkles({
8+
color: "textSecondary",
9+
}),
10+
inProgress: bentoSprinkles({
11+
color: "textInteractive",
12+
}),
13+
done: bentoSprinkles({
14+
color: "textSecondary",
15+
}),
16+
},
17+
},
18+
});
19+
20+
export const stepIconRecipe = strictRecipe({
21+
base: bentoSprinkles({
22+
display: "flex",
23+
alignItems: "center",
24+
justifyContent: "center",
25+
width: 24,
26+
height: 24,
27+
borderRadius: "circled",
28+
}),
29+
variants: {
30+
status: {
31+
todo: bentoSprinkles({
32+
background: "backgroundOverlay",
33+
color: "textSecondary",
34+
}),
35+
inProgress: bentoSprinkles({
36+
color: "textPrimaryInverse",
37+
background: "backgroundInteractive",
38+
}),
39+
done: bentoSprinkles({
40+
color: "foregroundSecondary",
41+
}),
42+
},
43+
},
44+
});
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,62 @@
1+
import { Box, Inline } from "../internal";
2+
import { Label, LocalizedString, unsafeLocalizedString } from "..";
3+
import { stepIconRecipe, stepRecipe } from "./Stepper.css";
4+
import { StepperConfig } from "./Config";
5+
6+
type Step = {
7+
label: LocalizedString;
8+
};
9+
10+
type Props = {
11+
currentStep: number;
12+
steps: Array<Step>;
13+
};
14+
15+
type StepStatus = "todo" | "inProgress" | "done";
16+
17+
export function createStepper(config: StepperConfig) {
18+
return function Stepper({ currentStep, steps }: Props) {
19+
return (
20+
<Inline space={config.spaceBetweenSteps} alignY="center">
21+
{steps.map(({ label }, index) => {
22+
const status =
23+
index < currentStep ? "done" : index === currentStep ? "inProgress" : "todo";
24+
return <Step label={label} index={index} status={status} key={label} />;
25+
})}
26+
</Inline>
27+
);
28+
};
29+
30+
function Step({
31+
label,
32+
index,
33+
status,
34+
}: {
35+
label: LocalizedString;
36+
index: number;
37+
status: StepStatus;
38+
}) {
39+
return (
40+
<Box className={stepRecipe({ status })}>
41+
<Inline space={config.internalSpacing} alignY="center">
42+
<StepIcon status={status} index={index} />
43+
<Label size={config.labelSize} uppercase={config.labelUppercase}>
44+
{label}
45+
</Label>
46+
</Inline>
47+
</Box>
48+
);
49+
}
50+
51+
function StepIcon({ status, index }: { status: StepStatus; index: number }) {
52+
return (
53+
<Box className={stepIconRecipe({ status })}>
54+
{status === "done" ? (
55+
config.doneIcon({ size: 24 })
56+
) : (
57+
<Label size={config.numberSize}>{unsafeLocalizedString(index + 1)}</Label>
58+
)}
59+
</Box>
60+
);
61+
}
62+
}

packages/bento-design-system/src/index.ts

+1
Original file line numberDiff line numberDiff line change
@@ -39,6 +39,7 @@ export * from "./Placeholder/Placeholder";
3939
export * from "./Popover/Popover";
4040
export * from "./ProgressBar/createProgressBar";
4141
export * from "./SearchBar/createSearchBar";
42+
export * from "./Stepper/createStepper";
4243
export * from "./Switch/createSwitch";
4344
export * from "./Table/createTable";
4445
export * from "./Tabs/createTabs";

packages/bento-design-system/src/util/defaultConfigs.tsx

+12-2
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@ import { AvatarConfig } from "../Avatar/Config";
44
import { BannerConfig } from "../Banner/Config";
55
import { BreadcrumbConfig } from "../Breadcrumb/Config";
66
import {
7-
IconCheckCircleSolid,
7+
IconPositive,
88
IconChevronRight,
99
IconClose,
1010
IconIdea,
@@ -41,6 +41,7 @@ import { TableConfig } from "../Table/Config";
4141
import { TabsConfig } from "../Tabs/Config";
4242
import { ToastConfig } from "../Toast/Config";
4343
import { ProgressBarConfig } from "../ProgressBar/Config";
44+
import { StepperConfig } from "../Stepper/Config";
4445

4546
export const actions: ActionsConfig = {
4647
buttonsAlignment: "right",
@@ -71,7 +72,7 @@ export const banner: BannerConfig = {
7172
closeIcon: IconClose,
7273
kindIcons: {
7374
informative: IconInformative,
74-
positive: IconCheckCircleSolid,
75+
positive: IconPositive,
7576
warning: IconWarning,
7677
negative: IconNegative,
7778
secondary: IconIdea,
@@ -415,3 +416,12 @@ export const progressBar: ProgressBarConfig = {
415416
radius: "circledX",
416417
discreteInternalSpacing: 8,
417418
};
419+
420+
export const stepper: StepperConfig = {
421+
spaceBetweenSteps: 40,
422+
internalSpacing: 8,
423+
labelSize: "large",
424+
numberSize: "large",
425+
labelUppercase: false,
426+
doneIcon: IconPositive,
427+
};
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,20 @@
1+
import { Stepper } from "../";
2+
import { createComponentStories, formatMessage } from "../util";
3+
4+
const { defaultExport, createStory } = createComponentStories({
5+
component: Stepper,
6+
args: {},
7+
});
8+
9+
export default defaultExport;
10+
11+
export const stepper = createStory({
12+
currentStep: 2,
13+
steps: [
14+
{ label: formatMessage("Step 1") },
15+
{ label: formatMessage("Step 2") },
16+
{ label: formatMessage("Step 3") },
17+
{ label: formatMessage("Step 4") },
18+
{ label: formatMessage("Step 5") },
19+
],
20+
});

packages/storybook/stories/index.tsx

+2
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,7 @@ import {
2121
createAvatar,
2222
createFormLayoutComponents,
2323
createSearchBar,
24+
createStepper,
2425
createSwitch,
2526
createFeedback,
2627
IllustrationNegative,
@@ -135,3 +136,4 @@ export const tableColumn = createTableColumns({ Button, ButtonLink, Chip, Link,
135136
export const Navigation = createNavigation(defaultConfigs.navigation);
136137
export const Menu = createMenu(defaultConfigs.menu, { List });
137138
export const ProgressBar = createProgressBar(defaultConfigs.progressBar);
139+
export const Stepper = createStepper(defaultConfigs.stepper);

0 commit comments

Comments
 (0)