react-native-molecules 0.5.0-beta.3 → 0.5.0-beta.31

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (227) hide show
  1. package/components/Accordion/Accordion.tsx +2 -6
  2. package/components/Accordion/AccordionItem.tsx +16 -12
  3. package/components/Accordion/AccordionItemContent.tsx +6 -1
  4. package/components/Accordion/AccordionItemHeader.tsx +1 -1
  5. package/components/Accordion/utils.ts +6 -0
  6. package/components/ActivityIndicator/ActivityIndicator.tsx +6 -15
  7. package/components/Appbar/AppbarBase.tsx +18 -13
  8. package/components/Button/Button.tsx +211 -264
  9. package/components/Button/index.tsx +9 -3
  10. package/components/Button/types.ts +16 -2
  11. package/components/Button/utils.ts +230 -208
  12. package/components/Card/Card.tsx +1 -1
  13. package/components/Checkbox/Checkbox.tsx +125 -88
  14. package/components/Checkbox/CheckboxBase.ios.tsx +14 -23
  15. package/components/Checkbox/CheckboxBase.tsx +21 -137
  16. package/components/Checkbox/context.tsx +14 -0
  17. package/components/Checkbox/index.tsx +11 -4
  18. package/components/Checkbox/types.ts +63 -29
  19. package/components/Checkbox/utils.ts +25 -108
  20. package/components/Chip/Chip.tsx +41 -52
  21. package/components/Chip/utils.ts +3 -7
  22. package/components/DateField/DateField.tsx +111 -0
  23. package/components/DateField/index.tsx +6 -0
  24. package/components/{DatePickerInput/inputUtils.ts → DateField/useDateFieldState.ts} +19 -51
  25. package/components/DatePicker/DateCalendar.tsx +83 -0
  26. package/components/DatePicker/DatePickerActions.tsx +73 -0
  27. package/components/DatePicker/DatePickerModal.tsx +246 -0
  28. package/components/DatePicker/DatePickerPopover.tsx +79 -0
  29. package/components/DatePicker/DatePickerProvider.tsx +158 -0
  30. package/components/DatePicker/DatePickerTrigger.tsx +23 -0
  31. package/components/DatePicker/context.tsx +83 -0
  32. package/components/DatePicker/index.tsx +45 -0
  33. package/components/DatePicker/utils.ts +295 -0
  34. package/components/DatePickerInline/DatePickerDockedHeader.tsx +117 -0
  35. package/components/DatePickerInline/DatePickerInline.tsx +17 -16
  36. package/components/DatePickerInline/DatePickerInlineBase.tsx +11 -5
  37. package/components/DatePickerInline/DatePickerInlineHeader.tsx +50 -20
  38. package/components/DatePickerInline/Day.tsx +25 -1
  39. package/components/DatePickerInline/DayNames.tsx +13 -10
  40. package/components/DatePickerInline/DayRange.tsx +2 -4
  41. package/components/DatePickerInline/HeaderItem.tsx +44 -29
  42. package/components/DatePickerInline/Month.tsx +48 -67
  43. package/components/DatePickerInline/MonthPicker.tsx +80 -92
  44. package/components/DatePickerInline/Swiper.native.tsx +21 -4
  45. package/components/DatePickerInline/Swiper.tsx +169 -14
  46. package/components/DatePickerInline/SwiperUtils.ts +1 -1
  47. package/components/DatePickerInline/Week.tsx +6 -1
  48. package/components/DatePickerInline/YearPicker.tsx +220 -78
  49. package/components/DatePickerInline/dateUtils.tsx +18 -13
  50. package/components/DatePickerInline/store.tsx +27 -0
  51. package/components/DatePickerInline/types.ts +6 -2
  52. package/components/DatePickerInline/utils.ts +66 -29
  53. package/components/Divider/Divider.tsx +192 -0
  54. package/components/Divider/index.tsx +10 -0
  55. package/components/Drawer/Drawer.tsx +17 -6
  56. package/components/Drawer/DrawerItemGroup.tsx +3 -7
  57. package/components/ElementGroup/ElementGroup.tsx +1 -1
  58. package/components/FilePicker/FilePicker.tsx +48 -78
  59. package/components/FilePicker/index.tsx +2 -1
  60. package/components/FilePicker/utils.ts +9 -0
  61. package/components/HelperText/HelperText.tsx +0 -35
  62. package/components/Icon/iconFactory.tsx +5 -4
  63. package/components/Icon/index.tsx +1 -1
  64. package/components/Icon/types.ts +17 -6
  65. package/components/IconButton/IconButton.tsx +84 -84
  66. package/components/IconButton/index.tsx +1 -0
  67. package/components/IconButton/types.ts +10 -0
  68. package/components/IconButton/utils.ts +167 -33
  69. package/components/List/List.tsx +276 -0
  70. package/components/List/context.tsx +27 -0
  71. package/components/List/index.ts +8 -0
  72. package/components/List/types.ts +117 -0
  73. package/components/List/utils.ts +79 -0
  74. package/components/LoadingIndicator/LoadingIndicator.tsx +253 -0
  75. package/components/LoadingIndicator/LoadingIndicator.web.tsx +136 -0
  76. package/components/LoadingIndicator/index.tsx +13 -0
  77. package/components/LoadingIndicator/utils.ts +117 -0
  78. package/components/Menu/Menu.tsx +162 -39
  79. package/components/Menu/index.tsx +10 -7
  80. package/components/Menu/utils.ts +21 -70
  81. package/components/NavigationRail/NavigationRail.tsx +15 -9
  82. package/components/Popover/Popover.tsx +119 -145
  83. package/components/Popover/PopoverRoot.tsx +60 -0
  84. package/components/Popover/common.ts +54 -34
  85. package/components/Popover/index.ts +12 -1
  86. package/components/Popover/usePlatformMeasure.native.ts +90 -0
  87. package/components/Popover/usePlatformMeasure.ts +120 -0
  88. package/components/Popover/utils.ts +34 -0
  89. package/components/Portal/Portal.tsx +1 -2
  90. package/components/Radio/Radio.tsx +188 -0
  91. package/components/Radio/RadioBase.ios.tsx +69 -0
  92. package/components/Radio/RadioBase.tsx +136 -0
  93. package/components/Radio/context.tsx +23 -0
  94. package/components/Radio/index.tsx +20 -0
  95. package/components/Radio/types.ts +101 -0
  96. package/components/Radio/utils.ts +115 -0
  97. package/components/Rating/Rating.tsx +1 -1
  98. package/components/Select/Select.tsx +521 -785
  99. package/components/Select/context.tsx +81 -0
  100. package/components/Select/index.ts +26 -14
  101. package/components/Select/types.ts +65 -58
  102. package/components/Select/utils.ts +126 -0
  103. package/components/Slot/Slot.tsx +224 -0
  104. package/components/Slot/compose-refs.tsx +62 -0
  105. package/components/Slot/index.tsx +8 -0
  106. package/components/Surface/Surface.android.tsx +32 -7
  107. package/components/Surface/Surface.ios.tsx +34 -29
  108. package/components/Surface/Surface.tsx +31 -4
  109. package/components/Surface/utils.ts +44 -6
  110. package/components/Switch/Switch.ios.tsx +1 -1
  111. package/components/Switch/Switch.tsx +10 -3
  112. package/components/Tabs/TabItem.tsx +35 -58
  113. package/components/Tabs/TabLabel.tsx +5 -9
  114. package/components/Tabs/Tabs.tsx +156 -150
  115. package/components/Tabs/utils.ts +15 -2
  116. package/components/Text/textFactory.tsx +17 -5
  117. package/components/TextInput/TextInput.tsx +663 -579
  118. package/components/TextInput/index.tsx +19 -3
  119. package/components/TextInput/types.ts +77 -28
  120. package/components/TextInput/utils.ts +235 -145
  121. package/components/TimeField/TimeField.tsx +75 -0
  122. package/components/TimeField/index.tsx +6 -0
  123. package/components/TimeField/useTimeFieldState.ts +70 -0
  124. package/components/{TimePickerField/sanitizeTime.ts → TimeField/utils.ts} +77 -10
  125. package/components/TimePicker/AnalogClock.tsx +1 -1
  126. package/components/TimePicker/TimeInput.tsx +87 -42
  127. package/components/TimePicker/TimeInputs.tsx +138 -50
  128. package/components/TimePicker/TimePicker.tsx +74 -11
  129. package/components/TimePicker/TimePickerModal.tsx +186 -0
  130. package/components/TimePicker/context.tsx +17 -0
  131. package/components/TimePicker/index.tsx +15 -3
  132. package/components/TimePicker/utils.ts +93 -4
  133. package/components/Tooltip/Tooltip.tsx +42 -67
  134. package/components/Tooltip/TooltipContent.tsx +32 -5
  135. package/components/Tooltip/TooltipTrigger.tsx +21 -24
  136. package/components/Tooltip/index.tsx +1 -1
  137. package/components/TouchableRipple/TouchableRipple.native.tsx +83 -16
  138. package/components/TouchableRipple/TouchableRipple.tsx +150 -102
  139. package/components/TouchableRipple/rippleFromForegroundColor.ts +21 -0
  140. package/hocs/index.tsx +1 -1
  141. package/hocs/withKeyboardAccessibility.tsx +2 -3
  142. package/hocs/withPortal.tsx +1 -1
  143. package/hooks/index.tsx +2 -12
  144. package/hooks/useActionState.tsx +19 -8
  145. package/hooks/useContrastColor.ts +1 -2
  146. package/hooks/useFilePicker.tsx +7 -17
  147. package/hooks/useHandleNumberFormat.tsx +2 -2
  148. package/hooks/useMediaQuery.tsx +1 -2
  149. package/package.json +95 -111
  150. package/shortcuts-manager/ShortcutsManager/ShortcutsManager.tsx +6 -3
  151. package/shortcuts-manager/ShortcutsManager/utils.tsx +1 -1
  152. package/shortcuts-manager/useSetScopes/useSetScopes.tsx +1 -1
  153. package/shortcuts-manager/useShortcut/useShortcut.tsx +1 -1
  154. package/styles/shadow.ts +2 -1
  155. package/styles/themes/LightTheme.tsx +1 -1
  156. package/utils/DocumentPicker/documentPicker.ts +78 -27
  157. package/utils/DocumentPicker/types.ts +0 -1
  158. package/utils/extractSubcomponents.ts +89 -0
  159. package/utils/extractTextStyles.ts +1 -2
  160. package/utils/formatNumberWithMask/formatNumberWithMask.ts +2 -1
  161. package/utils/index.ts +0 -3
  162. package/utils/normalizeToNumberString/normalizeToNumberString.ts +1 -1
  163. package/components/DatePickerDocked/DatePickerDocked.tsx +0 -30
  164. package/components/DatePickerDocked/DatePickerDockedHeader.tsx +0 -129
  165. package/components/DatePickerDocked/index.tsx +0 -17
  166. package/components/DatePickerDocked/types.ts +0 -11
  167. package/components/DatePickerDocked/utils.ts +0 -157
  168. package/components/DatePickerInline/DatePickerContext.tsx +0 -21
  169. package/components/DatePickerInput/DatePickerInput.tsx +0 -139
  170. package/components/DatePickerInput/DatePickerInputModal.tsx +0 -48
  171. package/components/DatePickerInput/DatePickerInputWithoutModal.tsx +0 -77
  172. package/components/DatePickerInput/DateRangeInput.tsx +0 -88
  173. package/components/DatePickerInput/index.tsx +0 -10
  174. package/components/DatePickerInput/types.ts +0 -28
  175. package/components/DatePickerInput/utils.ts +0 -15
  176. package/components/DatePickerModal/AnimatedCrossView.tsx +0 -94
  177. package/components/DatePickerModal/CalendarEdit.tsx +0 -139
  178. package/components/DatePickerModal/DatePickerModal.tsx +0 -85
  179. package/components/DatePickerModal/DatePickerModalContent.tsx +0 -155
  180. package/components/DatePickerModal/DatePickerModalContentHeader.tsx +0 -213
  181. package/components/DatePickerModal/DatePickerModalHeader.tsx +0 -74
  182. package/components/DatePickerModal/DatePickerModalHeaderBackground.tsx +0 -13
  183. package/components/DatePickerModal/index.tsx +0 -16
  184. package/components/DatePickerModal/types.ts +0 -92
  185. package/components/DatePickerModal/utils.ts +0 -122
  186. package/components/DateTimePicker/DateTimePicker.tsx +0 -172
  187. package/components/DateTimePicker/index.tsx +0 -10
  188. package/components/DateTimePicker/utils.ts +0 -12
  189. package/components/HorizontalDivider/HorizontalDivider.tsx +0 -103
  190. package/components/HorizontalDivider/index.tsx +0 -9
  191. package/components/ListItem/ListItem.tsx +0 -136
  192. package/components/ListItem/ListItemDescription.tsx +0 -25
  193. package/components/ListItem/ListItemTitle.tsx +0 -25
  194. package/components/ListItem/index.tsx +0 -14
  195. package/components/ListItem/utils.ts +0 -115
  196. package/components/Menu/MenuDivider.tsx +0 -13
  197. package/components/Menu/MenuItem.tsx +0 -128
  198. package/components/Popover/Popover.native.tsx +0 -185
  199. package/components/RadioButton/RadioButton.tsx +0 -138
  200. package/components/RadioButton/RadioButtonAndroid.tsx +0 -188
  201. package/components/RadioButton/RadioButtonGroup.tsx +0 -98
  202. package/components/RadioButton/RadioButtonIOS.tsx +0 -106
  203. package/components/RadioButton/RadioButtonItem.tsx +0 -232
  204. package/components/RadioButton/index.ts +0 -22
  205. package/components/RadioButton/utils.ts +0 -165
  206. package/components/TimePickerField/TimePickerField.tsx +0 -152
  207. package/components/TimePickerField/index.tsx +0 -10
  208. package/components/TimePickerField/utils.ts +0 -94
  209. package/components/TimePickerModal/TimePickerModal.tsx +0 -115
  210. package/components/TimePickerModal/index.tsx +0 -10
  211. package/components/TimePickerModal/utils.ts +0 -47
  212. package/components/VerticalDivider/VerticalDivider.tsx +0 -100
  213. package/components/VerticalDivider/index.tsx +0 -9
  214. package/context-bridge/index.tsx +0 -87
  215. package/fast-context/index.tsx +0 -190
  216. package/hocs/typedMemo.tsx +0 -5
  217. package/hooks/useControlledValue.tsx +0 -68
  218. package/hooks/useLatest.tsx +0 -9
  219. package/hooks/useMergedRefs.ts +0 -14
  220. package/hooks/usePrevious.ts +0 -13
  221. package/hooks/useSearchable.tsx +0 -74
  222. package/hooks/useSubcomponents.tsx +0 -59
  223. package/hooks/useToggle.tsx +0 -24
  224. package/utils/color.ts +0 -22
  225. package/utils/compare/index.ts +0 -54
  226. package/utils/lodash.ts +0 -49
  227. package/utils/repository.ts +0 -53
