From 67519f37bffea7efb45d24d25e2b269520450c7c Mon Sep 17 00:00:00 2001 From: Anton Korzunov Date: Mon, 11 Mar 2019 09:46:08 +1100 Subject: [PATCH] feat: support shards --- src/component.tsx | 58 ++++++++++++++++++++++++++++++++++++----------- 1 file changed, 45 insertions(+), 13 deletions(-) diff --git a/src/component.tsx b/src/component.tsx index 1d7f6e4..5680fb1 100644 --- a/src/component.tsx +++ b/src/component.tsx @@ -6,12 +6,14 @@ import {aggressive} from './aggresiveCapture'; export const getTouchY = (event: TouchEvent) => event.changedTouches ? event.changedTouches[0].clientY : 0; -export interface RemoveScrollProps { +export interface IRemoveScrollProps { noIsolation?: boolean; forwardProps?: boolean; enabled?: boolean; className?: string; removeScrollBar?: boolean; + + shards?: Array>; } const classNames = { @@ -19,19 +21,20 @@ const classNames = { zeroRight: zeroRightClassName, }; -export class RemoveScroll extends React.Component { - private shouldPreventQueue: Array<{ name: string, delta: number, target: any, should: boolean }> = []; - private touchStart = 0; - private ref = React.createRef(); - +export class RemoveScroll extends React.Component { public static classNames = classNames; - public static stack: Array = []; - static defaultProps = { + public static defaultProps = { enabled: true, removeScrollBar: true, }; + private static stack: RemoveScroll[] = []; + + private shouldPreventQueue: Array<{ name: string, delta: number, target: any, should: boolean }> = []; + private touchStart = 0; + private ref = React.createRef(); + componentDidMount() { RemoveScroll.stack.push(this); this.componentDidUpdate({enabled: false}) @@ -56,6 +59,7 @@ export class RemoveScroll extends React.Component { if (typeof document !== 'undefined') { document.addEventListener('wheel', this.shouldPrevent, aggressive); document.addEventListener('touchmove', this.shouldPrevent, aggressive); + document.addEventListener('touchstart', this.scrollTouchStart, aggressive); } } @@ -63,9 +67,21 @@ export class RemoveScroll extends React.Component { if (typeof window !== 'undefined') { document.removeEventListener('wheel', this.shouldPrevent, aggressive as any); document.removeEventListener('touchmove', this.shouldPrevent, aggressive as any); + document.removeEventListener('touchstart', this.scrollTouchStart, aggressive as any); } } + shouldCancelEvent(event: any, parent: HTMLElement) { + switch (event.type) { + case 'wheel': + case 'scroll': + return handleScroll(parent, event, event.deltaY) + case 'touchmove': + return handleScroll(parent, event, this.touchStart - getTouchY(event)); + } + return false; + }; + shouldPrevent = (event: any) => { const stack = RemoveScroll.stack.filter(el => el.props.enabled); if (!stack.length || stack[stack.length - 1] !== this) { @@ -76,8 +92,25 @@ export class RemoveScroll extends React.Component { const sourceEvent = this.shouldPreventQueue.filter( (e: any) => e.name === event.type && e.delta === delta && e.target === event.target )[0]; - if ((!sourceEvent && !this.props.noIsolation) || (sourceEvent && sourceEvent.should)) { + // self event, and should be canceled + if (sourceEvent && sourceEvent.should) { event.preventDefault(); + return; + } + // outside or shard event + if (!sourceEvent) { + const shardNodes = (this.props.shards || []) + .map(({current}) => current) + .filter(Boolean) + .filter(node => node.contains(event.target)); + + const shouldStop = shardNodes.length > 0 + ? this.shouldCancelEvent(event, shardNodes[0]) + : !this.props.noIsolation + + if (shouldStop) { + event.preventDefault(); + } } }; @@ -89,16 +122,16 @@ export class RemoveScroll extends React.Component { }, 1); }; - scrollTouchStart = (event: TouchEvent) => { + scrollTouchStart = (event: any) => { this.touchStart = getTouchY(event); }; scrollWheel = (event: any) => { - this.shouldCancel(event.type, event.deltaY, event.target, handleScroll(this.ref.current as any, event, event.deltaY)); + this.shouldCancel(event.type, event.deltaY, event.target, this.shouldCancelEvent(event, this.ref.current as any)); }; scrollTouchMove = (event: TouchEvent) => { - this.shouldCancel(event.type, getTouchY(event), event.target, handleScroll(this.ref.current as any, event, this.touchStart - getTouchY(event))); + this.shouldCancel(event.type, getTouchY(event), event.target, this.shouldCancelEvent(event, this.ref.current as any)); }; render() { @@ -108,7 +141,6 @@ export class RemoveScroll extends React.Component { ref: this.ref, onScrollCapture: this.scrollWheel, onWheelCapture: this.scrollWheel, - onTouchStartCapture: this.scrollTouchStart, onTouchMoveCapture: this.scrollTouchMove, }; return (