-
Notifications
You must be signed in to change notification settings - Fork 2.9k
/
Checkbox.tsx
131 lines (111 loc) · 4.15 KB
/
Checkbox.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
import React, {forwardRef} from 'react';
import type {ForwardedRef, MouseEventHandler, KeyboardEvent as ReactKeyboardEvent} from 'react';
import type {GestureResponderEvent, StyleProp, ViewStyle} from 'react-native';
import {View} from 'react-native';
import useStyleUtils from '@hooks/useStyleUtils';
import useTheme from '@hooks/useTheme';
import useThemeStyles from '@hooks/useThemeStyles';
import CONST from '@src/CONST';
import type ChildrenProps from '@src/types/utils/ChildrenProps';
import Icon from './Icon';
import * as Expensicons from './Icon/Expensicons';
import PressableWithFeedback from './Pressable/PressableWithFeedback';
type CheckboxProps = Partial<ChildrenProps> & {
/** Whether checkbox is checked */
isChecked?: boolean;
/** A function that is called when the box/label is pressed */
onPress: () => void;
/** Should the input be styled for errors */
hasError?: boolean;
/** Should the input be disabled */
disabled?: boolean;
/** Additional styles to add to checkbox button */
style?: StyleProp<ViewStyle>;
/** Additional styles to add to checkbox container */
containerStyle?: StyleProp<ViewStyle>;
/** Callback that is called when mousedown is triggered. */
onMouseDown?: MouseEventHandler;
/** The size of the checkbox container */
containerSize?: number;
/** The border radius of the checkbox container */
containerBorderRadius?: number;
/** The size of the caret (checkmark) */
caretSize?: number;
/** An accessibility label for the checkbox */
accessibilityLabel: string;
};
function Checkbox(
{
isChecked = false,
hasError = false,
disabled = false,
style,
containerStyle,
children = null,
onMouseDown,
containerSize = 20,
containerBorderRadius = 4,
caretSize = 14,
onPress,
accessibilityLabel,
}: CheckboxProps,
ref: ForwardedRef<View>,
) {
const theme = useTheme();
const styles = useThemeStyles();
const StyleUtils = useStyleUtils();
const handleSpaceKey = (event?: ReactKeyboardEvent) => {
if (event?.code !== 'Space') {
return;
}
onPress();
};
const firePressHandlerOnClick = (event?: GestureResponderEvent | KeyboardEvent) => {
// Pressable can be triggered with Enter key and by a click. As this is a checkbox,
// We do not want to toggle it, when Enter key is pressed.
if (event?.type && event.type !== 'click') {
return;
}
onPress();
};
return (
<PressableWithFeedback
disabled={disabled}
onPress={firePressHandlerOnClick}
onMouseDown={onMouseDown}
ref={ref}
style={[StyleUtils.getCheckboxPressableStyle(containerBorderRadius + 2), style]} // to align outline on focus, border-radius of pressable should be 2px more than Checkbox
onKeyDown={handleSpaceKey}
role={CONST.ROLE.CHECKBOX}
aria-checked={isChecked}
accessibilityLabel={accessibilityLabel}
pressDimmingValue={1}
>
{children ?? (
<View
style={[
StyleUtils.getCheckboxContainerStyle(containerSize, containerBorderRadius),
containerStyle,
isChecked && styles.checkedContainer,
hasError && styles.borderColorDanger,
disabled && styles.cursorDisabled,
disabled && styles.buttonOpacityDisabled,
isChecked && styles.borderColorFocus,
]}
>
{isChecked && (
<Icon
src={Expensicons.Checkmark}
fill={theme.textLight}
height={caretSize}
width={caretSize}
/>
)}
</View>
)}
</PressableWithFeedback>
);
}
Checkbox.displayName = 'Checkbox';
export default forwardRef(Checkbox);
export type {CheckboxProps};