From 5abfc004f5476944494edc86e8a7e9a4b23af4c4 Mon Sep 17 00:00:00 2001 From: RabbitDoge <72658581+RabbitDoge@users.noreply.github.com> Date: Wed, 31 Mar 2021 12:08:45 +0900 Subject: [PATCH] feat: Stepper --- .../src/components/Spinner/index.stories.tsx | 2 +- .../src/components/Stepper/Step.tsx | 90 ++++++++++++++++++ .../src/components/Stepper/Stepper.tsx | 25 +++++ .../src/components/Stepper/index.stories.tsx | 91 +++++++++++++++++++ .../src/components/Stepper/index.ts | 3 + .../src/components/Stepper/types.ts | 18 ++++ 6 files changed, 228 insertions(+), 1 deletion(-) create mode 100644 packages/pancake-uikit/src/components/Stepper/Step.tsx create mode 100644 packages/pancake-uikit/src/components/Stepper/Stepper.tsx create mode 100644 packages/pancake-uikit/src/components/Stepper/index.stories.tsx create mode 100644 packages/pancake-uikit/src/components/Stepper/index.ts create mode 100644 packages/pancake-uikit/src/components/Stepper/types.ts diff --git a/packages/pancake-uikit/src/components/Spinner/index.stories.tsx b/packages/pancake-uikit/src/components/Spinner/index.stories.tsx index ba96abcf7..d5e567192 100644 --- a/packages/pancake-uikit/src/components/Spinner/index.stories.tsx +++ b/packages/pancake-uikit/src/components/Spinner/index.stories.tsx @@ -8,5 +8,5 @@ export default { }; export const Default: React.FC = () => { - return ; + return ; }; diff --git a/packages/pancake-uikit/src/components/Stepper/Step.tsx b/packages/pancake-uikit/src/components/Stepper/Step.tsx new file mode 100644 index 000000000..b46952bfa --- /dev/null +++ b/packages/pancake-uikit/src/components/Stepper/Step.tsx @@ -0,0 +1,90 @@ +import React from "react"; +import styled from "styled-components"; +import Flex from "../Box/Flex"; +import Box from "../Box/Box"; +import { StatusProps, StepProps } from "./types"; + +const getStepNumberFontColor = ({ theme, status }: StatusProps) => { + if (status === "past") { + return theme.colors.success; + } + if (status === "current") { + return theme.colors.invertedContrast; + } + return theme.colors.textDisabled; +}; + +const Connector = styled.div` + position: absolute; + width: 4px; + height: 100%; + top: 50%; + left: calc(50% - 2px); + z-index: -1; + background-color: ${({ theme, status }) => theme.colors[status === "past" ? "success" : "textDisabled"]}; +`; + +const ChildrenWrapper = styled(Box)<{ isVisible: boolean }>` + ${({ theme }) => theme.mediaQueries.md} { + visibility: ${({ isVisible }) => (isVisible ? "visible" : "hidden")}; + } +`; + +const ChildrenLeftWrapper = styled(ChildrenWrapper)` + display: none; + ${({ theme }) => theme.mediaQueries.md} { + display: block; + margin-right: 16px; + } +`; + +const ChildrenRightWrapper = styled(ChildrenWrapper)` + margin-left: 8px; + ${({ theme }) => theme.mediaQueries.md} { + margin-left: 16px; + } +`; + +const Wrapper = styled.div` + position: relative; + display: flex; + align-items: center; +`; + +export const StepNumber = styled.div` + box-shadow: 0px 1px 4px rgba(25, 19, 38, 0.15); + background-color: ${({ theme, status }) => theme.colors[status === "current" ? "secondary" : "invertedContrast"]}; + border: 2px solid ${({ theme, status }) => (status === "past" ? theme.colors.success : "transparent")}; + border-radius: ${({ theme }) => theme.radii.circle}; + color: ${getStepNumberFontColor}; + display: flex; + justify-content: center; + align-items: center; + font-weight: 600; + font-size: 32px; + width: 48px; + height: 48px; + ${({ theme }) => theme.mediaQueries.md} { + font-size: 40px; + width: 80px; + height: 80px; + } +`; + +/** + * ChildrenLeftWrapper and ChildrenRightWrapper are used on the non mobile version, to force the alternate layout. + * One of the child is hidden based on the step number. + */ +export const Step: React.FC = ({ index, status, numberOfSteps = 0, children }) => { + const isIndexPair = index % 2 === 0; + return ( + + {children} + + {index + 1} + {index < numberOfSteps - 1 && } + + {children} + + ); +}; diff --git a/packages/pancake-uikit/src/components/Stepper/Stepper.tsx b/packages/pancake-uikit/src/components/Stepper/Stepper.tsx new file mode 100644 index 000000000..988dd6bcc --- /dev/null +++ b/packages/pancake-uikit/src/components/Stepper/Stepper.tsx @@ -0,0 +1,25 @@ +import React from "react"; +import styled from "styled-components"; +import { ThemedProps } from "./types"; + +const StepperWrapper = styled.div` + display: flex; + flex-direction: column; + width: fit-content; +`; + +const Stepper: React.FC = ({ children }) => { + const numberOfSteps = React.Children.count(children); + return ( + + {React.Children.map(children, (child) => { + if (React.isValidElement(child)) { + return React.cloneElement(child, { numberOfSteps }); + } + return child; + })} + + ); +}; + +export default Stepper; diff --git a/packages/pancake-uikit/src/components/Stepper/index.stories.tsx b/packages/pancake-uikit/src/components/Stepper/index.stories.tsx new file mode 100644 index 000000000..e3fdacccd --- /dev/null +++ b/packages/pancake-uikit/src/components/Stepper/index.stories.tsx @@ -0,0 +1,91 @@ +import React from "react"; +import styled from "styled-components"; +import Stepper from "./Stepper"; +import { Step, StepNumber } from "./Step"; +import { Status } from "./types"; +import Card from "../Card/Card"; +import CardBody from "../Card/CardBody"; + +export default { + title: "Components/Stepper", + component: Stepper, + argTypes: {}, +}; + +const mock = + "Lorem ipsum dolor sit amet, consectetur adipiscing elit. Ut vitae nisl imperdiet, vestibulum lacus at, placerat nisi. Vestibulum quis scelerisque purus. Curabitur non magna tincidunt, fermentum neque sed, finibus neque. Phasellus consequat at lorem a venenatis. Lorem ipsum dolor sit amet, consectetur adipiscing elit. Ut vitae nisl imperdiet, vestibulum lacus at, placerat nisi. Vestibulum quis scelerisque purus. Curabitur non magna tincidunt, fermentum neque sed, finibus neque. Phasellus consequat at lorem a venenatis. Lorem ipsum dolor sit amet, consectetur adipiscing elit. Ut vitae nisl imperdiet, vestibulum lacus at, placerat nisi. Vestibulum quis scelerisque purus. Curabitur non magna tincidunt, fermentum neque sed, finibus neque. Phasellus consequat at lorem a venenatis."; +const steps = [mock, mock, mock, mock]; +const status: Status[] = ["past", "current", "future", "future"]; + +const Row = styled.div` + display: flex; + margin-bottom: 32px; +`; + +export const Default: React.FC = () => { + return ( + + {steps.map((step, index) => ( + + + {step} + + + ))} + + ); +}; + +export const Components: React.FC = () => { + return ( +
+ + 1 + 1 + 1 + + + + + +

Step 0

+
+ Lorem ipsum dolor sit amet, consectetur adipiscing elit. Ut vitae nisl imperdiet, vestibulum lacus at, + placerat nisi. Vestibulum quis scelerisque purus. Curabitur non magna tincidunt, fermentum neque sed, + finibus neque. Phasellus consequat at lorem a venenatis. +
+
+
+
+
+ + + + +

Step 1

+
+ Lorem ipsum dolor sit amet, consectetur adipiscing elit. Ut vitae nisl imperdiet, vestibulum lacus at, + placerat nisi. Vestibulum quis scelerisque purus. Curabitur non magna tincidunt, fermentum neque sed, + finibus neque. Phasellus consequat at lorem a venenatis. +
+
+
+
+
+ + + + +

Step 2

+
+ Lorem ipsum dolor sit amet, consectetur adipiscing elit. Ut vitae nisl imperdiet, vestibulum lacus at, + placerat nisi. Vestibulum quis scelerisque purus. Curabitur non magna tincidunt, fermentum neque sed, + finibus neque. Phasellus consequat at lorem a venenatis. +
+
+
+
+
+
+ ); +}; diff --git a/packages/pancake-uikit/src/components/Stepper/index.ts b/packages/pancake-uikit/src/components/Stepper/index.ts new file mode 100644 index 000000000..fc1ce7256 --- /dev/null +++ b/packages/pancake-uikit/src/components/Stepper/index.ts @@ -0,0 +1,3 @@ +export { default as Stepper } from "./Stepper"; +export { Step } from "./Step"; +export type { Status as StepStatus, StepProps } from "./types"; diff --git a/packages/pancake-uikit/src/components/Stepper/types.ts b/packages/pancake-uikit/src/components/Stepper/types.ts new file mode 100644 index 000000000..b1bf0fb20 --- /dev/null +++ b/packages/pancake-uikit/src/components/Stepper/types.ts @@ -0,0 +1,18 @@ +import { DefaultTheme } from "styled-components"; + +export interface ThemedProps { + theme: DefaultTheme; +} + +export type Status = "past" | "current" | "future"; + +export interface StatusProps extends ThemedProps { + theme: DefaultTheme; + status: Status; +} + +export interface StepProps { + index: number; + status: Status; + numberOfSteps?: number; +}