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

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


import MuiIcon from 'components/common/MuiIcon';
import { GearsIcon, useGearsIconInfo } from 'components/process/GearsIcon';
import SidebarContextProvider from 'contexts/SidebarContext';
import { useLayoutContext } from 'hooks/layout';
import {
    SidebarItemSx, useSidebarChildItemActive, useSidebarContext, useSidebarItemActive,
    useSidebarItemOnClick, useSidebarItemSX
} from 'hooks/sidebar';
import _ from 'lodash';
import React, { useEffect, useRef, useState } from 'react';
import { ReactChildren } from 'types/react';
import {
    SidebarItemData, SidebarItemDataCascading, SidebarItemDataGroup, SidebarItemDataIcon,
    SidebarItemDataLink
} from 'types/sidebar';
import { ThemeIcon } from 'types/theming';
import Types, { GearsIconType } from 'types/types';
import { decomposeRefPath } from 'utils/path';

import {
    Badge, Box, Collapse, IconButton, List, ListItemButton, ListItemIcon, ListItemText,
    ListSubheader, Tooltip, Typography, useTheme
} from '@mui/material';

import { isSidebarMatchFunction } from '../dashboard/DashboardSidebar';
import SidebarMenu from '../dashboard/SidebarMenu';

type ItemsProps = {
  items: SidebarItemData[]
}

