import * as React from 'react'; import classNames from 'classnames'; import useState from 'rc-util/lib/hooks/useState'; import ArrowLeftOutlined from '@ant-design/icons/ArrowLeftOutlined'; import ArrowRightOutlined from '@ant-design/icons/ArrowRightOutlined'; import ResizeObserver from 'rc-resize-observer'; import { ConfigConsumer, ConfigConsumerProps, DirectionType } from '../config-provider'; import { TagType } from '../tag'; import Breadcrumb, { BreadcrumbProps } from '../breadcrumb'; import Avatar, { AvatarProps } from '../avatar'; import Space from '../space'; import TransButton from '../_util/transButton'; import LocaleReceiver from '../locale-provider/LocaleReceiver'; export interface PageHeaderProps { backIcon?: React.ReactNode; prefixCls?: string; title?: React.ReactNode; subTitle?: React.ReactNode; style?: React.CSSProperties; breadcrumb?: BreadcrumbProps | React.ReactElement; breadcrumbRender?: (props: PageHeaderProps, defaultDom: React.ReactNode) => React.ReactNode; tags?: React.ReactElement | React.ReactElement[]; footer?: React.ReactNode; extra?: React.ReactNode; avatar?: AvatarProps; onBack?: (e?: React.MouseEvent) => void; className?: string; ghost?: boolean; } const renderBack = ( prefixCls: string, backIcon?: React.ReactNode, onBack?: (e?: React.MouseEvent) => void, ) => { if (!backIcon || !onBack) { return null; } return ( {({ back }: { back: string }) => (
) => { onBack?.(e); }} className={`${prefixCls}-back-button`} aria-label={back} > {backIcon}
)}
); }; const renderBreadcrumb = (breadcrumb: BreadcrumbProps) => ; const getBackIcon = (props: PageHeaderProps, direction: DirectionType = 'ltr') => { if (props.backIcon !== undefined) { return props.backIcon; } return direction === 'rtl' ? : ; }; const renderTitle = ( prefixCls: string, props: PageHeaderProps, direction: DirectionType = 'ltr', ) => { const { title, avatar, subTitle, tags, extra, onBack } = props; const headingPrefixCls = `${prefixCls}-heading`; const hasHeading = title || subTitle || tags || extra; // If there is nothing, return a null if (!hasHeading) { return null; } const backIcon = getBackIcon(props, direction); const backIconDom = renderBack(prefixCls, backIcon, onBack); const hasTitle = backIconDom || avatar || hasHeading; return (
{hasTitle && (
{backIconDom} {avatar && } {title && ( {title} )} {subTitle && ( {subTitle} )} {tags && {tags}}
)} {extra && ( {extra} )}
); }; const renderFooter = (prefixCls: string, footer: React.ReactNode) => { if (footer) { return
{footer}
; } return null; }; const renderChildren = (prefixCls: string, children: React.ReactNode) => (
{children}
); const PageHeader: React.FC = props => { const [compact, updateCompact] = useState(false); const onResize = ({ width }: { width: number }) => { updateCompact(width < 768, true); }; return ( {({ getPrefixCls, pageHeader, direction }: ConfigConsumerProps) => { const { prefixCls: customizePrefixCls, style, footer, children, breadcrumb, breadcrumbRender, className: customizeClassName, } = props; let ghost: undefined | boolean = true; // Use `ghost` from `props` or from `ConfigProvider` instead. if ('ghost' in props) { ghost = props.ghost; } else if (pageHeader && 'ghost' in pageHeader) { ghost = pageHeader.ghost; } const prefixCls = getPrefixCls('page-header', customizePrefixCls); const getDefaultBreadcrumbDom = () => { if ((breadcrumb as BreadcrumbProps)?.routes) { return renderBreadcrumb(breadcrumb as BreadcrumbProps); } return null; }; const defaultBreadcrumbDom = getDefaultBreadcrumbDom(); const isBreadcrumbComponent = breadcrumb && 'props' in breadcrumb; // support breadcrumbRender function const breadcrumbRenderDomFromProps = breadcrumbRender?.(props, defaultBreadcrumbDom) ?? defaultBreadcrumbDom; const breadcrumbDom = isBreadcrumbComponent ? breadcrumb : breadcrumbRenderDomFromProps; const className = classNames(prefixCls, customizeClassName, { 'has-breadcrumb': !!breadcrumbDom, 'has-footer': !!footer, [`${prefixCls}-ghost`]: ghost, [`${prefixCls}-rtl`]: direction === 'rtl', [`${prefixCls}-compact`]: compact, }); return (
{breadcrumbDom} {renderTitle(prefixCls, props, direction)} {children && renderChildren(prefixCls, children)} {renderFooter(prefixCls, footer)}
); }}
); }; export default PageHeader;