import React from 'react';
import ReactDOM from 'react-dom';
import PureRenderMixin from 'react-addons-pure-render-mixin';
import ColorManipulator from 'material-ui/lib/utils/color-manipulator';
import StylePropable from 'material-ui/lib/mixins/style-propable';
import Colors from 'material-ui/lib/styles/colors';
import Transitions from 'material-ui/lib/styles/transitions';
import Typography from 'material-ui/lib/styles/typography';
import EnhancedButton from 'material-ui/lib/enhanced-button';
import IconButton from 'material-ui/lib/icon-button';
import OpenIcon from 'material-ui/lib/svg-icons/navigation/arrow-drop-up';
import CloseIcon from 'material-ui/lib/svg-icons/navigation/arrow-drop-down';
import NestedList from 'material-ui/lib/lists/nested-list';
import getMuiTheme from 'material-ui/lib/styles/getMuiTheme';
const Item = React.createClass({
propTypes: {
/**
* Generate a nested list indicator icon when
* nested list items are detected. Set to false
* if you do not want an indicator auto-generated.
* Note that an indicator will not be created if a
* rightIcon/Button has been specified.
*/
autoGenerateNestedIndicator: React.PropTypes.bool,
/**
* Children passed into the ListItem.
*/
children: React.PropTypes.node,
/**
* Does not allow the element to be focused by the keyboard.
*/
disableKeyboardFocus: React.PropTypes.bool,
/**
* If true, the list-item will not be clickable
* and will not display hover affects.
* This is automatically disabled if leftCheckbox
* or rightToggle is set.
*/
disabled: React.PropTypes.bool,
/**
* Controls whether or not the child ListItems are initially displayed.
*/
initiallyOpen: React.PropTypes.bool,
/**
* Style prop for the innder div element.
*/
innerDivStyle: React.PropTypes.object,
/**
* If true, the children will be indented by 72px.
* Only needed if there is no left avatar or left icon.
*/
insetChildren: React.PropTypes.bool,
/**
* This is the Avatar element to be displayed on the left side.
*/
leftAvatar: React.PropTypes.element,
/**
* This is the Checkbox element to be displayed on the left side.
*/
leftCheckbox: React.PropTypes.element,
/**
* This is the SvgIcon or FontIcon to be displayed on the left side.
*/
leftIcon: React.PropTypes.element,
/**
* An array of ListItems to nest underneath the current ListItem.
*/
nestedItems: React.PropTypes.arrayOf(React.PropTypes.element),
/**
* Controls how deep a ListItem appears.
* This property is automatically managed so modify at your own risk.
*/
nestedLevel: React.PropTypes.number,
/**
* Override the inline-styles of the nestedItems NestedList.
*/
nestedListStyle: React.PropTypes.object,
/**
* Called when the ListItem has keyboard focus.
*/
onKeyboardFocus: React.PropTypes.func,
/**
* Called when the mouse is over the ListItem.
*/
onMouseEnter: React.PropTypes.func,
/**
* Called when the mouse is no longer over the ListItem.
*/
onMouseLeave: React.PropTypes.func,
/**
* Called when the ListItem toggles its nested ListItems.
*/
onNestedListToggle: React.PropTypes.func,
/**
* Called when touches start.
*/
onTouchStart: React.PropTypes.func,
/**
* Called when a touch tap event occures on the component.
*/
onTouchTap: React.PropTypes.func,
/**
* This is the block element that contains the primary text.
* If a string is passed in, a div tag will be rendered.
*/
primaryText: React.PropTypes.node,
/**
* If provided, tapping on the primary text
* of the item toggles the nested list.
*/
primaryTogglesNestedList: React.PropTypes.bool,
/**
* This is the avatar element to be displayed on the right side.
*/
rightAvatar: React.PropTypes.element,
/**
* This is the SvgIcon or FontIcon to be displayed on the right side.
*/
rightIcon: React.PropTypes.element,
/**
* This is the IconButton to be displayed on the right side.
* Hovering over this button will remove the ListItem hover.
* Also, clicking on this button will not trigger a
* ListItem ripple. The event will be stopped and prevented
* from bubbling up to cause a ListItem click.
*/
rightIconButton: React.PropTypes.element,
/**
* This is the Toggle element to display on the right side.
*/
rightToggle: React.PropTypes.element,
/**
* This is the block element that contains the secondary text.
* If a string is passed in, a div tag will be rendered.
*/
secondaryText: React.PropTypes.node,
/**
* Can be 1 or 2. This is the number of secondary
* text lines before ellipsis will show.
*/
secondaryTextLines: React.PropTypes.oneOf([1, 2]),
/**
* Override the inline-styles of the root element.
*/
style: React.PropTypes.object,
},
contextTypes: {
muiTheme: React.PropTypes.object,
},
//for passing default theme context to children
childContextTypes: {
muiTheme: React.PropTypes.object,
},
mixins: [
PureRenderMixin,
StylePropable,
],
getDefaultProps() {
return {
autoGenerateNestedIndicator: true,
disableKeyboardFocus: false,
disabled: false,
initiallyOpen: false,
insetChildren: false,
nestedItems: [],
nestedLevel: 0,
onKeyboardFocus: () => {},
onMouseEnter: () => {},
onMouseLeave: () => {},
onNestedListToggle: () => {},
onTouchStart: () => {},
primaryTogglesNestedList: false,
secondaryTextLines: 1,
};
},
getInitialState() {
return {
hovered: false,
isKeyboardFocused: false,
open: this.props.initiallyOpen,
rightIconButtonHovered: false,
rightIconButtonKeyboardFocused: false,
touch: false,
muiTheme: this.context.muiTheme || getMuiTheme(),
};
},
getChildContext() {
return {
muiTheme: this.state.muiTheme,
};
},
//to update theme inside state whenever a new theme is passed down
//from the parent / owner using context
componentWillReceiveProps(nextProps, nextContext) {
let newMuiTheme = nextContext.muiTheme ? nextContext.muiTheme : this.state.muiTheme;
this.setState({muiTheme: newMuiTheme});
},
applyFocusState(focusState) {
const button = this.refs.enhancedButton;
const buttonEl = ReactDOM.findDOMNode(button);
if (button) {
switch (focusState) {
case 'none':
buttonEl.blur();
break;
case 'focused':
buttonEl.focus();
break;
case 'keyboard-focused':
button.setKeyboardFocus();
buttonEl.focus();
break;
}
}
},
_createDisabledElement(styles, contentChildren, additionalProps) {
const {
innerDivStyle,
style,
} = this.props;
const mergedDivStyles = this.mergeStyles(
styles.root,
styles.innerDiv,
innerDivStyle,
style
);
return (