├── V2.md
├── index.js
├── .npmignore
├── 2017_03_06_13_09_14.gif
├── demo
├── public
│ ├── favicon.ico
│ ├── manifest.json
│ └── index.html
├── src
│ ├── index.css
│ ├── index.js
│ ├── registerServiceWorker.js
│ └── App.js
├── config
│ ├── jest
│ │ ├── fileTransform.js
│ │ └── cssTransform.js
│ ├── polyfills.js
│ ├── paths.js
│ ├── env.js
│ ├── webpackDevServer.config.js
│ ├── webpack.config.dev.js
│ └── webpack.config.prod.js
├── .gitignore
├── scripts
│ ├── test.js
│ ├── start.js
│ └── build.js
└── package.json
├── .gitignore
├── .editorconfig
├── .babelrc
├── .eslintrc
├── package.json
├── src
├── spring.js
├── component
│ ├── index.js
│ └── index.native.js
└── index.js
├── README.md
└── yarn.lock
/V2.md:
--------------------------------------------------------------------------------
1 | # V2
2 |
--------------------------------------------------------------------------------
/index.js:
--------------------------------------------------------------------------------
1 | module.exports = require('./lib')
2 |
--------------------------------------------------------------------------------
/.npmignore:
--------------------------------------------------------------------------------
1 | /test/
2 | /demo/
3 | *.gif
4 | *.tgz
5 | .babelrc
6 | /src/
7 | *.md
8 |
--------------------------------------------------------------------------------
/2017_03_06_13_09_14.gif:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/yusukeshib/react-pullrefresh/HEAD/2017_03_06_13_09_14.gif
--------------------------------------------------------------------------------
/demo/public/favicon.ico:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/yusukeshib/react-pullrefresh/HEAD/demo/public/favicon.ico
--------------------------------------------------------------------------------
/demo/src/index.css:
--------------------------------------------------------------------------------
1 | body {
2 | margin: 0;
3 | padding: 0;
4 | font-family: sans-serif;
5 | overflow: hidden;
6 | }
7 |
--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------
1 | # See http://help.github.com/ignore-files/ for more about ignoring files.
2 |
3 | # dependencies
4 | node_modules
5 |
6 | # misc
7 | .DS_Store
8 | npm-debug.log
9 |
10 | # build files
11 | *.tgz
12 | *.log
13 | /lib/
14 |
--------------------------------------------------------------------------------
/.editorconfig:
--------------------------------------------------------------------------------
1 | root = true
2 |
3 | [*]
4 | indent_style = space
5 | indent_size = 2
6 | end_of_line = lf
7 | charset = utf-8
8 | trim_trailing_whitespace = true
9 | insert_final_newline = true
10 |
11 | [*.md]
12 | trim_trailing_whitespace = false
13 |
--------------------------------------------------------------------------------
/.babelrc:
--------------------------------------------------------------------------------
1 | {
2 | "presets": [
3 | [ "env" , {
4 | "targets": {
5 | "browsers": ["last 2 versions", "safari >= 7"]
6 | }
7 | }],
8 | "react"
9 | ],
10 | "plugins": [
11 | "transform-object-rest-spread",
12 | "transform-function-bind"
13 | ]
14 | }
15 |
--------------------------------------------------------------------------------
/demo/src/index.js:
--------------------------------------------------------------------------------
1 | import React from 'react'
2 | import ReactDOM from 'react-dom'
3 | import App from './App'
4 | import registerServiceWorker from './registerServiceWorker'
5 | import whyDidYouUpdate from 'why-did-you-update'
6 |
7 | whyDidYouUpdate(React)
8 | ReactDOM.render(, document.getElementById('root'))
9 | registerServiceWorker()
10 |
--------------------------------------------------------------------------------
/demo/public/manifest.json:
--------------------------------------------------------------------------------
1 | {
2 | "short_name": "React App",
3 | "name": "Create React App Sample",
4 | "icons": [
5 | {
6 | "src": "favicon.ico",
7 | "sizes": "192x192",
8 | "type": "image/png"
9 | }
10 | ],
11 | "start_url": "./index.html",
12 | "display": "standalone",
13 | "theme_color": "#000000",
14 | "background_color": "#ffffff"
15 | }
16 |
--------------------------------------------------------------------------------
/demo/config/jest/fileTransform.js:
--------------------------------------------------------------------------------
1 | 'use strict';
2 |
3 | const path = require('path');
4 |
5 | // This is a custom Jest transformer turning file imports into filenames.
6 | // http://facebook.github.io/jest/docs/tutorial-webpack.html
7 |
8 | module.exports = {
9 | process(src, filename) {
10 | return `module.exports = ${JSON.stringify(path.basename(filename))};`;
11 | },
12 | };
13 |
--------------------------------------------------------------------------------
/demo/config/jest/cssTransform.js:
--------------------------------------------------------------------------------
1 | 'use strict';
2 |
3 | // This is a custom Jest transformer turning style imports into empty objects.
4 | // http://facebook.github.io/jest/docs/tutorial-webpack.html
5 |
6 | module.exports = {
7 | process() {
8 | return 'module.exports = {};';
9 | },
10 | getCacheKey() {
11 | // The output is always the same.
12 | return 'cssTransform';
13 | },
14 | };
15 |
--------------------------------------------------------------------------------
/demo/.gitignore:
--------------------------------------------------------------------------------
1 | # See https://help.github.com/ignore-files/ for more about ignoring files.
2 |
3 | # dependencies
4 | /node_modules
5 |
6 | # testing
7 | /coverage
8 |
9 | # production
10 | /build
11 |
12 | # misc
13 | .DS_Store
14 | .env.local
15 | .env.development.local
16 | .env.test.local
17 | .env.production.local
18 |
19 | npm-debug.log*
20 | yarn-debug.log*
21 | yarn-error.log*
22 |
23 | /src/react-pullrefresh/
24 |
--------------------------------------------------------------------------------
/demo/config/polyfills.js:
--------------------------------------------------------------------------------
1 | 'use strict';
2 |
3 | if (typeof Promise === 'undefined') {
4 | // Rejection tracking prevents a common issue where React gets into an
5 | // inconsistent state due to an error, but it gets swallowed by a Promise,
6 | // and the user has no idea what causes React's erratic future behavior.
7 | require('promise/lib/rejection-tracking').enable();
8 | window.Promise = require('promise/lib/es6-extensions.js');
9 | }
10 |
11 | // fetch() polyfill for making API calls.
12 | require('whatwg-fetch');
13 |
14 | // Object.assign() is commonly used with React.
15 | // It will use the native implementation if it's present and isn't buggy.
16 | Object.assign = require('object-assign');
17 |
--------------------------------------------------------------------------------
/.eslintrc:
--------------------------------------------------------------------------------
1 | {
2 | "parser": "babel-eslint",
3 | "plugins": [
4 | ],
5 | "parserOptions": {
6 | "ecmaVersion": 6,
7 | "sourceType": "module",
8 | "ecmaFeatures": {
9 | "jsx": true
10 | }
11 | },
12 | "env": {
13 | "browser": true,
14 | "amd": true,
15 | "es6": true,
16 | "node": true,
17 | "mocha": true
18 | },
19 | "rules": {
20 | "space-before-function-paren": [1, {"anonymous": "never", "named": "never"}],
21 | "comma-spacing": [1, { "before": false, "after": true }],
22 | "space-infix-ops": 1,
23 | "semi": [1, "never" ],
24 | "comma-dangle": 1,
25 | "quotes": [ 1, "single" ],
26 | "no-undef": 1,
27 | "no-extra-semi": 1,
28 | "no-trailing-spaces": [1, { "skipBlankLines": true }],
29 | "no-unreachable": 1
30 | }
31 | }
32 |
--------------------------------------------------------------------------------
/demo/scripts/test.js:
--------------------------------------------------------------------------------
1 | 'use strict';
2 |
3 | // Do this as the first thing so that any code reading it knows the right env.
4 | process.env.BABEL_ENV = 'test';
5 | process.env.NODE_ENV = 'test';
6 | process.env.PUBLIC_URL = '';
7 |
8 | // Makes the script crash on unhandled rejections instead of silently
9 | // ignoring them. In the future, promise rejections that are not handled will
10 | // terminate the Node.js process with a non-zero exit code.
11 | process.on('unhandledRejection', err => {
12 | throw err;
13 | });
14 |
15 | // Ensure environment variables are read.
16 | require('../config/env');
17 |
18 | const jest = require('jest');
19 | const argv = process.argv.slice(2);
20 |
21 | // Watch unless on CI or in coverage mode
22 | if (!process.env.CI && argv.indexOf('--coverage') < 0) {
23 | argv.push('--watch');
24 | }
25 |
26 |
27 | jest.run(argv);
28 |
--------------------------------------------------------------------------------
/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "react-pullrefresh",
3 | "version": "2.0.0-alpha.1",
4 | "description": "react component pull to refresh navigation",
5 | "main": "index.js",
6 | "scripts": {
7 | "prepublishOnly": "npm run build",
8 | "build": "babel src --out-dir lib",
9 | "lint:fix": "eslint src --fix"
10 | },
11 | "repository": {
12 | "type": "git",
13 | "url": "git+https://github.com/yusukeshibata/react-pullrefresh.git"
14 | },
15 | "keywords": [
16 | "pull",
17 | "refresh",
18 | "react",
19 | "component"
20 | ],
21 | "author": "Yusuke Shibata (https://github.com/yusukeshibata)",
22 | "license": "MIT",
23 | "bugs": {
24 | "url": "https://github.com/yusukeshibata/react-pullrefresh/issues"
25 | },
26 | "homepage": "https://github.com/yusukeshibata/react-pullrefresh#readme",
27 | "peerDependencies": {
28 | "react": "^16.1.1",
29 | "react-native": "^0.42.3",
30 | "react-native-svg": "^5.1.6"
31 | },
32 | "devDependencies": {
33 | "babel-cli": "^6.26.0",
34 | "babel-core": "^6.26.0",
35 | "babel-eslint": "^8.0.2",
36 | "babel-plugin-transform-function-bind": "^6.22.0",
37 | "babel-plugin-transform-object-rest-spread": "^6.26.0",
38 | "babel-polyfill": "^6.26.0",
39 | "babel-preset-env": "^1.6.1",
40 | "babel-preset-react": "^6.24.1",
41 | "eslint": "^4.11.0",
42 | "react": "^16.1.1",
43 | "react-dom": "^16.1.1"
44 | },
45 | "dependencies": {
46 | "event-emitter": "^0.3.5",
47 | "styled-components": "^2.2.3"
48 | }
49 | }
50 |
--------------------------------------------------------------------------------
/demo/public/index.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
11 |
12 |
13 |
22 | React App
23 |
28 |
29 |
30 |
33 |
34 |
44 |
45 |
46 |
--------------------------------------------------------------------------------
/src/spring.js:
--------------------------------------------------------------------------------
1 | import EventEmitter from 'event-emitter'
2 |
3 | const sleep = msec => new Promise(resolve => setTimeout(resolve, msec))
4 | const loop = async promise => {
5 | const proc = async () => await promise() && await proc()
6 | await proc()
7 | }
8 |
9 | export default class Spring {
10 | constructor(tension, friction) {
11 | this._emitter = new EventEmitter()
12 | this._tension = tension
13 | this._friction = friction
14 | this._value = 0
15 | this._endValue = 0
16 | this._loop = false
17 | this._paused = false
18 | }
19 | pause() {
20 | this._paused = true
21 | }
22 | resume() {
23 | this._paused = false
24 | }
25 | set onUpdate(onUpdate) {
26 | this._onUpdate = onUpdate
27 | }
28 | set endValue(value) {
29 | this._endValue = value
30 | this.loop()
31 | }
32 | async to(value) {
33 | this._endValue = value
34 | this.loop()
35 | await this._wait('end')
36 | }
37 | get currentValue() {
38 | return this._value
39 | }
40 | setValue(value) {
41 | if(this._value !== value) {
42 | this._value = value
43 | this._onUpdate(this)
44 | }
45 | }
46 | _emit(type) {
47 | this._emitter.emit(type)
48 | }
49 | async _wait(type) {
50 | await new Promise(resolve => this._emitter.once(type, resolve))
51 | }
52 | async loop() {
53 | if(this._loop) return
54 |
55 | this._emit('start')
56 | this._loop = true
57 |
58 | await loop(async () => {
59 | await sleep(1000 / 60)
60 | if(this._paused) return true
61 | // TODO: dummy -> use tention,friction
62 | const dv = (this._endValue - this._value) / 5
63 | this.setValue(this._value + dv)
64 | return Math.abs(dv) > 0.2
65 | })
66 | this.setValue(this._endValue)
67 |
68 | this._loop = false
69 | this._emit('end')
70 | }
71 | }
72 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # react-pullrefresh
2 |
3 | Pull to reflesh material design component.
4 | react-native is supported.
5 |
6 | 
7 |
8 | #### Demo
9 |
10 | [https://yusukeshibata.github.io/react-pullrefresh/](https://yusukeshibata.github.io/react-pullrefresh/)
11 |
12 |
13 | #### Install
14 |
15 | ```sh
16 | npm install react-pullrefresh
17 | ```
18 |
19 | #### Usage
20 |
21 | ```javascript
22 | import PullRefresh from 'react-pullrefresh'
23 |
24 | class App extends Component {
25 | // onRefresh function canbe async/sync
26 | async onRefresh() {
27 | await someAsyncFunction()
28 | }
29 | // Without children PullRefresh element observe document.body's scroll
30 | render() {
31 | return (
32 |
35 | {range(100).map(i => {
36 | return (
37 | {i}
38 | )
39 | })}
40 |
41 | )
42 | }
43 | }
44 |
45 | export default App
46 | ```
47 | #### Behaviour difference between v1/v2
48 |
49 | TODO:
50 |
51 | #### Props
52 |
53 | ##### render
54 |
55 | TODO:
56 |
57 |
58 | ##### color
59 |
60 | default: `#787878`
61 |
62 | ##### bgColor
63 |
64 | default: `#ffffff`
65 |
66 | ##### disabled
67 |
68 | disable component
69 |
70 | default: `false`
71 |
72 | ##### zIndex
73 |
74 | specify css z-index.
75 |
76 | default: `undefined`
77 |
78 | ##### onRefresh
79 |
80 | ```javascript
81 | async function onRefresh() {
82 | //...some async function
83 | }
84 | ```
85 |
86 | ##### style
87 |
88 | container style.
89 |
90 | default: `undefined`
91 |
92 | #### Removed props
93 |
94 | * size
95 | * offset
96 | * max
97 | * waitingComponent
98 | * pullingComponent
99 | * pulledComponent
100 | * supportDesktop
101 |
102 | #### License
103 |
104 | MIT
105 |
--------------------------------------------------------------------------------
/demo/config/paths.js:
--------------------------------------------------------------------------------
1 | 'use strict';
2 |
3 | const path = require('path');
4 | const fs = require('fs');
5 | const url = require('url');
6 |
7 | // Make sure any symlinks in the project folder are resolved:
8 | // https://github.com/facebookincubator/create-react-app/issues/637
9 | const appDirectory = fs.realpathSync(process.cwd());
10 | const resolveApp = relativePath => path.resolve(appDirectory, relativePath);
11 |
12 | const envPublicUrl = process.env.PUBLIC_URL;
13 |
14 | function ensureSlash(path, needsSlash) {
15 | const hasSlash = path.endsWith('/');
16 | if (hasSlash && !needsSlash) {
17 | return path.substr(path, path.length - 1);
18 | } else if (!hasSlash && needsSlash) {
19 | return `${path}/`;
20 | } else {
21 | return path;
22 | }
23 | }
24 |
25 | const getPublicUrl = appPackageJson =>
26 | envPublicUrl || require(appPackageJson).homepage;
27 |
28 | // We use `PUBLIC_URL` environment variable or "homepage" field to infer
29 | // "public path" at which the app is served.
30 | // Webpack needs to know it to put the right