Skip to content

Commit

Permalink
Merge pull request #1281 from hai-cea/icon-menu-perf
Browse files Browse the repository at this point in the history
[Menus] Performance enhancements and added animated prop.
  • Loading branch information
Hai Nguyen committed Jul 29, 2015
2 parents 102c171 + f839583 commit 3829890
Show file tree
Hide file tree
Showing 3 changed files with 148 additions and 127 deletions.
192 changes: 99 additions & 93 deletions docs/src/app/components/pages/components/menus.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -57,6 +57,13 @@ class MenusPage extends React.Component {
{
name: 'Menu Props',
infoArray: [
{
name: 'animated',
type: 'bool',
header: 'default: false',
desc: 'If true, the menu will apply transitions when added it gets added to the DOM. In order for transitions ' +
'to work, wrap the menu inside a ReactTransitionGroup.'
},
{
name: 'autoWidth',
type: 'bool',
Expand Down Expand Up @@ -229,110 +236,109 @@ class MenusPage extends React.Component {
desc={desc}
componentInfo={componentInfo}>

<ReactTransitionGroup>
<Menu style={styles.menu}>
<MenuItem primaryText="Maps" />
<MenuItem primaryText="Books" />
<MenuItem primaryText="Flights" />
<MenuItem primaryText="Apps" />
</Menu>
<Menu style={styles.menu}>
<MenuItem primaryText="Maps" />
<MenuItem primaryText="Books" />
<MenuItem primaryText="Flights" />
<MenuItem primaryText="Apps" />
</Menu>

<Menu style={styles.menu}>
<MenuItem primaryText="Refresh" />
<MenuItem primaryText="Help &amp; feedback" />
<MenuItem primaryText="Settings" />
<MenuItem primaryText="Sign out" />
</Menu>

<Menu style={styles.menu}>
<MenuItem primaryText="Refresh" />
<MenuItem primaryText="Help &amp; feedback" />
<MenuItem primaryText="Settings" />
<MenuItem primaryText="Sign out" />
</Menu>
<Menu style={styles.menu} desktop={true}>
<MenuItem primaryText="Back" />
<MenuItem primaryText="Forward" disabled={true} />
<MenuDivider />
<MenuItem primaryText="Recently closed" disabled={true} />
<MenuItem primaryText="Google" disabled={true} />
<MenuItem primaryText="YouTube" />
</Menu>

<Menu style={styles.menu} desktop={true}>
<MenuItem primaryText="Back" />
<MenuItem primaryText="Forward" disabled={true} />
<MenuDivider />
<MenuItem primaryText="Recently closed" disabled={true} />
<MenuItem primaryText="Google" disabled={true} />
<MenuItem primaryText="YouTube" />
</Menu>
<Menu style={styles.menu}>
<MenuItem primaryText="Preview" leftIcon={<RemoveRedEye />} />
<MenuItem primaryText="Share" leftIcon={<PersonAdd />} />
<MenuItem primaryText="Get links" leftIcon={<ContentLink />} />
<MenuDivider />
<MenuItem primaryText="Make a copy" leftIcon={<ContentCopy />} />
<MenuItem primaryText="Download" leftIcon={<Download />} />
<MenuDivider />
<MenuItem primaryText="Remove" leftIcon={<Delete />} />
</Menu>

<Menu style={styles.menu}>
<MenuItem primaryText="Preview" leftIcon={<RemoveRedEye />} />
<MenuItem primaryText="Share" leftIcon={<PersonAdd />} />
<MenuItem primaryText="Get links" leftIcon={<ContentLink />} />
<MenuDivider />
<MenuItem primaryText="Make a copy" leftIcon={<ContentCopy />} />
<MenuItem primaryText="Download" leftIcon={<Download />} />
<MenuDivider />
<MenuItem primaryText="Remove" leftIcon={<Delete />} />
</Menu>
<Menu style={styles.menu} desktop={true}>
<MenuItem primaryText="Undo" />
<MenuItem primaryText="Redo" disabled={true} />
<MenuDivider />
<MenuItem primaryText="Cut" disabled={true} />
<MenuItem primaryText="Copy" disabled={true} />
<MenuItem primaryText="Paste" />
</Menu>

<Menu style={styles.menu} desktop={true}>
<MenuItem primaryText="Undo" />
<MenuItem primaryText="Redo" disabled={true} />
<MenuDivider />
<MenuItem primaryText="Cut" disabled={true} />
<MenuItem primaryText="Copy" disabled={true} />
<MenuItem primaryText="Paste" />
</Menu>
<Menu style={styles.menu} desktop={true}>
<MenuItem primaryText="Untitled" />
<MenuItem primaryText="Using the z-axis to Solve Design Challenges" />
<MenuItem primaryText="An Extensive History of Dimensionality" />
</Menu>

<Menu style={styles.menu} desktop={true}>
<MenuItem primaryText="Untitled" />
<MenuItem primaryText="Using the z-axis to Solve Design Challenges" />
<MenuItem primaryText="An Extensive History of Dimensionality" />
</Menu>
<Menu style={styles.menu} desktop={true}>
<MenuItem primaryText="Untitled" />
<MenuItem primaryText="Using the z-axis to Solve Design Challenges" />
<MenuItem primaryText="An Extensive History of Dimensionality: the Abridged Edition" />
</Menu>

<Menu style={styles.menu} desktop={true}>
<MenuItem primaryText="Untitled" />
<MenuItem primaryText="Using the z-axis to Solve Design Challenges" />
<MenuItem primaryText="An Extensive History of Dimensionality: the Abridged Edition" />
</Menu>
<Menu style={styles.menu} desktop={true} width={320}>
<MenuItem primaryText="Open" secondaryText="Cmnd + O" />
<MenuItem primaryText="Paste in place" secondaryText="Shift + V" />
<MenuItem primaryText="Research" secondaryText="Opt + Shift + Cmnd + I" />
</Menu>

<Menu style={styles.menu} desktop={true} width={320}>
<MenuItem primaryText="Open" secondaryText="Cmnd + O" />
<MenuItem primaryText="Paste in place" secondaryText="Shift + V" />
<MenuItem primaryText="Research" secondaryText="Opt + Shift + Cmnd + I" />
</Menu>
<Menu style={styles.menu} desktop={true} width={320}>
<MenuItem primaryText="Open" secondaryText="&#8984;O" />
<MenuItem primaryText="Paste in place" secondaryText="&#8679;&#8984;V" />
<MenuItem primaryText="Research" secondaryText="&#8997;&#8679;&#8984;I" />
</Menu>

<Menu style={styles.menu} desktop={true} width={320}>
<MenuItem primaryText="Open" secondaryText="&#8984;O" />
<MenuItem primaryText="Paste in place" secondaryText="&#8679;&#8984;V" />
<MenuItem primaryText="Research" secondaryText="&#8997;&#8679;&#8984;I" />
</Menu>
<Menu style={styles.menu} desktop={true} width={320}>
<MenuItem primaryText="Bold" secondaryText="&#8984;B" />
<MenuItem primaryText="Italic" secondaryText="&#8984;I" />
<MenuItem primaryText="Underline" secondaryText="&#8984;U" />
<MenuItem primaryText="Strikethrough" secondaryText="Alt+Shift+5" />
<MenuItem primaryText="Superscript" secondaryText="&#8984;." />
<MenuItem primaryText="Subscript" secondaryText="&#8984;," />
<MenuDivider />
<MenuItem primaryText="Paragraph styles" rightIcon={<ArrowDropRight />} />
<MenuItem primaryText="Align" rightIcon={<ArrowDropRight />} />
<MenuItem primaryText="Line spacing" rightIcon={<ArrowDropRight />} />
<MenuItem primaryText="Numbered list" rightIcon={<ArrowDropRight />} />
<MenuItem primaryText="List options" rightIcon={<ArrowDropRight />} />
<MenuDivider />
<MenuItem primaryText="Clear formatting" secondaryText="&#8984;/" />
</Menu>

<Menu style={styles.menu} desktop={true} width={320}>
<MenuItem primaryText="Bold" secondaryText="&#8984;B" />
<MenuItem primaryText="Italic" secondaryText="&#8984;I" />
<MenuItem primaryText="Underline" secondaryText="&#8984;U" />
<MenuItem primaryText="Strikethrough" secondaryText="Alt+Shift+5" />
<MenuItem primaryText="Superscript" secondaryText="&#8984;." />
<MenuItem primaryText="Subscript" secondaryText="&#8984;," />
<MenuDivider />
<MenuItem primaryText="Paragraph styles" rightIcon={<ArrowDropRight />} />
<MenuItem primaryText="Align" rightIcon={<ArrowDropRight />} />
<MenuItem primaryText="Line spacing" rightIcon={<ArrowDropRight />} />
<MenuItem primaryText="Numbered list" rightIcon={<ArrowDropRight />} />
<MenuItem primaryText="List options" rightIcon={<ArrowDropRight />} />
<MenuDivider />
<MenuItem primaryText="Clear formatting" secondaryText="&#8984;/" />
</Menu>
<Menu style={styles.menu} desktop={true} width={320}>
<MenuItem primaryText="Single" insetChildren={true} />
<MenuItem primaryText="1.15" insetChildren={true} />
<MenuItem primaryText="Double" insetChildren={true} />
<MenuItem primaryText="Custom: 1.2" checked={true} rightIcon={<ArrowDropRight />} />
<MenuDivider />
<MenuItem primaryText="Add space before paragraph" />
<MenuItem primaryText="Add space after paragraph" />
<MenuDivider />
<MenuItem primaryText="Custom spacing..." />
</Menu>

<Menu style={styles.menu} desktop={true} width={320}>
<MenuItem primaryText="Single" insetChildren={true} />
<MenuItem primaryText="1.15" insetChildren={true} />
<MenuItem primaryText="Double" insetChildren={true} />
<MenuItem primaryText="Custom: 1.2" checked={true} rightIcon={<ArrowDropRight />} />
<MenuDivider />
<MenuItem primaryText="Add space before paragraph" />
<MenuItem primaryText="Add space after paragraph" />
<MenuDivider />
<MenuItem primaryText="Custom spacing..." />
</Menu>
<Menu style={styles.menu} desktop={true}>
<MenuItem primaryText="Show" />
<MenuItem primaryText="Grid lines" checked={true} />
<MenuItem primaryText="Page breaks" insetChildren={true} />
<MenuItem primaryText="Rules" checked={true} />
</Menu>

<Menu style={styles.menu} desktop={true}>
<MenuItem primaryText="Show" />
<MenuItem primaryText="Grid lines" checked={true} />
<MenuItem primaryText="Page breaks" insetChildren={true} />
<MenuItem primaryText="Rules" checked={true} />
</Menu>
</ReactTransitionGroup>
</ComponentDoc>
);

Expand Down
1 change: 1 addition & 0 deletions src/menus/icon-menu.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -111,6 +111,7 @@ let IconMenu = React.createClass({
let menu = open ? (
<Menu
{...other}
animated={true}
initiallyKeyboardFocused={this.state.menuInitiallyKeyboardFocused}
onEscKeyDown={this._handleMenuEscKeyDown}
onItemTouchTap={this._handleItemTouchTap}
Expand Down
82 changes: 48 additions & 34 deletions src/menus/menu.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@ let Menu = React.createClass({
},

propTypes: {
animated: React.PropTypes.bool,
autoWidth: React.PropTypes.bool,
desktop: React.PropTypes.bool,
initiallyKeyboardFocused: React.PropTypes.bool,
Expand All @@ -36,6 +37,7 @@ let Menu = React.createClass({

getDefaultProps() {
return {
animated: false,
autoWidth: true,
maxHeight: null,
onEscKeyDown: () => {},
Expand All @@ -53,24 +55,16 @@ let Menu = React.createClass({
focusIndex: selectedIndex >= 0 ? selectedIndex : 0,
isKeyboardFocused: this.props.initiallyKeyboardFocused,
keyWidth: this.props.desktop ? 64 : 56,
componentEntered: false,
};
},

componentDidAppear() {
this.setState({
componentEntered: true,
});
},

componentDidEnter() {
this.setState({
componentEntered: true,
});
this._animateOpen();
},

componentDidMount() {
if (this.props.autoWidth) this._setWidth();
if (!this.props.animated) this._animateOpen();
this._setScollPosition();
},

Expand Down Expand Up @@ -99,6 +93,7 @@ let Menu = React.createClass({

render() {
let {
animated,
autoWidth,
children,
desktop,
Expand All @@ -116,22 +111,21 @@ let Menu = React.createClass({
...other,
} = this.props;

let componentEntered = this.state.componentEntered;
let openDown = openDirection.split('-')[0] === 'bottom';
let openLeft = openDirection.split('-')[1] === 'left';

let styles = {
root: {
//Nested div bacause the List scales x faster than
//it scales y
transition: Transitions.easeOut('250ms', 'transform'),
transition: animated ? Transitions.easeOut('250ms', 'transform') : null,
position: 'absolute',
zIndex: 10,
top: openDown ? 0 : null,
bottom: !openDown ? 0 : null,
left: !openLeft ? 0 : null,
right: openLeft ? 0 : null,
transform: componentEntered ? 'scaleX(1)' : 'scaleX(0)',
transform: 'scaleX(0)',
transformOrigin: openLeft ? 'right' : 'left',
},

Expand All @@ -143,16 +137,16 @@ let Menu = React.createClass({
width: width,
},

menuItem: {
transition: Transitions.easeOut(null, 'opacity'),
opacity: componentEntered ? 1 : 0,
menuItemContainer: {
transition: animated ? Transitions.easeOut(null, 'opacity') : null,
opacity: 0,
},

paper: {
transition: Transitions.easeOut('500ms', ['transform', 'opacity']),
transform: componentEntered ? 'scaleY(1)' : 'scaleY(0)',
transition: animated ? Transitions.easeOut('500ms', ['transform', 'opacity']) : null,
transform: 'scaleY(0)',
transformOrigin: openDown ? 'top' : 'bottom',
opacity: componentEntered ? 1 : 0,
opacity: 0,
maxHeight: maxHeight,
overflowY: maxHeight ? 'scroll' : null,
},
Expand All @@ -175,29 +169,35 @@ let Menu = React.createClass({

let childIsADivider = child.type.displayName === 'MenuDivider';
let childIsDisabled = child.props.disabled;
let focusIndex = this.state.focusIndex;
let transitionDelay = 0;

//Only cascade the visible menu items
if (componentEntered && (menuItemIndex >= focusIndex - 1) &&
(menuItemIndex <= focusIndex + cascadeChildrenCount - 1)) {
cumulativeDelay = openDown ?
cumulativeDelay + cumulativeDelayIncrement :
cumulativeDelay - cumulativeDelayIncrement;
transitionDelay = cumulativeDelay;
}
let childrenContainerStyles = {};

if (animated) {
let focusIndex = this.state.focusIndex;
let transitionDelay = 0;

//Only cascade the visible menu items
if ((menuItemIndex >= focusIndex - 1) &&
(menuItemIndex <= focusIndex + cascadeChildrenCount - 1)) {
cumulativeDelay = openDown ?
cumulativeDelay + cumulativeDelayIncrement :
cumulativeDelay - cumulativeDelayIncrement;
transitionDelay = cumulativeDelay;
}

let childrenContainerStyles = this.mergeStyles(styles.menuItem, {
transitionDelay: transitionDelay + 'ms',
});
childrenContainerStyles = this.mergeAndPrefix(styles.menuItemContainer, {
transitionDelay: transitionDelay + 'ms',
});
}

let clonedChild = childIsADivider ? child :
childIsDisabled ? React.cloneElement(child, {desktop: desktop}) :
this._cloneMenuItem(child, menuItemIndex, styles);

if (!childIsADivider && !childIsDisabled) menuItemIndex++;

return <div style={childrenContainerStyles}>{clonedChild}</div>;
return animated ? (
<div style={childrenContainerStyles}>{clonedChild}</div>
) : clonedChild;

}.bind(this));

Expand Down Expand Up @@ -226,6 +226,20 @@ let Menu = React.createClass({
});
},

_animateOpen() {
let rootStyle = React.findDOMNode(this).style;
let scrollContainerStyle = React.findDOMNode(this.refs.scrollContainer).style;
let menuContainers = React.findDOMNode(this.refs.list).childNodes;

AutoPrefix.set(rootStyle, 'transform', 'scaleX(1)');
AutoPrefix.set(scrollContainerStyle, 'transform', 'scaleY(1)');
scrollContainerStyle.opacity = 1;

for (let i = 0; i < menuContainers.length; ++i) {
menuContainers[i].style.opacity = 1;
}
},

_cloneMenuItem(child, childIndex, styles) {

let {
Expand Down

0 comments on commit 3829890

Please sign in to comment.