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; +}