import React, { useState, useRef, useEffect, useCallback } from 'react'; import PropTypes from 'prop-types'; import classnames from 'classnames'; import { useTranslation } from 'react-i18next'; import { Swiper, SwiperSlide } from 'swiper/react'; import SwiperCore, { A11y, Controller, Pagination, Scrollbar, Navigation, } from 'swiper'; import { Button, Icon, IconButton, Tooltip } from '../'; import 'swiper/css'; import 'swiper/css/navigation'; import './style.css'; const borderSize = 4; const expandedWidth = 248; const collapsedWidth = 25; const baseStyle = { maxWidth: `${expandedWidth}px`, width: `${expandedWidth}px`, }; const collapsedHideWidth = expandedWidth - collapsedWidth - borderSize; const styleMap = { open: { left: { marginLeft: '0px' }, right: { marginRight: '0px' }, }, closed: { left: { marginLeft: `-${collapsedHideWidth}px` }, right: { marginRight: `-${collapsedHideWidth}px` }, }, }; const baseClasses = 'transition-all duration-300 ease-in-out h-100 bg-black border-black justify-start box-content flex flex-col'; const classesMap = { open: { left: `mr-1`, right: `ml-1`, }, closed: { left: `mr-2 items-end`, right: `ml-2 items-start`, }, }; const openStateIconName = { left: 'push-left', right: 'push-right', }; const position = { left: { right: 5, }, right: { left: 5, }, }; const SidePanel = ({ side, className, activeTabIndex: activeTabIndexProp, tabs, }) => { const { t } = useTranslation('SidePanel'); const [panelOpen, setPanelOpen] = useState(activeTabIndexProp !== null); const [activeTabIndex, setActiveTabIndex] = useState(activeTabIndexProp || 0); const swiperRef = useRef() as any; const [swiper, setSwiper] = useState(); const prevRef = React.useRef(); const nextRef = React.useRef(); const openStatus = panelOpen ? 'open' : 'closed'; const style = Object.assign({}, styleMap[openStatus][side], baseStyle); const ActiveComponent = tabs[activeTabIndex].content; useEffect(() => { if (panelOpen && swiper) { swiper.slideTo(activeTabIndex, 500); } }, [panelOpen, swiper]); useEffect(() => { if (swiper) { swiper.params.navigation.prevEl = prevRef.current; swiper.params.navigation.nextEl = nextRef.current; swiper.navigation.init(); swiper.navigation.update(); } }, [swiper]); const getCloseStateComponent = () => { const _childComponents = Array.isArray(tabs) ? tabs : [tabs]; return ( <>
{ setPanelOpen(prev => !prev); }} data-cy={`side-panel-header-${side}`} >
{_childComponents.map((childComponent, index) => ( { setActiveTabIndex(index); setPanelOpen(true); }} > ))}
); }; return (
{panelOpen ? ( {/** Panel Header with Arrow and Close Actions */}
{ setPanelOpen(prev => !prev); // slideToActivePanel(); }} data-cy={`side-panel-header-${side}`} >
{tabs.length > 1 && _getMoreThanOneTabLayout( swiperRef, setSwiper, prevRef, nextRef, tabs, activeTabIndex, setActiveTabIndex, setPanelOpen )} {/** carousel navigation with the arrows */} {/** only show carousel nav if tabs are more than 3 tabs */} {tabs.length > 3 && (
)}
) : ( {getCloseStateComponent()} )}
); }; SidePanel.defaultProps = { defaultComponentOpen: null, }; SidePanel.propTypes = { side: PropTypes.oneOf(['left', 'right']).isRequired, className: PropTypes.string, activeTabIndex: PropTypes.number, tabs: PropTypes.oneOfType([ PropTypes.arrayOf( PropTypes.shape({ iconName: PropTypes.string.isRequired, iconLabel: PropTypes.string.isRequired, name: PropTypes.string.isRequired, label: PropTypes.string.isRequired, content: PropTypes.func, // TODO: Should be node, but it keeps complaining? }) ), ]), }; function _getMoreThanOneTabLayout( swiperRef: any, setSwiper: React.Dispatch, prevRef: React.MutableRefObject, nextRef: React.MutableRefObject, tabs: any, activeTabIndex: any, setActiveTabIndex: React.Dispatch, setPanelOpen: React.Dispatch> ) { return (
{ swiperRef.current = core.el; }} simulateTouch={false} modules={[Navigation, Pagination, Scrollbar, A11y, Controller]} slidesPerView={3} spaceBetween={5} onSwiper={swiper => setSwiper(swiper)} navigation={{ prevEl: prevRef?.current, nextEl: nextRef?.current, }} > {tabs.map((obj, index) => (
{ setActiveTabIndex(index); setPanelOpen(true); }} data-cy={`${obj.name}-btn`} > {obj.label}
))}
); } export default SidePanel;