Skip to content

Commit

Permalink
Merge branch 'master' into 'v0.26-rc'
Browse files Browse the repository at this point in the history
  • Loading branch information
AlexKVal committed Sep 27, 2015
2 parents a1494c8 + 59c89b9 commit 4e60f54
Show file tree
Hide file tree
Showing 12 changed files with 357 additions and 2 deletions.
2 changes: 1 addition & 1 deletion .travis.yml
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
sudo: false
language: node_js
node_js:
- "iojs"
- 4
cache:
directories:
- node_modules
Expand Down
2 changes: 2 additions & 0 deletions docs/examples/.eslintrc
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,8 @@
"Accordion",
"Alert",
"Badge",
"Breadcrumb",
"BreadcrumbItem",
"Button",
"ButtonGroup",
"ButtonInput",
Expand Down
15 changes: 15 additions & 0 deletions docs/examples/Breadcrumb.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
const breadcrumbInstance = (
<Breadcrumb>
<BreadcrumbItem href="#">
Home
</BreadcrumbItem>
<BreadcrumbItem href="http://getbootstrap.com/components/#breadcrumbs">
Library
</BreadcrumbItem>
<BreadcrumbItem active>
Data
</BreadcrumbItem>
</Breadcrumb>
);

React.render(breadcrumbInstance, mountNode);
17 changes: 17 additions & 0 deletions docs/src/ComponentsPage.js
Original file line number Diff line number Diff line change
Expand Up @@ -541,6 +541,22 @@ const ComponentsPage = React.createClass({
<PropTable component="Navbar"/>
</div>

{/* Breadcrumb */}
<div className="bs-docs-section">
<h1 className="page-header"><Anchor id="breadcrumbs">Breadcrumbs</Anchor> <small>Breadcrumb, BreadcrumbItems</small></h1>
<p>Breadcrumbs are used to indicate the current page's location. Add <code>active</code> attribute to active <code>BreadcrumbItem</code>.</p>
<p>Do not set both <code>active</code> and <code>href</code> attributes. <code>active</code> overrides <code>href</code> and <code>span</code> element is rendered instead of <code>a</code>.</p>

<h3><Anchor id="breadcrumbs-example">Breadcrumbs Example</Anchor></h3>
<ReactPlayground codeText={Samples.Breadcrumb} />

<h3><Anchor id="breadcrumbs-props">Props</Anchor></h3>
<p><code>Breadcrumb</code> component itself doesn't have any specific public properties</p>

<h4><Anchor id="breadcrumbs-props-breadcrumbItem">BreadcrumbItem</Anchor></h4>
<PropTable component="BreadcrumbItem"/>
</div>

{/* Tabbed Areas */}
<div className="bs-docs-section">
<h1 className="page-header"><Anchor id="tabs">Togglable tabs</Anchor> <small>Tabs, Tab</small></h1>
Expand Down Expand Up @@ -947,6 +963,7 @@ const ComponentsPage = React.createClass({
<NavItem href="#progress" key={8}>Progress bars</NavItem>
<NavItem href="#navs" key={9}>Navs</NavItem>
<NavItem href="#navbars" key={10}>Navbars</NavItem>
<NavItem href="#breadcrumbs" key={30}>Breadcrumbs</NavItem>
<NavItem href="#tabs" key={11}>Tabs</NavItem>
<NavItem href="#pager" key={12}>Pager</NavItem>
<NavItem href="#pagination" key={13}>Pagination</NavItem>
Expand Down
2 changes: 2 additions & 0 deletions docs/src/ReactPlayground.js
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,8 @@ const React = require('react');
const Accordion = require('../../src/Accordion');
const Alert = require('../../src/Alert');
const Badge = require('../../src/Badge');
const Breadcrumb = require('../../src/Breadcrumb');
const BreadcrumbItem = require('../../src/BreadcrumbItem');
const Button = require('../../src/Button');
const ButtonGroup = require('../../src/ButtonGroup');
const ButtonInput = require('../../src/ButtonInput');
Expand Down
1 change: 1 addition & 0 deletions docs/src/Samples.js
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ export default {
Collapse: require('fs').readFileSync(__dirname + '/../examples/Collapse.js', 'utf8'),
Fade: require('fs').readFileSync(__dirname + '/../examples/Fade.js', 'utf8'),

Breadcrumb: require('fs').readFileSync(__dirname + '/../examples/Breadcrumb.js', 'utf8'),
ButtonTypes: require('fs').readFileSync(__dirname + '/../examples/ButtonTypes.js', 'utf8'),
ButtonSizes: require('fs').readFileSync(__dirname + '/../examples/ButtonSizes.js', 'utf8'),
ButtonBlock: require('fs').readFileSync(__dirname + '/../examples/ButtonBlock.js', 'utf8'),
Expand Down
39 changes: 39 additions & 0 deletions src/Breadcrumb.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
import React, { cloneElement } from 'react';
import classNames from 'classnames';
import ValidComponentChildren from './utils/ValidComponentChildren';

const Breadcrumb = React.createClass({
propTypes: {
/**
* bootstrap className
* @private
*/
bsClass: React.PropTypes.string
},

getDefaultProps() {
return {
bsClass: 'breadcrumb'
};
},

render() {
const { className, ...props } = this.props;

return (
<ol
{...props}
role="navigation"
aria-label="breadcrumbs"
className={classNames(className, this.props.bsClass)}>
{ValidComponentChildren.map(this.props.children, this.renderBreadcrumbItem)}
</ol>
);
},

renderBreadcrumbItem(child, index) {
return cloneElement( child, { key: child.key ? child.key : index } );
}
});

export default Breadcrumb;
83 changes: 83 additions & 0 deletions src/BreadcrumbItem.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,83 @@
import React from 'react';
import classNames from 'classnames';
import SafeAnchor from './SafeAnchor';
import warning from 'react/lib/warning';

const BreadcrumbItem = React.createClass({
propTypes: {
/**
* If set to true, renders `span` instead of `a`
*/
active: React.PropTypes.bool,
/**
* HTML id for the wrapper `li` element
*/
id: React.PropTypes.oneOfType([
React.PropTypes.string,
React.PropTypes.number
]),
/**
* HTML id for the inner `a` element
*/
linkId: React.PropTypes.oneOfType([
React.PropTypes.string,
React.PropTypes.number
]),
/**
* `href` attribute for the inner `a` element
*/
href: React.PropTypes.string,
/**
* `title` attribute for the inner `a` element
*/
title: React.PropTypes.node,
/**
* `target` attribute for the inner `a` element
*/
target: React.PropTypes.string
},

getDefaultProps() {
return {
active: false,
};
},

render() {
const {
active,
className,
id,
linkId,
children,
href,
title,
target,
...props } = this.props;

warning(!(href && active), '[react-bootstrap] `href` and `active` properties cannot be set at the same time');

const linkProps = {
href,
title,
target,
id: linkId
};

return (
<li id={id} className={classNames(className, { active })}>
{
active ?
<span {...props}>
{ children }
</span> :
<SafeAnchor {...props} {...linkProps}>
{ children }
</SafeAnchor>
}
</li>
);
}
});

export default BreadcrumbItem;
2 changes: 1 addition & 1 deletion src/Input.js
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ import deprecationWarning from './utils/deprecationWarning';
class Input extends InputBase {
render() {
if (this.props.type === 'static') {
deprecationWarning('Input type=static', 'StaticText');
deprecationWarning('Input type=static', 'FormControls.Static');
return <FormControls.Static {...this.props} />;
}

Expand Down
2 changes: 2 additions & 0 deletions src/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,8 @@ export Button from './Button';
export ButtonGroup from './ButtonGroup';
export ButtonInput from './ButtonInput';
export ButtonToolbar from './ButtonToolbar';
export Breadcrumb from './Breadcrumb';
export BreadcrumbItem from './BreadcrumbItem';
export Carousel from './Carousel';
export CarouselItem from './CarouselItem';
export Col from './Col';
Expand Down
140 changes: 140 additions & 0 deletions test/BreadcrumbItemSpec.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,140 @@
import React from 'react';
import ReactTestUtils from 'react/lib/ReactTestUtils';
import BreadcrumbItem from '../src/BreadcrumbItem';
import { shouldWarn } from './helpers';

describe('BreadcrumbItem', () => {
it('Should warn if `active` and `href` attributes set', () => {
ReactTestUtils.renderIntoDocument(
<BreadcrumbItem href='#' active>
Crumb
</BreadcrumbItem>
);

shouldWarn('[react-bootstrap] `href` and `active` properties cannot be set at the same time');
});

it('Should render `a` as inner element when is not active', () => {
const instance = ReactTestUtils.renderIntoDocument(
<BreadcrumbItem href='#'>
Crumb
</BreadcrumbItem>
);

assert.ok(ReactTestUtils.findRenderedDOMComponentWithTag(instance, 'a'));
assert.notInclude(React.findDOMNode(instance).className, 'active');
});

it('Should add `active` class with `active` attribute set.', () => {
const instance = ReactTestUtils.renderIntoDocument(
<BreadcrumbItem active>
Active Crumb
</BreadcrumbItem>
);

assert.include(React.findDOMNode(instance).className, 'active');
});

it('Should render `span` as inner element when is active', () => {
const instance = ReactTestUtils.renderIntoDocument(
<BreadcrumbItem active>
Crumb
</BreadcrumbItem>
);

assert.ok(ReactTestUtils.findRenderedDOMComponentWithTag(instance, 'span'));
});

it('Should add custom classes onto `li` wrapper element', () => {
const instance = ReactTestUtils.renderIntoDocument(
<BreadcrumbItem className="custom-one custom-two">
Active Crumb
</BreadcrumbItem>
);

const classes = React.findDOMNode(instance).className;
assert.include(classes, 'custom-one');
assert.include(classes, 'custom-two');
});

it('Should spread additional props onto inner element', (done) => {
const handleClick = () => {
done();
};

const instance = ReactTestUtils.renderIntoDocument(
<BreadcrumbItem href='#' onClick={handleClick}>
Crumb
</BreadcrumbItem>
);

const anchorNode = ReactTestUtils.findRenderedDOMComponentWithTag(instance, 'a');
ReactTestUtils.Simulate.click(anchorNode);
});

it('Should apply id onto `li` wrapper element via `id` property', () => {
const instance = ReactTestUtils.renderIntoDocument(
<BreadcrumbItem href='#' id='test-li-id'>
Crumb
</BreadcrumbItem>
);

assert.equal(React.findDOMNode(instance).id, 'test-li-id');
});

it('Should apply id onto `a` inner alement via `linkId` property', () => {
const instance = ReactTestUtils.renderIntoDocument(
<BreadcrumbItem href='#' linkId='test-link-id'>
Crumb
</BreadcrumbItem>
);

const linkNode = React.findDOMNode(ReactTestUtils.findRenderedDOMComponentWithTag(instance, 'a'));
assert.equal(linkNode.id, 'test-link-id');
});

it('Should apply `href` property onto `a` inner element', () => {
const instance = ReactTestUtils.renderIntoDocument(
<BreadcrumbItem href='http://getbootstrap.com/components/#breadcrumbs'>
Crumb
</BreadcrumbItem>
);

const linkNode = React.findDOMNode(ReactTestUtils.findRenderedDOMComponentWithTag(instance, 'a'));
assert.equal(linkNode.href, 'http://getbootstrap.com/components/#breadcrumbs');
});

it('Should apply `title` property onto `a` inner element', () => {
const instance = ReactTestUtils.renderIntoDocument(
<BreadcrumbItem title='test-title' href='http://getbootstrap.com/components/#breadcrumbs'>
Crumb
</BreadcrumbItem>
);

const linkNode = React.findDOMNode(ReactTestUtils.findRenderedDOMComponentWithTag(instance, 'a'));
assert.equal(linkNode.title, 'test-title');
});

it('Should not apply properties for inner `anchor` onto `li` wrapper element', () => {
const instance = ReactTestUtils.renderIntoDocument(
<BreadcrumbItem title='test-title' href='/hi'>
Crumb
</BreadcrumbItem>
);

const liNode = React.findDOMNode(instance);
assert.notOk(liNode.hasAttribute('href'));
assert.notOk(liNode.hasAttribute('title'));
});

it('Should set `target` attribute on `anchor`', () => {
const instance = ReactTestUtils.renderIntoDocument(
<BreadcrumbItem target='_blank' href='http://getbootstrap.com/components/#breadcrumbs'>
Crumb
</BreadcrumbItem>
);

const linkNode = React.findDOMNode(ReactTestUtils.findRenderedDOMComponentWithTag(instance, 'a'));
assert.equal(linkNode.target, '_blank');
});
});
Loading

0 comments on commit 4e60f54

Please sign in to comment.