react-nav-bar
Version:
Simple yet very coustomizable navigation bar for react
380 lines (304 loc) • 14 kB
JavaScript
'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
};