react-menu
Advanced tools
Comparing version 0.0.4 to 0.0.5
@@ -0,1 +1,9 @@ | ||
v0.0.5 - Sat, 29 Nov 2014 18:42:49 GMT | ||
-------------------------------------- | ||
- [d61cbcf](../../commit/d61cbcf) [fixed] typo in docs regarding css class names | ||
- [7e5fa2a](../../commit/7e5fa2a) [fixed] Accessibility issues closes #2 | ||
- [7e91a17](../../commit/7e91a17) [added] smart css defaults for MenuOptions placement | ||
v0.0.4 - Wed, 15 Oct 2014 17:53:32 GMT | ||
@@ -2,0 +10,0 @@ -------------------------------------- |
@@ -10,2 +10,3 @@ !function(e){if("object"==typeof exports&&"undefined"!=typeof module)module.exports=e();else if("function"==typeof define&&define.amd)define([],e);else{var f;"undefined"!=typeof window?f=window:"undefined"!=typeof global?f=global:"undefined"!=typeof self&&(f=self),f.ReactMenu=e()}}(function(){var define,module,exports;return (function e(t,n,r){function s(o,u){if(!n[o]){if(!t[o]){var a=typeof require=="function"&&require;if(!u&&a)return a(o,!0);if(i)return i(o,!0);throw new Error("Cannot find module '"+o+"'")}var f=n[o]={exports:{}};t[o][0].call(f.exports,function(e){var n=t[o][1][e];return s(n?n:e)},f,f.exports,e,t,n,r)}return n[o].exports}var i=typeof require=="function"&&require;for(var o=0;o<r.length;o++)s(r[o]);return s})({1:[function(_dereq_,module,exports){ | ||
var MenuOption = _dereq_('./MenuOption'); | ||
var uuid = _dereq_('../helpers/uuid'); | ||
var injectCSS = _dereq_('../helpers/injectCSS'); | ||
@@ -24,6 +25,21 @@ var buildClassName = _dereq_('../mixins/buildClassName'); | ||
childContextTypes: { | ||
id: React.PropTypes.string, | ||
active: React.PropTypes.bool | ||
}, | ||
getChildContext: function () { | ||
return { | ||
id: this.state.id, | ||
active: this.state.active | ||
}; | ||
}, | ||
getInitialState: function(){ | ||
return { | ||
id: uuid(), | ||
active: false, | ||
selectedIndex: 0 | ||
selectedIndex: 0, | ||
horizontalPlacement: 'right', // only 'right' || 'left' | ||
verticalPlacement: 'bottom' // only 'top' || 'bottom' | ||
}; | ||
@@ -50,11 +66,29 @@ }, | ||
handleTriggerToggle: function() { | ||
this.setState({active: !this.state.active}, this.attemptOptionsFocus); | ||
this.setState({active: !this.state.active}, this.afterTriggerToggle); | ||
}, | ||
attemptOptionsFocus: function() { | ||
if (this.state.active){ | ||
afterTriggerToggle: function() { | ||
if (this.state.active) { | ||
this.refs.options.focusOption(0); | ||
this.updatePositioning(); | ||
} | ||
}, | ||
updatePositioning: function() { | ||
var triggerRect = this.refs.trigger.getDOMNode().getBoundingClientRect(); | ||
var optionsRect = this.refs.options.getDOMNode().getBoundingClientRect(); | ||
positionState = {}; | ||
// horizontal = left if it wont fit on left side | ||
if (triggerRect.left + optionsRect.width > window.innerWidth) { | ||
positionState.horizontalPlacement = 'left'; | ||
} else { | ||
positionState.horizontalPlacement = 'right'; | ||
} | ||
if (triggerRect.top + optionsRect.height > window.innerHeight) { | ||
positionState.verticalPlacement = 'top'; | ||
} else { | ||
positionState.verticalPlacement = 'bottom'; | ||
} | ||
this.setState(positionState); | ||
}, | ||
@@ -80,4 +114,4 @@ handleKeys: function(e) { | ||
trigger = cloneWithProps(child, { | ||
onToggleActive: this.handleTriggerToggle, | ||
ref: 'trigger' | ||
ref: 'trigger', | ||
onToggleActive: this.handleTriggerToggle | ||
}); | ||
@@ -91,5 +125,2 @@ } | ||
renderMenuOptions: function() { | ||
if (!this.state.active) { | ||
return null; | ||
} | ||
var options; | ||
@@ -101,2 +132,4 @@ if(this.verifyTwoChildren()) { | ||
ref: 'options', | ||
horizontalPlacement: this.state.horizontalPlacement, | ||
verticalPlacement: this.state.verticalPlacement, | ||
onSelectionMade: this.closeMenu | ||
@@ -115,3 +148,2 @@ }); | ||
className: this.buildClassName('Menu'), | ||
role: "menu", | ||
onKeyDown: this.handleKeys, | ||
@@ -128,3 +160,3 @@ onBlur: this.handleBlur | ||
},{"../helpers/injectCSS":5,"../mixins/buildClassName":7,"./MenuOption":2,"./MenuOptions":3,"./MenuTrigger":4,"react/lib/cloneWithProps":10}],2:[function(_dereq_,module,exports){ | ||
},{"../helpers/injectCSS":5,"../helpers/uuid":6,"../mixins/buildClassName":8,"./MenuOption":2,"./MenuOptions":3,"./MenuTrigger":4,"react/lib/cloneWithProps":11}],2:[function(_dereq_,module,exports){ | ||
/** @jsx React.DOM */ | ||
@@ -204,3 +236,4 @@ | ||
role: "menuitem", | ||
tabIndex: "-1" | ||
tabIndex: "-1", | ||
'aria-disabled': this.props.disabled | ||
}, | ||
@@ -214,3 +247,3 @@ this.props.children | ||
},{"../mixins/buildClassName":7}],3:[function(_dereq_,module,exports){ | ||
},{"../mixins/buildClassName":8}],3:[function(_dereq_,module,exports){ | ||
/** @jsx React.DOM */ | ||
@@ -225,2 +258,7 @@ | ||
contextTypes: { | ||
id: React.PropTypes.string, | ||
active: React.PropTypes.bool | ||
}, | ||
getInitialState: function() { | ||
@@ -271,12 +309,7 @@ return {activeIndex: 0} | ||
updateFocusIndexBy: function(delta) { | ||
// open menu if it's closed, and retry focus | ||
if (!this.state.active) { | ||
this.selectedIndex = 0; | ||
this.setState({active: true}, this.updateFocusIndexBy.bind(this, 0)); | ||
return | ||
} | ||
var optionNodes = this.getDOMNode().querySelectorAll('.Menu__MenuOption'); | ||
this.normalizeSelectedBy(delta, optionNodes.length); | ||
this.setState({activeIndex: this.selectedIndex}); | ||
optionNodes[this.selectedIndex].focus(); | ||
this.setState({activeIndex: this.selectedIndex}, function () { | ||
optionNodes[this.selectedIndex].focus(); | ||
}); | ||
}, | ||
@@ -302,7 +335,19 @@ | ||
buildName: function() { | ||
var cn = this.buildClassName('Menu__MenuOptions'); | ||
cn += ' Menu__MenuOptions--horizontal-' + this.props.horizontalPlacement; | ||
cn += ' Menu__MenuOptions--vertical-' + this.props.verticalPlacement; | ||
return cn; | ||
}, | ||
render: function() { | ||
return ( | ||
React.DOM.div({ | ||
className: this.buildClassName('Menu__MenuOptions'), | ||
onKeyUp: this.handleKeys | ||
id: this.context.id, | ||
role: "menu", | ||
tabIndex: "-1", | ||
'aria-expanded': this.context.active, | ||
style: {visibility: this.context.active ? 'visible' : 'hidden'}, | ||
className: this.buildName(), | ||
onKeyDown: this.handleKeys | ||
}, | ||
@@ -316,3 +361,3 @@ this.renderOptions() | ||
},{"../mixins/buildClassName":7,"./MenuOption":2,"react/lib/cloneWithProps":10}],4:[function(_dereq_,module,exports){ | ||
},{"../mixins/buildClassName":8,"./MenuOption":2,"react/lib/cloneWithProps":11}],4:[function(_dereq_,module,exports){ | ||
/** @jsx React.DOM */ | ||
@@ -325,6 +370,5 @@ | ||
getInitialState: function() { | ||
return { | ||
active: false | ||
}; | ||
contextTypes: { | ||
id: React.PropTypes.string, | ||
active: React.PropTypes.bool | ||
}, | ||
@@ -334,11 +378,4 @@ | ||
notifyParent: function() { | ||
if (this.props.onToggleActive) | ||
this.props.onToggleActive(this.state.active); | ||
}, | ||
toggleActive: function() { | ||
this.setState({ | ||
active: !this.state.active | ||
}, this.notifyParent); | ||
this.props.onToggleActive(!this.context.active); | ||
}, | ||
@@ -369,3 +406,6 @@ | ||
onKeyDown: this.handleKeyDown, | ||
tabIndex: "0" | ||
tabIndex: "0", | ||
role: "button", | ||
'aria-owns': this.context.id, | ||
'aria-haspopup': "true" | ||
}, | ||
@@ -379,3 +419,3 @@ this.props.children | ||
},{"../mixins/buildClassName":7}],5:[function(_dereq_,module,exports){ | ||
},{"../mixins/buildClassName":8}],5:[function(_dereq_,module,exports){ | ||
var jss = _dereq_('js-stylesheet'); | ||
@@ -414,2 +454,13 @@ | ||
background: '#FFF' | ||
}, | ||
'.Menu__MenuOptions--horizontal-left': { | ||
right: '0px' | ||
}, | ||
'.Menu__MenuOptions--horizontal-right': { | ||
left: '0px' | ||
}, | ||
'.Menu__MenuOptions--vertical-top': { | ||
bottom: '45px' | ||
}, | ||
'.Menu__MenuOptions--vertical-bottom': { | ||
} | ||
@@ -419,3 +470,9 @@ }); | ||
},{"js-stylesheet":8}],6:[function(_dereq_,module,exports){ | ||
},{"js-stylesheet":9}],6:[function(_dereq_,module,exports){ | ||
var count = 0; | ||
module.exports = function () { | ||
return 'react-menu-' + count++; | ||
}; | ||
},{}],7:[function(_dereq_,module,exports){ | ||
var Menu = _dereq_('./components/Menu'); | ||
@@ -428,3 +485,3 @@ Menu.MenuTrigger = _dereq_('./components/MenuTrigger'); | ||
},{"./components/Menu":1,"./components/MenuOption":2,"./components/MenuOptions":3,"./components/MenuTrigger":4}],7:[function(_dereq_,module,exports){ | ||
},{"./components/Menu":1,"./components/MenuOption":2,"./components/MenuOptions":3,"./components/MenuTrigger":4}],8:[function(_dereq_,module,exports){ | ||
module.exports = { | ||
@@ -441,3 +498,3 @@ | ||
},{}],8:[function(_dereq_,module,exports){ | ||
},{}],9:[function(_dereq_,module,exports){ | ||
!(function() { | ||
@@ -482,3 +539,3 @@ function jss(blocks) { | ||
},{}],9:[function(_dereq_,module,exports){ | ||
},{}],10:[function(_dereq_,module,exports){ | ||
/** | ||
@@ -647,3 +704,3 @@ * Copyright 2013-2014 Facebook, Inc. | ||
},{"./emptyFunction":12,"./invariant":13,"./joinClasses":14,"./merge":17}],10:[function(_dereq_,module,exports){ | ||
},{"./emptyFunction":13,"./invariant":14,"./joinClasses":15,"./merge":18}],11:[function(_dereq_,module,exports){ | ||
/** | ||
@@ -711,3 +768,3 @@ * Copyright 2013-2014 Facebook, Inc. | ||
},{"./ReactPropTransferer":9,"./keyOf":16,"./warning":20}],11:[function(_dereq_,module,exports){ | ||
},{"./ReactPropTransferer":10,"./keyOf":17,"./warning":21}],12:[function(_dereq_,module,exports){ | ||
/** | ||
@@ -768,3 +825,3 @@ * Copyright 2013-2014 Facebook, Inc. | ||
},{}],12:[function(_dereq_,module,exports){ | ||
},{}],13:[function(_dereq_,module,exports){ | ||
/** | ||
@@ -814,3 +871,3 @@ * Copyright 2013-2014 Facebook, Inc. | ||
},{"./copyProperties":11}],13:[function(_dereq_,module,exports){ | ||
},{"./copyProperties":12}],14:[function(_dereq_,module,exports){ | ||
/** | ||
@@ -877,3 +934,3 @@ * Copyright 2013-2014 Facebook, Inc. | ||
},{}],14:[function(_dereq_,module,exports){ | ||
},{}],15:[function(_dereq_,module,exports){ | ||
/** | ||
@@ -924,3 +981,3 @@ * Copyright 2013-2014 Facebook, Inc. | ||
},{}],15:[function(_dereq_,module,exports){ | ||
},{}],16:[function(_dereq_,module,exports){ | ||
/** | ||
@@ -985,3 +1042,3 @@ * Copyright 2013-2014 Facebook, Inc. | ||
},{"./invariant":13}],16:[function(_dereq_,module,exports){ | ||
},{"./invariant":14}],17:[function(_dereq_,module,exports){ | ||
/** | ||
@@ -1029,3 +1086,3 @@ * Copyright 2013-2014 Facebook, Inc. | ||
},{}],17:[function(_dereq_,module,exports){ | ||
},{}],18:[function(_dereq_,module,exports){ | ||
/** | ||
@@ -1069,3 +1126,3 @@ * Copyright 2013-2014 Facebook, Inc. | ||
},{"./mergeInto":19}],18:[function(_dereq_,module,exports){ | ||
},{"./mergeInto":20}],19:[function(_dereq_,module,exports){ | ||
/** | ||
@@ -1219,3 +1276,3 @@ * Copyright 2013-2014 Facebook, Inc. | ||
},{"./invariant":13,"./keyMirror":15}],19:[function(_dereq_,module,exports){ | ||
},{"./invariant":14,"./keyMirror":16}],20:[function(_dereq_,module,exports){ | ||
/** | ||
@@ -1268,3 +1325,3 @@ * Copyright 2013-2014 Facebook, Inc. | ||
},{"./mergeHelpers":18}],20:[function(_dereq_,module,exports){ | ||
},{"./mergeHelpers":19}],21:[function(_dereq_,module,exports){ | ||
/** | ||
@@ -1319,4 +1376,4 @@ * Copyright 2014 Facebook, Inc. | ||
},{"./emptyFunction":12}]},{},[6]) | ||
(6) | ||
},{"./emptyFunction":13}]},{},[7]) | ||
(7) | ||
}); |
@@ -1,1 +0,1 @@ | ||
!function(e){if("object"==typeof exports&&"undefined"!=typeof module)module.exports=e();else if("function"==typeof define&&define.amd)define([],e);else{var f;"undefined"!=typeof window?f=window:"undefined"!=typeof global?f=global:"undefined"!=typeof self&&(f=self),f.ReactMenu=e()}}(function(){return function e(t,n,r){function s(o,u){if(!n[o]){if(!t[o]){var a="function"==typeof require&&require;if(!u&&a)return a(o,!0);if(i)return i(o,!0);throw new Error("Cannot find module '"+o+"'")}var f=n[o]={exports:{}};t[o][0].call(f.exports,function(e){var n=t[o][1][e];return s(n?n:e)},f,f.exports,e,t,n,r)}return n[o].exports}for(var i="function"==typeof require&&require,o=0;o<r.length;o++)s(r[o]);return s}({1:[function(_dereq_,module){{var React="undefined"!=typeof window?window.React:"undefined"!=typeof global?global.React:null,cloneWithProps=_dereq_("react/lib/cloneWithProps"),MenuTrigger=_dereq_("./MenuTrigger"),MenuOptions=_dereq_("./MenuOptions"),injectCSS=(_dereq_("./MenuOption"),_dereq_("../helpers/injectCSS")),buildClassName=_dereq_("../mixins/buildClassName");module.exports=React.createClass({displayName:"Menu",statics:{injectCSS:injectCSS},mixins:[buildClassName],getInitialState:function(){return{active:!1,selectedIndex:0}},closeMenu:function(){this.setState({active:!1},this.focusTrigger)},focusTrigger:function(){this.refs.trigger.getDOMNode().focus()},handleBlur:function(){setTimeout(function(){!document.activeElement.className.match(/Menu__/)&&this.state.active&&this.closeMenu()}.bind(this),1)},handleTriggerToggle:function(){this.setState({active:!this.state.active},this.attemptOptionsFocus)},attemptOptionsFocus:function(){this.state.active&&this.refs.options.focusOption(0)},handleKeys:function(e){"Escape"===e.key&&this.closeMenu()},verifyTwoChildren:function(){var ok=2===React.Children.count(this.props.children);if(!ok)throw"react-menu can only take two children, a MenuTrigger, and a MenuOptions";return ok},renderTrigger:function(){var trigger;return this.verifyTwoChildren()&&React.Children.forEach(this.props.children,function(child){child.type===MenuTrigger.type&&(trigger=cloneWithProps(child,{onToggleActive:this.handleTriggerToggle,ref:"trigger"}))}.bind(this)),trigger},renderMenuOptions:function(){if(!this.state.active)return null;var options;return this.verifyTwoChildren()&&React.Children.forEach(this.props.children,function(child){child.type===MenuOptions.type&&(options=cloneWithProps(child,{ref:"options",onSelectionMade:this.closeMenu}))}.bind(this)),options},render:function(){return React.DOM.div({className:this.buildClassName("Menu"),role:"menu",onKeyDown:this.handleKeys,onBlur:this.handleBlur},this.renderTrigger(),this.renderMenuOptions())}})}},{"../helpers/injectCSS":5,"../mixins/buildClassName":7,"./MenuOption":2,"./MenuOptions":3,"./MenuTrigger":4,"react/lib/cloneWithProps":10}],2:[function(_dereq_,module){{var React="undefined"!=typeof window?window.React:"undefined"!=typeof global?global.React:null,buildClassName=_dereq_("../mixins/buildClassName");module.exports=React.createClass({displayName:"exports",propTypes:{active:React.PropTypes.bool,onSelect:React.PropTypes.func,onDisabledSelect:React.PropTypes.func,disabled:React.PropTypes.bool},mixins:[buildClassName],notifyDisabledSelect:function(){this.props.onDisabledSelect&&this.props.onDisabledSelect()},onSelect:function(){return this.props.disabled?void this.notifyDisabledSelect():(this.props.onSelect&&this.props.onSelect(),void this.props._internalSelect())},handleKeyUp:function(e){" "===e.key&&this.onSelect()},handleKeyDown:function(e){"Enter"===e.key&&this.onSelect()},handleClick:function(){this.onSelect()},handleHover:function(){this.props._internalFocus(this.props.index)},buildName:function(){var name=this.buildClassName("Menu__MenuOption");return this.props.active&&(name+=" Menu__MenuOption--active"),this.props.disabled&&(name+=" Menu__MenuOption--disabled"),name},render:function(){return React.DOM.div({onClick:this.handleClick,onKeyUp:this.handleKeyUp,onKeyDown:this.handleKeyDown,onMouseOver:this.handleHover,className:this.buildName(),role:"menuitem",tabIndex:"-1"},this.props.children)}})}},{"../mixins/buildClassName":7}],3:[function(_dereq_,module){{var React="undefined"!=typeof window?window.React:"undefined"!=typeof global?global.React:null,MenuOption=_dereq_("./MenuOption"),cloneWithProps=_dereq_("react/lib/cloneWithProps"),buildClassName=_dereq_("../mixins/buildClassName");module.exports=React.createClass({displayName:"exports",getInitialState:function(){return{activeIndex:0}},mixins:[buildClassName],onSelectionMade:function(){this.props.onSelectionMade()},moveSelectionUp:function(){this.updateFocusIndexBy(-1)},moveSelectionDown:function(){this.updateFocusIndexBy(1)},handleKeys:function(e){var options={ArrowDown:this.moveSelectionDown,ArrowUp:this.moveSelectionUp,Escape:this.closeMenu};options[e.key]&&options[e.key].call(this)},normalizeSelectedBy:function(delta,numOptions){this.selectedIndex+=delta,this.selectedIndex>numOptions-1?this.selectedIndex=0:this.selectedIndex<0&&(this.selectedIndex=numOptions-1)},focusOption:function(index){this.selectedIndex=index,this.updateFocusIndexBy(0)},updateFocusIndexBy:function(delta){if(!this.state.active)return this.selectedIndex=0,void this.setState({active:!0},this.updateFocusIndexBy.bind(this,0));var optionNodes=this.getDOMNode().querySelectorAll(".Menu__MenuOption");this.normalizeSelectedBy(delta,optionNodes.length),this.setState({activeIndex:this.selectedIndex}),optionNodes[this.selectedIndex].focus()},renderOptions:function(){var index=0;return React.Children.map(this.props.children,function(c){var clonedOption=c;if(c.type===MenuOption.type){var active=this.state.activeIndex===index;clonedOption=cloneWithProps(c,{active:active,index:index,_internalFocus:this.focusOption,_internalSelect:this.onSelectionMade}),index++}return clonedOption}.bind(this))},render:function(){return React.DOM.div({className:this.buildClassName("Menu__MenuOptions"),onKeyUp:this.handleKeys},this.renderOptions())}})}},{"../mixins/buildClassName":7,"./MenuOption":2,"react/lib/cloneWithProps":10}],4:[function(_dereq_,module){{var React="undefined"!=typeof window?window.React:"undefined"!=typeof global?global.React:null,buildClassName=_dereq_("../mixins/buildClassName");module.exports=React.createClass({displayName:"exports",getInitialState:function(){return{active:!1}},mixins:[buildClassName],notifyParent:function(){this.props.onToggleActive&&this.props.onToggleActive(this.state.active)},toggleActive:function(){this.setState({active:!this.state.active},this.notifyParent)},handleKeyUp:function(e){return" "===e.key&&this.toggleActive(),!0},handleKeyDown:function(e){return"Enter"===e.key&&this.toggleActive(),!0},handleClick:function(){this.toggleActive()},render:function(){return React.DOM.div({className:this.buildClassName("Menu__MenuTrigger"),onClick:this.handleClick,onKeyUp:this.handleKeyUp,onKeyDown:this.handleKeyDown,tabIndex:"0"},this.props.children)}})}},{"../mixins/buildClassName":7}],5:[function(_dereq_,module){var jss=_dereq_("js-stylesheet");module.exports=function(){jss({".Menu":{position:"relative"},".Menu__MenuOptions":{border:"1px solid #ccc","border-radius":"3px",background:"#FFF",position:"absolute"},".Menu__MenuOption":{padding:"5px","border-radius":"2px",outline:"none",cursor:"pointer"},".Menu__MenuOption--disabled":{"background-color":"#eee"},".Menu__MenuOption--active":{"background-color":"#0aafff"},".Menu__MenuOption--active.Menu__MenuOption--disabled":{"background-color":"#ccc"},".Menu__MenuTrigger":{border:"1px solid #ccc","border-radius":"3px",padding:"5px",background:"#FFF"}})}},{"js-stylesheet":8}],6:[function(_dereq_,module){var Menu=_dereq_("./components/Menu");Menu.MenuTrigger=_dereq_("./components/MenuTrigger"),Menu.MenuOptions=_dereq_("./components/MenuOptions"),Menu.MenuOption=_dereq_("./components/MenuOption"),module.exports=Menu},{"./components/Menu":1,"./components/MenuOption":2,"./components/MenuOptions":3,"./components/MenuTrigger":4}],7:[function(_dereq_,module){module.exports={buildClassName:function(baseName){var name=baseName;return this.props.className&&(name+=" "+this.props.className),name}}},{}],8:[function(_dereq_,module,exports){!function(){function jss(blocks){var css=[];for(var block in blocks)css.push(createStyleBlock(block,blocks[block]));injectCSS(css)}function createStyleBlock(selector,rules){return selector+" {\n"+parseRules(rules)+"\n}"}function parseRules(rules){var css=[];for(var rule in rules)css.push(" "+rule+": "+rules[rule]+";");return css.join("\n")}function injectCSS(css){var style=document.getElementById("jss-styles");if(!style){style=document.createElement("style"),style.setAttribute("id","jss-styles");var head=document.getElementsByTagName("head")[0];head.insertBefore(style,head.firstChild)}var node=document.createTextNode(css.join("\n\n"));style.appendChild(node)}"object"==typeof exports?module.exports=jss:window.jss=jss}()},{}],9:[function(_dereq_,module){"use strict";function createTransferStrategy(mergeStrategy){return function(props,key,value){props[key]=props.hasOwnProperty(key)?mergeStrategy(props[key],value):value}}function transferInto(props,newProps){for(var thisKey in newProps)if(newProps.hasOwnProperty(thisKey)){var transferStrategy=TransferStrategies[thisKey];transferStrategy&&TransferStrategies.hasOwnProperty(thisKey)?transferStrategy(props,thisKey,newProps[thisKey]):props.hasOwnProperty(thisKey)||(props[thisKey]=newProps[thisKey])}return props}var emptyFunction=_dereq_("./emptyFunction"),invariant=_dereq_("./invariant"),joinClasses=_dereq_("./joinClasses"),merge=_dereq_("./merge"),transferStrategyMerge=createTransferStrategy(function(a,b){return merge(b,a)}),TransferStrategies={children:emptyFunction,className:createTransferStrategy(joinClasses),key:emptyFunction,ref:emptyFunction,style:transferStrategyMerge},ReactPropTransferer={TransferStrategies:TransferStrategies,mergeProps:function(oldProps,newProps){return transferInto(merge(oldProps),newProps)},Mixin:{transferPropsTo:function(descriptor){return invariant(descriptor._owner===this),transferInto(descriptor.props,this.props),descriptor}}};module.exports=ReactPropTransferer},{"./emptyFunction":12,"./invariant":13,"./joinClasses":14,"./merge":17}],10:[function(_dereq_,module){"use strict";function cloneWithProps(child,props){var newProps=ReactPropTransferer.mergeProps(props,child.props);return!newProps.hasOwnProperty(CHILDREN_PROP)&&child.props.hasOwnProperty(CHILDREN_PROP)&&(newProps.children=child.props.children),child.constructor(newProps)}var ReactPropTransferer=_dereq_("./ReactPropTransferer"),keyOf=_dereq_("./keyOf"),CHILDREN_PROP=(_dereq_("./warning"),keyOf({children:null}));module.exports=cloneWithProps},{"./ReactPropTransferer":9,"./keyOf":16,"./warning":20}],11:[function(_dereq_,module){function copyProperties(obj,a,b,c,d,e,f){obj=obj||{};for(var v,args=[a,b,c,d,e],ii=0;args[ii];){v=args[ii++];for(var k in v)obj[k]=v[k];v.hasOwnProperty&&v.hasOwnProperty("toString")&&"undefined"!=typeof v.toString&&obj.toString!==v.toString&&(obj.toString=v.toString)}return obj}module.exports=copyProperties},{}],12:[function(_dereq_,module){function makeEmptyFunction(arg){return function(){return arg}}function emptyFunction(){}var copyProperties=_dereq_("./copyProperties");copyProperties(emptyFunction,{thatReturns:makeEmptyFunction,thatReturnsFalse:makeEmptyFunction(!1),thatReturnsTrue:makeEmptyFunction(!0),thatReturnsNull:makeEmptyFunction(null),thatReturnsThis:function(){return this},thatReturnsArgument:function(arg){return arg}}),module.exports=emptyFunction},{"./copyProperties":11}],13:[function(_dereq_,module){"use strict";var invariant=function(condition,format,a,b,c,d,e,f){if(!condition){var error;if(void 0===format)error=new Error("Minified exception occurred; use the non-minified dev environment for the full error message and additional helpful warnings.");else{var args=[a,b,c,d,e,f],argIndex=0;error=new Error("Invariant Violation: "+format.replace(/%s/g,function(){return args[argIndex++]}))}throw error.framesToPop=1,error}};module.exports=invariant},{}],14:[function(_dereq_,module){"use strict";function joinClasses(className){className||(className="");var nextClass,argLength=arguments.length;if(argLength>1)for(var ii=1;argLength>ii;ii++)nextClass=arguments[ii],nextClass&&(className+=" "+nextClass);return className}module.exports=joinClasses},{}],15:[function(_dereq_,module){"use strict";var invariant=_dereq_("./invariant"),keyMirror=function(obj){var key,ret={};invariant(obj instanceof Object&&!Array.isArray(obj));for(key in obj)obj.hasOwnProperty(key)&&(ret[key]=key);return ret};module.exports=keyMirror},{"./invariant":13}],16:[function(_dereq_,module){var keyOf=function(oneKeyObj){var key;for(key in oneKeyObj)if(oneKeyObj.hasOwnProperty(key))return key;return null};module.exports=keyOf},{}],17:[function(_dereq_,module){"use strict";var mergeInto=_dereq_("./mergeInto"),merge=function(one,two){var result={};return mergeInto(result,one),mergeInto(result,two),result};module.exports=merge},{"./mergeInto":19}],18:[function(_dereq_,module){"use strict";var invariant=_dereq_("./invariant"),keyMirror=_dereq_("./keyMirror"),MAX_MERGE_DEPTH=36,isTerminal=function(o){return"object"!=typeof o||null===o},mergeHelpers={MAX_MERGE_DEPTH:MAX_MERGE_DEPTH,isTerminal:isTerminal,normalizeMergeArg:function(arg){return void 0===arg||null===arg?{}:arg},checkMergeArrayArgs:function(one,two){invariant(Array.isArray(one)&&Array.isArray(two))},checkMergeObjectArgs:function(one,two){mergeHelpers.checkMergeObjectArg(one),mergeHelpers.checkMergeObjectArg(two)},checkMergeObjectArg:function(arg){invariant(!isTerminal(arg)&&!Array.isArray(arg))},checkMergeIntoObjectArg:function(arg){invariant(!(isTerminal(arg)&&"function"!=typeof arg||Array.isArray(arg)))},checkMergeLevel:function(level){invariant(MAX_MERGE_DEPTH>level)},checkArrayStrategy:function(strategy){invariant(void 0===strategy||strategy in mergeHelpers.ArrayStrategies)},ArrayStrategies:keyMirror({Clobber:!0,IndexByIndex:!0})};module.exports=mergeHelpers},{"./invariant":13,"./keyMirror":15}],19:[function(_dereq_,module){"use strict";function mergeInto(one,two){if(checkMergeIntoObjectArg(one),null!=two){checkMergeObjectArg(two);for(var key in two)two.hasOwnProperty(key)&&(one[key]=two[key])}}var mergeHelpers=_dereq_("./mergeHelpers"),checkMergeObjectArg=mergeHelpers.checkMergeObjectArg,checkMergeIntoObjectArg=mergeHelpers.checkMergeIntoObjectArg;module.exports=mergeInto},{"./mergeHelpers":18}],20:[function(_dereq_,module){"use strict";var emptyFunction=_dereq_("./emptyFunction"),warning=emptyFunction;module.exports=warning},{"./emptyFunction":12}]},{},[6])(6)}); | ||
!function(e){if("object"==typeof exports&&"undefined"!=typeof module)module.exports=e();else if("function"==typeof define&&define.amd)define([],e);else{var f;"undefined"!=typeof window?f=window:"undefined"!=typeof global?f=global:"undefined"!=typeof self&&(f=self),f.ReactMenu=e()}}(function(){return function e(t,n,r){function s(o,u){if(!n[o]){if(!t[o]){var a="function"==typeof require&&require;if(!u&&a)return a(o,!0);if(i)return i(o,!0);throw new Error("Cannot find module '"+o+"'")}var f=n[o]={exports:{}};t[o][0].call(f.exports,function(e){var n=t[o][1][e];return s(n?n:e)},f,f.exports,e,t,n,r)}return n[o].exports}for(var i="function"==typeof require&&require,o=0;o<r.length;o++)s(r[o]);return s}({1:[function(_dereq_,module){{var React="undefined"!=typeof window?window.React:"undefined"!=typeof global?global.React:null,cloneWithProps=_dereq_("react/lib/cloneWithProps"),MenuTrigger=_dereq_("./MenuTrigger"),MenuOptions=_dereq_("./MenuOptions"),uuid=(_dereq_("./MenuOption"),_dereq_("../helpers/uuid")),injectCSS=_dereq_("../helpers/injectCSS"),buildClassName=_dereq_("../mixins/buildClassName");module.exports=React.createClass({displayName:"Menu",statics:{injectCSS:injectCSS},mixins:[buildClassName],childContextTypes:{id:React.PropTypes.string,active:React.PropTypes.bool},getChildContext:function(){return{id:this.state.id,active:this.state.active}},getInitialState:function(){return{id:uuid(),active:!1,selectedIndex:0,horizontalPlacement:"right",verticalPlacement:"bottom"}},closeMenu:function(){this.setState({active:!1},this.focusTrigger)},focusTrigger:function(){this.refs.trigger.getDOMNode().focus()},handleBlur:function(){setTimeout(function(){!document.activeElement.className.match(/Menu__/)&&this.state.active&&this.closeMenu()}.bind(this),1)},handleTriggerToggle:function(){this.setState({active:!this.state.active},this.afterTriggerToggle)},afterTriggerToggle:function(){this.state.active&&(this.refs.options.focusOption(0),this.updatePositioning())},updatePositioning:function(){var triggerRect=this.refs.trigger.getDOMNode().getBoundingClientRect(),optionsRect=this.refs.options.getDOMNode().getBoundingClientRect();positionState={},positionState.horizontalPlacement=triggerRect.left+optionsRect.width>window.innerWidth?"left":"right",positionState.verticalPlacement=triggerRect.top+optionsRect.height>window.innerHeight?"top":"bottom",this.setState(positionState)},handleKeys:function(e){"Escape"===e.key&&this.closeMenu()},verifyTwoChildren:function(){var ok=2===React.Children.count(this.props.children);if(!ok)throw"react-menu can only take two children, a MenuTrigger, and a MenuOptions";return ok},renderTrigger:function(){var trigger;return this.verifyTwoChildren()&&React.Children.forEach(this.props.children,function(child){child.type===MenuTrigger.type&&(trigger=cloneWithProps(child,{ref:"trigger",onToggleActive:this.handleTriggerToggle}))}.bind(this)),trigger},renderMenuOptions:function(){var options;return this.verifyTwoChildren()&&React.Children.forEach(this.props.children,function(child){child.type===MenuOptions.type&&(options=cloneWithProps(child,{ref:"options",horizontalPlacement:this.state.horizontalPlacement,verticalPlacement:this.state.verticalPlacement,onSelectionMade:this.closeMenu}))}.bind(this)),options},render:function(){return React.DOM.div({className:this.buildClassName("Menu"),onKeyDown:this.handleKeys,onBlur:this.handleBlur},this.renderTrigger(),this.renderMenuOptions())}})}},{"../helpers/injectCSS":5,"../helpers/uuid":6,"../mixins/buildClassName":8,"./MenuOption":2,"./MenuOptions":3,"./MenuTrigger":4,"react/lib/cloneWithProps":11}],2:[function(_dereq_,module){{var React="undefined"!=typeof window?window.React:"undefined"!=typeof global?global.React:null,buildClassName=_dereq_("../mixins/buildClassName");module.exports=React.createClass({displayName:"exports",propTypes:{active:React.PropTypes.bool,onSelect:React.PropTypes.func,onDisabledSelect:React.PropTypes.func,disabled:React.PropTypes.bool},mixins:[buildClassName],notifyDisabledSelect:function(){this.props.onDisabledSelect&&this.props.onDisabledSelect()},onSelect:function(){return this.props.disabled?void this.notifyDisabledSelect():(this.props.onSelect&&this.props.onSelect(),void this.props._internalSelect())},handleKeyUp:function(e){" "===e.key&&this.onSelect()},handleKeyDown:function(e){"Enter"===e.key&&this.onSelect()},handleClick:function(){this.onSelect()},handleHover:function(){this.props._internalFocus(this.props.index)},buildName:function(){var name=this.buildClassName("Menu__MenuOption");return this.props.active&&(name+=" Menu__MenuOption--active"),this.props.disabled&&(name+=" Menu__MenuOption--disabled"),name},render:function(){return React.DOM.div({onClick:this.handleClick,onKeyUp:this.handleKeyUp,onKeyDown:this.handleKeyDown,onMouseOver:this.handleHover,className:this.buildName(),role:"menuitem",tabIndex:"-1","aria-disabled":this.props.disabled},this.props.children)}})}},{"../mixins/buildClassName":8}],3:[function(_dereq_,module){{var React="undefined"!=typeof window?window.React:"undefined"!=typeof global?global.React:null,MenuOption=_dereq_("./MenuOption"),cloneWithProps=_dereq_("react/lib/cloneWithProps"),buildClassName=_dereq_("../mixins/buildClassName");module.exports=React.createClass({displayName:"exports",contextTypes:{id:React.PropTypes.string,active:React.PropTypes.bool},getInitialState:function(){return{activeIndex:0}},mixins:[buildClassName],onSelectionMade:function(){this.props.onSelectionMade()},moveSelectionUp:function(){this.updateFocusIndexBy(-1)},moveSelectionDown:function(){this.updateFocusIndexBy(1)},handleKeys:function(e){var options={ArrowDown:this.moveSelectionDown,ArrowUp:this.moveSelectionUp,Escape:this.closeMenu};options[e.key]&&options[e.key].call(this)},normalizeSelectedBy:function(delta,numOptions){this.selectedIndex+=delta,this.selectedIndex>numOptions-1?this.selectedIndex=0:this.selectedIndex<0&&(this.selectedIndex=numOptions-1)},focusOption:function(index){this.selectedIndex=index,this.updateFocusIndexBy(0)},updateFocusIndexBy:function(delta){var optionNodes=this.getDOMNode().querySelectorAll(".Menu__MenuOption");this.normalizeSelectedBy(delta,optionNodes.length),this.setState({activeIndex:this.selectedIndex},function(){optionNodes[this.selectedIndex].focus()})},renderOptions:function(){var index=0;return React.Children.map(this.props.children,function(c){var clonedOption=c;if(c.type===MenuOption.type){var active=this.state.activeIndex===index;clonedOption=cloneWithProps(c,{active:active,index:index,_internalFocus:this.focusOption,_internalSelect:this.onSelectionMade}),index++}return clonedOption}.bind(this))},buildName:function(){var cn=this.buildClassName("Menu__MenuOptions");return cn+=" Menu__MenuOptions--horizontal-"+this.props.horizontalPlacement,cn+=" Menu__MenuOptions--vertical-"+this.props.verticalPlacement},render:function(){return React.DOM.div({id:this.context.id,role:"menu",tabIndex:"-1","aria-expanded":this.context.active,style:{visibility:this.context.active?"visible":"hidden"},className:this.buildName(),onKeyDown:this.handleKeys},this.renderOptions())}})}},{"../mixins/buildClassName":8,"./MenuOption":2,"react/lib/cloneWithProps":11}],4:[function(_dereq_,module){{var React="undefined"!=typeof window?window.React:"undefined"!=typeof global?global.React:null,buildClassName=_dereq_("../mixins/buildClassName");module.exports=React.createClass({displayName:"exports",contextTypes:{id:React.PropTypes.string,active:React.PropTypes.bool},mixins:[buildClassName],toggleActive:function(){this.props.onToggleActive(!this.context.active)},handleKeyUp:function(e){return" "===e.key&&this.toggleActive(),!0},handleKeyDown:function(e){return"Enter"===e.key&&this.toggleActive(),!0},handleClick:function(){this.toggleActive()},render:function(){return React.DOM.div({className:this.buildClassName("Menu__MenuTrigger"),onClick:this.handleClick,onKeyUp:this.handleKeyUp,onKeyDown:this.handleKeyDown,tabIndex:"0",role:"button","aria-owns":this.context.id,"aria-haspopup":"true"},this.props.children)}})}},{"../mixins/buildClassName":8}],5:[function(_dereq_,module){var jss=_dereq_("js-stylesheet");module.exports=function(){jss({".Menu":{position:"relative"},".Menu__MenuOptions":{border:"1px solid #ccc","border-radius":"3px",background:"#FFF",position:"absolute"},".Menu__MenuOption":{padding:"5px","border-radius":"2px",outline:"none",cursor:"pointer"},".Menu__MenuOption--disabled":{"background-color":"#eee"},".Menu__MenuOption--active":{"background-color":"#0aafff"},".Menu__MenuOption--active.Menu__MenuOption--disabled":{"background-color":"#ccc"},".Menu__MenuTrigger":{border:"1px solid #ccc","border-radius":"3px",padding:"5px",background:"#FFF"},".Menu__MenuOptions--horizontal-left":{right:"0px"},".Menu__MenuOptions--horizontal-right":{left:"0px"},".Menu__MenuOptions--vertical-top":{bottom:"45px"},".Menu__MenuOptions--vertical-bottom":{}})}},{"js-stylesheet":9}],6:[function(_dereq_,module){var count=0;module.exports=function(){return"react-menu-"+count++}},{}],7:[function(_dereq_,module){var Menu=_dereq_("./components/Menu");Menu.MenuTrigger=_dereq_("./components/MenuTrigger"),Menu.MenuOptions=_dereq_("./components/MenuOptions"),Menu.MenuOption=_dereq_("./components/MenuOption"),module.exports=Menu},{"./components/Menu":1,"./components/MenuOption":2,"./components/MenuOptions":3,"./components/MenuTrigger":4}],8:[function(_dereq_,module){module.exports={buildClassName:function(baseName){var name=baseName;return this.props.className&&(name+=" "+this.props.className),name}}},{}],9:[function(_dereq_,module,exports){!function(){function jss(blocks){var css=[];for(var block in blocks)css.push(createStyleBlock(block,blocks[block]));injectCSS(css)}function createStyleBlock(selector,rules){return selector+" {\n"+parseRules(rules)+"\n}"}function parseRules(rules){var css=[];for(var rule in rules)css.push(" "+rule+": "+rules[rule]+";");return css.join("\n")}function injectCSS(css){var style=document.getElementById("jss-styles");if(!style){style=document.createElement("style"),style.setAttribute("id","jss-styles");var head=document.getElementsByTagName("head")[0];head.insertBefore(style,head.firstChild)}var node=document.createTextNode(css.join("\n\n"));style.appendChild(node)}"object"==typeof exports?module.exports=jss:window.jss=jss}()},{}],10:[function(_dereq_,module){"use strict";function createTransferStrategy(mergeStrategy){return function(props,key,value){props[key]=props.hasOwnProperty(key)?mergeStrategy(props[key],value):value}}function transferInto(props,newProps){for(var thisKey in newProps)if(newProps.hasOwnProperty(thisKey)){var transferStrategy=TransferStrategies[thisKey];transferStrategy&&TransferStrategies.hasOwnProperty(thisKey)?transferStrategy(props,thisKey,newProps[thisKey]):props.hasOwnProperty(thisKey)||(props[thisKey]=newProps[thisKey])}return props}var emptyFunction=_dereq_("./emptyFunction"),invariant=_dereq_("./invariant"),joinClasses=_dereq_("./joinClasses"),merge=_dereq_("./merge"),transferStrategyMerge=createTransferStrategy(function(a,b){return merge(b,a)}),TransferStrategies={children:emptyFunction,className:createTransferStrategy(joinClasses),key:emptyFunction,ref:emptyFunction,style:transferStrategyMerge},ReactPropTransferer={TransferStrategies:TransferStrategies,mergeProps:function(oldProps,newProps){return transferInto(merge(oldProps),newProps)},Mixin:{transferPropsTo:function(descriptor){return invariant(descriptor._owner===this),transferInto(descriptor.props,this.props),descriptor}}};module.exports=ReactPropTransferer},{"./emptyFunction":13,"./invariant":14,"./joinClasses":15,"./merge":18}],11:[function(_dereq_,module){"use strict";function cloneWithProps(child,props){var newProps=ReactPropTransferer.mergeProps(props,child.props);return!newProps.hasOwnProperty(CHILDREN_PROP)&&child.props.hasOwnProperty(CHILDREN_PROP)&&(newProps.children=child.props.children),child.constructor(newProps)}var ReactPropTransferer=_dereq_("./ReactPropTransferer"),keyOf=_dereq_("./keyOf"),CHILDREN_PROP=(_dereq_("./warning"),keyOf({children:null}));module.exports=cloneWithProps},{"./ReactPropTransferer":10,"./keyOf":17,"./warning":21}],12:[function(_dereq_,module){function copyProperties(obj,a,b,c,d,e,f){obj=obj||{};for(var v,args=[a,b,c,d,e],ii=0;args[ii];){v=args[ii++];for(var k in v)obj[k]=v[k];v.hasOwnProperty&&v.hasOwnProperty("toString")&&"undefined"!=typeof v.toString&&obj.toString!==v.toString&&(obj.toString=v.toString)}return obj}module.exports=copyProperties},{}],13:[function(_dereq_,module){function makeEmptyFunction(arg){return function(){return arg}}function emptyFunction(){}var copyProperties=_dereq_("./copyProperties");copyProperties(emptyFunction,{thatReturns:makeEmptyFunction,thatReturnsFalse:makeEmptyFunction(!1),thatReturnsTrue:makeEmptyFunction(!0),thatReturnsNull:makeEmptyFunction(null),thatReturnsThis:function(){return this},thatReturnsArgument:function(arg){return arg}}),module.exports=emptyFunction},{"./copyProperties":12}],14:[function(_dereq_,module){"use strict";var invariant=function(condition,format,a,b,c,d,e,f){if(!condition){var error;if(void 0===format)error=new Error("Minified exception occurred; use the non-minified dev environment for the full error message and additional helpful warnings.");else{var args=[a,b,c,d,e,f],argIndex=0;error=new Error("Invariant Violation: "+format.replace(/%s/g,function(){return args[argIndex++]}))}throw error.framesToPop=1,error}};module.exports=invariant},{}],15:[function(_dereq_,module){"use strict";function joinClasses(className){className||(className="");var nextClass,argLength=arguments.length;if(argLength>1)for(var ii=1;argLength>ii;ii++)nextClass=arguments[ii],nextClass&&(className+=" "+nextClass);return className}module.exports=joinClasses},{}],16:[function(_dereq_,module){"use strict";var invariant=_dereq_("./invariant"),keyMirror=function(obj){var key,ret={};invariant(obj instanceof Object&&!Array.isArray(obj));for(key in obj)obj.hasOwnProperty(key)&&(ret[key]=key);return ret};module.exports=keyMirror},{"./invariant":14}],17:[function(_dereq_,module){var keyOf=function(oneKeyObj){var key;for(key in oneKeyObj)if(oneKeyObj.hasOwnProperty(key))return key;return null};module.exports=keyOf},{}],18:[function(_dereq_,module){"use strict";var mergeInto=_dereq_("./mergeInto"),merge=function(one,two){var result={};return mergeInto(result,one),mergeInto(result,two),result};module.exports=merge},{"./mergeInto":20}],19:[function(_dereq_,module){"use strict";var invariant=_dereq_("./invariant"),keyMirror=_dereq_("./keyMirror"),MAX_MERGE_DEPTH=36,isTerminal=function(o){return"object"!=typeof o||null===o},mergeHelpers={MAX_MERGE_DEPTH:MAX_MERGE_DEPTH,isTerminal:isTerminal,normalizeMergeArg:function(arg){return void 0===arg||null===arg?{}:arg},checkMergeArrayArgs:function(one,two){invariant(Array.isArray(one)&&Array.isArray(two))},checkMergeObjectArgs:function(one,two){mergeHelpers.checkMergeObjectArg(one),mergeHelpers.checkMergeObjectArg(two)},checkMergeObjectArg:function(arg){invariant(!isTerminal(arg)&&!Array.isArray(arg))},checkMergeIntoObjectArg:function(arg){invariant(!(isTerminal(arg)&&"function"!=typeof arg||Array.isArray(arg)))},checkMergeLevel:function(level){invariant(MAX_MERGE_DEPTH>level)},checkArrayStrategy:function(strategy){invariant(void 0===strategy||strategy in mergeHelpers.ArrayStrategies)},ArrayStrategies:keyMirror({Clobber:!0,IndexByIndex:!0})};module.exports=mergeHelpers},{"./invariant":14,"./keyMirror":16}],20:[function(_dereq_,module){"use strict";function mergeInto(one,two){if(checkMergeIntoObjectArg(one),null!=two){checkMergeObjectArg(two);for(var key in two)two.hasOwnProperty(key)&&(one[key]=two[key])}}var mergeHelpers=_dereq_("./mergeHelpers"),checkMergeObjectArg=mergeHelpers.checkMergeObjectArg,checkMergeIntoObjectArg=mergeHelpers.checkMergeIntoObjectArg;module.exports=mergeInto},{"./mergeHelpers":19}],21:[function(_dereq_,module){"use strict";var emptyFunction=_dereq_("./emptyFunction"),warning=emptyFunction;module.exports=warning},{"./emptyFunction":13}]},{},[7])(7)}); |
@@ -9,2 +9,3 @@ /** @jsx React.DOM */ | ||
var MenuOption = require('./MenuOption'); | ||
var uuid = require('../helpers/uuid'); | ||
var injectCSS = require('../helpers/injectCSS'); | ||
@@ -23,6 +24,21 @@ var buildClassName = require('../mixins/buildClassName'); | ||
childContextTypes: { | ||
id: React.PropTypes.string, | ||
active: React.PropTypes.bool | ||
}, | ||
getChildContext: function () { | ||
return { | ||
id: this.state.id, | ||
active: this.state.active | ||
}; | ||
}, | ||
getInitialState: function(){ | ||
return { | ||
id: uuid(), | ||
active: false, | ||
selectedIndex: 0 | ||
selectedIndex: 0, | ||
horizontalPlacement: 'right', // only 'right' || 'left' | ||
verticalPlacement: 'bottom' // only 'top' || 'bottom' | ||
}; | ||
@@ -49,11 +65,29 @@ }, | ||
handleTriggerToggle: function() { | ||
this.setState({active: !this.state.active}, this.attemptOptionsFocus); | ||
this.setState({active: !this.state.active}, this.afterTriggerToggle); | ||
}, | ||
attemptOptionsFocus: function() { | ||
if (this.state.active){ | ||
afterTriggerToggle: function() { | ||
if (this.state.active) { | ||
this.refs.options.focusOption(0); | ||
this.updatePositioning(); | ||
} | ||
}, | ||
updatePositioning: function() { | ||
var triggerRect = this.refs.trigger.getDOMNode().getBoundingClientRect(); | ||
var optionsRect = this.refs.options.getDOMNode().getBoundingClientRect(); | ||
positionState = {}; | ||
// horizontal = left if it wont fit on left side | ||
if (triggerRect.left + optionsRect.width > window.innerWidth) { | ||
positionState.horizontalPlacement = 'left'; | ||
} else { | ||
positionState.horizontalPlacement = 'right'; | ||
} | ||
if (triggerRect.top + optionsRect.height > window.innerHeight) { | ||
positionState.verticalPlacement = 'top'; | ||
} else { | ||
positionState.verticalPlacement = 'bottom'; | ||
} | ||
this.setState(positionState); | ||
}, | ||
@@ -79,4 +113,4 @@ handleKeys: function(e) { | ||
trigger = cloneWithProps(child, { | ||
onToggleActive: this.handleTriggerToggle, | ||
ref: 'trigger' | ||
ref: 'trigger', | ||
onToggleActive: this.handleTriggerToggle | ||
}); | ||
@@ -90,5 +124,2 @@ } | ||
renderMenuOptions: function() { | ||
if (!this.state.active) { | ||
return null; | ||
} | ||
var options; | ||
@@ -100,2 +131,4 @@ if(this.verifyTwoChildren()) { | ||
ref: 'options', | ||
horizontalPlacement: this.state.horizontalPlacement, | ||
verticalPlacement: this.state.verticalPlacement, | ||
onSelectionMade: this.closeMenu | ||
@@ -114,3 +147,2 @@ }); | ||
className={this.buildClassName('Menu')} | ||
role='menu' | ||
onKeyDown={this.handleKeys} | ||
@@ -117,0 +149,0 @@ onBlur={this.handleBlur} |
@@ -74,4 +74,5 @@ /** @jsx React.DOM */ | ||
className={this.buildName()} | ||
role='menuitem' | ||
tabIndex='-1' | ||
role="menuitem" | ||
tabIndex="-1" | ||
aria-disabled={this.props.disabled} | ||
> | ||
@@ -78,0 +79,0 @@ {this.props.children} |
@@ -10,2 +10,7 @@ /** @jsx React.DOM */ | ||
contextTypes: { | ||
id: React.PropTypes.string, | ||
active: React.PropTypes.bool | ||
}, | ||
getInitialState: function() { | ||
@@ -56,12 +61,7 @@ return {activeIndex: 0} | ||
updateFocusIndexBy: function(delta) { | ||
// open menu if it's closed, and retry focus | ||
if (!this.state.active) { | ||
this.selectedIndex = 0; | ||
this.setState({active: true}, this.updateFocusIndexBy.bind(this, 0)); | ||
return | ||
} | ||
var optionNodes = this.getDOMNode().querySelectorAll('.Menu__MenuOption'); | ||
this.normalizeSelectedBy(delta, optionNodes.length); | ||
this.setState({activeIndex: this.selectedIndex}); | ||
optionNodes[this.selectedIndex].focus(); | ||
this.setState({activeIndex: this.selectedIndex}, function () { | ||
optionNodes[this.selectedIndex].focus(); | ||
}); | ||
}, | ||
@@ -87,7 +87,19 @@ | ||
buildName: function() { | ||
var cn = this.buildClassName('Menu__MenuOptions'); | ||
cn += ' Menu__MenuOptions--horizontal-' + this.props.horizontalPlacement; | ||
cn += ' Menu__MenuOptions--vertical-' + this.props.verticalPlacement; | ||
return cn; | ||
}, | ||
render: function() { | ||
return ( | ||
<div | ||
className={this.buildClassName('Menu__MenuOptions')} | ||
onKeyUp={this.handleKeys} | ||
id={this.context.id} | ||
role="menu" | ||
tabIndex="-1" | ||
aria-expanded={this.context.active} | ||
style={{visibility: this.context.active ? 'visible' : 'hidden'}} | ||
className={this.buildName()} | ||
onKeyDown={this.handleKeys} | ||
> | ||
@@ -94,0 +106,0 @@ {this.renderOptions()} |
@@ -8,6 +8,5 @@ /** @jsx React.DOM */ | ||
getInitialState: function() { | ||
return { | ||
active: false | ||
}; | ||
contextTypes: { | ||
id: React.PropTypes.string, | ||
active: React.PropTypes.bool | ||
}, | ||
@@ -17,11 +16,4 @@ | ||
notifyParent: function() { | ||
if (this.props.onToggleActive) | ||
this.props.onToggleActive(this.state.active); | ||
}, | ||
toggleActive: function() { | ||
this.setState({ | ||
active: !this.state.active | ||
}, this.notifyParent); | ||
this.props.onToggleActive(!this.context.active); | ||
}, | ||
@@ -52,3 +44,6 @@ | ||
onKeyDown={this.handleKeyDown} | ||
tabIndex='0' | ||
tabIndex="0" | ||
role="button" | ||
aria-owns={this.context.id} | ||
aria-haspopup="true" | ||
> | ||
@@ -55,0 +50,0 @@ {this.props.children} |
@@ -34,4 +34,15 @@ var jss = require('js-stylesheet'); | ||
background: '#FFF' | ||
}, | ||
'.Menu__MenuOptions--horizontal-left': { | ||
right: '0px' | ||
}, | ||
'.Menu__MenuOptions--horizontal-right': { | ||
left: '0px' | ||
}, | ||
'.Menu__MenuOptions--vertical-top': { | ||
bottom: '45px' | ||
}, | ||
'.Menu__MenuOptions--vertical-bottom': { | ||
} | ||
}); | ||
}; |
{ | ||
"name": "react-menu", | ||
"version": "0.0.4", | ||
"version": "0.0.5", | ||
"description": "Accessible menu component for React.JS", | ||
@@ -16,3 +16,4 @@ "main": "./lib/index", | ||
"scripts": { | ||
"test": "script/test --browsers Firefox --single-run" | ||
"test": "scripts/test --browsers Firefox --single-run", | ||
"start": "scripts/dev-examples" | ||
}, | ||
@@ -28,2 +29,3 @@ "authors": [ | ||
"expect": "0.1.1", | ||
"jsx-loader": "0.11.2", | ||
"karma": "0.12.16", | ||
@@ -37,7 +39,6 @@ "karma-browserify": "^0.2.1", | ||
"react": ">=0.11.0", | ||
"react-tap-event-plugin": "git://github.com/appsforartists/react-tap-event-plugin", | ||
"reactify": "^0.14.0", | ||
"rf-release": "0.3.1", | ||
"uglify-js": "2.4.15", | ||
"fsmonitor": "^0.2.4" | ||
"webpack-dev-server": "1.6.5" | ||
}, | ||
@@ -44,0 +45,0 @@ "peerDependencies": { |
@@ -67,3 +67,4 @@ # react-menu | ||
Default styles will be added to the top of the head, and thus any styles you write will override any of the defaults. | ||
Default styles will be added to the top of the head, and thus any styles you | ||
write will override any of the defaults. | ||
@@ -77,2 +78,11 @@ The following class names are used / available for modification in your own stylsheets: | ||
.Menu__MenuOption | ||
.Menu__MenuOptions--vertical-bottom | ||
.Menu__MenuOptions--vertical-top | ||
.Menu__MenuOptions--horizontal-right | ||
.Menu__MenuOptions--horizontal-left | ||
``` | ||
The last four class names control the placement of menu options when the menu | ||
would otherwise bleed off the screen. See `/lib/helpers/injectCSS.js` for | ||
defaults. The `.Menu__MenuOptions` element will always have a vertical and | ||
horizontal modifier. |
Filesystem access
Supply chain riskAccesses the file system, and could potentially read sensitive data.
Found 1 instance in 1 package
73154
22
1619
87
5