feat: snack-bar component (#626)

* feat: SnackBarProvider and queuing

* feat: use snack bar on onboarding errors

* feat: workspace copy use snackBar

* fix: remove magic number
This commit is contained in:
Jérémy M
2023-07-14 06:27:09 +02:00
committed by GitHub
parent 551c3b5e60
commit 03364330d1
13 changed files with 549 additions and 64 deletions

View File

@ -0,0 +1,101 @@
import {
forwardRef,
useCallback,
useEffect,
useImperativeHandle,
useRef,
} from 'react';
import { useTheme } from '@emotion/react';
import styled from '@emotion/styled';
import { AnimationControls, motion, useAnimation } from 'framer-motion';
const Bar = styled.div<Pick<ProgressBarProps, 'barHeight'>>`
height: ${({ barHeight }) => barHeight}px;
overflow: hidden;
width: 100%;
`;
const BarFilling = styled(motion.div)`
height: 100%;
width: 100%;
`;
export type ProgressBarProps = {
duration?: number;
delay?: number;
easing?: string;
barHeight?: number;
barColor?: string;
autoStart?: boolean;
};
export type ProgressBarControls = AnimationControls & {
start: () => Promise<any>;
pause: () => Promise<any>;
};
export const ProgressBar = forwardRef<ProgressBarControls, ProgressBarProps>(
(
{
duration = 3,
delay = 0,
easing = 'easeInOut',
barHeight = 24,
barColor,
autoStart = true,
},
ref,
) => {
const theme = useTheme();
const controls = useAnimation();
const startTimestamp = useRef<number>(0);
const remainingTime = useRef<number>(duration);
const start = useCallback(async () => {
startTimestamp.current = Date.now();
return controls.start({
scaleX: 0,
transition: {
duration: remainingTime.current / 1000, // convert ms to s for framer-motion
delay: delay / 1000, // likewise
ease: easing,
},
});
}, [controls, delay, easing]);
useImperativeHandle(ref, () => ({
...controls,
start: async () => {
return start();
},
pause: async () => {
const elapsed = Date.now() - startTimestamp.current;
remainingTime.current = remainingTime.current - elapsed;
return controls.stop();
},
}));
useEffect(() => {
if (autoStart) {
start();
}
}, [controls, delay, duration, easing, autoStart, start]);
return (
<Bar barHeight={barHeight}>
<BarFilling
style={{
originX: 0,
// Seems like custom props are not well handled by react when used with framer-motion and emotion styled
backgroundColor: barColor ?? theme.color.gray80,
}}
initial={{ scaleX: 1 }}
animate={controls}
exit={{ scaleX: 0 }}
/>
</Bar>
);
},
);

View File

@ -38,3 +38,5 @@ export { IconTimelineEvent } from '@tabler/icons-react';
export { IconAlertCircle } from '@tabler/icons-react';
export { IconEye } from '@tabler/icons-react';
export { IconEyeOff } from '@tabler/icons-react';
export { IconAlertTriangle } from '@tabler/icons-react';
export { IconCopy } from '@tabler/icons-react';

View File

@ -13,6 +13,20 @@ const common = {
icon: icon,
text: text,
blur: blur,
snackBar: {
success: {
background: '#16A26B',
color: '#D0F8E9',
},
error: {
background: '#B43232',
color: '#FED8D8',
},
info: {
background: color.gray80,
color: color.gray0,
},
},
spacing: (multiplicator: number) => `${multiplicator * 4}px`,
table: {
horizontalCellMargin: '8px',