Skip to content

Commit

Permalink
Remove history integration
Browse files Browse the repository at this point in the history
- Expose only the ScrollBehavior class
- Remove explicit history dependencies
  • Loading branch information
taion committed Nov 4, 2016
1 parent 7940ee8 commit 8f1ea39
Show file tree
Hide file tree
Showing 16 changed files with 425 additions and 433 deletions.
4 changes: 2 additions & 2 deletions .babelrc
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
{
"presets": [
"./tools/es2015Preset",
"stage-1"
"./tools/latestPreset",
"stage-2"
],
"plugins": ["dev-expression"],

Expand Down
8 changes: 1 addition & 7 deletions .eslintrc
Original file line number Diff line number Diff line change
@@ -1,12 +1,6 @@
{
"extends": "airbnb-base",
"parser": "babel-eslint",
"extends": "4catalyzer",
"env": {
"browser": true
},
"rules": {
"max-len": [2, 79, {
"ignorePattern": " // eslint-disable-line "
}]
}
}
80 changes: 51 additions & 29 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,74 +1,96 @@
# scroll-behavior [![Travis][build-badge]][build] [![npm][npm-badge]][npm]

Scroll management for [`history`](https://github.com/ReactTraining/history).
Pluggable browser scroll behavior management.

**If you are using [React Router](https://github.com/reactjs/react-router), check out [react-router-scroll](https://github.com/taion/react-router-scroll), which wraps up the scroll management logic here into a router middleware.**
**If you use [React Router](https://github.com/reactjs/react-router), use [react-router-scroll](https://github.com/taion/react-router-scroll), which wraps up the scroll behavior management logic here into a React Router middleware.**

[![Codecov][codecov-badge]][codecov]
[![Discord][discord-badge]][discord]

## Usage

```js
import createHistory from 'history/lib/createBrowserHistory';
import withScroll from 'scroll-behavior';
import ScrollBehavior from 'scroll-behavior';

const history = withScroll(createHistory());
/* ... */

const scrollBehavior = new ScrollBehavior({
addTransitionHook,
stateStorage,
getCurrentLocation,
/* shouldUpdateScroll, */
});

// After a transition:
scrollBehavior.updateScroll(/* prevContext, context */);
```

## Guide

### Installation

```
$ npm i -S history
$ npm i -S scroll-behavior
```

### Scroll behaviors

### Basic usage

Extend your history object using `withScroll`. The extended history object will manage the scroll position for transitions.
Create a `ScrollBehavior` object with the following arguments:
- `addTransitionHook`: this function should take a transition hook function and return an unregister function
- The transition hook function should be called immediately before a transition updates the page
- The unregister function should remove the transition hook when called
- `stateStorage`: this object should implement `read` and `save` methods
- The `save` method should take a location object, a nullable element key, and a truthy value; it should save that value for the duration of the page session
- The `read` method should take a location object and a nullable element key; it should return the value that `save` was called with for that location and element key, or a falsy value if no saved value is available
- `getCurrentLocation`: this function should return the current location object

This object will keep track of the scroll position. Call the `updateScroll` method on this object after transitions to emulate the default browser scroll behavior on page changes.

Call the `stop` method to tear down all listeners.

### Custom scroll behavior

You can customize the scroll behavior by providing a `shouldUpdateScroll` callback when extending the history object. This callback is called with both the previous location and the current location.
You can customize the scroll behavior by providing a `shouldUpdateScroll` callback when constructing the `ScrollBehavior` object. When you call `updateScroll`, you can pass in up to two additional context arguments, which will get passed to this callback.

The callback can return:

You can return:
- a falsy value to suppress updating the scroll position
- a position array of `x` and `y`, such as `[0, 100]`, to scroll to that position
- a truthy value to emulate the browser default scroll behavior

- a falsy value to suppress the scroll update
- a position array such as `[0, 100]` to scroll to that position
- a truthy value to get normal scroll behavior
Assuming we call `updateScroll` with the previous and current location objects:

```js
const history = withScroll(createHistory(), (prevLocation, location) => (
// Don't scroll if the pathname is the same.
!prevLocation || location.pathname !== prevLocation.pathname
));
const scrollBehavior = new ScrollBehavior({
...options,
shouldUpdateScroll: (prevLocation, location) => (
// Don't scroll if the pathname is the same.
!prevLocation || location.pathname !== prevLocation.pathname
),
});
```

```js
const history = withScroll(createHistory(), (prevLocation, location) => (
// Scroll to top when attempting to vist the current path.
prevLocation && location.pathname === prevLocation.pathname ? [0, 0] : true
));
const scrollBehavior = new ScrollBehavior({
...options,
shouldUpdateScroll: (prevLocation, location) => (
// Scroll to top when attempting to vist the current path.
prevLocation && location.pathname === prevLocation.pathname ? [0, 0] : true
),
});
```

### Scrolling elements other than `window`

The `withScroll`-extended history object has a `registerScrollElement` method. This method registers an element other than `window` to have managed scroll behavior on transitions. Each of these elements needs to be given a unique key at registration time, and can be given an optional `shouldUpdateScroll` callback that behaves as above.
Call the `registerElement` method to register an element other than `window` to have managed scroll behavior. Each of these elements needs to be given a unique key at registration time, and can be given an optional `shouldUpdateScroll` callback that behaves as above. This method should also be called with the current context per `updateScroll` above, if applicable, to set up the element's initial scroll position.

```js
const history = withScroll(createHistory(), () => false);
history.listen(listener);

history.registerScrollElement(
key, element, shouldUpdateScroll
scrollBehavior.registerScrollElement(
key, element, shouldUpdateScroll, context,
);
```

The `registerScrollElement` method returns an `unregister` function that you can use to explicitly unregister the scroll behavior on the element, if necessary. In general, you will not need to do this, as `withScroll` will perform all necessary cleanup on removal of the last history listener.
To unregister an element, call the `unregisterElement` method with the key used to register that element.

[build-badge]: https://img.shields.io/travis/taion/scroll-behavior/master.svg
[build]: https://travis-ci.org/taion/scroll-behavior
Expand Down
4 changes: 2 additions & 2 deletions karma.conf.js
Original file line number Diff line number Diff line change
@@ -1,10 +1,10 @@
const webpack = require('webpack'); // eslint-disable-line import/no-extraneous-dependencies

module.exports = config => {
module.exports = (config) => {
const { env } = process;

config.set({
frameworks: ['mocha'],
frameworks: ['mocha', 'sinon-chai'],

files: ['test/index.js'],

Expand Down
51 changes: 25 additions & 26 deletions package.json
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
{
"name": "scroll-behavior",
"version": "0.8.2",
"description": "Scroll management for history",
"description": "Pluggable browser scroll behavior management",
"files": [
"es",
"lib"
Expand All @@ -24,8 +24,6 @@
"url": "git+https://github.com/taion/scroll-behavior.git"
},
"keywords": [
"history",
"location",
"scroll"
],
"author": "Jimmy Jia",
Expand All @@ -35,40 +33,41 @@
},
"homepage": "https://github.com/taion/scroll-behavior#readme",
"dependencies": {
"dom-helpers": "^2.4.0",
"dom-helpers": "^3.0.0",
"invariant": "^2.2.1"
},
"peerDependencies": {
"history": "^1.12.1 || ^2.0.0"
},
"devDependencies": {
"babel-cli": "^6.11.4",
"babel-core": "^6.13.2",
"babel-eslint": "^6.1.2",
"babel-loader": "^6.2.4",
"babel-cli": "^6.18.0",
"babel-core": "^6.18.2",
"babel-eslint": "^7.1.0",
"babel-loader": "^6.2.7",
"babel-plugin-add-module-exports": "^0.2.1",
"babel-plugin-dev-expression": "^0.2.1",
"babel-plugin-istanbul": "^1.0.3",
"babel-polyfill": "^6.13.0",
"babel-preset-es2015": "^6.13.2",
"babel-preset-stage-1": "^6.13.0",
"babel-plugin-istanbul": "^2.0.3",
"babel-polyfill": "^6.16.0",
"babel-preset-latest": "^6.16.0",
"babel-preset-stage-2": "^6.18.0",
"chai": "^3.5.0",
"codecov": "^1.0.1",
"cross-env": "^2.0.0",
"eslint": "^3.2.2",
"eslint-config-airbnb-base": "^5.0.1",
"eslint-plugin-import": "^1.12.0",
"cross-env": "^3.1.3",
"dirty-chai": "^1.2.2",
"eslint": "^3.9.1",
"eslint-config-4catalyzer": "^0.1.3",
"eslint-plugin-import": "^1.16.0",
"history": "^2.1.2",
"karma": "^1.1.2",
"karma-chrome-launcher": "^1.0.1",
"karma": "^1.3.0",
"karma-chrome-launcher": "^2.0.0",
"karma-coverage": "^1.1.1",
"karma-firefox-launcher": "^1.0.0",
"karma-mocha": "^1.1.1",
"karma-mocha-reporter": "^2.1.0",
"karma-mocha": "^1.2.0",
"karma-mocha-reporter": "^2.2.0",
"karma-sinon-chai": "^1.2.4",
"karma-sourcemap-loader": "^0.3.7",
"karma-webpack": "^1.7.0",
"mocha": "^3.0.1",
"karma-webpack": "^1.8.0",
"mocha": "^3.1.2",
"rimraf": "^2.5.4",
"webpack": "^1.13.1"
"sinon": "^1.17.6",
"sinon-chai": "^2.8.0",
"webpack": "^1.13.3"
}
}
Loading

0 comments on commit 8f1ea39

Please sign in to comment.