jobiqo-cl
Version:
[](https://circleci.com/gh/jobiqo/jobiqo-cl)
190 lines (184 loc) • 6.15 kB
JavaScript
import React__default, { useEffect } from 'react';
import styled from 'styled-components';
import FocusTrap from '../../../../../node_modules/focus-trap-react/dist/focus-trap-react.js';
import { motion } from '../../../../../node_modules/framer-motion/dist/framer-motion.es.js';
/**
* @file index.tsx
*
* @fileoverview Renders a drawer in a position defined by props. Can be used for sidenavs or mobile drops.
*/
const ESCAPE_KEY = 27;
const StyledOverlay = styled.div `
z-index: 1300;
position: fixed;
top: 0;
left: 0;
right: 0;
bottom: 0;
width: 100vw;
height: 100vh;
z-index: 100;
position: fixed;
touch-action: none;
-webkit-tap-highlight-color: transparent;
background-color: ${props => props.theme.navigation.mobile.sidenav.overlay.background};
`;
const variants = {
left: {
open: {
x: '0%',
opacity: 1,
transition: { ease: 'easeIn', duration: 0.3, staggerChildren: 0.5 }
},
closed: {
x: '-150%',
opacity: 0,
transition: { ease: 'easeOut', duration: 0.5, staggerChildren: 0.5 }
}
},
right: {
open: {
x: '0%',
opacity: 1,
transition: { ease: 'easeIn', duration: 0.3, staggerChildren: 0.5 }
},
closed: {
x: '200%',
opacity: 0,
transition: { ease: 'easeOut', duration: 0.5, staggerChildren: 0.5 }
}
},
bottom: {
open: {
y: '0%',
opacity: 1,
transition: { ease: 'easeIn', duration: 0.3, staggerChildren: 0.5 }
},
closed: {
y: '100%',
opacity: 0,
transition: { ease: 'easeOut', duration: 0.5, staggerChildren: 0.5 }
}
},
top: {
open: {
y: '0%',
opacity: 1,
transition: { ease: 'easeIn', duration: 0.3, staggerChildren: 0.5 }
},
closed: {
y: '-100%',
opacity: 0,
transition: { ease: 'easeOut', duration: 0.5, staggerChildren: 0.5 }
}
}
};
const StyledSideNavBlock = styled(motion.div) `
overflow: auto;
position: fixed;
${props => (props.position === 'right' ? `right: 0;` : `left:0;`)}
${props => (props.position === 'top' ? `top: 0;` : `bottom: 0;`)}
width: 100%;
${props => props.position === 'left' || props.position === 'right'
? `
top: 0;
max-width: ${props.theme.navigation.mobile.sidenav.maxWidth};
`
: `
min-height: ${props.full === 'true' ? `100%` : props.theme.tabs.minHeight};
`}
${props => props.height
? `height: ${props.height};`
: `max-height: 100vh;`}
z-index: 101;
box-shadow: ${props => props.theme.navigation.mobile.sidenav.boxShadow};
background-color: ${props => props.theme.navigation.mobile.sidenav.background};
.focus-area {
height: 100%;
}
`;
/**
* Handle keyboard escape manually because we want to hide the navbar when key is pressed. Not only
* remove the focus trap.
*
* @event {SyntheticKeyboardEvent}
* The event called by the keydown.
*/
const handleKeyDown = (event, hideFn, onToggle) => {
switch (event.keyCode) {
case ESCAPE_KEY:
hideFn(onToggle);
break;
}
};
/**
* Will hide the sidenav by toggling isOpen state or calling onProps in case of a controlled
* element.
*/
const hide = onToggle => {
onToggle(false);
};
const getConstraint = (position) => {
if (position === 'left') {
return {
right: 0
};
}
if (position === 'right') {
return {
left: 0
};
}
if (position === 'top') {
return {
bottom: 0
};
}
if (position === 'bottom') {
return {
top: 0
};
}
return { right: 0 };
};
/**
* A component that can be toggle on and off on a position defined by the user via props. Can be used for
* sidebar navigation or mobile drop (show from bottom).
*/
const Drawer = ({ children, height, full = false, isOpen = false, position = 'left', onToggle }) => {
const [activeTrap, setActiveTrap] = React__default.useState(false);
// When the isOpen prop gets changed make sure to set or unset
// mouse traps accordingly.
useEffect(() => {
if (isOpen) {
setActiveTrap(true);
}
else {
setActiveTrap(false);
}
}, [isOpen]);
const sidenav = (React__default.createElement(StyledSideNavBlock, { drag: position === 'left' || position === 'right' ? 'x' : 'y', dragConstraints: getConstraint(position), dragElastic: 0, "data-testid": "sidenav", onDragEnd: (event, info) => {
if (position === 'left' && info.point.x < 0) {
hide(onToggle);
}
if (position === 'right' && info.point.x > 0) {
hide(onToggle);
}
if (position === 'top' && info.point.y < 0) {
hide(onToggle);
}
if (position === 'bottom' && info.point.y > 0) {
hide(onToggle);
}
}, onKeyDown: e => handleKeyDown(e, hide, onToggle), variants: variants[position], initial: "closed", position: position, height: height, full: full === true ? 'true' : 'false', animate: isOpen ? 'open' : 'closed' }, activeTrap ? (React__default.createElement(FocusTrap, { className: "focus-area", focusTrapOptions: {
clickOutsideDeactivates: true,
escapeDeactivates: false,
onDeactivate: () => setActiveTrap(false)
} },
children,
React__default.createElement("a", { href: "#" }))) : (false)));
return (React__default.createElement("div", { role: "navigation" },
sidenav,
isOpen && (React__default.createElement(StyledOverlay, { "data-testid": "sidenav-overlay", isOpen: isOpen, onClick: e => hide(onToggle) }))));
};
export { Drawer, StyledOverlay, StyledSideNavBlock };