Não pode escolher mais do que 25 tópicos Os tópicos devem começar com uma letra ou um número, podem incluir traços ('-') e podem ter até 35 caracteres.
 
 
 
 

316 linhas
12 KiB

  1. var _extends = Object.assign || function (target) { for (var i = 1; i < arguments.length; i++) { var source = arguments[i]; for (var key in source) { if (Object.prototype.hasOwnProperty.call(source, key)) { target[key] = source[key]; } } } return target; };
  2. var _createClass = function () { function defineProperties(target, props) { for (var i = 0; i < props.length; i++) { var descriptor = props[i]; descriptor.enumerable = descriptor.enumerable || false; descriptor.configurable = true; if ("value" in descriptor) descriptor.writable = true; Object.defineProperty(target, descriptor.key, descriptor); } } return function (Constructor, protoProps, staticProps) { if (protoProps) defineProperties(Constructor.prototype, protoProps); if (staticProps) defineProperties(Constructor, staticProps); return Constructor; }; }();
  3. function _defineProperty(obj, key, value) { if (key in obj) { Object.defineProperty(obj, key, { value: value, enumerable: true, configurable: true, writable: true }); } else { obj[key] = value; } return obj; }
  4. function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); } }
  5. function _possibleConstructorReturn(self, call) { if (!self) { throw new ReferenceError("this hasn't been initialised - super() hasn't been called"); } return call && (typeof call === "object" || typeof call === "function") ? call : self; }
  6. function _inherits(subClass, superClass) { if (typeof superClass !== "function" && superClass !== null) { throw new TypeError("Super expression must either be null or a function, not " + typeof superClass); } subClass.prototype = Object.create(superClass && superClass.prototype, { constructor: { value: subClass, enumerable: false, writable: true, configurable: true } }); if (superClass) Object.setPrototypeOf ? Object.setPrototypeOf(subClass, superClass) : subClass.__proto__ = superClass; }
  7. import React from 'react';
  8. import PropTypes from 'prop-types';
  9. import cx from 'classnames';
  10. import assign from 'object-assign';
  11. import { hideMenu } from './actions';
  12. import AbstractMenu from './AbstractMenu';
  13. import { callIfExists, cssClasses, hasOwnProp, store } from './helpers';
  14. import listener from './globalEventListener';
  15. var SubMenu = function (_AbstractMenu) {
  16. _inherits(SubMenu, _AbstractMenu);
  17. function SubMenu(props) {
  18. _classCallCheck(this, SubMenu);
  19. var _this = _possibleConstructorReturn(this, (SubMenu.__proto__ || Object.getPrototypeOf(SubMenu)).call(this, props));
  20. _this.getMenuPosition = function () {
  21. var _window = window,
  22. innerWidth = _window.innerWidth,
  23. innerHeight = _window.innerHeight;
  24. var rect = _this.subMenu.getBoundingClientRect();
  25. var position = {};
  26. if (rect.bottom > innerHeight) {
  27. position.bottom = 0;
  28. } else {
  29. position.top = 0;
  30. }
  31. if (rect.right < innerWidth) {
  32. position.left = '100%';
  33. } else {
  34. position.right = '100%';
  35. }
  36. return position;
  37. };
  38. _this.getRTLMenuPosition = function () {
  39. var _window2 = window,
  40. innerHeight = _window2.innerHeight;
  41. var rect = _this.subMenu.getBoundingClientRect();
  42. var position = {};
  43. if (rect.bottom > innerHeight) {
  44. position.bottom = 0;
  45. } else {
  46. position.top = 0;
  47. }
  48. if (rect.left < 0) {
  49. position.left = '100%';
  50. } else {
  51. position.right = '100%';
  52. }
  53. return position;
  54. };
  55. _this.hideSubMenu = function (e) {
  56. // avoid closing submenus of a different menu tree
  57. if (e.detail && e.detail.id && _this.menu && e.detail.id !== _this.menu.id) {
  58. return;
  59. }
  60. if (_this.props.forceOpen) {
  61. _this.props.forceClose();
  62. }
  63. _this.setState({ visible: false, selectedItem: null });
  64. _this.unregisterHandlers();
  65. };
  66. _this.handleClick = function (event) {
  67. event.preventDefault();
  68. if (_this.props.disabled) return;
  69. callIfExists(_this.props.onClick, event, assign({}, _this.props.data, store.data), store.target);
  70. if (!_this.props.onClick || _this.props.preventCloseOnClick) return;
  71. hideMenu();
  72. };
  73. _this.handleMouseEnter = function () {
  74. if (_this.closetimer) clearTimeout(_this.closetimer);
  75. if (_this.props.disabled || _this.state.visible) return;
  76. _this.opentimer = setTimeout(function () {
  77. return _this.setState({
  78. visible: true,
  79. selectedItem: null
  80. });
  81. }, _this.props.hoverDelay);
  82. };
  83. _this.handleMouseLeave = function () {
  84. if (_this.opentimer) clearTimeout(_this.opentimer);
  85. if (!_this.state.visible) return;
  86. _this.closetimer = setTimeout(function () {
  87. return _this.setState({
  88. visible: false,
  89. selectedItem: null
  90. });
  91. }, _this.props.hoverDelay);
  92. };
  93. _this.menuRef = function (c) {
  94. _this.menu = c;
  95. };
  96. _this.subMenuRef = function (c) {
  97. _this.subMenu = c;
  98. };
  99. _this.registerHandlers = function () {
  100. document.removeEventListener('keydown', _this.props.parentKeyNavigationHandler);
  101. document.addEventListener('keydown', _this.handleKeyNavigation);
  102. };
  103. _this.unregisterHandlers = function (dismounting) {
  104. document.removeEventListener('keydown', _this.handleKeyNavigation);
  105. if (!dismounting) {
  106. document.addEventListener('keydown', _this.props.parentKeyNavigationHandler);
  107. }
  108. };
  109. _this.state = assign({}, _this.state, {
  110. visible: false
  111. });
  112. return _this;
  113. }
  114. _createClass(SubMenu, [{
  115. key: 'componentDidMount',
  116. value: function componentDidMount() {
  117. this.listenId = listener.register(function () {}, this.hideSubMenu);
  118. }
  119. }, {
  120. key: 'getSubMenuType',
  121. value: function getSubMenuType() {
  122. // eslint-disable-line class-methods-use-this
  123. return SubMenu;
  124. }
  125. }, {
  126. key: 'shouldComponentUpdate',
  127. value: function shouldComponentUpdate(nextProps, nextState) {
  128. this.isVisibilityChange = (this.state.visible !== nextState.visible || this.props.forceOpen !== nextProps.forceOpen) && !(this.state.visible && nextProps.forceOpen) && !(this.props.forceOpen && nextState.visible);
  129. return true;
  130. }
  131. }, {
  132. key: 'componentDidUpdate',
  133. value: function componentDidUpdate() {
  134. var _this2 = this;
  135. if (!this.isVisibilityChange) return;
  136. if (this.props.forceOpen || this.state.visible) {
  137. var wrapper = window.requestAnimationFrame || setTimeout;
  138. wrapper(function () {
  139. var styles = _this2.props.rtl ? _this2.getRTLMenuPosition() : _this2.getMenuPosition();
  140. _this2.subMenu.style.removeProperty('top');
  141. _this2.subMenu.style.removeProperty('bottom');
  142. _this2.subMenu.style.removeProperty('left');
  143. _this2.subMenu.style.removeProperty('right');
  144. if (hasOwnProp(styles, 'top')) _this2.subMenu.style.top = styles.top;
  145. if (hasOwnProp(styles, 'left')) _this2.subMenu.style.left = styles.left;
  146. if (hasOwnProp(styles, 'bottom')) _this2.subMenu.style.bottom = styles.bottom;
  147. if (hasOwnProp(styles, 'right')) _this2.subMenu.style.right = styles.right;
  148. _this2.subMenu.classList.add(cssClasses.menuVisible);
  149. _this2.registerHandlers();
  150. _this2.setState({ selectedItem: null });
  151. });
  152. } else {
  153. var cleanup = function cleanup() {
  154. _this2.subMenu.removeEventListener('transitionend', cleanup);
  155. _this2.subMenu.style.removeProperty('bottom');
  156. _this2.subMenu.style.removeProperty('right');
  157. _this2.subMenu.style.top = 0;
  158. _this2.subMenu.style.left = '100%';
  159. _this2.unregisterHandlers();
  160. };
  161. this.subMenu.addEventListener('transitionend', cleanup);
  162. this.subMenu.classList.remove(cssClasses.menuVisible);
  163. }
  164. }
  165. }, {
  166. key: 'componentWillUnmount',
  167. value: function componentWillUnmount() {
  168. if (this.listenId) {
  169. listener.unregister(this.listenId);
  170. }
  171. if (this.opentimer) clearTimeout(this.opentimer);
  172. if (this.closetimer) clearTimeout(this.closetimer);
  173. this.unregisterHandlers(true);
  174. }
  175. }, {
  176. key: 'render',
  177. value: function render() {
  178. var _cx;
  179. var _props = this.props,
  180. children = _props.children,
  181. attributes = _props.attributes,
  182. disabled = _props.disabled,
  183. title = _props.title,
  184. selected = _props.selected;
  185. var visible = this.state.visible;
  186. var menuProps = {
  187. ref: this.menuRef,
  188. onMouseEnter: this.handleMouseEnter,
  189. onMouseLeave: this.handleMouseLeave,
  190. className: cx(cssClasses.menuItem, cssClasses.subMenu, attributes.listClassName),
  191. style: {
  192. position: 'relative'
  193. }
  194. };
  195. var menuItemProps = {
  196. className: cx(cssClasses.menuItem, attributes.className, (_cx = {}, _defineProperty(_cx, cx(cssClasses.menuItemDisabled, attributes.disabledClassName), disabled), _defineProperty(_cx, cx(cssClasses.menuItemActive, attributes.visibleClassName), visible), _defineProperty(_cx, cx(cssClasses.menuItemSelected, attributes.selectedClassName), selected), _cx)),
  197. onMouseMove: this.props.onMouseMove,
  198. onMouseOut: this.props.onMouseOut,
  199. onClick: this.handleClick
  200. };
  201. var subMenuProps = {
  202. ref: this.subMenuRef,
  203. style: {
  204. position: 'absolute',
  205. transition: 'opacity 1ms', // trigger transitionend event
  206. top: 0,
  207. left: '100%'
  208. },
  209. className: cx(cssClasses.menu, this.props.className)
  210. };
  211. return React.createElement(
  212. 'nav',
  213. _extends({}, menuProps, { role: 'menuitem', tabIndex: '-1', 'aria-haspopup': 'true' }),
  214. React.createElement(
  215. 'div',
  216. _extends({}, attributes, menuItemProps),
  217. title
  218. ),
  219. React.createElement(
  220. 'nav',
  221. _extends({}, subMenuProps, { role: 'menu', tabIndex: '-1' }),
  222. this.renderChildren(children)
  223. )
  224. );
  225. }
  226. }]);
  227. return SubMenu;
  228. }(AbstractMenu);
  229. SubMenu.propTypes = {
  230. children: PropTypes.node.isRequired,
  231. attributes: PropTypes.object,
  232. title: PropTypes.node.isRequired,
  233. className: PropTypes.string,
  234. disabled: PropTypes.bool,
  235. hoverDelay: PropTypes.number,
  236. rtl: PropTypes.bool,
  237. selected: PropTypes.bool,
  238. onMouseMove: PropTypes.func,
  239. onMouseOut: PropTypes.func,
  240. forceOpen: PropTypes.bool,
  241. forceClose: PropTypes.func,
  242. parentKeyNavigationHandler: PropTypes.func
  243. };
  244. SubMenu.defaultProps = {
  245. disabled: false,
  246. hoverDelay: 500,
  247. attributes: {},
  248. className: '',
  249. rtl: false,
  250. selected: false,
  251. onMouseMove: function onMouseMove() {
  252. return null;
  253. },
  254. onMouseOut: function onMouseOut() {
  255. return null;
  256. },
  257. forceOpen: false,
  258. forceClose: function forceClose() {
  259. return null;
  260. },
  261. parentKeyNavigationHandler: function parentKeyNavigationHandler() {
  262. return null;
  263. }
  264. };
  265. export default SubMenu;