@@ -34,8 +34,9 @@ function _inherits(subClass, superClass) { if (typeof superClass !== "function"
3434var MOUSE_ENTER_DELAY = 500 ,
3535 MOUSE_LEAVE_DELAY = 100 ,
3636 ALIGNER = _Aligner . Aligner ,
37- HINTS = function HINTS ( level ) {
38- return ! level ? [ 'ss' , 'se' , 'sm' , 'ns' , 'ne' , 'nm' ] : // zero depth
37+ HINTS = function HINTS ( depth ) {
38+ // default hints. Could be overridden via props
39+ return ! depth ? [ 'ss' , 'se' , 'sm' , 'ns' , 'ne' , 'nm' ] : // zero depth (first menu popup)
3940 [ 'es' , 'em' , 'ee' , 'ws' , 'wm' , 'we' ] ; // all the others
4041} ;
4142
@@ -53,9 +54,7 @@ var DropdownMenu = exports.DropdownMenu = function (_Component) {
5354 _this . onClose = _this . onClose . bind ( _this ) ;
5455 _this . setMenuVisibility = _this . setMenuVisibility . bind ( _this ) ;
5556 _this . hideMenu = _this . hideMenu . bind ( _this ) ;
56- _this . hideMenuDeferred = function ( ) {
57- _lodash2 . default . defer ( this . hideMenu ) ;
58- } ;
57+
5958 _this . state = {
6059 isOpen : false
6160 } ;
@@ -70,31 +69,48 @@ var DropdownMenu = exports.DropdownMenu = function (_Component) {
7069 } , {
7170 key : 'onClose' ,
7271 value : function onClose ( ) {
73- this . hideMenuDeferred ( ) ;
72+ this . hideMenu ( ) ;
7473 this . props . onClose ( ) ;
7574 }
7675 } , {
7776 key : 'hideMenu' ,
7877 value : function hideMenu ( ) {
79- this . setMenuVisibility ( false ) ;
78+ var self = this ;
79+
80+ _lodash2 . default . defer ( function ( ) {
81+ // we're deferring the hiding of the menu, so on close it doesn't go through the open->close->open transition
82+ self . setMenuVisibility ( false ) ;
83+ } ) ;
8084 }
8185 } , {
8286 key : 'setMenuVisibility' ,
83- value : function setMenuVisibility ( menuVisible ) {
87+ value : function setMenuVisibility ( visible ) {
8488 this . setState ( {
85- isOpen : menuVisible
89+ isOpen : visible
8690 } ) ;
8791 }
92+ } , {
93+ key : 'tryOpenMenu' ,
94+ value : function tryOpenMenu ( ) {
95+ if ( ! this . state . isOpen ) {
96+ // open only if currently closed
97+ this . setMenuVisibility ( true ) ;
98+ }
99+ // else do nothing. If the menu is already open, it will close we'were clicking away from it.
100+ }
101+
102+ //<editor-fold desc="Button handlers">
103+
88104 } , {
89105 key : 'onButtonClick' ,
90106 value : function onButtonClick ( ) {
91- _lodash2 . default . defer ( this . setMenuVisibility , ! this . state . isOpen ) ;
107+ this . tryOpenMenu ( ) ;
92108 }
93109 } , {
94110 key : 'onButtonMouseEnter' ,
95111 value : function onButtonMouseEnter ( ) {
96112 if ( this . props . openOnMouseOver ) {
97- this . setMenuVisibility ( true ) ;
113+ this . tryOpenMenu ( ) ;
98114 }
99115 }
100116 } , {
@@ -103,20 +119,44 @@ var DropdownMenu = exports.DropdownMenu = function (_Component) {
103119 e . preventDefault ( ) ;
104120 e . stopPropagation ( ) ;
105121 }
122+ //</editor-fold>
123+
124+ //<editor-fold desc="Rendering">
125+
126+ } , {
127+ key : 'renderButton' ,
128+ value : function renderButton ( ) {
129+ // render a child passed from the outside, or a default button
130+ var children = this . props . children || _react2 . default . createElement (
131+ 'button' ,
132+ { ref : 'button' , className : 'menu-button' } ,
133+ this . props . buttonText
134+ ) ,
135+ self = this ;
136+
137+ return _react2 . default . Children . map ( children , function ( child ) {
138+ return _react2 . default . cloneElement ( child , {
139+ ref : 'button' ,
140+ onClick : self . onButtonClick ,
141+ onContextMenu : self . onButtonContextMenu ,
142+ onMouseEnter : self . onButtonMouseEnter
143+ } ) ;
144+ } . bind ( this ) ) ;
145+ }
106146 } , {
107147 key : 'render' ,
108148 value : function render ( ) {
109149 var menu = this . state . isOpen ? _react2 . default . createElement ( _Menu . Menu , {
110- onClick : this . onMenuClick ,
111- onMouseEnter : this . onMenuMouseEnter ,
112- onMouseLeave : this . onMenuMouseLeave ,
113150 onOpen : this . onOpen ,
114151 onClose : this . onClose ,
152+ onItemMouseEnter : this . props . onItemMouseEnter ,
153+ onItemMouseLeave : this . props . onItemMouseLeave ,
154+ onItemClick : this . props . onItemClick ,
115155 aligner : this . props . aligner ,
116156 alignTo : this . buttonElement ,
117157 hints : this . props . hints ,
118158 items : this . props . items ,
119- autoCloseInstances : this . props . autoCloseInstances ,
159+ autoCloseOtherMenuInstances : this . props . autoCloseOtherMenuInstances ,
120160 renderers : this . props . renderers ,
121161 mouseEnterDelay : this . props . mouseEnterDelay ,
122162 mouseLeaveDelay : this . props . mouseLeaveDelay
@@ -129,25 +169,8 @@ var DropdownMenu = exports.DropdownMenu = function (_Component) {
129169 menu
130170 ) ;
131171 }
132- } , {
133- key : 'renderButton' ,
134- value : function renderButton ( ) {
135- var children = this . props . children || _react2 . default . createElement (
136- 'button' ,
137- { ref : 'button' , className : 'menu-button' } ,
138- this . props . buttonText
139- ) ,
140- self = this ;
172+ //</editor-fold>
141173
142- return _react2 . default . Children . map ( children , function ( child ) {
143- return _react2 . default . cloneElement ( child , {
144- ref : 'button' ,
145- onClick : self . onButtonClick ,
146- onContextMenu : self . onButtonContextMenu ,
147- onMouseEnter : self . onButtonMouseEnter
148- } ) ;
149- } . bind ( this ) ) ;
150- }
151174 } , {
152175 key : 'componentDidMount' ,
153176 value : function componentDidMount ( ) {
@@ -159,25 +182,31 @@ var DropdownMenu = exports.DropdownMenu = function (_Component) {
159182} ( _react . Component ) ;
160183
161184DropdownMenu . propTypes = {
162- buttonText : _react2 . default . PropTypes . string ,
163- items : _react2 . default . PropTypes . array . isRequired ,
164- openOnMouseOver : _react2 . default . PropTypes . bool . isRequired ,
165- autoCloseInstances : _react2 . default . PropTypes . bool . isRequired ,
185+ buttonText : _react2 . default . PropTypes . string , // the text of the default button
186+ openOnMouseOver : _react2 . default . PropTypes . bool . isRequired , // should menu be opened on mouse over (Mac menu is opened on first click)
187+ items : _react2 . default . PropTypes . array . isRequired , // menu items (data)
188+ autoCloseOtherMenuInstances : _react2 . default . PropTypes . bool . isRequired ,
166189 mouseEnterDelay : _react2 . default . PropTypes . number ,
167190 mouseLeaveDelay : _react2 . default . PropTypes . number ,
168191 hints : _react2 . default . PropTypes . func . isRequired ,
169- onOpen : _react2 . default . PropTypes . func ,
170- onClose : _react2 . default . PropTypes . func
192+ onOpen : _react2 . default . PropTypes . func , // custom open handler
193+ onClose : _react2 . default . PropTypes . func , // custom close handler
194+ onItemMouseEnter : _react2 . default . PropTypes . func , // custom item mouse enter handler
195+ onItemMouseLeave : _react2 . default . PropTypes . func , // custom item mouse leave handler
196+ onItemClick : _react2 . default . PropTypes . func // custom item click handler
171197} ;
172198DropdownMenu . defaultProps = {
173199 buttonText : '- Menu -' ,
200+ openOnMouseOver : false ,
174201 items : [ ] ,
175202 aligner : new ALIGNER ( ) ,
176- autoCloseInstances : true ,
177- openOnMouseOver : false ,
203+ autoCloseOtherMenuInstances : true ,
178204 mouseEnterDelay : MOUSE_ENTER_DELAY ,
179205 mouseLeaveDelay : MOUSE_LEAVE_DELAY ,
180206 hints : HINTS ,
181207 onOpen : function onOpen ( ) { } ,
182- onClose : function onClose ( ) { }
208+ onClose : function onClose ( ) { } ,
209+ onItemMouseEnter : function onItemMouseEnter ( ) { } ,
210+ onItemMouseLeave : function onItemMouseLeave ( ) { } ,
211+ onItemClick : function onItemClick ( ) { }
183212} ;
0 commit comments