import * as React from 'react'; import classNames from 'classnames'; 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 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; 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] = React.useState(false); const onResize = ({ width }: { width: number }) => { updateCompact(width < 768); }; 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(); // support breadcrumbRender function const breadcrumbDom = breadcrumbRender?.(props, defaultBreadcrumbDom) || defaultBreadcrumbDom; 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;