All Downloads are FREE. Search and download functionalities are using the official Maven repository.

components.layout.sidebar.Sidebar.tsx Maven / Gradle / Ivy

import LoadingIcon from 'components/common/LoadingIcon';
import LayoutContextProvider, {
    ExpandAction, ExpandEnable, ExpandState, LayoutProps, SidebarKind, SidebarState
} from 'contexts/LayoutContext';
import { nextBannerState, useLayoutContext } from 'hooks/layout';
import useKeyboardShortcut, { keyboardCodeToChar } from 'hooks/shortcut';
import { useLocalTypeState } from 'hooks/state';
import { useTranslator } from 'hooks/translator';
import { useEffect, useRef, useState } from 'react';
import { DivProps } from 'types/react';

import ExpandIcon from '@mui/icons-material/ChevronLeft';
import { Box, useMediaQuery, useTheme } from '@mui/material';

const SidebarLayoutSidebar = (): JSX.Element => {
  const [sidebarState, setSidebarState] = useSidebarState()
  
  return ( 
    
      
    
  )
}

const SidebarContent = (): JSX.Element => {
  const { props: { side, transitionTime } } = useLayoutContext() 
  const bannerSx = useBannerSx()
  
  return (
    
      
        
      

      
          
      
    
  )
}

const SidebarBanner = ({}: DivProps): JSX.Element => {
  const { props: {sidebarBanner} } = useLayoutContext()

  return <>{sidebarBanner}
}

const SidebarBody = ({}: DivProps): JSX.Element => {
  const config = useLayoutContext()
  const { sidebarState, props: {side, sidebarBody, sidebarBodyFooter}, props: {transitionTime, expandedWidth}} = config
  const ref = useRef()
  const [height, setHeight] = useState("0px")

  useEffect(() => { 
    // @ts-ignore   
    setHeight(ref?.current?.clientHeight) 
  }, [])

  return (
    
      
        
          
            {sidebarBody}
          
        
      
      
        
          {sidebarBodyFooter}
        
      
      
    
  )
}

export const BannerSlidingExpander = (): JSX.Element => {
  const {bannerState, props: { transitionTime }} = useLayoutContext()
 
  const getMargin = () => {
    switch(bannerState) {
      case "expanded": 
        return {
          marginTop: "-36px", 
        }

      case "collapsed": 
      case 'none':
        return {
          marginTop: "-10px",
          "&:hover": {
            transition: "margin 0.1s linear",
            marginTop: "0px"
        }
      }
    }
  }

  return (
    
      
        
          
        
      
    
  )
}

export const BannerExpander = (): JSX.Element => {
  const { bannerProps: {shortcut, enabled}, bannerState, setBannerState, props: { transitionTime, side } } = useLayoutContext()
  const { t } = useTranslator()

  const handleClick = () => {
    setBannerState(state => nextBannerState(state, enabled))
  }
  
  const rotate = bannerState == "none" || bannerState == "collapsed"

  return 
}

const SidebarSlidingExpander = (): JSX.Element => {
  const {sidebarState, props: { transitionTime, side }} = useLayoutContext()

  const getMarginSx = () => {
    switch(sidebarState.expandState) {
      case "collapsed": 
      case "expanded": 
        return {
          marginLeft: side == "left" ? "-36px" : "0px", 
        }
      case 'none':
        return {
          marginLeft: side == "left" ? "-10px" : "-25px",
          "&:hover": {
            transition: "margin 0.1s linear",
            marginLeft: side == "left" ? "0px" : "-36px"
        }
      }
    }
  }
 
  return (
    
  )
}

const SidebarExpander = (): JSX.Element => {
  const { sidebarProps: {shortcut, enabled}, sidebarState, setSidebarState, props: { transitionTime, side } } = useLayoutContext()
  const { t } = useTranslator()

  const expandAction = nextSidebarAction(sidebarState, enabled)
  const handleClick  = () => {
    setSidebarState(state =>  updateSidebarState(state, enabled, expandAction))
  }
 
  const rotate = side == "left" && expandAction == "expand" || side == "right" && expandAction == "collapse"

  return 
}

