import type { ExtractPropTypes, PropType } from 'vue'; import { defineComponent, ref, computed } from 'vue'; import PropTypes from '../_util/vue-types'; import { filterEmpty, flattenChildren, isEmptyContent } from '../_util/props-util'; import ArrowLeftOutlined from '@ant-design/icons-vue/ArrowLeftOutlined'; import ArrowRightOutlined from '@ant-design/icons-vue/ArrowRightOutlined'; import Breadcrumb from '../breadcrumb'; import Avatar from '../avatar'; import TransButton from '../_util/transButton'; import LocaleReceiver from '../locale-provider/LocaleReceiver'; import { withInstall } from '../_util/type'; import useConfigInject from '../_util/hooks/useConfigInject'; import classNames from '../_util/classNames'; import ResizeObserver from '../vc-resize-observer'; import useDestroyed from '../_util/hooks/useDestroyed'; import type { MouseEventHandler } from '../_util/EventInterface'; export const pageHeaderProps = () => ({ backIcon: PropTypes.any, prefixCls: String, title: PropTypes.any, subTitle: PropTypes.any, breadcrumb: PropTypes.object, tags: PropTypes.any, footer: PropTypes.any, extra: PropTypes.any, avatar: PropTypes.object, ghost: { type: Boolean, default: undefined }, onBack: Function as PropType, }); export type PageHeaderProps = Partial>>; const PageHeader = defineComponent({ name: 'APageHeader', props: pageHeaderProps(), // emits: ['back'], slots: ['backIcon', 'avatar', 'breadcrumb', 'title', 'subTitle', 'tags', 'extra', 'footer'], setup(props, { emit, slots }) { const { prefixCls, direction, pageHeader } = useConfigInject('page-header', props); const compact = ref(false); const isDestroyed = useDestroyed(); const onResize = ({ width }: { width: number }) => { if (!isDestroyed.value) { compact.value = width < 768; } }; const ghost = computed(() => props.ghost ?? pageHeader.value?.ghost ?? true); const getBackIcon = () => { return ( props.backIcon ?? slots.backIcon?.() ?? (direction.value === 'rtl' ? : ) ); }; const renderBack = (backIcon: any) => { if (!backIcon || !props.onBack) { return null; } return ( (
{ emit('back', e); }} class={`${prefixCls.value}-back-button`} aria-label={back} > {backIcon}
)} >
); }; const renderBreadcrumb = () => { return props.breadcrumb ? : slots.breadcrumb?.(); }; const renderTitle = () => { const { avatar } = props; const title = props.title ?? slots.title?.(); const subTitle = props.subTitle ?? slots.subTitle?.(); const tags = props.tags ?? slots.tags?.(); const extra = props.extra ?? slots.extra?.(); const headingPrefixCls = `${prefixCls.value}-heading`; const hasHeading = title || subTitle || tags || extra; // If there is nothing, return a null if (!hasHeading) { return null; } const backIcon = getBackIcon(); const backIconDom = renderBack(backIcon); const hasTitle = backIconDom || avatar || hasHeading; return (
{hasTitle && (
{backIconDom} {avatar ? : slots.avatar?.()} {title && ( {title} )} {subTitle && ( {subTitle} )} {tags && {tags}}
)} {extra && {extra}}
); }; const renderFooter = () => { const footer = props.footer ?? filterEmpty(slots.footer?.()); return isEmptyContent(footer) ? null : (
{footer}
); }; const renderChildren = (children: any) => { return
{children}
; }; return () => { const hasBreadcrumb = props.breadcrumb?.routes || slots.breadcrumb; const hasFooter = props.footer || slots.footer; const children = flattenChildren(slots.default?.()); const className = classNames(prefixCls.value, { 'has-breadcrumb': hasBreadcrumb, 'has-footer': hasFooter, [`${prefixCls.value}-ghost`]: ghost.value, [`${prefixCls.value}-rtl`]: direction.value === 'rtl', [`${prefixCls.value}-compact`]: compact.value, }); return (
{renderBreadcrumb()} {renderTitle()} {children.length ? renderChildren(children) : null} {renderFooter()}
); }; }, }); export default withInstall(PageHeader);