1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162 |
- import {cloneElement, PureComponent} from 'react';
- type ClickProps<T> = {
- onClick?: React.HTMLAttributes<T>['onClick'];
- };
- type Props<T extends HTMLElement> = ClickProps<T> & {
- children: React.ReactElement<T>;
- };
- type State = {
- startCoords?: [number, number];
- };
- /**
- * Does not fire the onclick event if the mouse has moved outside of the
- * original click location upon release.
- *
- * <StrictClick onClick={this.onClickHandler}>
- * <button>Some button</button>
- * </StrictClick>
- */
- class StrictClick<T extends HTMLElement> extends PureComponent<Props<T>, State> {
- static MAX_DELTA_X = 10;
- static MAX_DELTA_Y = 10;
- handleMouseDown = ({screenX, screenY}: React.MouseEvent<T>) =>
- this.setState({startCoords: [screenX, screenY]});
- handleMouseClick = (evt: React.MouseEvent<T>) => {
- if (!this.props.onClick) {
- return;
- }
- // Click happens if mouse down/up in same element - click will not fire if
- // either initial mouse down OR final mouse up occurs in different element
- const [x, y] = this.state.startCoords!;
- const deltaX = Math.abs(evt.screenX - x);
- const deltaY = Math.abs(evt.screenY - y);
- // If mouse hasn't moved more than 10 pixels in either Y or X direction,
- // fire onClick
- if (deltaX < StrictClick.MAX_DELTA_X && deltaY < StrictClick.MAX_DELTA_Y) {
- this.props.onClick(evt);
- }
- this.setState({startCoords: undefined});
- };
- render() {
- // Bail out early if there is no onClick handler
- if (!this.props.onClick) {
- return this.props.children;
- }
- return cloneElement(this.props.children, {
- onMouseDown: this.handleMouseDown,
- onClick: this.handleMouseClick,
- });
- }
- }
- export default StrictClick;
|