You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 
 

342 lines
13 KiB

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