From 88175dafdcdbc0bbf6c0b355b681aa02b112cec6 Mon Sep 17 00:00:00 2001 From: Anurag Hazra Date: Thu, 10 Sep 2020 12:09:01 +0530 Subject: [PATCH] refactor: removed duplicate storybook code (#29) * refactor: removed duplicate storybook code * refactor: abstracted common examples * chore: type argument in useFakeProgression --- src/meter/stories/CircularMeter.stories.tsx | 115 +------- src/meter/stories/LinearMeter.stories.tsx | 82 +----- src/meter/stories/utils.ts | 70 ----- .../stories/CircularProgress.stories.tsx | 115 +------- .../stories/LinearProgress.stories.tsx | 80 +----- src/progress/stories/utils.ts | 70 ----- src/utils.tsx | 268 ++++++++++++++++++ 7 files changed, 302 insertions(+), 498 deletions(-) delete mode 100644 src/meter/stories/utils.ts delete mode 100644 src/progress/stories/utils.ts create mode 100644 src/utils.tsx diff --git a/src/meter/stories/CircularMeter.stories.tsx b/src/meter/stories/CircularMeter.stories.tsx index c4d193aea..b848c0282 100644 --- a/src/meter/stories/CircularMeter.stories.tsx +++ b/src/meter/stories/CircularMeter.stories.tsx @@ -1,130 +1,27 @@ import React from "react"; import { Meta } from "@storybook/react"; -import { css, keyframes } from "emotion"; -import { isUndefined } from "@chakra-ui/utils"; import { Meter } from "../Meter"; import { useMeterState } from "../index"; -import { useMeterSimulation } from "./utils"; +import { useFakeProgression, createCircularExample } from "../../utils"; export default { title: "Component/Meter/Circular", } as Meta; -const spin = keyframes({ - "0%": { - strokeDasharray: "1, 400", - strokeDashoffset: "0", - }, - "50%": { - strokeDasharray: "400, 400", - strokeDashoffset: "-100", - }, - "100%": { - strokeDasharray: "400, 400", - strokeDashoffset: "-260", - }, +const CircularMeter = createCircularExample({ + stateHook: useMeterState, + component: Meter, }); -const rotate = keyframes({ - "0%": { - transform: "rotate(0deg)", - }, - "100%": { - transform: "rotate(360deg)", - }, -}); - -const CircularMeter = (props: any) => { - const { - size = "48px", - value, - capIsRound, - thickness = "10px", - color = "#0078d4", - trackColor = "#edebe9", - label = false, - } = props; - - const progress = useMeterState({ value }); - - const determinant = progress.isIndeterminate - ? undefined - : (progress.percent ?? 0) * 2.64; - - const strokeDasharray = isUndefined(determinant) - ? undefined - : `${determinant} ${264 - determinant}`; - - const indicatorStyles = progress.isIndeterminate - ? css({ - animation: `${spin} 1.5s linear infinite`, - }) - : css({ - strokeDashoffset: 66, - strokeDasharray, - transition: `stroke-dasharray 0.6s ease 0s, stroke 0.6s ease`, - }); - - const rootStyles = css({ - display: "inline-block", - position: "relative", - verticalAlign: "middle", - }); - - const svgStyles = css({ - width: size, - height: size, - animation: progress.isIndeterminate - ? `${rotate} 2s linear infinite` - : undefined, - }); - - const labelStyles = css({ - fontSize: "14px", - top: "50%", - left: "50%", - width: "100%", - textAlign: "center", - position: "absolute", - transform: "translate(-50%, -50%)", - }); - - return ( - - - - - - {label &&
{`${progress.value}%`}
} -
- ); -}; - export const Default = () => { - const value = useMeterSimulation(); + const value = useFakeProgression("meter"); return ; }; export const WithLabel = () => { - const value = useMeterSimulation(); + const value = useFakeProgression("meter"); return ; }; diff --git a/src/meter/stories/LinearMeter.stories.tsx b/src/meter/stories/LinearMeter.stories.tsx index 2632cb03f..e9de4ebaa 100644 --- a/src/meter/stories/LinearMeter.stories.tsx +++ b/src/meter/stories/LinearMeter.stories.tsx @@ -1,82 +1,20 @@ -import React from "react"; import { Meta } from "@storybook/react"; -import { css, keyframes, cx } from "emotion"; import { Meter } from "../Meter"; import { useMeterState } from "../index"; -import { - generateStripe, - labelStyles, - useMeterSimulation, - progressBarStyle, - progressStyle, -} from "./utils"; +import { createLinearExamples } from "../../utils"; export default { title: "Component/Meter/Linear", } as Meta; -export const Default = () => { - const value = useMeterSimulation(); - const progress = useMeterState({ value }); +const examples = createLinearExamples({ + stateHook: useMeterState, + component: Meter, + type: "meter", +})(); - return ( -
- -
- ); -}; - -export const WithLabel = () => { - const value = useMeterSimulation(); - const progress = useMeterState({ value }); - - return ( -
-
{progress.value}
- -
- ); -}; - -export const WithStripe = () => { - const value = useMeterSimulation(); - const progress = useMeterState({ value }); - - const stripStyles = css({ - ...generateStripe(), - }); - - return ( -
- -
- ); -}; - -export const WithAnimatedStripe = () => { - const value = useMeterSimulation(); - const progress = useMeterState({ value }); - - const stripe = keyframes({ - from: { backgroundPosition: "1rem 0" }, - to: { backgroundPosition: "0 0" }, - }); - - const stripStyles = css({ - ...generateStripe(), - animation: `${stripe} 1s linear infinite`, - }); - - return ( -
- -
- ); -}; +export const Default = examples.Default; +export const WithLabel = examples.WithLabel; +export const WithStripe = examples.WithStripe; +export const WithAnimatedStripe = examples.WithAnimatedStripe; diff --git a/src/meter/stories/utils.ts b/src/meter/stories/utils.ts deleted file mode 100644 index a877d21b6..000000000 --- a/src/meter/stories/utils.ts +++ /dev/null @@ -1,70 +0,0 @@ -import { css } from "emotion"; -import React, { CSSProperties } from "react"; - -export const progressStyle: CSSProperties = { - background: "rgb(237, 242, 247)", - height: "0.75rem", - width: "400px", - overflow: "hidden", - position: "relative", -}; - -export const labelStyles: CSSProperties = { - top: "50%", - left: "50%", - width: "100%", - textAlign: "center", - position: "absolute", - transform: "translate(-50%, -50%)", - fontWeight: "bold", - fontSize: "0.75em", - lineHeight: 1, -}; - -export const progressBarStyle = (percent: any) => { - return css({ - transition: "all 0.3s", - backgroundColor: "#3182ce", - width: percent != null ? `${percent}%` : undefined, - height: "100%", - }); -}; - -export function generateStripe( - size = "1rem", - color = "rgba(255, 255, 255, 0.15)", -) { - return { - backgroundImage: `linear-gradient( - 45deg, - ${color} 25%, - transparent 25%, - transparent 50%, - ${color} 50%, - ${color} 75%, - transparent 75%, - transparent - )`, - backgroundSize: `${size} ${size}`, - }; -} - -export function useMeterSimulation() { - const [value, setValue] = React.useState(0); - - React.useEffect(() => { - const clearId = setInterval(() => { - setValue(prevValue => prevValue + 5); - }, 500); - - if (value === 100) { - setValue(5); - } - - return () => { - clearInterval(clearId); - }; - }, [value]); - - return value; -} diff --git a/src/progress/stories/CircularProgress.stories.tsx b/src/progress/stories/CircularProgress.stories.tsx index 44b478d51..b31f44bfd 100644 --- a/src/progress/stories/CircularProgress.stories.tsx +++ b/src/progress/stories/CircularProgress.stories.tsx @@ -1,130 +1,27 @@ import React from "react"; import { Meta } from "@storybook/react"; -import { css, keyframes } from "emotion"; -import { isUndefined } from "@chakra-ui/utils"; import { Progress } from "../Progress"; -import { useProgressSimulation } from "./utils"; import { useProgressState } from "../ProgressState"; +import { useFakeProgression, createCircularExample } from "../../utils"; export default { title: "Component/Progress/Circular", } as Meta; -const spin = keyframes({ - "0%": { - strokeDasharray: "1, 400", - strokeDashoffset: "0", - }, - "50%": { - strokeDasharray: "400, 400", - strokeDashoffset: "-100", - }, - "100%": { - strokeDasharray: "400, 400", - strokeDashoffset: "-260", - }, +const CircularProgress = createCircularExample({ + stateHook: useProgressState, + component: Progress, }); -const rotate = keyframes({ - "0%": { - transform: "rotate(0deg)", - }, - "100%": { - transform: "rotate(360deg)", - }, -}); - -const CircularProgress = (props: any) => { - const { - size = "48px", - value, - capIsRound, - thickness = "10px", - color = "#0078d4", - trackColor = "#edebe9", - label = false, - } = props; - - const progress = useProgressState({ value }); - - const determinant = progress.isIndeterminate - ? undefined - : (progress.percent ?? 0) * 2.64; - - const strokeDasharray = isUndefined(determinant) - ? undefined - : `${determinant} ${264 - determinant}`; - - const indicatorStyles = progress.isIndeterminate - ? css({ - animation: `${spin} 1.5s linear infinite`, - }) - : css({ - strokeDashoffset: 66, - strokeDasharray, - transition: `stroke-dasharray 0.6s ease 0s, stroke 0.6s ease`, - }); - - const rootStyles = css({ - display: "inline-block", - position: "relative", - verticalAlign: "middle", - }); - - const svgStyles = css({ - width: size, - height: size, - animation: progress.isIndeterminate - ? `${rotate} 2s linear infinite` - : undefined, - }); - - const labelStyles = css({ - fontSize: "14px", - top: "50%", - left: "50%", - width: "100%", - textAlign: "center", - position: "absolute", - transform: "translate(-50%, -50%)", - }); - - return ( - - - - - - {label &&
{`${progress.value}%`}
} -
- ); -}; - export const Default = () => { - const value = useProgressSimulation(); + const value = useFakeProgression(); return ; }; export const WithLabel = () => { - const value = useProgressSimulation(); + const value = useFakeProgression(); return ; }; diff --git a/src/progress/stories/LinearProgress.stories.tsx b/src/progress/stories/LinearProgress.stories.tsx index 0d4e1f2f1..93f1567cd 100644 --- a/src/progress/stories/LinearProgress.stories.tsx +++ b/src/progress/stories/LinearProgress.stories.tsx @@ -1,85 +1,29 @@ import React from "react"; import { Meta } from "@storybook/react"; -import { css, keyframes, cx } from "emotion"; +import { css, keyframes } from "emotion"; import { Progress } from "../Progress"; import { useProgressState } from "../ProgressState"; import { + progressStyle, generateStripe, - labelStyles, progressBarStyle, - progressStyle, - useProgressSimulation, -} from "./utils"; + createLinearExamples, +} from "../../utils"; export default { title: "Component/Progress/Linear", } as Meta; -export const Default = () => { - const value = useProgressSimulation(); - const progress = useProgressState({ value }); - - return ( -
- -
- ); -}; - -export const WithLabel = () => { - const value = useProgressSimulation(); - const progress = useProgressState({ value }); - - return ( -
-
{progress.value}
- -
- ); -}; - -export const WithStripe = () => { - const value = useProgressSimulation(); - const progress = useProgressState({ value }); - - const stripStyles = css({ - ...generateStripe(), - }); - - return ( -
- -
- ); -}; - -export const WithAnimatedStripe = () => { - const value = useProgressSimulation(); - const progress = useProgressState({ value }); - - const stripe = keyframes({ - from: { backgroundPosition: "1rem 0" }, - to: { backgroundPosition: "0 0" }, - }); - - const stripStyles = css({ - ...generateStripe(), - animation: `${stripe} 1s linear infinite`, - }); +const examples = createLinearExamples({ + stateHook: useProgressState, + component: Progress, +})(); - return ( -
- -
- ); -}; +export const Default = examples.Default; +export const WithLabel = examples.WithLabel; +export const WithStripe = examples.WithStripe; +export const WithAnimatedStripe = examples.WithAnimatedStripe; export const WhenIsIndeterminate = () => { const progress = useProgressState({ value: undefined }); diff --git a/src/progress/stories/utils.ts b/src/progress/stories/utils.ts deleted file mode 100644 index f54b65434..000000000 --- a/src/progress/stories/utils.ts +++ /dev/null @@ -1,70 +0,0 @@ -import { css } from "emotion"; -import React, { CSSProperties } from "react"; - -export const progressStyle: CSSProperties = { - background: "rgb(237, 242, 247)", - height: "0.75rem", - width: "400px", - overflow: "hidden", - position: "relative", -}; - -export const labelStyles: CSSProperties = { - top: "50%", - left: "50%", - width: "100%", - textAlign: "center", - position: "absolute", - transform: "translate(-50%, -50%)", - fontWeight: "bold", - fontSize: "0.75em", - lineHeight: 1, -}; - -export const progressBarStyle = (percent: any) => { - return css({ - transition: "all 0.3s", - backgroundColor: "#3182ce", - width: percent != null ? `${percent}%` : undefined, - height: "100%", - }); -}; - -export function generateStripe( - size = "1rem", - color = "rgba(255, 255, 255, 0.15)", -) { - return { - backgroundImage: `linear-gradient( - 45deg, - ${color} 25%, - transparent 25%, - transparent 50%, - ${color} 50%, - ${color} 75%, - transparent 75%, - transparent - )`, - backgroundSize: `${size} ${size}`, - }; -} - -export function useProgressSimulation() { - const [value, setValue] = React.useState(0); - - React.useEffect(() => { - const clearId = setInterval(() => { - setValue(prevValue => prevValue + 5); - }, 500); - - if (value === 100) { - clearInterval(clearId); - } - - return () => { - clearInterval(clearId); - }; - }, [value]); - - return value; -} diff --git a/src/utils.tsx b/src/utils.tsx new file mode 100644 index 000000000..07794918b --- /dev/null +++ b/src/utils.tsx @@ -0,0 +1,268 @@ +import { css, keyframes } from "emotion"; +import React, { CSSProperties } from "react"; +import { isUndefined, cx } from "@chakra-ui/utils"; + +export const progressStyle: CSSProperties = { + background: "rgb(237, 242, 247)", + height: "0.75rem", + width: "400px", + overflow: "hidden", + position: "relative", +}; + +export const labelStyles: CSSProperties = { + top: "50%", + left: "50%", + width: "100%", + textAlign: "center", + position: "absolute", + transform: "translate(-50%, -50%)", + fontWeight: "bold", + fontSize: "0.75em", + lineHeight: 1, +}; + +export const progressBarStyle = (percent: any) => { + return css({ + transition: "all 0.3s", + backgroundColor: "#3182ce", + width: percent != null ? `${percent}%` : undefined, + height: "100%", + }); +}; + +export function generateStripe( + size = "1rem", + color = "rgba(255, 255, 255, 0.15)", +) { + return { + backgroundImage: `linear-gradient( + 45deg, + ${color} 25%, + transparent 25%, + transparent 50%, + ${color} 50%, + ${color} 75%, + transparent 75%, + transparent + )`, + backgroundSize: `${size} ${size}`, + }; +} + +export const spin = keyframes({ + "0%": { + strokeDasharray: "1, 400", + strokeDashoffset: "0", + }, + "50%": { + strokeDasharray: "400, 400", + strokeDashoffset: "-100", + }, + "100%": { + strokeDasharray: "400, 400", + strokeDashoffset: "-260", + }, +}); + +export const rotate = keyframes({ + "0%": { + transform: "rotate(0deg)", + }, + "100%": { + transform: "rotate(360deg)", + }, +}); + +export function useFakeProgression(type: "progress" | "meter" = "progress") { + const [value, setValue] = React.useState(0); + + React.useEffect(() => { + const clearId = setInterval(() => { + setValue(prevValue => prevValue + 5); + }, 500); + + if (value === 100) { + if (type === "progress") { + clearInterval(clearId); + } + if (type === "meter") { + setValue(5); + } + } + + return () => { + clearInterval(clearId); + }; + }, [value, type]); + + return value; +} + +export const createCircularExample = ({ + stateHook: useStateHook, + component: Component, +}: any) => { + return (props: any) => { + const { + size = "48px", + value, + capIsRound, + thickness = "10px", + color = "#0078d4", + trackColor = "#edebe9", + label = false, + } = props; + + const progress = useStateHook({ value }); + + const determinant = progress.isIndeterminate + ? undefined + : (progress.percent ?? 0) * 2.64; + + const strokeDasharray = isUndefined(determinant) + ? undefined + : `${determinant} ${264 - determinant}`; + + const indicatorStyles = progress.isIndeterminate + ? css({ + animation: `${spin} 1.5s linear infinite`, + }) + : css({ + strokeDashoffset: 66, + strokeDasharray, + transition: `stroke-dasharray 0.6s ease 0s, stroke 0.6s ease`, + }); + + const rootStyles = css({ + display: "inline-block", + position: "relative", + verticalAlign: "middle", + }); + + const svgStyles = css({ + width: size, + height: size, + animation: progress.isIndeterminate + ? `${rotate} 2s linear infinite` + : undefined, + }); + + const labelStyles = css({ + fontSize: "14px", + top: "50%", + left: "50%", + width: "100%", + textAlign: "center", + position: "absolute", + transform: "translate(-50%, -50%)", + }); + + return ( + + + + + + {label &&
{`${progress.value}%`}
} +
+ ); + }; +}; + +export const createLinearExamples = ({ + stateHook: useStateHook, + component: Component, + type, +}: any) => { + return () => { + const Default = () => { + const value = useFakeProgression(type); + const progress = useStateHook({ value }); + + return ( +
+ +
+ ); + }; + + const WithLabel = () => { + const value = useFakeProgression(type); + const progress = useStateHook({ value }); + + return ( +
+
{progress.value}
+ +
+ ); + }; + + const WithStripe = () => { + const value = useFakeProgression(type); + const progress = useStateHook({ value }); + + const stripStyles = css({ + ...generateStripe(), + }); + + return ( +
+ +
+ ); + }; + + const WithAnimatedStripe = () => { + const value = useFakeProgression(type); + const progress = useStateHook({ value }); + + const stripe = keyframes({ + from: { backgroundPosition: "1rem 0" }, + to: { backgroundPosition: "0 0" }, + }); + + const stripStyles = css({ + ...generateStripe(), + animation: `${stripe} 1s linear infinite`, + }); + + return ( +
+ +
+ ); + }; + + return { Default, WithLabel, WithStripe, WithAnimatedStripe }; + }; +};