forked from mantinedev/mantine
/
Indicator.tsx
133 lines (110 loc) · 3.39 KB
/
Indicator.tsx
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
/* eslint-disable react/no-unused-prop-types */
import React, { forwardRef, useMemo } from 'react';
import {
Selectors,
DefaultProps,
MantineColor,
MantineNumberSize,
useComponentDefaultProps,
getDefaultZIndex,
} from '@mantine/styles';
import { isNumber, isUnDef } from '@mantine/utils';
import { Box } from '../Box';
import { IndicatorPosition } from './Indicator.types';
import useStyles, { IndicatorStylesParams } from './Indicator.styles';
import { Machine } from './Machine/Machine';
export type IndicatorStylesNames = Selectors<typeof useStyles>;
export interface IndicatorProps
extends DefaultProps<IndicatorStylesNames, IndicatorStylesParams>,
React.ComponentPropsWithoutRef<'div'> {
/** Element that should have an indicator */
children: React.ReactNode;
/** Indicator position relative to child element */
position?: IndicatorPosition;
/** Changes position offset, usually used when element has border-radius */
offset?: number;
/** Determines whether indicator container should be an inline element */
inline?: boolean;
/** Size in px */
size?: number;
/** Indicator label */
label?: React.ReactNode;
/** Indicator count overflowCount */
overflowCount?: number;
dot?: boolean;
/** border-radius from theme.radius or number value to set radius in px */
radius?: MantineNumberSize;
/** Color from theme.colors or any other valid CSS color value */
color?: MantineColor;
/** Determines whether indicator should have border */
withBorder?: boolean;
/** When component is disabled it renders children without indicator */
disabled?: boolean;
/** When showZero is true and label is zero renders children with indicator*/
showZero?: boolean;
/** Indicator processing animation */
processing?: boolean;
/** Indicator z-index */
zIndex?: React.CSSProperties['zIndex'];
}
const defaultProps: Partial<IndicatorProps> = {
position: 'top-end',
offset: 0,
inline: false,
withBorder: false,
disabled: false,
showZero: false,
processing: false,
size: 10,
overflowCount: 99,
radius: 1000,
zIndex: getDefaultZIndex('app'),
};
export const Indicator = forwardRef<HTMLDivElement, IndicatorProps>((props, ref) => {
const {
children,
position,
offset,
size,
radius,
inline,
withBorder,
className,
color,
dot,
styles,
label,
overflowCount,
showZero,
classNames,
disabled,
zIndex,
unstyled,
processing,
...others
} = useComponentDefaultProps('Indicator', defaultProps, props);
const { classes, cx } = useStyles(
{ position, offset, size, radius, inline, color, withBorder, zIndex, withLabel: !!label },
{ name: 'Indicator', classNames, styles, unstyled }
);
const renderLabel = useMemo(() => {
if (isNumber(label)) {
return <Machine value={label} max={overflowCount} />;
}
return label;
}, [label, overflowCount]);
const isShowIndicator = useMemo(
() => !disabled && (dot || (!isUnDef(label) && !(label <= 0 && !showZero))),
[disabled, label, showZero]
);
return (
<Box ref={ref} className={cx(classes.root, className)} {...others}>
{isShowIndicator && (
<div className={cx(classes.indicator, classes.common)}>{renderLabel}</div>
)}
{processing && <div className={cx(classes.processing, classes.common)} />}
{children}
</Box>
);
});
Indicator.displayName = '@mantine/core/Indicator';