react-native-molecules 0.5.0-beta.3 → 0.5.0-beta.30
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.
- package/components/Accordion/Accordion.tsx +2 -6
- package/components/Accordion/AccordionItem.tsx +16 -12
- package/components/Accordion/AccordionItemContent.tsx +6 -1
- package/components/Accordion/AccordionItemHeader.tsx +1 -1
- package/components/Accordion/utils.ts +6 -0
- package/components/ActivityIndicator/ActivityIndicator.tsx +6 -15
- package/components/Appbar/AppbarBase.tsx +18 -13
- package/components/Button/Button.tsx +211 -264
- package/components/Button/index.tsx +9 -3
- package/components/Button/types.ts +16 -2
- package/components/Button/utils.ts +230 -208
- package/components/Card/Card.tsx +1 -1
- package/components/Checkbox/Checkbox.tsx +125 -88
- package/components/Checkbox/CheckboxBase.ios.tsx +14 -23
- package/components/Checkbox/CheckboxBase.tsx +21 -137
- package/components/Checkbox/context.tsx +14 -0
- package/components/Checkbox/index.tsx +11 -4
- package/components/Checkbox/types.ts +63 -29
- package/components/Checkbox/utils.ts +25 -108
- package/components/Chip/Chip.tsx +41 -52
- package/components/Chip/utils.ts +3 -7
- package/components/DateField/DateField.tsx +111 -0
- package/components/DateField/index.tsx +6 -0
- package/components/{DatePickerInput/inputUtils.ts → DateField/useDateFieldState.ts} +19 -51
- package/components/DatePicker/DateCalendar.tsx +83 -0
- package/components/DatePicker/DatePickerActions.tsx +73 -0
- package/components/DatePicker/DatePickerModal.tsx +246 -0
- package/components/DatePicker/DatePickerPopover.tsx +79 -0
- package/components/DatePicker/DatePickerProvider.tsx +158 -0
- package/components/DatePicker/DatePickerTrigger.tsx +23 -0
- package/components/DatePicker/context.tsx +83 -0
- package/components/DatePicker/index.tsx +45 -0
- package/components/DatePicker/utils.ts +295 -0
- package/components/DatePickerInline/DatePickerDockedHeader.tsx +117 -0
- package/components/DatePickerInline/DatePickerInline.tsx +17 -16
- package/components/DatePickerInline/DatePickerInlineBase.tsx +11 -5
- package/components/DatePickerInline/DatePickerInlineHeader.tsx +50 -20
- package/components/DatePickerInline/Day.tsx +25 -1
- package/components/DatePickerInline/DayNames.tsx +13 -10
- package/components/DatePickerInline/DayRange.tsx +2 -4
- package/components/DatePickerInline/HeaderItem.tsx +44 -29
- package/components/DatePickerInline/Month.tsx +48 -67
- package/components/DatePickerInline/MonthPicker.tsx +80 -92
- package/components/DatePickerInline/Swiper.native.tsx +21 -4
- package/components/DatePickerInline/Swiper.tsx +169 -14
- package/components/DatePickerInline/SwiperUtils.ts +1 -1
- package/components/DatePickerInline/Week.tsx +6 -1
- package/components/DatePickerInline/YearPicker.tsx +220 -78
- package/components/DatePickerInline/dateUtils.tsx +18 -13
- package/components/DatePickerInline/store.tsx +27 -0
- package/components/DatePickerInline/types.ts +6 -2
- package/components/DatePickerInline/utils.ts +66 -29
- package/components/Divider/Divider.tsx +192 -0
- package/components/Divider/index.tsx +10 -0
- package/components/Drawer/Drawer.tsx +17 -6
- package/components/Drawer/DrawerItemGroup.tsx +3 -7
- package/components/ElementGroup/ElementGroup.tsx +1 -1
- package/components/FilePicker/FilePicker.tsx +48 -78
- package/components/FilePicker/index.tsx +2 -1
- package/components/FilePicker/utils.ts +9 -0
- package/components/HelperText/HelperText.tsx +0 -35
- package/components/Icon/iconFactory.tsx +5 -4
- package/components/Icon/index.tsx +1 -1
- package/components/Icon/types.ts +17 -6
- package/components/IconButton/IconButton.tsx +84 -84
- package/components/IconButton/index.tsx +1 -0
- package/components/IconButton/types.ts +10 -0
- package/components/IconButton/utils.ts +167 -33
- package/components/List/List.tsx +276 -0
- package/components/List/context.tsx +27 -0
- package/components/List/index.ts +8 -0
- package/components/List/types.ts +117 -0
- package/components/List/utils.ts +79 -0
- package/components/LoadingIndicator/LoadingIndicator.tsx +253 -0
- package/components/LoadingIndicator/LoadingIndicator.web.tsx +136 -0
- package/components/LoadingIndicator/index.tsx +13 -0
- package/components/LoadingIndicator/utils.ts +117 -0
- package/components/Menu/Menu.tsx +162 -39
- package/components/Menu/index.tsx +10 -7
- package/components/Menu/utils.ts +21 -70
- package/components/NavigationRail/NavigationRail.tsx +15 -9
- package/components/Popover/Popover.tsx +119 -145
- package/components/Popover/PopoverRoot.tsx +60 -0
- package/components/Popover/common.ts +54 -34
- package/components/Popover/index.ts +12 -1
- package/components/Popover/usePlatformMeasure.native.ts +90 -0
- package/components/Popover/usePlatformMeasure.ts +120 -0
- package/components/Popover/utils.ts +34 -0
- package/components/Portal/Portal.tsx +1 -2
- package/components/Radio/Radio.tsx +188 -0
- package/components/Radio/RadioBase.ios.tsx +69 -0
- package/components/Radio/RadioBase.tsx +136 -0
- package/components/Radio/context.tsx +23 -0
- package/components/Radio/index.tsx +20 -0
- package/components/Radio/types.ts +101 -0
- package/components/Radio/utils.ts +115 -0
- package/components/Rating/Rating.tsx +1 -1
- package/components/Select/Select.tsx +521 -785
- package/components/Select/context.tsx +81 -0
- package/components/Select/index.ts +26 -14
- package/components/Select/types.ts +65 -58
- package/components/Select/utils.ts +126 -0
- package/components/Slot/Slot.tsx +244 -0
- package/components/Slot/compose-refs.tsx +62 -0
- package/components/Slot/index.tsx +8 -0
- package/components/Surface/Surface.android.tsx +32 -7
- package/components/Surface/Surface.ios.tsx +34 -29
- package/components/Surface/Surface.tsx +31 -4
- package/components/Surface/utils.ts +44 -6
- package/components/Switch/Switch.ios.tsx +1 -1
- package/components/Switch/Switch.tsx +10 -3
- package/components/Tabs/TabItem.tsx +35 -58
- package/components/Tabs/TabLabel.tsx +5 -9
- package/components/Tabs/Tabs.tsx +156 -150
- package/components/Tabs/utils.ts +15 -2
- package/components/Text/textFactory.tsx +17 -5
- package/components/TextInput/TextInput.tsx +663 -579
- package/components/TextInput/index.tsx +19 -3
- package/components/TextInput/types.ts +77 -28
- package/components/TextInput/utils.ts +235 -145
- package/components/TimeField/TimeField.tsx +75 -0
- package/components/TimeField/index.tsx +6 -0
- package/components/TimeField/useTimeFieldState.ts +70 -0
- package/components/{TimePickerField/sanitizeTime.ts → TimeField/utils.ts} +77 -10
- package/components/TimePicker/AnalogClock.tsx +1 -1
- package/components/TimePicker/TimeInput.tsx +87 -42
- package/components/TimePicker/TimeInputs.tsx +138 -50
- package/components/TimePicker/TimePicker.tsx +74 -11
- package/components/TimePicker/TimePickerModal.tsx +186 -0
- package/components/TimePicker/context.tsx +17 -0
- package/components/TimePicker/index.tsx +15 -3
- package/components/TimePicker/utils.ts +93 -4
- package/components/Tooltip/Tooltip.tsx +42 -67
- package/components/Tooltip/TooltipContent.tsx +32 -5
- package/components/Tooltip/TooltipTrigger.tsx +20 -20
- package/components/Tooltip/index.tsx +1 -1
- package/components/TouchableRipple/TouchableRipple.native.tsx +83 -16
- package/components/TouchableRipple/TouchableRipple.tsx +150 -102
- package/components/TouchableRipple/rippleFromForegroundColor.ts +21 -0
- package/hocs/index.tsx +1 -1
- package/hocs/withKeyboardAccessibility.tsx +2 -3
- package/hocs/withPortal.tsx +1 -1
- package/hooks/index.tsx +2 -12
- package/hooks/useActionState.tsx +19 -8
- package/hooks/useContrastColor.ts +1 -2
- package/hooks/useFilePicker.tsx +7 -17
- package/hooks/useHandleNumberFormat.tsx +2 -2
- package/hooks/useMediaQuery.tsx +1 -2
- package/package.json +95 -111
- package/shortcuts-manager/ShortcutsManager/ShortcutsManager.tsx +6 -3
- package/shortcuts-manager/ShortcutsManager/utils.tsx +1 -1
- package/shortcuts-manager/useSetScopes/useSetScopes.tsx +1 -1
- package/shortcuts-manager/useShortcut/useShortcut.tsx +1 -1
- package/styles/shadow.ts +2 -1
- package/styles/themes/LightTheme.tsx +1 -1
- package/utils/DocumentPicker/documentPicker.ts +78 -27
- package/utils/DocumentPicker/types.ts +0 -1
- package/utils/extractSubcomponents.ts +89 -0
- package/utils/extractTextStyles.ts +1 -2
- package/utils/formatNumberWithMask/formatNumberWithMask.ts +2 -1
- package/utils/index.ts +0 -3
- package/utils/normalizeToNumberString/normalizeToNumberString.ts +1 -1
- package/components/DatePickerDocked/DatePickerDocked.tsx +0 -30
- package/components/DatePickerDocked/DatePickerDockedHeader.tsx +0 -129
- package/components/DatePickerDocked/index.tsx +0 -17
- package/components/DatePickerDocked/types.ts +0 -11
- package/components/DatePickerDocked/utils.ts +0 -157
- package/components/DatePickerInline/DatePickerContext.tsx +0 -21
- package/components/DatePickerInput/DatePickerInput.tsx +0 -139
- package/components/DatePickerInput/DatePickerInputModal.tsx +0 -48
- package/components/DatePickerInput/DatePickerInputWithoutModal.tsx +0 -77
- package/components/DatePickerInput/DateRangeInput.tsx +0 -88
- package/components/DatePickerInput/index.tsx +0 -10
- package/components/DatePickerInput/types.ts +0 -28
- package/components/DatePickerInput/utils.ts +0 -15
- package/components/DatePickerModal/AnimatedCrossView.tsx +0 -94
- package/components/DatePickerModal/CalendarEdit.tsx +0 -139
- package/components/DatePickerModal/DatePickerModal.tsx +0 -85
- package/components/DatePickerModal/DatePickerModalContent.tsx +0 -155
- package/components/DatePickerModal/DatePickerModalContentHeader.tsx +0 -213
- package/components/DatePickerModal/DatePickerModalHeader.tsx +0 -74
- package/components/DatePickerModal/DatePickerModalHeaderBackground.tsx +0 -13
- package/components/DatePickerModal/index.tsx +0 -16
- package/components/DatePickerModal/types.ts +0 -92
- package/components/DatePickerModal/utils.ts +0 -122
- package/components/DateTimePicker/DateTimePicker.tsx +0 -172
- package/components/DateTimePicker/index.tsx +0 -10
- package/components/DateTimePicker/utils.ts +0 -12
- package/components/HorizontalDivider/HorizontalDivider.tsx +0 -103
- package/components/HorizontalDivider/index.tsx +0 -9
- package/components/ListItem/ListItem.tsx +0 -136
- package/components/ListItem/ListItemDescription.tsx +0 -25
- package/components/ListItem/ListItemTitle.tsx +0 -25
- package/components/ListItem/index.tsx +0 -14
- package/components/ListItem/utils.ts +0 -115
- package/components/Menu/MenuDivider.tsx +0 -13
- package/components/Menu/MenuItem.tsx +0 -128
- package/components/Popover/Popover.native.tsx +0 -185
- package/components/RadioButton/RadioButton.tsx +0 -138
- package/components/RadioButton/RadioButtonAndroid.tsx +0 -188
- package/components/RadioButton/RadioButtonGroup.tsx +0 -98
- package/components/RadioButton/RadioButtonIOS.tsx +0 -106
- package/components/RadioButton/RadioButtonItem.tsx +0 -232
- package/components/RadioButton/index.ts +0 -22
- package/components/RadioButton/utils.ts +0 -165
- package/components/TimePickerField/TimePickerField.tsx +0 -152
- package/components/TimePickerField/index.tsx +0 -10
- package/components/TimePickerField/utils.ts +0 -94
- package/components/TimePickerModal/TimePickerModal.tsx +0 -115
- package/components/TimePickerModal/index.tsx +0 -10
- package/components/TimePickerModal/utils.ts +0 -47
- package/components/VerticalDivider/VerticalDivider.tsx +0 -100
- package/components/VerticalDivider/index.tsx +0 -9
- package/context-bridge/index.tsx +0 -87
- package/fast-context/index.tsx +0 -190
- package/hocs/typedMemo.tsx +0 -5
- package/hooks/useControlledValue.tsx +0 -68
- package/hooks/useLatest.tsx +0 -9
- package/hooks/useMergedRefs.ts +0 -14
- package/hooks/usePrevious.ts +0 -13
- package/hooks/useSearchable.tsx +0 -74
- package/hooks/useSubcomponents.tsx +0 -59
- package/hooks/useToggle.tsx +0 -24
- package/utils/color.ts +0 -22
- package/utils/compare/index.ts +0 -54
- package/utils/lodash.ts +0 -49
- package/utils/repository.ts +0 -53
|
@@ -1,14 +1,18 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { noop } from '@react-native-molecules/utils/helpers/lodash';
|
|
2
|
+
import { forwardRef, memo, type ReactNode, useCallback, useRef } from 'react';
|
|
2
3
|
import {
|
|
3
4
|
type GestureResponderEvent,
|
|
5
|
+
Platform,
|
|
4
6
|
Pressable,
|
|
5
7
|
type PressableProps,
|
|
6
8
|
type StyleProp,
|
|
7
|
-
View,
|
|
8
9
|
type ViewStyle,
|
|
9
10
|
} from 'react-native';
|
|
10
11
|
import { StyleSheet } from 'react-native-unistyles';
|
|
11
12
|
|
|
13
|
+
import { useTheme } from '../../hooks/useTheme';
|
|
14
|
+
import { Slot } from '../Slot';
|
|
15
|
+
import { rippleColorFromBackground } from './rippleFromForegroundColor';
|
|
12
16
|
import { touchableRippleStyles } from './utils';
|
|
13
17
|
|
|
14
18
|
export type Props = PressableProps & {
|
|
@@ -45,11 +49,38 @@ export type Props = PressableProps & {
|
|
|
45
49
|
* Color of the underlay for the highlight effect (Android < 5.0 and iOS).
|
|
46
50
|
*/
|
|
47
51
|
underlayColor?: string;
|
|
52
|
+
/**
|
|
53
|
+
* Alpha used for auto-derived ripple color when `rippleColor` is not provided.
|
|
54
|
+
* @default 0.24
|
|
55
|
+
*/
|
|
56
|
+
rippleAlpha?: number;
|
|
48
57
|
/**
|
|
49
58
|
* Content of the `TouchableRipple`.
|
|
50
59
|
*/
|
|
51
60
|
children: ReactNode;
|
|
52
61
|
style?: StyleProp<ViewStyle>;
|
|
62
|
+
/**
|
|
63
|
+
* When `true`, the component will not render a wrapper element. Instead, it will
|
|
64
|
+
* merge its props (styles, event handlers, ref) onto its immediate child element.
|
|
65
|
+
* This follows the Radix UI "Slot" pattern for flexible component composition.
|
|
66
|
+
*
|
|
67
|
+
* @example
|
|
68
|
+
* ```tsx
|
|
69
|
+
* // Without asChild - renders a Pressable wrapper
|
|
70
|
+
* <TouchableRipple onPress={handlePress}>
|
|
71
|
+
* <View><Text>Click me</Text></View>
|
|
72
|
+
* </TouchableRipple>
|
|
73
|
+
*
|
|
74
|
+
* // With asChild - merges props onto the child
|
|
75
|
+
* <TouchableRipple asChild onPress={handlePress}>
|
|
76
|
+
* <Link href="/page"><Text>Navigate</Text></Link>
|
|
77
|
+
* </TouchableRipple>
|
|
78
|
+
* ```
|
|
79
|
+
*
|
|
80
|
+
* @note When `asChild` is `true`, only a single child element is allowed.
|
|
81
|
+
* @default false
|
|
82
|
+
*/
|
|
83
|
+
asChild?: boolean;
|
|
53
84
|
};
|
|
54
85
|
|
|
55
86
|
/**
|
|
@@ -91,73 +122,70 @@ const TouchableRipple = (
|
|
|
91
122
|
disabled: disabledProp,
|
|
92
123
|
rippleColor: rippleColorProp,
|
|
93
124
|
underlayColor: _underlayColor,
|
|
94
|
-
|
|
125
|
+
rippleAlpha = 0.24,
|
|
126
|
+
onPress = noop,
|
|
95
127
|
children,
|
|
96
128
|
onPressIn: onPressInProp,
|
|
97
129
|
onPressOut: onPressOutProp,
|
|
98
130
|
centered,
|
|
131
|
+
asChild = false,
|
|
99
132
|
...rest
|
|
100
133
|
}: Props,
|
|
101
134
|
ref: any,
|
|
102
135
|
) => {
|
|
103
136
|
// TODO - enable ripple onLongPress, need to check for mobile as well
|
|
104
|
-
const disabled = disabledProp
|
|
137
|
+
const disabled = disabledProp;
|
|
138
|
+
const theme = useTheme();
|
|
105
139
|
|
|
106
140
|
const componentStyles = touchableRippleStyles;
|
|
107
141
|
|
|
108
|
-
const { rippleColor
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
}
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
const
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
touchY = touch.locationY ?? e.pageY;
|
|
147
|
-
}
|
|
142
|
+
const { rippleColor: themeRippleFallback } = componentStyles.root;
|
|
143
|
+
|
|
144
|
+
const tokenResolvedColor =
|
|
145
|
+
typeof rippleColorProp === 'string'
|
|
146
|
+
? theme.colors[rippleColorProp as keyof typeof theme.colors]
|
|
147
|
+
: undefined;
|
|
148
|
+
|
|
149
|
+
const rippleColorResolvedProp =
|
|
150
|
+
typeof tokenResolvedColor === 'string' ? tokenResolvedColor : rippleColorProp;
|
|
151
|
+
const containerStyle = [
|
|
152
|
+
styles.touchable,
|
|
153
|
+
{ borderRadius: 'inherit' },
|
|
154
|
+
borderless && styles.borderless,
|
|
155
|
+
// ...(Platform.OS === 'web' && !disabled ? ({ cursor: 'pointer' } as any) : {}),
|
|
156
|
+
componentStyles.root,
|
|
157
|
+
style,
|
|
158
|
+
];
|
|
159
|
+
|
|
160
|
+
// The active ripple is tracked so onPressOut can fade it. Driving the lifecycle
|
|
161
|
+
// off Pressable's press events (instead of raw pointer events) means a nested
|
|
162
|
+
// element that captures the gesture won't trigger an orphan ripple — Pressable
|
|
163
|
+
// only fires onPressIn when its own press is being handled.
|
|
164
|
+
const activeRippleRef = useRef<HTMLElement | null>(null);
|
|
165
|
+
|
|
166
|
+
const startRipple = useCallback(
|
|
167
|
+
(host: HTMLElement, x: number, y: number) => {
|
|
168
|
+
const computedStyle = window.getComputedStyle(host);
|
|
169
|
+
const dimensions = host.getBoundingClientRect();
|
|
170
|
+
|
|
171
|
+
const resolvedRippleColor =
|
|
172
|
+
rippleColorResolvedProp ??
|
|
173
|
+
(Platform.OS === 'web'
|
|
174
|
+
? rippleColorFromBackground(
|
|
175
|
+
computedStyle.backgroundColor,
|
|
176
|
+
String(themeRippleFallback),
|
|
177
|
+
rippleAlpha,
|
|
178
|
+
)
|
|
179
|
+
: String(themeRippleFallback));
|
|
148
180
|
|
|
149
|
-
// Get the size of the button to determine how big the ripple should be
|
|
150
181
|
const size = centered
|
|
151
|
-
?
|
|
152
|
-
|
|
153
|
-
: // Otherwise make it twice as big so clicking on one end spreads ripple to other
|
|
154
|
-
Math.max(dimensions.width, dimensions.height) * 2;
|
|
182
|
+
? Math.min(dimensions.width, dimensions.height) * 1.25
|
|
183
|
+
: Math.max(dimensions.width, dimensions.height) * 2;
|
|
155
184
|
|
|
156
|
-
|
|
157
|
-
const container = document.createElement('span');
|
|
158
|
-
|
|
159
|
-
container.setAttribute('data-paper-ripple', '');
|
|
185
|
+
const expandDuration = Math.min(size * 1.5, 350);
|
|
160
186
|
|
|
187
|
+
const container = document.createElement('span');
|
|
188
|
+
container.setAttribute('data-molecules-ripple', '');
|
|
161
189
|
Object.assign(container.style, {
|
|
162
190
|
position: 'absolute',
|
|
163
191
|
pointerEvents: 'none',
|
|
@@ -172,39 +200,28 @@ const TouchableRipple = (
|
|
|
172
200
|
overflow: centered ? 'visible' : 'hidden',
|
|
173
201
|
});
|
|
174
202
|
|
|
175
|
-
// Create span to show the ripple effect
|
|
176
203
|
const ripple = document.createElement('span');
|
|
177
|
-
|
|
178
204
|
Object.assign(ripple.style, {
|
|
179
205
|
position: 'absolute',
|
|
180
206
|
pointerEvents: 'none',
|
|
181
|
-
backgroundColor:
|
|
207
|
+
backgroundColor: resolvedRippleColor,
|
|
182
208
|
borderRadius: '50%',
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
transitionProperty: 'transform opacity',
|
|
186
|
-
transitionDuration: `${Math.min(size * 1.5, 350)}ms`,
|
|
209
|
+
transitionProperty: 'transform, opacity',
|
|
210
|
+
transitionDuration: `${expandDuration}ms`,
|
|
187
211
|
transitionTimingFunction: 'linear',
|
|
188
212
|
transformOrigin: 'center',
|
|
189
|
-
|
|
190
|
-
/* We'll animate these properties */
|
|
191
213
|
transform: 'translate3d(-50%, -50%, 0) scale3d(0.1, 0.1, 0.1)',
|
|
192
214
|
opacity: '0.5',
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
left: `${touchX}px`,
|
|
196
|
-
top: `${touchY}px`,
|
|
215
|
+
left: `${x}px`,
|
|
216
|
+
top: `${y}px`,
|
|
197
217
|
width: `${size}px`,
|
|
198
218
|
height: `${size}px`,
|
|
199
219
|
});
|
|
200
220
|
|
|
201
|
-
// Finally, append it to DOM
|
|
202
221
|
container.appendChild(ripple);
|
|
203
|
-
|
|
222
|
+
host.appendChild(container);
|
|
223
|
+
activeRippleRef.current = container;
|
|
204
224
|
|
|
205
|
-
// rAF runs in the same frame as the event handler
|
|
206
|
-
// Use double rAF to ensure the transition class is added in next frame
|
|
207
|
-
// This will make sure that the transition animation is triggered
|
|
208
225
|
requestAnimationFrame(() => {
|
|
209
226
|
requestAnimationFrame(() => {
|
|
210
227
|
Object.assign(ripple.style, {
|
|
@@ -214,49 +231,80 @@ const TouchableRipple = (
|
|
|
214
231
|
});
|
|
215
232
|
});
|
|
216
233
|
},
|
|
217
|
-
[
|
|
234
|
+
[centered, rippleColorResolvedProp, themeRippleFallback, rippleAlpha],
|
|
218
235
|
);
|
|
219
236
|
|
|
220
|
-
const
|
|
221
|
-
(
|
|
222
|
-
|
|
223
|
-
|
|
224
|
-
|
|
237
|
+
const fadeRipple = useCallback((container: HTMLElement | null) => {
|
|
238
|
+
if (!container) return;
|
|
239
|
+
const ripple = container.firstChild as HTMLElement | null;
|
|
240
|
+
if (!ripple) {
|
|
241
|
+
container.parentNode?.removeChild(container);
|
|
242
|
+
return;
|
|
243
|
+
}
|
|
244
|
+
|
|
245
|
+
const onTransitionEnd = (ev: TransitionEvent) => {
|
|
246
|
+
if (ev.propertyName !== 'opacity') return;
|
|
247
|
+
ripple.removeEventListener('transitionend', onTransitionEnd);
|
|
248
|
+
container.parentNode?.removeChild(container);
|
|
249
|
+
};
|
|
250
|
+
ripple.addEventListener('transitionend', onTransitionEnd);
|
|
225
251
|
|
|
226
|
-
|
|
227
|
-
|
|
228
|
-
|
|
252
|
+
Object.assign(ripple.style, {
|
|
253
|
+
transitionDuration: '250ms',
|
|
254
|
+
opacity: '0',
|
|
255
|
+
});
|
|
256
|
+
}, []);
|
|
229
257
|
|
|
230
|
-
|
|
231
|
-
|
|
232
|
-
|
|
233
|
-
|
|
258
|
+
const handlePressIn = useCallback(
|
|
259
|
+
(e: GestureResponderEvent) => {
|
|
260
|
+
onPressInProp?.(e);
|
|
261
|
+
if (disabled) return;
|
|
234
262
|
|
|
235
|
-
|
|
236
|
-
|
|
237
|
-
|
|
238
|
-
|
|
263
|
+
const host = e.currentTarget as unknown as HTMLElement | null;
|
|
264
|
+
if (!host || typeof host.appendChild !== 'function') return;
|
|
265
|
+
|
|
266
|
+
const rect = host.getBoundingClientRect();
|
|
267
|
+
let x = rect.width / 2;
|
|
268
|
+
let y = rect.height / 2;
|
|
269
|
+
|
|
270
|
+
if (!centered) {
|
|
271
|
+
const ne: any = e.nativeEvent;
|
|
272
|
+
if (ne) {
|
|
273
|
+
if (typeof ne.locationX === 'number' && typeof ne.locationY === 'number') {
|
|
274
|
+
x = ne.locationX;
|
|
275
|
+
y = ne.locationY;
|
|
276
|
+
} else if (typeof ne.clientX === 'number' && typeof ne.clientY === 'number') {
|
|
277
|
+
x = ne.clientX - rect.left;
|
|
278
|
+
y = ne.clientY - rect.top;
|
|
279
|
+
}
|
|
280
|
+
}
|
|
281
|
+
}
|
|
239
282
|
|
|
240
|
-
|
|
241
|
-
|
|
242
|
-
|
|
283
|
+
startRipple(host, x, y);
|
|
284
|
+
},
|
|
285
|
+
[onPressInProp, disabled, centered, startRipple],
|
|
286
|
+
);
|
|
243
287
|
|
|
244
|
-
|
|
245
|
-
|
|
246
|
-
|
|
247
|
-
|
|
248
|
-
|
|
249
|
-
|
|
250
|
-
});
|
|
288
|
+
const handlePressOut = useCallback(
|
|
289
|
+
(e: GestureResponderEvent) => {
|
|
290
|
+
onPressOutProp?.(e);
|
|
291
|
+
const container = activeRippleRef.current;
|
|
292
|
+
activeRippleRef.current = null;
|
|
293
|
+
fadeRipple(container);
|
|
251
294
|
},
|
|
252
|
-
[onPressOutProp,
|
|
295
|
+
[onPressOutProp, fadeRipple],
|
|
253
296
|
);
|
|
254
297
|
|
|
255
|
-
const Component =
|
|
298
|
+
const Component = asChild ? Slot : Pressable;
|
|
299
|
+
|
|
300
|
+
const accessibilityRoleProp = (rest as { accessibilityRole?: unknown }).accessibilityRole;
|
|
301
|
+
const roleProp = (rest as { role?: unknown }).role;
|
|
302
|
+
const applyDefaultWebButtonRole =
|
|
303
|
+
!!onPress && accessibilityRoleProp === undefined && roleProp === undefined;
|
|
256
304
|
|
|
257
305
|
return (
|
|
258
306
|
<Component
|
|
259
|
-
{...(
|
|
307
|
+
{...(applyDefaultWebButtonRole ? { role: 'button' } : {})}
|
|
260
308
|
{...rest}
|
|
261
309
|
style={containerStyle}
|
|
262
310
|
ref={ref}
|
|
@@ -264,7 +312,7 @@ const TouchableRipple = (
|
|
|
264
312
|
onPressIn={handlePressIn}
|
|
265
313
|
onPressOut={handlePressOut}
|
|
266
314
|
disabled={disabled}>
|
|
267
|
-
{
|
|
315
|
+
{children}
|
|
268
316
|
</Component>
|
|
269
317
|
);
|
|
270
318
|
};
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
import setColor from 'color';
|
|
2
|
+
|
|
3
|
+
/** Ripple ink derived from background color for better contrast. */
|
|
4
|
+
export function rippleColorFromBackground(
|
|
5
|
+
backgroundColor: string | undefined,
|
|
6
|
+
fallback: string,
|
|
7
|
+
alpha: number = 0.24,
|
|
8
|
+
): string {
|
|
9
|
+
if (!backgroundColor || backgroundColor === '') {
|
|
10
|
+
return fallback;
|
|
11
|
+
}
|
|
12
|
+
try {
|
|
13
|
+
const base = setColor(backgroundColor);
|
|
14
|
+
if (base.alpha() < 0.05) {
|
|
15
|
+
return fallback;
|
|
16
|
+
}
|
|
17
|
+
return base.isLight() ? `rgba(0, 0, 0, ${alpha})` : `rgba(255, 255, 255, ${alpha})`;
|
|
18
|
+
} catch {
|
|
19
|
+
return fallback;
|
|
20
|
+
}
|
|
21
|
+
}
|
package/hocs/index.tsx
CHANGED
|
@@ -1,3 +1,5 @@
|
|
|
1
|
+
import { createFastContext } from '@react-native-molecules/utils/fast-context';
|
|
2
|
+
import { useLatest } from '@react-native-molecules/utils/hooks';
|
|
1
3
|
import {
|
|
2
4
|
type ComponentType,
|
|
3
5
|
forwardRef,
|
|
@@ -15,9 +17,6 @@ import type { FlatList } from 'react-native';
|
|
|
15
17
|
import type { SectionList } from 'react-native';
|
|
16
18
|
import { Platform } from 'react-native';
|
|
17
19
|
|
|
18
|
-
import { createFastContext } from '../fast-context';
|
|
19
|
-
import useLatest from '../hooks/useLatest';
|
|
20
|
-
|
|
21
20
|
export type Store = {
|
|
22
21
|
currentIndex: number | null;
|
|
23
22
|
};
|
package/hocs/withPortal.tsx
CHANGED
package/hooks/index.tsx
CHANGED
|
@@ -4,7 +4,6 @@ export * from './useActionState';
|
|
|
4
4
|
export * from './useActive';
|
|
5
5
|
export { default as useColorMode } from './useColorMode';
|
|
6
6
|
export { useContrastColor } from './useContrastColor';
|
|
7
|
-
export { default as useControlledValue } from './useControlledValue';
|
|
8
7
|
export * from './useFocus';
|
|
9
8
|
export {
|
|
10
9
|
type NumberMaskConfig,
|
|
@@ -13,16 +12,7 @@ export {
|
|
|
13
12
|
} from './useHandleNumberFormat';
|
|
14
13
|
export * from './useHover';
|
|
15
14
|
export * from './useKeyboardDismissable';
|
|
16
|
-
export
|
|
17
|
-
export { useMediaQuery } from './useMediaQuery';
|
|
18
|
-
export { useMergedRefs } from './useMergedRefs';
|
|
19
|
-
export { default as usePrevious } from './usePrevious';
|
|
15
|
+
export * from './useMediaQuery';
|
|
20
16
|
export * from './useQueryFilter';
|
|
21
|
-
export {
|
|
22
|
-
default as useSearchable,
|
|
23
|
-
type UseSearchableProps,
|
|
24
|
-
useSearchInputProps,
|
|
25
|
-
} from './useSearchable';
|
|
26
|
-
export { default as useSubcomponents, type UseSubcomponentsProps } from './useSubcomponents';
|
|
27
17
|
export * from './useTheme';
|
|
28
|
-
export
|
|
18
|
+
export * from '@react-native-molecules/utils/hooks';
|
package/hooks/useActionState.tsx
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { type RefObject, useRef } from 'react';
|
|
1
|
+
import { type RefObject, useCallback, useRef } from 'react';
|
|
2
2
|
|
|
3
3
|
import { useActive } from './useActive';
|
|
4
4
|
import { useFocus } from './useFocus';
|
|
@@ -14,16 +14,27 @@ export type UseActionStateProps = {
|
|
|
14
14
|
export const useActionState = (
|
|
15
15
|
props: UseActionStateProps & { ref?: RefObject<any> | React.ForwardedRef<any> } = {},
|
|
16
16
|
) => {
|
|
17
|
-
const
|
|
18
|
-
const
|
|
19
|
-
|
|
20
|
-
|
|
17
|
+
const internalRef = useRef(null);
|
|
18
|
+
const externalRef = props.ref;
|
|
19
|
+
|
|
20
|
+
const actionsRef = useCallback(
|
|
21
|
+
(node: any) => {
|
|
22
|
+
internalRef.current = node;
|
|
23
|
+
if (typeof externalRef === 'function') {
|
|
24
|
+
externalRef(node);
|
|
25
|
+
} else if (externalRef) {
|
|
26
|
+
(externalRef as RefObject<any>).current = node;
|
|
27
|
+
}
|
|
28
|
+
},
|
|
29
|
+
[externalRef],
|
|
30
|
+
) as unknown as RefObject<any>;
|
|
31
|
+
|
|
21
32
|
const hovered =
|
|
22
|
-
useHover(
|
|
33
|
+
useHover(internalRef, props.actionsToListen?.includes('hover')) || !!props.hovered;
|
|
23
34
|
const pressed =
|
|
24
|
-
useActive(
|
|
35
|
+
useActive(internalRef, props.actionsToListen?.includes('press')) || !!props.pressed;
|
|
25
36
|
const focused =
|
|
26
|
-
useFocus(
|
|
37
|
+
useFocus(internalRef, props.actionsToListen?.includes('focus')) || !!props.focused;
|
|
27
38
|
|
|
28
39
|
return {
|
|
29
40
|
actionsRef,
|
|
@@ -1,8 +1,7 @@
|
|
|
1
|
+
import { resolveContrastColor } from '@react-native-molecules/utils/helpers/resolveContrastColor';
|
|
1
2
|
import { useMemo } from 'react';
|
|
2
3
|
import { useUnistyles } from 'react-native-unistyles';
|
|
3
4
|
|
|
4
|
-
import { resolveContrastColor } from '../utils/color';
|
|
5
|
-
|
|
6
5
|
export const useContrastColor = (bgColor: string, lightColor?: string, darkColor?: string) => {
|
|
7
6
|
const isDarkMode = useUnistyles().theme.dark;
|
|
8
7
|
|
package/hooks/useFilePicker.tsx
CHANGED
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import { isNil, omitBy } from '@react-native-molecules/utils/helpers/lodash';
|
|
1
2
|
import { useCallback } from 'react';
|
|
2
3
|
|
|
3
4
|
import {
|
|
@@ -5,17 +6,12 @@ import {
|
|
|
5
6
|
type DocumentPickerOptions,
|
|
6
7
|
type DocumentResult,
|
|
7
8
|
} from '../utils/DocumentPicker';
|
|
8
|
-
import { isNil, omitBy } from '../utils/lodash';
|
|
9
9
|
|
|
10
|
-
export const useFilePicker = ({
|
|
11
|
-
multiple,
|
|
12
|
-
onCancel,
|
|
13
|
-
onError,
|
|
14
|
-
...options
|
|
15
|
-
}: DocumentPickerOptions) => {
|
|
10
|
+
export const useFilePicker = (options: DocumentPickerOptions) => {
|
|
16
11
|
const openFilePicker = useCallback(
|
|
17
|
-
async (callback: (response: DocumentResult
|
|
18
|
-
const
|
|
12
|
+
async (callback: (response: DocumentResult[]) => void) => {
|
|
13
|
+
const { multiple, ...rest } = options;
|
|
14
|
+
const omittedOptions = omitBy(rest, isNil);
|
|
19
15
|
|
|
20
16
|
try {
|
|
21
17
|
let response;
|
|
@@ -30,16 +26,10 @@ export const useFilePicker = ({
|
|
|
30
26
|
} catch (e: any) {
|
|
31
27
|
// eslint-disable-next-line no-console
|
|
32
28
|
console.log('FilePicker Error', e, e?.code);
|
|
33
|
-
|
|
34
|
-
if (e?.code === 'DOCUMENT_PICKER_CANCELED.') {
|
|
35
|
-
onCancel?.();
|
|
36
|
-
return;
|
|
37
|
-
}
|
|
38
|
-
// It might result in an error.
|
|
39
|
-
onError?.(e);
|
|
29
|
+
// Error and cancel callbacks are handled by DocumentPicker itself
|
|
40
30
|
}
|
|
41
31
|
},
|
|
42
|
-
[
|
|
32
|
+
[options],
|
|
43
33
|
);
|
|
44
34
|
|
|
45
35
|
return { openFilePicker };
|
|
@@ -1,9 +1,9 @@
|
|
|
1
|
+
import { isNil } from '@react-native-molecules/utils/helpers/lodash';
|
|
2
|
+
import { usePrevious } from '@react-native-molecules/utils/hooks';
|
|
1
3
|
import { useCallback, useEffect, useMemo, useRef, useState } from 'react';
|
|
2
4
|
import type { NativeSyntheticEvent, TextInputFocusEventData } from 'react-native';
|
|
3
5
|
|
|
4
6
|
import { formatNumberWithMask, normalizeToNumberString } from '../utils';
|
|
5
|
-
import { isNil } from '../utils/lodash';
|
|
6
|
-
import usePrevious from './usePrevious';
|
|
7
7
|
|
|
8
8
|
export type NumberMaskConfig = {
|
|
9
9
|
prefix?: string;
|
package/hooks/useMediaQuery.tsx
CHANGED
|
@@ -1,8 +1,7 @@
|
|
|
1
|
+
import { isNil } from '@react-native-molecules/utils/helpers/lodash';
|
|
1
2
|
import { useMemo } from 'react';
|
|
2
3
|
import { useWindowDimensions } from 'react-native';
|
|
3
4
|
|
|
4
|
-
import { isNil } from '../utils/lodash';
|
|
5
|
-
|
|
6
5
|
type Query = {
|
|
7
6
|
maxWidth?: number;
|
|
8
7
|
minWidth?: number;
|