react-responsive-html-menu
Version:
A React component which will move list items into a dropdown menu by detecting if it will fit within parent container
167 lines (127 loc) • 6.86 kB
JavaScript
;
Object.defineProperty(exports, "__esModule", {
value: true
});
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; };
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 _react = require('react');
var _react2 = _interopRequireDefault(_react);
var _ResponsiveMenuItem = require('./ResponsiveMenuItem.jsx');
var _ResponsiveMenuItem2 = _interopRequireDefault(_ResponsiveMenuItem);
var _ResponsiveMenuDropdown = require('./ResponsiveMenuDropdown.jsx');
var _ResponsiveMenuDropdown2 = _interopRequireDefault(_ResponsiveMenuDropdown);
var _throttle = require('lodash/throttle');
var _throttle2 = _interopRequireDefault(_throttle);
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 ResponsiveMenu = function (_Component) {
_inherits(ResponsiveMenu, _Component);
_createClass(ResponsiveMenu, null, [{
key: 'setWindowWidth',
value: function setWindowWidth(width) {
ResponsiveMenu.windowWidth = width;
}
}]);
function ResponsiveMenu(props) {
_classCallCheck(this, ResponsiveMenu);
var _this = _possibleConstructorReturn(this, Object.getPrototypeOf(ResponsiveMenu).call(this, props));
_this.setBrowserState = (0, _throttle2.default)(function () {
var visibleCount = _this.state.visibleCount;
var menu = _this.refs.menu;
if (!menu.children.length > 1) return;
var menuChildren = Object.keys(menu.children).map(function (key) {
return menu.children[key];
});
var dropMenu = menuChildren[menuChildren.length - 1];
dropMenu.style.display = '';
var menuTopPos = _this.state.init ? dropMenu.getBoundingClientRect().top : menuChildren[0].getBoundingClientRect().top;
var fittedCount = 0;
var childrenToCheck = undefined;
if (ResponsiveMenu.windowWidth < window.innerWidth) {
// When window size has increased
childrenToCheck = menuChildren.slice(visibleCount, -1);
fittedCount = visibleCount;
} else {
// When window size has decreased
childrenToCheck = menuChildren.slice(0, -1);
childrenToCheck.forEach(function (child) {
return child.style.display = 'none';
});
}
ResponsiveMenu.setWindowWidth(window.innerWidth);
childrenToCheck.every(function (child) {
child.style.display = '';
if (dropMenu.getBoundingClientRect().top !== menuTopPos) {
return false;
}
fittedCount++;
return true;
});
menuChildren.slice(visibleCount, fittedCount + 1).forEach(function (child) {
return child.style.display = 'none';
});
_this.setState({
visibleCount: fittedCount
});
}, 500);
_this.state = {
init: true,
visibleCount: 0
};
return _this;
}
_createClass(ResponsiveMenu, [{
key: 'componentDidMount',
value: function componentDidMount() {
this.setState({ init: false });
this.setBrowserState();
window.addEventListener('resize', this.setBrowserState, false);
}
}, {
key: 'componentWillUnmount',
value: function componentWillUnmount() {
window.removeEventListener('resize', this.setBrowserState, false);
}
}, {
key: 'render',
value: function render() {
var _props = this.props;
var className = _props.className;
var dropdownText = _props.dropdownText;
var list = _props.list;
var _state = this.state;
var init = _state.init;
var visibleCount = _state.visibleCount;
if (!list || !Array.isArray(list) || !list.length) return null;
var dropList = init ? list : list.slice(visibleCount);
return _react2.default.createElement(
'ul',
{ ref: 'menu', className: ('react-responsive-menu ' + className).trim() },
list.map(function (item, i) {
var showItem = init ? false : i < visibleCount;
return _react2.default.createElement(_ResponsiveMenuItem2.default, _extends({
key: i,
show: showItem
}, item));
}).concat(_react2.default.createElement(_ResponsiveMenuDropdown2.default, {
key: 'dropdown',
list: dropList,
dropdownText: dropdownText }))
);
}
}]);
return ResponsiveMenu;
}(_react.Component);
ResponsiveMenu.propTypes = {
className: _react.PropTypes.string,
dropdownText: _react.PropTypes.string,
list: _react.PropTypes.arrayOf(_react.PropTypes.object).isRequired
};
ResponsiveMenu.defaultProps = {
className: '',
dropdownText: 'More'
};
ResponsiveMenu.windowWidth = 0;
exports.default = ResponsiveMenu;