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

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 (157) 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.tsx +23 -128
  14. package/components/Checkbox/utils.ts +0 -25
  15. package/components/Chip/Chip.tsx +40 -52
  16. package/components/Chip/utils.ts +3 -7
  17. package/components/DateField/DateField.tsx +110 -0
  18. package/components/DateField/index.tsx +6 -0
  19. package/components/{DatePickerInput/inputUtils.ts → DateField/useDateFieldState.ts} +17 -49
  20. package/components/DatePicker/DateCalendar.tsx +83 -0
  21. package/components/DatePicker/DatePickerActions.tsx +73 -0
  22. package/components/DatePicker/DatePickerModal.tsx +234 -0
  23. package/components/DatePicker/DatePickerPopover.tsx +79 -0
  24. package/components/DatePicker/DatePickerProvider.tsx +152 -0
  25. package/components/DatePicker/DatePickerTrigger.tsx +23 -0
  26. package/components/DatePicker/context.tsx +82 -0
  27. package/components/DatePicker/index.tsx +44 -0
  28. package/components/DatePicker/utils.ts +293 -0
  29. package/components/DatePickerInline/DatePickerContext.tsx +1 -0
  30. package/components/DatePickerInline/DatePickerDockedHeader.tsx +113 -0
  31. package/components/DatePickerInline/DatePickerInline.tsx +16 -15
  32. package/components/DatePickerInline/DatePickerInlineBase.tsx +7 -1
  33. package/components/DatePickerInline/Day.tsx +25 -1
  34. package/components/DatePickerInline/DayRange.tsx +2 -4
  35. package/components/DatePickerInline/HeaderItem.tsx +42 -27
  36. package/components/DatePickerInline/Month.tsx +45 -65
  37. package/components/DatePickerInline/MonthPicker.tsx +25 -41
  38. package/components/DatePickerInline/Swiper.native.tsx +21 -4
  39. package/components/DatePickerInline/Swiper.tsx +168 -13
  40. package/components/DatePickerInline/Week.tsx +6 -1
  41. package/components/DatePickerInline/YearPicker.tsx +206 -53
  42. package/components/DatePickerInline/dateUtils.tsx +17 -12
  43. package/components/DatePickerInline/types.ts +3 -0
  44. package/components/DatePickerInline/utils.ts +66 -29
  45. package/components/Drawer/Drawer.tsx +17 -6
  46. package/components/ElementGroup/ElementGroup.tsx +16 -14
  47. package/components/FilePicker/FilePicker.tsx +48 -78
  48. package/components/FilePicker/index.tsx +2 -1
  49. package/components/FilePicker/utils.ts +9 -0
  50. package/components/HelperText/HelperText.tsx +0 -35
  51. package/components/Icon/iconFactory.tsx +3 -3
  52. package/components/Icon/index.tsx +1 -1
  53. package/components/Icon/types.ts +17 -6
  54. package/components/IconButton/IconButton.tsx +42 -57
  55. package/components/IconButton/utils.ts +142 -33
  56. package/components/ListItem/ListItem.tsx +3 -1
  57. package/components/ListItem/utils.ts +1 -1
  58. package/components/LoadingIndicator/LoadingIndicator.tsx +253 -0
  59. package/components/LoadingIndicator/LoadingIndicator.web.tsx +136 -0
  60. package/components/LoadingIndicator/index.tsx +13 -0
  61. package/components/LoadingIndicator/utils.ts +117 -0
  62. package/components/Menu/Menu.tsx +3 -18
  63. package/components/NavigationRail/NavigationRail.tsx +15 -9
  64. package/components/Popover/Popover.tsx +122 -145
  65. package/components/Popover/PopoverRoot.tsx +74 -0
  66. package/components/Popover/common.ts +50 -34
  67. package/components/Popover/index.ts +18 -1
  68. package/components/Popover/usePlatformMeasure.native.ts +90 -0
  69. package/components/Popover/usePlatformMeasure.ts +118 -0
  70. package/components/Popover/utils.ts +34 -0
  71. package/components/Select/Select.tsx +368 -507
  72. package/components/Select/context.tsx +72 -0
  73. package/components/Select/index.ts +8 -14
  74. package/components/Select/types.ts +2 -4
  75. package/components/Select/utils.ts +144 -0
  76. package/components/Slot/Slot.tsx +244 -0
  77. package/components/Slot/compose-refs.tsx +62 -0
  78. package/components/Slot/index.tsx +8 -0
  79. package/components/Surface/Surface.android.tsx +34 -8
  80. package/components/Surface/Surface.ios.tsx +36 -29
  81. package/components/Surface/Surface.tsx +31 -4
  82. package/components/Surface/utils.ts +44 -30
  83. package/components/Switch/Switch.tsx +8 -2
  84. package/components/Tabs/TabItem.tsx +35 -58
  85. package/components/Tabs/TabLabel.tsx +5 -9
  86. package/components/Tabs/Tabs.tsx +154 -148
  87. package/components/Tabs/utils.ts +15 -2
  88. package/components/TextInput/TextInput.tsx +658 -575
  89. package/components/TextInput/index.tsx +19 -3
  90. package/components/TextInput/types.ts +76 -27
  91. package/components/TextInput/utils.ts +225 -145
  92. package/components/TimeField/TimeField.tsx +75 -0
  93. package/components/TimeField/index.tsx +6 -0
  94. package/components/TimeField/useTimeFieldState.ts +70 -0
  95. package/components/{TimePickerField/sanitizeTime.ts → TimeField/utils.ts} +77 -10
  96. package/components/TimePicker/TimeInput.tsx +87 -37
  97. package/components/TimePicker/TimeInputs.tsx +137 -49
  98. package/components/TimePicker/TimePicker.tsx +73 -10
  99. package/components/TimePicker/TimePickerModal.tsx +186 -0
  100. package/components/TimePicker/context.tsx +17 -0
  101. package/components/TimePicker/index.tsx +15 -3
  102. package/components/TimePicker/utils.ts +93 -0
  103. package/components/Tooltip/Tooltip.tsx +42 -67
  104. package/components/Tooltip/TooltipContent.tsx +32 -5
  105. package/components/Tooltip/TooltipTrigger.tsx +20 -20
  106. package/components/Tooltip/index.tsx +1 -1
  107. package/components/TouchableRipple/TouchableRipple.native.tsx +50 -14
  108. package/components/TouchableRipple/TouchableRipple.tsx +137 -47
  109. package/hocs/withPortal.tsx +1 -1
  110. package/hooks/index.tsx +0 -6
  111. package/hooks/useActionState.tsx +19 -8
  112. package/hooks/useControlledValue.tsx +20 -4
  113. package/hooks/useFilePicker.tsx +6 -16
  114. package/hooks/useWhatHasUpdated.tsx +48 -0
  115. package/package.json +17 -13
  116. package/shortcuts-manager/ShortcutsManager/ShortcutsManager.tsx +5 -2
  117. package/styles/shadow.ts +2 -1
  118. package/styles/themes/LightTheme.tsx +1 -1
  119. package/utils/DocumentPicker/documentPicker.ts +78 -27
  120. package/utils/DocumentPicker/types.ts +0 -1
  121. package/utils/extractPropertiesFromStyles.ts +25 -0
  122. package/utils/extractSubcomponents.ts +89 -0
  123. package/utils/lodash.ts +77 -5
  124. package/components/DatePickerDocked/DatePickerDocked.tsx +0 -30
  125. package/components/DatePickerDocked/DatePickerDockedHeader.tsx +0 -129
  126. package/components/DatePickerDocked/index.tsx +0 -17
  127. package/components/DatePickerDocked/types.ts +0 -11
  128. package/components/DatePickerDocked/utils.ts +0 -157
  129. package/components/DatePickerInput/DatePickerInput.tsx +0 -139
  130. package/components/DatePickerInput/DatePickerInputModal.tsx +0 -48
  131. package/components/DatePickerInput/DatePickerInputWithoutModal.tsx +0 -77
  132. package/components/DatePickerInput/DateRangeInput.tsx +0 -88
  133. package/components/DatePickerInput/index.tsx +0 -10
  134. package/components/DatePickerInput/types.ts +0 -28
  135. package/components/DatePickerInput/utils.ts +0 -15
  136. package/components/DatePickerModal/AnimatedCrossView.tsx +0 -94
  137. package/components/DatePickerModal/CalendarEdit.tsx +0 -139
  138. package/components/DatePickerModal/DatePickerModal.tsx +0 -85
  139. package/components/DatePickerModal/DatePickerModalContent.tsx +0 -155
  140. package/components/DatePickerModal/DatePickerModalContentHeader.tsx +0 -213
  141. package/components/DatePickerModal/DatePickerModalHeader.tsx +0 -74
  142. package/components/DatePickerModal/DatePickerModalHeaderBackground.tsx +0 -13
  143. package/components/DatePickerModal/index.tsx +0 -16
  144. package/components/DatePickerModal/types.ts +0 -92
  145. package/components/DatePickerModal/utils.ts +0 -122
  146. package/components/DateTimePicker/DateTimePicker.tsx +0 -172
  147. package/components/DateTimePicker/index.tsx +0 -10
  148. package/components/DateTimePicker/utils.ts +0 -12
  149. package/components/Popover/Popover.native.tsx +0 -185
  150. package/components/TimePickerField/TimePickerField.tsx +0 -152
  151. package/components/TimePickerField/index.tsx +0 -10
  152. package/components/TimePickerField/utils.ts +0 -94
  153. package/components/TimePickerModal/TimePickerModal.tsx +0 -115
  154. package/components/TimePickerModal/index.tsx +0 -10
  155. package/components/TimePickerModal/utils.ts +0 -47
  156. package/hooks/useSearchable.tsx +0 -74
  157. package/hooks/useSubcomponents.tsx +0 -59
