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,140 +1,94 @@
1
- import setColor from 'color';
1
+ import { forwardRef, memo, type PropsWithoutRef, type ReactNode, useContext, useMemo } from 'react';
2
2
  import {
3
- forwardRef,
4
- memo,
5
- type PropsWithoutRef,
6
- type ReactNode,
7
- useCallback,
8
- useMemo,
9
- } from 'react';
10
- import { type StyleProp, type TextStyle, View, type ViewProps, type ViewStyle } from 'react-native';
3
+ type StyleProp,
4
+ type TextProps,
5
+ type TextStyle,
6
+ type ViewProps,
7
+ type ViewStyle,
8
+ } from 'react-native';
11
9
 
12
10
  import { useActionState } from '../../hooks';
13
11
  import type { MD3Elevation } from '../../types/theme';
14
12
  import { resolveStateVariant } from '../../utils';
15
- import { extractPropertiesFromStyles } from '../../utils/extractPropertiesFromStyles';
16
- import { ActivityIndicator } from '../ActivityIndicator';
17
- import { Icon, type IconType } from '../Icon';
13
+ import { ActivityIndicator, type ActivityIndicatorProps } from '../ActivityIndicator';
14
+ import { Icon, type IconProps } from '../Icon';
18
15
  import { StateLayer } from '../StateLayer';
19
16
  import { Surface, type SurfaceProps } from '../Surface';
20
17
  import { Text } from '../Text';
21
- import { TouchableRipple } from '../TouchableRipple';
22
- import type { ButtonSize, ButtonVariant } from './types';
23
- import { defaultStyles, sizeToIconSizeMap } from './utils';
18
+ import { TouchableRipple, type TouchableRippleProps } from '../TouchableRipple';
19
+ import type { ButtonContextType, ButtonShape, ButtonSize, ButtonVariant } from './types';
20
+ import {
21
+ buttonActivityIndicatorStyles,
22
+ ButtonContext,
23
+ buttonIconStyles,
24
+ buttonStyles,
25
+ buttonTextStyles,
26
+ elevationMap,
27
+ sizeToIconSizeMap,
28
+ } from './utils';
24
29
 
