react-native-molecules 0.5.0-beta.2 → 0.5.0-beta.21

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 (160) hide show
  1. package/README.md +1 -1
  2. package/components/Accordion/Accordion.tsx +2 -6
  3. package/components/Accordion/AccordionItem.tsx +16 -12
  4. package/components/Accordion/AccordionItemContent.tsx +6 -1
  5. package/components/Accordion/AccordionItemHeader.tsx +1 -1
  6. package/components/Accordion/utils.ts +6 -0
  7. package/components/ActivityIndicator/ActivityIndicator.tsx +6 -15
  8. package/components/Appbar/AppbarBase.tsx +18 -13
  9. package/components/Button/Button.tsx +209 -264
  10. package/components/Button/index.tsx +9 -3
  11. package/components/Button/types.ts +16 -2
  12. package/components/Button/utils.ts +230 -208
  13. package/components/Checkbox/CheckboxBase.ios.tsx +10 -14
  14. package/components/Checkbox/CheckboxBase.tsx +14 -121
  15. package/components/Checkbox/utils.ts +0 -25
  16. package/components/Chip/Chip.tsx +40 -52
  17. package/components/Chip/utils.ts +3 -7
  18. package/components/DateField/DateField.tsx +111 -0
  19. package/components/DateField/index.tsx +6 -0
  20. package/components/{DatePickerInput/inputUtils.ts → DateField/useDateFieldState.ts} +17 -49
  21. package/components/DatePicker/DateCalendar.tsx +83 -0
  22. package/components/DatePicker/DatePickerActions.tsx +73 -0
  23. package/components/DatePicker/DatePickerModal.tsx +245 -0
  24. package/components/DatePicker/DatePickerPopover.tsx +79 -0
  25. package/components/DatePicker/DatePickerProvider.tsx +158 -0
  26. package/components/DatePicker/DatePickerTrigger.tsx +23 -0
  27. package/components/DatePicker/context.tsx +83 -0
  28. package/components/DatePicker/index.tsx +45 -0
  29. package/components/DatePicker/utils.ts +293 -0
  30. package/components/DatePickerInline/DatePickerContext.tsx +1 -0
  31. package/components/DatePickerInline/DatePickerDockedHeader.tsx +117 -0
  32. package/components/DatePickerInline/DatePickerInline.tsx +16 -15
  33. package/components/DatePickerInline/DatePickerInlineBase.tsx +8 -2
  34. package/components/DatePickerInline/DatePickerInlineHeader.tsx +8 -4
  35. package/components/DatePickerInline/Day.tsx +25 -1
  36. package/components/DatePickerInline/DayNames.tsx +13 -10
  37. package/components/DatePickerInline/DayRange.tsx +2 -4
  38. package/components/DatePickerInline/HeaderItem.tsx +42 -27
  39. package/components/DatePickerInline/Month.tsx +48 -67
  40. package/components/DatePickerInline/MonthPicker.tsx +38 -44
  41. package/components/DatePickerInline/Swiper.native.tsx +21 -4
  42. package/components/DatePickerInline/Swiper.tsx +168 -13
  43. package/components/DatePickerInline/Week.tsx +6 -1
  44. package/components/DatePickerInline/YearPicker.tsx +206 -53
  45. package/components/DatePickerInline/dateUtils.tsx +17 -12
  46. package/components/DatePickerInline/types.ts +6 -2
  47. package/components/DatePickerInline/utils.ts +66 -29
  48. package/components/Drawer/Drawer.tsx +17 -6
  49. package/components/ElementGroup/ElementGroup.tsx +16 -14
  50. package/components/FilePicker/FilePicker.tsx +48 -78
  51. package/components/FilePicker/index.tsx +2 -1
  52. package/components/FilePicker/utils.ts +9 -0
  53. package/components/HelperText/HelperText.tsx +0 -35
  54. package/components/Icon/iconFactory.tsx +3 -3
  55. package/components/Icon/index.tsx +1 -1
  56. package/components/Icon/types.ts +17 -6
  57. package/components/IconButton/IconButton.tsx +42 -57
  58. package/components/IconButton/utils.ts +142 -33
  59. package/components/ListItem/ListItem.tsx +3 -1
  60. package/components/ListItem/utils.ts +1 -1
  61. package/components/LoadingIndicator/LoadingIndicator.tsx +253 -0
  62. package/components/LoadingIndicator/LoadingIndicator.web.tsx +136 -0
  63. package/components/LoadingIndicator/index.tsx +13 -0
  64. package/components/LoadingIndicator/utils.ts +117 -0
  65. package/components/Menu/Menu.tsx +3 -18
  66. package/components/NavigationRail/NavigationRail.tsx +15 -9
  67. package/components/Popover/Popover.tsx +122 -145
  68. package/components/Popover/PopoverRoot.tsx +74 -0
  69. package/components/Popover/common.ts +50 -34
  70. package/components/Popover/index.ts +18 -1
  71. package/components/Popover/usePlatformMeasure.native.ts +90 -0
  72. package/components/Popover/usePlatformMeasure.ts +118 -0
  73. package/components/Popover/utils.ts +34 -0
  74. package/components/Select/Select.tsx +368 -507
  75. package/components/Select/context.tsx +72 -0
  76. package/components/Select/index.ts +8 -14
  77. package/components/Select/types.ts +2 -4
  78. package/components/Select/utils.ts +144 -0
  79. package/components/Slot/Slot.tsx +244 -0
  80. package/components/Slot/compose-refs.tsx +62 -0
  81. package/components/Slot/index.tsx +8 -0
  82. package/components/Surface/Surface.android.tsx +34 -8
  83. package/components/Surface/Surface.ios.tsx +36 -29
  84. package/components/Surface/Surface.tsx +31 -4
  85. package/components/Surface/utils.ts +44 -30
  86. package/components/Switch/Switch.tsx +8 -2
  87. package/components/Tabs/TabItem.tsx +35 -58
  88. package/components/Tabs/TabLabel.tsx +5 -9
  89. package/components/Tabs/Tabs.tsx +154 -148
  90. package/components/Tabs/utils.ts +15 -2
  91. package/components/TextInput/TextInput.tsx +658 -575
  92. package/components/TextInput/index.tsx +19 -3
  93. package/components/TextInput/types.ts +76 -27
  94. package/components/TextInput/utils.ts +225 -145
  95. package/components/TimeField/TimeField.tsx +75 -0
  96. package/components/TimeField/index.tsx +6 -0
  97. package/components/TimeField/useTimeFieldState.ts +70 -0
  98. package/components/{TimePickerField/sanitizeTime.ts → TimeField/utils.ts} +77 -10
  99. package/components/TimePicker/TimeInput.tsx +87 -37
  100. package/components/TimePicker/TimeInputs.tsx +137 -49
  101. package/components/TimePicker/TimePicker.tsx +73 -10
  102. package/components/TimePicker/TimePickerModal.tsx +186 -0
  103. package/components/TimePicker/context.tsx +17 -0
  104. package/components/TimePicker/index.tsx +15 -3
  105. package/components/TimePicker/utils.ts +93 -0
  106. package/components/Tooltip/Tooltip.tsx +42 -67
  107. package/components/Tooltip/TooltipContent.tsx +32 -5
  108. package/components/Tooltip/TooltipTrigger.tsx +20 -20
  109. package/components/Tooltip/index.tsx +1 -1
  110. package/components/TouchableRipple/TouchableRipple.native.tsx +50 -14
  111. package/components/TouchableRipple/TouchableRipple.tsx +137 -47
  112. package/hocs/withPortal.tsx +1 -1
  113. package/hooks/index.tsx +0 -6
  114. package/hooks/useActionState.tsx +19 -8
  115. package/hooks/useControlledValue.tsx +20 -4
  116. package/hooks/useFilePicker.tsx +6 -16
  117. package/hooks/useWhatHasUpdated.tsx +48 -0
  118. package/package.json +17 -13
  119. package/shortcuts-manager/ShortcutsManager/ShortcutsManager.tsx +5 -2
  120. package/styles/shadow.ts +2 -1
  121. package/styles/themes/LightTheme.tsx +1 -1
  122. package/utils/DocumentPicker/documentPicker.ts +78 -27
  123. package/utils/DocumentPicker/types.ts +0 -1
  124. package/utils/extractPropertiesFromStyles.ts +25 -0
  125. package/utils/extractSubcomponents.ts +89 -0
  126. package/utils/lodash.ts +77 -5
  127. package/components/DatePickerDocked/DatePickerDocked.tsx +0 -30
  128. package/components/DatePickerDocked/DatePickerDockedHeader.tsx +0 -129
  129. package/components/DatePickerDocked/index.tsx +0 -17
  130. package/components/DatePickerDocked/types.ts +0 -11
  131. package/components/DatePickerDocked/utils.ts +0 -157
  132. package/components/DatePickerInput/DatePickerInput.tsx +0 -139
  133. package/components/DatePickerInput/DatePickerInputModal.tsx +0 -48
  134. package/components/DatePickerInput/DatePickerInputWithoutModal.tsx +0 -77
  135. package/components/DatePickerInput/DateRangeInput.tsx +0 -88
  136. package/components/DatePickerInput/index.tsx +0 -10
  137. package/components/DatePickerInput/types.ts +0 -28
  138. package/components/DatePickerInput/utils.ts +0 -15
  139. package/components/DatePickerModal/AnimatedCrossView.tsx +0 -94
  140. package/components/DatePickerModal/CalendarEdit.tsx +0 -139
  141. package/components/DatePickerModal/DatePickerModal.tsx +0 -85
  142. package/components/DatePickerModal/DatePickerModalContent.tsx +0 -155
  143. package/components/DatePickerModal/DatePickerModalContentHeader.tsx +0 -213
  144. package/components/DatePickerModal/DatePickerModalHeader.tsx +0 -74
  145. package/components/DatePickerModal/DatePickerModalHeaderBackground.tsx +0 -13
  146. package/components/DatePickerModal/index.tsx +0 -16
  147. package/components/DatePickerModal/types.ts +0 -92
  148. package/components/DatePickerModal/utils.ts +0 -122
  149. package/components/DateTimePicker/DateTimePicker.tsx +0 -172
  150. package/components/DateTimePicker/index.tsx +0 -10
  151. package/components/DateTimePicker/utils.ts +0 -12
  152. package/components/Popover/Popover.native.tsx +0 -185
  153. package/components/TimePickerField/TimePickerField.tsx +0 -152
  154. package/components/TimePickerField/index.tsx +0 -10
  155. package/components/TimePickerField/utils.ts +0 -94
  156. package/components/TimePickerModal/TimePickerModal.tsx +0 -115
  157. package/components/TimePickerModal/index.tsx +0 -10
  158. package/components/TimePickerModal/utils.ts +0 -47
  159. package/hooks/useSearchable.tsx +0 -74
  160. package/hooks/useSubcomponents.tsx +0 -59
