diff --git a/components/_util/hooks/useConfigInject.ts b/components/_util/hooks/useConfigInject.ts index c804f3031..77655efd4 100644 --- a/components/_util/hooks/useConfigInject.ts +++ b/components/_util/hooks/useConfigInject.ts @@ -1,8 +1,26 @@ -import { computed, inject } from 'vue'; -import { defaultConfigProvider } from '../../config-provider'; +import { computed, ComputedRef, inject, UnwrapRef } from 'vue'; +import { + ConfigProviderProps, + defaultConfigProvider, + Direction, + SizeType, +} from '../../config-provider'; -export default (name: string, props: Record) => { - const configProvider = inject('configProvider', defaultConfigProvider); +export default ( + name: string, + props: Record, +): { + configProvider: UnwrapRef; + prefixCls: ComputedRef; + direction: ComputedRef; + size: ComputedRef; +} => { + const configProvider = inject>( + 'configProvider', + defaultConfigProvider, + ); const prefixCls = computed(() => configProvider.getPrefixCls(name, props.prefixCls)); - return { configProvider, prefixCls }; + const direction = computed(() => configProvider.direction); + const size = computed(() => props.size || configProvider.componentSize); + return { configProvider, prefixCls, direction, size }; }; diff --git a/components/_util/hooks/usePrefixCls.ts b/components/_util/hooks/usePrefixCls.ts new file mode 100644 index 000000000..5f653be67 --- /dev/null +++ b/components/_util/hooks/usePrefixCls.ts @@ -0,0 +1,8 @@ +import { computed, ComputedRef, inject } from 'vue'; +import { defaultConfigProvider } from '../../config-provider'; + +export default (name: string, props: Record): ComputedRef => { + const configProvider = inject('configProvider', defaultConfigProvider); + const prefixCls = computed(() => configProvider.getPrefixCls(name, props.prefixCls)); + return prefixCls; +}; diff --git a/components/_util/responsiveObserve.ts b/components/_util/responsiveObserve.ts index ba27e1e0a..2d15daccf 100644 --- a/components/_util/responsiveObserve.ts +++ b/components/_util/responsiveObserve.ts @@ -1,5 +1,5 @@ export type Breakpoint = 'xxl' | 'xl' | 'lg' | 'md' | 'sm' | 'xs'; -export type BreakpointMap = Partial>; +export type BreakpointMap = Record; export type ScreenMap = Partial>; export type ScreenSizeMap = Partial>; @@ -44,7 +44,7 @@ const responsiveObserve = { }, unregister() { Object.keys(responsiveMap).forEach((screen: string) => { - const matchMediaQuery = responsiveMap[screen]!; + const matchMediaQuery = responsiveMap[screen]; const handler = this.matchHandlers[matchMediaQuery]; handler?.mql.removeListener(handler?.listener); }); @@ -52,7 +52,7 @@ const responsiveObserve = { }, register() { Object.keys(responsiveMap).forEach((screen: string) => { - const matchMediaQuery = responsiveMap[screen]!; + const matchMediaQuery = responsiveMap[screen]; const listener = ({ matches }: { matches: boolean }) => { this.dispatch({ ...screens, diff --git a/components/avatar/Avatar.tsx b/components/avatar/Avatar.tsx index 85446b0aa..46b6dbe12 100644 --- a/components/avatar/Avatar.tsx +++ b/components/avatar/Avatar.tsx @@ -22,7 +22,7 @@ export type AvatarSize = 'large' | 'small' | 'default' | number | ScreenSizeMap; export const avatarProps = { prefixCls: PropTypes.string, - shape: PropTypes.oneOf(tuple('circle', 'square')), + shape: PropTypes.oneOf(tuple('circle', 'square')).def('circle'), size: { type: [Number, String, Object] as PropType, default: (): AvatarSize => 'default', diff --git a/components/avatar/Group.tsx b/components/avatar/Group.tsx index eda441ed6..72b54c4c6 100644 --- a/components/avatar/Group.tsx +++ b/components/avatar/Group.tsx @@ -1,20 +1,11 @@ -import toArray from 'lodash/toArray'; import { cloneElement } from '../_util/vnode'; -import { defaultConfigProvider } from '../config-provider'; -import Avatar, { avatarProps } from './Avatar'; +import Avatar, { avatarProps, AvatarSize } from './Avatar'; import Popover from '../popover'; -import { - computed, - defineComponent, - inject, - provide, - PropType, - ExtractPropTypes, - CSSProperties, -} from 'vue'; +import { defineComponent, provide, PropType, ExtractPropTypes, CSSProperties } from 'vue'; import PropTypes from '../_util/vue-types'; -import { getPropsSlot } from '../_util/props-util'; +import { flattenChildren, getPropsSlot } from '../_util/props-util'; import { tuple } from '../_util/type'; +import useConfigInject from '../_util/hooks/useConfigInject'; const groupProps = { prefixCls: PropTypes.string, @@ -31,39 +22,30 @@ const groupProps = { size: avatarProps.size, }; -export type AvatarGroupProps = Partial>; +export type AvatarGroupProps = Partial> & { + size?: AvatarSize; +}; const Group = defineComponent({ name: 'AAvatarGroup', props: groupProps, inheritAttrs: false, setup(props, { slots, attrs }) { - const configProvider = inject('configProvider', defaultConfigProvider); + const { prefixCls, direction, size } = useConfigInject('avatar-group', props); - provide( - 'SizeProvider', - computed(() => props.size || configProvider.componentSize), - ); + provide('SizeProvider', size); return () => { - const { - prefixCls: customizePrefixCls, - maxPopoverPlacement = 'top', - maxCount, - maxStyle, - } = props; - - const { getPrefixCls } = configProvider; - const prefixCls = getPrefixCls('avatar-group', customizePrefixCls); - const className = attrs.class as string; + const { maxPopoverPlacement = 'top', maxCount, maxStyle } = props; const cls = { - [prefixCls]: true, - [className]: className !== undefined, + [prefixCls.value]: true, + [`${prefixCls.value}-rtl`]: direction.value === 'rtl', + [`${attrs.class}`]: !!attrs.class, }; const children = getPropsSlot(slots, props); - const childrenWithProps = toArray(children).map((child, index) => + const childrenWithProps = flattenChildren(children).map((child, index) => cloneElement(child, { key: `avatar-key-${index}`, }), @@ -80,20 +62,20 @@ const Group = defineComponent({ content={childrenHidden} trigger="hover" placement={maxPopoverPlacement} - overlayClassName={`${prefixCls}-popover`} + overlayClassName={`${prefixCls.value}-popover`} > {`+${numOfChildren - maxCount}`} , ); return ( -
+
{childrenShow}
); } return ( -
+
{childrenWithProps}
); diff --git a/components/avatar/style/index.less b/components/avatar/style/index.less index e039ef893..62c158384 100644 --- a/components/avatar/style/index.less +++ b/components/avatar/style/index.less @@ -19,6 +19,10 @@ background: transparent; } + .@{ant-prefix}-image-img { + display: block; + } + .avatar-size(@avatar-size-base, @avatar-font-size-base); &-lg { @@ -55,7 +59,12 @@ &.@{avatar-prefix-cls}-icon { font-size: @font-size; + + > .@{iconfont-css-prefix} { + margin: 0; + } } } @import './group'; +@import './rtl'; diff --git a/components/avatar/style/rtl.less b/components/avatar/style/rtl.less new file mode 100644 index 000000000..ba3e2d4d6 --- /dev/null +++ b/components/avatar/style/rtl.less @@ -0,0 +1,15 @@ +.@{avatar-prefix-cls}-group { + &-rtl { + .@{avatar-prefix-cls}:not(:first-child) { + margin-right: @avatar-group-overlapping; + margin-left: 0; + } + } + + &-popover.@{ant-prefix}-popover-rtl { + .@{ant-prefix}-avatar + .@{ant-prefix}-avatar { + margin-right: @avatar-group-space; + margin-left: 0; + } + } +} diff --git a/components/config-provider/index.tsx b/components/config-provider/index.tsx index 55c31214a..8a85799df 100644 --- a/components/config-provider/index.tsx +++ b/components/config-provider/index.tsx @@ -1,4 +1,12 @@ -import { reactive, provide, PropType, defineComponent, watch, ExtractPropTypes } from 'vue'; +import { + reactive, + provide, + PropType, + defineComponent, + watch, + ExtractPropTypes, + UnwrapRef, +} from 'vue'; import PropTypes from '../_util/vue-types'; import defaultRenderEmpty, { RenderEmptyHandler } from './renderEmpty'; import LocaleProvider, { Locale, ANT_MARK } from '../locale-provider'; @@ -14,6 +22,8 @@ export interface CSPConfig { export { RenderEmptyHandler }; +export type Direction = 'ltr' | 'rtl'; + export interface ConfigConsumerProps { getTargetContainer?: () => HTMLElement; getPopupContainer?: (triggerNode: HTMLElement) => HTMLElement; @@ -146,13 +156,13 @@ const ConfigProvider = defineComponent({ }, }); -export const defaultConfigProvider: ConfigProviderProps = { +export const defaultConfigProvider: UnwrapRef = reactive({ getPrefixCls: (suffixCls: string, customizePrefixCls?: string) => { if (customizePrefixCls) return customizePrefixCls; return `ant-${suffixCls}`; }, renderEmpty: defaultRenderEmpty, direction: 'ltr', -}; +}); export default withInstall(ConfigProvider);