@massds/mayflower-react
Version:
React versions of Mayflower design system UI components
173 lines (169 loc) • 5.16 kB
JavaScript
function _extends() { return _extends = Object.assign ? Object.assign.bind() : function (n) { for (var e = 1; e < arguments.length; e++) { var t = arguments[e]; for (var r in t) ({}).hasOwnProperty.call(t, r) && (n[r] = t[r]); } return n; }, _extends.apply(null, arguments); }
import React from "react";
import useEventListener from "../hooks/use-event-listener.mjs";
import useWindowWidth from "../hooks/use-window-width.mjs";
export function mainNavReducer(state, action) {
const newState = _extends({}, state);
switch (action.type) {
case 'setButtonExpanded':
{
if (newState.items[action.index]) {
newState.items[action.index] = _extends({}, newState.items[action.index], {
buttonExpanded: action.status
});
}
break;
}
case 'setIsOpen':
{
if (action.status) {
newState.isOpen = action.status;
}
break;
}
case 'setIsItemOpen':
{
if (newState.items[action.index]) {
newState.items[action.index] = _extends({}, newState.items[action.index], {
isOpen: action.status
});
}
break;
}
case 'hide':
{
newState.items = newState.items.map(() => ({
buttonExpanded: false,
isOpen: false
}));
newState.isOpen = false;
if (Object.prototype.hasOwnProperty.call(action, 'index') && newState.items[action.index]) {
newState.items[action.index] = {
buttonExpanded: true,
isOpen: true
};
}
break;
}
case 'show':
{
if (Object.prototype.hasOwnProperty.call(action, 'index') && state.items[action.index]) {
newState.items[action.index] = {
buttonExpanded: true,
isOpen: true
};
}
newState.isOpen = true;
break;
}
default:
return newState;
}
return newState;
}
export const initMainNavState = items => {
const initialList = {
isOpen: false,
items: items.map(() => ({
buttonExpanded: false,
isOpen: false
}))
};
return initialList;
};
// Custom hook that sets up the Header's MainNav context.
// This isn't placed in the hooks file because it uses mainNavReducer.
export const useHeaderMainNav = items => {
const windowWidth = useWindowWidth();
const breakpoint = 840;
const _React$useReducer = React.useReducer(mainNavReducer, items, initMainNavState),
state = _React$useReducer[0],
dispatch = _React$useReducer[1];
const setButtonExpanded = React.useCallback(_ref => {
let index = _ref.index,
status = _ref.status;
dispatch({
type: 'setButtonExpanded',
index: index,
status: status
});
}, []);
const setIsOpen = React.useCallback(_ref2 => {
let index = _ref2.index,
status = _ref2.status;
dispatch({
type: 'setIsItemOpen',
index: index,
status: status
});
}, []);
// Hides all Nav Items. If you pass an object with an index key,
// all nav items except the one that matches the index will be hidden.
const hide = React.useCallback(function (options) {
if (options === void 0) {
options = {};
}
const _options = options,
_options$index = _options.index,
index = _options$index === void 0 ? undefined : _options$index;
if (windowWidth) {
const body = document.querySelector('body');
const submenuClass = 'show-submenu';
body.classList.remove(submenuClass);
if (windowWidth <= breakpoint) {
dispatch({
type: 'hide',
index: index,
status: false
});
} else {
// @todo animate here!
dispatch({
type: 'hide',
index: index,
status: false
});
}
}
}, [windowWidth]);
// Shows the NavItem with the passed index number.
const show = React.useCallback(function (options) {
if (options === void 0) {
options = {};
}
const _options2 = options,
index = _options2.index;
const body = document.querySelector('body');
const submenuClass = 'show-submenu';
body.classList.add(submenuClass);
if (windowWidth <= breakpoint) {
dispatch({
type: 'show',
index: index
});
} else {
// @todo animate here!
dispatch({
type: 'show',
index: index
});
}
}, [windowWidth]);
// Restrict the available functionality for NavItem components to the following.
return React.useMemo(() => _extends({}, state, {
setButtonExpanded: setButtonExpanded,
setIsOpen: setIsOpen,
hide: hide,
show: show
}), [state]);
};
export const useHeaderNavKeydown = (element, onKeyDown) => {
useEventListener('keydown', onKeyDown, element);
};
export const useHeaderNavMouseEvents = (element, onMouseEnter, onMouseLeave) => {
useEventListener('mouseenter', onMouseEnter, element);
useEventListener('mouseleave', onMouseLeave, element);
};
export const useHeaderNavButtonEffects = (element, onClick) => {
useEventListener('click', onClick, element);
};