diff --git a/components/page-header/index.tsx b/components/page-header/index.tsx index 604de2874..5c2148c12 100644 --- a/components/page-header/index.tsx +++ b/components/page-header/index.tsx @@ -1,15 +1,18 @@ -import { defineComponent, inject, VNodeTypes, ExtractPropTypes } from 'vue'; +import { defineComponent, ExtractPropTypes, ref, computed } from 'vue'; import PropTypes from '../_util/vue-types'; -import { getComponent, getOptionProps, getSlot } from '../_util/props-util'; -import { defaultConfigProvider } from '../config-provider'; +import { flattenChildren } 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'; -export const PageHeaderProps = { +export const pageHeaderProps = { backIcon: PropTypes.VNodeChild, prefixCls: PropTypes.string, title: PropTypes.VNodeChild, @@ -23,121 +26,131 @@ export const PageHeaderProps = { onBack: PropTypes.func, }; -const renderBack = ( - instance: any, - prefixCls: string, - backIcon: VNodeTypes, - onBack: (e: HTMLElement) => void, -) => { - if (!backIcon || !onBack) { - return null; - } - return ( - ( -
- { - instance.$emit('back', e); - }} - class={`${prefixCls}-back-button`} - aria-label={back} - > - {backIcon} - -
- )} - >
- ); -}; - -const renderBreadcrumb = (breadcrumb: any) => { - return ; -}; - -const renderTitle = (prefixCls: string, instance: any) => { - const { avatar } = instance; - const title = getComponent(instance, 'title'); - const subTitle = getComponent(instance, 'subTitle'); - const tags = getComponent(instance, 'tags'); - const extra = getComponent(instance, 'extra'); - const backIcon = - getComponent(instance, 'backIcon') !== undefined ? ( - getComponent(instance, 'backIcon') - ) : ( - - ); - const onBack = instance.onBack; - const headingPrefixCls = `${prefixCls}-heading`; - if (title || subTitle || tags || extra) { - const backIconDom = renderBack(instance, prefixCls, backIcon, onBack); - return ( -
- {backIconDom} - {avatar && } - {title && {title}} - {subTitle && {subTitle}} - {tags && {tags}} - {extra && {extra}} -
- ); - } - return null; -}; - -const renderFooter = (prefixCls: string, footer: VNodeTypes) => { - if (footer) { - return
{footer}
; - } - return null; -}; - -const renderChildren = (prefixCls: string, children: VNodeTypes) => { - return
{children}
; -}; +export type PageHeaderProps = Partial>; const PageHeader = defineComponent({ name: 'APageHeader', - props: PageHeaderProps, - setup() { - return { - configProvider: inject('configProvider', defaultConfigProvider), + 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 onResize = ({ width }: { width: number }) => { + compact.value = width < 768; }; - }, - render() { - const { getPrefixCls, pageHeader } = this.configProvider; - const props = getOptionProps(this) as ExtractPropTypes; - const { prefixCls: customizePrefixCls, breadcrumb } = props; - const footer = getComponent(this, 'footer'); - const children = getSlot(this); - let ghost = true; + const ghost = computed(() => props.ghost ?? pageHeader.value?.ghost ?? false); - // 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 breadcrumbDom = breadcrumb && breadcrumb.routes ? renderBreadcrumb(breadcrumb) : null; - const className = [ - prefixCls, - { - 'has-breadcrumb': breadcrumbDom, - 'has-footer': footer, - [`${prefixCls}-ghost`]: ghost, - }, - ]; + const getBackIcon = () => { + return ( + props.backIcon ?? + slots.backIcon?.() ?? + (direction.value === 'rtl' ? : ) + ); + }; - return ( -
- {breadcrumbDom} - {renderTitle(prefixCls, this)} - {children.length ? renderChildren(prefixCls, children) : null} - {renderFooter(prefixCls, footer)} -
- ); + 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 = () => { + return
{props.footer ?? slots.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)} + {renderFooter()} +
+
+ ); + }; }, }); diff --git a/components/vc-resize-observer/index.tsx b/components/vc-resize-observer/index.tsx index 723f0af52..c6e0f0e36 100644 --- a/components/vc-resize-observer/index.tsx +++ b/components/vc-resize-observer/index.tsx @@ -18,7 +18,7 @@ interface ResizeObserverState { offsetWidth: number; } -const VueResizeObserver = defineComponent({ +const ResizeObserver = defineComponent({ name: 'ResizeObserver', props: { disabled: Boolean, @@ -110,7 +110,7 @@ const VueResizeObserver = defineComponent({ } if (!resizeObserver && element) { - resizeObserver = new ResizeObserver(onResize); + resizeObserver = new window.ResizeObserver(onResize); resizeObserver.observe(element); } }; @@ -136,4 +136,4 @@ const VueResizeObserver = defineComponent({ }, }); -export default VueResizeObserver; +export default ResizeObserver;