UNPKG

12.6 kBJavaScriptView Raw
1import _extends from "@babel/runtime/helpers/esm/extends";
2import _objectWithoutPropertiesLoose from "@babel/runtime/helpers/esm/objectWithoutPropertiesLoose";
3import * as React from 'react';
4import PropTypes from 'prop-types';
5import clsx from 'clsx';
6import { chainPropTypes } from '@material-ui/utils';
7import withStyles from '../styles/withStyles';
8import capitalize from '../utils/capitalize';
9const RADIUS_STANDARD = 10;
10const RADIUS_DOT = 4;
11export const styles = theme => ({
12 /* Styles applied to the root element. */
13 root: {
14 position: 'relative',
15 display: 'inline-flex',
16 // For correct alignment with the text.
17 verticalAlign: 'middle',
18 flexShrink: 0
19 },
20
21 /* Styles applied to the badge `span` element. */
22 badge: {
23 display: 'flex',
24 flexDirection: 'row',
25 flexWrap: 'wrap',
26 justifyContent: 'center',
27 alignContent: 'center',
28 alignItems: 'center',
29 position: 'absolute',
30 boxSizing: 'border-box',
31 fontFamily: theme.typography.fontFamily,
32 fontWeight: theme.typography.fontWeightMedium,
33 fontSize: theme.typography.pxToRem(12),
34 minWidth: RADIUS_STANDARD * 2,
35 lineHeight: 1,
36 padding: '0 6px',
37 height: RADIUS_STANDARD * 2,
38 borderRadius: RADIUS_STANDARD,
39 zIndex: 1,
40 // Render the badge on top of potential ripples.
41 transition: theme.transitions.create('transform', {
42 easing: theme.transitions.easing.easeInOut,
43 duration: theme.transitions.duration.enteringScreen
44 })
45 },
46
47 /* Styles applied to the root element if `color="primary"`. */
48 colorPrimary: {
49 backgroundColor: theme.palette.primary.main,
50 color: theme.palette.primary.contrastText
51 },
52
53 /* Styles applied to the root element if `color="secondary"`. */
54 colorSecondary: {
55 backgroundColor: theme.palette.secondary.main,
56 color: theme.palette.secondary.contrastText
57 },
58
59 /* Styles applied to the root element if `color="error"`. */
60 colorError: {
61 backgroundColor: theme.palette.error.main,
62 color: theme.palette.error.contrastText
63 },
64
65 /* Styles applied to the root element if `variant="dot"`. */
66 dot: {
67 borderRadius: RADIUS_DOT,
68 height: RADIUS_DOT * 2,
69 minWidth: RADIUS_DOT * 2,
70 padding: 0
71 },
72
73 /* Styles applied to the root element if `anchorOrigin={{ 'top', 'right' }} overlap="rectangle"`. */
74 anchorOriginTopRightRectangle: {
75 top: 0,
76 right: 0,
77 transform: 'scale(1) translate(50%, -50%)',
78 transformOrigin: '100% 0%',
79 '&$invisible': {
80 transform: 'scale(0) translate(50%, -50%)'
81 }
82 },
83
84 /* Styles applied to the root element if `anchorOrigin={{ 'top', 'right' }} overlap="rectangular"`. */
85 anchorOriginTopRightRectangular: {
86 top: 0,
87 right: 0,
88 transform: 'scale(1) translate(50%, -50%)',
89 transformOrigin: '100% 0%',
90 '&$invisible': {
91 transform: 'scale(0) translate(50%, -50%)'
92 }
93 },
94
95 /* Styles applied to the root element if `anchorOrigin={{ 'bottom', 'right' }} overlap="rectangle"`. */
96 anchorOriginBottomRightRectangle: {
97 bottom: 0,
98 right: 0,
99 transform: 'scale(1) translate(50%, 50%)',
100 transformOrigin: '100% 100%',
101 '&$invisible': {
102 transform: 'scale(0) translate(50%, 50%)'
103 }
104 },
105
106 /* Styles applied to the root element if `anchorOrigin={{ 'bottom', 'right' }} overlap="rectangular"`. */
107 anchorOriginBottomRightRectangular: {
108 bottom: 0,
109 right: 0,
110 transform: 'scale(1) translate(50%, 50%)',
111 transformOrigin: '100% 100%',
112 '&$invisible': {
113 transform: 'scale(0) translate(50%, 50%)'
114 }
115 },
116
117 /* Styles applied to the root element if `anchorOrigin={{ 'top', 'left' }} overlap="rectangle"`. */
118 anchorOriginTopLeftRectangle: {
119 top: 0,
120 left: 0,
121 transform: 'scale(1) translate(-50%, -50%)',
122 transformOrigin: '0% 0%',
123 '&$invisible': {
124 transform: 'scale(0) translate(-50%, -50%)'
125 }
126 },
127
128 /* Styles applied to the root element if `anchorOrigin={{ 'top', 'left' }} overlap="rectangular"`. */
129 anchorOriginTopLeftRectangular: {
130 top: 0,
131 left: 0,
132 transform: 'scale(1) translate(-50%, -50%)',
133 transformOrigin: '0% 0%',
134 '&$invisible': {
135 transform: 'scale(0) translate(-50%, -50%)'
136 }
137 },
138
139 /* Styles applied to the root element if `anchorOrigin={{ 'bottom', 'left' }} overlap="rectangle"`. */
140 anchorOriginBottomLeftRectangle: {
141 bottom: 0,
142 left: 0,
143 transform: 'scale(1) translate(-50%, 50%)',
144 transformOrigin: '0% 100%',
145 '&$invisible': {
146 transform: 'scale(0) translate(-50%, 50%)'
147 }
148 },
149
150 /* Styles applied to the root element if `anchorOrigin={{ 'bottom', 'left' }} overlap="rectangular"`. */
151 anchorOriginBottomLeftRectangular: {
152 bottom: 0,
153 left: 0,
154 transform: 'scale(1) translate(-50%, 50%)',
155 transformOrigin: '0% 100%',
156 '&$invisible': {
157 transform: 'scale(0) translate(-50%, 50%)'
158 }
159 },
160
161 /* Styles applied to the root element if `anchorOrigin={{ 'top', 'right' }} overlap="circle"`. */
162 anchorOriginTopRightCircle: {
163 top: '14%',
164 right: '14%',
165 transform: 'scale(1) translate(50%, -50%)',
166 transformOrigin: '100% 0%',
167 '&$invisible': {
168 transform: 'scale(0) translate(50%, -50%)'
169 }
170 },
171
172 /* Styles applied to the root element if `anchorOrigin={{ 'top', 'right' }} overlap="circular"`. */
173 anchorOriginTopRightCircular: {
174 top: '14%',
175 right: '14%',
176 transform: 'scale(1) translate(50%, -50%)',
177 transformOrigin: '100% 0%',
178 '&$invisible': {
179 transform: 'scale(0) translate(50%, -50%)'
180 }
181 },
182
183 /* Styles applied to the root element if `anchorOrigin={{ 'bottom', 'right' }} overlap="circle"`. */
184 anchorOriginBottomRightCircle: {
185 bottom: '14%',
186 right: '14%',
187 transform: 'scale(1) translate(50%, 50%)',
188 transformOrigin: '100% 100%',
189 '&$invisible': {
190 transform: 'scale(0) translate(50%, 50%)'
191 }
192 },
193
194 /* Styles applied to the root element if `anchorOrigin={{ 'bottom', 'right' }} overlap="circular"`. */
195 anchorOriginBottomRightCircular: {
196 bottom: '14%',
197 right: '14%',
198 transform: 'scale(1) translate(50%, 50%)',
199 transformOrigin: '100% 100%',
200 '&$invisible': {
201 transform: 'scale(0) translate(50%, 50%)'
202 }
203 },
204
205 /* Styles applied to the root element if `anchorOrigin={{ 'top', 'left' }} overlap="circle"`. */
206 anchorOriginTopLeftCircle: {
207 top: '14%',
208 left: '14%',
209 transform: 'scale(1) translate(-50%, -50%)',
210 transformOrigin: '0% 0%',
211 '&$invisible': {
212 transform: 'scale(0) translate(-50%, -50%)'
213 }
214 },
215
216 /* Styles applied to the root element if `anchorOrigin={{ 'top', 'left' }} overlap="circular"`. */
217 anchorOriginTopLeftCircular: {
218 top: '14%',
219 left: '14%',
220 transform: 'scale(1) translate(-50%, -50%)',
221 transformOrigin: '0% 0%',
222 '&$invisible': {
223 transform: 'scale(0) translate(-50%, -50%)'
224 }
225 },
226
227 /* Styles applied to the root element if `anchorOrigin={{ 'bottom', 'left' }} overlap="circle"`. */
228 anchorOriginBottomLeftCircle: {
229 bottom: '14%',
230 left: '14%',
231 transform: 'scale(1) translate(-50%, 50%)',
232 transformOrigin: '0% 100%',
233 '&$invisible': {
234 transform: 'scale(0) translate(-50%, 50%)'
235 }
236 },
237
238 /* Styles applied to the root element if `anchorOrigin={{ 'bottom', 'left' }} overlap="circular"`. */
239 anchorOriginBottomLeftCircular: {
240 bottom: '14%',
241 left: '14%',
242 transform: 'scale(1) translate(-50%, 50%)',
243 transformOrigin: '0% 100%',
244 '&$invisible': {
245 transform: 'scale(0) translate(-50%, 50%)'
246 }
247 },
248
249 /* Pseudo-class to the badge `span` element if `invisible={true}`. */
250 invisible: {
251 transition: theme.transitions.create('transform', {
252 easing: theme.transitions.easing.easeInOut,
253 duration: theme.transitions.duration.leavingScreen
254 })
255 }
256});
257const Badge = /*#__PURE__*/React.forwardRef(function Badge(props, ref) {
258 const {
259 anchorOrigin = {
260 vertical: 'top',
261 horizontal: 'right'
262 },
263 badgeContent,
264 children,
265 classes,
266 className,
267 color = 'default',
268 component: ComponentProp = 'span',
269 invisible: invisibleProp,
270 max = 99,
271 overlap = 'rectangle',
272 showZero = false,
273 variant = 'standard'
274 } = props,
275 other = _objectWithoutPropertiesLoose(props, ["anchorOrigin", "badgeContent", "children", "classes", "className", "color", "component", "invisible", "max", "overlap", "showZero", "variant"]);
276
277 let invisible = invisibleProp;
278
279 if (invisibleProp == null && (badgeContent === 0 && !showZero || badgeContent == null && variant !== 'dot')) {
280 invisible = true;
281 }
282
283 let displayValue = '';
284
285 if (variant !== 'dot') {
286 displayValue = badgeContent > max ? `${max}+` : badgeContent;
287 }
288
289 return /*#__PURE__*/React.createElement(ComponentProp, _extends({
290 className: clsx(classes.root, className),
291 ref: ref
292 }, other), children, /*#__PURE__*/React.createElement("span", {
293 className: clsx(classes.badge, classes[`${anchorOrigin.horizontal}${capitalize(anchorOrigin.vertical)}}`], classes[`anchorOrigin${capitalize(anchorOrigin.vertical)}${capitalize(anchorOrigin.horizontal)}${capitalize(overlap)}`], color !== 'default' && classes[`color${capitalize(color)}`], invisible && classes.invisible, variant === 'dot' && classes.dot)
294 }, displayValue));
295});
296process.env.NODE_ENV !== "production" ? Badge.propTypes = {
297 // ----------------------------- Warning --------------------------------
298 // | These PropTypes are generated from the TypeScript type definitions |
299 // | To update them edit the d.ts file and run "yarn proptypes" |
300 // ----------------------------------------------------------------------
301
302 /**
303 * The anchor of the badge.
304 */
305 anchorOrigin: PropTypes.shape({
306 horizontal: PropTypes.oneOf(['left', 'right']).isRequired,
307 vertical: PropTypes.oneOf(['bottom', 'top']).isRequired
308 }),
309
310 /**
311 * The content rendered within the badge.
312 */
313 badgeContent: PropTypes.node,
314
315 /**
316 * The badge will be added relative to this node.
317 */
318 children: PropTypes.node,
319
320 /**
321 * Override or extend the styles applied to the component.
322 * See [CSS API](#css) below for more details.
323 */
324 classes: chainPropTypes(PropTypes.object, props => {
325 const {
326 classes
327 } = props;
328
329 if (classes == null) {
330 return null;
331 }
332
333 [['anchorOriginTopRightRectangle', 'anchorOriginTopRightRectangular'], ['anchorOriginBottomRightRectangle', 'anchorOriginBottomRightRectangular'], ['anchorOriginTopLeftRectangle', 'anchorOriginTopLeftRectangular'], ['anchorOriginBottomLeftRectangle', 'anchorOriginBottomLeftRectangular'], ['anchorOriginTopRightCircle', 'anchorOriginTopRightCircular'], ['anchorOriginBottomRightCircle', 'anchorOriginBottomRightCircular'], ['anchorOriginTopLeftCircle', 'anchorOriginTopLeftCircular']].forEach(([deprecatedClassKey, newClassKey]) => {
334 if (classes[deprecatedClassKey] != null && // 2 classnames? one from withStyles the other must be custom
335 classes[deprecatedClassKey].split(' ').length > 1) {
336 throw new Error(`Material-UI: The \`${deprecatedClassKey}\` class was deprecated. Use \`${newClassKey}\` instead.`);
337 }
338 });
339 return null;
340 }),
341
342 /**
343 * @ignore
344 */
345 className: PropTypes.string,
346
347 /**
348 * The color of the component. It supports those theme colors that make sense for this component.
349 */
350 color: PropTypes.oneOf(['default', 'error', 'primary', 'secondary']),
351
352 /**
353 * The component used for the root node.
354 * Either a string to use a HTML element or a component.
355 */
356 component: PropTypes
357 /* @typescript-to-proptypes-ignore */
358 .elementType,
359
360 /**
361 * If `true`, the badge will be invisible.
362 */
363 invisible: PropTypes.bool,
364
365 /**
366 * Max count to show.
367 */
368 max: PropTypes.number,
369
370 /**
371 * Wrapped shape the badge should overlap.
372 */
373 overlap: chainPropTypes(PropTypes.oneOf(['circle', 'rectangle', 'circular', 'rectangular']), props => {
374 const {
375 overlap
376 } = props;
377
378 if (overlap === 'rectangle') {
379 throw new Error('Material-UI: `overlap="rectangle"` was deprecated. Use `overlap="rectangular"` instead.');
380 }
381
382 if (overlap === 'circle') {
383 throw new Error('Material-UI: `overlap="circle"` was deprecated. Use `overlap="circular"` instead.');
384 }
385
386 return null;
387 }),
388
389 /**
390 * Controls whether the badge is hidden when `badgeContent` is zero.
391 */
392 showZero: PropTypes.bool,
393
394 /**
395 * The variant to use.
396 */
397 variant: PropTypes.oneOf(['dot', 'standard'])
398} : void 0;
399export default withStyles(styles, {
400 name: 'MuiBadge'
401})(Badge);
\No newline at end of file