diff --git a/docs/data/material/components/avatars/CustomSurplusAvatars.js b/docs/data/material/components/avatars/CustomSurplusAvatars.js new file mode 100644 index 00000000000000..010a885afd9a9b --- /dev/null +++ b/docs/data/material/components/avatars/CustomSurplusAvatars.js @@ -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 ( + +{surplus.toString()[0]}k} + total={4251} + > + + + + + + ); +} diff --git a/docs/data/material/components/avatars/CustomSurplusAvatars.tsx b/docs/data/material/components/avatars/CustomSurplusAvatars.tsx new file mode 100644 index 00000000000000..010a885afd9a9b --- /dev/null +++ b/docs/data/material/components/avatars/CustomSurplusAvatars.tsx @@ -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 ( + +{surplus.toString()[0]}k} + total={4251} + > + + + + + + ); +} diff --git a/docs/data/material/components/avatars/CustomSurplusAvatars.tsx.preview b/docs/data/material/components/avatars/CustomSurplusAvatars.tsx.preview new file mode 100644 index 00000000000000..8db3b90b5a3537 --- /dev/null +++ b/docs/data/material/components/avatars/CustomSurplusAvatars.tsx.preview @@ -0,0 +1,9 @@ + +{surplus.toString()[0]}k} + total={4251} +> + + + + + \ No newline at end of file diff --git a/docs/data/material/components/avatars/avatars.md b/docs/data/material/components/avatars/avatars.md index 73bd47eb6dc194..b67ee06436f943 100644 --- a/docs/data/material/components/avatars/avatars.md +++ b/docs/data/material/components/avatars/avatars.md @@ -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"}} diff --git a/docs/pages/material-ui/api/avatar-group.json b/docs/pages/material-ui/api/avatar-group.json index 3710a1fbe14a16..a3d1b00adddd7e 100644 --- a/docs/pages/material-ui/api/avatar-group.json +++ b/docs/pages/material-ui/api/avatar-group.json @@ -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": "{}" diff --git a/docs/translations/api-docs/avatar-group/avatar-group.json b/docs/translations/api-docs/avatar-group/avatar-group.json index 6df3c90b4c0b01..147861930ab378 100644 --- a/docs/translations/api-docs/avatar-group/avatar-group.json +++ b/docs/translations/api-docs/avatar-group/avatar-group.json @@ -10,6 +10,13 @@ "description": "The extra props for the slot components. You can override the existing props or add new ones.
This prop is an alias for the slotProps prop. It's recommended to use the slotProps prop instead, as componentsProps 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.
This prop is an alias for the componentsProps prop, which will be deprecated in the future." }, diff --git a/packages/mui-material/src/AvatarGroup/AvatarGroup.d.ts b/packages/mui-material/src/AvatarGroup/AvatarGroup.d.ts index cad93b0926cb0a..ed052bbf48d468 100644 --- a/packages/mui-material/src/AvatarGroup/AvatarGroup.d.ts +++ b/packages/mui-material/src/AvatarGroup/AvatarGroup.d.ts @@ -40,6 +40,12 @@ export interface AvatarGroupProps extends StandardProps React.ReactNode; /** * The extra props for the slot components. * You can override the existing props or add new ones. diff --git a/packages/mui-material/src/AvatarGroup/AvatarGroup.js b/packages/mui-material/src/AvatarGroup/AvatarGroup.js index 5ac2191abb5aeb..4cd5193787cc3e 100644 --- a/packages/mui-material/src/AvatarGroup/AvatarGroup.js +++ b/packages/mui-material/src/AvatarGroup/AvatarGroup.js @@ -71,6 +71,7 @@ const AvatarGroup = React.forwardRef(function AvatarGroup(inProps, ref) { component = 'div', componentsProps = {}, max = 5, + renderSurplus, slotProps = {}, spacing = 'medium', total, @@ -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; @@ -135,7 +137,7 @@ const AvatarGroup = React.forwardRef(function AvatarGroup(inProps, ref) { className={clsx(classes.avatar, additionalAvatarSlotProps?.className)} style={{ marginLeft, ...additionalAvatarSlotProps?.style }} > - +{extraAvatars} + {extraAvatarsElement} ) : null} {children @@ -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. diff --git a/packages/mui-material/src/AvatarGroup/AvatarGroup.spec.tsx b/packages/mui-material/src/AvatarGroup/AvatarGroup.spec.tsx index 5dea4e7ab56bf7..05f8efe1ac4caa 100644 --- a/packages/mui-material/src/AvatarGroup/AvatarGroup.spec.tsx +++ b/packages/mui-material/src/AvatarGroup/AvatarGroup.spec.tsx @@ -1,4 +1,5 @@ import * as React from 'react'; +import { expectType } from '@mui/types'; import AvatarGroup from '@mui/material/AvatarGroup'; ; @@ -8,3 +9,10 @@ import AvatarGroup from '@mui/material/AvatarGroup'; // @ts-expect-error ; + + { + expectType(surplus); + return
{surplus}
; + }} +/>; diff --git a/packages/mui-material/src/AvatarGroup/AvatarGroup.test.js b/packages/mui-material/src/AvatarGroup/AvatarGroup.test.js index 26764b881281b3..e755aea41a4d36 100644 --- a/packages/mui-material/src/AvatarGroup/AvatarGroup.test.js +++ b/packages/mui-material/src/AvatarGroup/AvatarGroup.test.js @@ -59,6 +59,18 @@ describe('', () => { expect(container.textContent).to.equal('+2'); }); + it('should display custom surplus element if renderSurplus prop is passed', () => { + const { container } = render( + %{num}} max={3}> + + + + + , + ); + expect(container.textContent).to.equal('%2'); + }); + it('should pass props from componentsProps.additionalAvatar to the slot component', () => { const componentsProps = { additionalAvatar: { className: 'additional-avatar-test' } };