diff options
Diffstat (limited to 'packages/instant/src/components/timed_progress_bar.tsx')
-rw-r--r-- | packages/instant/src/components/timed_progress_bar.tsx | 101 |
1 files changed, 101 insertions, 0 deletions
diff --git a/packages/instant/src/components/timed_progress_bar.tsx b/packages/instant/src/components/timed_progress_bar.tsx new file mode 100644 index 000000000..7fdfe1a25 --- /dev/null +++ b/packages/instant/src/components/timed_progress_bar.tsx @@ -0,0 +1,101 @@ +import * as _ from 'lodash'; +import * as React from 'react'; +import { Keyframes } from 'styled-components'; + +import { PROGRESS_FINISH_ANIMATION_TIME_MS, PROGRESS_STALL_AT_PERCENTAGE } from '../constants'; +import { ColorOption, keyframes, styled } from '../style/theme'; +import { timeUtil } from '../util/time'; + +import { Container } from './ui/container'; +import { Flex } from './ui/flex'; +import { Text } from './ui/text'; + +export interface TimedProgressBarProps { + expectedTimeMs: number; + ended: boolean; +} + +interface TimedProgressBarState { + animationTimeMs: number; + animationStartingWidth: string; + maxWidthPercent: number; +} + +export const beginningState = (props: TimedProgressBarProps): TimedProgressBarState => { + return { + animationTimeMs: props.expectedTimeMs, + animationStartingWidth: '0%', + maxWidthPercent: PROGRESS_STALL_AT_PERCENTAGE, + }; +}; + +export class TimedProgressBar extends React.Component<TimedProgressBarProps, TimedProgressBarState> { + private readonly _barRef = React.createRef<HTMLDivElement>(); + + public constructor(props: TimedProgressBarProps) { + super(props); + this.state = beginningState(props); + } + + public componentDidUpdate(prevProps: TimedProgressBarProps, prevState: TimedProgressBarState): void { + if (prevProps.ended === false && this.props.ended === true) { + // Show nice animation going to end + // barRef current should always exist, but checking for typesafety + if (this._barRef.current) { + const curProgressWidth = this._barRef.current.offsetWidth; + this.setState({ + animationTimeMs: PROGRESS_FINISH_ANIMATION_TIME_MS, + animationStartingWidth: `${curProgressWidth}px`, + maxWidthPercent: 100, + }); + } + return; + } + + if (prevProps.expectedTimeMs !== this.props.expectedTimeMs || prevProps.ended !== this.props.ended) { + // things changed, get fresh state + this.setState(beginningState(this.props)); + } + } + + public render(): React.ReactNode { + return ( + <Container width="100%" backgroundColor={ColorOption.lightGrey} borderRadius="6px"> + <TimedProgress + fromWidth={this.state.animationStartingWidth} + timeMs={this.state.animationTimeMs} + maxWidthPercent={this.state.maxWidthPercent} + ref={this._barRef as any} + /> + </Container> + ); + } +} + +const expandingWidthKeyframes = (fromWidth: string, maxWidthPercent: number) => { + return keyframes` + from { + width: ${fromWidth} + } + to { + width: ${maxWidthPercent}%; + } + `; +}; + +interface TimedProgressProps { + timeMs: number; + fromWidth: string; + maxWidthPercent: number; +} +// TODO use PrimaryColor instead of black +export const TimedProgress = + styled.div < + TimedProgressProps > + ` + background-color: black; + border-radius: 6px; + height: 6px; + animation: ${props => expandingWidthKeyframes(props.fromWidth, props.maxWidthPercent)} + ${props => props.timeMs}ms linear 1 forwards; + `; |