/
Chip.tsx
154 lines (134 loc) · 3.75 KB
/
Chip.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
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
import React, { forwardRef } from 'react';
import { useId, useUncontrolled } from '@mantine/hooks';
import {
DefaultProps,
MantineNumberSize,
MantineSize,
MantineColor,
Selectors,
extractSystemStyles,
useComponentDefaultProps,
} from '@mantine/styles';
import { ForwardRefWithStaticComponents } from '@mantine/utils';
import { Box } from '../Box';
import { CheckIcon } from '../Checkbox';
import { ChipGroup } from './ChipGroup/ChipGroup';
import { useChipGroup } from './ChipGroup.context';
import useStyles, { ChipStylesParams } from './Chip.styles';
export type ChipStylesNames = Selectors<typeof useStyles>;
export interface ChipProps
extends DefaultProps<ChipStylesNames, ChipStylesParams>,
Omit<React.ComponentPropsWithRef<'input'>, 'size' | 'onChange'> {
/** Chip radius from theme or number to set value in px */
radius?: MantineNumberSize;
/** Predefined chip size */
size?: MantineSize;
/** Chip input type */
type?: 'radio' | 'checkbox';
/** Controls chip appearance, defaults to filled with dark theme and to outline in light theme */
variant?: 'outline' | 'filled';
/** Chip label */
children: React.ReactNode;
/** Checked state for controlled component */
checked?: boolean;
/** Default value for uncontrolled component */
defaultChecked?: boolean;
/** Calls when checked state changes */
onChange?(checked: boolean): void;
/** Active color from theme, defaults to theme.primaryColor */
color?: MantineColor;
/** Static id to bind input with label */
id?: string;
/** Props spread to wrapper element */
wrapperProps?: Record<string, any>;
}
const defaultProps: Partial<ChipProps> = {
type: 'checkbox',
size: 'sm',
radius: 'xl',
variant: 'outline',
};
type ChipComponent = ForwardRefWithStaticComponents<ChipProps, { Group: typeof ChipGroup }>;
export const Chip: ChipComponent = forwardRef<HTMLInputElement, ChipProps>((props, ref) => {
const {
radius,
type,
size,
variant,
disabled,
id,
color,
children,
className,
classNames,
style,
styles,
checked,
defaultChecked,
onChange,
sx,
wrapperProps,
value,
unstyled,
...others
} = useComponentDefaultProps('Chip', defaultProps, props);
const ctx = useChipGroup();
const uuid = useId(id);
const { systemStyles, rest } = extractSystemStyles(others);
const { classes, cx } = useStyles(
{ radius, size, color },
{ classNames, styles, unstyled, name: 'Chip' }
);
const [_value, setValue] = useUncontrolled({
value: checked,
defaultValue: defaultChecked,
finalValue: false,
onChange,
});
const contextProps = ctx
? {
checked: ctx.isChipSelected(value as string),
onChange: ctx.onChange,
type: ctx.multiple ? 'checkbox' : 'radio',
}
: {};
const _checked = contextProps.checked || _value;
return (
<Box
className={cx(classes.root, className)}
style={style}
sx={sx}
{...systemStyles}
{...wrapperProps}
>
<input
type={type}
className={classes.input}
checked={_checked}
onChange={(event) => setValue(event.currentTarget.checked)}
id={uuid}
disabled={disabled}
ref={ref}
value={value}
{...contextProps}
{...rest}
/>
<label
htmlFor={uuid}
data-checked={_checked || undefined}
data-disabled={disabled || undefined}
data-variant={variant}
className={classes.label}
>
{_checked && (
<span className={classes.iconWrapper}>
<CheckIcon className={classes.checkIcon} />
</span>
)}
{children}
</label>
</Box>
);
}) as any;
Chip.displayName = '@mantine/core/Chip';
Chip.Group = ChipGroup;