Skip to content

Commit

Permalink
refactor(progress): ♻️ refactor state & stories
Browse files Browse the repository at this point in the history
  • Loading branch information
navin-moorthy committed Oct 19, 2020
1 parent 642f331 commit 56d0cb3
Show file tree
Hide file tree
Showing 5 changed files with 186 additions and 94 deletions.
2 changes: 1 addition & 1 deletion src/accordion/AccordionState.ts
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,7 @@ export type AccordionState = CompositeState & {
* Whether the accodion selection should be manual.
* @default true
*/
manual: boolean;
manual?: boolean;
/**
* Allow to open multiple accordion items
* @default false
Expand Down
19 changes: 11 additions & 8 deletions src/progress/Progress.ts
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ import { createHook, createComponent } from "reakit-system";

import { PROGRESS_KEYS } from "./__keys";
import { ProgressStateReturn } from "./ProgressState";
import { dataAttr } from "../utils";

export type ProgressOptions = BoxOptions &
Pick<
Expand All @@ -21,7 +22,7 @@ export type ProgressOptions = BoxOptions &
* It's mostly used to generate a more human-readable
* representation of the value for assistive technologies
*/
getAriaValueText?(value: number, percent: number): string;
getAriaValueText?: (value: number, percent: number) => string;
};

export type ProgressHTMLProps = BoxHTMLProps;
Expand All @@ -36,18 +37,20 @@ export const useProgress = createHook<ProgressOptions, ProgressHTMLProps>({
useProps(options, { "aria-valuetext": ariaValueText, ...htmlProps }) {
const { isIndeterminate, value, max, min, percent } = options;

const getAriaValueText = () => {
if (value == null) return;
return isFunction(options.getAriaValueText)
? options.getAriaValueText(value, percent)
: ariaValueText ?? `${value}`;
};

return {
role: "progressbar",
"data-indeterminate": isIndeterminate ? "" : undefined,
"data-indeterminate": dataAttr(isIndeterminate),
"aria-valuemax": max,
"aria-valuemin": min,
"aria-valuenow": isIndeterminate ? undefined : value,
"aria-valuetext":
value == null || percent == null
? undefined
: isFunction(options.getAriaValueText)
? options.getAriaValueText(value, percent)
: ariaValueText ?? String(value),
"aria-valuetext": getAriaValueText(),
...htmlProps,
};
},
Expand Down
54 changes: 41 additions & 13 deletions src/progress/ProgressState.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,31 +4,59 @@
* We improved the Progress Component [Progress](https://github.com/chakra-ui/chakra-ui/tree/develop/packages/progress)
* to work with Reakit System
*/
import { isUndefined, valueToPercent } from "@chakra-ui/utils";
import * as React from "react";
import { SealedInitialState, useSealedState } from "reakit-utils";

export interface UseProgressProps {
import { valueToPercent } from "../utils";

export interface ProgressState {
/**
* The `value` of the progress indicator.
* If `undefined` the progress bar will be in `indeterminate` state
* @default 0
*/
value?: number;
value: number;
/**
* The minimum value of the progress
* @default 0
*/
min: number;
/**
* The maximum value of the
* @default 100
*/
max: number;
/**
* Set isInterminate state
*/
min?: number;
isIndeterminate?: boolean;
/**
* The maximum value of the progress
* Percentage of the value progressed with respect to min & max
*/
max?: number;
percent: number;
}

export interface ProgressAction {
setValue?: React.Dispatch<React.SetStateAction<number>>;
}

export const useProgressState = (props: UseProgressProps = {}) => {
const { value, min = 0, max = 100 } = props;
export type ProgressInitialState = Partial<
Pick<ProgressState, "value" | "min" | "max" | "isIndeterminate">
>;

const percent = value != null ? valueToPercent(value, min, max) : undefined;
const isIndeterminate = isUndefined(value);
export type ProgressStateReturn = ProgressState & ProgressAction;

return { value, isIndeterminate, min, max, percent };
};
export function useProgressState(
initialState: SealedInitialState<ProgressInitialState> = {},
): ProgressStateReturn {
const {
value: initialValue = 0,
min = 0,
max = 100,
isIndeterminate,
} = useSealedState(initialState);
const [value, setValue] = React.useState(initialValue);
const percent = valueToPercent(value, min, max);

export type ProgressStateReturn = ReturnType<typeof useProgressState>;
return { value, setValue, percent, isIndeterminate, min, max };
}
140 changes: 68 additions & 72 deletions src/progress/stories/LinearProgress.stories.tsx
Original file line number Diff line number Diff line change
@@ -1,89 +1,85 @@
import React from "react";
import { Meta } from "@storybook/react";
import { css, keyframes } from "emotion";

import { Progress } from "../Progress";
import { useProgressState } from "../ProgressState";
import {
progressStyle,
generateStripe,
progressBarStyle,
createLinearExamples,
} from "./storybook-progress-utils";
import { StyledProgress } from "./Progress";

export default {
title: "Progress/Linear",
} as Meta;

const examples = createLinearExamples({
stateHook: useProgressState,
component: Progress,
})();
export const Default = () => {
return <StyledProgress />;
};

export const Default = examples.Default;
export const WithLabel = examples.WithLabel;
export const WithStripe = examples.WithStripe;
export const WithAnimatedStripe = examples.WithAnimatedStripe;
// const examples = createLinearExamples({
// stateHook: useProgressState,
// component: Progress,
// })();

export const WhenIsIndeterminate = () => {
const progress = useProgressState({ value: undefined });
// export const Default = examples.Default;
// export const WithLabel = examples.WithLabel;
// export const WithStripe = examples.WithStripe;
// export const WithAnimatedStripe = examples.WithAnimatedStripe;

const progressAnim = keyframes({
"0%": { left: "-40%" },
"100%": { left: "100%" },
});
// export const WhenIsIndeterminate = () => {
// const progress = useProgressState({ value: undefined });

const indeterminateStyles = css({
...(progress.isIndeterminate && {
position: "absolute",
willChange: "left",
minWidth: "50%",
width: "100%",
height: "100%",
backgroundImage:
"linear-gradient( to right, transparent 0%, #D53F8C 50%, transparent 100% )",
animation: `${progressAnim} 1s ease infinite normal none running`,
}),
});
// const progressAnim = keyframes({
// "0%": { left: "-40%" },
// "100%": { left: "100%" },
// });

return (
<div style={progressStyle}>
<Progress
{...progress}
style={{ ...progressBarStyle, backgroundColor: "none" }}
className={indeterminateStyles}
/>
</div>
);
};
// const indeterminateStyles = css({
// ...(progress.isIndeterminate && {
// position: "absolute",
// willChange: "left",
// minWidth: "50%",
// width: "100%",
// height: "100%",
// backgroundImage:
// "linear-gradient( to right, transparent 0%, #D53F8C 50%, transparent 100% )",
// animation: `${progressAnim} 1s ease infinite normal none running`,
// }),
// });

export const WhenIsIndeterminateStripe = () => {
const progress = useProgressState();
// return (
// <div style={progressStyle}>
// <Progress
// {...progress}
// style={{ ...progressBarStyle, backgroundColor: "none" }}
// className={indeterminateStyles}
// />
// </div>
// );
// };

const progressAnim = keyframes({
"0%": { left: "-40%" },
"100%": { left: "100%" },
});
// export const WhenIsIndeterminateStripe = () => {
// const progress = useProgressState();

const indeterminateStyles = css({
...(progress.isIndeterminate && {
position: "absolute",
willChange: "left",
minWidth: "50%",
width: "100%",
height: "100%",
...generateStripe(),
animation: `${progressAnim} 1s ease infinite normal none running`,
}),
});
// const progressAnim = keyframes({
// "0%": { left: "-40%" },
// "100%": { left: "100%" },
// });

return (
<div style={progressStyle}>
<Progress
{...progress}
style={{ ...progressBarStyle, backgroundColor: "#D53F8C" }}
className={indeterminateStyles}
/>
</div>
);
};
// const indeterminateStyles = css({
// ...(progress.isIndeterminate && {
// position: "absolute",
// willChange: "left",
// minWidth: "50%",
// width: "100%",
// height: "100%",
// ...generateStripe(),
// animation: `${progressAnim} 1s ease infinite normal none running`,
// }),
// });

// return (
// <div style={progressStyle}>
// <Progress
// {...progress}
// style={{ ...progressBarStyle, backgroundColor: "#D53F8C" }}
// className={indeterminateStyles}
// />
// </div>
// );
// };
65 changes: 65 additions & 0 deletions src/progress/stories/Progress.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,65 @@
import { css } from "emotion";
import * as React from "react";
import { Button } from "reakit";

import {
Progress,
useProgressState,
ProgressState,
ProgressInitialState,
} from "../index";

export interface StyledProgressInitialState extends ProgressInitialState {}

export const StyledProgress: React.FC<StyledProgressInitialState> = props => {
const { children, ...rest } = props;
const { value, setValue, ...state } = useProgressState(rest);
console.log("%c state", "color: #735656", state);

React.useEffect(() => {
const clearId = setInterval(() => {
setValue(prevValue => prevValue + 5);
}, 500);

if (value === 100) {
clearInterval(clearId);
}

return () => {
clearInterval(clearId);
};
}, [setValue, value]);

return (
<div>
<div style={progressStyle}>
<Progress
{...state}
value={value}
className={progressBarStyle(state.percent)}
/>
</div>
<br />
<Button type="reset" onClick={() => setValue(0)}>
Reset
</Button>
</div>
);
};

const progressStyle: React.CSSProperties = {
background: "rgb(237, 242, 247)",
height: "0.75rem",
width: "400px",
overflow: "hidden",
position: "relative",
};

const progressBarStyle = (percent: ProgressState["percent"]) => {
return css({
transition: "all 0.3s",
backgroundColor: "#3182ce",
width: `${percent}%`,
height: "100%",
});
};

0 comments on commit 56d0cb3

Please sign in to comment.