UNPKG

d2-ui

Version:
338 lines (295 loc) 9.25 kB
import React from 'react'; import StylePropable from './mixins/style-propable'; import Typography from './styles/typography'; import IconButton from './icon-button'; import NavigationMenu from './svg-icons/navigation/menu'; import getMuiTheme from './styles/getMuiTheme'; import Paper from './paper'; import PropTypes from './utils/prop-types'; import warning from 'warning'; const AppBar = React.createClass({ propTypes: { /** * Can be used to render a tab inside an app bar for instance. */ children: React.PropTypes.node, /** * Applied to the app bar's root element. */ className: React.PropTypes.string, /** * The classname of the icon on the left of the app bar. * If you are using a stylesheet for your icons, enter the class name for the icon to be used here. */ iconClassNameLeft: React.PropTypes.string, /** * Similiar to the iconClassNameLeft prop except that * it applies to the icon displayed on the right of the app bar. */ iconClassNameRight: React.PropTypes.string, /** * The custom element to be displayed on the left side of the * app bar such as an SvgIcon. */ iconElementLeft: React.PropTypes.element, /** * Similiar to the iconElementLeft prop except that this element is displayed on the right of the app bar. */ iconElementRight: React.PropTypes.element, /** * Override the inline-styles of the element displayed on the right side of the app bar. */ iconStyleRight: React.PropTypes.object, /** * Callback function for when the left icon is selected via a touch tap. */ onLeftIconButtonTouchTap: React.PropTypes.func, /** * Callback function for when the right icon is selected via a touch tap. */ onRightIconButtonTouchTap: React.PropTypes.func, /** * Callback function for when the title text is selected via a touch tap. */ onTitleTouchTap: React.PropTypes.func, /** * Determines whether or not to display the Menu icon next to the title. * Setting this prop to false will hide the icon. */ showMenuIconButton: React.PropTypes.bool, /** * Override the inline-styles of the root element. */ style: React.PropTypes.object, /** * The title to display on the app bar. */ title: React.PropTypes.node, /** * Override the inline-styles of the app bar's title element. */ titleStyle: React.PropTypes.object, /** * The zDepth of the component. * The shadow of the app bar is also dependent on this property. */ zDepth: PropTypes.zDepth, }, contextTypes: { muiTheme: React.PropTypes.object, }, //for passing default theme context to children childContextTypes: { muiTheme: React.PropTypes.object, }, mixins: [StylePropable], getDefaultProps() { return { showMenuIconButton: true, title: '', zDepth: 1, }; }, getInitialState() { return { muiTheme: this.context.muiTheme || getMuiTheme(), }; }, getChildContext() { return { muiTheme: this.state.muiTheme, }; }, componentDidMount() { warning(!this.props.iconElementLeft || !this.props.iconClassNameLeft, `Properties iconElementLeft and iconClassNameLeft cannot be simultaneously defined. Please use one or the other.`); warning(!this.props.iconElementRight || !this.props.iconClassNameRight, `Properties iconElementRight and iconClassNameRight cannot be simultaneously defined. Please use one or the other.`); }, //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}); }, getStyles() { const muiTheme = this.state.muiTheme; const rawTheme = muiTheme.rawTheme; let themeVariables = muiTheme.appBar; let iconButtonSize = muiTheme.button.iconButtonSize; let flatButtonSize = 36; let styles = { root: { position: 'relative', zIndex: muiTheme.zIndex.appBar, width: '100%', display: 'flex', minHeight: themeVariables.height, backgroundColor: themeVariables.color, paddingLeft: rawTheme.spacing.desktopGutter, paddingRight: rawTheme.spacing.desktopGutter, }, title: { whiteSpace: 'nowrap', overflow: 'hidden', textOverflow: 'ellipsis', margin: 0, paddingTop: 0, letterSpacing: 0, fontSize: 24, fontWeight: Typography.fontWeightNormal, color: themeVariables.textColor, lineHeight: themeVariables.height + 'px', }, mainElement: { boxFlex: 1, flex: '1', }, iconButton: { style: { marginTop: (themeVariables.height - iconButtonSize) / 2, marginRight: 8, marginLeft: -16, }, iconStyle: { fill: themeVariables.textColor, color: themeVariables.textColor, }, }, flatButton: { color: themeVariables.textColor, marginTop: (iconButtonSize - flatButtonSize) / 2 + 2, }, }; return styles; }, _onLeftIconButtonTouchTap(event) { if (this.props.onLeftIconButtonTouchTap) { this.props.onLeftIconButtonTouchTap(event); } }, _onRightIconButtonTouchTap(event) { if (this.props.onRightIconButtonTouchTap) { this.props.onRightIconButtonTouchTap(event); } }, _onTitleTouchTap(event) { if (this.props.onTitleTouchTap) { this.props.onTitleTouchTap(event); } }, render() { let { title, titleStyle, iconStyleRight, showMenuIconButton, iconElementLeft, iconElementRight, iconClassNameLeft, iconClassNameRight, className, style, zDepth, children, ...other, } = this.props; let menuElementLeft; let menuElementRight; let styles = this.getStyles(); let iconRightStyle = this.mergeStyles(styles.iconButton.style, { marginRight: -16, marginLeft: 'auto', }, iconStyleRight); let titleElement; if (title) { // If the title is a string, wrap in an h1 tag. // If not, just use it as a node. titleElement = typeof title === 'string' || title instanceof String ? <h1 onTouchTap={this._onTitleTouchTap} style={this.prepareStyles(styles.title, styles.mainElement, titleStyle)} > {title} </h1> : <div onTouchTap={this._onTitleTouchTap} style={this.prepareStyles(styles.title, styles.mainElement, titleStyle)} > {title} </div>; } if (showMenuIconButton) { if (iconElementLeft) { switch (iconElementLeft.type.displayName) { case 'IconButton': iconElementLeft = React.cloneElement(iconElementLeft, { iconStyle: this.mergeStyles(styles.iconButton.iconStyle, iconElementLeft.props.iconStyle), }); break; } menuElementLeft = ( <div style={this.prepareStyles(styles.iconButton.style)}> {iconElementLeft} </div> ); } else { let child = iconClassNameLeft ? '' : <NavigationMenu style={this.mergeStyles(styles.iconButton.iconStyle)}/>; menuElementLeft = ( <IconButton style={this.mergeStyles(styles.iconButton.style)} iconStyle={this.mergeStyles(styles.iconButton.iconStyle)} iconClassName={iconClassNameLeft} onTouchTap={this._onLeftIconButtonTouchTap} > {child} </IconButton> ); } } if (iconElementRight) { switch (iconElementRight.type.displayName) { case 'IconMenu': case 'IconButton': iconElementRight = React.cloneElement(iconElementRight, { iconStyle: this.mergeStyles(styles.iconButton.iconStyle, iconElementRight.props.iconStyle), }); break; case 'FlatButton': iconElementRight = React.cloneElement(iconElementRight, { style: this.mergeStyles(styles.flatButton, iconElementRight.props.style), }); break; } menuElementRight = ( <div style={this.prepareStyles(iconRightStyle)}> {iconElementRight} </div> ); } else if (iconClassNameRight) { menuElementRight = ( <IconButton style={iconRightStyle} iconStyle={this.mergeStyles(styles.iconButton.iconStyle)} iconClassName={iconClassNameRight} onTouchTap={this._onRightIconButtonTouchTap} /> ); } return ( <Paper {...other} rounded={false} className={className} style={this.mergeStyles(styles.root, style)} zDepth={zDepth} > {menuElementLeft} {titleElement} {menuElementRight} {children} </Paper> ); }, }); export default AppBar;