25
- export type Props = Omit<SurfaceProps, 'style'> & {
26
- /**
27
- * Mode of the button. You can change the mode to adjust the styling to give it desired emphasis.
28
- * - `text` - flat button without background or outline, used for the lowest priority actions, especially when presenting multiple options.
29
- * - `outlined` - button with an outline without background, typically used for important, but not primary action represents medium emphasis.
30
- * - `contained` - button with a background color, used for important action, have the most visual impact and high emphasis.
31
- * - `elevated` - button with a background color and elevation, used when absolutely necessary e.g. button requires visual separation from a patterned background. @supported Available in v5.x with theme version 3
32
- * - `contained-tonal` - button with a secondary background color, an alternative middle ground between contained and outlined buttons. @supported Available in v5.x with theme version 3
33
- */
34
- variant?: ButtonVariant;
35
- /**
36
- * @supported Available in v5.x
37
- * Custom button's background color.
38
- */
39
- buttonColor?: string;
40
- /**
41
- * Whether to show a loading indicator.
42
- */
43
- loading?: boolean;
44
- /**
45
- * Icon to display for the `Button`.
46
- */
47
- iconType?: IconType;
48
- iconName?: string;
49
- iconSize?: number;
50
- /**
51
- * Whether the button is disabled. A disabled button is greyed out and `onPress` is not called on touch.
52
- */
53
- disabled?: boolean;
54
- /**
55
- * Label text of the button.
56
- */
57
- children: ReactNode;
58
- /**
59
- * Accessibility label for the button. This is read by the screen reader when the user taps the button.
60
- */
61
- accessibilityLabel?: string;
62
- /**
63
- * Accessibility hint for the button. This is read by the screen reader when the user taps the button.
64
- */
65
- accessibilityHint?: string;
66
- /**
67
- * Function to execute on press.
68
- */
69
- onPress?: () => void;
70
- /**
71
- * @supported Available in v5.x
72
- * Function to execute as soon as the touchable element is pressed and invoked even before onPress.
73
- */
74
- onPressIn?: () => void;
75
- /**
76
- * @supported Available in v5.x
77
- * Function to execute as soon as the touch is released even before onPress.
78
- */
79
- onPressOut?: () => void;
80
- /**
81
- * Function to execute on long press.
82
- */
83
- onLongPress?: () => void;
84
- /**
85
- * Style of button's inner content.
86
- * Use this prop to apply custom height and width and to set the icon on the right with `flexDirection: 'row-reverse'`.
87
- */
88
- contentStyle?: StyleProp<ViewStyle>;
89
- style?: StyleProp<TextStyle>;
90
- /**
91
- * Style for the button text.
92
- */
93
- labelStyle?: TextStyle;
94
- /**
95
- * Style for the Icon
96
- */
97
- iconContainerStyle?: StyleProp<ViewStyle>;
98
- iconStyle?: StyleProp<TextStyle>;
99
- /*
100
- * Size
101
- * */
102
- size?: ButtonSize;
103
- /*
104
- * Elevation level
105
- * */
106
- elevation?: MD3Elevation;
107
- /**
108
- * testID to be used on tests.
109
- */
110
- testID?: string;
111
- /**
112
- * props for the stateLayer
113
- */
114
- stateLayerProps?: PropsWithoutRef<ViewProps>;
115
- textRelatedStyle?: StyleProp<TextStyle>;
116
- };
30
+ export type Props = Omit<SurfaceProps, 'style'> &
31
+ Pick<TouchableRippleProps, 'onPress' | 'onPressIn' | 'onPressOut' | 'onLongPress'> & {
32
+ /**
33
+ * Mode of the button. You can change the mode to adjust the styling to give it desired emphasis.
34
+ * - `text` - flat button without background or outline, used for the lowest priority actions, especially when presenting multiple options.
35
+ * - `outlined` - button with an outline without background, typically used for important, but not primary action represents medium emphasis.
36
+ * - `contained` - button with a background color, used for important action, have the most visual impact and high emphasis.
37
+ * - `elevated` - button with a background color and elevation, used when absolutely necessary e.g. button requires visual separation from a patterned background. @supported Available in v5.x with theme version 3
38
+ * - `contained-tonal` - button with a secondary background color, an alternative middle ground between contained and outlined buttons. @supported Available in v5.x with theme version 3
39
+ */
40
+ variant?: ButtonVariant;
41
+ /**
42
+ * Shape of the button.
43
+ * - `rounded` - fully rounded corners (default)
44
+ * - `square` - square corners with medium border radius
45
+ */
46
+ shape?: ButtonShape;
47
+ /**
48
+ * Whether the button is disabled. A disabled button is greyed out and `onPress` is not called on touch.
49
+ */
50
+ disabled?: boolean;
51
+ /**
52
+ * Content of the button. Use Button.Icon and Button.Text compound components.
53
+ */
54
+ children?: ReactNode;
55
+ /**
56
+ * Accessibility label for the button. This is read by the screen reader when the user taps the button.
57
+ */
58
+ accessibilityLabel?: string;
59
+ /**
60
+ * Accessibility hint for the button. This is read by the screen reader when the user taps the button.
61
+ */
62
+ accessibilityHint?: string;
63
+ style?: StyleProp<TextStyle>;
64
+ /*
65
+ * Size
66
+ * */
67
+ size?: ButtonSize;
68
+ /*
69
+ * Elevation level
70
+ * */
71
+ elevation?: MD3Elevation;
72
+ /**
73
+ * testID to be used on tests.
74
+ */
75
+ testID?: string;
76
+ /**
77
+ * props for the stateLayer
78
+ */
79
+ stateLayerProps?: PropsWithoutRef<ViewProps>;
80
+ textRelatedStyle?: StyleProp<TextStyle>;
81
+ disabledPress?: boolean;
82
+ };
117
83
 
118
- const elevationMap: Record<string, Record<string, number>> = {
119
- true: {
120
- contained: 1,
121
- 'contained-tonal': 1,
122
- elevated: 2,
123
- },
124
- false: {
125
- elevated: 1,
126
- },
127
- };
84
+ const emptyObj = {};
128
85
 
