diff --git a/bower.json b/bower.json index 4f2a165..fa2918c 100644 --- a/bower.json +++ b/bower.json @@ -6,7 +6,7 @@ "Jason Madsen" ], "description": "Accessible menu component for React.JS", - "main": "dist/react-menu.js", + "main": "dist/umd/react-menu.js", "keywords": [ "react", "menu", @@ -25,4 +25,4 @@ "karma.conf.js", "package.json" ] -} \ No newline at end of file +} diff --git a/dist/lib/components/Menu.js b/dist/lib/components/Menu.js new file mode 100644 index 0000000..88f914a --- /dev/null +++ b/dist/lib/components/Menu.js @@ -0,0 +1,150 @@ +/** @jsx React.DOM */ + +var React = require('react'); + +var cloneWithProps = require('react/lib/cloneWithProps'); +var MenuTrigger = require('./MenuTrigger'); +var MenuOptions = require('./MenuOptions'); +var MenuOption = require('./MenuOption'); +var uuid = require('../helpers/uuid'); +var injectCSS = require('../helpers/injectCSS'); +var buildClassName = require('../mixins/buildClassName'); + +var Menu = 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: false, + selectedIndex: 0, + horizontalPlacement: 'right', // only 'right' || 'left' + verticalPlacement: 'bottom' // only 'top' || 'bottom' + }; + }, + + closeMenu: function() { + this.setState({active: false}, this.focusTrigger); + }, + + focusTrigger: function() { + this.refs.trigger.getDOMNode().focus(); + }, + + handleBlur: function(e) { + // give next element a tick to take focus + setTimeout(function() { + if (!this.getDOMNode().contains(document.activeElement) && this.state.active){ + this.closeMenu(); + } + }.bind(this), 1); + }, + + handleTriggerToggle: function() { + this.setState({active: !this.state.active}, this.afterTriggerToggle); + }, + + 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(); + var 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); + }, + + handleKeys: function(e) { + if (e.key === 'Escape') { + this.closeMenu(); + } + }, + + verifyTwoChildren: function() { + var ok = (React.Children.count(this.props.children) === 2); + if (!ok) + throw 'react-menu can only take two children, a MenuTrigger, and a MenuOptions'; + return ok; + }, + + renderTrigger: function() { + var trigger; + if(this.verifyTwoChildren()) { + React.Children.forEach(this.props.children, function(child){ + if (child.type === MenuTrigger.type) { + trigger = cloneWithProps(child, { + ref: 'trigger', + onToggleActive: this.handleTriggerToggle + }); + } + }.bind(this)); + } + return trigger; + }, + + renderMenuOptions: function() { + var options; + if(this.verifyTwoChildren()) { + React.Children.forEach(this.props.children, function(child){ + if (child.type === MenuOptions.type) { + options = cloneWithProps(child, { + ref: 'options', + horizontalPlacement: this.state.horizontalPlacement, + verticalPlacement: this.state.verticalPlacement, + onSelectionMade: this.closeMenu + }); + } + }.bind(this)); + } + return options; + }, + + + render: function() { + return ( + React.DOM.div({ + className: this.buildClassName('Menu'), + onKeyDown: this.handleKeys, + onBlur: this.handleBlur + }, + this.renderTrigger(), + this.renderMenuOptions() + ) + ) + } + +}); diff --git a/dist/lib/components/MenuOption.js b/dist/lib/components/MenuOption.js new file mode 100644 index 0000000..5f23bbe --- /dev/null +++ b/dist/lib/components/MenuOption.js @@ -0,0 +1,83 @@ +/** @jsx React.DOM */ + +var React = require('react'); +var buildClassName = require('../mixins/buildClassName'); + +var MenuOption = 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() { + if (this.props.onDisabledSelect) { + this.props.onDisabledSelect(); + } + }, + + onSelect: function() { + if (this.props.disabled) { + this.notifyDisabledSelect(); + //early return if disabled + return; + } + if (this.props.onSelect) { + this.props.onSelect(); + } + this.props._internalSelect(); + }, + + handleKeyUp: function(e) { + if (e.key === ' ') { + this.onSelect(); + } + }, + + handleKeyDown: function(e) { + if (e.key === 'Enter') { + this.onSelect(); + } + }, + + handleClick: function() { + this.onSelect(); + }, + + handleHover: function() { + this.props._internalFocus(this.props.index); + }, + + buildName: function() { + var name = this.buildClassName('Menu__MenuOption'); + if (this.props.active){ + name += ' Menu__MenuOption--active'; + } + if (this.props.disabled) { + name += ' Menu__MenuOption--disabled'; + } + return 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 + ) + ) + } + +}); diff --git a/dist/lib/components/MenuOptions.js b/dist/lib/components/MenuOptions.js new file mode 100644 index 0000000..706b386 --- /dev/null +++ b/dist/lib/components/MenuOptions.js @@ -0,0 +1,108 @@ +/** @jsx React.DOM */ + +var React = require('react'); +var MenuOption = require('./MenuOption'); +var cloneWithProps = require('react/lib/cloneWithProps') +var buildClassName = require('../mixins/buildClassName'); + +var MenuOptions = 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 + } + if(options[e.key]){ + options[e.key].call(this); + } + }, + + normalizeSelectedBy: function(delta, numOptions){ + this.selectedIndex += delta; + if (this.selectedIndex > numOptions - 1) { + this.selectedIndex = 0; + } else if (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'); + cn += ' Menu__MenuOptions--horizontal-' + this.props.horizontalPlacement; + cn += ' Menu__MenuOptions--vertical-' + this.props.verticalPlacement; + return cn; + }, + + 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() + ) + ) + } + +}); diff --git a/dist/lib/components/MenuTrigger.js b/dist/lib/components/MenuTrigger.js new file mode 100644 index 0000000..596a683 --- /dev/null +++ b/dist/lib/components/MenuTrigger.js @@ -0,0 +1,58 @@ +/** @jsx React.DOM */ + +var React = require('react'); +var buildClassName = require('../mixins/buildClassName'); + +var MenuTrigger = 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) { + if (e.key === ' ') + this.toggleActive(); + }, + + handleKeyDown: function(e) { + if (e.key === 'Enter') + this.toggleActive(); + }, + + handleClick: function() { + this.toggleActive(); + }, + + render: function() { + var triggerClassName = + this.buildClassName( + 'Menu__MenuTrigger ' + + (this.context.active + ? 'Menu__MenuTrigger__active' + : 'Menu__MenuTrigger__inactive') + ); + + return ( + React.DOM.div({ + className: triggerClassName, + onClick: this.handleClick, + onKeyUp: this.handleKeyUp, + onKeyDown: this.handleKeyDown, + tabIndex: "0", + role: "button", + 'aria-owns': this.context.id, + 'aria-haspopup': "true" + }, + this.props.children + ) + ) + } + +}); diff --git a/dist/lib/helpers/injectCSS.js b/dist/lib/helpers/injectCSS.js new file mode 100644 index 0000000..9a50be2 --- /dev/null +++ b/dist/lib/helpers/injectCSS.js @@ -0,0 +1,47 @@ +var jss = require('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': { + } + }); +}; diff --git a/dist/lib/helpers/uuid.js b/dist/lib/helpers/uuid.js new file mode 100644 index 0000000..a368657 --- /dev/null +++ b/dist/lib/helpers/uuid.js @@ -0,0 +1,4 @@ +var count = 0; +module.exports = function () { + return 'react-menu-' + count++; +}; diff --git a/dist/lib/index.js b/dist/lib/index.js new file mode 100644 index 0000000..090e3ea --- /dev/null +++ b/dist/lib/index.js @@ -0,0 +1,6 @@ +var Menu = require('./components/Menu'); +Menu.MenuTrigger = require('./components/MenuTrigger'); +Menu.MenuOptions = require('./components/MenuOptions'); +Menu.MenuOption = require('./components/MenuOption'); + +module.exports = Menu; diff --git a/dist/lib/mixins/buildClassName.js b/dist/lib/mixins/buildClassName.js new file mode 100644 index 0000000..f117033 --- /dev/null +++ b/dist/lib/mixins/buildClassName.js @@ -0,0 +1,10 @@ +module.exports = { + + buildClassName: function(baseName) { + var name = baseName; + if (this.props.className) { + name += ' ' + this.props.className; + } + return name; + }, +}; diff --git a/dist/package.json b/dist/package.json new file mode 100644 index 0000000..08e0ecc --- /dev/null +++ b/dist/package.json @@ -0,0 +1,44 @@ +{ + "name": "react-menu", + "version": "0.0.7", + "description": "Accessible menu component for React.JS", + "main": "dist/lib/index.js", + "repository": { + "type": "git", + "url": "https://github.com/instructure-react/react-menu.git" + }, + "homepage": "https://github.com/instructure-react/react-menu", + "bugs": "https://github.com/instructure-react/react-menu/issues", + "directories": { + "example": "examples" + }, + "authors": [ + "Jason Madsen" + ], + "license": "MIT", + "peerDependencies": { + "react": "^0.13.0" + }, + "tags": [ + "react", + "menu", + "dropdown" + ], + "keywords": [ + "react", + "react-component", + "menu", + "dropdown" + ], + "browserify-shim": { + "react": "global:React" + }, + "browserify": { + "transform": [ + "reactify" + ] + }, + "dependencies": { + "js-stylesheet": "0.0.1" + } +} diff --git a/dist/react-menu.js b/dist/umd/react-menu.js similarity index 87% rename from dist/react-menu.js rename to dist/umd/react-menu.js index b38e85e..8ad1595 100644 --- a/dist/react-menu.js +++ b/dist/umd/react-menu.js @@ -522,7 +522,7 @@ module.exports = { },{}],10:[function(_dereq_,module,exports){ /** - * Copyright 2014, Facebook, Inc. + * Copyright 2014-2015, Facebook, Inc. * All rights reserved. * * This source code is licensed under the BSD-style license found in the @@ -534,6 +534,8 @@ module.exports = { // https://people.mozilla.org/~jorendorff/es6-draft.html#sec-object.assign +'use strict'; + function assign(target, sources) { if (target == null) { throw new TypeError('Object.assign target cannot be null or undefined'); @@ -563,13 +565,13 @@ function assign(target, sources) { } return to; -}; +} module.exports = assign; },{}],11:[function(_dereq_,module,exports){ /** - * Copyright 2013-2014, Facebook, Inc. + * Copyright 2013-2015, Facebook, Inc. * All rights reserved. * * This source code is licensed under the BSD-style license found in the @@ -579,9 +581,13 @@ module.exports = assign; * @providesModule ReactContext */ -"use strict"; +'use strict'; var assign = _dereq_("./Object.assign"); +var emptyObject = _dereq_("./emptyObject"); +var warning = _dereq_("./warning"); + +var didWarn = false; /** * Keeps track of the current context. @@ -595,7 +601,7 @@ var ReactContext = { * @internal * @type {object} */ - current: {}, + current: emptyObject, /** * Temporarily extends the current context while executing scopedCallback. @@ -614,6 +620,16 @@ var ReactContext = { * @return {ReactComponent|array} */ withContext: function(newContext, scopedCallback) { + if ("production" !== "production") { + ("production" !== "production" ? warning( + didWarn, + 'withContext is deprecated and will be removed in a future version. ' + + 'Use a wrapper component with getChildContext instead.' + ) : null); + + didWarn = true; + } + var result; var previousContext = ReactContext.current; ReactContext.current = assign({}, previousContext, newContext); @@ -629,9 +645,9 @@ var ReactContext = { module.exports = ReactContext; -},{"./Object.assign":10}],12:[function(_dereq_,module,exports){ +},{"./Object.assign":10,"./emptyObject":17,"./warning":20}],12:[function(_dereq_,module,exports){ /** - * Copyright 2013-2014, Facebook, Inc. + * Copyright 2013-2015, Facebook, Inc. * All rights reserved. * * This source code is licensed under the BSD-style license found in the @@ -641,7 +657,7 @@ module.exports = ReactContext; * @providesModule ReactCurrentOwner */ -"use strict"; +'use strict'; /** * Keeps track of the current owner. @@ -665,7 +681,7 @@ module.exports = ReactCurrentOwner; },{}],13:[function(_dereq_,module,exports){ /** - * Copyright 2014, Facebook, Inc. + * Copyright 2014-2015, Facebook, Inc. * All rights reserved. * * This source code is licensed under the BSD-style license found in the @@ -675,11 +691,12 @@ module.exports = ReactCurrentOwner; * @providesModule ReactElement */ -"use strict"; +'use strict'; var ReactContext = _dereq_("./ReactContext"); var ReactCurrentOwner = _dereq_("./ReactCurrentOwner"); +var assign = _dereq_("./Object.assign"); var warning = _dereq_("./warning"); var RESERVED_PROPS = { @@ -710,8 +727,9 @@ function defineWarningProperty(object, key) { set: function(value) { ("production" !== "production" ? warning( false, - 'Don\'t set the ' + key + ' property of the component. ' + - 'Mutate the existing props object instead.' + 'Don\'t set the %s property of the React element. Instead, ' + + 'specify the correct value when initially creating the element.', + key ) : null); this._store[key] = value; } @@ -772,7 +790,21 @@ var ReactElement = function(type, key, ref, owner, context, props) { // an external backing store so that we can freeze the whole object. // This can be replaced with a WeakMap once they are implemented in // commonly used development environments. - this._store = { validated: false, props: props }; + this._store = {props: props, originalProps: assign({}, props)}; + + // To make comparing ReactElements easier for testing purposes, we make + // the validation flag non-enumerable (where possible, which should + // include every environment we run tests in), so the test framework + // ignores it. + try { + Object.defineProperty(this._store, 'validated', { + configurable: false, + enumerable: false, + writable: true + }); + } catch (x) { + } + this._store.validated = false; // We're not allowed to set props directly on the object so we early // return and rely on the prototype membrane to forward to the backing @@ -807,16 +839,7 @@ ReactElement.createElement = function(type, config, children) { if (config != null) { ref = config.ref === undefined ? null : config.ref; - if ("production" !== "production") { - ("production" !== "production" ? warning( - config.key !== null, - 'createElement(...): Encountered component with a `key` of null. In ' + - 'a future version, this will be treated as equivalent to the string ' + - '\'null\'; instead, provide an explicit key or use undefined.' - ) : null); - } - // TODO: Change this back to `config.key === undefined` - key = config.key == null ? null : '' + config.key; + key = config.key === undefined ? null : '' + config.key; // Remaining properties are added to a new props object for (propName in config) { if (config.hasOwnProperty(propName) && @@ -865,6 +888,7 @@ ReactElement.createFactory = function(type) { // easily accessed on elements. E.g. .type === Foo.type. // This should not be named `constructor` since this may not be the function // that created the element, and it may not even be a constructor. + // Legacy hook TODO: Warn if this is accessed factory.type = type; return factory; }; @@ -886,6 +910,60 @@ ReactElement.cloneAndReplaceProps = function(oldElement, newProps) { return newElement; }; +ReactElement.cloneElement = function(element, config, children) { + var propName; + + // Original props are copied + var props = assign({}, element.props); + + // Reserved names are extracted + var key = element.key; + var ref = element.ref; + + // Owner will be preserved, unless ref is overridden + var owner = element._owner; + + if (config != null) { + if (config.ref !== undefined) { + // Silently steal the ref from the parent. + ref = config.ref; + owner = ReactCurrentOwner.current; + } + if (config.key !== undefined) { + key = '' + config.key; + } + // Remaining properties override existing props + for (propName in config) { + if (config.hasOwnProperty(propName) && + !RESERVED_PROPS.hasOwnProperty(propName)) { + props[propName] = config[propName]; + } + } + } + + // Children can be more than one argument, and those are transferred onto + // the newly allocated props object. + var childrenLength = arguments.length - 2; + if (childrenLength === 1) { + props.children = children; + } else if (childrenLength > 1) { + var childArray = Array(childrenLength); + for (var i = 0; i < childrenLength; i++) { + childArray[i] = arguments[i + 2]; + } + props.children = childArray; + } + + return new ReactElement( + element.type, + key, + ref, + owner, + element._context, + props + ); +}; + /** * @param {?object} object * @return {boolean} True if `object` is a valid component. @@ -907,9 +985,9 @@ ReactElement.isValidElement = function(object) { module.exports = ReactElement; -},{"./ReactContext":11,"./ReactCurrentOwner":12,"./warning":20}],14:[function(_dereq_,module,exports){ +},{"./Object.assign":10,"./ReactContext":11,"./ReactCurrentOwner":12,"./warning":20}],14:[function(_dereq_,module,exports){ /** - * Copyright 2013-2014, Facebook, Inc. + * Copyright 2013-2015, Facebook, Inc. * All rights reserved. * * This source code is licensed under the BSD-style license found in the @@ -919,15 +997,11 @@ module.exports = ReactElement; * @providesModule ReactPropTransferer */ -"use strict"; +'use strict'; var assign = _dereq_("./Object.assign"); var emptyFunction = _dereq_("./emptyFunction"); -var invariant = _dereq_("./invariant"); var joinClasses = _dereq_("./joinClasses"); -var warning = _dereq_("./warning"); - -var didWarn = false; /** * Creates a transfer strategy that will merge prop values using the supplied @@ -1006,8 +1080,6 @@ function transferInto(props, newProps) { */ var ReactPropTransferer = { - TransferStrategies: TransferStrategies, - /** * Merge two props objects using TransferStrategies. * @@ -1017,75 +1089,26 @@ var ReactPropTransferer = { */ mergeProps: function(oldProps, newProps) { return transferInto(assign({}, oldProps), newProps); - }, - - /** - * @lends {ReactPropTransferer.prototype} - */ - Mixin: { - - /** - * Transfer props from this component to a target component. - * - * Props that do not have an explicit transfer strategy will be transferred - * only if the target component does not already have the prop set. - * - * This is usually used to pass down props to a returned root component. - * - * @param {ReactElement} element Component receiving the properties. - * @return {ReactElement} The supplied `component`. - * @final - * @protected - */ - transferPropsTo: function(element) { - ("production" !== "production" ? invariant( - element._owner === this, - '%s: You can\'t call transferPropsTo() on a component that you ' + - 'don\'t own, %s. This usually means you are calling ' + - 'transferPropsTo() on a component passed in as props or children.', - this.constructor.displayName, - typeof element.type === 'string' ? - element.type : - element.type.displayName - ) : invariant(element._owner === this)); - - if ("production" !== "production") { - if (!didWarn) { - didWarn = true; - ("production" !== "production" ? warning( - false, - 'transferPropsTo is deprecated. ' + - 'See http://fb.me/react-transferpropsto for more information.' - ) : null); - } - } - - // Because elements are immutable we have to merge into the existing - // props object rather than clone it. - transferInto(element.props, this.props); - - return element; - } - } + }; module.exports = ReactPropTransferer; -},{"./Object.assign":10,"./emptyFunction":16,"./invariant":17,"./joinClasses":18,"./warning":20}],15:[function(_dereq_,module,exports){ +},{"./Object.assign":10,"./emptyFunction":16,"./joinClasses":18}],15:[function(_dereq_,module,exports){ /** - * Copyright 2013-2014, Facebook, Inc. + * Copyright 2013-2015, Facebook, Inc. * All rights reserved. * * This source code is licensed under the BSD-style license found in the * LICENSE file in the root directory of this source tree. An additional grant * of patent rights can be found in the PATENTS file in the same directory. * - * @typechecks + * @typechecks static-only * @providesModule cloneWithProps */ -"use strict"; +'use strict'; var ReactElement = _dereq_("./ReactElement"); var ReactPropTransferer = _dereq_("./ReactPropTransferer"); @@ -1099,10 +1122,10 @@ var CHILDREN_PROP = keyOf({children: null}); * Sometimes you want to change the props of a child passed to you. Usually * this is to add a CSS class. * - * @param {object} child child component you'd like to clone - * @param {object} props props you'd like to modify. They will be merged - * as if you used `transferPropsTo()`. - * @return {object} a clone of child with props merged in. + * @param {ReactElement} child child element you'd like to clone + * @param {object} props props you'd like to modify. className and style will be + * merged automatically. + * @return {ReactElement} a clone of child with props merged in. */ function cloneWithProps(child, props) { if ("production" !== "production") { @@ -1131,7 +1154,7 @@ module.exports = cloneWithProps; },{"./ReactElement":13,"./ReactPropTransferer":14,"./keyOf":19,"./warning":20}],16:[function(_dereq_,module,exports){ /** - * Copyright 2013-2014, Facebook, Inc. + * Copyright 2013-2015, Facebook, Inc. * All rights reserved. * * This source code is licensed under the BSD-style license found in the @@ -1165,62 +1188,29 @@ module.exports = emptyFunction; },{}],17:[function(_dereq_,module,exports){ /** - * Copyright 2013-2014, Facebook, Inc. + * Copyright 2013-2015, Facebook, Inc. * All rights reserved. * * This source code is licensed under the BSD-style license found in the * LICENSE file in the root directory of this source tree. An additional grant * of patent rights can be found in the PATENTS file in the same directory. * - * @providesModule invariant + * @providesModule emptyObject */ "use strict"; -/** - * Use invariant() to assert state which your program assumes to be true. - * - * Provide sprintf-style format (only %s is supported) and arguments - * to provide information about what broke and what you were - * expecting. - * - * The invariant message will be stripped in production, but the invariant - * will remain to ensure logic does not differ in production. - */ - -var invariant = function(condition, format, a, b, c, d, e, f) { - if ("production" !== "production") { - if (format === undefined) { - throw new Error('invariant requires an error message argument'); - } - } - - if (!condition) { - var error; - if (format === undefined) { - 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]; - var argIndex = 0; - error = new Error( - 'Invariant Violation: ' + - format.replace(/%s/g, function() { return args[argIndex++]; }) - ); - } +var emptyObject = {}; - error.framesToPop = 1; // we don't care about invariant's own frame - throw error; - } -}; +if ("production" !== "production") { + Object.freeze(emptyObject); +} -module.exports = invariant; +module.exports = emptyObject; },{}],18:[function(_dereq_,module,exports){ /** - * Copyright 2013-2014, Facebook, Inc. + * Copyright 2013-2015, Facebook, Inc. * All rights reserved. * * This source code is licensed under the BSD-style license found in the @@ -1231,7 +1221,7 @@ module.exports = invariant; * @typechecks static-only */ -"use strict"; +'use strict'; /** * Combines multiple className strings into one. @@ -1261,7 +1251,7 @@ module.exports = joinClasses; },{}],19:[function(_dereq_,module,exports){ /** - * Copyright 2013-2014, Facebook, Inc. + * Copyright 2013-2015, Facebook, Inc. * All rights reserved. * * This source code is licensed under the BSD-style license found in the @@ -1297,7 +1287,7 @@ module.exports = keyOf; },{}],20:[function(_dereq_,module,exports){ /** - * Copyright 2014, Facebook, Inc. + * Copyright 2014-2015, Facebook, Inc. * All rights reserved. * * This source code is licensed under the BSD-style license found in the @@ -1329,9 +1319,27 @@ if ("production" !== "production") { ); } + if (format.length < 10 || /^[s\W]*$/.test(format)) { + throw new Error( + 'The warning format should be able to uniquely identify this ' + + 'warning. Please, use a more descriptive format than: ' + format + ); + } + + if (format.indexOf('Failed Composite propType: ') === 0) { + return; // Ignore CompositeComponent proptype check. + } + if (!condition) { var argIndex = 0; - console.warn('Warning: ' + format.replace(/%s/g, function() {return args[argIndex++];})); + var message = 'Warning: ' + format.replace(/%s/g, function() {return args[argIndex++];}); + console.warn(message); + try { + // --- Welcome to debugging React --- + // This error was thrown as a convenience so that you can use this stack + // to find the callsite that caused this warning to fire. + throw new Error(message); + } catch(x) {} } }; } diff --git a/dist/react-menu.min.js b/dist/umd/react-menu.min.js similarity index 61% rename from dist/react-menu.min.js rename to dist/umd/react-menu.min.js index 1937946..f2005b1 100644 --- a/dist/react-menu.min.js +++ b/dist/umd/react-menu.min.js @@ -1 +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;owindow.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":15}],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":15}],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){" "===e.key&&this.toggleActive()},handleKeyDown:function(e){"Enter"===e.key&&this.toggleActive()},handleClick:function(){this.toggleActive()},render:function(){var triggerClassName=this.buildClassName("Menu__MenuTrigger "+(this.context.active?"Menu__MenuTrigger__active":"Menu__MenuTrigger__inactive"));return React.DOM.div({className:triggerClassName,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){function assign(target){if(null==target)throw new TypeError("Object.assign target cannot be null or undefined");for(var to=Object(target),hasOwnProperty=Object.prototype.hasOwnProperty,nextIndex=1;nextIndex1){for(var childArray=Array(childrenLength),i=0;childrenLength>i;i++)childArray[i]=arguments[i+2];props.children=childArray}if(type&&type.defaultProps){var defaultProps=type.defaultProps;for(propName in defaultProps)"undefined"==typeof props[propName]&&(props[propName]=defaultProps[propName])}return new ReactElement(type,key,ref,ReactCurrentOwner.current,ReactContext.current,props)},ReactElement.createFactory=function(type){var factory=ReactElement.createElement.bind(null,type);return factory.type=type,factory},ReactElement.cloneAndReplaceProps=function(oldElement,newProps){var newElement=new ReactElement(oldElement.type,oldElement.key,oldElement.ref,oldElement._owner,oldElement._context,newProps);return newElement},ReactElement.isValidElement=function(object){var isElement=!(!object||!object._isReactElement);return isElement},module.exports=ReactElement},{"./ReactContext":11,"./ReactCurrentOwner":12,"./warning":20}],14:[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 assign=_dereq_("./Object.assign"),emptyFunction=_dereq_("./emptyFunction"),invariant=_dereq_("./invariant"),joinClasses=_dereq_("./joinClasses"),transferStrategyMerge=(_dereq_("./warning"),createTransferStrategy(function(a,b){return assign({},b,a)})),TransferStrategies={children:emptyFunction,className:createTransferStrategy(joinClasses),style:transferStrategyMerge},ReactPropTransferer={TransferStrategies:TransferStrategies,mergeProps:function(oldProps,newProps){return transferInto(assign({},oldProps),newProps)},Mixin:{transferPropsTo:function(element){return invariant(element._owner===this),transferInto(element.props,this.props),element}}};module.exports=ReactPropTransferer},{"./Object.assign":10,"./emptyFunction":16,"./invariant":17,"./joinClasses":18,"./warning":20}],15:[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),ReactElement.createElement(child.type,newProps)}var ReactElement=_dereq_("./ReactElement"),ReactPropTransferer=_dereq_("./ReactPropTransferer"),keyOf=_dereq_("./keyOf"),CHILDREN_PROP=(_dereq_("./warning"),keyOf({children:null}));module.exports=cloneWithProps},{"./ReactElement":13,"./ReactPropTransferer":14,"./keyOf":19,"./warning":20}],16:[function(_dereq_,module){function makeEmptyFunction(arg){return function(){return arg}}function emptyFunction(){}emptyFunction.thatReturns=makeEmptyFunction,emptyFunction.thatReturnsFalse=makeEmptyFunction(!1),emptyFunction.thatReturnsTrue=makeEmptyFunction(!0),emptyFunction.thatReturnsNull=makeEmptyFunction(null),emptyFunction.thatReturnsThis=function(){return this},emptyFunction.thatReturnsArgument=function(arg){return arg},module.exports=emptyFunction},{}],17:[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},{}],18:[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=(className?className+" ":"")+nextClass);return className}module.exports=joinClasses},{}],19:[function(_dereq_,module){var keyOf=function(oneKeyObj){var key;for(key in oneKeyObj)if(oneKeyObj.hasOwnProperty(key))return key;return null};module.exports=keyOf},{}],20:[function(_dereq_,module){"use strict";var emptyFunction=_dereq_("./emptyFunction"),warning=emptyFunction;module.exports=warning},{"./emptyFunction":16}]},{},[7])(7)}); \ No newline at end of file +!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;owindow.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":15}],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":15}],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){" "===e.key&&this.toggleActive()},handleKeyDown:function(e){"Enter"===e.key&&this.toggleActive()},handleClick:function(){this.toggleActive()},render:function(){var triggerClassName=this.buildClassName("Menu__MenuTrigger "+(this.context.active?"Menu__MenuTrigger__active":"Menu__MenuTrigger__inactive"));return React.DOM.div({className:triggerClassName,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 assign(target){if(null==target)throw new TypeError("Object.assign target cannot be null or undefined");for(var to=Object(target),hasOwnProperty=Object.prototype.hasOwnProperty,nextIndex=1;nextIndex1){for(var childArray=Array(childrenLength),i=0;childrenLength>i;i++)childArray[i]=arguments[i+2];props.children=childArray}if(type&&type.defaultProps){var defaultProps=type.defaultProps;for(propName in defaultProps)"undefined"==typeof props[propName]&&(props[propName]=defaultProps[propName])}return new ReactElement(type,key,ref,ReactCurrentOwner.current,ReactContext.current,props)},ReactElement.createFactory=function(type){var factory=ReactElement.createElement.bind(null,type);return factory.type=type,factory},ReactElement.cloneAndReplaceProps=function(oldElement,newProps){var newElement=new ReactElement(oldElement.type,oldElement.key,oldElement.ref,oldElement._owner,oldElement._context,newProps);return newElement},ReactElement.cloneElement=function(element,config,children){var propName,props=assign({},element.props),key=element.key,ref=element.ref,owner=element._owner;if(null!=config){void 0!==config.ref&&(ref=config.ref,owner=ReactCurrentOwner.current),void 0!==config.key&&(key=""+config.key);for(propName in config)config.hasOwnProperty(propName)&&!RESERVED_PROPS.hasOwnProperty(propName)&&(props[propName]=config[propName])}var childrenLength=arguments.length-2;if(1===childrenLength)props.children=children;else if(childrenLength>1){for(var childArray=Array(childrenLength),i=0;childrenLength>i;i++)childArray[i]=arguments[i+2];props.children=childArray}return new ReactElement(element.type,key,ref,owner,element._context,props)},ReactElement.isValidElement=function(object){var isElement=!(!object||!object._isReactElement);return isElement},module.exports=ReactElement},{"./Object.assign":10,"./ReactContext":11,"./ReactCurrentOwner":12,"./warning":20}],14:[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 assign=_dereq_("./Object.assign"),emptyFunction=_dereq_("./emptyFunction"),joinClasses=_dereq_("./joinClasses"),transferStrategyMerge=createTransferStrategy(function(a,b){return assign({},b,a)}),TransferStrategies={children:emptyFunction,className:createTransferStrategy(joinClasses),style:transferStrategyMerge},ReactPropTransferer={mergeProps:function(oldProps,newProps){return transferInto(assign({},oldProps),newProps)}};module.exports=ReactPropTransferer},{"./Object.assign":10,"./emptyFunction":16,"./joinClasses":18}],15:[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),ReactElement.createElement(child.type,newProps)}var ReactElement=_dereq_("./ReactElement"),ReactPropTransferer=_dereq_("./ReactPropTransferer"),keyOf=_dereq_("./keyOf"),CHILDREN_PROP=(_dereq_("./warning"),keyOf({children:null}));module.exports=cloneWithProps},{"./ReactElement":13,"./ReactPropTransferer":14,"./keyOf":19,"./warning":20}],16:[function(_dereq_,module){function makeEmptyFunction(arg){return function(){return arg}}function emptyFunction(){}emptyFunction.thatReturns=makeEmptyFunction,emptyFunction.thatReturnsFalse=makeEmptyFunction(!1),emptyFunction.thatReturnsTrue=makeEmptyFunction(!0),emptyFunction.thatReturnsNull=makeEmptyFunction(null),emptyFunction.thatReturnsThis=function(){return this},emptyFunction.thatReturnsArgument=function(arg){return arg},module.exports=emptyFunction},{}],17:[function(_dereq_,module){"use strict";var emptyObject={};module.exports=emptyObject},{}],18:[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=(className?className+" ":"")+nextClass);return className}module.exports=joinClasses},{}],19:[function(_dereq_,module){var keyOf=function(oneKeyObj){var key;for(key in oneKeyObj)if(oneKeyObj.hasOwnProperty(key))return key;return null};module.exports=keyOf},{}],20:[function(_dereq_,module){"use strict";var emptyFunction=_dereq_("./emptyFunction"),warning=emptyFunction;module.exports=warning},{"./emptyFunction":16}]},{},[7])(7)}); \ No newline at end of file diff --git a/package.json b/package.json index 5abf646..9abad52 100644 --- a/package.json +++ b/package.json @@ -2,7 +2,7 @@ "name": "react-menu", "version": "0.0.7", "description": "Accessible menu component for React.JS", - "main": "./lib/index", + "main": "./dist/lib/index", "repository": { "type": "git", "url": "https://github.com/instructure-react/react-menu.git" diff --git a/scripts/build b/scripts/build index e58f95d..5cead05 100755 --- a/scripts/build +++ b/scripts/build @@ -1,10 +1,25 @@ -#!/bin/sh -mkdir -p dist +#!/bin/sh -e + +rm -rf dist +mkdir -p dist/{umd,lib} + NODE_ENV=production node_modules/.bin/browserify lib/index.js \ -t reactify \ -t browserify-shim \ -t envify \ --detect-globals false \ - -s ReactMenu > dist/react-menu.js -node_modules/.bin/uglifyjs dist/react-menu.js \ - --compress warnings=false > dist/react-menu.min.js + -s ReactMenu > dist/umd/react-menu.js +node_modules/.bin/uglifyjs dist/umd/react-menu.js \ + --compress warnings=false > dist/umd/react-menu.min.js + +JSX=node_modules/jsx-loader/node_modules/react-tools/bin/jsx + +node -p 'p=require("./package");p.main="dist/lib/index.js";p.scripts=p.devDependencies=undefined;JSON.stringify(p,null,2)' > dist/package.json + +for FILE in $(find lib -name '*.js'); do + DIRNAME=$(dirname ${FILE}) + mkdir -p dist/${DIRNAME} + DESTNAME=dist/${FILE} + + ${JSX} --harmony ${FILE} > ${DESTNAME} +done