export const SidebarList = ({items}: ItemsProps) => {
  const context = useSidebarContext()
  const theme   = useTheme()

  return (
    
       0 ? 22 : 0}px`, flexShrink: 0}} />
      
        
          
        
      
    
  )
}

export const SidebarItems = ({items}: ItemsProps): JSX.Element => {

  return (
    
      {items.map((item, index) => )}
    
  )
}

const SidebarGenericItem = ({item, isFirstItem}: {item: SidebarItemData, isFirstItem?: boolean}) => {
  switch (item.type) {
    case "group":
      return (item)} isFirstItem={isFirstItem} />

    case "cascading":
      return (item)} />

    default:
      return (item)}/>
  }
}

const SidebarGroupTitle = ({item, isFirstItem}: {item: SidebarItemDataGroup, isFirstItem?: boolean}) => {
  const { sidebarState } = useLayoutContext()
  const { sidebarType }  = useSidebarContext()

  const show = sidebarType != "sidebar" || sidebarState.kind == 'permanent' && sidebarState.expandState == "expanded"

  return (
    <>
       {/*sidebarType != "sidebar" || sidebarState.expand != "collapsed" && sidebarState.expand != "none"} > */}
        
          
            { item.label }
          
        
      
      
    
  )
}

const SidebarCascadingItem = ({item}: {item: SidebarItemDataCascading}) => {
  const childActive                    = useSidebarChildItemActive(item)
  const { level, sidebarType, filter } = useSidebarContext()
  const isMatch                        = isSidebarMatchFunction(filter)
  const [open, setOpen]                = useState(filter ? !isMatch(item) : false)
  const onClick                        = useSidebarItemOnClick(item)
  const {itemSx, textSx}               = useSidebarItemSX(item)
  const active                         = useSidebarItemActive(item)
  const {sidebarState}                 = useLayoutContext()

  const cascadingType           = sidebarState.expandState == "collapsed" || sidebarState.expandState == "none" || level > 1 ? "menu" : "list"
  const openList                = cascadingType == "list" && open 
  const ref                     = useRef()
  const [anchorEl, setAnchorEl] = useState(null);

  useEffect(() => {
    setOpen(filter ? !isMatch(item) : false)
  }, [filter])

  useEffect(() => {
    if (childActive && !open)
      setOpen(true)
  }, [childActive])

  const handleClick = (e: React.SyntheticEvent) => {
    e.preventDefault()
    e.stopPropagation()

    // open sidebar menu
    if (cascadingType == "menu")
      // @ts-ignore
      setAnchorEl(ref.current);

    // open list 
    if (cascadingType == "list")
      handleListOpen(e)

    if (onClick)
      onClick(e)
  }
  
  const handleListOpen = (e: React.SyntheticEvent) => {
    e.preventDefault()
    e.stopPropagation()

    if (cascadingType == "menu")
      // @ts-ignore
      setAnchorEl(ref.current)
    
    if (cascadingType == "list")
      setOpen(open => !open)
  }

  return (
    <>
      
        {/* @ts-ignore*/}
        
          
          
          {item.label}} />
          
            
          
        
      
      { cascadingType == "menu" || sidebarType == "menu" 
        ? 
            
          
        : null 
      }
      
        
          
        
      
    
  )
}

const SidebarLink = ({item}: {item: SidebarItemDataLink}) => {
  const onClick            = useSidebarItemOnClick(item)
  const { itemSx, textSx } = useSidebarItemSX(item)
  const active             = useSidebarItemActive(item)

  return (
    
       {onClick(e);}} 
        sx={{...itemSx, paddingRight: "45px"}} 
      >
        
        
        {item.label}} />
      
    
  )
}

export const SidebarIcon = ({item}: {item: SidebarItemData}) => {
  const active     = useSidebarItemActive(item)
  // @ts-ignore
  const { counts } = useSidebarContext()

  const badgeCount = getItemBadges(item).reduce((partialSum, badge) => partialSum + counts[badge], 0)

  return (
    
       ({
            // @ts-ignore
            ...theme.components?.badge,
          })
        }}
      >
        
      
    
  )
}

const getItemBadges = (item: SidebarItemData): string[] => {
  const children = getItemChildren(item)
  const badges   = children
    .flatMap(child => getItemBadges(child))
    .filter(badge => badge != 'allBadge')
  const badge    = getItemBadge(item)

  return badge ? [badge, ...badges] : badges
}

function getItemBadge(item: SidebarItemData): string | undefined {
  return asItemCascading(item)?.badge || asItemLink(item)?.badge
}

function isItemLink(item: SidebarItemData): boolean {
  return item.type == "item" || item.type == undefined
}

function isItemCascading(item: SidebarItemData): boolean {
  return item.type == "cascading"
}

function isItemGroup(item: SidebarItemData): boolean {
  return item.type == "group"
}

function asItemLink(item: SidebarItemData): SidebarItemDataLink | undefined {
  return isItemLink(item) ? Types.as(item) : undefined
}

function asItemCascading(item: SidebarItemData): SidebarItemDataCascading | undefined {
  return isItemCascading(item) ? Types.as(item) : undefined
}

function asItemGroup(item: SidebarItemData): SidebarItemDataGroup | undefined {
  return isItemGroup(item) ? Types.as(item) : undefined
}

function getItemChildren(item: SidebarItemData): SidebarItemData[] {
  switch (item.type) {
    case "cascading": 
      return Types.as(item)?.children || []
    case "group": 
      return Types.as(item)?.children || []
    default:
      return []
  }
}

const useSidebarIconSelector = ({item, active}: {item: SidebarItemData, active: boolean}): GearsIconType => {
  const itemIcon = selectItemIcon(active, Types.as(item))

  const toIconType = (itemIcon: any): GearsIconType => {
    if (Types.isObject(itemIcon)) {
      // @ts-ignore
      if (itemIcon.__kind == "icon")
        return itemIcon as GearsIconType
      else {
        return { __kind: "icon", ...(itemIcon as ThemeIcon) }
      }
    } else if (typeof itemIcon == "string") {
      return { __kind: "icon", name: itemIcon }
    } else {
      return {__kind: "icon"}
    }
  }

  if (item.ref && decomposeRefPath(item.ref)?.domain == "default") {
    const ret =  useGearsIconInfo({gearsRef: item.ref, icon: toIconType(itemIcon).name, active})
    return ret
  } else if (itemIcon) {
    return toIconType(itemIcon)
  } else if (item.ref) {
    // go look for the icon in the theme
    return useGearsIconInfo({gearsRef: item.ref, active})
  } 
    
  return {__kind: "icon"}
}

function selectItemIcon(active: boolean, item: SidebarItemDataIcon): string | ThemeIcon | GearsIconType | undefined {
  if (active)
    return item.activeIcon
  else 
    return item.icon
}

const SidebarItemIcon = ({item, active}: {item: SidebarItemData, active: boolean}) => {
  if (item.type != "cascading" && item.type != "item")
    return null

  const baseIcon = active ? _.get(item, "activeIcon") : _.get(item, "icon")
  const iconName = typeof baseIcon == "string" ? baseIcon : _.get(baseIcon, "name")  
  const icon     = useGearsIconInfo({gearsRef: item.ref, icon: iconName, override: true, active: active})
  const color    = active ? 'primary.main' : undefined

  return 
}

const SidebarTooltip = ({children, title}: {children: ReactChildren, title: string}) => {
  const { level } = useSidebarContext()
  const { props: {side, expandedWidth, collapsedWidth}, sidebarState: { expandState } } = useLayoutContext() 
  const diff = parseInt(collapsedWidth,10) - parseInt(expandedWidth, 10) 
  

  if (level == 0 && expandState == "collapsed") {
    return (
      
        {children}
      
    )
  }
  else return children
}

const ActiveIndicator = ({active}: {active: boolean}) => (
   theme.palette.primary.main,
      marginLeft: "-12px",
      borderRadius: "99px",
      marginRight: "5px",
      transition: "all .2s linear",
    }}
  />
)





© 2015 - 2024 Weber Informatics LLC | Privacy Policy