From b7436a1934cdff6d558abc262776c3a2d21df8f7 Mon Sep 17 00:00:00 2001 From: Kristóf Marussy Date: Sat, 1 Oct 2022 13:45:56 +0200 Subject: feat(frontend): animate GenerateButton --- subprojects/frontend/src/editor/AnimatedButton.tsx | 95 ++++++++++++++++++++++ 1 file changed, 95 insertions(+) create mode 100644 subprojects/frontend/src/editor/AnimatedButton.tsx (limited to 'subprojects/frontend/src/editor/AnimatedButton.tsx') diff --git a/subprojects/frontend/src/editor/AnimatedButton.tsx b/subprojects/frontend/src/editor/AnimatedButton.tsx new file mode 100644 index 00000000..d08decbc --- /dev/null +++ b/subprojects/frontend/src/editor/AnimatedButton.tsx @@ -0,0 +1,95 @@ +import Box from '@mui/material/Box'; +import Button from '@mui/material/Button'; +import { styled } from '@mui/material/styles'; +import React, { type ReactNode, useLayoutEffect, useState } from 'react'; + +const AnimatedButtonBase = styled(Button, { + shouldForwardProp: (prop) => prop !== 'width', +})<{ width: string }>(({ theme, width }) => { + // Transition copied from `@mui/material/Button`. + const colorTransition = theme.transitions.create( + ['background-color', 'box-shadow', 'border-color', 'color'], + { duration: theme.transitions.duration.short }, + ); + return { + width, + // Make sure the button does not change width if a number is updated. + fontVariantNumeric: 'tabular-nums', + transition: ` + ${colorTransition}, + ${theme.transitions.create(['width'], { + duration: theme.transitions.duration.short, + easing: theme.transitions.easing.easeOut, + })} + `, + '@media (prefers-reduced-motion: reduce)': { + transition: colorTransition, + }, + }; +}); + +export default function AnimatedButton({ + 'aria-label': ariaLabel, + onClick, + color, + disabled, + startIcon, + children, +}: { + 'aria-label'?: string; + onClick?: () => void; + color: 'error' | 'warning' | 'primary' | 'inherit'; + disabled?: boolean; + startIcon: JSX.Element; + children?: ReactNode; +}): JSX.Element { + const [width, setWidth] = useState(); + const [contentsElement, setContentsElement] = useState( + null, + ); + + useLayoutEffect(() => { + if (contentsElement !== null) { + const updateWidth = () => { + setWidth(window.getComputedStyle(contentsElement).width); + }; + updateWidth(); + const observer = new ResizeObserver(updateWidth); + observer.observe(contentsElement); + return () => observer.unobserve(contentsElement); + } + return () => {}; + }, [setWidth, contentsElement]); + + return ( + + + + {children} + + + + ); +} + +AnimatedButton.defaultProps = { + 'aria-label': undefined, + onClick: undefined, + disabled: false, + children: undefined, +}; -- cgit v1.2.3-54-g00ecf