129
86
  const Button = (
130
87
  {
131
88
  disabled = false,
132
89
  variant = 'text',
133
- size = 'lg',
134
- loading,
135
- iconType,
136
- iconName,
137
- buttonColor: customButtonColor,
90
+ shape = 'rounded',
91
+ size = 'sm',
138
92
  children,
139
93
  accessibilityLabel,
140
94
  accessibilityHint,
@@ -143,17 +97,13 @@ const Button = (
143
97
  onPressOut,
144
98
  onLongPress,
145
99
  style: styleProp,
146
- contentStyle,
147
- labelStyle,
148
- iconContainerStyle: iconContainerStyleProp,
149
100
  testID,
150
101
  accessible,
151
- stateLayerProps = {},
102
+ stateLayerProps = emptyObj,
152
103
  elevation: elevationProp,
153
- iconSize: _iconSizeProp,
154
104
  textRelatedStyle,
155
- iconStyle: _iconStyleProp,
156
- ...rest
105
+ disabledPress,
106
+ ...restProps
157
107
  }: Props,
158
108
  ref: any,
159
109
  ) => {
@@ -164,124 +114,48 @@ const Button = (
164
114
  hovered,
165
115
  });
166
116
 
167
- defaultStyles.useVariants({
117
+ buttonStyles.useVariants({
168
118
  variant,
169
119
  // @ts-ignore // TODO - fix this
170
120
  state: state as any,
171
121
  size,
122
+ shape,
172
123
  });
173
-
174
- // const componentStyles = useComponentStyles(
175
- // 'Button',
176
- // [styleProp, { customButtonColor, customTextColor }],
177
- // {
178
- // variant,
179
- // state: disabled ? 'disabled' : hovered ? 'hovered' : undefined,
180
- // size,
181
- // },
182
- // );
183
-
184
- // console.log({ hovered, componentStyles });
185
-
186
- const isVariant = useCallback(
187
- (variantComponent: ButtonVariant) => {
188
- return variant === variantComponent;
189
- },
190
- [variant],
191
- );
192
-
193
- const iconSize = _iconSizeProp ?? sizeToIconSizeMap[size] ?? sizeToIconSizeMap.md;
124
+ const iconSize = sizeToIconSizeMap[size] ?? sizeToIconSizeMap.md;
194
125
  const elevationLevel = elevationMap[(!!hovered).toString()][variant] ?? 0;
195
126
 
196
- const {
197
- customLabelColor,
198
- customLabelSize,
199
- rippleColor,
200
- surfaceStyle,
201
- textStyle,
202
- iconStyle,
203
- viewStyle,
204
- iconContainerStyle,
205
- accessibilityState,
206
- stateLayerStyle,
207
- } = useMemo(() => {
208
- const { button, content, icon, iconTextMode, label, labelText, labelTextAddons } =
209
- defaultStyles;
210
-
211
- // for mobile
212
- const { borderRadius } = extractPropertiesFromStyles(
213
- [defaultStyles.root, styleProp],
214
- ['borderRadius'],
215
- );
216
-
217
- const backgroundColor = customButtonColor && !disabled ? customButtonColor : undefined;
218
-
219
- const _iconStyle = [icon, isVariant('text') && iconTextMode];
220
-
221
- const { color: labelColor, fontSize: labelFontSize } = labelStyle ?? {};
222
-
223
- // TODO - remove this workaround
224
- let _rippleColor: string | undefined;
225
-
226
- try {
227
- _rippleColor = setColor(labelColor).alpha(0.12).rgb().string();
228
- } catch (e) {
229
- _rippleColor = undefined;
230
- }
231
-
127
+ const { surfaceStyle, accessibilityState, stateLayerStyle, contextValue } = useMemo(() => {
232
128
  return {
233
- customLabelColor: labelColor,
234
- customLabelSize: labelFontSize,
235
- rippleColor: _rippleColor,
236
- surfaceStyle: [
237
- button,
238
- backgroundColor ? { backgroundColor } : {},
239
- defaultStyles.root,
240
- styleProp,
241
- ],
242
-
243
- iconStyle: [_iconStyle, textRelatedStyle, _iconStyleProp] as unknown as ViewStyle,
244
- viewStyle: [
245
- content,
246
- { flexGrow: 1 },
247
- borderRadius ? { borderRadius } : {},
248
- contentStyle,
249
- ],
250
- iconContainerStyle: [defaultStyles.iconContainer, iconContainerStyleProp],
251
- textStyle: [
252
- // @ts-ignore // TODO - fix this
253
- isVariant('text') ? (iconName || loading ? labelTextAddons : labelText) : label,
254
- textRelatedStyle,
255
- labelStyle,
256
- ],
129
+ surfaceStyle: [buttonStyles.root, styleProp],
257
130
  accessibilityState: { disabled },
258
- stateLayerStyle: [defaultStyles.stateLayer, stateLayerProps?.style],
131
+ stateLayerStyle: [buttonStyles.stateLayer, stateLayerProps?.style],
132
+ contextValue: {
133
+ variant,
134
+ size,
135
+ state: state as ButtonContextType['state'],
136
+ disabled,
137
+ iconSize,
138
+ textRelatedStyle,
139
+ } as ButtonContextType,
259
140
  };
260
- // eslint-disable-next-line
141
+ // eslint-disable-next-line react-hooks/exhaustive-deps
261
142
  }, [
143
+ shape,
262
144
  state,
263
145
  variant,
264
146
  size,
265
- contentStyle,
266
- customButtonColor,
267
147
  disabled,
268
- iconContainerStyleProp,
269
- iconName,
270
- isVariant,
271
- labelStyle,
272
- loading,
273
148
  stateLayerProps?.style,
274
149
  styleProp,
150
+ iconSize,
151
+ textRelatedStyle,
275
152
  ]);
276
153
 
277
- const elevation = useMemo(
278
- () => (elevationProp === undefined ? elevationLevel ?? 0 : elevationProp),
279
- [elevationLevel, elevationProp],
280
- );
154
+ const elevation = elevationProp === undefined ? elevationLevel ?? 0 : elevationProp;
281
155
 
282
156
  return (
283
157
  <Surface
284
- {...rest}
158
+ {...restProps}
285
159
  style={surfaceStyle}
286
160
  elevation={
287
161
  (disabled
@@ -289,7 +163,8 @@ const Button = (
289
163
  : hovered
290
164
  ? (elevationProp || 0) + elevationLevel
291
165
  : elevation) as MD3Elevation
292
- }>
166
+ }
167
+ asChild>
293
168
  <TouchableRipple
294
169
  borderless
295
170
  onPress={onPress}
@@ -301,51 +176,123 @@ const Button = (
301
176
  accessibilityRole="button"
302
177
  accessibilityState={accessibilityState}
303
178
  accessible={accessible}
304
- disabled={disabled}
305
- rippleColor={rippleColor}
306
- style={viewStyle}
179
+ disabled={disabled || disabledPress}
307
180
  ref={actionsRef}
308
181
  testID={testID}>
309
- <>
310
- {iconName && loading !== true ? (
311
- <View style={iconContainerStyle}>
312
- <Icon
313
- type={iconType}
314
- name={iconName}
315
- size={iconSize ?? customLabelSize}
316
- color={
317
- typeof customLabelColor === 'string'
318
- ? customLabelColor
319
- : undefined
320
- }
321
- style={iconStyle}
322
- />
323
- </View>
324
- ) : null}
325
- {loading ? (
326
- <ActivityIndicator
327
- size={customLabelSize ?? iconSize}
328
- color={
329
- (typeof customLabelColor === 'string'
330
- ? customLabelColor
331
- : undefined) as string
332
- }
333
- style={iconStyle}
334
- />
335
- ) : null}
336
- <Text selectable={false} numberOfLines={1} style={textStyle}>
182
+ <ButtonContext.Provider value={contextValue}>
183
+ <>
337
184
  {children}
338
- </Text>
339
185
 
340
- <StateLayer
341
- testID={testID ? `${testID}-stateLayer` : ''}
342
- {...stateLayerProps}
343
- style={stateLayerStyle}
344
- />
345
- </>
186
+ <StateLayer
187
+ testID={testID ? `${testID}-stateLayer` : ''}
188
+ {...stateLayerProps}
189
+ style={stateLayerStyle}
190
+ />
191
+ </>
192
+ </ButtonContext.Provider>
346
193
  </TouchableRipple>
347
194
  </Surface>
348
195
  );
349
196
  };
350
197
 
351
198
  export default memo(forwardRef(Button));
199
+
200
+ /**
201
+ * Button.Icon - Renders an icon within the button
202
+ */
203
+ export const ButtonIcon = memo(
204
+ ({ type, name, size: sizeProp, color: colorProp, style, ...rest }: IconProps) => {
205
+ const { labelColor, iconSize, variant, state, disabled, textRelatedStyle } =
206
+ useContext(ButtonContext);
207
+
208
+ const iconSizeResolved = sizeProp ?? iconSize;
209
+ const colorResolved =
210
+ colorProp ?? (typeof labelColor === 'string' ? labelColor : undefined);
211
+
212
+ buttonIconStyles.useVariants({
213
+ variant,
214
+ // @ts-ignore - state includes 'default' which is valid but not typed
215
+ state,
216
+ });
217
+
218
+ return (
219
+ <Icon
220
+ type={type}
221
+ name={name}
222
+ size={iconSizeResolved}
223
+ color={disabled ? undefined : colorResolved}
224
+ style={[buttonIconStyles.root, textRelatedStyle, style]}
225
+ {...rest}
226
+ />
227
+ );
228
+ },
229
+ );
230
+
231
+ ButtonIcon.displayName = 'Button_Icon';
232
+
233
+ /**
234
+ * Button.Text - Renders text within the button
235
+ */
236
+ export const ButtonText = memo(({ children, style, ...rest }: TextProps) => {
237
+ const { variant, state, size, textRelatedStyle } = useContext(ButtonContext);
238
+
239
+ buttonTextStyles.useVariants({
240
+ variant,
241
+ // @ts-ignore - state includes 'default' which is valid but not typed
242
+ state,
243
+ // @ts-ignore - size type mismatch
244
+ size,
245
+ });
246
+
247
+ return (
248
+ // @ts-ignore - deep type instantiation
249
+ <Text
250
+ selectable={false}
251
+ numberOfLines={1}
252
+ {...rest}
253
+ style={[buttonTextStyles.root, textRelatedStyle, style]}>
254
+ {children}
255
+ </Text>
256
+ );
257
+ });
258
+
259
+ ButtonText.displayName = 'Button_Text';
260
+
261
+ /**
262
+ * Button.Loading - Renders a loading indicator within the button
263
+ */
264
+ export const ButtonActivityIndicator = memo(
265
+ ({
266
+ size: sizeProp,
267
+ color: colorProp,
268
+ style,
269
+ ...rest
270
+ }: Omit<ActivityIndicatorProps, 'animating'>) => {
271
+ const { iconSize, variant, state } = useContext(ButtonContext);
272
+
273
+ const sizeResolved = sizeProp ?? iconSize;
274
+ // Default to onPrimary for contained variants, primary for others
275
+ const colorResolved = colorProp ?? (variant === 'contained' ? 'onPrimary' : 'primary');
276
+
277
+ buttonActivityIndicatorStyles.useVariants({
278
+ variant,
279
+ // @ts-ignore - state includes 'default' which is valid but not typed
280
+ state,
281
+ });
282
+ const activityIndicatorStyle = useMemo(() => {
283
+ return [buttonActivityIndicatorStyles.root, style] as StyleProp<ViewStyle>;
284
+ // eslint-disable-next-line react-hooks/exhaustive-deps
285
+ }, [style, variant, state]);
286
+
287
+ return (
288
+ <ActivityIndicator
289
+ size={sizeResolved}
290
+ color={colorResolved}
291
+ style={activityIndicatorStyle}
292
+ {...rest}
293
+ />
294
+ );
295
+ },
296
+ );
297
+
298
+ ButtonActivityIndicator.displayName = 'Button_ActivityIndicator';
@@ -1,7 +1,13 @@
1
1
  import { getRegisteredComponentWithFallback } from '../../core';
2
- import ButtonDefault from './Button';
2
+ import ButtonDefault, { ButtonActivityIndicator, ButtonIcon, ButtonText } from './Button';
3
3
 
4
- export const Button = getRegisteredComponentWithFallback('Button', ButtonDefault);
4
+ const ButtonBase = getRegisteredComponentWithFallback('Button', ButtonDefault);
5
+
6
+ export const Button = Object.assign(ButtonBase, {
7
+ Icon: ButtonIcon,
8
+ Text: ButtonText,
9
+ ActivityIndicator: ButtonActivityIndicator,
10
+ });
5
11
 
6
12
  export type { Props as ButtonProps } from './Button';
7
- export { defaultStyles } from './utils';
13
+ export { ButtonContext, buttonIconStyles, buttonStyles, buttonTextStyles } from './utils';
@@ -1,5 +1,19 @@
1
+ import type { StyleProp, TextStyle } from 'react-native';
2
+
1
3
  export type ButtonVariant = 'text' | 'outlined' | 'contained' | 'elevated' | 'contained-tonal';
2
4
 
3
- export type ButtonSize = 'sm' | 'md' | 'lg';
5
+ export type ButtonSize = 'xs' | 'sm' | 'md' | 'lg' | 'xl';
6
+
7
+ export type ButtonStates = 'hovered' | 'disabled' | 'default';
8
+
9
+ export type ButtonShape = 'rounded' | 'square';
4
10
 
5
- export type ButtonStates = 'hovered' | 'disabled';
11
+ export type ButtonContextType = {
12
+ variant: ButtonVariant;
13
+ size: ButtonSize;
14
+ state: ButtonStates;
15
+ disabled: boolean;
16
+ labelColor?: string;
17
+ iconSize?: number;
18
+ textRelatedStyle?: StyleProp<TextStyle>;
19
+ };