React Blueprint is a react-native insipred web app generator and tool set.
It uses the best libraries for React development without being too opinionated. We make no assumptions on how your app should look, but instead provide a strong architecture to build upon.
âť— This project is in early stages of development. I will strive to keep the api consistent, but it may be subject to change.
- react
- react-router
- react-redux
- redux
- redux-thunk
- redux-simple-router
- reselect
- radium
- babel
- webpack
- eslint
- sockjs-client
- superagent
- core-decorators
- lodash
- Install the command line interface -
npm i -g react-blueprint-cli
- Generate your project -
react-blueprint init [app-name]
- Start your app -
cd [app-name] && npm start
The dev server will be running on localhost:3001
by default.
Upon creation of your project, you will notice that these docs are rendered in your application. They have been included to provided some examples of usage. All the docs are located in src/components/Docs
. To remove the docs, open the projects main index at src/index.js
.
- Remove the import of
DocRoutes
on line24
- Change reference to
DocRoutes
toRoutes
on line42
When complete your new index should look as follows:
import 'babel-polyfill';
import React from 'react';
import { render } from 'react-dom';
import { Provider } from 'react-redux';
import {
Router,
browserHistory as history
} from 'react-router';
import { App } from 'containers';
import { DevTools, Routes } from 'components';
import Store from 'stores/Store';
import { getHydratedState } from 'utils/localStorage';
import rootReducer from 'reducers';
const store = Store.store(rootReducer, getHydratedState());
const dest = document.getElementById('app-container');
Store.middleware.syncHistoryToStore(store, state => state.route);
// Enable Debugger
if (__DEVELOPMENT__) {
window.React = React;
}
if (__DEVTOOLS__ && !window.devToolsExtension) {
// Dev Render
render(
<Provider store={store}>
<div>
<Router history={history}>{Routes}</Router>
<DevTools />
</div>
</Provider>,
dest
);
} else {
// Production Render
render(
<Provider store={store}>
<Router history={history}>{Routes}</Router>
</Provider>,
dest
);
}
At this point you can safely remove the Docs directory from src/components
and your app will be rendering the blank App Container located at src/containers/App/App.js
.
You can find example usage in the previously mentioned Docs
component. It has been structured to simulate the applcation structure (don't structure your components like this).
The main container component Docs
resides at src/components/Docs/containers/Docs.js
.
react-blueprint init [app-name]
- generates a React Blueprint project
npm start
- Start the development server
npm run clean
- Cleans the build directory
npm run build
- Build the source files
npm run lint
- Lint the source files
npm test
- Run the test suite
The static directory contains all your static assets. Images, fonts, stylesheets, and the index.html
.
The config directory contains your development and production config files. They are provided to your application via WebpackProvidePlugin
.
The source directory contains all your application views and logic.
- actions - Redux actions
- components - Reusable components
- containers - Container components (components that act as route handlers)
- reducers - Redux store reducers
- selectors - Redux store selectors
- stores - There is only one store in a Redux app. This is kept in a directory to keep things uniform.
- utils - Various utilities including a websocket dispatcher, superagent request factory, custom decorators, LocalStorage middleware, style abstractions/variables and application copy centrailization.
Diagram of the tree structure:
.
├── LICENSE
├── README.md
├── config
│  ├── dev-config.js
│  └── prod-config.js
├── package.json
├── src
│  ├── actions
│  │  ├── UIActions.js
│  │  └── index.js
│  ├── components
│  │  ├── DevTools
│  │  │  └── DevTools.js
│  │  ├── Routes
│  │  │  └── Routes.js
│  │  └── index.js
│  ├── containers
│  │  ├── App
│  │  │  └── App.js
│  │  └── index.js
│  ├── index.js
│  ├── reducers
│  │  ├── UIReducer.js
│  │  └── index.js
│  ├── selectors
│  │  ├── RouteSelectors.js
│  │  ├── UISelectors.js
│  │  └── index.js
│  ├── stores
│  │  └── store.js
│  └── utils
│  ├── api.js
│  ├── copy.js
│  ├── decorators.js
│  ├── index.js
│  ├── localStorage.js
│  ├── style.js
│  └── websocket.js
├── static
│  ├── fonts
│  │  ├── clearsans
│  │  ├── clearsans_bold
│  │  ├── clearsans_bold_italic
│  │  ├── clearsans_italic
│  │  ├── clearsans_light
│  │  ├── clearsans_medium
│  │  ├── clearsans_medium_italic
│  │  ├── clearsans_thin
│  │  └── fonts.css
│  └── index.html
├── webpack
│  ├── dev.config.js
│  ├── prod.config.js
│  ├── webpack-dev-server.js
│  └── webpack-isomorphic-tools.js
└── webpack-assets.json
React Blueprint is equipped with Redux DevTools increase visibility into and control of your applications state. All Redux actions are logged in the console using redux-logger.
In addition to the logger, we have provided Redux DevTools in the form of a panel overlay. See usage below:
H
Toggle the visibilty of the DevTools panelQ
Change the DevTools panel position
React Blueprint components can be used independently of the project generator. If you generate a project using the React Blueprint CLI then the component library will be installed automatically. Otherwise install React Blueprint...
npm i react-blueprint --save
and import in your project
import { View, ScrollView, Dimensions } from 'react-blueprint';
A flexbox component.
<View row>
<View auto row>
<View column width="100px">
<View className="red">Left</View>
</View>
<View column width="100px">
<View className="red">Left</View>
</View>
</View>
<View row className="green">Hello test view</View>
</View>
<View column height="200px">
<View column auto>
<View style={{ color: "green"}} height="20px">Green</View>
<View style={{ color: "red"}} height="20px">Red</View>
</View>
<View style={{ color: "green" }}>Hello test view </View>
</View>
All props are optional.
- sets the flexDirection to row
- sets the flexDirection to column
- sets the flex to '0 0 auto'
- width can be either a number
width={2}
, this acts asflex-grow
or a string with a unit (for example % or px)
it must be a valid css unit.
- sets the height of the component
it must be a valid css unit
- className to apply to the component
- Will be merged the flex style. This allows you to override the style.
A scrolling view component with rendering optimizations. Based on react-infinite with some additions and optimizations.
- To use ScrollView with a list of elements you want to make scrollable, provide them to ScrollView as children.
<ScrollView containerHeight={200} elementHeight={40}>
<div className="one"/>
<div className="two"/>
<div className="three"/>
</ScrollView>
- A simple ScrollView with no optimizations.
<ScrollView containerHeight={200} optimizeRendering={false}>
<div className="one"/>
<div className="two"/>
<div className="three"/>
</ScrollView>
- If not all of the children have the same height, you must provide an array of integers to the
elementHeight
prop instead.
<ScrollView containerHeight={200} elementHeight={[111, 252, 143]}>
<div className="111-px"/>
<div className="252-px"/>
<div className="143-px"/>
</ScrollView>
- To use the entire window as a scroll container instead of just a single
div
(thus usingwindow.scrollY
instead of a DOM element'sscrollTop
), add theuseWindowAsScrollContainer
prop.
<ScrollView containerHeight={200} elementHeight={[111, 252, 143]}
useWindowAsScrollContainer>
<div className="111-px"/>
<div className="252-px"/>
<div className="143-px"/>
</ScrollView>
- ScrollView now supports being used as a chat box, i.e. appended elements appear at the bottom when added, and the loading of the next page occurs when the user scrolls to the top of the container. To do so, simply add the
displayBottomUpwards
prop.
<ScrollView containerHeight={200} elementHeight={[111, 252, 143]}
displayBottomUpwards>
// insert messages for subsequent pages at this point
<div className="third-latest-chat"/>
<div className="second-latest-chat"/>
<div className="latest-chat-message"/>
</ScrollView>
- A wrapper
div
is applied that disables pointer events on the children for a default of 150 milliseconds after the last user scroll action for browsers with inertial scrolling. To configure this, settimeScrollStateLastsForAfterUserScrolls
.
- This function allows a value to be specified for
preloadBatchSize
andpreloadAdditionalHeight
that is a relative to the container height. Please see the documentation for those two props for further information on how to use it.
- This function will set the scrollTop of the
ScrollView
. Useful if you want to programatically set scroll position.
- The children of the
<ScrollView>
element are the components you want to render. This gives you as much flexibility as you need in the presentation of those components. Each child can be a different component if you desire. If you wish to render a set of children not all of which have the same height, you must map each component in the children array to an number representing its height and pass it in as theelementHeight
prop.
- Defaults to
true
. SettingoptimizeRendering={false}
will keep your children rendered in the dom. TheelementHeight
prop can also be ignored.
⚠️ This is only intended to be used for simple applications where the scroll content is relatively small. You will experience limitations in this mode.
- Defaults to
false
. This option allows the window to be used as the scroll container, instead of an arbitrarydiv
, when it is set totrue
. This means that scroll position is detected bywindow.scrollY
instead of thescrollTop
of thediv
that ScrollView creates. Using this option is a way of achieving smoother scrolling on mobile before the problem is solved for containerdiv
s.
- Defaults to
false
. This allows ScrollView to be used as a chatbox. This means that the scroll is stuck to the bottom by default, and the user scrolls up to the top of the container to load the next page. Thechildren
are displayed in the same order.
- If each child element has the same height, you can pass a number representing that height as the
elementHeight
prop. If the children do not all have the same height, you can pass an array which is a map the children to numbers representing their heights to theelementHeight
prop.
- The height of the scrolling container in pixels. This is a required prop if
useWindowAsScrollContainer
is not set totrue
.
-
Defaults to
this.props.containerHeight * 0.5
. Imagine the total height of the scrollable divs. Now divide this equally into blockspreloadBatchSize
pixels high. Every time the container's scrollTop enters each of these blocks the set of elements rendered in full are those contained within the block and elements that are withinpreloadAdditionalHeight
above and below it. -
When working with the window as the scroll container, it is sometimes useful to specify a scale factor relative to the container height as the batch size, so your code does not need to know anything about the
window
. To do this, useInfinite.containerHeightScaleFactor
. So, for example, if you want the preloaded batch size to be twice the container height, writepreloadBatchSize={Infinite.containerHeightScaleFactor(2)}
.
-
Defaults to
this.props.containerHeight
. The total height of the area in which elements are rendered in full is height of the current scroll block (seepreloadBatchSize
) as well aspreloadAdditionalHeight
above and below it. -
When working with the window as the scroll container, it is sometimes useful to specify this relative to the container height. If you want the preloaded additional height to be twice the container height, write
preloadAdditionalHeight={Infinite.containerHeightScaleFactor(2)}
. Please seepreloadBatchSize
for more details.
- Defaults to
function(){}
. A function that is called when the container is scrolled, i.e. when theonScroll
event of the infinite scrolling container is fired. The only argument passed to it is the native DOM Node of the scrolling container.
- Defaults to
undefined
, which means that infinite loading is disabled. To disable infinite loading, do not provide this property or set it to undefined.
Regular Mode
- When the user reaches this number of pixels from the bottom, the infinite load sequence will be triggered by showing the infinite load spinner delegate and calling the function
onInfiniteLoad
.
displayBottomUpwards
mode
- When the user reaches this number of pixels from the top of the container, the infinite load sequence will be triggered by showing the infinite loading spinner delegate at the top of the container and calling
onInfiniteLoad
.
- Defaults to
function(){}
. This function is called when the scroll exceedsinfiniteLoadBeginEdgeOffset
. Before this function is called, the infinite loading spinner is automatically turned on.
You can set up infinite scrolling with this function like this:
- Fetch a new page of records from the appropriate API
- When the AJAX call returns, send the new list of elements (with the items that were just fetched) back as the children of ScrollView.
- Set ScrollView's
isInfiniteLoading
prop tofalse
to hide the loading spinner display
onInfiniteLoad
relies heavily on passing props as a means of communication in the style of idiomatic React.
- Defaults to
<div/>
. The element that is provided is used to render the loading view when ScrollView'sisInfiniteLoading
property is set totrue
. A React Node is anything that satisfiesReact.PropTypes.node
.
- Defaults to
false
. This property determines whether the infinite spinner is showing.
- Defaults to
150
(in milliseconds). On Apple and some other devices, scroll is inertial. This means that the window continues to scroll for several hundred milliseconds after anonScroll
event is fired. To prevent janky behavior, we do not wantpointer-events
to reactivate before the window has finished moving. Setting this parameter causes theInfinite
component to think that the user is still scrolling for the specified number of milliseconds after the lastonScroll
event is received.
- Allows a CSS class to be set on the scrollable container.
Dimensions
is a utiltiy that will get the width and height (including margin and borders) of a given element. You will need to ensure that your DOM is rendered before you can get the dimensions of a react element. However, Dimensions
also supports window
and document
and their dimensions can be accessed immediately. It can also be invoked as a decorator.
Dimensions([ window || document || element ]);
returns
{
width: [number],
height: [number]
}
/**
* Window / Document example
*/
import React, { Component } from 'react';
import { Dimensions } from 'react-blueprint';
export default class WindowExample extends Component {
componentWillMount() {
this.setState({
windowDimensions: Dimensions(window),
documentDimensions: Dimensions(document)
});
}
render() {
return (
<View
width={this.state.windowDimensions.width}
height={this.state.windowDimensions.height}>
<p>width: {this.state.documentDimensions.width}</p>
<p>height: {this.state.documentDimensions.height}</p>
</View>
);
}
}
React now exposes the DOM element of their DOM components (div
, span
, p
, a
, etc) through this refs.
/**
* React DOM Component Example
*/
import React, { Component } from 'react';
import { Dimensions } from 'react-blueprint';
export default class ReactDOMComponent extends Component {
componentDidMount() {
let dimensions = Dimensions(this.refs.container);
this.setState({ dimensions });
}
render() {
return (
<div ref='container'>
<p>width: {this.state.dimensions.width}</p>
<p>height: {this.state.dimensions.height}</p>
</div>
);
}
}
If you want to measure a custom component you will have to use ReactDOM.findDOMNode(this.refs.yourRef)
/**
* Custom Component Example
*/
import React, { Component } from 'react';
import { findDOMNode as $ } from 'react-dom';
import { Dimensions } from 'react-blueprint';
export default class CustomComponentExample extends Component {
componentDidMount() {
let dimensions = Dimensions($(this.refs.container));
this.setState({ dimensions });
}
render() {
return (
<View ref='container'>
<p>width: {this.state.dimensions.width}</p>
<p>height: {this.state.dimensions.height}</p>
</View>
);
}
}
You can decorate your custom classes with Dimensions
and it will add a width
and a height
prop to your component. It also attaches a getDimensions()
method which will return the components width
and height
. Anytime the window is resized the new dimensions will be computed and made available via props.
/**
* Decorated Component Example
*/
import React, { Component } from 'react';
import { findDOMNode as $ } from 'react-dom';
import { Dimensions } from 'react-blueprint';
@Dimensions
export default class DecoratorExample extends Component {
render() {
return (
<View>
<p>width: {this.props.width}</p>
<p>height: {this.props.height}</p>
</View>
);
}
}
class App extends Component {
render() {
return <DecoratorExample ref="decoratorExample" />
},
getChildDimensions() {
return this.refs.decoratorExample.getDimensions();
}
}