diff --git a/docs/src/app/components/pages/components/left-nav.jsx b/docs/src/app/components/pages/components/left-nav.jsx index d809878f5ea6fc..50318c4d5f38a5 100644 --- a/docs/src/app/components/pages/components/left-nav.jsx +++ b/docs/src/app/components/pages/components/left-nav.jsx @@ -20,7 +20,9 @@ var LeftNavPage = React.createClass({ { route: 'css-framework', text: 'CSS Framework' }, { route: 'components', text: 'Components' }, { type: MenuItem.Types.SUBHEADER, text: 'Resources' }, - { type: MenuItem.Types.LINK, payload: 'https://github.com/callemall/material-ui', text: 'GitHub' } + { type: MenuItem.Types.LINK, payload: 'https://github.com/callemall/material-ui', text: 'GitHub' }, + { text: 'Disabled', disabled: true }, + { type: MenuItem.Types.LINK, payload: 'https://www.google.com', text: 'Disabled Link', disabled: true } ]; var code = @@ -34,6 +36,16 @@ var LeftNavPage = React.createClass({ ' payload: \'https://github.com/callemall/material-ui\', \n' + ' text: \'GitHub\' \n' + ' },\n' + + ' { \n' + + ' text: \'Disabled\', \n' + + ' disabled: true \n' + + ' },\n' + + ' { \n' + + ' type: MenuItem.Types.LINK, \n' + + ' payload: \'https://www.google.com\', \n' + + ' text: \'Disabled Link\', \n' + + ' disabled: true \n' + + ' },\n' + '];\n\n' + '//Docked Left Nav\n' + '\n\n' + diff --git a/docs/src/app/components/pages/components/menus.jsx b/docs/src/app/components/pages/components/menus.jsx index 9abe8288701966..1bfa65fb2adbde 100644 --- a/docs/src/app/components/pages/components/menus.jsx +++ b/docs/src/app/components/pages/components/menus.jsx @@ -31,27 +31,27 @@ var nestedMenuItems = [ { type: mui.MenuItem.Types.NESTED, text: 'Reports', items: [ { payload: '1', text: 'Nested Item 1' }, { type: mui.MenuItem.Types.NESTED, text: 'Nested Item 2', items: [ - { payload: '1', text: 'Nested Item 3' }, - { type: mui.MenuItem.Types.NESTED, text: 'Nested Item 4', items: [ - { payload: '1', text: 'Nested Item 5' }, - { payload: '3', text: 'Nested Item 6' } + { payload: '1', text: 'Nested Item 2.1' }, + { type: mui.MenuItem.Types.NESTED, text: 'Nested Item 2.2', items: [ + { payload: '1', text: 'Nested Item 2.2.1' }, + { payload: '3', text: 'Nested Item 2.2.2' } ] }, - { payload: '3', text: 'Nested Item 7' } + { payload: '3', text: 'Nested Item 2.3' } ] }, - { payload: '3', text: 'Nested Item 9' }, - { type: mui.MenuItem.Types.NESTED, text: 'Nested Item 2', items: [ - { payload: '1', text: 'Nested Item 3' }, - { type: mui.MenuItem.Types.NESTED, text: 'Nested Item 4', items: [ - { payload: '1', text: 'Nested Item 5' }, - { payload: '3', text: 'Nested Item 6' } + { payload: '3', text: 'Nested Item 3' }, + { type: mui.MenuItem.Types.NESTED, text: 'Nested Item 4', items: [ + { payload: '1', text: 'Nested Item 4.1' }, + { type: mui.MenuItem.Types.NESTED, text: 'Nested Item 4.2', items: [ + { payload: '1', text: 'Nested Item 4.2.1', disabled: true }, + { payload: '3', text: 'Nested Item 4.2.2' } ] }, - { payload: '3', text: 'Nested Item 7' } + { payload: '3', text: 'Nested Item 4.3' } ] }, - { payload: '4', text: 'Nested Item 10' } + { payload: '4', text: 'Nested Item 5' } ] }, { payload: '1', text: 'Audio Library'}, { payload: '2', text: 'Settings'}, - { payload: '3', text: 'Logout'} + { payload: '3', text: 'Logout', disabled: true} ]; @@ -160,27 +160,27 @@ var MenusPage = React.createClass({ " { type: mui.MenuItem.Types.NESTED, text: 'Reports', items: [\n" + " { payload: '1', text: 'Nested Item 1' },\n" + " { type: mui.MenuItem.Types.NESTED, text: 'Nested Item 2', items: [\n" + - " { payload: '1', text: 'Nested Item 3' },\n" + - " { type: mui.MenuItem.Types.NESTED, text: 'Nested Item 4', items: [\n" + - " { payload: '1', text: 'Nested Item 5' },\n" + - " { payload: '3', text: 'Nested Item 6' }\n" + + " { payload: '1', text: 'Nested Item 2.1' },\n" + + " { type: mui.MenuItem.Types.NESTED, text: 'Nested Item 2.2', items: [\n" + + " { payload: '1', text: 'Nested Item 2.2.1' },\n" + + " { payload: '3', text: 'Nested Item 2.2.2' }\n" + " ] },\n" + - " { payload: '3', text: 'Nested Item 7' }\n" + + " { payload: '3', text: 'Nested Item 2.3' }\n" + " ] },\n" + - " { payload: '3', text: 'Nested Item 9' },\n" + - " { type: mui.MenuItem.Types.NESTED, text: 'Nested Item 2', items: [\n" + - " { payload: '1', text: 'Nested Item 3' },\n" + - " { type: mui.MenuItem.Types.NESTED, text: 'Nested Item 4', items: [\n" + - " { payload: '1', text: 'Nested Item 5' },\n" + - " { payload: '3', text: 'Nested Item 6' }\n" + + " { payload: '3', text: 'Nested Item 3' },\n" + + " { type: mui.MenuItem.Types.NESTED, text: 'Nested Item 4', items: [\n" + + " { payload: '1', text: 'Nested Item 4.1' },\n" + + " { type: mui.MenuItem.Types.NESTED, text: 'Nested Item 4.2', items: [\n" + + " { payload: '1', text: 'Nested Item 4.2.1', disabled: true },\n" + + " { payload: '3', text: 'Nested Item 4.2.2' }\n" + " ] },\n" + - " { payload: '3', text: 'Nested Item 7' }\n" + + " { payload: '3', text: 'Nested Item 4.3' }\n" + " ] },\n" + - " { payload: '4', text: 'Nested Item 10' }\n" + + " { payload: '4', text: 'Nested Item 5' }\n" + " ] },\n" + " { payload: '1', text: 'Audio Library'},\n" + " { payload: '2', text: 'Settings'},\n" + - " { payload: '3', text: 'Logout'}\n" + + " { payload: '3', text: 'Logout', disabled: true}\n" + " ];\n\n" + ''; diff --git a/src/index.js b/src/index.js index bd003d0455c9b3..b234cb8892cb27 100644 --- a/src/index.js +++ b/src/index.js @@ -14,8 +14,8 @@ module.exports = { IconButton: require('./js/icon-button'), Input: require('./js/input'), LeftNav: require('./js/left-nav'), - MenuItem: require('./js/menu-item'), - Menu: require('./js/menu'), + Menu: require('./js/menu/menu'), + MenuItem: require('./js/menu/menu-item'), Mixins: { Classable: require('./js/mixins/classable'), ClickAwayable: require('./js/mixins/click-awayable'), diff --git a/src/js/drop-down-icon.jsx b/src/js/drop-down-icon.jsx index d1a4b89f03e091..9185c23187d065 100644 --- a/src/js/drop-down-icon.jsx +++ b/src/js/drop-down-icon.jsx @@ -4,8 +4,7 @@ var ClickAwayable = require('./mixins/click-awayable'); var KeyLine = require('./utils/key-line'); var Paper = require('./paper'); var FontIcon = require('./font-icon'); -var Menu = require('./menu'); -var MenuItem = require('./menu-item'); +var Menu = require('./menu/menu'); var DropDownIcon = React.createClass({ diff --git a/src/js/drop-down-menu.jsx b/src/js/drop-down-menu.jsx index 7113c67750f9e5..af0d5a9f4cd7b4 100644 --- a/src/js/drop-down-menu.jsx +++ b/src/js/drop-down-menu.jsx @@ -4,7 +4,7 @@ var ClickAwayable = require('./mixins/click-awayable'); var DropDownArrow = require('./svg-icons/drop-down-arrow'); var KeyLine = require('./utils/key-line'); var Paper = require('./paper'); -var Menu = require('./menu'); +var Menu = require('./menu/menu'); var DropDownMenu = React.createClass({ diff --git a/src/js/left-nav.jsx b/src/js/left-nav.jsx index 95ad87ddb9ffcf..0b5de6dd0dbfcc 100644 --- a/src/js/left-nav.jsx +++ b/src/js/left-nav.jsx @@ -4,7 +4,7 @@ var React = require('react'), WindowListenable = require('./mixins/window-listenable'), Overlay = require('./overlay'), Paper = require('./paper'), - Menu = require('./menu'); + Menu = require('./menu/menu'); var LeftNav = React.createClass({ @@ -82,10 +82,10 @@ var LeftNav = React.createClass({ }, _onMenuItemClick: function(e, key, payload) { - if (!this.props.docked) this.close(); if (this.props.onChange && this.props.selectedIndex !== key) { this.props.onChange(e, key, payload); } + if (!this.props.docked) this.close(); }, _onOverlayTouchTap: function() { diff --git a/src/js/menu/link-menu-item.jsx b/src/js/menu/link-menu-item.jsx new file mode 100644 index 00000000000000..d8f6fa590c2f4c --- /dev/null +++ b/src/js/menu/link-menu-item.jsx @@ -0,0 +1,41 @@ +var React = require('react'); +var Classable = require('../mixins/classable'); + +var LinkMenuItem = React.createClass({ + + mixins: [Classable], + + propTypes: { + index: React.PropTypes.number.isRequired, + payload: React.PropTypes.string.isRequired, + text: React.PropTypes.string.isRequired, + target: React.PropTypes.string, + disabled: React.PropTypes.bool + }, + + getDefaultProps: function() { + return { + disabled: false + }; + }, + + render: function() { + var classes = this.getClasses('mui-menu-item', { + 'mui-is-disabled': this.props.disabled + }); + var onClickHandler = (this.props.disabled) ? this._stopLink : undefined; + // Prevent context menu 'Open In New Tab/Window' + var linkAttribute = (this.props.disabled) ? 'data-href' : 'href'; + var link = {linkAttribute: this.props.payload}; + + return ( + {this.props.text} + ); + }, + + _stopLink: function(event) { + event.preventDefault(); + } +}); + +module.exports = LinkMenuItem; \ No newline at end of file diff --git a/src/js/menu-item.jsx b/src/js/menu/menu-item.jsx similarity index 78% rename from src/js/menu-item.jsx rename to src/js/menu/menu-item.jsx index 3f7198fa042d48..804b6c5f320e3f 100644 --- a/src/js/menu-item.jsx +++ b/src/js/menu/menu-item.jsx @@ -1,7 +1,7 @@ var React = require('react'); -var Classable = require('./mixins/classable'); -var FontIcon = require('./font-icon'); -var Toggle = require('./toggle'); +var Classable = require('../mixins/classable'); +var FontIcon = require('../font-icon'); +var Toggle = require('../toggle'); var Types = { LINK: 'LINK', @@ -21,25 +21,28 @@ var MenuItem = React.createClass({ number: React.PropTypes.string, data: React.PropTypes.string, toggle: React.PropTypes.bool, + disabled: React.PropTypes.bool, onTouchTap: React.PropTypes.func, onClick: React.PropTypes.func, onToggle: React.PropTypes.func, selected: React.PropTypes.bool }, - + statics: { Types: Types }, getDefaultProps: function() { return { - toggle: false + toggle: false, + disabled: false }; }, render: function() { var classes = this.getClasses('mui-menu-item', { - 'mui-is-selected': this.props.selected + 'mui-is-selected': this.props.selected, + 'mui-is-disabled': this.props.disabled }); var icon; var data; @@ -86,15 +89,15 @@ var MenuItem = React.createClass({ }, _handleTouchTap: function(e) { - if (this.props.onTouchTap) this.props.onTouchTap(e, this.props.index); + if (!this.props.disabled && this.props.onTouchTap) this.props.onTouchTap(e, this.props.index); }, _handleOnClick: function(e) { - if (this.props.onClick) this.props.onClick(e, this.props.index); + if (!this.props.disabled && this.props.onClick) this.props.onClick(e, this.props.index); }, _handleToggle: function(e, toggled) { - if (this.props.onToggle) this.props.onToggle(e, this.props.index, toggled); + if (!this.props.disabled && this.props.onToggle) this.props.onToggle(e, this.props.index, toggled); } }); diff --git a/src/js/menu.jsx b/src/js/menu/menu.jsx similarity index 82% rename from src/js/menu.jsx rename to src/js/menu/menu.jsx index 521846b2119997..9cfc5b9d9cfdb1 100644 --- a/src/js/menu.jsx +++ b/src/js/menu/menu.jsx @@ -1,15 +1,17 @@ var React = require('react'); -var CssEvent = require('./utils/css-event'); -var Dom = require('./utils/dom'); -var KeyLine = require('./utils/key-line'); -var Classable = require('./mixins/classable'); -var ClickAwayable = require('./mixins/click-awayable'); -var Paper = require('./paper'); +var CssEvent = require('../utils/css-event'); +var Dom = require('../utils/dom'); +var KeyLine = require('../utils/key-line'); +var Classable = require('../mixins/classable'); +var ClickAwayable = require('../mixins/click-awayable'); +var Paper = require('../paper'); var MenuItem = require('./menu-item'); +var LinkMenuItem = require('./link-menu-item'); +var SubheaderMenuItem = require('./subheader-menu-item'); /*********************** - * Nested Menu Component - ***********************/ +* Nested Menu Component +***********************/ var NestedMenuItem = React.createClass({ mixins: [Classable, ClickAwayable], @@ -19,9 +21,16 @@ var NestedMenuItem = React.createClass({ text: React.PropTypes.string, menuItems: React.PropTypes.array.isRequired, zDepth: React.PropTypes.number, + disabled: React.PropTypes.bool, onItemClick: React.PropTypes.func, onItemTap: React.PropTypes.func }, + + getDefaultProps: function() { + return { + disabled: false + }; + }, getInitialState: function() { return { open: false } @@ -41,12 +50,13 @@ var NestedMenuItem = React.createClass({ render: function() { var classes = this.getClasses('mui-nested-menu-item', { - 'mui-open': this.state.open + 'mui-open': this.state.open, + 'mui-is-disabled': this.props.disabled }); return (
- + {this.props.text} {menuItem.text} + ); - break; + break; case MenuItem.Types.SUBHEADER: itemComponent = ( -
{menuItem.text}
+ ); break; @@ -190,6 +212,7 @@ var Menu = React.createClass({ key={i} index={i} text={menuItem.text} + disabled={isDisabled} menuItems={menuItem.items} zDepth={this.props.zDepth} onItemClick={this._onNestedItemClick} @@ -210,6 +233,7 @@ var Menu = React.createClass({ attribute={menuItem.attribute} number={menuItem.number} toggle={menuItem.toggle} + disabled={isDisabled} onClick={this._onItemClick} onTouchTap={this._onItemTap}> {menuItem.text} diff --git a/src/js/menu/subheader-menu-item.jsx b/src/js/menu/subheader-menu-item.jsx new file mode 100644 index 00000000000000..12942afea68972 --- /dev/null +++ b/src/js/menu/subheader-menu-item.jsx @@ -0,0 +1,18 @@ +var React = require('react'); + +var SubheaderMenuItem = React.createClass({ + + propTypes: { + index: React.PropTypes.number.isRequired, + text: React.PropTypes.string.isRequired + }, + + render: function() { + return ( +
{this.props.text}
+ ); + } + +}); + +module.exports = SubheaderMenuItem; \ No newline at end of file diff --git a/src/js/slider.jsx b/src/js/slider.jsx index 6e0cfbb25be212..6ec1a2448aa25e 100644 --- a/src/js/slider.jsx +++ b/src/js/slider.jsx @@ -1,4 +1,3 @@ - var React = require('react'), Paper = require('./paper'), Classable = require('./mixins/classable'), diff --git a/src/less/components/menu-item.less b/src/less/components/menu-item.less index 96ae63829b3149..9d7900a02c1d24 100644 --- a/src/less/components/menu-item.less +++ b/src/less/components/menu-item.less @@ -9,7 +9,9 @@ background-color: fade(@menu-item-hover-color, 0%); &:hover { - background-color: @menu-item-hover-color; + &:not(.mui-is-disabled) { + background-color: @menu-item-hover-color; + } } .mui-menu-item-number { @@ -58,5 +60,10 @@ &.mui-is-selected { color: @menu-item-selected-text-color; } + + &.mui-is-disabled { + color: @disabled-color !important; + cursor: default; + } } \ No newline at end of file diff --git a/src/less/components/menu.less b/src/less/components/menu.less index 29bb3f27279cb6..a93b5041f209a3 100644 --- a/src/less/components/menu.less +++ b/src/less/components/menu.less @@ -35,6 +35,11 @@ .mui-nested-menu-item { position: relative; + + &.mui-is-disabled { + color: @disabled-color; + cursor: default; + } &.mui-open { & > .mui-menu { diff --git a/src/less/resets/normalize.css b/src/less/resets/normalize.css index 81c6f31ea4b8d3..a40f7ed1c84ea9 100644 --- a/src/less/resets/normalize.css +++ b/src/less/resets/normalize.css @@ -297,11 +297,14 @@ input[type="submit"] { /** * Re-set default cursor for disabled elements. + * + * Input types do not display default cursor if element contains styling + * that overrides cursor. */ button[disabled], html input[disabled] { - cursor: default; + cursor: default !important; } /**