@@ -1,122 +0,0 @@
1
- import { StyleSheet } from 'react-native-unistyles';
2
-
3
- import { getRegisteredComponentStylesWithFallback } from '../../core';
4
-
5
- const datePickerModalStylesDefault = StyleSheet.create(theme => ({
6
- header: {
7
- backgroundColor: theme.colors.primary,
8
- },
9
- }));
10
-
11
- const datePickerModalHeaderStylesDefault = StyleSheet.create(theme => ({
12
- root: {
13
- color: theme.colors.onPrimary,
14
- },
15
- animated: {
16
- paddingBottom: theme.spacings['0'],
17
- elevation: 4,
18
- },
19
- safeContent: {
20
- paddingBottom: theme.spacings['0'],
21
-
22
- variants: {
23
- state: {
24
- disableSafeTop: {
25
- paddingTop: 0,
26
- },
27
- },
28
- },
29
- },
30
- safeContentNoTop: {
31
- paddingTop: theme.spacings['0'],
32
- },
33
- appbarHeader: {
34
- flexDirection: 'row',
35
- alignItems: 'center',
36
- justifyContent: 'space-between',
37
- paddingHorizontal: theme.spacings['2'],
38
- paddingVertical: theme.spacings['2'],
39
- elevation: 0,
40
- backgroundColor: 'transparent',
41
- },
42
- }));
43
-
44
- const datePickerModalContentHeaderStylesDefault = StyleSheet.create(theme => ({
45
- root: {
46
- color: theme.colors.onPrimary,
47
- },
48
-
49
- fill: {
50
- flex: 1,
51
- },
52
- header: {
53
- height: 75,
54
- alignItems: 'center',
55
- flexDirection: 'row',
56
- paddingLeft: theme.spacings['6'],
57
- paddingRight: theme.spacings['3'],
58
- },
59
- headerContentContainer: {
60
- marginTop: theme.spacings['1'],
61
- flexDirection: 'row',
62
- alignItems: 'center',
63
- },
64
- label: {
65
- color: theme.colors.onPrimary,
66
- letterSpacing: 1,
67
- fontSize: theme.typescale.bodyMedium.fontSize,
68
- },
69
- headerText: {
70
- fontSize: theme.typescale.bodyMedium.fontSize,
71
- color: theme.colors.onPrimary,
72
- },
73
- headerSeparator: {
74
- fontSize: theme.typescale.bodyMedium.fontSize,
75
- paddingLeft: theme.spacings['2'],
76
- paddingRight: theme.spacings['2'],
77
- color: theme.colors.onPrimary,
78
- },
79
- icon: {
80
- color: theme.colors.onPrimary,
81
- },
82
- }));
83
-
84
- const datePickerModalHeaderBackgroundStylesDefault = StyleSheet.create(theme => ({
85
- header: {
86
- backgroundColor: theme.colors.primary,
87
- paddingBottom: theme.spacings['0'],
88
- elevation: 4,
89
- },
90
- safeContent: {
91
- paddingBottom: theme.spacings['0'],
92
- },
93
- }));
94
-
95
- const datePickerModalEditStylesDefault = StyleSheet.create(theme => ({
96
- container: { padding: theme.spacings['3'] },
97
- inner: { flexDirection: 'row' },
98
- inputContainer: { flex: 1 },
99
- input: { flex: 1 },
100
- separator: { width: 12 },
101
- }));
102
-
103
- export const datePickerModalStyles = getRegisteredComponentStylesWithFallback(
104
- 'DatePickerModal',
105
- datePickerModalStylesDefault,
106
- );
107
- export const datePickerModalHeaderStyles = getRegisteredComponentStylesWithFallback(
108
- 'DatePickerModal_Header',
109
- datePickerModalHeaderStylesDefault,
110
- );
111
- export const datePickerModalContentHeaderStyles = getRegisteredComponentStylesWithFallback(
112
- 'DatePickerModal_ContentHeader',
113
- datePickerModalContentHeaderStylesDefault,
114
- );
115
- export const datePickerModalHeaderBackgroundStyles = getRegisteredComponentStylesWithFallback(
116
- 'DatePickerModal_HeaderBackground',
117
- datePickerModalHeaderBackgroundStylesDefault,
118
- );
119
- export const datePickerModalEditStyles = getRegisteredComponentStylesWithFallback(
120
- 'DatePickerModal_Edit',
121
- datePickerModalEditStylesDefault,
122
- );
@@ -1,172 +0,0 @@
1
- import { format, parse, set } from 'date-fns';
2
- import {
3
- type ComponentType,
4
- forwardRef,
5
- memo,
6
- type RefObject,
7
- useCallback,
8
- useEffect,
9
- useImperativeHandle,
10
- useMemo,
11
- useRef,
12
- } from 'react';
13
- import type { ViewProps, ViewStyle } from 'react-native';
14
-
15
- import { useControlledValue } from '../../hooks';
16
- import { isValid } from '../../utils/date-fns';
17
- import { DatePickerInput, type DatePickerInputProps } from '../DatePickerInput';
18
- import { ElementGroup } from '../ElementGroup';
19
- import type { TextInputHandles } from '../TextInput/TextInput';
20
- import { sanitizeTimeString, TimePickerField, type TimePickerFieldProps } from '../TimePickerField';
21
-
22
- export type Props = Omit<ViewProps, 'style'> & {
23
- is24Hour?: boolean;
24
- date?: Date | null;
25
- onChange?: (date: Date | null) => void;
26
- defaultValue?: Date | null;
27
- timePickerFieldProps?: Omit<
28
- Partial<TimePickerFieldProps>,
29
- 'value' | 'onChangeText' | 'date' | 'onTimeChange'
30
- >;
31
- datePickerInputProps?: Omit<Partial<DatePickerInputProps>, 'value' | 'onChange'>;
32
- datePickerInputRef?: RefObject<TextInputHandles | null>;
33
- timePickerInputRef?: RefObject<TextInputHandles | null>;
34
- Wrapper?: ComponentType<any>;
35
- style?: ViewStyle;
36
- };
37
-
38
- const emptyObj = {};
39
-
40
- const normalizeDateWithCurrentTime = (specificDate: Date) => {
41
- const date = new Date();
42
-
43
- return set(specificDate, {
44
- hours: date.getHours(),
45
- minutes: date.getHours(),
46
- seconds: date.getSeconds(),
47
- });
48
- };
49
-
50
- const DateTimePicker = (
51
- {
52
- is24Hour = false,
53
- date: dateProp,
54
- onChange: onChangeProp,
55
- defaultValue,
56
- datePickerInputProps = emptyObj,
57
- timePickerFieldProps = emptyObj,
58
- style,
59
- testID,
60
- datePickerInputRef: _datePickerInputRef,
61
- timePickerInputRef: _timePickerInputRef,
62
- Wrapper: _WrapperProp,
63
- ...rest
64
- }: Props,
65
- ref: any,
66
- ) => {
67
- const Wrapper = _WrapperProp ?? ElementGroup;
68
-
69
- const containerRef = useRef(null);
70
- const datePickerInputRef = useRef<TextInputHandles>(null);
71
- const timePickerInputRef = useRef<TextInputHandles>(null);
72
-
73
- const [date, onChange] = useControlledValue<Date | null>({
74
- value: dateProp,
75
- defaultValue,
76
- onChange: onChangeProp,
77
- });
78
-
79
- const timeString = useMemo(() => (date && isValid(date) ? format(date, 'HH:mm') : ''), [date]);
80
-
81
- const timeStringRef = useRef(timeString);
82
-
83
- const onDateChange = useCallback(
84
- (newDate: Date | null) => {
85
- if (newDate === date || (!isValid(newDate) && !isValid(date))) return;
86
-
87
- if (!newDate) {
88
- onChange(null);
89
-
90
- return;
91
- }
92
-
93
- const addTimeString = (_date: Date) =>
94
- timeStringRef.current
95
- ? parse(timeStringRef.current ?? '00:00', 'HH:mm', _date)
96
- : _date;
97
-
98
- if (!date) {
99
- onChange(addTimeString(normalizeDateWithCurrentTime(newDate)));
100
- return;
101
- }
102
-
103
- if (!isValid(newDate)) {
104
- onChange(date);
105
- return;
106
- }
107
-
108
- const [day, month, year] = format(newDate, 'dd/MM/yyyy').split('/');
109
-
110
- onChange(addTimeString(set(date, { date: +day, month: +month - 1, year: +year })));
111
- },
112
- [date, onChange],
113
- );
114
-
115
- const onTimeChange = useCallback(
116
- (time: string) => {
117
- if (!time) return;
118
-
119
- const newTime = sanitizeTimeString(time);
120
-
121
- timeStringRef.current = newTime;
122
-
123
- onChange(date ? parse(newTime, 'HH:mm', date) : null);
124
- },
125
- [date, onChange],
126
- );
127
-
128
- useEffect(() => {
129
- if (isValid(date)) return;
130
-
131
- onChange(null);
132
- }, [date, onChange]);
133
-
134
- useImperativeHandle(_datePickerInputRef, () => datePickerInputRef.current as TextInputHandles);
135
- useImperativeHandle(_timePickerInputRef, () => timePickerInputRef.current as TextInputHandles);
136
-
137
- useImperativeHandle(ref, () =>
138
- Object.assign(containerRef.current || {}, {
139
- blur: () => {
140
- datePickerInputRef.current?.blur?.();
141
- timePickerInputRef.current?.blur?.();
142
- },
143
- }),
144
- );
145
-
146
- return (
147
- <>
148
- <Wrapper style={style} testID={testID} {...rest} ref={containerRef}>
149
- <DatePickerInput
150
- ref={datePickerInputRef}
151
- inputMode="start"
152
- variant="outlined"
153
- testID={testID ? `${testID}--datepickerinput` : undefined}
154
- {...datePickerInputProps}
155
- value={date}
156
- onChange={onDateChange}
157
- />
158
- <TimePickerField
159
- ref={timePickerInputRef}
160
- variant="outlined"
161
- testID={testID ? `${testID}--timepickerinput` : undefined}
162
- is24Hour={is24Hour}
163
- {...timePickerFieldProps}
164
- time={timeString}
165
- onTimeChange={onTimeChange}
166
- />
167
- </Wrapper>
168
- </>
169
- );
170
- };
171
-
172
- export default memo(forwardRef(DateTimePicker));
@@ -1,10 +0,0 @@
1
- import { getRegisteredComponentWithFallback } from '../../core';
2
- import DateTimePickerDefault from './DateTimePicker';
3
-
4
- export const DateTimePicker = getRegisteredComponentWithFallback(
5
- 'DateTimePicker',
6
- DateTimePickerDefault,
7
- );
8
-
9
- export type { Props as DateTimePickerProps } from './DateTimePicker';
10
- export { dateTimePickerStyles } from './utils';
@@ -1,12 +0,0 @@
1
- import { StyleSheet } from 'react-native-unistyles';
2
-
3
- import { getRegisteredComponentStylesWithFallback } from '../../core';
4
-
5
- const dateTimePickerStylesDefault = StyleSheet.create({
6
- container: {},
7
- });
8
-
9
- export const dateTimePickerStyles = getRegisteredComponentStylesWithFallback(
10
- 'DateTimePicker',
11
- dateTimePickerStylesDefault,
12
- );
@@ -1,185 +0,0 @@
1
- import { Fragment, memo, useCallback, useEffect, useLayoutEffect, useRef } from 'react';
2
- import { AppState, Dimensions, Platform, Pressable, StyleSheet, View } from 'react-native';
3
- import { ScopedTheme, UnistylesRuntime } from 'react-native-unistyles';
4
-
5
- import { Portal } from '../Portal';
6
- import {
7
- DEFAULT_ARROW_SIZE,
8
- popoverDefaultStyles,
9
- type PopoverProps,
10
- useArrowStyles,
11
- usePopover,
12
- } from './common';
13
-
14
- const Popover = ({
15
- triggerRef,
16
- children,
17
- isOpen,
18
- onClose,
19
- position = 'bottom',
20
- align = 'center',
21
- style,
22
- showArrow = false,
23
- arrowSize = DEFAULT_ARROW_SIZE,
24
- inverted = false,
25
- triggerDimensions,
26
- offset = 8,
27
- ...rest
28
- }: PopoverProps) => {
29
- const {
30
- popoverLayoutRef,
31
- targetLayoutRef,
32
- actualPositionRef,
33
- calculatedPosition,
34
- calculateAndSetPosition,
35
- handlePopoverLayout,
36
- } = usePopover({
37
- isOpen,
38
- position,
39
- align,
40
- showArrow,
41
- arrowSize,
42
- offset,
43
- });
44
-
45
- const popoverRef = useRef<View>(null);
46
-
47
- const measureTarget = useCallback(() => {
48
- if (triggerRef.current) {
49
- triggerRef.current.measure(
50
- (
51
- _fx: number,
52
- _fy: number,
53
- width: number,
54
- height: number,
55
- px: number,
56
- py: number,
57
- ) => {
58
- if (width !== 0 || height !== 0) {
59
- const newLayout = { x: px, y: py, width, height };
60
- const changed =
61
- !targetLayoutRef.current ||
62
- targetLayoutRef.current.x !== newLayout.x ||
63
- targetLayoutRef.current.y !== newLayout.y ||
64
- targetLayoutRef.current.width !== newLayout.width ||
65
- targetLayoutRef.current.height !== newLayout.height;
66
-
67
- if (changed) {
68
- targetLayoutRef.current = newLayout;
69
- calculateAndSetPosition();
70
- }
71
- } else {
72
- targetLayoutRef.current = null;
73
- calculateAndSetPosition();
74
- }
75
- },
76
- () => {
77
- console.error('Failed to measure target element for Popover.');
78
- targetLayoutRef.current = null;
79
- calculateAndSetPosition();
80
- },
81
- );
82
- } else {
83
- targetLayoutRef.current = null;
84
- calculateAndSetPosition();
85
- }
86
- }, [triggerRef, calculateAndSetPosition, targetLayoutRef]);
87
-
88
- useLayoutEffect(() => {
89
- if (isOpen) {
90
- measureTarget();
91
- }
92
- }, [isOpen, measureTarget, triggerDimensions]);
93
-
94
- useEffect(() => {
95
- if (!isOpen) return;
96
- const subscription = Dimensions.addEventListener('change', measureTarget);
97
- return () => {
98
- if (typeof subscription?.remove === 'function') {
99
- subscription.remove();
100
- }
101
- };
102
- }, [isOpen, measureTarget]);
103
-
104
- useEffect(() => {
105
- if (!isOpen || Platform.OS === 'web') return;
106
- const handleAppStateChange = (nextAppState: string) => {
107
- if (nextAppState === 'active') {
108
- setTimeout(measureTarget, 50);
109
- }
110
- };
111
- const subscription = AppState.addEventListener('change', handleAppStateChange);
112
- return () => {
113
- if (typeof subscription?.remove === 'function') {
114
- subscription.remove();
115
- }
116
- };
117
- }, [isOpen, measureTarget]);
118
-
119
- const arrowStyles = useArrowStyles({
120
- showArrow,
121
- arrowSize,
122
- style,
123
- calculatedPosition,
124
- targetLayoutRef,
125
- popoverLayoutRef,
126
- actualPositionRef,
127
- });
128
-
129
- const popoverStyle = calculatedPosition ?? popoverDefaultStyles;
130
- const Wrapper = inverted ? ScopedTheme : Fragment;
131
-
132
- if (!isOpen && popoverStyle.opacity === 0) {
133
- return null;
134
- }
135
-
136
- const handleOutsidePress = () => {
137
- if (isOpen && onClose) {
138
- onClose();
139
- }
140
- };
141
-
142
- return (
143
- <Portal>
144
- <Wrapper
145
- {...(inverted
146
- ? { name: UnistylesRuntime.themeName === 'dark' ? 'light' : 'dark' }
147
- : ({} as { name: 'light' }))}>
148
- <Pressable onPress={handleOutsidePress} style={styles.overlay} />
149
-
150
- <View
151
- ref={popoverRef}
152
- onLayout={handlePopoverLayout}
153
- style={[styles.popoverContainer, style, popoverStyle]}
154
- {...rest}>
155
- {children}
156
- {showArrow && popoverStyle.opacity === 1 && <View style={arrowStyles} />}
157
- </View>
158
- </Wrapper>
159
- </Portal>
160
- );
161
- };
162
-
163
- const styles = StyleSheet.create({
164
- overlay: {
165
- position: 'absolute',
166
- top: 0,
167
- bottom: 0,
168
- left: 0,
169
- right: 0,
170
- backgroundColor: 'transparent',
171
- },
172
- popoverContainer: {
173
- ...popoverDefaultStyles,
174
- backgroundColor: 'white',
175
- borderRadius: 4,
176
- shadowColor: 'rgba(0, 0, 0, 1)',
177
- shadowOffset: { width: 0, height: 2 },
178
- shadowOpacity: 0.3,
179
- shadowRadius: 3.84,
180
- elevation: 5,
181
- zIndex: 100,
182
- },
183
- });
184
-
185
- export default memo(Popover);
@@ -1,152 +0,0 @@
1
- import { forwardRef, memo, useCallback, useEffect, useMemo, useRef, useState } from 'react';
2
- import type { BlurEvent, FocusEvent } from 'react-native';
3
-
4
- import { useToggle } from '../../hooks';
5
- import { IconButton, type IconButtonProps } from '../IconButton';
6
- import { TextInput, type TextInputProps } from '../TextInput';
7
- import type { TimePickerModalProps } from '../TimePickerModal';
8
- import { TimePickerModal } from '../TimePickerModal/TimePickerModal';
9
- import { sanitizeTime } from './sanitizeTime';
10
- import { getFormattedTime, getOutputTime, styles, timeFormat } from './utils';
11
-
12
- export type Props = TextInputProps & {
13
- time: string;
14
- onTimeChange: (time: string) => void;
15
- is24Hour?: boolean;
16
- withModal?: boolean;
17
- modalProps?: Omit<TimePickerModalProps, 'time' | 'onConfirm' | 'isOpen' | 'onClose' | 'ref'>;
18
- iconButtonProps?: Omit<Partial<IconButtonProps>, 'onPress' | 'ref'>;
19
- };
20
-
21
- const TimePickerField = (
22
- {
23
- time,
24
- onTimeChange: onTimeChangeProp,
25
- is24Hour = false,
26
- withModal = true,
27
- style,
28
- onBlur: onBlurProp,
29
- modalProps = {},
30
- iconButtonProps = {},
31
- disabled,
32
- onFocus: onFocusProp,
33
- ...rest
34
- }: Props,
35
- ref: any,
36
- ) => {
37
- const componentStyles = useMemo(() => [styles.root, style], [style]);
38
-
39
- const [timeString, setTimeString] = useState(() => getFormattedTime({ time, is24Hour }));
40
- const isBlurredRef = useRef(true);
41
-
42
- const currentTimeFormat = useMemo(() => timeFormat[!is24Hour ? '12' : '24'], [is24Hour]);
43
-
44
- const { state: isOpen, handleOpen: onOpenModal, handleClose: onCloseModal } = useToggle(false);
45
-
46
- const onChangeText = useCallback(
47
- (_text: string) => {
48
- const text = sanitizeTime(_text, is24Hour);
49
- setTimeString(_text);
50
-
51
- if (disabled || !text) return;
52
-
53
- const outputTime = getOutputTime({ time: text || time, is24Hour });
54
-
55
- onTimeChangeProp(outputTime);
56
- },
57
- [disabled, is24Hour, onTimeChangeProp, time],
58
- );
59
-
60
- const onConfirmTime = useCallback(
61
- (newTime: string) => {
62
- onCloseModal();
63
-
64
- onTimeChangeProp(newTime);
65
- },
66
- [onTimeChangeProp, onCloseModal],
67
- );
68
-
69
- const onBlur = useCallback(
70
- (e: BlurEvent) => {
71
- isBlurredRef.current = true;
72
- onBlurProp?.(e);
73
-
74
- if (disabled) return;
75
-
76
- // const outputTime = getOutputTime({ time: timeString || time, is24Hour });
77
- // onTimeChangeProp(outputTime);
78
-
79
- // if (time === outputTime) {
80
- setTimeString(sanitizeTime(getFormattedTime({ time, is24Hour }), is24Hour));
81
- // }
82
- },
83
- [disabled, is24Hour, onBlurProp, time],
84
- );
85
-
86
- const onFocus = useCallback(
87
- (e: FocusEvent) => {
88
- isBlurredRef.current = false;
89
-
90
- onFocusProp?.(e);
91
- },
92
- [onFocusProp],
93
- );
94
-
95
- const rightElement = useMemo(() => {
96
- if (!withModal) return null;
97
-
98
- return (
99
- <>
100
- <IconButton
101
- name="clock-outline"
102
- onPress={onOpenModal}
103
- disabled={disabled}
104
- {...iconButtonProps}
105
- />
106
- <TimePickerModal
107
- {...modalProps}
108
- time={getFormattedTime({ time: time, is24Hour: true })}
109
- isOpen={isOpen}
110
- onClose={onCloseModal}
111
- onConfirm={onConfirmTime}
112
- is24Hour={is24Hour}
113
- />
114
- </>
115
- );
116
- }, [
117
- disabled,
118
- iconButtonProps,
119
- is24Hour,
120
- isOpen,
121
- modalProps,
122
- onCloseModal,
123
- onConfirmTime,
124
- onOpenModal,
125
- time,
126
- withModal,
127
- ]);
128
-
129
- // only change masked string when the input is not focus so as to not interrup the user
130
- useEffect(() => {
131
- if (!isBlurredRef.current) return;
132
-
133
- setTimeString(getFormattedTime({ time, is24Hour }));
134
- }, [is24Hour, time]);
135
-
136
- return (
137
- <TextInput
138
- ref={ref}
139
- placeholder={currentTimeFormat.format}
140
- {...rest}
141
- disabled={disabled}
142
- value={timeString}
143
- onFocus={onFocus}
144
- onChangeText={onChangeText}
145
- style={componentStyles}
146
- onBlur={onBlur}
147
- right={rightElement}
148
- />
149
- );
150
- };
151
-
152
- export default memo(forwardRef(TimePickerField));
@@ -1,10 +0,0 @@
1
- import { getRegisteredComponentWithFallback } from '../../core';
2
- import TimePickerFieldDefault from './TimePickerField';
3
-
4
- export const TimePickerField = getRegisteredComponentWithFallback(
5
- 'TimePickerField',
6
- TimePickerFieldDefault,
7
- );
8
-
9
- export { type Props as TimePickerFieldProps } from './TimePickerField';
10
- export { sanitizeTimeString, styles } from './utils';