Skip to content

Commit

Permalink
Merge pull request ant-design#25817 from ant-design/resolve-conflict-1
Browse files Browse the repository at this point in the history
chore: merge feature into master
  • Loading branch information
07akioni authored Jul 26, 2020
2 parents 7dbe4fe + 9d49434 commit d857800
Show file tree
Hide file tree
Showing 84 changed files with 2,439 additions and 457 deletions.
1 change: 1 addition & 0 deletions .eslintignore
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@ lib/**/*
node_modules
_site
dist
coverage
**/*.d.ts
# Scripts
scripts/previewEditor/**/*
3 changes: 3 additions & 0 deletions components/_util/usePatchElement.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -7,8 +7,11 @@ export default function usePatchElement(): [
const [elements, setElements] = React.useState<React.ReactElement[]>([]);

function patchElement(element: React.ReactElement) {
// append a new element to elements (and create a new ref)
setElements(originElements => [...originElements, element]);

// return a function that removes the new element out of elements (and create a new ref)
// it works a little like useEffect
return () => {
setElements(originElements => originElements.filter(ele => ele !== element));
};
Expand Down
114 changes: 114 additions & 0 deletions components/avatar/__tests__/__snapshots__/demo.test.js.snap
Original file line number Diff line number Diff line change
Expand Up @@ -469,6 +469,120 @@ Array [
]
`;

exports[`renders ./components/avatar/demo/group.md correctly 1`] = `
Array [
<div
class="ant-avatar-group"
>
<span
class="ant-avatar ant-avatar-circle ant-avatar-image"
>
<img
src="https://zos.alipayobjects.com/rmsportal/ODTLcjxAfvqbxHnVXCYX.png"
/>
</span>
<span
class="ant-avatar ant-avatar-circle"
style="background-color:#f56a00"
>
<span
class="ant-avatar-string"
style="opacity:0"
>
K
</span>
</span>
<span
class="ant-avatar ant-avatar-circle ant-avatar-icon"
style="background-color:#87d068"
>
<span
aria-label="user"
class="anticon anticon-user"
role="img"
>
<svg
aria-hidden="true"
class=""
data-icon="user"
fill="currentColor"
focusable="false"
height="1em"
viewBox="64 64 896 896"
width="1em"
>
<path
d="M858.5 763.6a374 374 0 00-80.6-119.5 375.63 375.63 0 00-119.5-80.6c-.4-.2-.8-.3-1.2-.5C719.5 518 760 444.7 760 362c0-137-111-248-248-248S264 225 264 362c0 82.7 40.5 156 102.8 201.1-.4.2-.8.3-1.2.5-44.8 18.9-85 46-119.5 80.6a375.63 375.63 0 00-80.6 119.5A371.7 371.7 0 00136 901.8a8 8 0 008 8.2h60c4.4 0 7.9-3.5 8-7.8 2-77.2 33-149.5 87.8-204.3 56.7-56.7 132-87.9 212.2-87.9s155.5 31.2 212.2 87.9C779 752.7 810 825 812 902.2c.1 4.4 3.6 7.8 8 7.8h60a8 8 0 008-8.2c-1-47.8-10.9-94.3-29.5-138.2zM512 534c-45.9 0-89.1-17.9-121.6-50.4S340 407.9 340 362c0-45.9 17.9-89.1 50.4-121.6S466.1 190 512 190s89.1 17.9 121.6 50.4S684 316.1 684 362c0 45.9-17.9 89.1-50.4 121.6S557.9 534 512 534z"
/>
</svg>
</span>
</span>
<span
class="ant-avatar ant-avatar-circle ant-avatar-icon"
style="background-color:#1890ff"
>
<span
aria-label="ant-design"
class="anticon anticon-ant-design"
role="img"
>
<svg
aria-hidden="true"
class=""
data-icon="ant-design"
fill="currentColor"
focusable="false"
height="1em"
viewBox="64 64 896 896"
width="1em"
>
<path
d="M716.3 313.8c19-18.9 19-49.7 0-68.6l-69.9-69.9.1.1c-18.5-18.5-50.3-50.3-95.3-95.2-21.2-20.7-55.5-20.5-76.5.5L80.9 474.2a53.84 53.84 0 000 76.4L474.6 944a54.14 54.14 0 0076.5 0l165.1-165c19-18.9 19-49.7 0-68.6a48.7 48.7 0 00-68.7 0l-125 125.2c-5.2 5.2-13.3 5.2-18.5 0L189.5 521.4c-5.2-5.2-5.2-13.3 0-18.5l314.4-314.2c.4-.4.9-.7 1.3-1.1 5.2-4.1 12.4-3.7 17.2 1.1l125.2 125.1c19 19 49.8 19 68.7 0zM408.6 514.4a106.3 106.2 0 10212.6 0 106.3 106.2 0 10-212.6 0zm536.2-38.6L821.9 353.5c-19-18.9-49.8-18.9-68.7.1a48.4 48.4 0 000 68.6l83 82.9c5.2 5.2 5.2 13.3 0 18.5l-81.8 81.7a48.4 48.4 0 000 68.6 48.7 48.7 0 0068.7 0l121.8-121.7a53.93 53.93 0 00-.1-76.4z"
/>
</svg>
</span>
</span>
</div>,
<div
class="ant-divider ant-divider-horizontal"
role="separator"
/>,
<div
class="ant-avatar-group"
>
<span
class="ant-avatar ant-avatar-circle ant-avatar-image"
>
<img
src="https://zos.alipayobjects.com/rmsportal/ODTLcjxAfvqbxHnVXCYX.png"
/>
</span>
<span
class="ant-avatar ant-avatar-circle"
style="background-color:#f56a00"
>
<span
class="ant-avatar-string"
style="opacity:0"
>
K
</span>
</span>
<span
class="ant-avatar ant-avatar-circle"
style="color:#f56a00;background-color:#fde3cf"
>
<span
class="ant-avatar-string"
style="opacity:0"
>
+2
</span>
</span>
</div>,
]
`;

exports[`renders ./components/avatar/demo/fallback.md correctly 1`] = `
Array [
<span
Expand Down
213 changes: 213 additions & 0 deletions components/avatar/avatar.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,213 @@
import * as React from 'react';
import classNames from 'classnames';

import { ConfigContext } from '../config-provider';
import devWarning from '../_util/devWarning';
import { composeRef } from '../_util/ref';

export interface AvatarProps {
/** Shape of avatar, options:`circle`, `square` */
shape?: 'circle' | 'square';
/*
* Size of avatar, options: `large`, `small`, `default`
* or a custom number size
* */
size?: 'large' | 'small' | 'default' | number;
gap?: number;
/** Src of image avatar */
src?: string;
/** Srcset of image avatar */
srcSet?: string;
draggable?: boolean;
/** icon to be used in avatar */
icon?: React.ReactNode;
style?: React.CSSProperties;
prefixCls?: string;
className?: string;
children?: React.ReactNode;
alt?: string;
/* callback when img load error */
/* return false to prevent Avatar show default fallback behavior, then you can do fallback by your self */
onError?: () => boolean;
}

const InternalAvatar: React.ForwardRefRenderFunction<unknown, AvatarProps> = (props, ref) => {
const [scale, setScale] = React.useState(1);
const [mounted, setMounted] = React.useState(false);
const [isImgExist, setIsImgExist] = React.useState(true);

const avatarNodeRef = React.useRef<HTMLElement>();
const avatarChildrenRef = React.useRef<HTMLElement>();

const avatarNodeMergeRef = composeRef(ref, avatarNodeRef);

let lastChildrenWidth: number;
let lastNodeWidth: number;

const { getPrefixCls } = React.useContext(ConfigContext);

const setScaleParam = () => {
if (!avatarChildrenRef.current || !avatarNodeRef.current) {
return;
}
const childrenWidth = avatarChildrenRef.current.offsetWidth; // offsetWidth avoid affecting be transform scale
const nodeWidth = avatarNodeRef.current.offsetWidth;
const { gap = 4 } = props;
// denominator is 0 is no meaning
if (
childrenWidth !== 0 &&
nodeWidth !== 0 &&
(lastChildrenWidth !== childrenWidth || lastNodeWidth !== nodeWidth)
) {
lastChildrenWidth = childrenWidth;
lastNodeWidth = nodeWidth;
}

if (gap * 2 < nodeWidth) {
setScale(nodeWidth - gap * 2 < childrenWidth ? (nodeWidth - gap * 2) / childrenWidth : 1);
}
};

React.useEffect(() => {
setMounted(true);
}, []);

React.useEffect(() => {
setIsImgExist(true);
setScale(1);
}, [props.src]);

React.useEffect(() => {
setScaleParam();
}, [props.children, props.gap, props.size]);

React.useEffect(() => {
if (props.children) {
setScaleParam();
}
}, [isImgExist]);

const handleImgLoadError = () => {
const { onError } = props;
const errorFlag = onError ? onError() : undefined;
if (errorFlag !== false) {
setIsImgExist(false);
}
};

const {
prefixCls: customizePrefixCls,
shape,
size,
src,
srcSet,
icon,
className,
alt,
draggable,
children,
...others
} = props;

devWarning(
!(typeof icon === 'string' && icon.length > 2),
'Avatar',
`\`icon\` is using ReactNode instead of string naming in v4. Please check \`${icon}\` at https://ant.design/components/icon`,
);

const prefixCls = getPrefixCls('avatar', customizePrefixCls);

const sizeCls = classNames({
[`${prefixCls}-lg`]: size === 'large',
[`${prefixCls}-sm`]: size === 'small',
});

const classString = classNames(prefixCls, className, sizeCls, {
[`${prefixCls}-${shape}`]: shape,
[`${prefixCls}-image`]: src && isImgExist,
[`${prefixCls}-icon`]: icon,
});

const sizeStyle: React.CSSProperties =
typeof size === 'number'
? {
width: size,
height: size,
lineHeight: `${size}px`,
fontSize: icon ? size / 2 : 18,
}
: {};

let childrenToRender;
if (src && isImgExist) {
childrenToRender = (
<img src={src} draggable={draggable} srcSet={srcSet} onError={handleImgLoadError} alt={alt} />
);
} else if (icon) {
childrenToRender = icon;
} else if (mounted || scale !== 1) {
const transformString = `scale(${scale}) translateX(-50%)`;
const childrenStyle: React.CSSProperties = {
msTransform: transformString,
WebkitTransform: transformString,
transform: transformString,
};

const sizeChildrenStyle: React.CSSProperties =
typeof size === 'number'
? {
lineHeight: `${size}px`,
}
: {};

childrenToRender = (
<span
className={`${prefixCls}-string`}
ref={(node: HTMLElement) => {
avatarChildrenRef.current = node;
}}
style={{ ...sizeChildrenStyle, ...childrenStyle }}
>
{children}
</span>
);
} else {
childrenToRender = (
<span
className={`${prefixCls}-string`}
style={{ opacity: 0 }}
ref={(node: HTMLElement) => {
avatarChildrenRef.current = node;
}}
>
{children}
</span>
);
}

// The event is triggered twice from bubbling up the DOM tree.
// see https://codesandbox.io/s/kind-snow-9lidz
delete others.onError;
delete others.gap;

return (
<span
{...others}
style={{ ...sizeStyle, ...others.style }}
className={classString}
ref={avatarNodeMergeRef as any}
>
{childrenToRender}
</span>
);
};

const Avatar = React.forwardRef<unknown, AvatarProps>(InternalAvatar);
Avatar.displayName = 'Avatar';

Avatar.defaultProps = {
shape: 'circle' as AvatarProps['shape'],
size: 'default' as AvatarProps['size'],
};

export default Avatar;
Loading

0 comments on commit d857800

Please sign in to comment.