@@ -1,124 +1,161 @@
1
- import { forwardRef, memo, useCallback, useMemo } from 'react';
1
+ import { useControlledValue } from '@react-native-molecules/utils/hooks';
2
+ import { forwardRef, memo, useCallback, useContext, useId, useMemo } from 'react';
2
3
  import { View } from 'react-native';
3
4
 
4
- import { useControlledValue } from '../../hooks';
5
5
  import { resolveStateVariant } from '../../utils';
6
6
  import { Text } from '../Text';
7
7
  import CheckboxBase from './CheckboxBase';
8
- import type { CheckBoxBaseProps, States } from './types';
9
- import { styles } from './utils';
10
-
11
- export type Props = CheckBoxBaseProps;
8
+ import { CheckboxItemContext } from './context';
9
+ import type { CheckboxLabelProps, CheckboxProps, CheckboxRowProps } from './types';
10
+ import { checkboxRowStyles } from './utils';
12
11
 
12
+ /**
13
+ * The checkbox control (the box). Use inside a CheckboxRow, or standalone with `value`/`onChange`.
14
+ */
13
15
  const Checkbox = (
14
16
  {
15
17
  value: valueProp,
16
- onChange: onChangeProp,
17
18
  defaultValue,
18
- disabled,
19
+ onChange: onChangeProp,
19
20
  indeterminate,
20
- label,
21
- labelStyle,
22
- containerStyle,
23
- labelProps,
24
- position = 'leading',
25
- accessibilityLabel: accessibilityLabelProp,
21
+ disabled: disabledProp,
22
+ size: sizeProp,
26
23
  testID,
27
- size = 'md',
28
- style: styleProp,
29
24
  ...rest
30
- }: Props,
25
+ }: CheckboxProps,
31
26
  ref: any,
