import type { CSSProperties } from 'react'; import React from 'react'; import { Layout, Menu } from 'antd'; import classNames from 'classnames'; import type { SiderProps } from 'antd/lib/layout/Sider'; import { MenuUnfoldOutlined, MenuFoldOutlined } from '@ant-design/icons'; import './index.less'; import type { WithFalse } from '../../typings'; import type { BaseMenuProps } from './BaseMenu'; import BaseMenu from './BaseMenu'; import MenuCounter from './Counter'; const { Sider } = Layout; export const defaultRenderLogo = (logo: React.ReactNode): React.ReactNode => { if (typeof logo === 'string') { return logo; } if (typeof logo === 'function') { return logo(); } return logo; }; export const defaultRenderLogoAndTitle = ( props: SiderMenuProps, renderKey: string = 'menuHeaderRender', ): React.ReactNode => { const { logo, title, layout } = props; const renderFunction = props[renderKey || '']; if (renderFunction === false) { return null; } const logoDom = defaultRenderLogo(logo); const titleDom =

{title}

; if (renderFunction) { // when collapsed, no render title return renderFunction(logoDom, props.collapsed ? null : titleDom, props); } if (layout === 'mix' && renderKey === 'menuHeaderRender') { return null; } return ( {logoDom} {props.collapsed ? null : titleDom} ); }; export type SiderMenuProps = { logo?: React.ReactNode; siderWidth?: number; menuHeaderRender?: WithFalse< (logo: React.ReactNode, title: React.ReactNode, props?: SiderMenuProps) => React.ReactNode >; menuFooterRender?: WithFalse<(props?: SiderMenuProps) => React.ReactNode>; menuContentRender?: WithFalse< (props: SiderMenuProps, defaultDom: React.ReactNode) => React.ReactNode >; menuExtraRender?: WithFalse<(props: SiderMenuProps) => React.ReactNode>; collapsedButtonRender?: WithFalse<(collapsed?: boolean) => React.ReactNode>; breakpoint?: SiderProps['breakpoint'] | false; onMenuHeaderClick?: (e: React.MouseEvent) => void; hide?: boolean; className?: string; style?: CSSProperties; links?: React.ReactNode[]; onOpenChange?: (openKeys: WithFalse) => void; getContainer?: false; logoStyle?: CSSProperties; } & Pick>; export const defaultRenderCollapsedButton = (collapsed?: boolean) => collapsed ? : ; export type PrivateSiderMenuProps = { matchMenuKeys: string[]; }; const SiderMenu: React.FC = (props) => { const { collapsed, fixSiderbar, menuFooterRender, onCollapse, theme, siderWidth, isMobile, onMenuHeaderClick, breakpoint = 'lg', style, layout, menuExtraRender = false, collapsedButtonRender = defaultRenderCollapsedButton, links, menuContentRender, prefixCls, onOpenChange, headerHeight, logoStyle, } = props; const baseClassName = `${prefixCls}-sider`; const { flatMenuKeys } = MenuCounter.useContainer(); const siderClassName = classNames(`${baseClassName}`, { [`${baseClassName}-fixed`]: fixSiderbar, [`${baseClassName}-layout-${layout}`]: layout && !isMobile, [`${baseClassName}-light`]: theme === 'light', }); const headerDom = defaultRenderLogoAndTitle(props); const extraDom = menuExtraRender && menuExtraRender(props); const menuDom = menuContentRender !== false && flatMenuKeys && ( ); const menuRenderDom = menuContentRender ? menuContentRender(props, menuDom) : menuDom; return ( <> {fixSiderbar && (
)} { if (isMobile) return; onCollapse?.(collapse); }} collapsedWidth={48} style={{ overflow: 'hidden', paddingTop: layout === 'mix' && !isMobile ? headerHeight : undefined, ...style, }} width={siderWidth} theme={theme} className={siderClassName} > {headerDom && ( )} {extraDom && (
{extraDom}
)}
{menuRenderDom}
{(links || []).map((node, index) => ( // eslint-disable-next-line react/no-array-index-key {node} ))} {collapsedButtonRender && !isMobile && ( { if (onCollapse) { onCollapse(!collapsed); } }} > {collapsedButtonRender(collapsed)} )}
{menuFooterRender && (
{menuFooterRender(props)}
)}
); }; export default SiderMenu;