import { createVNode, defineComponent, inject, provide, toRefs, ref, ExtractPropTypes, HTMLAttributes, } from 'vue'; import PropTypes from '../_util/vue-types'; import classNames from '../_util/classNames'; import { defaultConfigProvider } from '../config-provider'; import { flattenChildren } from '../_util/props-util'; export const basicProps = { prefixCls: PropTypes.string, hasSider: PropTypes.looseBool, tagName: PropTypes.string, }; export type BasicProps = Partial> & HTMLAttributes; export interface SiderHookProvider { addSider?: (id: string) => void; removeSider?: (id: string) => void; } type GeneratorArgument = { suffixCls: string; tagName: string; name: string; }; function generator({ suffixCls, tagName, name }: GeneratorArgument) { return (BasicComponent: typeof Basic) => { const Adapter = defineComponent({ name, setup(props, { slots }) { const { getPrefixCls } = inject('configProvider', defaultConfigProvider); return () => { const { prefixCls: customizePrefixCls } = props; const prefixCls = getPrefixCls(suffixCls, customizePrefixCls); const basicComponentProps = { prefixCls, ...props, tagName, }; return ( {flattenChildren(slots.default?.())} ); }; }, }); Adapter.props = basicProps; return Adapter; }; } const Basic = defineComponent({ props: basicProps, setup(props, { slots }) { const { prefixCls, tagName } = toRefs(props); return () => createVNode(tagName.value, { class: prefixCls.value }, slots.default?.()); }, }); const BasicLayout = defineComponent({ props: basicProps, setup(props, { slots }) { const siders = ref([]); const siderHookProvider: SiderHookProvider = { addSider: id => { siders.value = [...siders.value, id]; }, removeSider: id => { siders.value = siders.value.filter(currentId => currentId !== id); }, }; provide('siderHook', siderHookProvider); return () => { const { prefixCls, hasSider, tagName } = props; const divCls = classNames(prefixCls, { [`${prefixCls}-has-sider`]: typeof hasSider === 'boolean' ? hasSider : siders.value.length > 0, }); return createVNode(tagName, { class: divCls }, slots.default?.()); }; }, }); const Layout = generator({ suffixCls: 'layout', tagName: 'section', name: 'ALayout', })(BasicLayout); const Header = generator({ suffixCls: 'layout-header', tagName: 'header', name: 'ALayoutHeader', })(Basic); const Footer = generator({ suffixCls: 'layout-footer', tagName: 'footer', name: 'ALayoutFooter', })(Basic); const Content = generator({ suffixCls: 'layout-content', tagName: 'main', name: 'ALayoutContent', })(Basic); Layout.Header = Header; Layout.Footer = Footer; Layout.Content = Content; export default Layout as typeof Layout & { readonly Header: typeof Header; readonly Footer: typeof Footer; readonly Content: typeof Content; };