diff --git a/docs/src/GettingStartedPage.js b/docs/src/GettingStartedPage.js
index 4e60afbcb7..1d2852450d 100644
--- a/docs/src/GettingStartedPage.js
+++ b/docs/src/GettingStartedPage.js
@@ -65,6 +65,16 @@ const Page = React.createClass({
`}
+
+
Without JSX
+ If you do not use JSX and just call components as functions, you must explicitly create a factory before calling it. React-bootstrap provides factories for you in lib/factories
:
+
+
{`
+ var Alert = require('react-bootstrap/lib/factories').Alert;
+ // or
+ var Alert = require('react-bootstrap/lib/factories/Alert');
+ `}
+
Browser support
diff --git a/package.json b/package.json
index 4ba14e7bf2..885445af25 100644
--- a/package.json
+++ b/package.json
@@ -10,7 +10,7 @@
"scripts": {
"build": "node run-babel tools/build.js",
"test-watch": "karma start",
- "test": "karma start --single-run && npm run lint && npm run build",
+ "test": "npm run lint && npm run build && karma start --single-run",
"lint": "eslint src test docs ie8 tools webpack karma.conf.js webpack.config.js webpack.docs.js",
"docs-build": "node run-babel tools/build.js --docs-only",
"docs": "node run-babel docs/server.js",
diff --git a/src/templates/factory.index.js.template b/src/templates/factory.index.js.template
new file mode 100644
index 0000000000..de68c1c23e
--- /dev/null
+++ b/src/templates/factory.index.js.template
@@ -0,0 +1,9 @@
+<% _.forEach(components, function (component) { %>
+import <%= component %> from './<%= component %>';
+<% }); %>
+
+export default {
+<% _.forEach(components, function (component) { %>
+ <%= component %>,
+<% }); %>
+}
diff --git a/src/templates/factory.js.template b/src/templates/factory.js.template
new file mode 100644
index 0000000000..d89a79c954
--- /dev/null
+++ b/src/templates/factory.js.template
@@ -0,0 +1,4 @@
+import React from 'react';
+import <%= name %> from '../<%= name %>';
+
+export default React.createFactory(<%= name %>);
diff --git a/test/FactoriesSpec.js b/test/FactoriesSpec.js
new file mode 100644
index 0000000000..c3fed1f148
--- /dev/null
+++ b/test/FactoriesSpec.js
@@ -0,0 +1,20 @@
+import React from 'react';
+import components from '../tools/public-components';
+
+let props = {
+ Glyphicon: {glyph: 'star'},
+ Modal: {onRequestHide: function() {}},
+ ModalTrigger: {modal: React.DOM.div(null)},
+ OverlayTrigger: {overlay: React.DOM.div(null)}
+};
+
+function createTest(component) {
+ let factory = require(`../lib/factories/${component}`);
+ describe('factories', function () {
+ it(`Should have a ${component} factory`, function () {
+ assert.ok(React.isValidElement(factory(props[component])));
+ });
+ });
+}
+
+components.map(component => createTest(component));
diff --git a/tools/amd/build.js b/tools/amd/build.js
index d29b06d460..cd2876075a 100644
--- a/tools/amd/build.js
+++ b/tools/amd/build.js
@@ -3,6 +3,7 @@ import path from 'path';
import fsp from 'fs-promise';
import { copy } from '../fs-utils';
import { exec } from '../exec';
+import generateFactories from '../generateFactories';
import { repoRoot, srcRoot, bowerRoot } from '../constants';
const packagePath = path.join(repoRoot, 'package.json');
@@ -12,6 +13,10 @@ const bowerJson = path.join(bowerRoot, 'bower.json');
const readme = path.join(__dirname, 'README.md');
const license = path.join(repoRoot, 'LICENSE');
+const babelOptions = '--modules amd --optional es7.objectRestSpread';
+
+const factoriesDestination = path.join(bowerRoot, 'factories');
+
function bowerConfig() {
return Promise.all([
fsp.readFile(packagePath)
@@ -27,10 +32,11 @@ export default function BuildBower() {
console.log('Building: '.cyan + 'bower module'.green);
return exec(`rimraf ${bowerRoot}`)
- .then(() => fsp.mkdir(bowerRoot))
+ .then(() => fsp.mkdirs(factoriesDestination))
.then(() => Promise.all([
bowerConfig(),
- exec(`babel --modules amd --optional es7.objectRestSpread ${srcRoot} --out-dir ${path.join(bowerRoot, 'lib')}`),
+ generateFactories(babelOptions, factoriesDestination),
+ exec(`babel ${babelOptions} ${srcRoot} --out-dir ${bowerRoot}`),
copy(readme, bowerRoot),
copy(license, bowerRoot)
]))
diff --git a/tools/generateFactories.js b/tools/generateFactories.js
new file mode 100644
index 0000000000..d46398b846
--- /dev/null
+++ b/tools/generateFactories.js
@@ -0,0 +1,31 @@
+import _ from 'lodash';
+import path from 'path';
+import fsp from 'fs-promise';
+import { exec } from './exec';
+import { srcRoot } from './constants';
+import components from './public-components';
+
+const templatePath = path.join(srcRoot, 'templates');
+const factoryTemplatePath = path.join(templatePath, 'factory.js.template');
+const indexTemplatePath = path.join(templatePath, 'factory.index.js.template');
+
+export default function generateFactories(babelOptions, destination) {
+
+ let generateCompiledFile = function (file, content) {
+ let outpath = path.join(destination, `${file}.js`);
+ return exec(`babel ${babelOptions} --out-file ${outpath} < {
+ Promise.all(components.map(name => {
+ generateCompiledFile(name, _.template(template)({name: name}));
+ }));
+ }),
+ fsp.readFile(indexTemplatePath)
+ .then(template => _.template(template)({components: components}))
+ .then(content => generateCompiledFile('index', content))
+ ]);
+
+}
diff --git a/tools/lib/build.js b/tools/lib/build.js
index cb1bc87e24..1c54b35a3c 100644
--- a/tools/lib/build.js
+++ b/tools/lib/build.js
@@ -1,11 +1,21 @@
import 'colors';
import { exec } from '../exec';
+import path from 'path';
+import fsp from 'fs-promise';
import { srcRoot, libRoot } from '../constants';
+import generateFactories from '../generateFactories';
+
+const factoryDestination = path.join(libRoot, 'factories');
+const babelOptions = '--optional es7.objectRestSpread';
export default function BuildCommonJs() {
console.log('Building: '.cyan + 'npm module'.green);
return exec(`rimraf ${libRoot}`)
- .then(() => exec(`babel --optional es7.objectRestSpread ${srcRoot} --out-dir ${libRoot}`))
+ .then(() => fsp.mkdirs(factoryDestination))
+ .then(() => Promise.all([
+ generateFactories(babelOptions, factoryDestination),
+ exec(`babel ${babelOptions} ${srcRoot} --out-dir ${libRoot}`)
+ ]))
.then(() => console.log('Built: '.cyan + 'npm module'.green));
}
diff --git a/tools/public-components.js b/tools/public-components.js
new file mode 100644
index 0000000000..a030df7253
--- /dev/null
+++ b/tools/public-components.js
@@ -0,0 +1,11 @@
+import React from 'react';
+import index from '../src/index';
+
+let components = [];
+Object.keys(index).forEach(function (item) {
+ if (index[item] instanceof React.Component.constructor) {
+ components.push(item);
+ }
+});
+
+export default components;