diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..947dcde --- /dev/null +++ b/.gitignore @@ -0,0 +1,6 @@ +.idea/ +node_modules/ +dist/ +*.log +*.map +.DS_Store diff --git a/.npmignore b/.npmignore new file mode 100644 index 0000000..47b88b7 --- /dev/null +++ b/.npmignore @@ -0,0 +1,12 @@ +.idea/ +node_modules/ +dist/ +*.log +*.map +.DS_Store + +static/ +src/example/ +src/example.* +tmp/ +webpack.*.js diff --git a/LICENSE.md b/LICENSE.md new file mode 100644 index 0000000..972b8a1 --- /dev/null +++ b/LICENSE.md @@ -0,0 +1,27 @@ +# BSD 3-Clause License + +Copyright © 2015, Rick Wong +All rights reserved. + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are met: + +1. Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. +2. Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in the + documentation and/or other materials provided with the distribution. +3. Neither the name of the copyright holder nor the + names of its contributors may be used to endorse or promote products + derived from this software without specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND +ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED +WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER BE LIABLE FOR ANY +DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES +(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; +LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND +ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS +SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. diff --git a/README.md b/README.md new file mode 100644 index 0000000..4d99fd8 --- /dev/null +++ b/README.md @@ -0,0 +1,20 @@ +# React Transmit + +Relay-ish library without the GraphQL. + +## Installation + + npm install react-transmit + +## Usage + +TODO. + +## Community + +Let's start one together! After you ★Star this project, follow [@Rygu](https://twitter.com/rygu) +on Twitter. + +## License + +BSD 3-Clause license. Copyright © 2015, Rick Wong. All rights reserved. diff --git a/package.json b/package.json new file mode 100644 index 0000000..ad079d5 --- /dev/null +++ b/package.json @@ -0,0 +1,41 @@ +{ + "name": "react-transmit", + "description": "Relay-ish library without the GraphQL.", + "version": "0.9.0", + "license": "BSD-3", + "repository": { + "type": "git", + "url": "https://github.com/RickWong/react-transmit.git" + }, + "homepage": "https://github.com/RickWong/react-transmit", + "keywords": [ + "react", + "transmit", + "relay", + "react-component" + ], + "main": "src/lib/react-transmit.js", + "scripts": { + "localhost": "sleep 2; which open && open http://localhost:8080", + "build": "webpack --verbose --colors --display-error-details --config webpack.client.js", + "watch-client": "webpack --verbose --colors --display-error-details --config webpack.client-watch.js && webpack-dev-server --config webpack.client-watch.js", + "watch": "concurrent --kill-others 'npm run watch-client' 'npm run localhost'" + }, + "dependencies": { + "react": "0.13.1", + "react-inline-css": "1.1.1" + }, + "devDependencies": { + "babel-core": "4.7.16", + "babel-loader": "4.2.0", + "babel-runtime": "4.7.16", + "concurrently": "0.0.5", + "json-loader": "0.5.1", + "react-hot-loader": "1.2.3", + "webpack": "1.7.3", + "webpack-dev-server": "1.7.0" + }, + "engines": { + "node" : ">=0.10.32" + } +} diff --git a/src/example.js b/src/example.js new file mode 100644 index 0000000..7cc1b68 --- /dev/null +++ b/src/example.js @@ -0,0 +1,4 @@ +import React from "react"; +import Newsfeed from "example/Newsfeed"; + +React.render(, document.getElementById("react-root")); diff --git a/src/example/Newsfeed.js b/src/example/Newsfeed.js new file mode 100644 index 0000000..db85d8f --- /dev/null +++ b/src/example/Newsfeed.js @@ -0,0 +1,93 @@ +import React from "react"; +import InlineCss from "react-inline-css"; +import Transmit from "lib/react-transmit"; +import Story from "example/Story"; + +/** + * @class Newsfeed + */ +const Newsfeed = React.createClass({ + statics: { + css: (avatarSize) => ` + body { + background: #E9EAED; + } + & .github { + position: absolute; + top: 0; + right: 0; + border: 0; + } + & { + font-family: Helvetica, sans-serif; + width: 500px; + margin: 20px auto; + font-size: 14px; + } + & header { + padding: 20px 30px; + background: #fff; + border: 1px solid #e5e5e5; + border-radius: 3px; + margin-bottom: 10px; + } + & header h2 { + color: #3B5998; + } + & footer { + text-align: center; + margin: 12px; + }` + }, + onLoadMore (event) { + event.preventDefault(); + this.props.setQueryParams({count: this.props.queryParams.count + 1}); + }, + render () { + const repositoryUrl = "https://github.com/RickWong/react-transmit"; + const stories = this.props.stories || []; + + return ( + + + Fork me on GitHub + +
+

+ React Transmit +

+

+ A promising Relay-ish library without the GraphQL. +

