├── .eslintrc
├── .gitignore
├── .npmignore
├── LICENSE
├── README.md
├── dist
└── react-smooth-scrollbar.js
├── gulpfile.js
├── package-lock.json
├── package.json
├── src
└── react-smooth-scrollbar.js
├── test
├── index.html
├── main.js
├── style.css
└── your_diary.jpg
├── webpack.dev.config.js
└── webpack.prod.config.js
/.eslintrc:
--------------------------------------------------------------------------------
1 | {
2 | "parser": "babel-eslint",
3 | "ecmaFeatures": {
4 | "arrowFunctions": true,
5 | "blockBindings": true,
6 | "classes": true,
7 | "defaultParams": true,
8 | "modules": true,
9 | "objectLiteralShorthandMethods": true,
10 | "objectLiteralShorthandProperties": true,
11 | "restParams": true,
12 | "spread": true,
13 | "superInFunctions": true,
14 | "templateStrings": true
15 | },
16 | "env": {
17 | "browser": true,
18 | "es6": true
19 | },
20 | "rules": {
21 | "accessor-pairs": 1,
22 | "curly": [1, "multi-line"],
23 | "quotes": [1, "single"],
24 | "new-cap": [2, {"newIsCap": true, "capIsNew": false}],
25 | "no-mixed-spaces-and-tabs": [2, "smart-tabs"],
26 | "no-var": 2,
27 | "no-else-return": 2,
28 | "semi": 1,
29 | "no-unused-vars": 1,
30 | "no-multiple-empty-lines": [1, {"max": 2}],
31 | "no-underscore-dangle": 0,
32 | "constructor-super": 2,
33 | "no-this-before-super": 2,
34 | "no-dupe-class-members": 2,
35 | "object-shorthand": 1,
36 | "prefer-arrow-callback": 1,
37 | "prefer-spread": 1,
38 | }
39 | }
40 |
--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------
1 | # Logs
2 | logs
3 | *.log
4 | npm-debug.log*
5 |
6 | # Runtime data
7 | pids
8 | *.pid
9 | *.seed
10 |
11 | # Directory for instrumented libs generated by jscoverage/JSCover
12 | lib-cov
13 |
14 | # Coverage directory used by tools like istanbul
15 | coverage
16 |
17 | # Grunt intermediate storage (http://gruntjs.com/creating-plugins#storing-task-files)
18 | .grunt
19 |
20 | # node-waf configuration
21 | .lock-wscript
22 |
23 | # Compiled binary addons (http://nodejs.org/api/addons.html)
24 | build/Release
25 |
26 | # Dependency directory
27 | node_modules
28 |
29 | # Optional npm cache directory
30 | .npm
31 |
32 | # Optional REPL history
33 | .node_repl_history
34 |
35 | # Build
36 | .tmp
--------------------------------------------------------------------------------
/.npmignore:
--------------------------------------------------------------------------------
1 | .tmp/
2 | test/
--------------------------------------------------------------------------------
/LICENSE:
--------------------------------------------------------------------------------
1 | The MIT License (MIT)
2 |
3 | Copyright (c) 2016 Dolphin Wood
4 |
5 | Permission is hereby granted, free of charge, to any person obtaining a copy
6 | of this software and associated documentation files (the "Software"), to deal
7 | in the Software without restriction, including without limitation the rights
8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9 | copies of the Software, and to permit persons to whom the Software is
10 | furnished to do so, subject to the following conditions:
11 |
12 | The above copyright notice and this permission notice shall be included in all
13 | copies or substantial portions of the Software.
14 |
15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21 | SOFTWARE.
22 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # react-smooth-scrollbar
2 |
3 | [smooth-scrollbar](https://github.com/idiotWu/smooth-scrollbar) for react projects.
4 |
5 | ## Requirements
6 |
7 | React 0.14+
8 |
9 | ## Install
10 |
11 | ```
12 | npm install react-smooth-scrollbar smooth-scrollbar --save
13 | ```
14 |
15 | ## Demo
16 |
17 | [http://idiotwu.github.io/react-smooth-scrollbar/](http://idiotwu.github.io/react-smooth-scrollbar/)
18 |
19 | ## Usage
20 |
21 | ```js
22 | import React from 'react';
23 | import ReactDOM from 'react-dom';
24 | import Scrollbar from 'react-smooth-scrollbar';
25 |
26 | class App extends React.Component {
27 | render() {
28 | return (
29 |
40 | your contents here...
41 |
42 | );
43 | }
44 | }
45 |
46 | ReactDOM.render( , document.body);
47 | ```
48 |
49 | ### Available Options
50 |
51 | | parameter | type | default | description |
52 | | :--------: | :--: | :-----: | :---------- |
53 | | damping | `number` | `0.1` | Momentum reduction damping factor, a float value between `(0, 1)`. The lower the value is, the more smooth the scrolling will be (also the more paint frames). |
54 | | thumbMinSize | `number` | `20` | Minimal size for scrollbar thumbs. |
55 | | renderByPixels | `boolean` | `true` | Render every frame in integer pixel values, set to `true` to improve scrolling performance. |
56 | | alwaysShowTracks | `boolean` | `false` | Keep scrollbar tracks visible. |
57 | | continuousScrolling | `boolean` | `true` | Set to `true` to allow outer scrollbars continue scrolling when current scrollbar reaches edge. |
58 | | wheelEventTarget | `EventTarget` | `null` | Element to be used as a listener for mouse wheel scroll events. By default, the container element is used. This option will be useful for dealing with fixed elements. |
59 | | plugins | `object` | `{}` | Options for plugins, see [Plugin System](https://github.com/idiotWu/smooth-scrollbar/blob/master/docs/plugin.md). |
60 |
61 |
62 | **Confusing with the option field? Try edit tool [here](http://idiotwu.github.io/smooth-scrollbar/)!**
63 |
64 | ## Using Scrollbar Plugins
65 |
66 | ```js
67 | import { Component } from 'react';
68 | import PropTypes from 'prop-types';
69 | import SmoothScrollbar from 'smooth-scrollbar';
70 | import OverscrollPlugin from 'smooth-scrollbar/plugins/overscroll';
71 | import Scrollbar from 'react-smooth-scrollbar';
72 |
73 | SmoothScrollbar.use(OverscrollPlugin);
74 |
75 | class App2 extends Component {
76 | render() {
77 | return (
78 | ...
79 | );
80 | }
81 | }
82 | ```
83 |
84 | ## Get Scrollbar Instance
85 |
86 | 1. Use `ref` in **parent component**:
87 |
88 | ```javascript
89 | class Parent extends React.Component {
90 | componentDidMount() {
91 | const { scrollbar } = this.$container;
92 | }
93 |
94 | render() {
95 | return (
96 | this.$container = c}>
97 | your content...
98 |
99 | );
100 | }
101 | }
102 | ```
103 |
104 | 2. Use `Context` in **child component**:
105 |
106 | ```javascript
107 | class Child extends React.Component {
108 | static contextTypes = {
109 | getScrollbar: React.PropTypes.func
110 | };
111 |
112 | componentDidMount() {
113 | this.context.getScrollbar((scrollbar) => {
114 | // ...
115 | });
116 | }
117 |
118 | render() {
119 | return
this is child component.
;
120 | }
121 | }
122 |
123 | class App extends React.Component {
124 | render(){
125 | return (
126 |
127 |
128 |
129 | );
130 | }
131 | }
132 | ```
133 |
134 |
135 | ## APIs
136 |
137 | [Documents](https://github.com/idiotWu/smooth-scrollbar/tree/develop/docs)
138 |
139 | ## License
140 |
141 | MIT.
142 |
143 | [](https://app.codesponsor.io/link/haJ2RqCqwBLZtPKnMNBYgn4M/idiotWu/react-smooth-scrollbar)
144 |
--------------------------------------------------------------------------------
/dist/react-smooth-scrollbar.js:
--------------------------------------------------------------------------------
1 | !function(e,t){"object"==typeof exports&&"object"==typeof module?module.exports=t(require("react"),require("prop-types"),require("smooth-scrollbar")):"function"==typeof define&&define.amd?define(["react","prop-types","smooth-scrollbar"],t):"object"==typeof exports?exports.Scrollbar=t(require("react"),require("prop-types"),require("smooth-scrollbar")):e.Scrollbar=t(e.React,e.PropTypes,e.Scrollbar)}(this,function(e,t,r){return function(e){function t(o){if(r[o])return r[o].exports;var n=r[o]={exports:{},id:o,loaded:!1};return e[o].call(n.exports,n,n.exports,t),n.loaded=!0,n.exports}var r={};return t.m=e,t.c=r,t.p="",t(0)}([function(e,t,r){"use strict";function o(e){return e&&e.__esModule?e:{"default":e}}function n(e,t){var r={};for(var o in e)t.indexOf(o)>=0||Object.prototype.hasOwnProperty.call(e,o)&&(r[o]=e[o]);return r}function l(e,t){if(!(e instanceof t))throw new TypeError("Cannot call a class as a function")}function i(e,t){if(!e)throw new ReferenceError("this hasn't been initialised - super() hasn't been called");return!t||"object"!=typeof t&&"function"!=typeof t?e:t}function c(e,t){if("function"!=typeof t&&null!==t)throw new TypeError("Super expression must either be null or a function, not "+typeof t);e.prototype=Object.create(t&&t.prototype,{constructor:{value:e,enumerable:!1,writable:!0,configurable:!0}}),t&&(Object.setPrototypeOf?Object.setPrototypeOf(e,t):e.__proto__=t)}Object.defineProperty(t,"__esModule",{value:!0});var a=Object.assign||function(e){for(var t=1;t {
32 | if (typeof cb !== 'function') return;
33 |
34 | if (this.scrollbar) setTimeout(() => cb(this.scrollbar));
35 | else this.callbacks.push(cb);
36 | }
37 | };
38 | }
39 |
40 | componentDidMount() {
41 | this.scrollbar = SmoothScrollbar.init(this.$container, this.props);
42 |
43 | this.callbacks.forEach((cb) => {
44 | requestAnimationFrame(() => cb(this.scrollbar));
45 | });
46 |
47 | this.scrollbar.addListener(this.handleScroll.bind(this));
48 | }
49 |
50 | componentWillUnmount() {
51 | if (this.scrollbar) {
52 | this.scrollbar.destroy();
53 | }
54 | }
55 |
56 | componentWillReceiveProps(nextProps) {
57 | Object.keys(nextProps).forEach((key) => {
58 | if (!key in this.scrollbar.options) {
59 | return;
60 | }
61 |
62 | if (key === 'plugins') {
63 | Object.keys(nextProps.plugins).forEach((pluginName) => {
64 | this.scrollbar.updatePluginOptions(pluginName, nextProps.plugins[pluginName]);
65 | });
66 | } else {
67 | this.scrollbar.options[key] = nextProps[key];
68 | }
69 | });
70 | }
71 |
72 | componentDidUpdate() {
73 | this.scrollbar && this.scrollbar.update();
74 | }
75 |
76 | handleScroll(status) {
77 | if (this.props.onScroll) {
78 | this.props.onScroll(status, this.scrollbar);
79 | }
80 | }
81 |
82 | render() {
83 | const {
84 | damping,
85 | thumbMinSize,
86 | syncCallbacks,
87 | renderByPixels,
88 | alwaysShowTracks,
89 | continuousScrolling,
90 | wheelEventTarget,
91 | plugins,
92 |
93 | onScroll,
94 | children,
95 | ...others,
96 | } = this.props;
97 |
98 | return (
99 | this.$container = element} {...others}>
100 | {children}
101 |
102 | );
103 | }
104 | }
105 |
--------------------------------------------------------------------------------
/test/index.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | React Smooth Scrollbar
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
--------------------------------------------------------------------------------
/test/main.js:
--------------------------------------------------------------------------------
1 | import React from 'react';
2 | import ReactDOM from 'react-dom';
3 | import Scrollbar from '../src/react-smooth-scrollbar.js';
4 | import SmoothScrollbar from 'smooth-scrollbar';
5 | import OverscrollPlugin from 'smooth-scrollbar/plugins/overscroll';
6 |
7 | SmoothScrollbar.use(OverscrollPlugin);
8 |
9 | class App extends React.Component {
10 | state = {
11 | damping: 0.1,
12 | count: 3,
13 | };
14 |
15 | randomDamping() {
16 | const nextState = {
17 | damping: Math.random() * 0.5 + 0.1,
18 | count: Math.random() * 10 | 0,
19 | };
20 |
21 | console.log(nextState);
22 |
23 | this.setState(nextState);
24 |
25 | setTimeout(this.randomDamping.bind(this), 3000);
26 | }
27 |
28 | componentDidMount() {
29 | this.scrollbar = this.$container.scrollbar;
30 |
31 | this.randomDamping();
32 | }
33 |
34 | _randomItem() {
35 | const res = [];
36 |
37 | for (let i = 0; i < this.state.count; i++) {
38 | res.push(Lorem ipsum dolor sit amet, consectetur adipisicing elit, sed do eiusmod
39 | tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam,
40 | quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo
41 | consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse
42 | cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non
43 | proident, sunt in culpa qui officia deserunt mollit anim id est laborum.
);
44 | }
45 |
46 | return res;
47 | }
48 |
49 | render() {
50 | return (
51 | this.$container = c}
53 | damping={this.state.damping}
54 | plugins={{
55 | overscroll: { damping: this.state.damping }
56 | }}
57 | >
58 |
59 | {this._randomItem()}
60 |
61 | );
62 | }
63 | }
64 |
65 | ReactDOM.render(
66 | ,
67 | document.getElementById('app')
68 | );
69 |
--------------------------------------------------------------------------------
/test/style.css:
--------------------------------------------------------------------------------
1 | main {
2 | position: absolute;
3 | top: 50%;
4 | left: 50%;
5 | transform: translate(-50%, -50%);
6 | }
7 |
8 | [data-scrollbar] {
9 | width: 600px;
10 | height: 400px;
11 | border: 3px solid #ccc;
12 | margin: 0 auto;
13 | }
14 |
15 | [data-scrollbar] img {
16 | display: block;
17 | width: 1920px;
18 | }
19 |
20 | [data-scrollbar] ol {
21 | width: 600px;
22 | }
23 |
24 | [data-scrollbar] footer {
25 | position: fixed;
26 | bottom: 0;
27 | left: 0;
28 | width: 600px;
29 | text-align: center;
30 | font-size: 2em;
31 | background: skyblue;
32 | text-align: center;
33 | color: #fff;
34 | transition: opacity .5s;
35 | }
36 |
--------------------------------------------------------------------------------
/test/your_diary.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/idiotWu/react-smooth-scrollbar/9e0b6a5ec0b8816f982b5a5d6e0d5766ebff6fd1/test/your_diary.jpg
--------------------------------------------------------------------------------
/webpack.dev.config.js:
--------------------------------------------------------------------------------
1 | module.exports = {
2 | devtool: 'inline-source-map',
3 | module: {
4 | preLoaders: [{
5 | test: /\.jsx?$/,
6 | exclude: /(node_modules|bower_components)/,
7 | loader: 'eslint-loader'
8 | }],
9 | loaders: [{
10 | test: /\.jsx?$/,
11 | loader: 'babel-loader',
12 | query: {
13 | presets: ['es2015', 'stage-0', 'react']
14 | }
15 | }]
16 | }
17 | };
18 |
--------------------------------------------------------------------------------
/webpack.prod.config.js:
--------------------------------------------------------------------------------
1 | module.exports = {
2 | output: {
3 | library: 'Scrollbar',
4 | libraryTarget: 'umd'
5 | },
6 | externals: {
7 | react: {
8 | root: 'React',
9 | commonjs: 'react',
10 | commonjs2: 'react',
11 | amd: 'react'
12 | },
13 | 'prop-types': {
14 | root: 'PropTypes',
15 | commonjs: 'prop-types',
16 | commonjs2: 'prop-types',
17 | amd: 'prop-types'
18 | },
19 | 'smooth-scrollbar': {
20 | root: 'Scrollbar',
21 | commonjs: 'smooth-scrollbar',
22 | commonjs2: 'smooth-scrollbar',
23 | amd: 'smooth-scrollbar'
24 | }
25 | },
26 | module: {
27 | preLoaders: [{
28 | test: /\.jsx?$/,
29 | exclude: /(node_modules|bower_components)/,
30 | loader: 'eslint-loader'
31 | }],
32 | loaders: [{
33 | test: /\.jsx?$/,
34 | exclude: /(node_modules|bower_components)/,
35 | loader: 'babel-loader',
36 | query: {
37 | presets: ['es2015', 'stage-0', 'react'],
38 | plugins: [
39 | 'add-module-exports',
40 | ]
41 | }
42 | }]
43 | }
44 | };
45 |
--------------------------------------------------------------------------------