const useSidebarState = () : [SidebarState, LayoutProps['setSidebarState']]=> {
  // @ts-ignore
  const sm = useMediaQuery(theme => theme?.breakpoints?.up('sm'));
  // @ts-ignore
  const lg = useMediaQuery(theme => theme?.breakpoints?.up('lg'));

  const { name, sidebarProps: { shortcut, enabled} } = useLayoutContext()
  const location = `${name}.sidebar`
  const {value: sidebarState, setValue: setSidebarState} = useLocalTypeState(location, createSidebarExpand(sm, lg, enabled)) 

  if (shortcut){
    useKeyboardShortcut(
      () => { 
        setSidebarState(state => ({...state, expandState: "none"})) }, 
      {code: shortcut, ctrlKey: true, altKey: true}
    )

    useKeyboardShortcut(
      () => { setSidebarState(state => updateSidebarState(state, enabled, nextSidebarAction(state, enabled))) }, 
      {code: shortcut, ctrlKey: true}
    )
  }
  
  const initialRender = useRef(false)
  useEffect(() => {
    if (initialRender.current)
      setSidebarState(createSidebarExpand(sm, lg, enabled))
    
    initialRender.current = true
  }, [sm, lg])

  return [sidebarState, setSidebarState]
}

const useBannerSx = () => {
  const theme = useTheme()
  const { bannerState, bannerProps, props: { transitionTime, withBanner } } = useLayoutContext() 

  //@ts-ignore
  const bannerSx     = theme.components?.banner
  const bannerColor  = bannerSx?.backgroundColor || bannerSx?.background
  const bannerHeight = withBanner ? parseInt(bannerProps.height) + (bannerState != "expanded"  ? 20 : 0) + 'px' : "0px"
  
  if (withBanner)
    return {
      margin: 0,
      height: bannerHeight,
      transition: `all ${transitionTime} ease`,
      marginBottom: bannerState != "expanded" ? "5px" : "0px",
      boxShadow: bannerState == "expanded" ? bannerProps.shadow : undefined,
      background: bannerState == "expanded" ? bannerColor : undefined,
    }
  else return {}
}

function nextSidebarAction(state: SidebarState, enabled: ExpandEnable): ExpandAction {
  if ((Number(enabled.collapsed) + Number(enabled.expanded) + Number(enabled.none) <= 1))
    return "none"

  switch (state.expandState) {
    case 'expanded': return 'collapse'
    case enabled.expanded && 'collapsed': return "expand"
    case 'collapsed': return "collapse"
    case 'none': return 'expand'
    default: return "none"
  }
}

function updateSidebarState(state: SidebarState, enabled: ExpandEnable, action: ExpandAction): SidebarState {
  if ((Number(enabled.collapsed) + Number(enabled.expanded) + Number(enabled.none) <= 1))
    return state

  if (state.kind == "sliding"){
    switch (true) {
      case state.expandState == "expanded" && action == "collapse": 
        return { ...state, expandState: "none"}

      case state.expandState == "none" && action == "expand": 
        return { ...state, expandState: "expanded"}

      default: 
        console.error("Attempting to perform action %o on sidebarState %o", action, JSON.stringify(state))
        return state
    }
  } else {

    switch (true) {
      case state.expandState == "expanded" && action == "collapse": 
        return { ...state, expandState: enabled.collapsed ? "collapsed" : "none"}

      case state.expandState == "collapsed" && action == "collapse" : 
        return enabled.none ? { ...state, expandState: "none"} : state

      case state.expandState == "collapsed" && action == "expand" : 
        return enabled.expanded ? { ...state, expandState: "expanded"} : state

      case state.expandState == "none" && action == "expand": 
        return { ...state, expandState: enabled.collapsed ? "collapsed" : "expanded"}

      default: 
        console.error("Attempting to perform action %o on sidebarState %o", action, JSON.stringify(state))
        return state
    } 
  }
}

function createSidebarExpand ( sm: boolean, lg: boolean, enabled: ExpandEnable) : SidebarState {
  switch (true) {
    case enabled.expanded  && lg : return { kind: "permanent", expandState: "expanded" }
    case enabled.collapsed && sm: return { kind: "permanent", expandState: "collapsed" }
    default: return { kind: "permanent", expandState: "none"}
    //default: return { kind: "sliding", expandState: "none"}
  }
}

function getSidebarWidth(config: LayoutProps): string {
  switch (config.sidebarState.expandState) {
    case "collapsed":
      return config.props.collapsedWidth
    case "expanded":
      return config.props.expandedWidth
    default:
      return "0px"
  }
}

export default SidebarLayoutSidebar




© 2015 - 2024 Weber Informatics LLC | Privacy Policy