+
+
+ {stories.map((story, i) => )} +
+ +
+ ); + } +}); + +export default Transmit.createContainer(Newsfeed, { + queryParams: { + count: 1 + }, + queries: { + stories (queryParams) { + return new Promise(function (resolve, reject) { + var storyPromises = []; + + for (var i=0; i ` + & { + padding: 12px; + background: #fff; + border: 1px solid #e5e5e5; + border-radius: 3px; + margin-bottom: 8px; + } + & img { + float: left; + border: 1px solid #e5e5e5; + margin: 0 6px 12px 0; + } + & h4 { + color: #3b5998; + margin: 5px 0; + } + & span { + color: #bbb; + font-size: 12px; + } + & div { + clear: both; + }` + }, + render() { + var story = this.props.story; + + if (!story) { + return null; + } + + return ( + + +

{story.author.name}

+ Mar 22 +
{story.text}
+
+ ); + } +}); + +export default Transmit.createContainer(Story, { + queries: { + story (queryParams) { + return new Promise(function (resolve, reject) { + var story = { + author: { + name: "Rick Wong", + profile_picture: { + uri: "https://avatars3.githubusercontent.com/u/40102?v=3&s=40" + } + }, + text: "React Transmit. A Relay-ish library." + }; + + resolve(story); + }); + } + } +}); diff --git a/src/lib/react-transmit.js b/src/lib/react-transmit.js new file mode 100644 index 0000000..db1b629 --- /dev/null +++ b/src/lib/react-transmit.js @@ -0,0 +1,60 @@ +/** + * @copyright © 2015, Rick Wong. All rights reserved. + */ +var React = require("react"); +var assign = React.__spread; + +var createContainer = function (Component, options) { + options = options || {}; + var queryParams = options.queryParams || {}; + var queries = options.queries || {}; + + return React.createClass({ + statics: { + getQuery: function (query) { + return queries[query]; + } + }, + componentWillMount: function () { + this.setQueryParams(queryParams); + }, + setQueryParams: function (nextQueryParams) { + queryParams = assign(queryParams, nextQueryParams); + this.transmit(); + }, + transmit: function () { + var promises = []; + var nextState = {}; + var _this = this; + + for (var query in queries) { + if (queries.hasOwnProperty(query)) { + var promise = queries[query](queryParams); + promise.then(function (value) { + nextState[query] = value; + }); + promises.push(promise); + } + } + + Promise.all(promises).then(function () { + _this.setState(nextState); + }); + }, + render: function () { + var props = { + queryParams: queryParams, + setQueryParams: this.setQueryParams + }; + + return React.createElement( + Component, + assign({}, this.state, props, this.props) + ); + } + }); +}; + +module.exports = { + createContainer: createContainer +}; diff --git a/static/favicon.ico b/static/favicon.ico new file mode 100644 index 0000000..5c125de Binary files /dev/null and b/static/favicon.ico differ diff --git a/static/index.html b/static/index.html new file mode 100644 index 0000000..bc39217 --- /dev/null +++ b/static/index.html @@ -0,0 +1,12 @@ + + + + + react-transmit + + + +
+ + + diff --git a/webpack.client-watch.js b/webpack.client-watch.js new file mode 100644 index 0000000..2524224 --- /dev/null +++ b/webpack.client-watch.js @@ -0,0 +1,41 @@ +var webpack = require("webpack"); +var config = require("./webpack.client.js"); + +config.cache = true; +config.debug = true; +config.devtool = "eval"; + +config.entry.unshift( + "webpack-dev-server/client?http://localhost:8080", + "webpack/hot/only-dev-server" +); + +config.output.publicPath = "http://localhost:8080/dist/"; +config.output.hotUpdateMainFilename = "update/[hash]/update.json"; +config.output.hotUpdateChunkFilename = "update/[hash]/[id].update.js"; + +config.plugins = [ + new webpack.HotModuleReplacementPlugin(), + new webpack.NoErrorsPlugin() +]; + +config.module = { + loaders: [ + {include: /\.json$/, loaders: ["json-loader"]}, + {include: /\.js$/, loaders: ["react-hot", "babel-loader?experimental&optional=runtime"], exclude: /(node_modules|lib)/} + ] +}; + +config.devServer = { + publicPath: "http://localhost:8080/dist/", + contentBase: "./static", + hot: true, + inline: true, + lazy: false, + quiet: true, + noInfo: false, + headers: {"Access-Control-Allow-Origin": "*"}, + stats: {colors: true} +}; + +module.exports = config; diff --git a/webpack.client.js b/webpack.client.js new file mode 100644 index 0000000..b5b1e94 --- /dev/null +++ b/webpack.client.js @@ -0,0 +1,40 @@ +var webpack = require("webpack"); +var path = require("path"); + +module.exports = { + target: "web", + cache: false, + context: __dirname, + devtool: false, + entry: ["./src/example"], + output: { + path: path.join(__dirname, "static/dist"), + filename: "client.js", + chunkFilename: "[name].[id].js", + publicPath: "dist/" + }, + plugins: [ + new webpack.DefinePlugin({"process.env": {NODE_ENV: '"production"'}}), + new webpack.optimize.DedupePlugin(), + new webpack.optimize.OccurenceOrderPlugin(), + new webpack.optimize.UglifyJsPlugin() + ], + module: { + loaders: [ + {include: /\.json$/, loaders: ["json-loader"]}, + {include: /\.js$/, loaders: ["babel-loader?experimental&optional=runtime"], exclude: /(node_modules|lib)/} + ] + }, + resolve: { + modulesDirectories: [ + "src", + "node_modules", + "web_modules" + ], + extensions: ["", ".json", ".js"] + }, + node: { + __dirname: true, + fs: 'empty' + } +};