import type { MenuHeaderRender, MenuContentRender, MenuExtraRender, CollapsedButtonRender, LogoRender, WithFalse, } from '../typings'; import type { SiderProps } from './typings'; // import { LayoutSider as Sider, Menu } from '../../components'; import { LayoutSider as Sider } from 'ant-design-vue/lib/layout'; import Menu from 'ant-design-vue/lib/menu/index'; import BaseMenu, { baseMenuProps } from './BaseMenu'; import { defaultSettingProps } from '../defaultSettings'; import PropTypes from 'ant-design-vue/lib/_util/vue-types'; import type { CSSProperties, ExtractPropTypes, PropType, FunctionalComponent, } from 'vue'; import type { VueNode } from 'ant-design-vue/lib/_util/type'; import IconFont from '../../Icon/icon'; import { useRouteContext } from '../RouteContext'; import { computed, unref } from 'vue'; export type PrivateSiderMenuProps = { matchMenuKeys?: string[]; }; export const siderMenuProps = { ...defaultSettingProps, ...baseMenuProps, logo: { type: [Object, String, Function] as PropType, default: () => undefined, }, logoStyle: { type: Object as PropType, default: () => undefined, }, siderWidth: PropTypes.number.def(208), headerHeight: PropTypes.number.def(48), collapsedWidth: PropTypes.number.def(48), menuHeaderRender: { type: [Function, Object, Boolean] as PropType, default: () => undefined, }, menuContentRender: { type: [Function, Object, Boolean] as PropType, default: () => undefined, }, menuExtraRender: { type: [Function, Object, Boolean] as PropType, default: () => undefined, }, collapsedButtonRender: { type: [Function, Object, Boolean] as PropType, default: () => undefined, }, breakpoint: { type: [Object, Boolean] as PropType, default: () => false, }, splitMenus: PropTypes.looseBool, fixed: PropTypes.looseBool, hide: PropTypes.looseBool, matchMenuKeys: { type: Array as PropType, default: () => [], }, // events onMenuHeaderClick: PropTypes.func, onMenuClick: PropTypes.func, onCollapse: { type: Function as PropType<(collapsed: boolean) => void>, }, onOpenKeys: { type: Function as PropType<(openKeys: WithFalse) => void>, }, onSelect: { type: Function as PropType<(selectedKeys: WithFalse) => void>, }, }; export type SiderMenuProps = Partial>; export const defaultRenderLogo = ( logo?: VueNode, logoStyle?: CSSProperties, ): VueNode => { if (!logo) { return null; } if (typeof logo === 'string') { return logo; } if (typeof logo === 'function') { // @ts-ignore return logo(); } return logo; }; export const defaultRenderLogoAndTitle = ( props: SiderMenuProps, renderKey: string | undefined = 'menuHeaderRender', ): VueNode | null => { const { logo = 'http://demo.jetlinks.cn/static/logo.760eb65c.png', logoStyle, title, layout, } = props; const renderFunction = (props as Record)[renderKey || '']; if (layout === 'mix' && renderFunction === false) { return null; } const logoDom = defaultRenderLogo(logo, logoStyle); const titleDom =

{title}

; if (renderKey === 'menuHeaderRender') { return null; } // call menuHeaderRender if (typeof renderFunction === 'function') { // @ts-ignore return renderFunction( logoDom, props.collapsed ? null : titleDom, props, ); } if (Array.isArray(renderFunction)) { return <>{renderFunction}; } return ( {logoDom} {props.collapsed ? null : titleDom} ); }; export const defaultRenderCollapsedButton = (collapsed?: boolean): VueNode => collapsed ? ( ) : ( ); const SiderMenu: FunctionalComponent = ( props: SiderMenuProps, ) => { const { collapsed, siderWidth, breakpoint, collapsedWidth = 48, menuExtraRender = false, menuContentRender = false, collapsedButtonRender = defaultRenderCollapsedButton, theme, } = props; const context = useRouteContext(); const { getPrefixCls } = context; const baseClassName = getPrefixCls('sider'); const hasSplitMenu = computed( () => props.layout === 'mix' && props.splitMenus, ); const sSideWidth = computed(() => props.collapsed ? props.collapsedWidth : props.siderWidth, ); const classNames = computed(() => { return { [baseClassName]: true, [`${baseClassName}-fixed`]: context.fixSiderbar, [`${baseClassName}-${theme}`]: true, // theme !== 'dark' [`${baseClassName}-layout-${props.layout}`]: props.layout, }; }); const handleSelect = ($event: string[]) => { if (props.onSelect) { if (unref(hasSplitMenu)) { props.onSelect([context.selectedKeys[0], ...$event]); return; } props.onSelect($event); } }; const headerDom = defaultRenderLogoAndTitle(props); const extraDom = menuExtraRender && menuExtraRender(props); if (hasSplitMenu.value && unref(context.flatMenuData).length === 0) { return null; } const defaultMenuDom = ( props.onOpenKeys && props.onOpenKeys($event), 'onUpdate:selectedKeys': handleSelect, }} /> ); return ( <> {context.fixSiderbar && (
)} { props.onCollapse?.(collapse); }} collapsedWidth={collapsedWidth} style={{ overflow: 'hidden', paddingTop: `${props.headerHeight}px`, }} width={siderWidth} theme={theme} class={classNames.value} > {headerDom && ( )} {extraDom && !props.collapsed && (
{extraDom}
)}
{(menuContentRender && menuContentRender(props, defaultMenuDom)) || defaultMenuDom}
{collapsedButtonRender !== false ? ( { if (props.onCollapse) { props.onCollapse(!props.collapsed); } }} > {collapsedButtonRender && typeof collapsedButtonRender === 'function' ? collapsedButtonRender(collapsed) : collapsedButtonRender} ) : null}
); }; export default SiderMenu;