Skip to content

Commit 346501e

Browse files
committed
[changed] DropdownButton, SplitButton, DropdownMenu, MenuItem completely rewritten
Adds: - Keyboard Navigation - Aria properties for Assistive Technology - Option to use custom menu with any of the dropdown variations - `NavDropdown` component (Similar to `DropdownButton` but specifically for use within `Nav` components. - `DropdownToggle` Component which can be used as an alternative to the `DropdownButton` `title` prop. Can either be directly imported or used as a static property of the `DropdownButton` with `DropdownButton.Toggle`. _(Useful should you want to use glyphicons or custom html within the toggle that's not a simple string.)_ - `SplitToggle` Similar to the `DropdownToggle` but targeted at the `SplitButton`'s toggle. - Generic `Dropdown` component for easy dropdown customization. Changed: - Event handling of all these components to be in line with react-bootstrap#419 - Written with ES6 class syntax Removed: - DropdownStateMixin - Everything is using ES6 class syntax so no more mixin usage
1 parent 6f13e04 commit 346501e

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

55 files changed

+2150
-938
lines changed

.ackrc

+2
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,4 @@
1+
--ignore-dir=.coverage
12
--ignore-dir=lib
23
--ignore-dir=dist
34
--ignore-dir=amd
@@ -7,3 +8,4 @@
78
--ignore-dir=tmp-bower-repo
89
--ignore-file=match:test_bundle.js
910
--ignore-file=match:components.html
11+
--ignore-file=match:.orig

.eslintrc

+4-2
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,8 @@
1010
"parser": "babel-eslint",
1111
"plugins": [
1212
"react",
13-
"babel"
13+
"babel",
14+
"lodash"
1415
],
1516
"rules": {
1617
"constructor-super": 2,
@@ -32,11 +33,12 @@
3233
"react/no-did-mount-set-state": 2,
3334
"react/no-did-update-set-state": 2,
3435
"react/no-multi-comp": 2,
35-
"react/prop-types": [2, { "ignore": [ "children", "className" ] }],
36+
"react/prop-types": [1, { "ignore": [ "children", "className" ] }],
3637
"react/react-in-jsx-scope": 2,
3738
"react/self-closing-comp": 2,
3839
"react/wrap-multilines": 2,
3940
"react/jsx-uses-vars": 2,
41+
"lodash/import": 2,
4042
"space-infix-ops": 2,
4143
"strict": [2, "never"]
4244
}

.projections.json

+4
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,4 @@
1+
{
2+
"src/*.js": { "alternate": "test/{}Spec.js" },
3+
"test/*Spec.js": { "alternate": "src/{}.js" }
4+
}

docs/assets/style.css

+34-1
Original file line numberDiff line numberDiff line change
@@ -36,7 +36,7 @@ body {
3636
}
3737
}
3838

39-
.navbar>.container .navbar-brand, .navbar>.container-fluid .navbar-brand {
39+
.bs-docs-nav .navbar-brand {
4040
color: #00d8ff;
4141
}
4242

@@ -173,6 +173,29 @@ body {
173173

174174
}
175175

176+
.bs-example .super-colors {
177+
background: -moz-linear-gradient( top ,
178+
rgba(255, 0, 0, 1) 0%,
179+
rgba(255, 255, 0, 1) 15%,
180+
rgba(0, 255, 0, 1) 30%,
181+
rgba(0, 255, 255, 1) 50%,
182+
rgba(0, 0, 255, 1) 65%,
183+
rgba(255, 0, 255, 1) 80%,
184+
rgba(255, 0, 0, 1) 100%);
185+
background: -webkit-gradient(linear, left top, left bottom,
186+
color-stop(0%, rgba(255, 0, 0, 1)),
187+
color-stop(15%, rgba(255, 255, 0, 1)),
188+
color-stop(30%, rgba(0, 255, 0, 1)),
189+
color-stop(50%, rgba(0, 255, 255, 1)),
190+
color-stop(65%, rgba(0, 0, 255, 1)),
191+
color-stop(80%, rgba(255, 0, 255, 1)),
192+
color-stop(100%, rgba(255, 0, 0, 1)));
193+
}
194+
195+
/*.bs-example .custom-menu > ul > li {
196+
padding: 0 20px;
197+
}*/
198+
176199
.anchor,
177200
.anchor:hover,
178201
.anchor:active,
@@ -199,3 +222,13 @@ h4:hover .anchor-icon,
199222
h4 a:focus .anchor-icon {
200223
opacity: 0.5;
201224
}
225+
226+
.prop-desc pre {
227+
border-radius: 0;
228+
border-width: 0;
229+
border-left-width: 3px;
230+
}
231+
232+
.prop-desc-heading {
233+
margin-bottom: 10px;
234+
}

docs/examples/.eslintrc

+3
Original file line numberDiff line numberDiff line change
@@ -19,7 +19,9 @@
1919
"Carousel",
2020
"CarouselItem",
2121
"Col",
22+
"Dropdown",
2223
"DropdownButton",
24+
"DropdownMenu",
2325
"FormControls",
2426
"Glyphicon",
2527
"Grid",
@@ -30,6 +32,7 @@
3032
"ListGroupItem",
3133
"Nav",
3234
"Navbar",
35+
"NavDropdown",
3336
"NavItem",
3437
"MenuItem",
3538
"Modal",

docs/examples/ButtonGroupJustified.js

+1-1
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@ const buttonGroupInstance = (
22
<ButtonGroup justified>
33
<Button href='#'>Left</Button>
44
<Button href='#'>Middle</Button>
5-
<DropdownButton title='Dropdown'>
5+
<DropdownButton title='Dropdown' id='bg-justified-dropdown'>
66
<MenuItem eventKey='1'>Dropdown link</MenuItem>
77
<MenuItem eventKey='2'>Dropdown link</MenuItem>
88
</DropdownButton>

docs/examples/ButtonGroupNested.js

+1-1
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@ const buttonGroupInstance = (
22
<ButtonGroup>
33
<Button>1</Button>
44
<Button>2</Button>
5-
<DropdownButton title='Dropdown'>
5+
<DropdownButton title='Dropdown' id='bg-nested-dropdown'>
66
<MenuItem eventKey='1'>Dropdown link</MenuItem>
77
<MenuItem eventKey='2'>Dropdown link</MenuItem>
88
</DropdownButton>

docs/examples/ButtonGroupVertical.js

+3-3
Original file line numberDiff line numberDiff line change
@@ -2,17 +2,17 @@ const buttonGroupInstance = (
22
<ButtonGroup vertical>
33
<Button>Button</Button>
44
<Button>Button</Button>
5-
<DropdownButton title='Dropdown'>
5+
<DropdownButton title='Dropdown' id='bg-vertical-dropdown-1'>
66
<MenuItem eventKey='1'>Dropdown link</MenuItem>
77
<MenuItem eventKey='2'>Dropdown link</MenuItem>
88
</DropdownButton>
99
<Button>Button</Button>
1010
<Button>Button</Button>
11-
<DropdownButton title='Dropdown'>
11+
<DropdownButton title='Dropdown' id='bg-vertical-dropdown-2'>
1212
<MenuItem eventKey='1'>Dropdown link</MenuItem>
1313
<MenuItem eventKey='2'>Dropdown link</MenuItem>
1414
</DropdownButton>
15-
<DropdownButton title='Dropdown'>
15+
<DropdownButton title='Dropdown' id='bg-vertical-dropdown-3'>
1616
<MenuItem eventKey='1'>Dropdown link</MenuItem>
1717
<MenuItem eventKey='2'>Dropdown link</MenuItem>
1818
</DropdownButton>

docs/examples/CollapsibleNav.js

+2-2
Original file line numberDiff line numberDiff line change
@@ -4,13 +4,13 @@ const navbarInstance = (
44
<Nav navbar>
55
<NavItem eventKey={1} href='#'>Link</NavItem>
66
<NavItem eventKey={2} href='#'>Link</NavItem>
7-
<DropdownButton eventKey={3} title='Dropdown'>
7+
<NavDropdown eventKey={3} title='Dropdown' id='collapsible-nav-dropdown'>
88
<MenuItem eventKey='1'>Action</MenuItem>
99
<MenuItem eventKey='2'>Another action</MenuItem>
1010
<MenuItem eventKey='3'>Something else here</MenuItem>
1111
<MenuItem divider />
1212
<MenuItem eventKey='4'>Separated link</MenuItem>
13-
</DropdownButton>
13+
</NavDropdown>
1414
</Nav>
1515
<Nav navbar right>
1616
<NavItem eventKey={1} href='#'>Link Right</NavItem>

docs/examples/DropdownButtonBasic.js

+1-1
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@ const BUTTONS = ['Default', 'Primary', 'Success', 'Info', 'Warning', 'Danger', '
22

33
function renderDropdownButton (title, i) {
44
return (
5-
<DropdownButton bsStyle={title.toLowerCase()} title={title} key={i}>
5+
<DropdownButton bsStyle={title.toLowerCase()} title={title} key={i} id={`dropdown-basic-${i}`}>
66
<MenuItem eventKey='1'>Action</MenuItem>
77
<MenuItem eventKey='2'>Another action</MenuItem>
88
<MenuItem eventKey='3' active>Active Item</MenuItem>

docs/examples/DropdownButtonCustom.js

+35
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,35 @@
1+
2+
const dropdownInstance = (
3+
<ButtonToolbar>
4+
<Dropdown id='dropdown-custom-1'>
5+
<Dropdown.Toggle>
6+
<Glyphicon glyph='star' />
7+
Pow! Zoom!
8+
</Dropdown.Toggle>
9+
<Dropdown.Menu className='super-colors'>
10+
<MenuItem eventKey='1'>Action</MenuItem>
11+
<MenuItem eventKey='2'>Another action</MenuItem>
12+
<MenuItem eventKey='3' active>Active Item</MenuItem>
13+
<MenuItem divider />
14+
<MenuItem eventKey='4'>Separated link</MenuItem>
15+
</Dropdown.Menu>
16+
</Dropdown>
17+
18+
<Dropdown id='dropdown-custom-2'>
19+
<Button bsStyle='info'>
20+
mix it up style-wise
21+
</Button>
22+
<Dropdown.Toggle bsStyle='success'/>
23+
<Dropdown.Menu className='super-colors'>
24+
<MenuItem eventKey='1'>Action</MenuItem>
25+
<MenuItem eventKey='2'>Another action</MenuItem>
26+
<MenuItem eventKey='3' active>Active Item</MenuItem>
27+
<MenuItem divider />
28+
<MenuItem eventKey='4'>Separated link</MenuItem>
29+
</Dropdown.Menu>
30+
</Dropdown>
31+
32+
</ButtonToolbar>
33+
);
34+
35+
React.render(dropdownInstance, mountNode);
+75
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,75 @@
1+
2+
class CustomMenu extends React.Component {
3+
4+
constructor(...args){
5+
super(...args);
6+
this.state = { value: '' };
7+
this.onChange = e => this.setState({ value: e.target.value });
8+
}
9+
10+
render(){
11+
let { className, ...props } = this.props;
12+
13+
return (
14+
<div
15+
className={'dropdown-menu'}
16+
style={{ padding: '5px 10px'}}
17+
>
18+
<input
19+
ref={input => this.input = input}
20+
type='text'
21+
className='form-control'
22+
placeholder='type to filter...'
23+
onChange={this.onChange}
24+
value={this.state.value}
25+
/>
26+
<ul className='list-unstyled'>
27+
{ this.filterChildren() }
28+
</ul>
29+
</div>
30+
);
31+
}
32+
33+
filterChildren(){
34+
let { children } = this.props;
35+
let { value } = this.state;
36+
let filtered = [];
37+
38+
let matches = child => child.props.children.indexOf(value) !== -1;
39+
40+
React.Children.forEach(children, child => {
41+
if (!value.trim() || matches(child)) {
42+
filtered.push(child);
43+
}
44+
});
45+
46+
return filtered;
47+
}
48+
49+
focusNext() {
50+
let input = React.findDOMNode(this.input);
51+
52+
if (input) {
53+
input.focus();
54+
}
55+
}
56+
}
57+
58+
let preventDefault = e => e.preventDefault();
59+
60+
let dropdownExample = (
61+
<Dropdown id='dropdown-custom-menu'>
62+
<a href='#' bsRole='toggle' onClick={preventDefault}>
63+
custom Toggle
64+
</a>
65+
66+
<CustomMenu bsRole='menu'>
67+
<MenuItem eventKey='1'>Red</MenuItem>
68+
<MenuItem eventKey='2'>Blue</MenuItem>
69+
<MenuItem eventKey='3' active>Orange</MenuItem>
70+
<MenuItem eventKey='1'>Red-Orange</MenuItem>
71+
</CustomMenu>
72+
</Dropdown>
73+
);
74+
75+
React.render(dropdownExample, mountNode);

docs/examples/DropdownButtonNoCaret.js

+1-1
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
const buttonInstance = (
22
<ButtonToolbar>
3-
<DropdownButton bsStyle='default' title='No caret' noCaret>
3+
<DropdownButton bsStyle='default' title='No caret' noCaret id='dropdown-no-caret'>
44
<MenuItem eventKey='1'>Action</MenuItem>
55
<MenuItem eventKey='2'>Another action</MenuItem>
66
<MenuItem eventKey='3'>Something else here</MenuItem>

docs/examples/DropdownButtonSizes.js

+13-3
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
const buttonsInstance = (
22
<div>
33
<ButtonToolbar>
4-
<DropdownButton bsSize='large' title='Large button'>
4+
<DropdownButton bsSize='large' title='Large button' id='dropdown-size-large'>
55
<MenuItem eventKey='1'>Action</MenuItem>
66
<MenuItem eventKey='2'>Another action</MenuItem>
77
<MenuItem eventKey='3'>Something else here</MenuItem>
@@ -11,7 +11,7 @@ const buttonsInstance = (
1111
</ButtonToolbar>
1212

1313
<ButtonToolbar>
14-
<DropdownButton bsSize='small' title='Small button'>
14+
<DropdownButton bsSize='medium' title='Small button' id='dropdown-size-medium'>
1515
<MenuItem eventKey='1'>Action</MenuItem>
1616
<MenuItem eventKey='2'>Another action</MenuItem>
1717
<MenuItem eventKey='3'>Something else here</MenuItem>
@@ -21,7 +21,17 @@ const buttonsInstance = (
2121
</ButtonToolbar>
2222

2323
<ButtonToolbar>
24-
<DropdownButton bsSize='xsmall' title='Extra small button'>
24+
<DropdownButton bsSize='small' title='Small button' id='dropdown-size-small'>
25+
<MenuItem eventKey='1'>Action</MenuItem>
26+
<MenuItem eventKey='2'>Another action</MenuItem>
27+
<MenuItem eventKey='3'>Something else here</MenuItem>
28+
<MenuItem divider />
29+
<MenuItem eventKey='4'>Separated link</MenuItem>
30+
</DropdownButton>
31+
</ButtonToolbar>
32+
33+
<ButtonToolbar>
34+
<DropdownButton bsSize='xsmall' title='Extra small button' id='dropdown-size-extra-small'>
2535
<MenuItem eventKey='1'>Action</MenuItem>
2636
<MenuItem eventKey='2'>Another action</MenuItem>
2737
<MenuItem eventKey='3'>Something else here</MenuItem>

docs/examples/InputAddons.js

+1-1
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
const innerGlyphicon = <Glyphicon glyph='music' />;
22
const innerButton = <Button>Before</Button>;
33
const innerDropdown = (
4-
<DropdownButton title='Action'>
4+
<DropdownButton title='Action' id='input-dropdown-addon'>
55
<MenuItem key='1'>Item</MenuItem>
66
</DropdownButton>
77
);

docs/examples/MenuItem.js

+3-5
Original file line numberDiff line numberDiff line change
@@ -2,18 +2,16 @@ function onSelectAlert(eventKey, href, target) {
22
alert('Alert from menu item.\neventKey: "' + eventKey + '"\nhref: "' + href + '"');
33
}
44

5-
function preventDefault() {}
6-
75
const MenuItems = (
86
<div className="clearfix">
97
<ul className="dropdown-menu open">
108
<MenuItem header>Header</MenuItem>
11-
<MenuItem onSelect={preventDefault}>link</MenuItem>
9+
<MenuItem>link</MenuItem>
1210
<MenuItem divider/>
1311
<MenuItem header>Header</MenuItem>
14-
<MenuItem onSelect={preventDefault}>link</MenuItem>
12+
<MenuItem>link</MenuItem>
1513
<MenuItem disabled>disabled</MenuItem>
16-
<MenuItem title="See? I have a title." onSelect={preventDefault}>
14+
<MenuItem title="See? I have a title.">
1715
link with title
1816
</MenuItem>
1917
<MenuItem eventKey={1} href="#someHref" onSelect={onSelectAlert}>

docs/examples/NavDropdown.js

+4-4
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
const NavDropdown = React.createClass({
1+
const NavDropdownExample = React.createClass({
22
handleSelect(selectedKey) {
33
alert('selected ' + selectedKey);
44
},
@@ -9,16 +9,16 @@ const NavDropdown = React.createClass({
99
<NavItem eventKey={1} href='/home'>NavItem 1 content</NavItem>
1010
<NavItem eventKey={2} title='Item'>NavItem 2 content</NavItem>
1111
<NavItem eventKey={3} disabled>NavItem 3 content</NavItem>
12-
<DropdownButton eventKey={4} title='Dropdown' navItem>
12+
<NavDropdown eventKey={4} title='Dropdown' id='nav-dropdown'>
1313
<MenuItem eventKey='4.1'>Action</MenuItem>
1414
<MenuItem eventKey='4.2'>Another action</MenuItem>
1515
<MenuItem eventKey='4.3'>Something else here</MenuItem>
1616
<MenuItem divider />
1717
<MenuItem eventKey='4.4'>Separated link</MenuItem>
18-
</DropdownButton>
18+
</NavDropdown>
1919
</Nav>
2020
);
2121
}
2222
});
2323

24-
React.render(<NavDropdown />, mountNode);
24+
React.render(<NavDropdownExample />, mountNode);

0 commit comments

Comments
 (0)