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;