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