refactor: avatar

feat-new-menu
tanjinzhou 2021-05-12 21:06:53 +08:00
parent 0984951845
commit 4a5c4cdeb7
8 changed files with 89 additions and 47 deletions

View File

@ -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<any, any>) => {
const configProvider = inject('configProvider', defaultConfigProvider);
export default (
name: string,
props: Record<any, any>,
): {
configProvider: UnwrapRef<ConfigProviderProps>;
prefixCls: ComputedRef<string>;
direction: ComputedRef<Direction>;
size: ComputedRef<SizeType>;
} => {
const configProvider = inject<UnwrapRef<ConfigProviderProps>>(
'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 };
};

View File

@ -0,0 +1,8 @@
import { computed, ComputedRef, inject } from 'vue';
import { defaultConfigProvider } from '../../config-provider';
export default (name: string, props: Record<any, any>): ComputedRef<string> => {
const configProvider = inject('configProvider', defaultConfigProvider);
const prefixCls = computed(() => configProvider.getPrefixCls(name, props.prefixCls));
return prefixCls;
};

View File

@ -1,5 +1,5 @@
export type Breakpoint = 'xxl' | 'xl' | 'lg' | 'md' | 'sm' | 'xs';
export type BreakpointMap = Partial<Record<Breakpoint, string>>;
export type BreakpointMap = Record<Breakpoint, string>;
export type ScreenMap = Partial<Record<Breakpoint, boolean>>;
export type ScreenSizeMap = Partial<Record<Breakpoint, number>>;
@ -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,

View File

@ -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<AvatarSize>,
default: (): AvatarSize => 'default',

View File

@ -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<ExtractPropTypes<typeof groupProps>>;
export type AvatarGroupProps = Partial<ExtractPropTypes<typeof groupProps>> & {
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`}
>
<Avatar style={maxStyle}>{`+${numOfChildren - maxCount}`}</Avatar>
</Popover>,
);
return (
<div class={cls} style={attrs.style}>
<div {...attrs} class={cls} style={attrs.style}>
{childrenShow}
</div>
);
}
return (
<div class={cls} style={attrs.style}>
<div {...attrs} class={cls} style={attrs.style}>
{childrenWithProps}
</div>
);

View File

@ -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';

View File

@ -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;
}
}
}

View File

@ -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<ConfigProviderProps> = reactive({
getPrefixCls: (suffixCls: string, customizePrefixCls?: string) => {
if (customizePrefixCls) return customizePrefixCls;
return `ant-${suffixCls}`;
},
renderEmpty: defaultRenderEmpty,
direction: 'ltr',
};
});
export default withInstall(ConfigProvider);