import React, { useEffect, useState, useRef, useMemo, useCallback, } from 'react'; import PropTypes from 'prop-types'; import { Nav, NavItem, NavLink, } from 'reactstrap'; function getBreakpointOneLevelLarger(breakpoint) { switch (breakpoint) { case 'sm': return 'md'; case 'md': return 'lg'; case 'lg': return 'xl'; case 'xl': default: return '2xl'; } } export const CustomNavDropdown = (props) => { const { activeTab, navTabMapping, onNavSelected, } = props; const activeObj = navTabMapping[activeTab]; const menuItemClickHandler = useCallback((key) => { if (onNavSelected != null) { onNavSelected(key); } }, [onNavSelected]); return (
{Object.entries(navTabMapping).map(([key, value]) => { const isActive = activeTab === key; const isLinkEnabled = value.isLinkEnabled != null ? value.isLinkEnabled(value) : true; const { Icon, i18n } = value; return ( ); })}
); }; CustomNavDropdown.propTypes = { activeTab: PropTypes.string.isRequired, navTabMapping: PropTypes.object.isRequired, onNavSelected: PropTypes.func, }; export const CustomNavTab = (props) => { const navContainer = useRef(); const [sliderWidth, setSliderWidth] = useState(0); const [sliderMarginLeft, setSliderMarginLeft] = useState(0); const { activeTab, navTabMapping, onNavSelected, hideBorderBottom, breakpointToHideInactiveTabsDown, navRightElement, } = props; const navTabRefs = useMemo(() => { const obj = {}; Object.keys(navTabMapping).forEach((key) => { obj[key] = React.createRef(); }); return obj; }, [navTabMapping]); const navLinkClickHandler = useCallback((key) => { if (onNavSelected != null) { onNavSelected(key); } }, [onNavSelected]); function registerNavLink(key, elm) { if (elm != null) { navTabRefs[key] = elm; } } // Might make this dynamic for px, %, pt, em function getPercentage(min, max) { return min / max * 100; } useEffect(() => { if (activeTab === '') { return; } if (navContainer == null) { return; } let tempML = 0; const styles = Object.entries(navTabRefs).map((el) => { const width = getPercentage(el[1].offsetWidth, navContainer.current.offsetWidth); const marginLeft = tempML; tempML += width; return { width, marginLeft }; }); const { width, marginLeft } = styles[navTabMapping[activeTab].index]; setSliderWidth(width); setSliderMarginLeft(marginLeft); }, [activeTab, navTabRefs, navTabMapping]); // determine inactive classes to hide NavItem const inactiveClassnames = []; if (breakpointToHideInactiveTabsDown != null) { const breakpointOneLevelLarger = getBreakpointOneLevelLarger(breakpointToHideInactiveTabsDown); inactiveClassnames.push('d-none'); inactiveClassnames.push(`d-${breakpointOneLevelLarger}-block`); } return (
{navRightElement}

{ !hideBorderBottom &&
}
); }; CustomNavTab.propTypes = { activeTab: PropTypes.string.isRequired, navTabMapping: PropTypes.object.isRequired, onNavSelected: PropTypes.func, hideBorderBottom: PropTypes.bool, breakpointToHideInactiveTabsDown: PropTypes.oneOf(['xs', 'sm', 'md', 'lg', 'xl']), navRightElement: PropTypes.node, }; CustomNavTab.defaultProps = { hideBorderBottom: false, }; const CustomNav = (props) => { const tabClassnames = ['d-none']; const dropdownClassnames = ['d-block']; // determine classes to show/hide const breakpointOneLevelLarger = getBreakpointOneLevelLarger(props.breakpointToSwitchDropdownDown); tabClassnames.push(`d-${breakpointOneLevelLarger}-block`); dropdownClassnames.push(`d-${breakpointOneLevelLarger}-none`); return (
); }; CustomNav.propTypes = { activeTab: PropTypes.string.isRequired, navTabMapping: PropTypes.object.isRequired, onNavSelected: PropTypes.func, hideBorderBottom: PropTypes.bool, breakpointToHideInactiveTabsDown: PropTypes.oneOf(['xs', 'sm', 'md', 'lg', 'xl']), breakpointToSwitchDropdownDown: PropTypes.oneOf(['xs', 'sm', 'md', 'lg', 'xl']), }; CustomNav.defaultProps = { hideBorderBottom: false, breakpointToSwitchDropdownDown: 'sm', }; export default CustomNav;