111 lines
		
	
	
		
			2.9 KiB
		
	
	
	
		
			TypeScript
		
	
	
			
		
		
	
	
			111 lines
		
	
	
		
			2.9 KiB
		
	
	
	
		
			TypeScript
		
	
	
| import { createVNode, defineComponent, inject, provide, toRefs, ref } from 'vue';
 | |
| import PropTypes from '../_util/vue-types';
 | |
| import classNames from '../_util/classNames';
 | |
| import { defaultConfigProvider } from '../config-provider';
 | |
| 
 | |
| export const BasicProps = {
 | |
|   prefixCls: PropTypes.string,
 | |
|   hasSider: PropTypes.looseBool,
 | |
|   tagName: PropTypes.string,
 | |
| };
 | |
| 
 | |
| 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) => {
 | |
|     return defineComponent({
 | |
|       name,
 | |
|       props: BasicProps,
 | |
|       setup(props, { slots }) {
 | |
|         const { getPrefixCls } = inject('configProvider', defaultConfigProvider);
 | |
|         return () => {
 | |
|           const { prefixCls: customizePrefixCls } = props;
 | |
|           const prefixCls = getPrefixCls(suffixCls, customizePrefixCls);
 | |
|           const basicComponentProps = {
 | |
|             prefixCls,
 | |
|             ...props,
 | |
|             tagName,
 | |
|           };
 | |
|           return <BasicComponent {...basicComponentProps}>{slots.default?.()}</BasicComponent>;
 | |
|         };
 | |
|       },
 | |
|     });
 | |
|   };
 | |
| }
 | |
| 
 | |
| 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<string[]>([]);
 | |
|     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;
 | |
| };
 |