UNPKG

7.34 kBJavaScriptView Raw
1'use client';
2
3import * as React from 'react';
4import PropTypes from 'prop-types';
5import { isFragment } from 'react-is';
6import clsx from 'clsx';
7import chainPropTypes from '@mui/utils/chainPropTypes';
8import composeClasses from '@mui/utils/composeClasses';
9import { styled } from "../zero-styled/index.js";
10import memoTheme from "../utils/memoTheme.js";
11import { useDefaultProps } from "../DefaultPropsProvider/index.js";
12import Avatar, { avatarClasses } from "../Avatar/index.js";
13import avatarGroupClasses, { getAvatarGroupUtilityClass } from "./avatarGroupClasses.js";
14import useSlot from "../utils/useSlot.js";
15import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
16const SPACINGS = {
17 small: -16,
18 medium: -8
19};
20const useUtilityClasses = ownerState => {
21 const {
22 classes
23 } = ownerState;
24 const slots = {
25 root: ['root'],
26 avatar: ['avatar']
27 };
28 return composeClasses(slots, getAvatarGroupUtilityClass, classes);
29};
30const AvatarGroupRoot = styled('div', {
31 name: 'MuiAvatarGroup',
32 slot: 'Root',
33 overridesResolver: (props, styles) => ({
34 [`& .${avatarGroupClasses.avatar}`]: styles.avatar,
35 ...styles.root
36 })
37})(memoTheme(({
38 theme
39}) => ({
40 display: 'flex',
41 flexDirection: 'row-reverse',
42 [`& .${avatarClasses.root}`]: {
43 border: `2px solid ${(theme.vars || theme).palette.background.default}`,
44 boxSizing: 'content-box',
45 marginLeft: 'var(--AvatarGroup-spacing, -8px)',
46 '&:last-child': {
47 marginLeft: 0
48 }
49 }
50})));
51const AvatarGroup = /*#__PURE__*/React.forwardRef(function AvatarGroup(inProps, ref) {
52 const props = useDefaultProps({
53 props: inProps,
54 name: 'MuiAvatarGroup'
55 });
56 const {
57 children: childrenProp,
58 className,
59 component = 'div',
60 componentsProps,
61 max = 5,
62 renderSurplus,
63 slotProps = {},
64 slots = {},
65 spacing = 'medium',
66 total,
67 variant = 'circular',
68 ...other
69 } = props;
70 let clampedMax = max < 2 ? 2 : max;
71 const ownerState = {
72 ...props,
73 max,
74 spacing,
75 component,
76 variant
77 };
78 const classes = useUtilityClasses(ownerState);
79 const children = React.Children.toArray(childrenProp).filter(child => {
80 if (process.env.NODE_ENV !== 'production') {
81 if (isFragment(child)) {
82 console.error(["MUI: The AvatarGroup component doesn't accept a Fragment as a child.", 'Consider providing an array instead.'].join('\n'));
83 }
84 }
85 return /*#__PURE__*/React.isValidElement(child);
86 });
87 const totalAvatars = total || children.length;
88 if (totalAvatars === clampedMax) {
89 clampedMax += 1;
90 }
91 clampedMax = Math.min(totalAvatars + 1, clampedMax);
92 const maxAvatars = Math.min(children.length, clampedMax - 1);
93 const extraAvatars = Math.max(totalAvatars - clampedMax, totalAvatars - maxAvatars, 0);
94 const extraAvatarsElement = renderSurplus ? renderSurplus(extraAvatars) : `+${extraAvatars}`;
95 const marginValue = ownerState.spacing && SPACINGS[ownerState.spacing] !== undefined ? SPACINGS[ownerState.spacing] : -ownerState.spacing || -8;
96 const externalForwardedProps = {
97 slots,
98 slotProps: {
99 surplus: slotProps.additionalAvatar ?? componentsProps?.additionalAvatar,
100 ...componentsProps,
101 ...slotProps
102 }
103 };
104 const [SurplusSlot, surplusProps] = useSlot('surplus', {
105 elementType: Avatar,
106 externalForwardedProps,
107 className: classes.avatar,
108 ownerState,
109 additionalProps: {
110 variant
111 }
112 });
113 return /*#__PURE__*/_jsxs(AvatarGroupRoot, {
114 as: component,
115 ownerState: ownerState,
116 className: clsx(classes.root, className),
117 ref: ref,
118 ...other,
119 style: {
120 '--AvatarGroup-spacing': marginValue ? `${marginValue}px` : undefined,
121 ...other.style
122 },
123 children: [extraAvatars ? /*#__PURE__*/_jsx(SurplusSlot, {
124 ...surplusProps,
125 children: extraAvatarsElement
126 }) : null, children.slice(0, maxAvatars).reverse().map(child => {
127 return /*#__PURE__*/React.cloneElement(child, {
128 className: clsx(child.props.className, classes.avatar),
129 variant: child.props.variant || variant
130 });
131 })]
132 });
133});
134process.env.NODE_ENV !== "production" ? AvatarGroup.propTypes /* remove-proptypes */ = {
135 // ┌────────────────────────────── Warning ──────────────────────────────┐
136 // │ These PropTypes are generated from the TypeScript type definitions. │
137 // │ To update them, edit the d.ts file and run `pnpm proptypes`. │
138 // └─────────────────────────────────────────────────────────────────────┘
139 /**
140 * The avatars to stack.
141 */
142 children: PropTypes.node,
143 /**
144 * Override or extend the styles applied to the component.
145 */
146 classes: PropTypes.object,
147 /**
148 * @ignore
149 */
150 className: PropTypes.string,
151 /**
152 * The component used for the root node.
153 * Either a string to use a HTML element or a component.
154 */
155 component: PropTypes.elementType,
156 /**
157 * The extra props for the slot components.
158 * You can override the existing props or add new ones.
159 *
160 * This prop is an alias for the `slotProps` prop.
161 *
162 * @deprecated use the `slotProps` prop instead. This prop will be removed in v7. See [Migrating from deprecated APIs](https://mui.com/material-ui/migration/migrating-from-deprecated-apis/) for more details.
163 */
164 componentsProps: PropTypes.shape({
165 additionalAvatar: PropTypes.object
166 }),
167 /**
168 * Max avatars to show before +x.
169 * @default 5
170 */
171 max: chainPropTypes(PropTypes.number, props => {
172 if (props.max < 2) {
173 return new Error(['MUI: The prop `max` should be equal to 2 or above.', 'A value below is clamped to 2.'].join('\n'));
174 }
175 return null;
176 }),
177 /**
178 * custom renderer of extraAvatars
179 * @param {number} surplus number of extra avatars
180 * @returns {React.ReactNode} custom element to display
181 */
182 renderSurplus: PropTypes.func,
183 /**
184 * The props used for each slot inside.
185 * @default {}
186 */
187 slotProps: PropTypes.shape({
188 additionalAvatar: PropTypes.object,
189 surplus: PropTypes.oneOfType([PropTypes.func, PropTypes.object])
190 }),
191 /**
192 * The components used for each slot inside.
193 * @default {}
194 */
195 slots: PropTypes.shape({
196 surplus: PropTypes.elementType
197 }),
198 /**
199 * Spacing between avatars.
200 * @default 'medium'
201 */
202 spacing: PropTypes.oneOfType([PropTypes.oneOf(['medium', 'small']), PropTypes.number]),
203 /**
204 * @ignore
205 */
206 style: PropTypes.object,
207 /**
208 * The system prop that allows defining system overrides as well as additional CSS styles.
209 */
210 sx: PropTypes.oneOfType([PropTypes.arrayOf(PropTypes.oneOfType([PropTypes.func, PropTypes.object, PropTypes.bool])), PropTypes.func, PropTypes.object]),
211 /**
212 * The total number of avatars. Used for calculating the number of extra avatars.
213 * @default children.length
214 */
215 total: PropTypes.number,
216 /**
217 * The variant to use.
218 * @default 'circular'
219 */
220 variant: PropTypes /* @typescript-to-proptypes-ignore */.oneOfType([PropTypes.oneOf(['circular', 'rounded', 'square']), PropTypes.string])
221} : void 0;
222export default AvatarGroup;
\No newline at end of file