', () => {
7 | it('should render correctly', () => {
8 | expect(
9 | $(
10 |
11 | Static text
12 |
13 | )
14 | .shallowRender()
15 | .single('.form-control-static.my-form-control-static')
16 | .text()
17 | ).to.equal('Static text');
18 | });
19 |
20 | it('should support custom componentClass', () => {
21 | function MyComponent({ children, ...props }) {
22 | return (
23 | {children}
24 | );
25 | }
26 |
27 | expect(
28 | $(
29 |
30 | Static text
31 |
32 | )
33 | .shallowRender()
34 | .single($.s`${MyComponent}.form-control-static`)
35 | .text()
36 | ).to.equal('Static text');
37 | });
38 | });
39 |
--------------------------------------------------------------------------------
/src/MediaRight.js:
--------------------------------------------------------------------------------
1 | import classNames from 'classnames';
2 | import React from 'react';
3 | import PropTypes from 'prop-types';
4 |
5 | import Media from './Media';
6 | import { bsClass, getClassSet, prefix, splitBsProps }
7 | from './utils/bootstrapUtils';
8 |
9 | const propTypes = {
10 | /**
11 | * Align the media to the top, middle, or bottom of the media object.
12 | */
13 | align: PropTypes.oneOf(['top', 'middle', 'bottom']),
14 | };
15 |
16 | class MediaRight extends React.Component {
17 | render() {
18 | const { align, className, ...props } = this.props;
19 | const [bsProps, elementProps] = splitBsProps(props);
20 |
21 | const classes = getClassSet(bsProps);
22 |
23 | if (align) {
24 | // The class is e.g. `media-top`, not `media-right-top`.
25 | classes[prefix(Media.defaultProps, align)] = true;
26 | }
27 |
28 | return (
29 |
33 | );
34 | }
35 | }
36 |
37 | MediaRight.propTypes = propTypes;
38 |
39 | export default bsClass('media-right', MediaRight);
40 |
--------------------------------------------------------------------------------
/docs/examples/GridWithoutClearfix.js:
--------------------------------------------------------------------------------
1 | const dummySentences = ['Lorem ipsum dolor sit amet, consectetuer adipiscing elit.', 'Donec hendrerit tempor tellus.', 'Donec pretium posuere tellus.', 'Proin quam nisl, tincidunt et, mattis eget, convallis nec, purus.', 'Cum sociis natoque penatibus et magnis dis parturient montes, nascetur ridiculus mus.', 'Nulla posuere.', 'Donec vitae dolor.', 'Nullam tristique diam non turpis.', 'Cras placerat accumsan nulla.', 'Nullam rutrum.', 'Nam vestibulum accumsan nisl.'];
2 |
3 | const gridInstance = (
4 |
5 |
6 | <{'Col sm={6} md={3}'} /> {dummySentences.slice(0, 6).join(' ')}
7 | <{'Col sm={6} md={3}'} /> {dummySentences.slice(0, 4).join(' ')}
8 | <{'Col sm={6} md={3}'} /> {dummySentences.slice(0, 6).join(' ')}
9 | <{'Col sm={6} md={3}'} /> {dummySentences.slice(0, 2).join(' ')}
10 |
11 |
12 | );
13 |
14 | ReactDOM.render(gridInstance, mountNode);
15 |
--------------------------------------------------------------------------------
/docs/src/sections/TableSection.js:
--------------------------------------------------------------------------------
1 | import React from 'react';
2 |
3 | import Anchor from '../Anchor';
4 | import PropTable from '../PropTable';
5 | import ReactPlayground from '../ReactPlayground';
6 | import Samples from '../Samples';
7 |
8 | export default function TableSection() {
9 | return (
10 |
11 |
12 | Tables Table
13 |
14 |
15 |
Use the striped, bordered, condensed and hover props to customise the table.
16 |
17 |
18 |
Responsive
19 |
Add responsive prop to make them scroll horizontally up to small devices (under 768px). When viewing on anything larger than 768px wide, you will not see any difference in these tables.
20 |
21 |
22 |
Props
23 |
24 |
25 | );
26 | }
27 |
--------------------------------------------------------------------------------
/src/Thumbnail.js:
--------------------------------------------------------------------------------
1 | import classNames from 'classnames';
2 | import React from 'react';
3 | import PropTypes from 'prop-types';
4 |
5 | import SafeAnchor from './SafeAnchor';
6 | import { bsClass, getClassSet, splitBsProps } from './utils/bootstrapUtils';
7 |
8 | const propTypes = {
9 | src: PropTypes.string,
10 | alt: PropTypes.string,
11 | href: PropTypes.string,
12 | };
13 |
14 | class Thumbnail extends React.Component {
15 | render() {
16 | const { src, alt, className, children, ...props } = this.props;
17 | const [bsProps, elementProps] = splitBsProps(props);
18 |
19 | const Component = elementProps.href ? SafeAnchor : 'div';
20 | const classes = getClassSet(bsProps);
21 |
22 | return (
23 |
27 |
28 |
29 | {children && (
30 |
31 | {children}
32 |
33 | )}
34 |
35 | );
36 | }
37 | }
38 |
39 | Thumbnail.propTypes = propTypes;
40 |
41 | export default bsClass('thumbnail', Thumbnail);
42 |
--------------------------------------------------------------------------------
/docs/examples/FormBasic.js:
--------------------------------------------------------------------------------
1 | const FormExample = React.createClass({
2 | getInitialState() {
3 | return {
4 | value: ''
5 | };
6 | },
7 |
8 | getValidationState() {
9 | const length = this.state.value.length;
10 | if (length > 10) return 'success';
11 | else if (length > 5) return 'warning';
12 | else if (length > 0) return 'error';
13 | },
14 |
15 | handleChange(e) {
16 | this.setState({ value: e.target.value });
17 | },
18 |
19 | render() {
20 | return (
21 |
37 | );
38 | }
39 | });
40 |
41 | ReactDOM.render( , mountNode);
42 |
--------------------------------------------------------------------------------
/docs/src/sections/ResponsiveEmbedSection.js:
--------------------------------------------------------------------------------
1 | import React from 'react';
2 |
3 | import Anchor from '../Anchor';
4 | import PropTable from '../PropTable';
5 | import ReactPlayground from '../ReactPlayground';
6 | import Samples from '../Samples';
7 |
8 | export default function ResponsiveEmbedSection() {
9 | return (
10 |
11 |
12 | Responsive embed ResponsiveEmbed
13 |
14 |
15 |
Allow browsers to determine video or slideshow dimensions based on the width of their containing block by creating an intrinsic ratio that will properly scale on any device.
16 |
You don't need to include frameborder="0" in your iframes.
17 |
Either 16by9 or 4by3 aspect ratio via a16by9 or a4by3 attribute must be set.
18 |
19 |
20 |
Props
21 |
22 |
23 | );
24 | }
25 |
--------------------------------------------------------------------------------
/docs/examples/AlertDismissable.js:
--------------------------------------------------------------------------------
1 | const AlertDismissable = React.createClass({
2 | getInitialState() {
3 | return {
4 | alertVisible: true
5 | };
6 | },
7 |
8 | render() {
9 | if (this.state.alertVisible) {
10 | return (
11 |
12 | Oh snap! You got an error!
13 | Change this and that and try again. Duis mollis, est non commodo luctus, nisi erat porttitor ligula, eget lacinia odio sem nec elit. Cras mattis consectetur purus sit amet fermentum.
14 |
15 | Take this action
16 | or
17 | Hide Alert
18 |
19 |
20 | );
21 | }
22 |
23 | return (
24 | Show Alert
25 | );
26 | },
27 |
28 | handleAlertDismiss() {
29 | this.setState({alertVisible: false});
30 | },
31 |
32 | handleAlertShow() {
33 | this.setState({alertVisible: true});
34 | }
35 | });
36 |
37 | ReactDOM.render( , mountNode);
38 |
--------------------------------------------------------------------------------
/docs/src/sections/FormValidationSection.js:
--------------------------------------------------------------------------------
1 | import React from 'react';
2 |
3 | import Anchor from '../Anchor';
4 | import PropTable from '../PropTable';
5 | import ReactPlayground from '../ReactPlayground';
6 | import Samples from '../Samples';
7 |
8 | export default function FormValidationSection() {
9 | return (
10 |
11 |
12 | Validation states FormControl.Feedback
13 |
14 |
15 |
Set validationState to one of 'success', 'warning' or 'error' to show validation state. Set validationState to null (or undefined) to hide validation state. Add {''} for a feedback icon when validation state is set.
16 |
17 |
18 |
Props
19 |
20 |
FormControl.Feedback
21 |
22 |
23 | );
24 | }
25 |
--------------------------------------------------------------------------------
/docs/src/sections/ThumbnailSection.js:
--------------------------------------------------------------------------------
1 | import React from 'react';
2 |
3 | import Anchor from '../Anchor';
4 | import PropTable from '../PropTable';
5 | import ReactPlayground from '../ReactPlayground';
6 | import Samples from '../Samples';
7 |
8 | export default function ThumbnailSection() {
9 | return (
10 |
11 |
12 | Thumbnails Thumbnail
13 |
14 |
15 |
Thumbnails are designed to showcase linked images with minimal required markup. You can extend the grid component with thumbnails.
16 |
17 |
Anchor Thumbnail
18 |
Creates an anchor wrapping an image.
19 |
20 |
21 |
Divider Thumbnail
22 |
Creates a divider wrapping an image and other children elements.
23 |
24 |
25 |
Props
26 |
27 |
28 | );
29 | }
30 |
--------------------------------------------------------------------------------
/LICENSE:
--------------------------------------------------------------------------------
1 | The MIT License (MIT)
2 |
3 | Copyright (c) 2014-present Stephen J. Collings, Matthew Honnibal, Pieter Vanderwerff
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
13 | all 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
21 | THE SOFTWARE.
22 |
--------------------------------------------------------------------------------
/docs/src/sections/PaginationSection.js:
--------------------------------------------------------------------------------
1 | import React from 'react';
2 |
3 | import Anchor from '../Anchor';
4 | import PropTable from '../PropTable';
5 | import ReactPlayground from '../ReactPlayground';
6 | import Samples from '../Samples';
7 |
8 | export default function PaginationSection() {
9 | return (
10 |
11 |
12 | Pagination
13 |
14 |
15 |
Provide pagination links for your site or app with the multi-page pagination component. Set items to the number of pages. activePage prop dictates which page is active
16 |
17 |
18 |
19 |
such as first, last, previous, next, boundaryLinks and ellipsis.
20 |
21 |
22 |
23 |
24 |
25 | );
26 | }
27 |
--------------------------------------------------------------------------------
/test/JumbotronSpec.js:
--------------------------------------------------------------------------------
1 | import React from 'react';
2 | import ReactTestUtils from 'react-addons-test-utils';
3 | import ReactDOM from 'react-dom';
4 |
5 | import Jumbotron from '../src/Jumbotron';
6 |
7 | describe('', () => {
8 | it('Should output a div with content', () => {
9 | let instance = ReactTestUtils.renderIntoDocument(
10 |
11 | Content
12 |
13 | );
14 |
15 | assert.equal(ReactDOM.findDOMNode(instance).nodeName, 'DIV');
16 | assert.ok(ReactTestUtils.findRenderedDOMComponentWithTag(instance, 'strong'));
17 | });
18 |
19 | it('Should have a jumbotron class', () => {
20 | let instance = ReactTestUtils.renderIntoDocument(
21 |
22 | Content
23 |
24 | );
25 | assert.ok(ReactDOM.findDOMNode(instance).className.match(/\bjumbotron\b/));
26 | });
27 |
28 | it('Should override node class', () => {
29 | let instance = ReactTestUtils.renderIntoDocument(
30 |
31 | Content
32 |
33 | );
34 | assert.equal(ReactDOM.findDOMNode(instance).nodeName, 'SECTION');
35 | });
36 | });
37 |
--------------------------------------------------------------------------------
/test/helpers.js:
--------------------------------------------------------------------------------
1 | import { cloneElement } from 'react';
2 | import ReactDOM from 'react-dom';
3 |
4 | export function shouldWarn(about) {
5 | console.error.expected.push(about); // eslint-disable-line no-console
6 | }
7 |
8 | /**
9 | * Helper for rendering and updating props for plain class Components
10 | * since `setProps` is deprecated.
11 | * @param {ReactElement} element Root element to render
12 | * @param {HTMLElement?} mountPoint Optional mount node, when empty it uses an unattached div like `renderIntoDocument()`
13 | * @return {ComponentInstance} The instance, with a new method `renderWithProps` which will return a new instance with updated props
14 | */
15 | export function render(element, mountPoint) {
16 | let mount = mountPoint || document.createElement('div');
17 | let instance = ReactDOM.render(element, mount);
18 |
19 | if (instance && !instance.renderWithProps) {
20 | instance.renderWithProps = newProps => {
21 |
22 | return render(
23 | cloneElement(element, newProps), mount);
24 | };
25 | }
26 |
27 | return instance;
28 | }
29 |
30 | export function getOne(collection) {
31 | expect(collection.length).to.equal(1);
32 | return collection[0];
33 | }
34 |
--------------------------------------------------------------------------------
/docs/examples/TableResponsive.js:
--------------------------------------------------------------------------------
1 | const tableInstance = (
2 |
3 |
4 |
5 | #
6 | Table heading
7 | Table heading
8 | Table heading
9 | Table heading
10 | Table heading
11 | Table heading
12 |
13 |
14 |
15 |
16 | 1
17 | Table cell
18 | Table cell
19 | Table cell
20 | Table cell
21 | Table cell
22 | Table cell
23 |
24 |
25 | 2
26 | Table cell
27 | Table cell
28 | Table cell
29 | Table cell
30 | Table cell
31 | Table cell
32 |
33 |
34 | 3
35 | Table cell
36 | Table cell
37 | Table cell
38 | Table cell
39 | Table cell
40 | Table cell
41 |
42 |
43 |
44 | );
45 |
46 | ReactDOM.render(tableInstance, mountNode);
47 |
--------------------------------------------------------------------------------
/docs/examples/ThumbnailDiv.js:
--------------------------------------------------------------------------------
1 | const thumbnailInstance = (
2 |
3 |
4 |
5 |
6 | Thumbnail label
7 | Description
8 |
9 | Button
10 | Button
11 |
12 |
13 |
14 |
15 |
16 | Thumbnail label
17 | Description
18 |
19 | Button
20 | Button
21 |
22 |
23 |
24 |
25 |
26 | Thumbnail label
27 | Description
28 |
29 | Button
30 | Button
31 |
32 |
33 |
34 |
35 |
36 | );
37 |
38 | ReactDOM.render(thumbnailInstance, mountNode);
39 |
--------------------------------------------------------------------------------
/src/Pager.js:
--------------------------------------------------------------------------------
1 | import classNames from 'classnames';
2 | import React, { cloneElement } from 'react';
3 | import PropTypes from 'prop-types';
4 |
5 | import PagerItem from './PagerItem';
6 | import { bsClass, getClassSet, splitBsProps } from './utils/bootstrapUtils';
7 | import createChainedFunction from './utils/createChainedFunction';
8 | import ValidComponentChildren from './utils/ValidComponentChildren';
9 |
10 | const propTypes = {
11 | onSelect: PropTypes.func,
12 | };
13 |
14 | class Pager extends React.Component {
15 | render() {
16 | const { onSelect, className, children, ...props } = this.props;
17 | const [bsProps, elementProps] = splitBsProps(props);
18 |
19 | const classes = getClassSet(bsProps);
20 |
21 | return (
22 |
26 | {ValidComponentChildren.map(children, child => (
27 | cloneElement(child, {
28 | onSelect: createChainedFunction(child.props.onSelect, onSelect),
29 | })
30 | ))}
31 |
32 | );
33 | }
34 | }
35 |
36 | Pager.propTypes = propTypes;
37 |
38 | Pager.Item = PagerItem;
39 |
40 | export default bsClass('pager', Pager);
41 |
--------------------------------------------------------------------------------
/docs/examples/GridWithClearfix.js:
--------------------------------------------------------------------------------
1 | const dummySentences = ['Lorem ipsum dolor sit amet, consectetuer adipiscing elit.', 'Donec hendrerit tempor tellus.', 'Donec pretium posuere tellus.', 'Proin quam nisl, tincidunt et, mattis eget, convallis nec, purus.', 'Cum sociis natoque penatibus et magnis dis parturient montes, nascetur ridiculus mus.', 'Nulla posuere.', 'Donec vitae dolor.', 'Nullam tristique diam non turpis.', 'Cras placerat accumsan nulla.', 'Nullam rutrum.', 'Nam vestibulum accumsan nisl.'];
2 |
3 | const gridInstance = (
4 |
5 |
6 | <{'Col sm={6} md={3}'} /> {dummySentences.slice(0, 6).join(' ')}
7 | <{'Col sm={6} md={3}'} /> {dummySentences.slice(0, 4).join(' ')}
8 | <{'Clearfix visibleSmBlock'} />
9 | <{'Col sm={6} md={3}'} /> {dummySentences.slice(0, 6).join(' ')}
10 | <{'Col sm={6} md={3}'} /> {dummySentences.slice(0, 2).join(' ')}
11 |
12 |
13 | );
14 |
15 | ReactDOM.render(gridInstance, mountNode);
16 |
--------------------------------------------------------------------------------
/test/RowSpec.js:
--------------------------------------------------------------------------------
1 | import React from 'react';
2 | import ReactTestUtils from 'react-addons-test-utils';
3 | import ReactDOM from 'react-dom';
4 |
5 | import Row from '../src/Row';
6 |
7 | describe('Row', () => {
8 | it('uses "div" by default', () => {
9 | let instance = ReactTestUtils.renderIntoDocument(
10 |
11 | );
12 |
13 | assert.equal(ReactDOM.findDOMNode(instance).nodeName, 'DIV');
14 | });
15 |
16 | it('has "row" class', () => {
17 | let instance = ReactTestUtils.renderIntoDocument(
18 | Row content
19 | );
20 | assert.equal(ReactDOM.findDOMNode(instance).className, 'row');
21 | });
22 |
23 | it('Should merge additional classes passed in', () => {
24 | let instance = ReactTestUtils.renderIntoDocument(
25 |
26 | );
27 | assert.ok(ReactDOM.findDOMNode(instance).className.match(/\bbob\b/));
28 | assert.ok(ReactDOM.findDOMNode(instance).className.match(/\brow\b/));
29 | });
30 |
31 | it('allows custom elements instead of "div"', () => {
32 | let instance = ReactTestUtils.renderIntoDocument(
33 |
34 | );
35 |
36 | assert.equal(ReactDOM.findDOMNode(instance).nodeName, 'SECTION');
37 | });
38 | });
39 |
--------------------------------------------------------------------------------
/docs/examples/DropdownButtonCustom.js:
--------------------------------------------------------------------------------
1 |
2 | const dropdownInstance = (
3 |
4 |
5 |
6 |
7 | Pow! Zoom!
8 |
9 |
10 | Action
11 | Another action
12 | Active Item
13 |
14 | Separated link
15 |
16 |
17 |
18 |
19 |
20 | mix it up style-wise
21 |
22 |
23 |
24 | Action
25 | Another action
26 | Active Item
27 |
28 | Separated link
29 |
30 |
31 |
32 |
33 | );
34 |
35 | ReactDOM.render(dropdownInstance, mountNode);
36 |
--------------------------------------------------------------------------------
/tools/amd/build.js:
--------------------------------------------------------------------------------
1 | import fsp from 'fs-promise';
2 | import template from 'lodash/template';
3 | import path from 'path';
4 |
5 | import { repoRoot, bowerRoot } from '../constants';
6 | import { exec } from '../exec';
7 | import { copy } from '../fs-utils';
8 |
9 | const packagePath = path.join(repoRoot, 'package.json');
10 | const bowerTemplatePath = path.join(__dirname, 'bower.json');
11 | const bowerJson = path.join(bowerRoot, 'bower.json');
12 |
13 | const readme = path.join(__dirname, 'README.md');
14 |
15 | function bowerConfig() {
16 | return Promise.all([
17 | fsp.readFile(packagePath)
18 | .then(json => JSON.parse(json)),
19 | fsp.readFile(bowerTemplatePath)
20 | .then(templateString => template(templateString))
21 | ])
22 | .then(([pkg, compiledTemplate]) => compiledTemplate({ pkg }))
23 | .then(config => fsp.writeFile(bowerJson, config));
24 | }
25 |
26 | export default function BuildBower() {
27 | console.log('Building: '.cyan + 'bower module'.green);
28 |
29 | return exec(`rimraf ${bowerRoot}`)
30 | .then(() => fsp.mkdirs(bowerRoot))
31 | .then(() => Promise.all([
32 | bowerConfig(),
33 | copy(readme, bowerRoot)
34 | ]))
35 | .then(() => console.log('Built: '.cyan + 'bower module'.green));
36 | }
37 |
--------------------------------------------------------------------------------
/src/Grid.js:
--------------------------------------------------------------------------------
1 | import classNames from 'classnames';
2 | import React from 'react';
3 | import PropTypes from 'prop-types';
4 | import elementType from 'prop-types-extra/lib/elementType';
5 |
6 | import { bsClass, prefix, splitBsProps } from './utils/bootstrapUtils';
7 |
8 | const propTypes = {
9 | /**
10 | * Turn any fixed-width grid layout into a full-width layout by this property.
11 | *
12 | * Adds `container-fluid` class.
13 | */
14 | fluid: PropTypes.bool,
15 | /**
16 | * You can use a custom element for this component
17 | */
18 | componentClass: elementType,
19 | };
20 |
21 | const defaultProps = {
22 | componentClass: 'div',
23 | fluid: false,
24 | };
25 |
26 | class Grid extends React.Component {
27 | render() {
28 | const { fluid, componentClass: Component, className, ...props } =
29 | this.props;
30 | const [bsProps, elementProps] = splitBsProps(props);
31 |
32 | const classes = prefix(bsProps, fluid && 'fluid');
33 |
34 | return (
35 |
39 | );
40 | }
41 | }
42 |
43 | Grid.propTypes = propTypes;
44 | Grid.defaultProps = defaultProps;
45 |
46 | export default bsClass('container', Grid);
47 |
--------------------------------------------------------------------------------
/test/InputGroupSpec.js:
--------------------------------------------------------------------------------
1 | import React from 'react';
2 | import $ from 'teaspoon';
3 |
4 | import Button from '../src/Button';
5 | import FormControl from '../src/FormControl';
6 | import InputGroup from '../src/InputGroup';
7 |
8 | describe('', () => {
9 | it('should render properly', () => {
10 | $(
11 |
12 |
13 | Foo
14 |
15 |
16 |
17 |
18 |
19 | Bar
20 |
21 |
22 | )
23 | .render()
24 | .single('.input-group.my-input-group')
25 | .end()
26 | .single('.input-group-addon.my-addon')
27 | .tap($addon => expect($addon.text()).to.equal('Foo'))
28 | .end()
29 | .single('input.form-control[type="text"]')
30 | .end()
31 | .single('.input-group-btn.my-button')
32 | .single($.s`${Button}`);
33 | });
34 |
35 | it('should support bsSize', () => {
36 | $(
37 |
38 | )
39 | .shallowRender()
40 | .single('.input-group.input-group-sm');
41 | });
42 | });
43 |
--------------------------------------------------------------------------------
/src/Label.js:
--------------------------------------------------------------------------------
1 | import classNames from 'classnames';
2 | import React from 'react';
3 |
4 | import { bsClass, bsStyles, getClassSet, splitBsProps }
5 | from './utils/bootstrapUtils';
6 | import { State, Style } from './utils/StyleConfig';
7 |
8 | class Label extends React.Component {
9 | hasContent(children) {
10 | let result = false;
11 |
12 | React.Children.forEach(children, child => {
13 | if (result) {
14 | return;
15 | }
16 |
17 | if (child || child === 0) {
18 | result = true;
19 | }
20 | });
21 |
22 | return result;
23 | }
24 |
25 | render() {
26 | const { className, children, ...props } = this.props;
27 | const [bsProps, elementProps] = splitBsProps(props);
28 |
29 | const classes = {
30 | ...getClassSet(bsProps),
31 |
32 | // Hack for collapsing on IE8.
33 | hidden: !this.hasContent(children),
34 | };
35 |
36 | return (
37 |
41 | {children}
42 |
43 | );
44 | }
45 | }
46 |
47 | export default bsClass('label',
48 | bsStyles(
49 | [...Object.values(State), Style.DEFAULT, Style.PRIMARY],
50 | Style.DEFAULT,
51 | Label
52 | )
53 | );
54 |
--------------------------------------------------------------------------------
/docs/examples/Overlay.js:
--------------------------------------------------------------------------------
1 | const Example = React.createClass({
2 | getInitialState() {
3 | return { show: true };
4 | },
5 |
6 | toggle() {
7 | this.setState({ show: !this.state.show });
8 | },
9 |
10 | render() {
11 | const sharedProps = {
12 | show: this.state.show,
13 | container: this,
14 | target: () => ReactDOM.findDOMNode(this.refs.target)
15 | };
16 |
17 | return (
18 |
19 |
20 | Click me!
21 |
22 |
23 |
24 | Tooltip overload!
25 |
26 |
27 | Tooltip overload!
28 |
29 |
30 | Tooltip overload!
31 |
32 |
33 | Tooltip overload!
34 |
35 |
36 | );
37 | }
38 | });
39 |
40 | ReactDOM.render( , mountNode);
41 |
--------------------------------------------------------------------------------
/src/Form.js:
--------------------------------------------------------------------------------
1 | import classNames from 'classnames';
2 | import React from 'react';
3 | import PropTypes from 'prop-types';
4 | import elementType from 'prop-types-extra/lib/elementType';
5 |
6 | import { bsClass, prefix, splitBsProps } from './utils/bootstrapUtils';
7 |
8 | const propTypes = {
9 | horizontal: PropTypes.bool,
10 | inline: PropTypes.bool,
11 | componentClass: elementType,
12 | };
13 |
14 | const defaultProps = {
15 | horizontal: false,
16 | inline: false,
17 | componentClass: 'form',
18 | };
19 |
20 | class Form extends React.Component {
21 | render() {
22 | const {
23 | horizontal,
24 | inline,
25 | componentClass: Component,
26 | className,
27 | ...props
28 | } = this.props;
29 |
30 | const [bsProps, elementProps] = splitBsProps(props);
31 |
32 | const classes = [];
33 | if (horizontal) {
34 | classes.push(prefix(bsProps, 'horizontal'));
35 | }
36 | if (inline) {
37 | classes.push(prefix(bsProps, 'inline'));
38 | }
39 |
40 | return (
41 |
45 | );
46 | }
47 | }
48 |
49 | Form.propTypes = propTypes;
50 | Form.defaultProps = defaultProps;
51 |
52 | export default bsClass('form', Form);
53 |
--------------------------------------------------------------------------------
/test/LabelSpec.js:
--------------------------------------------------------------------------------
1 | import React from 'react';
2 | import ReactTestUtils from 'react-addons-test-utils';
3 | import ReactDOM from 'react-dom';
4 |
5 | import Label from '../src/Label';
6 |
7 | describe('Label', () => {
8 |
9 | it('Should output a label with message', () => {
10 | let instance = ReactTestUtils.renderIntoDocument(
11 |
12 | Message
13 |
14 | );
15 | assert.ok(ReactTestUtils.findRenderedDOMComponentWithTag(instance, 'strong'));
16 | });
17 |
18 | it('Should have bsClass by default', () => {
19 | let instance = ReactTestUtils.renderIntoDocument(
20 |
21 | Message
22 |
23 | );
24 | assert.ok(ReactDOM.findDOMNode(instance).className.match(/\blabel\b/));
25 | });
26 |
27 | it('Should have bsStyle by default', () => {
28 | let instance = ReactTestUtils.renderIntoDocument(
29 |
30 | Message
31 |
32 | );
33 | assert.ok(ReactDOM.findDOMNode(instance).className.match(/\blabel-default\b/));
34 | });
35 |
36 | it('Hides when empty', () => {
37 | let instance = ReactTestUtils.renderIntoDocument(
38 |
39 | );
40 | assert.ok(ReactDOM.findDOMNode(instance).className.match(/\bhidden\b/));
41 | });
42 |
43 | });
44 |
--------------------------------------------------------------------------------
/docs/src/sections/BreadcrumbSection.js:
--------------------------------------------------------------------------------
1 | import React from 'react';
2 |
3 | import Anchor from '../Anchor';
4 | import PropTable from '../PropTable';
5 | import ReactPlayground from '../ReactPlayground';
6 | import Samples from '../Samples';
7 |
8 | export default function BreadcrumbSection() {
9 | return (
10 |
11 |
12 | Breadcrumbs Breadcrumb, Breadcrumb.Item
13 |
14 |
15 |
Breadcrumbs are used to indicate the current page's location. Add active attribute to active Breadcrumb.Item.
16 |
Do not set both active and href attributes. active overrides href and span element is rendered instead of a.
17 |
18 |
Breadcrumbs Example
19 |
20 |
21 |
Props
22 |
Breadcrumb component itself doesn't have any specific public properties
23 |
24 |
Breadcrumb.Item
25 |
26 |
27 | );
28 | }
29 |
--------------------------------------------------------------------------------
/test/MediaListSpec.js:
--------------------------------------------------------------------------------
1 | import React from 'react';
2 | import ReactTestUtils from 'react-addons-test-utils';
3 | import ReactDOM from 'react-dom';
4 |
5 | import Media from '../src/Media';
6 |
7 | describe(`Media.List`, () => {
8 | it(`uses "ul"`, () => {
9 | const instance = ReactTestUtils.renderIntoDocument(
10 |
11 | );
12 |
13 | assert.equal(ReactDOM.findDOMNode(instance).nodeName, 'UL');
14 | });
15 | it(`has "media-list" class`, () => {
16 | const instance = ReactTestUtils.renderIntoDocument(
17 |
18 | );
19 |
20 | assert.include(ReactDOM.findDOMNode(instance).className, 'media-list');
21 | });
22 | it(`should merge additional classes passed in`, () => {
23 | const instance = ReactTestUtils.renderIntoDocument(
24 |
25 | );
26 | const classes = ReactDOM.findDOMNode(instance).className;
27 |
28 | assert.include(classes, 'media-list');
29 | assert.include(classes, 'custom-class');
30 | });
31 | it(`should render children`, () => {
32 | const instance = ReactTestUtils.renderIntoDocument(
33 |
34 | Content
35 |
36 | );
37 | assert.ok(ReactTestUtils.findRenderedDOMComponentWithTag(instance, 'strong'));
38 | });
39 | });
40 |
--------------------------------------------------------------------------------
/src/BreadcrumbItem.js:
--------------------------------------------------------------------------------
1 | import classNames from 'classnames';
2 | import React from 'react';
3 | import PropTypes from 'prop-types';
4 |
5 | import SafeAnchor from './SafeAnchor';
6 |
7 | const propTypes = {
8 | /**
9 | * If set to true, renders `span` instead of `a`
10 | */
11 | active: PropTypes.bool,
12 | /**
13 | * `href` attribute for the inner `a` element
14 | */
15 | href: PropTypes.string,
16 | /**
17 | * `title` attribute for the inner `a` element
18 | */
19 | title: PropTypes.node,
20 | /**
21 | * `target` attribute for the inner `a` element
22 | */
23 | target: PropTypes.string,
24 | };
25 |
26 | const defaultProps = {
27 | active: false,
28 | };
29 |
30 | class BreadcrumbItem extends React.Component {
31 | render() {
32 | const { active, href, title, target, className, ...props } = this.props;
33 |
34 | // Don't try to render these props on non-active .
35 | const linkProps = { href, title, target };
36 |
37 | return (
38 |
39 | {active ?
40 | :
41 |
42 | }
43 |
44 | );
45 | }
46 | }
47 |
48 | BreadcrumbItem.propTypes = propTypes;
49 | BreadcrumbItem.defaultProps = defaultProps;
50 |
51 | export default BreadcrumbItem;
52 |
--------------------------------------------------------------------------------
/test/MediaListItemSpec.js:
--------------------------------------------------------------------------------
1 | import React from 'react';
2 | import ReactTestUtils from 'react-addons-test-utils';
3 | import ReactDOM from 'react-dom';
4 |
5 | import Media from '../src/Media';
6 |
7 | describe(`Media.ListItem`, () => {
8 | it(`uses "li"`, () => {
9 | const instance = ReactTestUtils.renderIntoDocument(
10 |
11 | );
12 |
13 | assert.equal(ReactDOM.findDOMNode(instance).nodeName, 'LI');
14 | });
15 | it(`has "media" class`, () => {
16 | const instance = ReactTestUtils.renderIntoDocument(
17 |
18 | );
19 |
20 | assert.include(ReactDOM.findDOMNode(instance).className, 'media');
21 | });
22 | it(`should merge additional classes passed in`, () => {
23 | const instance = ReactTestUtils.renderIntoDocument(
24 |
25 | );
26 | const classes = ReactDOM.findDOMNode(instance).className;
27 |
28 | assert.include(classes, 'media');
29 | assert.include(classes, 'custom-class');
30 | });
31 | it(`should render children`, () => {
32 | const instance = ReactTestUtils.renderIntoDocument(
33 |
34 | Content
35 |
36 | );
37 | assert.ok(ReactTestUtils.findRenderedDOMComponentWithTag(instance, 'strong'));
38 | });
39 | });
40 |
--------------------------------------------------------------------------------
/src/Media.js:
--------------------------------------------------------------------------------
1 | import classNames from 'classnames';
2 | import React from 'react';
3 | import elementType from 'prop-types-extra/lib/elementType';
4 |
5 | import MediaBody from './MediaBody';
6 | import MediaHeading from './MediaHeading';
7 | import MediaLeft from './MediaLeft';
8 | import MediaList from './MediaList';
9 | import MediaListItem from './MediaListItem';
10 | import MediaRight from './MediaRight';
11 | import { bsClass, getClassSet, splitBsProps } from './utils/bootstrapUtils';
12 |
13 | const propTypes = {
14 | componentClass: elementType,
15 | };
16 |
17 | const defaultProps = {
18 | componentClass: 'div',
19 | };
20 |
21 | class Media extends React.Component {
22 | render() {
23 | const { componentClass: Component, className, ...props } = this.props;
24 | const [bsProps, elementProps] = splitBsProps(props);
25 |
26 | const classes = getClassSet(bsProps);
27 |
28 | return (
29 |
33 | );
34 | }
35 | }
36 |
37 | Media.propTypes = propTypes;
38 | Media.defaultProps = defaultProps;
39 |
40 | Media.Heading = MediaHeading;
41 | Media.Body = MediaBody;
42 | Media.Left = MediaLeft;
43 | Media.Right = MediaRight;
44 | Media.List = MediaList;
45 | Media.ListItem = MediaListItem;
46 |
47 | export default bsClass('media', Media);
48 |
--------------------------------------------------------------------------------
/src/DropdownButton.js:
--------------------------------------------------------------------------------
1 | import React from 'react';
2 | import PropTypes from 'prop-types';
3 |
4 | import Dropdown from './Dropdown';
5 | import splitComponentProps from './utils/splitComponentProps';
6 |
7 | const propTypes = {
8 | ...Dropdown.propTypes,
9 |
10 | // Toggle props.
11 | bsStyle: PropTypes.string,
12 | bsSize: PropTypes.string,
13 | title: PropTypes.node.isRequired,
14 | noCaret: PropTypes.bool,
15 |
16 | // Override generated docs from .
17 | /**
18 | * @private
19 | */
20 | children: PropTypes.node,
21 | };
22 |
23 | class DropdownButton extends React.Component {
24 | render() {
25 | const { bsSize, bsStyle, title, children, ...props } = this.props;
26 |
27 | const [dropdownProps, toggleProps] =
28 | splitComponentProps(props, Dropdown.ControlledComponent);
29 |
30 | return (
31 |
36 |
41 | {title}
42 |
43 |
44 |
45 | {children}
46 |
47 |
48 | );
49 | }
50 | }
51 |
52 | DropdownButton.propTypes = propTypes;
53 |
54 | export default DropdownButton;
55 |
--------------------------------------------------------------------------------
/test/CarouselCaptionSpec.js:
--------------------------------------------------------------------------------
1 | import React from 'react';
2 | import ReactTestUtils from 'react-addons-test-utils';
3 | import ReactDOM from 'react-dom';
4 |
5 | import Carousel from '../src/Carousel';
6 |
7 | describe('', () => {
8 | it('uses "div" by default', () => {
9 | let instance = ReactTestUtils.renderIntoDocument(
10 |
11 | );
12 |
13 | assert.equal(ReactDOM.findDOMNode(instance).nodeName, 'DIV');
14 | });
15 |
16 | it('has "carousel-caption" class', () => {
17 | let instance = ReactTestUtils.renderIntoDocument(
18 | Carousel.Caption content
19 | );
20 | assert.equal(ReactDOM.findDOMNode(instance).className, 'carousel-caption');
21 | });
22 |
23 | it('Should merge additional classes passed in', () => {
24 | let instance = ReactTestUtils.renderIntoDocument(
25 |
26 | );
27 | assert.ok(ReactDOM.findDOMNode(instance).className.match(/\bbob\b/));
28 | assert.ok(ReactDOM.findDOMNode(instance).className.match(/\bcarousel-caption\b/));
29 | });
30 |
31 | it('allows custom elements instead of "div"', () => {
32 | let instance = ReactTestUtils.renderIntoDocument(
33 |
34 | );
35 |
36 | assert.equal(ReactDOM.findDOMNode(instance).nodeName, 'SECTION');
37 | });
38 | });
39 |
--------------------------------------------------------------------------------
/tools/exec.js:
--------------------------------------------------------------------------------
1 | import { exec as processExec } from 'child-process-promise';
2 | import 'colors';
3 |
4 | let executionOptions = {
5 | dryRun: false,
6 | verbose: false
7 | };
8 |
9 | function logWithPrefix(prefix, message) {
10 | console.log(
11 | message.toString().trim()
12 | .split('\n')
13 | .map((line) => `${prefix.grey} ${line}`)
14 | .join('\n')
15 | );
16 | }
17 |
18 | export function exec(command, options = {}) {
19 | let proc = processExec(command, options);
20 | if (!executionOptions.verbose) {
21 | return proc;
22 | }
23 |
24 | let title = options.title || command;
25 | let output = (data, type) => logWithPrefix(`[${title}] ${type}:`, data);
26 |
27 | return proc.progress(({stdout, stderr}) => {
28 | stdout.on('data', data => output(data, 'stdout'));
29 | stderr.on('data', data => output(data, 'stderr'));
30 | })
31 | .then(result => {
32 | logWithPrefix(`[${title}]`, 'Complete'.cyan);
33 | return result;
34 | });
35 | }
36 |
37 | export function safeExec(command, options = {}) {
38 | let title = options.title || command;
39 |
40 | if (executionOptions.dryRun) {
41 | logWithPrefix(`[${title}]`.grey, 'DRY RUN'.magenta);
42 | return Promise.resolve();
43 | }
44 |
45 | return exec(command, options);
46 | }
47 |
48 | export function setExecOptions(options) {
49 | executionOptions = { ...executionOptions, ...options };
50 | }
51 |
--------------------------------------------------------------------------------
/docs/examples/PopoverPositioned.js:
--------------------------------------------------------------------------------
1 | const popoverLeft = (
2 |
3 | Holy guacamole! Check this info.
4 |
5 | );
6 |
7 | const popoverTop = (
8 |
9 | Holy guacamole! Check this info.
10 |
11 | );
12 |
13 | const popoverBottom = (
14 |
15 | Holy guacamole! Check this info.
16 |
17 | );
18 |
19 | const popoverRight = (
20 |
21 | Holy guacamole! Check this info.
22 |
23 | );
24 |
25 | ReactDOM.render((
26 |
27 |
28 | Holy guacamole!
29 |
30 |
31 | Holy guacamole!
32 |
33 |
34 | Holy guacamole!
35 |
36 |
37 | Holy guacamole!
38 |
39 |
40 | ), mountNode);
41 |
--------------------------------------------------------------------------------
/karma.conf.js:
--------------------------------------------------------------------------------
1 | require('babel-register');
2 |
3 | const webpack = require('webpack');
4 |
5 | const webpackConfigBase = require('./webpack/base.config').default;
6 |
7 | module.exports = config => {
8 | const { env } = process;
9 |
10 | config.set({
11 | frameworks: ['mocha', 'sinon-chai'],
12 |
13 | files: ['test/index.js'],
14 |
15 | preprocessors: {
16 | 'test/index.js': ['webpack', 'sourcemap'],
17 | },
18 |
19 | // This explicitly doesn't use webpack-merge because we want to override
20 | // the DefinePlugin in the base config.
21 | webpack: Object.assign({}, webpackConfigBase, {
22 | plugins: [
23 | new webpack.DefinePlugin({
24 | 'process.env.NODE_ENV': JSON.stringify('test'),
25 | }),
26 | ],
27 | devtool: 'cheap-module-inline-source-map',
28 | }),
29 |
30 | webpackMiddleware: {
31 | noInfo: true,
32 | },
33 |
34 | reporters: ['mocha', 'coverage'],
35 |
36 | mochaReporter: {
37 | output: 'autowatch',
38 | },
39 |
40 | coverageReporter: {
41 | type: 'lcov',
42 | dir: 'coverage',
43 | },
44 |
45 | customLaunchers: {
46 | ChromeCi: {
47 | base: 'Chrome',
48 | flags: ['--no-sandbox'],
49 | },
50 | },
51 |
52 | browsers: env.BROWSER ? env.BROWSER.split(',') : ['Chrome'],
53 |
54 | singleRun: env.CONTINUOUS_INTEGRATION === 'true',
55 | });
56 | };
57 |
--------------------------------------------------------------------------------
/docs/examples/OverlayCustom.js:
--------------------------------------------------------------------------------
1 | const CustomPopover = React.createClass({
2 | render() {
3 | return (
4 |
17 | Holy guacamole! Check this info.
18 |
19 | );
20 | },
21 | });
22 |
23 | const Example = React.createClass({
24 | getInitialState() {
25 | return { show: true };
26 | },
27 |
28 | toggle() {
29 | this.setState({ show: !this.state.show });
30 | },
31 |
32 | render() {
33 | return (
34 |
35 |
36 | I am an Overlay target
37 |
38 |
39 | this.setState({ show: false })}
42 | placement="right"
43 | container={this}
44 | target={() => ReactDOM.findDOMNode(this.refs.target)}
45 | >
46 |
47 |
48 |
49 | );
50 | },
51 | });
52 |
53 | ReactDOM.render( , mountNode);
54 |
--------------------------------------------------------------------------------
/tools/buildBabel.js:
--------------------------------------------------------------------------------
1 | import { transform } from 'babel-core';
2 | import fs from 'fs';
3 | import path from 'path';
4 | import outputFileSync from 'output-file-sync';
5 |
6 | function buildContent(content, filename, destination, babelOptions = {}) {
7 | babelOptions.filename = filename;
8 | const result = transform(content, babelOptions);
9 | outputFileSync(destination, result.code, {encoding: 'utf8'});
10 | }
11 |
12 | function buildFile(filename, destination, babelOptions = {}) {
13 | const content = fs.readFileSync(filename, {encoding: 'utf8'});
14 | // We only have .js files that we need to build
15 | if (path.extname(filename) === '.js') {
16 | const outputPath = path.join(destination, path.basename(filename));
17 | // console.log('%s => %s', filename, outputPath);
18 | buildContent(content, filename, outputPath, babelOptions);
19 | }
20 | }
21 |
22 | export default function buildBabel(folderPath, destination, babelOptions = {}, firstFolder = true) {
23 | let stats = fs.statSync(folderPath);
24 |
25 | if (stats.isFile()) {
26 | buildFile(folderPath, destination, babelOptions);
27 | } else if (stats.isDirectory()) {
28 | let outputPath = firstFolder ? destination : path.join(destination, path.basename(folderPath));
29 | let files = fs.readdirSync(folderPath).map(file => path.join(folderPath, file));
30 | files.forEach(filename => buildBabel(filename, outputPath, babelOptions, false));
31 | }
32 | }
33 |
--------------------------------------------------------------------------------
/docs/src/sections/OverlaySection.js:
--------------------------------------------------------------------------------
1 | import React from 'react';
2 |
3 | import Anchor from '../Anchor';
4 | import PropTable from '../PropTable';
5 | import ReactPlayground from '../ReactPlayground';
6 | import Samples from '../Samples';
7 |
8 | export default function OverlaySection() {
9 | return (
10 |
11 |
12 | Custom overlays Overlay
13 |
14 |
15 |
16 | The OverlayTrigger component is great for most use cases, but as a higher level abstraction it can lack the flexibility needed to build more nuanced or custom behaviors into your Overlay components. For these cases it can be helpful to forgo the trigger and use the Overlay component directly.
17 |
18 |
19 |
20 |
Use Overlay instead of Tooltip and Popover
21 |
22 | You don't need to use the provided Tooltip or Popover components. Creating custom overlays is as easy as wrapping some markup in an Overlay component.
23 |
24 |
25 |
26 |
Props
27 |
28 |
29 | );
30 | }
31 |
--------------------------------------------------------------------------------
/docs/src/sections/PagerSection.js:
--------------------------------------------------------------------------------
1 | import React from 'react';
2 |
3 | import Anchor from '../Anchor';
4 | import PropTable from '../PropTable';
5 | import ReactPlayground from '../ReactPlayground';
6 | import Samples from '../Samples';
7 |
8 | export default function PagerSection() {
9 | return (
10 |
11 |
12 | Pager, Pager.Item
13 |
14 |
15 |
Quick previous and next links.
16 |
17 |
18 |
19 |
20 |
21 |
Set the previous or next prop to true, to align left or right.
22 |
23 |
24 |
25 |
Set the disabled prop to true to disable the link.
26 |
27 |
28 |
29 |
30 |
31 |
32 |
33 |
34 |
35 |
36 | );
37 | }
38 |
--------------------------------------------------------------------------------
/src/Alert.js:
--------------------------------------------------------------------------------
1 | import classNames from 'classnames';
2 | import React from 'react';
3 | import PropTypes from 'prop-types';
4 |
5 | import { bsClass, bsStyles, getClassSet, prefix, splitBsProps }
6 | from './utils/bootstrapUtils';
7 | import { State } from './utils/StyleConfig';
8 | import CloseButton from './CloseButton';
9 |
10 | const propTypes = {
11 | onDismiss: PropTypes.func,
12 | closeLabel: PropTypes.string,
13 | };
14 |
15 | const defaultProps = {
16 | closeLabel: 'Close alert',
17 | };
18 |
19 | class Alert extends React.Component {
20 | render() {
21 | const { onDismiss, closeLabel, className, children, ...props } =
22 | this.props;
23 | const [bsProps, elementProps] = splitBsProps(props);
24 |
25 | const dismissable = !!onDismiss;
26 | const classes = {
27 | ...getClassSet(bsProps),
28 | [prefix(bsProps, 'dismissable')]: dismissable,
29 | };
30 |
31 | return (
32 |
37 | {dismissable && (
38 |
42 | )}
43 | {children}
44 |
45 | );
46 | }
47 | }
48 |
49 | Alert.propTypes = propTypes;
50 | Alert.defaultProps = defaultProps;
51 |
52 | export default bsStyles(Object.values(State), State.INFO,
53 | bsClass('alert', Alert)
54 | );
55 |
--------------------------------------------------------------------------------
/src/Badge.js:
--------------------------------------------------------------------------------
1 | import classNames from 'classnames';
2 | import React from 'react';
3 | import PropTypes from 'prop-types';
4 |
5 | import { bsClass, getClassSet, splitBsProps } from './utils/bootstrapUtils';
6 |
7 | // TODO: `pullRight` doesn't belong here. There's no special handling here.
8 |
9 | const propTypes = {
10 | pullRight: PropTypes.bool,
11 | };
12 |
13 | const defaultProps = {
14 | pullRight: false,
15 | };
16 |
17 | class Badge extends React.Component {
18 | hasContent(children) {
19 | let result = false;
20 |
21 | React.Children.forEach(children, child => {
22 | if (result) {
23 | return;
24 | }
25 |
26 | if (child || child === 0) {
27 | result = true;
28 | }
29 | });
30 |
31 | return result;
32 | }
33 |
34 | render() {
35 | const { pullRight, className, children, ...props } = this.props;
36 | const [bsProps, elementProps] = splitBsProps(props);
37 |
38 | const classes = {
39 | ...getClassSet(bsProps),
40 | 'pull-right': pullRight,
41 |
42 | // Hack for collapsing on IE8.
43 | hidden: !this.hasContent(children),
44 | };
45 |
46 | return (
47 |
51 | {children}
52 |
53 | );
54 | }
55 | }
56 |
57 | Badge.propTypes = propTypes;
58 | Badge.defaultProps = defaultProps;
59 |
60 | export default bsClass('badge', Badge);
61 |
--------------------------------------------------------------------------------
/docs/src/sections/TooltipSection.js:
--------------------------------------------------------------------------------
1 | import React from 'react';
2 |
3 | import Anchor from '../Anchor';
4 | import PropTable from '../PropTable';
5 | import ReactPlayground from '../ReactPlayground';
6 | import Samples from '../Samples';
7 |
8 | export default function TooltipSection() {
9 | return (
10 |
11 |
12 | Tooltips Tooltip
13 |
14 |
15 |
16 | Tooltip component for a more stylish alternative to that anchor tag title attribute.
17 |
18 |
19 |
20 |
With OverlayTrigger
21 |
Attach and position tooltips with OverlayTrigger.
22 |
23 |
24 |
In text copy
25 |
Positioned tooltip in text copy.
26 |
27 |
28 |
Props
29 |
30 |
OverlayTrigger
31 |
32 |
33 |
Tooltip
34 |
35 |
36 | );
37 | }
38 |
--------------------------------------------------------------------------------
/docs/examples/PopoverTriggerBehaviors.js:
--------------------------------------------------------------------------------
1 | const popoverClick = (
2 |
3 | Holy guacamole! Check this info.
4 |
5 | );
6 |
7 | const popoverHoverFocus = (
8 |
9 | Holy guacamole! Check this info.
10 |
11 | );
12 |
13 | const popoverFocus = (
14 |
15 | Holy guacamole! Check this info.
16 |
17 | );
18 |
19 | const popoverClickRootClose = (
20 |
21 | Holy guacamole! Check this info.
22 |
23 | );
24 |
25 | ReactDOM.render((
26 |
27 |
28 | Click
29 |
30 |
31 | Hover + Focus
32 |
33 |
34 | Focus
35 |
36 |
37 | Click w/rootClose
38 |
39 |
40 | ), mountNode);
41 |
--------------------------------------------------------------------------------
/docs/src/sections/CarouselSection.js:
--------------------------------------------------------------------------------
1 | import React from 'react';
2 |
3 | import Anchor from '../Anchor';
4 | import PropTable from '../PropTable';
5 | import ReactPlayground from '../ReactPlayground';
6 | import Samples from '../Samples';
7 |
8 | export default function CarouselSection() {
9 | return (
10 |
11 |
12 | Carousels Carousel, Carousel.Item, Carousel.Caption
13 |
14 |
15 |
Uncontrolled
16 |
Allow the component to control its own state.
17 |
18 |
19 |
Controlled
20 |
Pass down the active state on render via props.
21 |
22 |
23 |
Props
24 |
25 |
Carousel
26 |
27 |
28 |
Carousel.Item
29 |
30 |
31 |
Carousel.Caption
32 |
33 |
34 | );
35 | }
36 |
--------------------------------------------------------------------------------
/src/ToggleButton.js:
--------------------------------------------------------------------------------
1 | import React from 'react';
2 |
3 | import Button from './Button';
4 |
5 | const propTypes = {
6 | /**
7 | * The ` ` `type`
8 | * @type {[type]}
9 | */
10 | type: React.PropTypes.oneOf(['checkbox', 'radio']),
11 |
12 | /**
13 | * The HTML input name, used to group like checkboxes or radio buttons together
14 | * semantically
15 | */
16 | name: React.PropTypes.string,
17 |
18 | /**
19 | * The checked state of the input, managed by ``` automatically
20 | */
21 | checked: React.PropTypes.bool,
22 |
23 | /**
24 | * [onChange description]
25 | */
26 | onChange: React.PropTypes.func,
27 | /**
28 | * The value of the input, and unique identifier in the ToggleButtonGroup
29 | */
30 | value: React.PropTypes.any.isRequired,
31 | };
32 |
33 | class ToggleButton extends React.Component {
34 | render() {
35 | const {
36 | children, name, checked, type, onChange, value, ...props } = this.props;
37 |
38 | return (
39 |
44 |
52 |
53 | {children}
54 |
55 | );
56 | }
57 | }
58 |
59 | ToggleButton.propTypes = propTypes;
60 |
61 | export default ToggleButton;
62 |
--------------------------------------------------------------------------------
/src/Image.js:
--------------------------------------------------------------------------------
1 | import classNames from 'classnames';
2 | import React from 'react';
3 | import PropTypes from 'prop-types';
4 |
5 | import { bsClass, prefix, splitBsProps } from './utils/bootstrapUtils';
6 |
7 | const propTypes = {
8 | /**
9 | * Sets image as responsive image
10 | */
11 | responsive: PropTypes.bool,
12 |
13 | /**
14 | * Sets image shape as rounded
15 | */
16 | rounded: PropTypes.bool,
17 |
18 | /**
19 | * Sets image shape as circle
20 | */
21 | circle: PropTypes.bool,
22 |
23 | /**
24 | * Sets image shape as thumbnail
25 | */
26 | thumbnail: PropTypes.bool,
27 | };
28 |
29 | const defaultProps = {
30 | responsive: false,
31 | rounded: false,
32 | circle: false,
33 | thumbnail: false,
34 | };
35 |
36 | class Image extends React.Component {
37 | render() {
38 | const { responsive, rounded, circle, thumbnail, className, ...props } =
39 | this.props;
40 | const [bsProps, elementProps] = splitBsProps(props);
41 |
42 | const classes = {
43 | [prefix(bsProps, 'responsive')]: responsive,
44 | [prefix(bsProps, 'rounded')]: rounded,
45 | [prefix(bsProps, 'circle')]: circle,
46 | [prefix(bsProps, 'thumbnail')]: thumbnail,
47 | };
48 |
49 | return (
50 |
54 | );
55 | }
56 | }
57 |
58 | Image.propTypes = propTypes;
59 | Image.defaultProps = defaultProps;
60 |
61 | export default bsClass('img', Image);
62 |
--------------------------------------------------------------------------------
/test/ControlLabelSpec.js:
--------------------------------------------------------------------------------
1 | import React from 'react';
2 | import $ from 'teaspoon';
3 |
4 | import ControlLabel from '../src/ControlLabel';
5 | import FormGroup from '../src/FormGroup';
6 |
7 | import { shouldWarn } from './helpers';
8 |
9 | describe('', () => {
10 | it('should render correctly', () => {
11 | expect(
12 | $(
13 |
14 | Label
15 |
16 | )
17 | .shallowRender()
18 | .single('label.control-label.my-control-label[htmlFor="foo"]')
19 | .text()
20 | ).to.equal('Label');
21 | });
22 |
23 | it('should respect srOnly', () => {
24 | $(
25 |
26 | Label
27 |
28 | )
29 | .shallowRender()
30 | .single('label.control-label.sr-only');
31 | });
32 |
33 | it('should use controlId for htmlFor', () => {
34 | $(
35 |
36 | Label
37 |
38 | )
39 | .render()
40 | .single('label.control-label[htmlFor="foo"]');
41 | });
42 |
43 | it('should prefer explicit htmlFor', () => {
44 | shouldWarn('ignored');
45 |
46 | $(
47 |
48 |
49 | Label
50 |
51 |
52 | )
53 | .render()
54 | .single('label.control-label[htmlFor="bar"]');
55 | });
56 | });
57 |
--------------------------------------------------------------------------------
/docs/examples/ModalContained.js:
--------------------------------------------------------------------------------
1 | /**
2 | * You will want to include this bit of css
3 | *
4 | * .modal-container {
5 | * position: relative;
6 | * }
7 | * .modal-container .modal, .modal-container .modal-backdrop {
8 | * position: absolute;
9 | * }
10 | */
11 |
12 | const Trigger = React.createClass({
13 | getInitialState() {
14 | return { show: false };
15 | },
16 |
17 | render() {
18 | let close = () => this.setState({ show: false});
19 |
20 | return (
21 |
22 | this.setState({ show: true})}
26 | >
27 | Launch contained modal
28 |
29 |
30 |
36 |
37 | Contained Modal
38 |
39 |
40 | Elit est explicabo ipsum eaque dolorem blanditiis doloribus sed id ipsam, beatae, rem fuga id earum? Inventore et facilis obcaecati.
41 |
42 |
43 | Close
44 |
45 |
46 |
47 | );
48 | }
49 | });
50 |
51 | ReactDOM.render( , mountNode);
52 |
--------------------------------------------------------------------------------
/docs/examples/TooltipInCopy.js:
--------------------------------------------------------------------------------
1 | const LinkWithTooltip = React.createClass({
2 | render() {
3 | let tooltip = {this.props.tooltip} ;
4 |
5 | return (
6 |
10 | {this.props.children}
11 |
12 | );
13 | }
14 | });
15 |
16 | const copyInstance = (
17 |
18 | Tight pants next level keffiyeh you probably haven't
19 | heard of them. Photo booth beard raw denim letterpress vegan messenger bag stumptown. Farm-to-table seitan, mcsweeney's
20 | fixie sustainable quinoa 8-bit american apparel Another tooltip
} href="#" id="tooltip-2">have a
21 | terry richardson vinyl chambray. Beard stumptown, cardigans banh mi lomo thundercats. Tofu biodiesel williamsburg marfa, four
22 | loko mcsweeney's cleanse vegan chambray. A really ironic artisan whatever keytar ,
23 | scenester farm-to-table banksy Austin twitter handle freegan
24 | cred raw denim single-origin coffee viral.
25 |
26 | );
27 |
28 | ReactDOM.render(copyInstance, mountNode);
29 |
--------------------------------------------------------------------------------
/docs/src/sections/MenuItemSection.js:
--------------------------------------------------------------------------------
1 | import React from 'react';
2 |
3 | import Anchor from '../Anchor';
4 | import PropTable from '../PropTable';
5 | import ReactPlayground from '../ReactPlayground';
6 | import Samples from '../Samples';
7 |
8 | export default function MenuItemSection() {
9 | return (
10 |
11 |
12 | MenuItem
13 |
14 |
15 |
This component represents a menu item in a dropdown.
16 |
It supports the basic anchor properties href, target, title.
17 |
18 | It also supports different properties of the normal Bootstrap MenuItem.
19 |
20 |
21 | header: To add a header label to sections
22 | divider: Adds an horizontal divider between sections
23 | disabled: shows the item as disabled, and prevents onSelect from firing
24 | eventKey: passed to the callback
25 | onSelect: a callback that is called when the user clicks the item.
26 |
27 |
The callback is called with the following arguments: event and eventKey
28 |
29 |
30 |
31 |
32 |
33 | );
34 | }
35 |
--------------------------------------------------------------------------------
/src/ModalDialog.js:
--------------------------------------------------------------------------------
1 | import classNames from 'classnames';
2 | import React from 'react';
3 | import PropTypes from 'prop-types';
4 |
5 | import { bsClass, bsSizes, getClassSet, prefix, splitBsProps }
6 | from './utils/bootstrapUtils';
7 | import { Size } from './utils/StyleConfig';
8 |
9 | const propTypes = {
10 | /**
11 | * A css class to apply to the Modal dialog DOM node.
12 | */
13 | dialogClassName: PropTypes.string,
14 | };
15 |
16 | class ModalDialog extends React.Component {
17 | render() {
18 | const { dialogClassName, className, style, children, ...props } =
19 | this.props;
20 | const [bsProps, elementProps] = splitBsProps(props);
21 |
22 | const bsClassName = prefix(bsProps);
23 |
24 | const modalStyle = { display: 'block', ...style };
25 |
26 | const dialogClasses = {
27 | ...getClassSet(bsProps),
28 | [bsClassName]: false,
29 | [prefix(bsProps, 'dialog')]: true,
30 | };
31 |
32 | return (
33 |
40 |
41 |
42 | {children}
43 |
44 |
45 |
46 | );
47 | }
48 | }
49 |
50 | ModalDialog.propTypes = propTypes;
51 |
52 | export default bsClass('modal',
53 | bsSizes([Size.LARGE, Size.SMALL], ModalDialog)
54 | );
55 |
--------------------------------------------------------------------------------
/test/GridSpec.js:
--------------------------------------------------------------------------------
1 | import React from 'react';
2 | import ReactTestUtils from 'react-addons-test-utils';
3 | import ReactDOM from 'react-dom';
4 |
5 | import Grid from '../src/Grid';
6 |
7 | describe('', () => {
8 | it('uses "div" by default', () => {
9 | let instance = ReactTestUtils.renderIntoDocument(
10 |
11 | );
12 |
13 | assert.equal(ReactDOM.findDOMNode(instance).nodeName, 'DIV');
14 | });
15 |
16 | it('has "container" class by default', () => {
17 | let instance = ReactTestUtils.renderIntoDocument(
18 |
19 | );
20 | assert.equal(ReactDOM.findDOMNode(instance).className, 'container');
21 | });
22 |
23 | it('turns grid into "full-width" layout via "fluid" property set', () => {
24 | let instance = ReactTestUtils.renderIntoDocument(
25 |
26 | );
27 | assert.equal(ReactDOM.findDOMNode(instance).className, 'container-fluid');
28 | });
29 |
30 | it('should merge additional classes passed in', () => {
31 | let instance = ReactTestUtils.renderIntoDocument(
32 |
33 | );
34 | assert.ok(ReactDOM.findDOMNode(instance).className.match(/\bwhatever\b/));
35 | assert.ok(ReactDOM.findDOMNode(instance).className.match(/\bcontainer-fluid\b/));
36 | });
37 |
38 | it('allows custom elements instead of "div"', () => {
39 | let instance = ReactTestUtils.renderIntoDocument(
40 |
41 | );
42 |
43 | assert.equal(ReactDOM.findDOMNode(instance).nodeName, 'SECTION');
44 | });
45 | });
46 |
--------------------------------------------------------------------------------
/docs/src/sections/FormLayoutSection.js:
--------------------------------------------------------------------------------
1 | import React from 'react';
2 |
3 | import Anchor from '../Anchor';
4 | import PropTable from '../PropTable';
5 | import ReactPlayground from '../ReactPlayground';
6 | import Samples from '../Samples';
7 |
8 | export default function FormLayoutSection() {
9 | return (
10 |
11 |
12 | Form layout Form
13 |
14 |
15 |
Inline forms
16 |
Use {' instead of {'. JSX strips whitespace between lines, so you will need to manually add spaces. Additionally, Bootstrap assigns inline form controls width: auto by default, so you may need to set custom widths.
17 |
18 |
19 |
Horizontal forms
20 |
Use {' instead of {', then use {' '}s to align labels and controls. Do not use {''}
here, as {''} will already serve as a grid row in a horizontal form.
21 |
22 |
23 |
Props
24 |
25 |
Form (only needed for horizontal or inline forms)
26 |
27 |
28 | );
29 | }
30 |
--------------------------------------------------------------------------------
/docs/src/sections/GridSection.js:
--------------------------------------------------------------------------------
1 | import React from 'react';
2 |
3 | import Anchor from '../Anchor';
4 | import PropTable from '../PropTable';
5 | import ReactPlayground from '../ReactPlayground';
6 | import Samples from '../Samples';
7 |
8 | export default function GridSection() {
9 | return (
10 |
11 |
12 | Grid system Grid, Row, Col, Clearfix
13 |
14 |
15 |
Basic Grid
16 |
17 |
18 |
Clearfix
19 |
20 |
Below, the columns won't clear correctly in viewport sm (768px ≤ width < 992px).
21 |
22 |
23 |
Introduce Clearfix, set to visible for the viewports with issue, so that columns clear correctly.
24 |
25 |
26 |
Props
27 |
28 |
Grid
29 |
30 |
31 |
Row
32 |
33 |
34 |
Col
35 |
36 |
37 |
Clearfix
38 |
39 |
40 | );
41 | }
42 |
--------------------------------------------------------------------------------
/docs/src/sections/NavSection.js:
--------------------------------------------------------------------------------
1 | import React from 'react';
2 |
3 | import Anchor from '../Anchor';
4 | import PropTable from '../PropTable';
5 | import ReactPlayground from '../ReactPlayground';
6 | import Samples from '../Samples';
7 |
8 | export default function NavSection() {
9 | return (
10 |
11 |
12 | Navs Nav, NavItem
13 |
14 |
15 |
Navs come in two styles, pills and tabs. Disable a tab by adding disabled.
16 |
17 |
18 |
Dropdown
19 |
Add dropdowns using the NavDropdown component.
20 |
21 |
22 |
Stacked
23 |
They can also be stacked vertically.
24 |
25 |
26 |
Justified
27 |
They can be justified to take the full width of their parent.
28 |
29 |
30 |
Props
31 |
32 |
Nav
33 |
34 |
35 |
NavItem
36 |
37 |
38 | );
39 | }
40 |
--------------------------------------------------------------------------------
/src/ControlLabel.js:
--------------------------------------------------------------------------------
1 | import classNames from 'classnames';
2 | import React from 'react';
3 | import PropTypes from 'prop-types';
4 | import warning from 'warning';
5 |
6 | import { bsClass, getClassSet, splitBsProps } from './utils/bootstrapUtils';
7 |
8 | const propTypes = {
9 | /**
10 | * Uses `controlId` from `` if not explicitly specified.
11 | */
12 | htmlFor: PropTypes.string,
13 | srOnly: PropTypes.bool,
14 | };
15 |
16 | const defaultProps = {
17 | srOnly: false,
18 | };
19 |
20 | const contextTypes = {
21 | $bs_formGroup: PropTypes.object,
22 | };
23 |
24 | class ControlLabel extends React.Component {
25 | render() {
26 | const formGroup = this.context.$bs_formGroup;
27 | const controlId = formGroup && formGroup.controlId;
28 |
29 | const { htmlFor = controlId, srOnly, className, ...props } = this.props;
30 | const [bsProps, elementProps] = splitBsProps(props);
31 |
32 | warning(
33 | controlId == null || htmlFor === controlId,
34 | '`controlId` is ignored on `` when `htmlFor` is specified.'
35 | );
36 |
37 | const classes = {
38 | ...getClassSet(bsProps),
39 | 'sr-only': srOnly,
40 | };
41 |
42 | return (
43 |
48 | );
49 | }
50 | }
51 |
52 | ControlLabel.propTypes = propTypes;
53 | ControlLabel.defaultProps = defaultProps;
54 | ControlLabel.contextTypes = contextTypes;
55 |
56 | export default bsClass('control-label', ControlLabel);
57 |
--------------------------------------------------------------------------------
/test/MediaSpec.js:
--------------------------------------------------------------------------------
1 | import React from 'react';
2 | import ReactTestUtils from 'react-addons-test-utils';
3 | import ReactDOM from 'react-dom';
4 |
5 | import Media from '../src/Media';
6 |
7 | describe('Media', () => {
8 | it('uses "div" by default', () => {
9 | const instance = ReactTestUtils.renderIntoDocument(
10 |
11 | );
12 |
13 | assert.equal(ReactDOM.findDOMNode(instance).nodeName, 'DIV');
14 | });
15 |
16 | it('has "media" class', () => {
17 | const instance = ReactTestUtils.renderIntoDocument(
18 |
19 | );
20 |
21 | assert.include(ReactDOM.findDOMNode(instance).className, 'media');
22 | });
23 |
24 | it('should merge additional classes passed in', () => {
25 | const instance = ReactTestUtils.renderIntoDocument(
26 |
27 | );
28 |
29 | assert.include(ReactDOM.findDOMNode(instance).className, 'media');
30 | assert.include(ReactDOM.findDOMNode(instance).className, 'custom-class');
31 | });
32 |
33 | it('should allow custom elements instead of "div"', () => {
34 | const instance = ReactTestUtils.renderIntoDocument(
35 |
36 | );
37 |
38 | assert.equal(ReactDOM.findDOMNode(instance).nodeName, 'SECTION');
39 | });
40 |
41 | it('should render children', () => {
42 | const instance = ReactTestUtils.renderIntoDocument(
43 |
44 | Children
45 |
46 | );
47 | assert.ok(ReactTestUtils.findRenderedDOMComponentWithTag(instance, 'strong'));
48 | });
49 | });
50 |
--------------------------------------------------------------------------------
/test/TooltipSpec.js:
--------------------------------------------------------------------------------
1 | import pick from 'lodash/pick';
2 | import React from 'react';
3 | import ReactTestUtils from 'react-addons-test-utils';
4 |
5 | import Tooltip from '../src/Tooltip';
6 |
7 | describe('Tooltip', () => {
8 | it('Should output a tooltip with content', () => {
9 | let instance = ReactTestUtils.renderIntoDocument(
10 |
15 | Tooltip Content
16 |
17 | );
18 | assert.ok(ReactTestUtils.findRenderedDOMComponentWithTag(instance, 'strong'));
19 |
20 | const tooltip = ReactTestUtils.findRenderedDOMComponentWithClass(instance, 'tooltip');
21 | expect(pick(tooltip.style, ['top', 'left']))
22 | .to.eql({ top: '10px', left: '20px' });
23 | });
24 |
25 | describe('When a style property is provided', () => {
26 | it('Should render a tooltip with merged styles', () => {
27 | let instance = ReactTestUtils.renderIntoDocument(
28 |
34 | Tooltip Content
35 |
36 | );
37 | const tooltip = ReactTestUtils.findRenderedDOMComponentWithClass(instance, 'tooltip');
38 | expect(pick(tooltip.style, ['top', 'left']))
39 | .to.eql({ top: '10px', left: '20px' });
40 | // Decimal point string depends on locale
41 | expect(parseFloat(tooltip.style.opacity)).to.eql(0.9);
42 | });
43 | });
44 | });
45 |
--------------------------------------------------------------------------------
/docs/examples/TabsWithDropdown.js:
--------------------------------------------------------------------------------
1 | const tabsInstance = (
2 |
3 |
4 |
5 |
6 |
7 | Tab 1
8 |
9 |
10 | Tab 2
11 |
12 |
13 | Action
14 | Another action
15 | Something else here
16 |
17 | Separated link
18 |
19 |
20 |
21 |
22 |
23 |
24 | Tab 1 content
25 |
26 |
27 | Tab 2 content
28 |
29 |
30 | Tab 3.1 content
31 |
32 |
33 | Tab 3.2 content
34 |
35 |
36 | Tab 3.3 content
37 |
38 |
39 | Tab 3.4 content
40 |
41 |
42 |
43 |
44 |
45 | );
46 |
47 | ReactDOM.render(tabsInstance, mountNode);
48 |
--------------------------------------------------------------------------------
/test/ModalBodySpec.js:
--------------------------------------------------------------------------------
1 | import React from 'react';
2 | import ReactTestUtils from 'react-addons-test-utils';
3 | import ReactDOM from 'react-dom';
4 |
5 | import Modal from '../src/Modal';
6 |
7 | describe('Modal.Body', () => {
8 | it('uses "div" by default', () => {
9 | const instance = ReactTestUtils.renderIntoDocument(
10 |
11 | );
12 |
13 | assert.equal(ReactDOM.findDOMNode(instance).nodeName, 'DIV');
14 | });
15 |
16 | it('has "modal-body" class', () => {
17 | const instance = ReactTestUtils.renderIntoDocument(
18 |
19 | );
20 |
21 | assert.include(ReactDOM.findDOMNode(instance).className, 'modal-body');
22 | });
23 |
24 | it('should merge additional classes passed in', () => {
25 | const instance = ReactTestUtils.renderIntoDocument(
26 |
27 | );
28 | const classes = ReactDOM.findDOMNode(instance).className;
29 |
30 | assert.include(classes, 'modal-body');
31 | assert.include(classes, 'custom-class');
32 | });
33 |
34 | it('should allow custom elements instead of "div"', () => {
35 | const instance = ReactTestUtils.renderIntoDocument(
36 |
37 | );
38 |
39 | assert.equal(ReactDOM.findDOMNode(instance).nodeName, 'SECTION');
40 | });
41 |
42 | it('should render children', () => {
43 | const instance = ReactTestUtils.renderIntoDocument(
44 |
45 | Content
46 |
47 | );
48 | assert.ok(ReactTestUtils.findRenderedDOMComponentWithTag(instance, 'strong'));
49 | });
50 | });
51 |
--------------------------------------------------------------------------------
/test/ModalTitleSpec.js:
--------------------------------------------------------------------------------
1 | import React from 'react';
2 | import ReactTestUtils from 'react-addons-test-utils';
3 | import ReactDOM from 'react-dom';
4 |
5 | import Modal from '../src/Modal';
6 |
7 | describe('Modal.Title', () => {
8 | it('uses "h4" by default', () => {
9 | const instance = ReactTestUtils.renderIntoDocument(
10 |
11 | );
12 |
13 | assert.equal(ReactDOM.findDOMNode(instance).nodeName, 'H4');
14 | });
15 |
16 | it('has "modal-title" class', () => {
17 | const instance = ReactTestUtils.renderIntoDocument(
18 |
19 | );
20 |
21 | assert.include(ReactDOM.findDOMNode(instance).className, 'modal-title');
22 | });
23 |
24 | it('should merge additional classes passed in', () => {
25 | const instance = ReactTestUtils.renderIntoDocument(
26 |
27 | );
28 | const classes = ReactDOM.findDOMNode(instance).className;
29 |
30 | assert.include(classes, 'modal-title');
31 | assert.include(classes, 'custom-class');
32 | });
33 |
34 | it('should allow custom elements instead of "h4"', () => {
35 | const instance = ReactTestUtils.renderIntoDocument(
36 |
37 | );
38 |
39 | assert.equal(ReactDOM.findDOMNode(instance).nodeName, 'H3');
40 | });
41 |
42 | it('should render children', () => {
43 | const instance = ReactTestUtils.renderIntoDocument(
44 |
45 | Children
46 |
47 | );
48 | assert.ok(ReactTestUtils.findRenderedDOMComponentWithTag(instance, 'strong'));
49 | });
50 | });
51 |
--------------------------------------------------------------------------------
/test/MediaBodySpec.js:
--------------------------------------------------------------------------------
1 | import React from 'react';
2 | import ReactTestUtils from 'react-addons-test-utils';
3 | import ReactDOM from 'react-dom';
4 |
5 | import Media from '../src/Media';
6 |
7 | describe('', () => {
8 | it('uses "div" by default', () => {
9 | const instance = ReactTestUtils.renderIntoDocument(
10 |
11 | );
12 |
13 | assert.equal(ReactDOM.findDOMNode(instance).nodeName, 'DIV');
14 | });
15 |
16 | it('has "media-body" class', () => {
17 | const instance = ReactTestUtils.renderIntoDocument(
18 |
19 | );
20 |
21 | assert.include(ReactDOM.findDOMNode(instance).className, 'media-body');
22 | });
23 |
24 | it('should merge additional classes passed in', () => {
25 | const instance = ReactTestUtils.renderIntoDocument(
26 |
27 | );
28 | const classes = ReactDOM.findDOMNode(instance).className;
29 |
30 | assert.include(classes, 'media-body');
31 | assert.include(classes, 'custom-class');
32 | });
33 |
34 | it('should allow custom elements instead of "div"', () => {
35 | const instance = ReactTestUtils.renderIntoDocument(
36 |
37 | );
38 |
39 | assert.equal(ReactDOM.findDOMNode(instance).nodeName, 'SECTION');
40 | });
41 |
42 | it('should render children', () => {
43 | const instance = ReactTestUtils.renderIntoDocument(
44 |
45 | Content
46 |
47 | );
48 | assert.ok(ReactTestUtils.findRenderedDOMComponentWithTag(instance, 'strong'));
49 | });
50 | });
51 |
--------------------------------------------------------------------------------