import React, { Component } from 'react'; import { autobind } from 'core-decorators'; import mergeEventHandlers from '@coffee-shope/merge-event-handlers'; import { keyframes } from '@emotion/core'; import styled from '@emotion/styled'; import { any } from 'prop-types'; interface RenderProps { ripple: React.ReactElement; eventHandlers: { onClick: (e: any) => void }; mergeEventHandlers: (old: object) => object; } interface Props { dark?: boolean; children: ({ ripple, eventHandlers, mergeEventHandlers }: RenderProps) => React.ReactElement; } interface State { ripple: null | { id: number; left: number; top: number }; } const rippleAnimation = keyframes` 0% { opacity: .5; transform: scale(1); } 100% { opacity: 0; transform: scale(50); } `; const RippleSpan = styled.span<{ left: number; top: number; dark?: boolean }>` position: absolute !important; width: 30px; height: 30px; border-radius: 50%; opacity: 0; pointer-events: none; animation: ${rippleAnimation} 1.2s ease; left: ${props => `${props.left}px`}; top: ${props => `${props.top}px`}; background-color: ${props => (props.dark ? 'rgba(0,0,0,.5)!important' : '#fff!important')}; `; @autobind class Ripple extends Component { state: State = { ripple: null, }; isRippleMounted = false; componentDidMount() { if (typeof this.props.children !== 'function') { throw new Error('Ripple takes a function as children.'); } this.isRippleMounted = true; } componentWillUnmount() { this.isRippleMounted = false; } Ripple() { const { ripple } = this.state; const { dark } = this.props; if (!ripple) { return null; } const { id, left, top } = ripple; return ( ); } removeRipple(id: number) { setTimeout(() => { const { ripple } = this.state; if (!this.isRippleMounted || !ripple) { return; } if (ripple.id === id) { this.setState({ ripple: null }); } }, 1500); } onClick(event: any) { const id = Date.now(); this.setState( { ripple: { id, left: event.nativeEvent.offsetX - event.target.offsetLeft, top: event.nativeEvent.offsetY - event.target.offsetTop, }, }, () => this.removeRipple(id), ); } getEventHandlers() { return { onClick: this.onClick }; } render() { const ripple = ; const eventHandlers = this.getEventHandlers(); return (
{this.props.children({ ripple, eventHandlers, mergeEventHandlers: mergeEventHandlers(eventHandlers), })}
); } } export { Ripple };