Skip to content

Commit

Permalink
fix(AvatarGroup): fix avatar deformation in group (#3727)
Browse files Browse the repository at this point in the history
  • Loading branch information
simonguo committed Apr 11, 2024
1 parent 6a9dab3 commit 466e428
Show file tree
Hide file tree
Showing 5 changed files with 38 additions and 36 deletions.
11 changes: 8 additions & 3 deletions src/Avatar/Avatar.tsx
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import React, { useContext, useMemo } from 'react';
import PropTypes from 'prop-types';
import { useClassNames } from '../utils';
import { useClassNames, useCustom, isIE } from '../utils';
import { WithAsProps, RsRefForwardingComponent, TypeAttributes } from '../@types/common';
import { AvatarGroupContext, type Size } from '../AvatarGroup/AvatarGroup';
import { oneOf } from '../internals/propTypes';
Expand Down Expand Up @@ -73,7 +73,7 @@ export interface AvatarProps extends WithAsProps {
*/
const Avatar: RsRefForwardingComponent<'div', AvatarProps> = React.forwardRef(
(props: AvatarProps, ref) => {
const { size: groupSize } = useContext(AvatarGroupContext);
const { size: groupSize, spacing } = useContext(AvatarGroupContext);

const {
as: Component = 'div',
Expand All @@ -88,6 +88,7 @@ const Avatar: RsRefForwardingComponent<'div', AvatarProps> = React.forwardRef(
src,
srcSet,
sizes,
style,
imgProps,
onError,
...rest
Expand All @@ -97,6 +98,7 @@ const Avatar: RsRefForwardingComponent<'div', AvatarProps> = React.forwardRef(
const classes = merge(className, withClassPrefix(size, color, { circle, bordered }));
const imageProps = { ...imgProps, alt, src, srcSet, sizes };
const { loaded } = useImage({ ...imageProps, onError });
const { rtl } = useCustom('Avatar');

const altComponent = useMemo(() => {
if (alt) {
Expand All @@ -113,8 +115,11 @@ const Avatar: RsRefForwardingComponent<'div', AvatarProps> = React.forwardRef(
const placeholder = children || altComponent || <AvatarIcon className={prefix`icon`} />;
const image = loaded ? <img {...imageProps} className={prefix`image`} /> : placeholder;

const margin = rtl ? 'marginLeft' : 'marginRight';
const insertStyles = isIE() && spacing ? { [margin]: spacing, ...style } : style;

return (
<Component {...rest} ref={ref} className={classes}>
<Component {...rest} ref={ref} className={classes} style={insertStyles}>
{src ? image : placeholder}
</Component>
);
Expand Down
19 changes: 6 additions & 13 deletions src/AvatarGroup/AvatarGroup.tsx
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import React, { useMemo } from 'react';
import PropTypes from 'prop-types';
import { useClassNames, useCustom } from '../utils';
import { useClassNames, isIE } from '../utils';
import { WithAsProps, RsRefForwardingComponent } from '../@types/common';
import { oneOf } from '../internals/propTypes';

Expand All @@ -24,7 +24,7 @@ export interface AvatarGroupProps extends WithAsProps {
size?: Size;
}

export const AvatarGroupContext = React.createContext<{ size?: Size }>({});
export const AvatarGroupContext = React.createContext<{ size?: Size; spacing?: number }>({});

/**
* The AvatarGroup component is used to represent a collection of avatars.
Expand All @@ -40,25 +40,18 @@ const AvatarGroup: RsRefForwardingComponent<'div', AvatarGroupProps> = React.for
children,
stack,
size,
style,
...rest
} = props;

const { rtl } = useCustom('AvatarGroup');
const { withClassPrefix, merge } = useClassNames(classPrefix);
const classes = merge(className, withClassPrefix({ stack }));
const contextValue = useMemo(() => ({ size }), [size]);
const styles = isIE() ? style : { ...style, gap: spacing };

return (
<Component {...rest} ref={ref} className={classes}>
<AvatarGroupContext.Provider value={contextValue}>
{spacing
? React.Children.map(children as React.ReactElement[], child => {
return React.cloneElement(child, {
style: { [rtl ? 'marginLeft' : 'marginRight']: spacing, ...child.props.style }
});
})
: children}
</AvatarGroupContext.Provider>
<Component role="group" {...rest} ref={ref} className={classes} style={styles}>
<AvatarGroupContext.Provider value={contextValue}>{children}</AvatarGroupContext.Provider>
</Component>
);
}
Expand Down
2 changes: 2 additions & 0 deletions src/AvatarGroup/styles/index.less
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,8 @@
.rs-avatar-group {
display: flex;
align-items: flex-end;
flex-wrap: wrap;

&-stack {
.rs-avatar {
box-sizing: content-box;
Expand Down
29 changes: 9 additions & 20 deletions src/AvatarGroup/test/AvatarGroupSpec.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -9,36 +9,25 @@ describe('AvatarGroup', () => {

it('Should change the size of all avatars', () => {
render(
<AvatarGroup size="xs" data-testid="group">
<Avatar data-testid="avatar">A</Avatar>
<AvatarGroup size="xs">
<Avatar>A</Avatar>
<Avatar>B</Avatar>
</AvatarGroup>
);

expect(screen.getByTestId('avatar')).to.have.class('rs-avatar-xs');
expect(screen.getByText('A')).to.have.class('rs-avatar-xs');
expect(screen.getByText('B')).to.have.class('rs-avatar-xs');
});

it('Should set the spacing between the avatars', () => {
render(
<AvatarGroup spacing={10} data-testid="group">
<Avatar>A</Avatar>
<Avatar>A</Avatar>
<Avatar>B</Avatar>
{[<Avatar key={1}>C</Avatar>, <Avatar key={2}>D</Avatar>]}
</AvatarGroup>
);
render(<AvatarGroup spacing={10} />);

// eslint-disable-next-line testing-library/no-node-access
const avatars = screen.getByTestId('group').querySelectorAll('.rs-avatar');

assert.equal((avatars[0] as HTMLElement).style.marginRight, '10px');
assert.equal((avatars[1] as HTMLElement).style.marginRight, '10px');
assert.equal((avatars[2] as HTMLElement).style.marginRight, '10px');
assert.equal((avatars[3] as HTMLElement).style.marginRight, '10px');
expect(screen.getByRole('group')).to.have.style('gap', '10px');
});

it('Should be stack', () => {
render(<AvatarGroup stack data-testid="group" />);
assert.include(screen.getByTestId('group').className, 'rs-avatar-group-stack');
render(<AvatarGroup stack />);

expect(screen.getByRole('group')).to.have.class('rs-avatar-group-stack');
});
});
13 changes: 13 additions & 0 deletions src/AvatarGroup/test/AvatarGroupStylesSpec.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
import React from 'react';
import { render, screen } from '@testing-library/react';
import AvatarGroup from '../index';

import '../styles/index.less';

describe('AvatarGroup styles', () => {
it('Should wrap children automatically', () => {
render(<AvatarGroup />);

expect(screen.getByRole('group')).to.have.style('flex-wrap', 'wrap');
});
});

0 comments on commit 466e428

Please sign in to comment.