@@ -1,11 +1,12 @@
1
1
  import type { MemoExoticComponent } from 'react';
2
2
  import type { ViewStyle } from 'react-native';
3
3
 
4
+ import type { DatePickerLocale } from '../DatePicker/context';
4
5
  import type { CalendarHeaderProps } from './DatePickerInlineHeader';
5
6
  import type { DisableWeekDaysType } from './dateUtils';
6
7
 
7
8
  export interface BaseMonthProps {
8
- locale: undefined | string;
9
+ locale: DatePickerLocale | undefined;
9
10
  scrollMode: 'horizontal' | 'vertical';
10
11
  disableWeekDays?: DisableWeekDaysType;
11
12
  mode: ModeType;
@@ -13,6 +14,7 @@ export interface BaseMonthProps {
13
14
  onPressDate: (date: Date) => any;
14
15
  validRange?: ValidRangeType;
15
16
  customMonthStyles?: Record<string, any>;
17
+ showOutsideDays?: boolean;
16
18
 
17
19
  // some of these should be required in final implementation
18
20
  date?: CalendarDate;
@@ -46,13 +48,15 @@ export type ValidRangeType = {
46
48
  };
47
49
 
48
50
  export type BaseDatePickerProps = {
49
- locale?: string;
51
+ locale?: DatePickerLocale;
50
52
  disableWeekDays?: DisableWeekDaysType;
51
53
  validRange?: ValidRangeType;
52
54
  startYear?: number;
53
55
  endYear?: number;
54
56
  HeaderComponent?: MemoExoticComponent<CalendarHeaderProps | any>;
57
+ headerLayout?: 'inline' | 'docked';
55
58
  monthStyle?: Record<string, any>;
59
+ showOutsideDays?: boolean;
56
60
 
57
61
  // here they are optional but in final implemenation they are required
58
62
  date?: CalendarDate;
@@ -3,11 +3,13 @@ import { StyleSheet } from 'react-native-unistyles';
3
3
  import { getRegisteredComponentStylesWithFallback } from '../../core';
4
4
  import { daySize } from './dateUtils';
5
5
 
6
- export const dayNamesHeight = 44;
6
+ export const dayNamesHeight = 48;
7
7
 
8
8
  // TODO make it flexible
9
- export const weekMargin = 6;
10
- export const weekSize = daySize + weekMargin;
9
+ export const cellSize = 48;
10
+ export const cellVerticalPadding = (cellSize - daySize) / 2;
11
+ export const weekMargin = 0;
12
+ export const weekSize = cellSize + weekMargin;
11
13
  export const montHeaderHeight = 56;
12
14
  export const monthHeaderSingleMarginTop = 4;
13
15
  export const monthHeaderSingleMarginBottom = 8 + 22 + 12;
@@ -33,8 +35,7 @@ const datePickerMonthStylesDefault = StyleSheet.create(theme => ({
33
35
  backgroundColor: theme.colors.surface,
34
36
  },
35
37
  monthLabel: {
36
- ...theme.typescale.bodyMedium,
37
- opacity: 0.7,
38
+ ...theme.typescale.labelLarge,
38
39
  },
39
40
  yearButton: {
40
41
  alignSelf: 'flex-start',
@@ -89,6 +90,30 @@ const datePickerYearPickerStylesDefault = StyleSheet.create(theme => ({
89
90
  },
90
91
  }));
91
92
 
93
+ export const datePickerDayStateLayerStyles = StyleSheet.create(theme => ({
94
+ stateLayer: {
95
+ variants: {
96
+ state: {
97
+ hovered: {
98
+ backgroundColor: theme.colors.stateLayer.hover.onSurface,
99
+ },
100
+ todayAndHovered: {
101
+ backgroundColor: theme.colors.stateLayer.hover.primary,
102
+ },
103
+ outsideAndHovered: {
104
+ backgroundColor: theme.colors.stateLayer.hover.onSurface,
105
+ },
106
+ selectedAndHovered: {
107
+ backgroundColor: theme.colors.stateLayer.hover.onPrimary,
108
+ },
109
+ inRangeAndHovered: {
110
+ backgroundColor: theme.colors.stateLayer.hover.onSurface,
111
+ },
112
+ },
113
+ },
114
+ },
115
+ }));
116
+
92
117
  const datePickerDayStylesDefault = StyleSheet.create(theme => ({
93
118
  containerStyle: {
94
119
  flex: 1,
@@ -102,6 +127,9 @@ const datePickerDayStylesDefault = StyleSheet.create(theme => ({
102
127
  disabled: {
103
128
  opacity: 0.3,
104
129
  },
130
+ outside: {
131
+ opacity: 0.38,
132
+ },
105
133
  },
106
134
  },
107
135
  },
@@ -117,7 +145,7 @@ const datePickerDayStylesDefault = StyleSheet.create(theme => ({
117
145
  variants: {
118
146
  state: {
119
147
  inRange: {
120
- backgroundColor: theme.colors.primary,
148
+ backgroundColor: 'transparent',
121
149
  },
122
150
  },
123
151
  },
@@ -140,12 +168,13 @@ const datePickerDayStylesDefault = StyleSheet.create(theme => ({
140
168
  },
141
169
 
142
170
  inRange: {
143
- borderColor: theme.colors.primary,
171
+ borderWidth: 0,
172
+ borderColor: 'transparent',
144
173
  button: {
145
- backgroundColor: theme.colors.primary,
174
+ backgroundColor: 'transparent',
146
175
  },
147
176
  today: {
148
- borderColor: theme.colors.primary,
177
+ borderColor: 'transparent',
149
178
  },
150
179
  },
151
180
  },
@@ -156,15 +185,17 @@ const datePickerDayStylesDefault = StyleSheet.create(theme => ({
156
185
  variants: {
157
186
  state: {
158
187
  inRange: {
159
- borderColor: theme.colors.primary,
188
+ borderWidth: 0,
189
+ borderColor: 'transparent',
160
190
  button: {
161
- backgroundColor: theme.colors.primary,
191
+ backgroundColor: 'transparent',
162
192
  },
163
193
  },
164
194
  },
165
195
  },
166
196
  },
167
197
  text: {
198
+ ...theme.typescale.bodyLarge,
168
199
  variants: {
169
200
  state: {
170
201
  selected: {
@@ -175,16 +206,16 @@ const datePickerDayStylesDefault = StyleSheet.create(theme => ({
175
206
  },
176
207
 
177
208
  inRange: {
178
- color: theme.colors.onPrimary,
209
+ color: theme.colors.onSecondaryContainer,
179
210
 
180
211
  day: {
181
- borderColor: theme.colors.primary,
212
+ borderColor: 'transparent',
182
213
  },
183
214
  button: {
184
- backgroundColor: theme.colors.primary,
215
+ backgroundColor: 'transparent',
185
216
  },
186
217
  today: {
187
- borderColor: theme.colors.primary,
218
+ borderColor: 'transparent',
188
219
  },
189
220
  },
190
221
  },
@@ -205,7 +236,7 @@ const datePickerDayEmptyStylesDefault = StyleSheet.create({
205
236
  const datePickerWeekStylesDefault = StyleSheet.create({
206
237
  root: {
207
238
  flexDirection: 'row',
208
- height: daySize,
239
+ height: cellSize,
209
240
  },
210
241
  });
211
242
 
@@ -214,7 +245,7 @@ const datePickerHeaderStylesDefault = StyleSheet.create(theme => ({
214
245
  flexDirection: 'row',
215
246
  alignItems: 'center',
216
247
  justifyContent: 'space-between',
217
- marginHorizontal: theme.spacings['5'],
248
+ padding: theme.spacings['2'],
218
249
  },
219
250
  buttonContainer: {
220
251
  height: 56,
@@ -226,8 +257,7 @@ const datePickerHeaderStylesDefault = StyleSheet.create(theme => ({
226
257
  buttonWrapper: {},
227
258
  spacer: { flex: 1 },
228
259
  yearLabelStyle: {
229
- ...theme.typescale.bodyMedium,
230
- opacity: 0.7,
260
+ ...theme.typescale.labelLarge,
231
261
  },
232
262
  yearButtonStyle: {
233
263
  alignSelf: 'flex-start',
@@ -249,24 +279,25 @@ const dateDayNameStylesDefault = StyleSheet.create(theme => ({
249
279
  alignItems: 'center',
250
280
  backgroundColor: theme.colors.surface,
251
281
  },
252
- dayName: { flex: 1, alignItems: 'center' },
282
+ dayName: { flex: 1, alignItems: 'center', ...theme.typescale.bodyLarge },
253
283
  dayNameLabel: {
254
- opacity: 0.7,
255
- ...theme.typescale.bodyMedium,
284
+ ...theme.typescale.bodyLarge,
256
285
  },
257
286
  }));
258
287
 
259
288
  const datePickerDayRangeStylesDefault = StyleSheet.create(theme => ({
260
289
  container: {
290
+ position: 'absolute',
291
+ top: cellVerticalPadding,
292
+ bottom: cellVerticalPadding,
293
+ left: 0,
294
+ right: 0,
261
295
  flexDirection: 'row',
262
296
 
263
297
  variants: {
264
298
  state: {
265
- bothWays: {
266
- borderRadius: daySize / 2,
267
- },
268
299
  inRange: {
269
- backgroundColor: theme.colors.primary,
300
+ backgroundColor: theme.colors.secondaryContainer,
270
301
  },
271
302
  isCrop: {
272
303
  backgroundColor: undefined,
@@ -280,7 +311,7 @@ const datePickerDayRangeStylesDefault = StyleSheet.create(theme => ({
280
311
  variants: {
281
312
  state: {
282
313
  isRightCrop: {
283
- backgroundColor: theme.colors.primary,
314
+ backgroundColor: theme.colors.secondaryContainer,
284
315
  },
285
316
  },
286
317
  },
@@ -291,13 +322,13 @@ const datePickerDayRangeStylesDefault = StyleSheet.create(theme => ({
291
322
  variants: {
292
323
  state: {
293
324
  isLeftCrop: {
294
- backgroundColor: theme.colors.primary,
325
+ backgroundColor: theme.colors.secondaryContainer,
295
326
  },
296
327
  },
297
328
  },
298
329
  },
299
330
  centerCrop: {
300
- backgroundColor: theme.colors.primary,
331
+ backgroundColor: theme.colors.secondaryContainer,
301
332
  minWidth: daySize,
302
333
  minHeight: daySize,
303
334
 
@@ -317,7 +348,13 @@ const datePickerDayRangeStylesDefault = StyleSheet.create(theme => ({
317
348
  }));
318
349
 
319
350
  const datePickerYearItemStylesDefault = StyleSheet.create(theme => ({
351
+ content: {
352
+ alignItems: 'center',
353
+ },
320
354
  yearButton: {
355
+ borderRadius: theme.shapes.corner.full,
356
+ paddingHorizontal: 0,
357
+ overflow: 'hidden',
321
358
  variants: {
322
359
  state: {
323
360
  selected: {
@@ -3,25 +3,36 @@ import { View, type ViewProps } from 'react-native';
3
3
  import { StyleSheet } from 'react-native-unistyles';
4
4
 
5
5
  import { getRegisteredComponentStylesWithFallback } from '../../core';
6
- import { useSubcomponents } from '../../hooks';
6
+ import { extractSubcomponents } from '../../utils/extractSubcomponents';
7
7
 
8
8
  export type Props = Omit<ViewProps, 'children'> & {
9
9
  children: ReactElement | ReactElement[];
10
10
  };
11
11
 
12
- const allowedChildren = ['Drawer_Footer', 'Drawer_Header', 'Drawer_Content'];
12
+ const allowedChildren = [
13
+ { name: 'Drawer_Footer', allowMultiple: false },
14
+ { name: 'Drawer_Header', allowMultiple: false },
15
+ { name: 'Drawer_Content', allowMultiple: false },
16
+ ];
13
17
 
14
18
  const Drawer = ({ style, children, ...rest }: Props) => {
15
- const { Drawer_Header, Drawer_Footer, Drawer_Content } = useSubcomponents({
19
+ const {
20
+ Drawer_Header,
21
+ Drawer_Footer,
22
+ Drawer_Content,
23
+ rest: restChildren,
24
+ } = extractSubcomponents({
16
25
  children,
17
26
  allowedChildren,
27
+ includeRest: true,
18
28
  });
19
29
 
20
30
  return (
21
31
  <View style={[drawerStyles.root, style]} {...rest}>
22
- {Drawer_Header[0]}
23
- {Drawer_Content[0]}
24
- {Drawer_Footer[0]}
32
+ {Drawer_Header}
33
+ {Drawer_Content}
34
+ {Drawer_Footer}
35
+ {restChildren}
25
36
  </View>
26
37
  );
27
38
  };
@@ -1,6 +1,7 @@
1
1
  import { Children, cloneElement, forwardRef, memo, type ReactElement, useMemo } from 'react';
2
2
  import { View, type ViewProps, type ViewStyle } from 'react-native';
3
3
 
4
+ import { extractPropertiesFromStyles } from '../../utils/extractPropertiesFromStyles';
4
5
  import { isNil } from '../../utils/lodash';
5
6
  import { elementGroupStyles } from './utils';
6
7
 
@@ -44,24 +45,25 @@ export const ElementGroup = (
44
45
  borderTopRightRadius,
45
46
  borderBottomLeftRadius,
46
47
  borderBottomRightRadius,
47
- ...restStyle
48
- } = elementGroupStyles.root as any;
49
- const {
50
- borderTopLeftRadius: _borderTopLeftRadius,
51
- borderTopRightRadius: _borderTopRightRadius,
52
- borderBottomLeftRadius: _borderBottomLeftRadius,
53
- borderBottomRightRadius: _borderBottomRightRadius,
54
- ..._restStyle
55
- } = style ?? {};
48
+ } = extractPropertiesFromStyles(
49
+ [elementGroupStyles.root, style],
50
+ [
51
+ 'borderRadius',
52
+ 'borderTopLeftRadius',
53
+ 'borderTopRightRadius',
54
+ 'borderBottomLeftRadius',
55
+ 'borderBottomRightRadius',
56
+ ],
57
+ );
56
58
 
57
59
  return {
58
- containerStyle: [restStyle, _restStyle],
60
+ containerStyle: [elementGroupStyles.root, style],
59
61
  borderRadius: borderRadiusProp || _borderRadius,
60
62
  borderRadiuses: {
61
- borderTopLeftRadius: borderTopLeftRadius || _borderTopLeftRadius,
62
- borderTopRightRadius: borderTopRightRadius || _borderTopRightRadius,
63
- borderBottomLeftRadius: borderBottomLeftRadius || _borderBottomLeftRadius,
64
- borderBottomRightRadius: borderBottomRightRadius || _borderBottomRightRadius,
63
+ borderTopLeftRadius: borderTopLeftRadius,
64
+ borderTopRightRadius: borderTopRightRadius,
65
+ borderBottomLeftRadius: borderBottomLeftRadius,
66
+ borderBottomRightRadius: borderBottomRightRadius,
65
67
  },
66
68
  };
67
69
  // eslint-disable-next-line react-hooks/exhaustive-deps
@@ -1,15 +1,17 @@
1
- import { forwardRef, memo, type ReactNode, useCallback, useEffect, useMemo, useState } from 'react';
1
+ import { memo, useCallback, useMemo } from 'react';
2
2
 
3
+ import useControlledValue from '../../hooks/useControlledValue';
3
4
  import useFilePicker from '../../hooks/useFilePicker';
4
5
  import type { DocumentPickerOptions, DocumentResult } from '../../utils/DocumentPicker';
5
- import { ActivityIndicator } from '../ActivityIndicator';
6
6
  import { IconButton } from '../IconButton';
7
7
  import { TextInput, type TextInputProps } from '../TextInput';
8
+ import { FilePickerContext } from './utils';
8
9
 
9
10
  export type OmitProp =
10
11
  | 'editable'
11
12
  | 'multiline'
12
13
  | 'onChangeText'
14
+ | 'onChange'
13
15
  | 'keyboardType'
14
16
  | 'defaultValue'
15
17
  | 'value'
@@ -24,45 +26,39 @@ export type Props = Omit<TextInputProps, OmitProp> &
24
26
  */
25
27
  multiple?: boolean;
26
28
  /**
27
- * Displays the Spinner on the right side in place of the default upload icon
28
- * @default false
29
+ * Default value for uncontrolled usage
29
30
  */
30
- loading?: boolean;
31
- left?: ReactNode;
32
- right?: ReactNode;
31
+ defaultValue?: DocumentResult[];
33
32
  /**
34
33
  * To Control the value
35
34
  */
36
- value?: DocumentResult | DocumentResult[];
35
+ value?: DocumentResult[];
37
36
  /**
38
37
  * The Callback function to return the selected files as an array or object
39
38
  */
40
- onChange?: (result: DocumentResult | DocumentResult[]) => any;
41
- /**
42
- * To replace the default progress indicator
43
- */
44
- progressIndicator?: ReactNode;
39
+ onChange?: (result: DocumentResult[] | undefined) => any;
45
40
  };
46
41
 
47
- const FilePicker = (
48
- {
49
- loading,
50
- right: rightProp,
51
- progressIndicator,
52
- type,
53
- multiple,
54
- transitionStyle,
55
- mode,
56
- presentationStyle,
57
- value,
58
- onChange = () => {},
59
- onCancel,
60
- onError,
61
- ...rest
62
- }: Props,
63
- ref: any,
64
- ) => {
65
- const [displayText, setDisplayText] = useState('');
42
+ const FilePicker = ({
43
+ ref,
44
+ type,
45
+ multiple,
46
+ transitionStyle,
47
+ mode,
48
+ presentationStyle,
49
+ value: valueProp,
50
+ defaultValue,
51
+ onChange,
52
+ onCancel,
53
+ onError,
54
+ children,
55
+ ...rest
56
+ }: Props) => {
57
+ const [value, onValueChange] = useControlledValue<DocumentResult[] | undefined>({
58
+ value: valueProp,
59
+ defaultValue,
60
+ onChange,
61
+ });
66
62
 
67
63
  const { openFilePicker } = useFilePicker({
68
64
  type,
@@ -74,60 +70,34 @@ const FilePicker = (
74
70
  onError,
75
71
  });
76
72
 
77
- const onSetInputValue = useCallback(
78
- (response: DocumentResult | DocumentResult[] | undefined) => {
79
- if (Array.isArray(response)) {
80
- if (response.length > 1) {
81
- setDisplayText(`${response.length} file${response.length > 1 ? 's' : ''}`);
82
- return;
83
- }
73
+ const displayText = useMemo(() => {
74
+ if (!value) return '';
84
75
 
85
- setDisplayText(response[0].name || '');
86
- return;
87
- }
88
-
89
- setDisplayText(response?.name || '');
90
- },
91
- [],
92
- );
76
+ if (value.length > 1) {
77
+ return `${value.length} files`;
78
+ }
79
+ return value[0]?.name || '';
80
+ }, [value]);
93
81
 
94
82
  const onPress = useCallback(() => {
95
83
  openFilePicker(response => {
96
- onSetInputValue(response);
97
-
98
- onChange?.(response);
84
+ onValueChange(response);
99
85
  });
100
- }, [onChange, onSetInputValue, openFilePicker]);
101
-
102
- const rightElement = useMemo(() => {
103
- if (!loading) {
104
- return (
105
- <>
106
- {rightProp || (
107
- <IconButton type="material-community" name="upload" onPress={onPress} />
108
- )}
109
- </>
110
- );
111
- } else {
112
- return <>{progressIndicator || <ActivityIndicator />}</>;
113
- }
114
- }, [loading, onPress, progressIndicator, rightProp]);
86
+ }, [onValueChange, openFilePicker]);
115
87
 
116
- // if the value changes, we only want file name or the length of the array to display the text
117
- useEffect(() => {
118
- onSetInputValue(value);
119
- }, [onSetInputValue, value]);
88
+ const contextValue = useMemo(() => ({ onPressTrigger: onPress }), [onPress]);
120
89
 
121
90
  return (
122
- <TextInput
123
- label="Choose file"
124
- {...rest}
125
- value={displayText}
126
- editable={false}
127
- right={rightElement}
128
- ref={ref}
129
- />
91
+ <FilePickerContext value={contextValue}>
92
+ <TextInput value={displayText} {...rest} editable={false} ref={ref}>
93
+ <TextInput.Label>Choose file</TextInput.Label>
94
+ <TextInput.Right>
95
+ <IconButton type="material-community" name="upload" onPress={onPress} />
96
+ </TextInput.Right>
97
+ {children}
98
+ </TextInput>
99
+ </FilePickerContext>
130
100
  );
131
101
  };
132
102
 
133
- export default memo(forwardRef(FilePicker));
103
+ export default memo(FilePicker);
@@ -4,4 +4,5 @@ import FilePickerDefault from './FilePicker';
4
4
  export const FilePicker = getRegisteredComponentWithFallback('FilePicker', FilePickerDefault);
5
5
 
6
6
  export type { Props as FilePickerProps } from './FilePicker';
7
- export { defaultStyles } from './utils';
7
+ export type { FilePickerContextType } from './utils';
8
+ export { defaultStyles, FilePickerContext } from './utils';
@@ -1,7 +1,16 @@
1
+ import { createContext } from 'react';
1
2
  import { StyleSheet } from 'react-native-unistyles';
2
3
 
3
4
  import { getRegisteredComponentStylesWithFallback } from '../../core';
4
5
 
6
+ export type FilePickerContextType = {
7
+ onPressTrigger: () => void;
8
+ };
9
+
10
+ export const FilePickerContext = createContext<FilePickerContextType>({
11
+ onPressTrigger: () => {},
12
+ });
13
+
5
14
  const filePickerStylesDefault = StyleSheet.create({
6
15
  root: {},
7
16
  });
@@ -24,41 +24,6 @@ export type Props = TextProps & {
24
24
  testID?: string;
25
25
  };
26
26
 
27
- /**
28
- * Helper text is used in conjuction with input elements to provide additional hints for the user.
29
- *
30
- * <div class="screenshots">
31
- * <img class="small" src="screenshots/helper-text.gif" />
32
- * </div>
33
- *
34
- * ## Usage
35
- * ```js
36
- * import * as React from 'react';
37
- * import { View } from 'react-native';
38
- * import { HelperText, TextInput } from 'react-native-paper';
39
- *
40
- * const MyComponent = () => {
41
- * const [text, setText] = React.useState('');
42
- *
43
- * const onChangeText = text => setText(text);
44
- *
45
- * const hasErrors = () => {
46
- * return !text.includes('@');
47
- * };
48
- *
49
- * return (
50
- * <View>
51
- * <TextInput label="Email" value={text} onChangeText={onChangeText} />
52
- * <HelperText variant="error" visible={hasErrors()}>
53
- * Email address is invalid!
54
- * </HelperText>
55
- * </View>
56
- * );
57
- * };
58
- *
59
- * export default MyComponent;
60
- * ```
61
- */
62
27
  const HelperText = ({
63
28
  style: styleProp,
64
29
  variant = 'info',
@@ -1,6 +1,6 @@
1
1
  // import { textFactory } from '../Text/textFactory';
2
2
  import { memoize } from '../../utils/lodash';
3
- import { IconPacks, type IconType } from './types';
3
+ import type { IconType } from './types';
4
4
 
5
5
  const customIcons: any = {};
6
6
 
@@ -10,9 +10,9 @@ export const registerCustomIconType = (id: string, customIcon: any) => {
10
10
 
11
11
  export default memoize((type: IconType) => {
12
12
  switch (type) {
13
- case IconPacks.MaterialCommunity:
13
+ case 'material-community':
14
14
  return require('@react-native-vector-icons/material-design-icons').default;
15
- case IconPacks.Feather:
15
+ case 'feather':
16
16
  return require('@react-native-vector-icons/feather').default;
17
17
  default:
18
18
  if (Object.prototype.hasOwnProperty.call(customIcons, type)) {
@@ -4,4 +4,4 @@ import IconDefault from './Icon';
4
4
  export const Icon = getRegisteredComponentWithFallback('Icon', IconDefault);
5
5
 
6
6
  export { registerCustomIconType } from './iconFactory';
7
- export type { IconPacks, IconProps, IconType } from './types';
7
+ export type { CustomIconTypes, IconProps, IconType } from './types';
@@ -1,10 +1,5 @@
1
1
  import type { ColorValue, TextProps } from 'react-native';
2
2
 
3
- export enum IconPacks {
4
- MaterialCommunity = 'material-community',
5
- Feather = 'feather',
6
- }
7
-
8
3
  export interface VectorIconProps extends TextProps {
9
4
  /**
10
5
  * Size of the icon, can also be passed as fontSize in the style object.
@@ -28,7 +23,23 @@ export interface VectorIconProps extends TextProps {
28
23
  color?: ColorValue | number | undefined;
29
24
  }
30
25
 
31
- export type IconType = `${IconPacks}`; // in TS 4.1+, we can do this to make enum values as a union type
26
+ /**
27
+ * Interface for registering custom icon types.
28
+ * Users can extend this interface via declaration merging to add their own icon types.
29
+ *
30
+ * @example
31
+ * // In your app's type declarations (e.g., global.d.ts or a dedicated types file)
32
+ * declare module 'react-native-molecules' {
33
+ * interface CustomIconTypes {
34
+ * 'my-custom-icons': true;
35
+ * 'another-icon-set': true;
36
+ * }
37
+ * }
38
+ */
39
+
40
+ export interface CustomIconTypes {}
41
+
42
+ export type IconType = 'material-community' | 'feather' | keyof CustomIconTypes;
32
43
 
33
44
  export type IconProps = VectorIconProps & {
34
45
  type?: IconType;