import classNames from 'classnames'; import omit from 'rc-util/lib/omit'; import * as React from 'react'; import { ConfigContext } from '../config-provider'; import useStyle from './style'; export interface GeneratorProps { suffixCls?: string; tagName: 'header' | 'footer' | 'main' | 'section'; displayName: string; } export interface BasicProps extends React.HTMLAttributes { prefixCls?: string; suffixCls?: string; rootClassName?: string; hasSider?: boolean; } export interface LayoutContextProps { siderHook: { addSider: (id: string) => void; removeSider: (id: string) => void; }; } export const LayoutContext = React.createContext({ siderHook: { addSider: () => null, removeSider: () => null, }, }); interface BasicPropsWithTagName extends BasicProps { tagName: 'header' | 'footer' | 'main' | 'section'; } function generator({ suffixCls, tagName, displayName }: GeneratorProps) { return (BasicComponent: any) => { const Adapter = React.forwardRef((props, ref) => ( )); if (process.env.NODE_ENV !== 'production') { Adapter.displayName = displayName; } return Adapter; }; } const Basic = React.forwardRef((props, ref) => { const { prefixCls: customizePrefixCls, suffixCls, className, tagName: TagName, ...others } = props; const { getPrefixCls } = React.useContext(ConfigContext); const prefixCls = getPrefixCls('layout', customizePrefixCls); const [wrapSSR, hashId] = useStyle(prefixCls); const prefixWithSuffixCls = suffixCls ? `${prefixCls}-${suffixCls}` : prefixCls; return wrapSSR( , ); }); const BasicLayout = React.forwardRef((props, ref) => { const { direction } = React.useContext(ConfigContext); const [siders, setSiders] = React.useState([]); const { prefixCls: customizePrefixCls, className, rootClassName, children, hasSider, tagName: Tag, style, ...others } = props; const passedProps = omit(others, ['suffixCls']); const { getPrefixCls, layout } = React.useContext(ConfigContext); const prefixCls = getPrefixCls('layout', customizePrefixCls); const [wrapSSR, hashId] = useStyle(prefixCls); const classString = classNames( prefixCls, { [`${prefixCls}-has-sider`]: typeof hasSider === 'boolean' ? hasSider : siders.length > 0, [`${prefixCls}-rtl`]: direction === 'rtl', }, layout?.className, className, rootClassName, hashId, ); const contextValue = React.useMemo( () => ({ siderHook: { addSider: (id: string) => { setSiders((prev) => [...prev, id]); }, removeSider: (id: string) => { setSiders((prev) => prev.filter((currentId) => currentId !== id)); }, }, }), [], ); return wrapSSR( {children} , ); }); const Layout = generator({ tagName: 'section', displayName: 'Layout', })(BasicLayout); const Header = generator({ suffixCls: 'header', tagName: 'header', displayName: 'Header', })(Basic); const Footer = generator({ suffixCls: 'footer', tagName: 'footer', displayName: 'Footer', })(Basic); const Content = generator({ suffixCls: 'content', tagName: 'main', displayName: 'Content', })(Basic); export { Content, Footer, Header }; export default Layout;