diff --git a/package-lock.json b/package-lock.json index c6076f7714..67c546eec5 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,6 +1,6 @@ { "name": "@outsystems/react-select", - "version": "2.4.2-os20", + "version": "2.4.2-os21", "lockfileVersion": 1, "requires": true, "dependencies": { diff --git a/package.json b/package.json index 293302ff83..10b07f0cf9 100644 --- a/package.json +++ b/package.json @@ -137,5 +137,5 @@ }, "sideEffects": false, "typings": "types/index.d.ts", - "version": "2.4.2-os20" + "version": "2.4.2-os21" } diff --git a/src/internal/ScrollCaptor.js b/src/internal/ScrollCaptor.js index 0a913e7d55..82457aa180 100644 --- a/src/internal/ScrollCaptor.js +++ b/src/internal/ScrollCaptor.js @@ -18,41 +18,72 @@ class ScrollCaptor extends Component { scrollTarget: HTMLElement; touchStart: number; + // Scroll element previous state variables + previousScrollTop: number = 0; + previousScrollHeight: number = 0; + previousClientHeight: number = 0; + + // Event listener flags + listeningToScroll: boolean = false; + listeningToTouchStart: boolean = false; + listeningToTouchMove: boolean = false; + componentDidMount() { - this.startListening(this.scrollTarget); + this.previousScrollHeight = this.scrollTarget.scrollHeight; + this.previousClientHeight = this.scrollTarget.previousClientHeight; + this.refreshListening(this.scrollTarget); + } + + componentDidUpdate() { + if (this.previousScrollHeight !== this.scrollTarget.scrollHeight || this.previousClientHeight !== this.scrollTarget.clientHeight) { + this.previousScrollHeight = this.scrollTarget.scrollHeight; + this.previousClientHeight = this.scrollTarget.clientHeight; + this.refreshListening(this.scrollTarget); + } } + componentWillUnmount() { this.stopListening(this.scrollTarget); } - startListening(el: HTMLElement) { - // bail early if no scroll available - if (!el) return; - if (el.scrollHeight <= el.clientHeight) return; + refreshListening(el: HTMLElement) { + // bail early if no scroll available or already listening to all events + if (!el || el.scrollHeight <= el.clientHeight) { + this.stopListening(el); + return; + } + + if (this.listeningToScroll && this.listeningToTouchStart && this.listeningToTouchMove) { + // already listenning to everything + return; + } // all the if statements are to appease Flow 😢 - if (typeof el.addEventListener === 'function') { - el.addEventListener('wheel', this.onWheel, false); + if (typeof el.addEventListener === 'function' && !this.listeningToScroll) { + el.addEventListener('scroll', this.onScroll, false); + this.listeningToScroll = true; } - if (typeof el.addEventListener === 'function') { + if (typeof el.addEventListener === 'function' && !this.listeningToTouchStart) { el.addEventListener('touchstart', this.onTouchStart, false); + this.listeningToTouchStart = true; } - if (typeof el.addEventListener === 'function') { + if (typeof el.addEventListener === 'function' && !this.listeningToTouchMove) { el.addEventListener('touchmove', this.onTouchMove, false); + this.listeningToTouchMove = true; } } stopListening(el: HTMLElement) { - // bail early if no scroll available - if (el.scrollHeight <= el.clientHeight) return; - // all the if statements are to appease Flow 😢 - if (typeof el.removeEventListener === 'function') { - el.removeEventListener('wheel', this.onWheel, false); + if (this.listeningToScroll) { + el.removeEventListener('scroll', this.onScroll, false); + this.listeningToScroll = false; } - if (typeof el.removeEventListener === 'function') { + if (this.listeningToTouchStart) { el.removeEventListener('touchstart', this.onTouchStart, false); + this.listeningToTouchStart = false; } - if (typeof el.removeEventListener === 'function') { + if (this.listeningToTouchMove) { el.removeEventListener('touchmove', this.onTouchMove, false); + this.listeningToTouchMove = false; } } @@ -108,8 +139,10 @@ class ScrollCaptor extends Component { } }; - onWheel = (event: SyntheticWheelEvent) => { - this.handleEventDelta(event, event.deltaY); + onScroll = (event: SyntheticEvent) => { + const deltaY = event.currentTarget.scrollTop - this.previousScrollTop; + this.previousScrollTop = event.currentTarget.scrollTop; + this.handleEventDelta(event, deltaY); }; onTouchStart = (event: SyntheticTouchEvent) => { // set touch start so we can calculate touchmove delta