32
27
  ) => {
33
- const [value, onChange] = useControlledValue({
28
+ const item = useContext(CheckboxItemContext);
29
+
30
+ const [value, setValue] = useControlledValue({
34
31
  value: valueProp,
35
- onChange: onChangeProp,
36
32
  defaultValue,
37
- disabled: disabled,
33
+ onChange: onChangeProp,
34
+ disabled: disabledProp,
38
35
  });
39
36
 
40
- // Prepare label-related state and styles (always compute, even if not used)
41
- const isLeading = position === 'leading';
42
- const checked = Boolean(value) && !indeterminate;
43
- const state = resolveStateVariant({ disabled: Boolean(disabled), checked });
44
- const accessibilityLabel = accessibilityLabelProp ?? label;
45
-
46
- // Use variants only when label is provided
47
- if (label) {
48
- styles.useVariants({
49
- variant: 'item',
50
- // @ts-ignore // TODO - fix this
51
- state: state as States,
52
- isLeading,
53
- size,
54
- });
55
- }
37
+ // Inside a CheckboxRow the item context drives state; standalone (bare) mode owns its own.
38
+ const checked = item ? item.checked : Boolean(value);
39
+ const disabled = disabledProp ?? item?.disabled;
40
+ const isIndeterminate = item ? item.indeterminate : indeterminate;
41
+ const size = sizeProp ?? item?.size ?? 'md';
42
+ const labelId = item?.labelId;
56
43
 
57
- const { containerStyles, labelStyles, style } = useMemo(() => {
58
- return {
59
- containerStyles: [styles.itemContainer, containerStyle],
60
- labelStyles: [
61
- // @ts-ignore
62
- styles.label,
63
- labelStyle,
64
- ],
65
- style: [styles.root, styleProp],
66
- };
67
- }, [containerStyle, labelStyle, styleProp]);
68
-
69
- const onLabelPress = useCallback(() => {
70
- if (!disabled) {
71
- onChange(!value);
72
- }
73
- }, [onChange, value, disabled]);
74
-
75
- const accessibilityState = useMemo(
76
- () => ({
77
- checked: Boolean(value),
78
- disabled,
79
- }),
80
- [disabled, value],
44
+ const onChange = useCallback(
45
+ (next: boolean) => {
46
+ if (item) {
47
+ item.onToggle();
48
+ } else {
49
+ setValue(next);
50
+ }
51
+ },
52
+ [item, setValue],
81
53
  );
82
54
 
83
- const checkboxStyle = label ? style : styleProp;
84
- const checkboxAccessibilityLabel = label ? undefined : accessibilityLabelProp;
85
-
86
- const checkbox = (
55
+ return (
87
56
  <CheckboxBase
88
- ref={label ? undefined : ref}
89
- value={value}
57
+ {...rest}
58
+ ref={ref}
59
+ value={checked}
90
60
  onChange={onChange}
61
+ indeterminate={isIndeterminate}
91
62
  disabled={disabled}
92
- indeterminate={indeterminate}
93
63
  size={size}
94
- style={checkboxStyle}
95
64
  testID={testID}
96
- accessibilityLabel={checkboxAccessibilityLabel}
97
- {...rest}
65
+ accessibilityLabelledBy={labelId}
98
66
  />
99
67
  );
68
+ };
69
+
70
+ /**
71
+ * The label for a CheckboxRow. Pressing it toggles the checkbox, and it is wired to the control via
72
+ * `nativeID` / `accessibilityLabelledBy` (web `id` / `aria-labelledby`).
73
+ */
74
+ export const CheckboxLabel = memo(({ children, style, ...rest }: CheckboxLabelProps) => {
75
+ const item = useContext(CheckboxItemContext);
100
76
 
101
- if (!label) {
102
- return checkbox;
77
+ const state = resolveStateVariant({
78
+ disabled: !!item?.disabled,
79
+ checked: !!item?.checked,
80
+ });
81
+
82
+ checkboxRowStyles.useVariants({ state: state as any });
83
+
84
+ if (!item) {
85
+ return (
86
+ <Text style={style} {...rest}>
87
+ {children}
88
+ </Text>
89
+ );
103
90
  }
104
91
 
105
92
  return (
106
- <View style={containerStyles} ref={ref}>
107
- {isLeading && checkbox}
108
- <Text
109
- onPress={onLabelPress}
110
- disabled={disabled}
111
- selectable={false}
112
- accessibilityLabel={accessibilityLabel}
113
- accessibilityRole="checkbox"
114
- accessibilityState={accessibilityState}
115
- {...labelProps}
116
- style={labelStyles}>
117
- {label}
118
- </Text>
119
- {!isLeading && checkbox}
120
- </View>
93
+ <Text
94
+ nativeID={item.labelId}
95
+ onPress={item.disabled ? undefined : item.onToggle}
96
+ disabled={item.disabled}
97
+ selectable={false}
98
+ style={[checkboxRowStyles.label, style]}
99
+ {...rest}>
100
+ {children}
101
+ </Text>
121
102
  );
122
- };
103
+ });
104
+
105
+ CheckboxLabel.displayName = 'Checkbox_Label';
106
+
107
+ /**
108
+ * A row that binds checked state to a Checkbox control and its Checkbox.Label. The row itself is not
109
+ * pressable — only the Checkbox and Checkbox.Label inside it are. Children may be in any order.
110
+ */
111
+ export const CheckboxRow = memo(
112
+ forwardRef(
113
+ (
114
+ {
115
+ value: valueProp,
116
+ defaultValue,
117
+ onChange,
118
+ indeterminate,
119
+ disabled,
120
+ size,
121
+ style,
122
+ children,
123
+ ...rest
124
+ }: CheckboxRowProps,
125
+ ref: any,
126
+ ) => {
127
+ const labelId = useId();
128
+
129
+ const [value, setValue] = useControlledValue({
130
+ value: valueProp,
131
+ defaultValue,
132
+ onChange,
133
+ disabled,
134
+ });
135
+
136
+ const checked = Boolean(value);
137
+
138
+ const onToggle = useCallback(() => {
139
+ if (disabled) return;
140
+ setValue(indeterminate ? true : !checked);
141
+ }, [disabled, setValue, checked, indeterminate]);
142
+
143
+ const contextValue = useMemo(
144
+ () => ({ checked, onToggle, disabled, indeterminate, size, labelId }),
145
+ [checked, onToggle, disabled, indeterminate, size, labelId],
146
+ );
147
+
148
+ return (
149
+ <CheckboxItemContext.Provider value={contextValue}>
150
+ <View ref={ref} style={[checkboxRowStyles.row, style]} {...rest}>
151
+ {children}
152
+ </View>
153
+ </CheckboxItemContext.Provider>
154
+ );
155
+ },
156
+ ),
157
+ );
158
+
159
+ CheckboxRow.displayName = 'Checkbox_Row';
123
160
 
124
161
  export default memo(forwardRef(Checkbox));
@@ -1,16 +1,13 @@
1
- import setColor from 'color';
2
1
  import { forwardRef, memo, useCallback, useMemo } from 'react';
3
2
  import { View } from 'react-native';
4
3
 
5
4
  import { resolveStateVariant } from '../../utils';
6
5
  import { Icon } from '../Icon';
7
6
  import { TouchableRipple } from '../TouchableRipple';
8
- import type { CheckBoxBaseProps, States } from './types';
7
+ import type { CheckboxBaseProps, States } from './types';
9
8
  import { iconSizeMap, styles } from './utils';
10
9
 
11
- export type Props = Omit<CheckBoxBaseProps, 'uncheckedColor' | 'value' | 'defaultValue'> & {
12
- value: boolean;
13
- };
10
+ export type Props = Omit<CheckboxBaseProps, 'uncheckedColor'>;
14
11
 
15
12
  const CheckboxIOS = (
16
13
  {
@@ -37,24 +34,19 @@ const CheckboxIOS = (
37
34
  state: state as States,
38
35
  size,
39
36
  });
37
+ const checkedColor = colorProp;
40
38
 
41
- const { checkedColor, iconSize, rippleColor, rippleContainerStyles, iconContainerStyles } =
42
- useMemo(() => {
43
- const _checkedColor = colorProp;
44
-
45
- return {
46
- checkedColor: _checkedColor,
47
- iconSize: iconSizeMap[size],
48
- rippleColor: setColor(_checkedColor).fade(0.32).rgb().string(),
49
- rippleContainerStyles: [styles.root, style],
50
- iconContainerStyles: { opacity: indeterminate || checked ? 1 : 0 },
51
- };
52
- // eslint-disable-next-line react-hooks/exhaustive-deps
53
- }, [checked, colorProp, indeterminate, style, state, size]);
39
+ const { rippleContainerStyles, iconContainerStyles } = useMemo(() => {
40
+ return {
41
+ rippleContainerStyles: [styles.root, style],
42
+ iconContainerStyles: { opacity: indeterminate || checked ? 1 : 0 },
43
+ };
44
+ // eslint-disable-next-line react-hooks/exhaustive-deps
45
+ }, [checked, colorProp, indeterminate, style, state, size, checkedColor]);
54
46
 
55
47
  const onChange = useCallback(() => {
56
- onChangeProp?.(!checked);
57
- }, [checked, onChangeProp]);
48
+ onChangeProp?.(indeterminate ? true : !checked);
49
+ }, [checked, indeterminate, onChangeProp]);
58
50
 
59
51
  const icon = indeterminate ? 'minus' : 'check';
60
52
 
@@ -62,11 +54,10 @@ const CheckboxIOS = (
62
54
  <TouchableRipple
63
55
  {...rest}
64
56
  borderless
65
- rippleColor={rippleColor}
66
57
  onPress={onChange}
67
58
  disabled={disabled}
68
59
  accessibilityRole="checkbox"
69
- accessibilityState={{ disabled, checked }}
60
+ accessibilityState={{ disabled, checked: indeterminate ? false : checked }}
70
61
  accessibilityLiveRegion="polite"
71
62
  style={rippleContainerStyles}
72
63
  testID={testID}
@@ -76,7 +67,7 @@ const CheckboxIOS = (
76
67
  allowFontScaling={false}
77
68
  type="material-community"
78
69
  name={icon}
79
- size={iconSize}
70
+ size={iconSizeMap[size]}
80
71
  color={checkedColor}
81
72
  />
82
73
  </View>
@@ -1,15 +1,4 @@
1
- import setColor from 'color';
2
- import {
3
- forwardRef,
4
- memo,
5
- type PropsWithoutRef,
6
- useCallback,
7
- useEffect,
8
- useMemo,
9
- useRef,
10
- } from 'react';
11
- import { Animated, Platform, View, type ViewProps } from 'react-native';
12
- import { StyleSheet } from 'react-native-unistyles';
1
+ import { forwardRef, memo, useCallback, useMemo } from 'react';
13
2
 
14
3
  import { useActionState } from '../../hooks';
15
4
  import { resolveStateVariant } from '../../utils';
@@ -17,16 +6,10 @@ import { tokenStylesParser } from '../../utils/tokenStylesParser';
17
6
  import { Icon } from '../Icon';
18
7
  import { StateLayer } from '../StateLayer';
19
8
  import { TouchableRipple } from '../TouchableRipple';
20
- import type { CheckBoxBaseProps, States } from './types';
9
+ import type { CheckboxBaseProps, States } from './types';
21
10
  import { iconSizeMap, styles } from './utils';
22
11
 
23
- export type Props = Omit<CheckBoxBaseProps, 'value' | 'defaultValue'> & {
24
- value: boolean;
25
- /**
26
- * props for the stateLayer
27
- */
28
- stateLayerProps?: PropsWithoutRef<ViewProps>;
29
- };
12
+ export type Props = CheckboxBaseProps;
30
13
 
31
14
  const CheckboxAndroid = (
32
15
  {
@@ -44,9 +27,6 @@ const CheckboxAndroid = (
44
27
  }: Props,
45
28
  ref: any,
46
29
  ) => {
47
- const { current: scaleAnim } = useRef<Animated.Value>(new Animated.Value(1));
48
- const isFirstRendering = useRef<boolean>(true);
49
-
50
30
  const { actionsRef, hovered } = useActionState({ ref, actionsToListen: ['hover'] });
51
31
 
52
32
  const state = resolveStateVariant({
@@ -63,105 +43,19 @@ const CheckboxAndroid = (
63
43
  size,
64
44
  });
65
45
 
66
- // const componentStyles = useComponentStyles('Checkbox', style, {
67
- // variant: 'android',
68
- // state: resolveStateVariant({
69
- // disabled,
70
- // checkedAndHovered: checked && !indeterminate && hovered,
71
- // checked: checked && !indeterminate,
72
- // hovered,
73
- // }),
74
- // size,
75
- // });
76
-
77
- const borderWidth = scaleAnim.interpolate({
78
- inputRange: [0.8, 1],
79
- outputRange: [7, 0],
80
- });
81
-
82
- const {
83
- iconSize,
84
- rippleColor,
85
- scale,
86
- animationDuration,
87
- rippleContainerStyles,
88
- filledContainerStyles,
89
- animatedContainerStyles,
90
- animatedFillStyles,
91
- stateLayerStyle,
92
- iconStyle,
93
- } = useMemo(() => {
94
- // const {
95
- // color: checkedColor,
96
- // uncheckedColor,
97
- // animationScale: _scale,
98
- // animationDuration: _animationDuration,
99
- // iconSize: _iconSize,
100
- // padding,
101
- // width,
102
- // height,
103
- // borderRadius,
104
- // ...checkboxStyles
105
- // // @ts-ignore
106
- // } = styles.root;
107
-
46
+ const { rippleContainerStyles, iconStyle } = useMemo(() => {
108
47
  const _color = tokenStylesParser.getColor(checked ? colorProp : uncheckedColorProp);
109
48
 
110
49
  return {
111
50
  iconStyle: [styles.icon, _color],
112
- iconSize: iconSizeMap[size],
113
- // TODO - fix this on web
114
- rippleColor:
115
- Platform.OS === 'web' ? undefined : setColor(_color).fade(0.32).rgb().string(),
116
- checkboxStyle: [styles.root, style],
117
- scale: 1,
118
- animationDuration: 100,
119
- rippleContainerStyles: [styles.root],
120
- animatedContainerStyles: { transform: [{ scale: scaleAnim }] },
121
- filledContainerStyles: [StyleSheet.absoluteFill, styles.fillContainer],
122
- // for toggle animation // This needs to be computed because it's opinionated animation
123
- animatedFillStyles: [
124
- styles.animatedFill, // 4 because padding - border(which is 1px each side)
125
- tokenStylesParser.getColor(checked ? colorProp : uncheckedColorProp, 'borderColor'),
126
- { borderWidth },
127
- ],
128
- stateLayerStyle: [styles.stateLayer, stateLayerProps?.style],
51
+ rippleContainerStyles: [styles.root, style],
129
52
  };
130
- }, [
131
- borderWidth,
132
- checked,
133
- colorProp,
134
- scaleAnim,
135
- stateLayerProps?.style,
136
- style,
137
- uncheckedColorProp,
138
- size,
139
- ]);
140
-
141
- useEffect(() => {
142
- // Do not run animation on very first rendering
143
- if (isFirstRendering.current) {
144
- isFirstRendering.current = false;
145
- return;
146
- }
147
-
148
- Animated.sequence([
149
- Animated.timing(scaleAnim, {
150
- toValue: 0.85,
151
- duration: checked ? animationDuration * scale : 0,
152
- useNativeDriver: false,
153
- }),
154
- Animated.timing(scaleAnim, {
155
- toValue: 1,
156
- duration: checked ? animationDuration * scale : animationDuration * scale * 1.75,
157
- useNativeDriver: false,
158
- }),
159
- ]).start();
160
- }, [checked, scaleAnim, scale, animationDuration]);
53
+ // eslint-disable-next-line react-hooks/exhaustive-deps
54
+ }, [checked, colorProp, uncheckedColorProp, style, size, state]);
161
55
 
162
56
  const onChange = useCallback(() => {
163
- onChangeProp?.(!checked);
164
- }, [checked, onChangeProp]);
57
+ onChangeProp?.(indeterminate ? true : !checked);
58
+ }, [checked, indeterminate, onChangeProp]);
165
59
 
166
60
  const icon = indeterminate
167
61
  ? 'minus-box'
@@ -169,13 +63,15 @@ const CheckboxAndroid = (
169
63
  ? 'checkbox-marked'
170
64
  : 'checkbox-blank-outline';
171
65
 
172
- const accessibilityState = useMemo(() => ({ disabled, checked }), [checked, disabled]);
66
+ const accessibilityState = useMemo(
67
+ () => ({ disabled, checked: indeterminate ? false : checked }),
68
+ [checked, disabled, indeterminate],
69
+ );
173
70
 
174
71
  return (
175
72
  <TouchableRipple
176
73
  {...rest}
177
74
  borderless
178
- rippleColor={rippleColor}
179
75
  onPress={onChange}
180
76
  disabled={disabled}
181
77
  accessibilityRole="checkbox"
@@ -185,33 +81,21 @@ const CheckboxAndroid = (
185
81
  testID={testID}
186
82
  ref={actionsRef}>
187
83
  <>
188
- <Animated.View style={animatedContainerStyles}>
189
- <Icon
190
- allowFontScaling={false}
191
- type="material-community"
192
- name={icon}
193
- size={iconSize}
194
- style={iconStyle}
195
- />
196
- <View style={filledContainerStyles}>
197
- <Animated.View style={animatedFillStyles} />
198
- </View>
199
- </Animated.View>
84
+ <Icon
85
+ allowFontScaling={false}
86
+ type="material-community"
87
+ name={icon}
88
+ size={iconSizeMap[size]}
89
+ style={iconStyle}
90
+ />
200
91
  <StateLayer
201
92
  testID={testID ? `${testID}-stateLayer` : ''}
202
93
  {...stateLayerProps}
203
- style={stateLayerStyle}
94
+ style={[styles.stateLayer, stateLayerProps?.style]}
204
95
  />
205
96
  </>
206
97
  </TouchableRipple>
207
98
  );
208
99
  };
209
100
 
210
- // const styles = StyleSheet.create({
211
- // fillContainer: {
212
- // alignItems: 'center',
213
- // justifyContent: 'center',
214
- // },
215
- // });
216
-
217
101
  export default memo(forwardRef(CheckboxAndroid));
@@ -0,0 +1,14 @@
1
+ import { createContext } from 'react';
2
+
3
+ import type { Size } from './types';
4
+
5
+ export type CheckboxItemContextType = {
6
+ checked: boolean;
7
+ onToggle: () => void;
8
+ disabled?: boolean;
9
+ indeterminate?: boolean;
10
+ size?: Size;
11
+ labelId: string;
12
+ };
13
+
14
+ export const CheckboxItemContext = createContext<CheckboxItemContextType | null>(null);
@@ -1,7 +1,14 @@
1
1
  import { getRegisteredComponentWithFallback } from '../../core';
2
- import CheckboxComponent from './Checkbox';
2
+ // @component ./Checkbox.tsx
3
+ import CheckboxBox, { CheckboxLabel, CheckboxRow as CheckboxRowComponent } from './Checkbox';
3
4
 
4
- export const Checkbox = getRegisteredComponentWithFallback('Checkbox', CheckboxComponent);
5
+ const CheckboxDefault = Object.assign(CheckboxBox, {
6
+ Label: CheckboxLabel,
7
+ Row: CheckboxRowComponent,
8
+ });
5
9
 
6
- export type { Props as CheckboxProps } from './Checkbox';
7
- export { styles as checkboxStyles } from './utils';
10
+ export const Checkbox = getRegisteredComponentWithFallback('Checkbox', CheckboxDefault);
11
+ export const CheckboxRow = CheckboxRowComponent;
12
+
13
+ export type { CheckboxLabelProps, CheckboxProps, CheckboxRowProps } from './types';
14
+ export { checkboxRowStyles, styles as checkboxStyles } from './utils';