import { computed, reactive, unref, defineComponent, toRefs, provide } from 'vue' import type { DefineComponent, ExtractPropTypes, PropType, CSSProperties, Plugin, App } from 'vue' import { Layout } from 'ant-design-vue' import useConfigInject from 'ant-design-vue/es/_util/hooks/useConfigInject' import { defaultSettingProps, defaultSettings } from './defaultSetting' import type { PureSettings } from './defaultSetting' import type { BreadcrumbProps, RouteContextProps } from './RouteContext' import type { BreadcrumbRender, CollapsedButtonRender, CustomRender, FooterRender, HeaderContentRender, HeaderRender, MenuContentRender, MenuExtraRender, MenuFooterRender, MenuHeaderRender, MenuItemRender, RightContentRender, SubMenuItemRender } from './typings' import SiderMenuWrapper, { siderMenuProps } from 'components/Layout/components/SiderMenu/SiderMenu' import { getSlot } from '@/utils/comm' import { getMenuFirstChildren } from 'components/Layout/utils' import { pick } from 'lodash-es' import { routeContextInjectKey } from './RouteContext' import { HeaderView, headerViewProps } from './components/Header' export const basicLayoutProps = { ...defaultSettingProps, ...siderMenuProps, ...headerViewProps, breadcrumb: { type: [Object, Function] as PropType, default: () => null }, breadcrumbRender: { type: [Object, Function, Boolean] as PropType, default() { return null } }, contentStyle: { type: [String, Object] as PropType, default: () => { return null } }, pure: { type: Boolean, default: () => false } } export type BasicLayoutProps = Partial>; export default defineComponent({ name: 'ProLayout', inheritAttrs: false, props: basicLayoutProps, emits: [ 'update:collapsed', 'update:open-keys', 'update:selected-keys', 'collapse', 'openKeys', 'select', 'menuHeaderClick', 'menuClick' ], setup(props, { emit, attrs, slots }) { const siderWidth = computed(() => (props.collapsed ? props.collapsedWidth : props.siderWidth)) const onCollapse = (collapsed: boolean) => { emit('update:collapsed', collapsed) emit('collapse', collapsed) } const onOpenKeys = (openKeys: string[] | false) => { emit('update:open-keys', openKeys) emit('openKeys', openKeys) } const onSelect = (selectedKeys: string[] | false) => { emit('update:selected-keys', selectedKeys) emit('select', selectedKeys) } const onMenuHeaderClick = (e: MouseEvent) => { emit('menuHeaderClick', e) } const onMenuClick = (args: any) => { emit('menuClick', args) } const headerRender = ( p: BasicLayoutProps & { hasSiderMenu: boolean; headerRender: HeaderRender; rightContentRender: RightContentRender; }, matchMenuKeys?: string[] ): CustomRender | null => { if (p.headerRender === false) { return null } return } const breadcrumb = computed(() => ({ ...props.breadcrumb, itemRender: getSlot(slots, props, 'breadcrumbRender') as BreadcrumbRender })) const flatMenuData = computed( () => (props.selectedKeys && getMenuFirstChildren(props.menuData, props.selectedKeys[0])) || []) const routeContext = reactive({ ...(pick(toRefs(props), [ 'menuData', 'openKeys', 'selectedKeys', 'contentWidth', 'headerHeight' ]) as any), siderWidth, breadcrumb, flatMenuData }) provide(routeContextInjectKey, routeContext) return () => { const { pure, onCollapse: propsOnCollapse, onOpenKeys: propsOnOpenKeys, onSelect: propsOnSelect, onMenuClick: propsOnMenuClick, ...restProps } = props const collapsedButtonRender = getSlot(slots, props, 'collapsedButtonRender') const rightContentRender = getSlot(slots, props, 'rightContentRender') const customHeaderRender = getSlot(slots, props, 'headerRender') // menu const menuHeaderRender = getSlot(slots, props, 'menuHeaderRender') const menuExtraRender = getSlot(slots, props, 'menuExtraRender') const menuContentRender = getSlot(slots, props, 'menuContentRender') const menuItemRender = getSlot(slots, props, 'menuItemRender') const subMenuItemRender = getSlot(slots, props, 'subMenuItemRender') const headerDom = computed(() => headerRender( { ...props, hasSiderMenu: true, menuItemRender, subMenuItemRender, menuData: props.menuData, onCollapse, onOpenKeys, onSelect, onMenuHeaderClick, rightContentRender, collapsedButtonRender, menuExtraRender, menuContentRender, headerRender: customHeaderRender, theme: props.navTheme }, [] ) ) return ( <> { pure ? ( slots.default?.() ) : ( {headerDom.value} {slots.default?.()} ) } ) } } })