Skip to content

Commit

Permalink
[material-ui][AvatarGroup] Add renderSurplus prop (#39283)
Browse files Browse the repository at this point in the history
  • Loading branch information
uuxxx authored Oct 11, 2023
1 parent 604d819 commit a3b75df
Show file tree
Hide file tree
Showing 10 changed files with 101 additions and 1 deletion.
17 changes: 17 additions & 0 deletions docs/data/material/components/avatars/CustomSurplusAvatars.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
import * as React from 'react';
import Avatar from '@mui/material/Avatar';
import AvatarGroup from '@mui/material/AvatarGroup';

export default function CustomSurplusAvatars() {
return (
<AvatarGroup
renderSurplus={(surplus) => <span>+{surplus.toString()[0]}k</span>}
total={4251}
>
<Avatar alt="Remy Sharp" src="/static/images/avatar/1.jpg" />
<Avatar alt="Travis Howard" src="/static/images/avatar/2.jpg" />
<Avatar alt="Agnes Walker" src="/static/images/avatar/4.jpg" />
<Avatar alt="Trevor Henderson" src="/static/images/avatar/5.jpg" />
</AvatarGroup>
);
}
17 changes: 17 additions & 0 deletions docs/data/material/components/avatars/CustomSurplusAvatars.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
import * as React from 'react';
import Avatar from '@mui/material/Avatar';
import AvatarGroup from '@mui/material/AvatarGroup';

export default function CustomSurplusAvatars() {
return (
<AvatarGroup
renderSurplus={(surplus) => <span>+{surplus.toString()[0]}k</span>}
total={4251}
>
<Avatar alt="Remy Sharp" src="/static/images/avatar/1.jpg" />
<Avatar alt="Travis Howard" src="/static/images/avatar/2.jpg" />
<Avatar alt="Agnes Walker" src="/static/images/avatar/4.jpg" />
<Avatar alt="Trevor Henderson" src="/static/images/avatar/5.jpg" />
</AvatarGroup>
);
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
<AvatarGroup
renderSurplus={(surplus) => <span>+{surplus.toString()[0]}k</span>}
total={4251}
>
<Avatar alt="Remy Sharp" src="/static/images/avatar/1.jpg" />
<Avatar alt="Travis Howard" src="/static/images/avatar/2.jpg" />
<Avatar alt="Agnes Walker" src="/static/images/avatar/4.jpg" />
<Avatar alt="Trevor Henderson" src="/static/images/avatar/5.jpg" />
</AvatarGroup>
8 changes: 8 additions & 0 deletions docs/data/material/components/avatars/avatars.md
Original file line number Diff line number Diff line change
Expand Up @@ -68,6 +68,14 @@ If you need to control the total number of avatars not shown, you can use the `t

{{"demo": "TotalAvatars.js"}}

### Custom surplus

Set the `renderSurplus` prop as a callback to customize the surplus avatar. The callback will receive the surplus number as an argument based on the children and the `max` prop, and should return a `React.ReactNode`.

The `renderSurplus` prop is useful when you need to render the surplus based on the data sent from the server.

{{"demo": "CustomSurplusAvatars.js"}}

## With badge

{{"demo": "BadgeAvatars.js"}}
8 changes: 8 additions & 0 deletions docs/pages/material-ui/api/avatar-group.json
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,14 @@
"default": "{}"
},
"max": { "type": { "name": "custom", "description": "number" }, "default": "5" },
"renderSurplus": {
"type": { "name": "func" },
"signature": {
"type": "function(surplus: number) => React.ReactNode",
"describedArgs": ["surplus"],
"returned": "React.ReactNode"
}
},
"slotProps": {
"type": { "name": "shape", "description": "{ additionalAvatar?: object }" },
"default": "{}"
Expand Down
7 changes: 7 additions & 0 deletions docs/translations/api-docs/avatar-group/avatar-group.json
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,13 @@
"description": "The extra props for the slot components. You can override the existing props or add new ones.<br>This prop is an alias for the <code>slotProps</code> prop. It&#39;s recommended to use the <code>slotProps</code> prop instead, as <code>componentsProps</code> will be deprecated in the future."
},
"max": { "description": "Max avatars to show before +x." },
"renderSurplus": {
"description": "custom renderer of extraAvatars",
"typeDescriptions": {
"surplus": "number of extra avatars",
"React.ReactNode": "custom element to display"
}
},
"slotProps": {
"description": "The extra props for the slot components. You can override the existing props or add new ones.<br>This prop is an alias for the <code>componentsProps</code> prop, which will be deprecated in the future."
},
Expand Down
6 changes: 6 additions & 0 deletions packages/mui-material/src/AvatarGroup/AvatarGroup.d.ts
Original file line number Diff line number Diff line change
Expand Up @@ -40,6 +40,12 @@ export interface AvatarGroupProps extends StandardProps<React.HTMLAttributes<HTM
* @default 5
*/
max?: number;
/**
* custom renderer of extraAvatars
* @param {number} surplus number of extra avatars
* @returns {React.ReactNode} custom element to display
*/
renderSurplus?: (surplus: number) => React.ReactNode;
/**
* The extra props for the slot components.
* You can override the existing props or add new ones.
Expand Down
10 changes: 9 additions & 1 deletion packages/mui-material/src/AvatarGroup/AvatarGroup.js
Original file line number Diff line number Diff line change
Expand Up @@ -71,6 +71,7 @@ const AvatarGroup = React.forwardRef(function AvatarGroup(inProps, ref) {
component = 'div',
componentsProps = {},
max = 5,
renderSurplus,
slotProps = {},
spacing = 'medium',
total,
Expand Down Expand Up @@ -114,6 +115,7 @@ const AvatarGroup = React.forwardRef(function AvatarGroup(inProps, ref) {

const maxAvatars = Math.min(children.length, clampedMax - 1);
const extraAvatars = Math.max(totalAvatars - clampedMax, totalAvatars - maxAvatars, 0);
const extraAvatarsElement = renderSurplus ? renderSurplus(extraAvatars) : `+${extraAvatars}`;

const marginLeft = spacing && SPACINGS[spacing] !== undefined ? SPACINGS[spacing] : -spacing;

Expand All @@ -135,7 +137,7 @@ const AvatarGroup = React.forwardRef(function AvatarGroup(inProps, ref) {
className={clsx(classes.avatar, additionalAvatarSlotProps?.className)}
style={{ marginLeft, ...additionalAvatarSlotProps?.style }}
>
+{extraAvatars}
{extraAvatarsElement}
</AvatarGroupAvatar>
) : null}
{children
Expand Down Expand Up @@ -207,6 +209,12 @@ AvatarGroup.propTypes /* remove-proptypes */ = {

return null;
}),
/**
* custom renderer of extraAvatars
* @param {number} surplus number of extra avatars
* @returns {React.ReactNode} custom element to display
*/
renderSurplus: PropTypes.func,
/**
* The extra props for the slot components.
* You can override the existing props or add new ones.
Expand Down
8 changes: 8 additions & 0 deletions packages/mui-material/src/AvatarGroup/AvatarGroup.spec.tsx
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
import * as React from 'react';
import { expectType } from '@mui/types';
import AvatarGroup from '@mui/material/AvatarGroup';

<AvatarGroup component="ul" />;
Expand All @@ -8,3 +9,10 @@ import AvatarGroup from '@mui/material/AvatarGroup';

// @ts-expect-error
<AvatarGroup variant="unknown" />;

<AvatarGroup
renderSurplus={(surplus) => {
expectType<number, number>(surplus);
return <div>{surplus}</div>;
}}
/>;
12 changes: 12 additions & 0 deletions packages/mui-material/src/AvatarGroup/AvatarGroup.test.js
Original file line number Diff line number Diff line change
Expand Up @@ -59,6 +59,18 @@ describe('<AvatarGroup />', () => {
expect(container.textContent).to.equal('+2');
});

it('should display custom surplus element if renderSurplus prop is passed', () => {
const { container } = render(
<AvatarGroup renderSurplus={(num) => <span>%{num}</span>} max={3}>
<Avatar src="/fake.png" />
<Avatar src="/fake.png" />
<Avatar src="/fake.png" />
<Avatar src="/fake.png" />
</AvatarGroup>,
);
expect(container.textContent).to.equal('%2');
});

it('should pass props from componentsProps.additionalAvatar to the slot component', () => {
const componentsProps = { additionalAvatar: { className: 'additional-avatar-test' } };

Expand Down

0 comments on commit a3b75df

Please sign in to comment.