├── .gitignore
├── .jshintrc
├── scripts
├── index.js
├── App.js
└── Pinch.js
├── index.html
├── .eslintrc
├── server.js
├── README.md
├── webpack.config.js
├── LICENSE
└── package.json
/.gitignore:
--------------------------------------------------------------------------------
1 | node_modules
2 | npm-debug.log
3 | .DS_Store
4 |
--------------------------------------------------------------------------------
/.jshintrc:
--------------------------------------------------------------------------------
1 | {
2 | "node": true,
3 | "browser": true,
4 | "esnext": true,
5 | "newcap": false
6 | }
7 |
--------------------------------------------------------------------------------
/scripts/index.js:
--------------------------------------------------------------------------------
1 | import React from 'react';
2 | import App from './App';
3 |
4 | React.render(, document.getElementById('root'));
5 |
--------------------------------------------------------------------------------
/index.html:
--------------------------------------------------------------------------------
1 |
2 |
3 | Sample App
4 |
5 |
6 |
7 |
8 |
9 |
10 |
--------------------------------------------------------------------------------
/.eslintrc:
--------------------------------------------------------------------------------
1 | {
2 | "env": {
3 | "browser": true,
4 | "node": true
5 | },
6 | "parser": "babel-eslint",
7 | "rules": {
8 | "quotes": [2, "single"],
9 | "strict": [2, "never"]
10 | }
11 | }
12 |
--------------------------------------------------------------------------------
/server.js:
--------------------------------------------------------------------------------
1 | var webpack = require('webpack');
2 | var WebpackDevServer = require('webpack-dev-server');
3 | var config = require('./webpack.config');
4 |
5 | new WebpackDevServer(webpack(config), {
6 | publicPath: config.output.publicPath,
7 | hot: true,
8 | historyApiFallback: true
9 | }).listen(3000, 'localhost', function (err, result) {
10 | if (err) {
11 | console.log(err);
12 | }
13 |
14 | console.log('Listening at localhost:3000');
15 | });
16 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | rx-react-pinch
2 | =====================
3 |
4 | Simple experiment to fiddle with [RxJS](https://github.com/Reactive-Extensions/RxJS), React, ES6 and [Higher-order components](https://medium.com/@dan_abramov/mixins-are-dead-long-live-higher-order-components-94a0d2f9e750).
5 |
6 | Look at this [beauty](https://github.com/hugobessaa/rx-react-pinch/blob/master/scripts/Pinch.js#L29#L45)!
7 |
8 | ### Usage
9 |
10 | ```
11 | npm install
12 | npm start
13 | open http://localhost:3000
14 | ```
15 |
--------------------------------------------------------------------------------
/scripts/App.js:
--------------------------------------------------------------------------------
1 | import React from 'react';
2 | import Pinch from './Pinch.js';
3 | import s from 'react-prefixr';
4 |
5 | export default class App extends React.Component {
6 | render() {
7 | return (
8 | {
9 | return (
10 |
17 | );
18 | }} />
19 | );
20 | }
21 | }
22 |
--------------------------------------------------------------------------------
/webpack.config.js:
--------------------------------------------------------------------------------
1 | var path = require('path');
2 | var webpack = require('webpack');
3 |
4 | module.exports = {
5 | devtool: 'eval',
6 | entry: [
7 | 'webpack-dev-server/client?http://localhost:3000',
8 | 'webpack/hot/only-dev-server',
9 | './scripts/index'
10 | ],
11 | output: {
12 | path: path.join(__dirname, 'build'),
13 | filename: 'bundle.js',
14 | publicPath: '/scripts/'
15 | },
16 | plugins: [
17 | new webpack.HotModuleReplacementPlugin(),
18 | new webpack.NoErrorsPlugin()
19 | ],
20 | resolve: {
21 | extensions: ['', '.js', '.jsx']
22 | },
23 | module: {
24 | loaders: [{
25 | test: /\.jsx?$/,
26 | loaders: ['react-hot', 'babel'],
27 | include: path.join(__dirname, 'scripts')
28 | }]
29 | }
30 | };
31 |
--------------------------------------------------------------------------------
/LICENSE:
--------------------------------------------------------------------------------
1 | The MIT License (MIT)
2 |
3 | Copyright (c) 2014 Dan Abramov
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 |
--------------------------------------------------------------------------------
/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "react-hot-boilerplate",
3 | "version": "1.0.0",
4 | "description": "Boilerplate for ReactJS project with hot code reloading",
5 | "scripts": {
6 | "start": "node server.js"
7 | },
8 | "repository": {
9 | "type": "git",
10 | "url": "https://github.com/gaearon/react-hot-boilerplate.git"
11 | },
12 | "keywords": [
13 | "react",
14 | "reactjs",
15 | "boilerplate",
16 | "hot",
17 | "hot",
18 | "reload",
19 | "hmr",
20 | "live",
21 | "edit",
22 | "webpack"
23 | ],
24 | "author": "Dan Abramov (http://github.com/gaearon)",
25 | "license": "MIT",
26 | "bugs": {
27 | "url": "https://github.com/gaearon/react-hot-boilerplate/issues"
28 | },
29 | "homepage": "https://github.com/gaearon/react-hot-boilerplate",
30 | "devDependencies": {
31 | "babel-core": "^4.7.4",
32 | "babel-loader": "^4.1.0",
33 | "react-hot-loader": "^1.2.2",
34 | "webpack": "^1.7.2",
35 | "webpack-dev-server": "^1.7.0"
36 | },
37 | "dependencies": {
38 | "react": "^0.13.0",
39 | "rx": "^2.5.2",
40 | "react-prefixr": "^0.1.0"
41 | }
42 | }
43 |
--------------------------------------------------------------------------------
/scripts/Pinch.js:
--------------------------------------------------------------------------------
1 | import React from 'react';
2 | import Rx from 'rx';
3 |
4 | let dom = ['touchstart', 'touchmove', 'touchend'].reduce((dom, event) => {
5 | dom[event] = (element, selector) => Rx.Observable.fromEvent(element, event, selector);
6 | return dom;
7 | }, {});
8 |
9 | function eventPreventDefault(event) {
10 | event.preventDefault();
11 | }
12 |
13 | function hasTwoTouchPoints(event) {
14 | return event.touches && event.touches.length === 2;
15 | }
16 |
17 | function logger(subject) {
18 | console.log(subject);
19 | }
20 |
21 | class Pinch extends React.Component {
22 | constructor(props) {
23 | super(props);
24 | this.state = { scale: 1 };
25 | }
26 |
27 | componentWillMount() {
28 | this.handlePinch();
29 | }
30 |
31 | componentWillUnmount() {
32 | if (this.pinchSubscription) {
33 | this.pinchSubscription.dispose();
34 | }
35 | }
36 |
37 | handlePinch() {
38 | let touchStart = dom.touchstart(window);
39 | let touchMove = dom.touchmove(window);
40 | let touchEnd = dom.touchend(window);
41 |
42 | let pinch = touchStart
43 | .tap(eventPreventDefault)
44 | .takeWhile(hasTwoTouchPoints)
45 | .flatMap(() => {
46 | return touchMove
47 | .pluck('scale')
48 | .takeUntil(touchEnd)
49 | })
50 | .tap(logger)
51 |
52 | this.pinchSubscription = pinch.subscribe(scale => this.setState({ scale: scale }));
53 | }
54 |
55 | render() {
56 | return (
57 |
58 | {this.props.render(this.state.scale)}
59 |
60 | );
61 | }
62 | }
63 |
64 | Pinch.propTypes = { render: React.PropTypes.func };
65 |
66 | export default Pinch;
67 |
--------------------------------------------------------------------------------