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
;
}
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 && (
{headerDom}
)}
{extraDom && (
{extraDom}
)}
{menuRenderDom}
{menuFooterRender && (
{menuFooterRender(props)}
)}
>
);
};
export default SiderMenu;