diff --git a/CHANGELOG.md b/CHANGELOG.md index b3c70dd..b1115d8 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,4 +1,7 @@ ## CHANGELOG +### 0.7.3 +Changed to css transforms for scrolling, instead of scrollTop + ### 0.1.0 First commit diff --git a/README.md b/README.md index 695a398..de247af 100644 --- a/README.md +++ b/README.md @@ -11,13 +11,6 @@ Uses `react-spring` for butter smooth enhanced scrolling experience npm install react-skroll --save ``` -## UMD -``` - - -``` -(Module exposed as `ReactSkroll`) - ## Demo [Codepen Demo](http://codepen.io/du5rte/pen/KrGjEm) diff --git a/demo/Demo.js b/demo/Demo.js index d899e42..8ec0cf2 100644 --- a/demo/Demo.js +++ b/demo/Demo.js @@ -61,9 +61,9 @@ export default class Demo extends Component { > { colors.map(({ name, color }, index) => -
+
-

{round(scroll.positionRatio)}

+

{round(this.state.scroll.positionRatio)}

@@ -71,7 +71,7 @@ export default class Demo extends Component {

{'{'}

{ - Object.entries(scroll) + Object.entries(this.state.scroll) .filter(([key, value]) => typeof value !== 'function') .filter(([key, value]) => typeof value !== 'object') .map(([key, value]) => diff --git a/demo/index.css b/demo/index.css index 4d6d5c4..f94eb93 100644 --- a/demo/index.css +++ b/demo/index.css @@ -41,6 +41,7 @@ nav { left: 0; width: 100%; padding: 0.5em; + z-index: 10; } h1 { diff --git a/package-lock.json b/package-lock.json index c85221b..ed15e95 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,6 +1,6 @@ { - "name": "react-skroll", - "version": "0.7.1", + "name": "@arturmiglio/react-skroll", + "version": "0.7.5", "lockfileVersion": 1, "requires": true, "dependencies": { @@ -2428,7 +2428,8 @@ "core-js": { "version": "2.6.1", "resolved": "https://registry.npmjs.org/core-js/-/core-js-2.6.1.tgz", - "integrity": "sha512-L72mmmEayPJBejKIWe2pYtGis5r0tQ5NaJekdhyXgeMQTpJoBsH0NL4ElY2LfSoV15xeQWKQ+XTTOZdyero5Xg==" + "integrity": "sha512-L72mmmEayPJBejKIWe2pYtGis5r0tQ5NaJekdhyXgeMQTpJoBsH0NL4ElY2LfSoV15xeQWKQ+XTTOZdyero5Xg==", + "dev": true }, "core-util-is": { "version": "1.0.2", @@ -3681,15 +3682,13 @@ "version": "1.0.0", "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.0.tgz", "integrity": "sha1-ibTRmasr7kneFk6gK4nORi1xt2c=", - "dev": true, - "optional": true + "dev": true }, "brace-expansion": { "version": "1.1.11", "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz", "integrity": "sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==", "dev": true, - "optional": true, "requires": { "balanced-match": "^1.0.0", "concat-map": "0.0.1" @@ -3706,22 +3705,19 @@ "version": "1.1.0", "resolved": "https://registry.npmjs.org/code-point-at/-/code-point-at-1.1.0.tgz", "integrity": "sha1-DQcLTQQ6W+ozovGkDi7bPZpMz3c=", - "dev": true, - "optional": true + "dev": true }, "concat-map": { "version": "0.0.1", "resolved": "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz", "integrity": "sha1-2Klr13/Wjfd5OnMDajug1UBdR3s=", - "dev": true, - "optional": true + "dev": true }, "console-control-strings": { "version": "1.1.0", "resolved": "https://registry.npmjs.org/console-control-strings/-/console-control-strings-1.1.0.tgz", "integrity": "sha1-PXz0Rk22RG6mRL9LOVB/mFEAjo4=", - "dev": true, - "optional": true + "dev": true }, "core-util-is": { "version": "1.0.2", @@ -3852,8 +3848,7 @@ "version": "2.0.3", "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.3.tgz", "integrity": "sha1-Yzwsg+PaQqUC9SRmAiSA9CCCYd4=", - "dev": true, - "optional": true + "dev": true }, "ini": { "version": "1.3.5", @@ -3867,7 +3862,6 @@ "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-1.0.0.tgz", "integrity": "sha1-754xOG8DGn8NZDr4L95QxFfvAMs=", "dev": true, - "optional": true, "requires": { "number-is-nan": "^1.0.0" } @@ -3884,7 +3878,6 @@ "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.0.4.tgz", "integrity": "sha512-yJHVQEhyqPLUTgt9B83PXu6W3rx4MvvHvSUvToogpwoGDOUQ+yDrR0HRot+yOCdCO7u4hX3pWft6kWBBcqh0UA==", "dev": true, - "optional": true, "requires": { "brace-expansion": "^1.1.7" } @@ -3893,15 +3886,13 @@ "version": "0.0.8", "resolved": "https://registry.npmjs.org/minimist/-/minimist-0.0.8.tgz", "integrity": "sha1-hX/Kv8M5fSYluCKCYuhqp6ARsF0=", - "dev": true, - "optional": true + "dev": true }, "minipass": { "version": "2.2.4", "resolved": "https://registry.npmjs.org/minipass/-/minipass-2.2.4.tgz", "integrity": "sha512-hzXIWWet/BzWhYs2b+u7dRHlruXhwdgvlTMDKC6Cb1U7ps6Ac6yQlR39xsbjWJE377YTCtKwIXIpJ5oP+j5y8g==", "dev": true, - "optional": true, "requires": { "safe-buffer": "^5.1.1", "yallist": "^3.0.0" @@ -3922,7 +3913,6 @@ "resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-0.5.1.tgz", "integrity": "sha1-MAV0OOrGz3+MR2fzhkjWaX11yQM=", "dev": true, - "optional": true, "requires": { "minimist": "0.0.8" } @@ -4011,8 +4001,7 @@ "version": "1.0.1", "resolved": "https://registry.npmjs.org/number-is-nan/-/number-is-nan-1.0.1.tgz", "integrity": "sha1-CXtgK1NCKlIsGvuHkDGDNpQaAR0=", - "dev": true, - "optional": true + "dev": true }, "object-assign": { "version": "4.1.1", @@ -4026,7 +4015,6 @@ "resolved": "https://registry.npmjs.org/once/-/once-1.4.0.tgz", "integrity": "sha1-WDsap3WWHUsROsF9nFC6753Xa9E=", "dev": true, - "optional": true, "requires": { "wrappy": "1" } @@ -4164,7 +4152,6 @@ "resolved": "https://registry.npmjs.org/string-width/-/string-width-1.0.2.tgz", "integrity": "sha1-EYvfW4zcUaKn5w0hHgfisLmxB9M=", "dev": true, - "optional": true, "requires": { "code-point-at": "^1.0.0", "is-fullwidth-code-point": "^1.0.0", diff --git a/package.json b/package.json index 902c6e2..492215c 100644 --- a/package.json +++ b/package.json @@ -1,7 +1,7 @@ { - "name": "react-skroll", + "name": "@arturmiglio/react-skroll", "description": "Reactive Scrolling", - "version": "0.7.3", + "version": "0.8.0", "main": "lib/index.js", "scripts": { "clean": "rm -rf dist lib && mkdir dist lib", @@ -16,14 +16,14 @@ "test": "jest" }, "license": "MIT", - "homepage": "https://github.com/du5rte/react-skroll#readme", + "homepage": "https://github.com/arturmiglio/react-skroll#readme", "repository": { "type": "git", - "url": "git+https://github.com/du5rte/react-skroll.git" + "url": "git+https://github.com/arturmiglio/react-skroll.git" }, - "author": "Duarte Monteiro (http://du5rte.com)", + "author": "Artur Miglio (http://arturmiglio.com)", "bugs": { - "url": "https://github.com/du5rte/react-skroll/issues" + "url": "https://github.com/arturmiglio/react-skroll/issues" }, "keywords": [ "react", @@ -70,5 +70,8 @@ "webpack": "^4.28.0", "webpack-cli": "^3.1.2", "webpack-dev-server": "^3.1.10" + }, + "directories": { + "lib": "lib" } } diff --git a/src/Scroller.js b/src/Scroller.js index 8ae039f..559d182 100644 --- a/src/Scroller.js +++ b/src/Scroller.js @@ -10,6 +10,9 @@ import scrollInitalState from './scrollInitalState' import nodeToScrollState from './nodeToScrollState' import nodeChildrenToScrollState from './nodeChildrenToScrollState' +const START_TRANSLATE_3D = 'translate3d(0px,0px,0px)' +const START_TRANSLATE = 'translate(0px,0px)' + const View = Globals.defaultElement export default class Scroller extends Component { @@ -26,17 +29,19 @@ export default class Scroller extends Component { scroll: scrollInitalState } + this.targetY = 0 + // debounce is used to mimiques start, move and end events that don't have this functions this.handleScrollStart = debounce(500, true, this.handleScrollStart) this.handleResizeMove = throttle(50, this.handleResizeMove) - this.handleScrollEnd = debounce(500, this.handleScrollEnd) + this.handleScrollEnd = debounce(50, this.handleScrollEnd) this.handleWheelStart = debounce(100, true, this.handleWheelStart) this.handleWheelEnd = debounce(100, this.handleWheelEnd) this.handleResizeStart = debounce(250, true, this.handleResizeStart) this.handleResizeEnd = debounce(250, this.handleResizeEnd) - this.scrollToPrevDebounced = debounce(250, true, this.scrollToPrev) - this.scrollToNextDebounced = debounce(250, true, this.scrollToNext) + this.scrollToPrevThrottled = throttle(700, true, this.scrollToPrev) + this.scrollToNextThrottled = throttle(700, true, this.scrollToNext) this.controller = new Controller({ scroll: 0 }) } @@ -50,7 +55,7 @@ export default class Scroller extends Component { // add component to resize observer to detect changes on resize this.resizeObserver = new ResizeObserver((entries, observer) => { - if (this.state.ready) { + if (this.state.scroll.ready) { this.handleResize() } else { this.setStateScroll({ @@ -147,8 +152,10 @@ export default class Scroller extends Component { findChildOnView = () => { const { children } = this.state.scroll + // return child on view, or the last one (when resizing ends up outside of the target) + const onView = children.find((child) => child.onView) || children[children.length - 1] - return children.find((child) => child.onView) + return onView } findChildIndexOnView = () => { @@ -159,8 +166,17 @@ export default class Scroller extends Component { scrollToPosition = (position) => { this.controller.update({ - scroll: position, - onFrame: ({ scroll }) => (this.target.scrollTop = scroll), + scroll: -position, + config: config.default, + onFrame: ({ scroll }) => { + this.setState((prevState) => ({ + scroll: { + ...prevState.scroll, + position: Math.abs(scroll), + } + }), this.handleScroll()) + return this.target.style.transform = `translate3d(0, ${scroll}px, 0)` + }, }) } @@ -218,6 +234,7 @@ export default class Scroller extends Component { let newPosition = this.findChildOnView().start this.scrollToPosition(newPosition) + this.targetY = newPosition } handleScroll = () => { @@ -263,10 +280,6 @@ export default class Scroller extends Component { handleWheel = (e) => { const { autoScroll } = this.props - if (autoScroll) { - e.preventDefault() - } - this.handleWheelStart(e) this.handleWheelMove(e) this.handleWheelEnd(e) @@ -285,13 +298,15 @@ export default class Scroller extends Component { const movingUpwards = e.deltaY > 0 const movingDownwards = e.deltaY < 0 - if (movingDownwards) this.scrollToPrevDebounced() - if (movingUpwards) this.scrollToNextDebounced() + if (movingDownwards) this.scrollToPrevThrottled() + if (movingUpwards) this.scrollToNextThrottled() } } handleWheelMove = (e) => { - const { autoScroll } = this.props + const { autoScroll, autoFrame } = this.props + const { scroll } = this.state + const { viewHeight, scrollHeight } = scroll if (autoScroll) { const prev = this.state.deltaY @@ -304,26 +319,33 @@ export default class Scroller extends Component { const movingDownwards = next < 0 if (movingDownwards) { - this.scrollToPrevDebounced() + this.scrollToPrevThrottled() } if (movingUpwards) { - this.scrollToNextDebounced() + this.scrollToNextThrottled() } } + } else { + this.targetY += e.deltaY + this.targetY = Math.max(0, Math.min(this.targetY, scrollHeight - viewHeight)) + + this.scrollToPosition(this.targetY) } this.setState({ deltaY: e.deltaY }) } handleWheelEnd = (e) => { - const { autoFrame } = this.state.scroll + const { autoFrame } = this.props this.setStateScrollEnd({ wheeling: false, deltaY: null }) - if (autoFrame) this.scrollToActive() + if (autoFrame) { + this.scrollToActive() + } } handleTouchStart = (e) => { @@ -334,12 +356,15 @@ export default class Scroller extends Component { } handleTouchMove = (e) => { - const { touches, originalPosition } = this.state.scroll + const { autoScroll } = this.props + const { touches, originalPosition, moving } = this.state.scroll let distanceFromTouchStart = e.changedTouches[0].clientY - touches[0].clientY let touchPosition = originalPosition - distanceFromTouchStart - this.scrollToPosition(touchPosition) + if (!autoScroll) { + this.scrollToPosition(touchPosition) + } } handleTouchEnd = (e) => { @@ -347,12 +372,16 @@ export default class Scroller extends Component { const timeLapse = Date.now() - timeStamp - if (timeLapse < 200) { + if (timeLapse < 500) { const movingUpwards = e.changedTouches[0].clientY < touches[0].clientY const movingDownwards = e.changedTouches[0].clientY > touches[0].clientY - if (movingDownwards) this.scrollToPrev() - if (movingUpwards) this.scrollToNext() + if (movingDownwards) { + this.scrollToPrevThrottled() + } + if (movingUpwards) { + this.scrollToNextThrottled() + } } else { this.scrollToActive() } @@ -378,6 +407,7 @@ export default class Scroller extends Component { scroll={scroll} />