Created
November 10, 2020 09:04
-
-
Save lucax88x/96dea5a8baeff69b8f2481464d675519 to your computer and use it in GitHub Desktop.
Revisions
-
lucax88x created this gist
Nov 10, 2020 .There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters. Learn more about bidirectional Unicode charactersOriginal file line number Diff line number Diff line change @@ -0,0 +1,152 @@ /* eslint-disable react/button-has-type */ import { useStyledTheme } from '@pfb/hooks/useTheme'; import { Theme } from '@pfb/models/theme.model'; import { ButtonHTMLAttributes, PropsWithChildren, useCallback, MouseEvent, forwardRef, ReactNode, } from 'react'; import { keyframes } from '@emotion/core'; export interface ButtonProps { primary?: boolean; error?: boolean; link?: boolean; transparent?: boolean; after?: ReactNode; } const getColorPair = (theme: Theme, props: ButtonProps) => { if (props.primary) { return theme.colors.primary; } if (props.error) { return theme.colors.error; } if (props.link) { return { backgroundColor: 'transparent', color: theme.elements.link.color, borderColor: 'transparent', }; } if (props.transparent) { return { backgroundColor: 'transparent', color: theme.elements.link.color, borderColor: 'transparent', }; } return theme.colors.default; }; const rippleTransition = keyframes` to { transform: scale(4); opacity: 0; }`; const styles = (props: { primary: boolean; error: boolean; link: boolean; transparent: boolean; }) => (theme: Theme) => { const colorPairByProps = getColorPair(theme, props); return { button: { width: '100%', color: colorPairByProps.color, borderRadius: '4px', fontWeight: 'bold' as const, padding: `${theme.spacing(1)} ${theme.spacing(4)}`, border: '1px solid', borderColor: colorPairByProps.borderColor, backgroundColor: colorPairByProps.backgroundColor, position: 'relative' as const, overflow: 'hidden', transition: 'background 400ms', outline: '0', boxShadow: !props.link && !props.transparent && '0 0 0.5rem rgba(0, 0, 0, 0.3)', cursor: 'pointer', gridGap: theme.spacing(1), display: 'grid', gridAutoFlow: 'column', 'span.ripple': { position: 'absolute' as const, borderRadius: '50%', transform: 'scale(0)', animation: `${rippleTransition} 600ms linear`, backgroundColor: 'rgba(255, 255, 255, 0.7)', }, ':disabled': { backgroundColor: theme.palette.neutral, borderColor: theme.palette.darkerNeutral, color: theme.palette.darkerNeutral, cursor: 'not-allowed', }, }, }; }; export const Button = forwardRef< HTMLButtonElement, PropsWithChildren<ButtonProps & ButtonHTMLAttributes<unknown>> >((props, ref) => { const { children, primary = false, error = false, link = false, transparent = false, after, onClick, ...otherProps } = props; const styled = useStyledTheme(styles({ primary, error, link, transparent })); console.log(styled.button.backgroundColor, 'transparent', transparent); const createRipple = useCallback( (event: MouseEvent<HTMLButtonElement>) => { if (!!onClick) { onClick(event); } const button = event.currentTarget; const circle = document.createElement('span'); const diameter = Math.max(button.clientWidth, button.clientHeight); const radius = diameter / 2; circle.style.width = `${diameter}px`; circle.style.height = `${diameter}px`; circle.style.left = `${event.clientX - button.offsetLeft - radius}px`; circle.style.top = `${event.clientY - button.offsetTop - radius}px`; circle.classList.add('ripple'); circle.addEventListener('animationend', () => button.removeChild(circle)); button.appendChild(circle); }, [onClick], ); return ( <button css={styled.button} {...otherProps} ref={ref} onClick={createRipple} > {styled.button.backgroundColor} {children} {!!after && after} </button> ); });