UNPKG

react-nav-bar

Version:

Simple yet very coustomizable navigation bar for react

380 lines (304 loc) 14 kB
'use strict'; Object.defineProperty(exports, "__esModule", { value: true }); var _typeof = typeof Symbol === "function" && typeof Symbol.iterator === "symbol" ? function (obj) { return typeof obj; } : function (obj) { return obj && typeof Symbol === "function" && obj.constructor === Symbol ? "symbol" : typeof obj; }; 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; }; }(); var _lodash = require('lodash'); var _lodash2 = _interopRequireDefault(_lodash); var _react = require('react'); var _react2 = _interopRequireDefault(_react); var _reactRouter = require('react-router'); var _reactFontawesome = require('react-fontawesome'); var _reactFontawesome2 = _interopRequireDefault(_reactFontawesome); var _reactMotion = require('react-motion'); var _utils = require('./../../lib/utils'); var _constants = require('./../../lib/constants'); var _menuShapes = require('./../../lib/menuShapes'); function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { "default": obj }; } function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); } } 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; } 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; } var Menu = function (_Component) { _inherits(Menu, _Component); function Menu(props) { _classCallCheck(this, Menu); var _this = _possibleConstructorReturn(this, Object.getPrototypeOf(Menu).call(this, props)); _this.state = { theme: _this.props.theme || _constants.DEFAULT_NAME, opened: _this.props.opened, openOnHover: typeof _this.props.openOnHover === 'boolean' ? _this.props.openOnHover : true, visible: _this.isVisible(_this.props.permission) || true }; return _this; } /** * Checks if menu should be visible * * @param {Function|Boolean} permission * @returns {*} */ _createClass(Menu, [{ key: 'isVisible', value: function isVisible(permission) { var visible = typeof permission === 'function' ? permission() : permission; return visible; } /** * Toggle this.state.opened true/false * * @param {Boolean} opened */ }, { key: 'toggleMenu', value: function toggleMenu(opened) { this.setState({ opened: typeof opened !== 'undefined' ? opened : !this.state.opened }); } /** * If onAction was supplied we invoke the action and prevent default. * * @param {Object} event * @param {Function} fn * @returns {*} */ }, { key: 'onMenuClick', value: function onMenuClick(event, fn) { if (!_lodash2["default"].isFunction(fn)) return; event.preventDefault(); return fn.call(this, event); } /** * Prepare all classes and states for render. * * @returns {{displayToggle: boolean labelClassName: * contentClassName: * liClassName: * chevron: * active: (string|*)}} */ }, { key: 'prepareForRender', value: function prepareForRender() { var menu = this.props; var theme = this.state.theme; var chevron = void 0, liClassName = void 0, labelClassName = void 0, contentClassName = void 0, displayToggle = true, toggleParent = {}, toggleChild = {}, toggleDefault = void 0, active = void 0; var _props = this.props; var parentIndex = _props.parentIndex; var index = _props.index; var toggle = _props.toggle; if ((typeof toggle === 'undefined' ? 'undefined' : _typeof(toggle)) === 'object') { displayToggle = typeof toggle.display === 'boolean' ? toggle.display : true; toggleParent = toggle.parent || {}; toggleChild = toggle.child || {}; toggleDefault = toggle["default"]; } if (typeof toggle === 'boolean') { displayToggle = toggle; } active = menu.active ? 'active' : ''; // if has parent index - this is a child menu if (parentIndex) { labelClassName = (0, _utils.createClassName)({ theme: theme, classNames: ['nav-label', 'label-child', active] }); contentClassName = (0, _utils.createClassName)({ theme: theme, classNames: ['nav-content', 'content-child'] }); liClassName = (0, _utils.createClassName)({ theme: theme, classNames: ['nav-li', 'child-li'] }); chevron = this.state.opened ? toggleChild.opened || toggleDefault || 'chevron-right' : toggleChild.closed || toggleDefault || 'chevron-left'; } else { labelClassName = (0, _utils.createClassName)({ theme: theme, classNames: ['nav-label', 'label-parent', active] }); contentClassName = (0, _utils.createClassName)({ theme: theme, classNames: ['nav-content'] }); liClassName = (0, _utils.createClassName)({ theme: theme, classNames: ['nav-li', 'parent-li'] }); chevron = this.state.opened ? toggleParent.opened || toggleDefault || 'chevron-down' : toggleParent.closed || toggleDefault || 'chevron-up'; } return { displayToggle: displayToggle, labelClassName: labelClassName, contentClassName: contentClassName, liClassName: liClassName, chevron: chevron, active: active }; } /** * Renders menu content with spring motion * * @param {String} contentClassName * @returns {XML} */ }, { key: 'renderContentWithSpring', value: function renderContentWithSpring(contentClassName) { var _this2 = this; var theme = this.state.theme; var springOpts = this.props.spring; return _react2["default"].createElement( _reactMotion.Motion, { style: { x: (0, _reactMotion.spring)(this.state.opened ? springOpts.opened : springOpts.closed) } }, function (_ref) { var x = _ref.x; return _react2["default"].createElement( 'div', { className: contentClassName + (!_this2.state.opened && springOpts.closed == x ? ' ' + (0, _utils.createClassName)({ theme: theme, classNames: 'isClosed' }) : ' ' + (0, _utils.createClassName)({ theme: theme, classNames: 'isOpened' })), style: springOpts.style(x) }, _react2["default"].createElement( 'ul', { className: (0, _utils.createClassName)({ theme: theme, classNames: 'nav-ul' }) }, _this2.props.children ) ); } ); } /** * Renders menu content without spring motion * * @param {String} contentClassName * @returns {XML} */ }, { key: 'renderContentWithoutSpring', value: function renderContentWithoutSpring(contentClassName) { var theme = this.state.theme; return _react2["default"].createElement( 'div', { className: contentClassName + (this.state.opened ? ' ' + (0, _utils.createClassName)({ theme: theme, classNames: 'isOpened' }) : ' ' + (0, _utils.createClassName)({ theme: theme, classNames: 'isClosed' })) }, _react2["default"].createElement( 'ul', { className: (0, _utils.createClassName)({ theme: theme, classNames: 'nav-ul' }) }, this.props.children ) ); } /** * Render menu icon in-case it exists * * @returns {*} */ }, { key: 'renderMenuIcon', value: function renderMenuIcon() { var menu = this.props; var theme = this.state.theme; return menu.icon ? _react2["default"].createElement(_reactFontawesome2["default"], { className: (0, _utils.createClassName)({ theme: theme, classNames: 'menu-icon' }), name: menu.icon }) : false; } /** * Render menu label * * @returns {*} */ }, { key: 'renderLabel', value: function renderLabel() { var _this3 = this; var menu = this.props; return _lodash2["default"].isFunction(menu.label) || _lodash2["default"].isObject(menu.label) ? menu.label : _react2["default"].createElement( _reactRouter.Link, { to: menu.path, onClick: function onClick(e) { _this3.onMenuClick(e, menu.action); } }, menu.label ); } /** * Render toggle button incase it exists * @param {Boolean} displayToggle * @param {String} chevron * @returns {*} */ }, { key: 'renderToggleButton', value: function renderToggleButton(_ref2) { var _this4 = this; var displayToggle = _ref2.displayToggle; var chevron = _ref2.chevron; var theme = this.state.theme; return displayToggle ? _react2["default"].createElement(_reactFontawesome2["default"], { className: (0, _utils.createClassName)({ theme: theme, classNames: 'toggle-button' }), name: chevron, onClick: function onClick() { _this4.toggleMenu(); } }) : false; } /** * reacts render * * @returns {*} */ }, { key: 'render', value: function render() { var _this5 = this; var menu = this.props; if (!this.state.visible) return false; var _state = this.state; var theme = _state.theme; var openOnHover = _state.openOnHover; var _prepareForRender = this.prepareForRender(); var displayToggle = _prepareForRender.displayToggle; var labelClassName = _prepareForRender.labelClassName; var contentClassName = _prepareForRender.contentClassName; var liClassName = _prepareForRender.liClassName; var chevron = _prepareForRender.chevron; var active = _prepareForRender.active; if (this.props.children) { var springOpts = this.props.spring; return _react2["default"].createElement( 'li', { className: liClassName + ' ' + menu.className + (this.state.opened ? ' ' + (0, _utils.createClassName)({ theme: theme, classNames: 'isOpened' }) : ''), onMouseEnter: function onMouseEnter() { if (openOnHover) _this5.toggleMenu(true); }, onMouseLeave: function onMouseLeave() { if (openOnHover) _this5.toggleMenu(false); } }, _react2["default"].createElement( 'div', { className: labelClassName }, this.renderMenuIcon(), this.renderLabel(), this.renderToggleButton({ displayToggle: displayToggle, chevron: chevron }) ), springOpts ? this.renderContentWithSpring(contentClassName) : this.renderContentWithoutSpring(contentClassName) ); } return _react2["default"].createElement( 'li', { className: liClassName + ' ' + menu.className }, _react2["default"].createElement( 'div', { className: (0, _utils.createClassName)({ theme: theme, classNames: ['nav-label', active] }) }, this.renderMenuIcon(), this.renderLabel() ) ); } }]); return Menu; }(_react.Component); exports["default"] = Menu; Menu.propTypes = { spring: _menuShapes.springShape, toggle: _react.PropTypes.oneOfType([_menuShapes.toggleShape, _react2["default"].PropTypes.bool]), index: _react.PropTypes.number, parentIndex: _react.PropTypes.number, openOnHover: _react.PropTypes.bool, /** * path {String} - required - route to redirect on click. * label {String|component} - what will be the menu's text Or component instead. * active {Boolean|Function|Undefined|String} - Determines if the menu is active currently. * - If String or Undefined will check if that string is in pathname to determine if is active. * - If Boolean will do nothing and use the given value. * - If Function will invoke the function and assign the returned value to active. * action {Function} - Will get invoked when a menu item is clicked and prevent default * opened {Boolean} - Flag to indicate if submenu is opened or closed. * permission {Function|Boolean} - determines whether or not to show this menu - can be use for access control. * - If Function Will invoke the function and assign the returned value to visible * - If Boolean will be assigned to visible * subMenus {Array} - an array of submenus with the same signature. * className {String} - class name to be used for that menu(in the li) * icon {String} - specify an icon for menu. */ path: _react.PropTypes.string.isRequired, label: _react.PropTypes.oneOfType([_react.PropTypes.node, _react.PropTypes.string]), active: _react.PropTypes.oneOfType([_react.PropTypes.bool, _react.PropTypes.func, _react.PropTypes.string]), action: _react.PropTypes.func, opened: _react.PropTypes.bool, permission: _react.PropTypes.oneOfType([_react.PropTypes.bool, _react.PropTypes.func]), subMenus: _react.PropTypes.array, className: _react.PropTypes.string, icon: _react.PropTypes.string };