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.
- package/README.md +1 -1
- 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 +209 -264
- package/components/Button/index.tsx +9 -3
- package/components/Button/types.ts +16 -2
- package/components/Button/utils.ts +230 -208
- package/components/Checkbox/CheckboxBase.ios.tsx +10 -14
- package/components/Checkbox/CheckboxBase.tsx +14 -121
- package/components/Checkbox/utils.ts +0 -25
- package/components/Chip/Chip.tsx +40 -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} +17 -49
- package/components/DatePicker/DateCalendar.tsx +83 -0
- package/components/DatePicker/DatePickerActions.tsx +73 -0
- package/components/DatePicker/DatePickerModal.tsx +245 -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 +293 -0
- package/components/DatePickerInline/DatePickerContext.tsx +1 -0
- package/components/DatePickerInline/DatePickerDockedHeader.tsx +117 -0
- package/components/DatePickerInline/DatePickerInline.tsx +16 -15
- package/components/DatePickerInline/DatePickerInlineBase.tsx +8 -2
- package/components/DatePickerInline/DatePickerInlineHeader.tsx +8 -4
- 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 +42 -27
- package/components/DatePickerInline/Month.tsx +48 -67
- package/components/DatePickerInline/MonthPicker.tsx +38 -44
- package/components/DatePickerInline/Swiper.native.tsx +21 -4
- package/components/DatePickerInline/Swiper.tsx +168 -13
- package/components/DatePickerInline/Week.tsx +6 -1
- package/components/DatePickerInline/YearPicker.tsx +206 -53
- package/components/DatePickerInline/dateUtils.tsx +17 -12
- package/components/DatePickerInline/types.ts +6 -2
- package/components/DatePickerInline/utils.ts +66 -29
- package/components/Drawer/Drawer.tsx +17 -6
- package/components/ElementGroup/ElementGroup.tsx +16 -14
- 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 +3 -3
- package/components/Icon/index.tsx +1 -1
- package/components/Icon/types.ts +17 -6
- package/components/IconButton/IconButton.tsx +42 -57
- package/components/IconButton/utils.ts +142 -33
- package/components/ListItem/ListItem.tsx +3 -1
- package/components/ListItem/utils.ts +1 -1
- 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 +3 -18
- package/components/NavigationRail/NavigationRail.tsx +15 -9
- package/components/Popover/Popover.tsx +122 -145
- package/components/Popover/PopoverRoot.tsx +74 -0
- package/components/Popover/common.ts +50 -34
- package/components/Popover/index.ts +18 -1
- package/components/Popover/usePlatformMeasure.native.ts +90 -0
- package/components/Popover/usePlatformMeasure.ts +118 -0
- package/components/Popover/utils.ts +34 -0
- package/components/Select/Select.tsx +368 -507
- package/components/Select/context.tsx +72 -0
- package/components/Select/index.ts +8 -14
- package/components/Select/types.ts +2 -4
- package/components/Select/utils.ts +144 -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 +34 -8
- package/components/Surface/Surface.ios.tsx +36 -29
- package/components/Surface/Surface.tsx +31 -4
- package/components/Surface/utils.ts +44 -30
- package/components/Switch/Switch.tsx +8 -2
- package/components/Tabs/TabItem.tsx +35 -58
- package/components/Tabs/TabLabel.tsx +5 -9
- package/components/Tabs/Tabs.tsx +154 -148
- package/components/Tabs/utils.ts +15 -2
- package/components/TextInput/TextInput.tsx +658 -575
- package/components/TextInput/index.tsx +19 -3
- package/components/TextInput/types.ts +76 -27
- package/components/TextInput/utils.ts +225 -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/TimeInput.tsx +87 -37
- package/components/TimePicker/TimeInputs.tsx +137 -49
- package/components/TimePicker/TimePicker.tsx +73 -10
- 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 -0
- 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 +50 -14
- package/components/TouchableRipple/TouchableRipple.tsx +137 -47
- package/hocs/withPortal.tsx +1 -1
- package/hooks/index.tsx +0 -6
- package/hooks/useActionState.tsx +19 -8
- package/hooks/useControlledValue.tsx +20 -4
- package/hooks/useFilePicker.tsx +6 -16
- package/hooks/useWhatHasUpdated.tsx +48 -0
- package/package.json +17 -13
- package/shortcuts-manager/ShortcutsManager/ShortcutsManager.tsx +5 -2
- 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/extractPropertiesFromStyles.ts +25 -0
- package/utils/extractSubcomponents.ts +89 -0
- package/utils/lodash.ts +77 -5
- 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/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/Popover/Popover.native.tsx +0 -185
- 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/hooks/useSearchable.tsx +0 -74
- package/hooks/useSubcomponents.tsx +0 -59
|
@@ -41,6 +41,9 @@ const timePickerStylesDefault = StyleSheet.create(theme => ({
|
|
|
41
41
|
|
|
42
42
|
const timePickerInputsStylesDefault = StyleSheet.create(theme => ({
|
|
43
43
|
spaceBetweenInputsAndSwitcher: { width: 12 },
|
|
44
|
+
wrapper: {
|
|
45
|
+
alignItems: 'center',
|
|
46
|
+
},
|
|
44
47
|
inputContainer: {
|
|
45
48
|
flexDirection: 'row',
|
|
46
49
|
alignItems: 'center',
|
|
@@ -70,6 +73,27 @@ const timePickerInputsStylesDefault = StyleSheet.create(theme => ({
|
|
|
70
73
|
betweenDot: {
|
|
71
74
|
height: 12,
|
|
72
75
|
},
|
|
76
|
+
supportingRow: {
|
|
77
|
+
flexDirection: 'row',
|
|
78
|
+
alignItems: 'flex-start',
|
|
79
|
+
width: '100%',
|
|
80
|
+
marginTop: 2,
|
|
81
|
+
},
|
|
82
|
+
supportingSlot: {
|
|
83
|
+
width: 96,
|
|
84
|
+
minHeight: theme.typescale.bodyMedium.lineHeight * 2,
|
|
85
|
+
},
|
|
86
|
+
supportingText: {
|
|
87
|
+
...theme.typescale.bodyMedium,
|
|
88
|
+
fontSize: 12,
|
|
89
|
+
lineHeight: 16,
|
|
90
|
+
color: theme.colors.onSurfaceVariant,
|
|
91
|
+
textAlign: 'left',
|
|
92
|
+
paddingHorizontal: theme.spacings['1'],
|
|
93
|
+
},
|
|
94
|
+
supportingTextError: {
|
|
95
|
+
color: theme.colors.error,
|
|
96
|
+
},
|
|
73
97
|
}));
|
|
74
98
|
|
|
75
99
|
const timePickerInputStylesDefault = StyleSheet.create(theme => ({
|
|
@@ -91,6 +115,10 @@ const timePickerInputStylesDefault = StyleSheet.create(theme => ({
|
|
|
91
115
|
color: theme.colors.onSurface,
|
|
92
116
|
borderRadius: theme.shapes.corner.small,
|
|
93
117
|
|
|
118
|
+
_web: {
|
|
119
|
+
outline: 'none',
|
|
120
|
+
},
|
|
121
|
+
|
|
94
122
|
variants: {
|
|
95
123
|
state: {
|
|
96
124
|
highlighted: {
|
|
@@ -100,6 +128,20 @@ const timePickerInputStylesDefault = StyleSheet.create(theme => ({
|
|
|
100
128
|
},
|
|
101
129
|
},
|
|
102
130
|
},
|
|
131
|
+
keyboardInput: {
|
|
132
|
+
borderWidth: 2,
|
|
133
|
+
borderColor: 'transparent',
|
|
134
|
+
},
|
|
135
|
+
keyboardInputHighlighted: {
|
|
136
|
+
borderColor: theme.colors.primary,
|
|
137
|
+
},
|
|
138
|
+
inputError: {
|
|
139
|
+
backgroundColor: theme.colors.errorContainer,
|
|
140
|
+
color: theme.colors.onErrorContainer,
|
|
141
|
+
},
|
|
142
|
+
keyboardInputError: {
|
|
143
|
+
borderColor: theme.colors.error,
|
|
144
|
+
},
|
|
103
145
|
button: {
|
|
104
146
|
overflow: 'hidden',
|
|
105
147
|
borderRadius: theme.shapes.corner.small,
|
|
@@ -218,6 +260,53 @@ const timePickerClockMinutesStylesDefault = StyleSheet.create(theme => ({
|
|
|
218
260
|
textWhite: { color: '#fff' },
|
|
219
261
|
}));
|
|
220
262
|
|
|
263
|
+
const timePickerModalStylesDefault = StyleSheet.create(theme => ({
|
|
264
|
+
keyboardView: {
|
|
265
|
+
justifyContent: 'center',
|
|
266
|
+
alignItems: 'center',
|
|
267
|
+
flex: 1,
|
|
268
|
+
},
|
|
269
|
+
modalContent: {
|
|
270
|
+
minWidth: 287,
|
|
271
|
+
width: undefined,
|
|
272
|
+
maxWidth: undefined,
|
|
273
|
+
flex: undefined,
|
|
274
|
+
borderRadius: theme.shapes.corner.extraLarge,
|
|
275
|
+
overflow: 'hidden',
|
|
276
|
+
},
|
|
277
|
+
frame: {
|
|
278
|
+
backgroundColor: theme.colors.surface,
|
|
279
|
+
},
|
|
280
|
+
labelContainer: {
|
|
281
|
+
minHeight: 56,
|
|
282
|
+
justifyContent: 'flex-end',
|
|
283
|
+
paddingLeft: theme.spacings['6'],
|
|
284
|
+
paddingRight: theme.spacings['6'],
|
|
285
|
+
paddingTop: theme.spacings['6'],
|
|
286
|
+
paddingBottom: theme.spacings['2'],
|
|
287
|
+
alignSelf: 'flex-start',
|
|
288
|
+
},
|
|
289
|
+
label: {
|
|
290
|
+
letterSpacing: 1,
|
|
291
|
+
fontSize: theme.typescale.labelLarge.fontSize,
|
|
292
|
+
color: theme.colors.onSurface,
|
|
293
|
+
fontWeight: theme.typescale.labelLarge.fontWeight,
|
|
294
|
+
},
|
|
295
|
+
timePickerContainer: {
|
|
296
|
+
padding: theme.spacings['6'],
|
|
297
|
+
paddingTop: theme.spacings['2'],
|
|
298
|
+
paddingBottom: 0,
|
|
299
|
+
},
|
|
300
|
+
footer: {
|
|
301
|
+
flexDirection: 'row',
|
|
302
|
+
alignItems: 'center',
|
|
303
|
+
padding: theme.spacings['2'],
|
|
304
|
+
width: '100%',
|
|
305
|
+
},
|
|
306
|
+
inputTypeToggle: { margin: theme.spacings['1'] },
|
|
307
|
+
fill: { flex: 1 },
|
|
308
|
+
}));
|
|
309
|
+
|
|
221
310
|
const timePickerAmPmSwitcherStylesDefault = StyleSheet.create(theme => ({
|
|
222
311
|
container: {
|
|
223
312
|
width: 50,
|
|
@@ -291,3 +380,7 @@ export const timePickerAmPmSwitcherStyles = getRegisteredComponentStylesWithFall
|
|
|
291
380
|
'TimePicker_AmPmSwitcher',
|
|
292
381
|
timePickerAmPmSwitcherStylesDefault,
|
|
293
382
|
);
|
|
383
|
+
export const timePickerModalStyles = getRegisteredComponentStylesWithFallback(
|
|
384
|
+
'TimePickerModal',
|
|
385
|
+
timePickerModalStylesDefault,
|
|
386
|
+
);
|
|
@@ -2,41 +2,63 @@ import {
|
|
|
2
2
|
createContext,
|
|
3
3
|
memo,
|
|
4
4
|
type ReactElement,
|
|
5
|
+
type RefObject,
|
|
5
6
|
useCallback,
|
|
6
7
|
useEffect,
|
|
7
8
|
useMemo,
|
|
8
9
|
useRef,
|
|
9
10
|
} from 'react';
|
|
10
|
-
import { Text, type ViewProps, type ViewStyle } from 'react-native';
|
|
11
11
|
|
|
12
|
-
import {
|
|
13
|
-
import {
|
|
14
|
-
import { tooltipStyles } from './utils';
|
|
12
|
+
import { useToggle } from '../../hooks';
|
|
13
|
+
import { extractSubcomponents } from '../../utils/extractSubcomponents';
|
|
15
14
|
|
|
16
|
-
export type Props =
|
|
15
|
+
export type Props = {
|
|
17
16
|
fadeInDelay?: number;
|
|
18
17
|
fadeOutDelay?: number;
|
|
19
|
-
showArrow?: boolean;
|
|
20
|
-
style?: ViewStyle;
|
|
21
|
-
children: ReactElement | ReactElement[];
|
|
22
18
|
hoverableContent?: boolean;
|
|
19
|
+
children: ReactElement | ReactElement[];
|
|
20
|
+
};
|
|
21
|
+
|
|
22
|
+
export type TooltipContextValue = {
|
|
23
|
+
isOpen: boolean;
|
|
24
|
+
triggerRef: RefObject<any>;
|
|
25
|
+
onOpen: () => void;
|
|
26
|
+
onClose: () => void;
|
|
27
|
+
onMouseEnter?: () => void;
|
|
28
|
+
onMouseLeave?: () => void;
|
|
23
29
|
};
|
|
24
30
|
|
|
31
|
+
export const TooltipContext = createContext<TooltipContextValue>({
|
|
32
|
+
isOpen: false,
|
|
33
|
+
onOpen: () => {},
|
|
34
|
+
onClose: () => {},
|
|
35
|
+
triggerRef: { current: null },
|
|
36
|
+
});
|
|
37
|
+
|
|
25
38
|
const Tooltip = ({
|
|
26
|
-
style,
|
|
27
39
|
children,
|
|
28
40
|
fadeInDelay = 100,
|
|
29
41
|
fadeOutDelay = 300,
|
|
30
|
-
showArrow = false,
|
|
31
42
|
hoverableContent = false,
|
|
32
|
-
...rest
|
|
33
43
|
}: Props) => {
|
|
34
44
|
const { state: isOpen, setState: setIsOpen } = useToggle(false);
|
|
35
45
|
const triggerRef = useRef(null);
|
|
36
46
|
const timeOutRef = useRef<NodeJS.Timeout>(undefined);
|
|
37
|
-
const popoverTimeoutRef = useRef<NodeJS.Timeout>(undefined);
|
|
38
47
|
const preventCloseRef = useRef(false);
|
|
39
48
|
|
|
49
|
+
const {
|
|
50
|
+
Tooltip_Trigger,
|
|
51
|
+
Tooltip_Content,
|
|
52
|
+
rest: restChildren,
|
|
53
|
+
} = extractSubcomponents({
|
|
54
|
+
children,
|
|
55
|
+
allowedChildren: [
|
|
56
|
+
{ name: 'Tooltip_Trigger', allowMultiple: false },
|
|
57
|
+
{ name: 'Tooltip_Content', allowMultiple: false },
|
|
58
|
+
],
|
|
59
|
+
includeRest: true,
|
|
60
|
+
});
|
|
61
|
+
|
|
40
62
|
const onClose = useCallback(() => {
|
|
41
63
|
if (preventCloseRef.current) return;
|
|
42
64
|
clearTimeout(timeOutRef.current);
|
|
@@ -48,34 +70,13 @@ const Tooltip = ({
|
|
|
48
70
|
timeOutRef.current = setTimeout(() => setIsOpen(true), fadeInDelay);
|
|
49
71
|
}, [fadeInDelay, setIsOpen]);
|
|
50
72
|
|
|
51
|
-
|
|
52
|
-
// (_isOpen: boolean) => {
|
|
53
|
-
// clearTimeout(popoverTimeoutRef.current);
|
|
54
|
-
// popoverTimeoutRef.current = setTimeout(
|
|
55
|
-
// () => setIsOpen(_isOpen),
|
|
56
|
-
// isOpen ? fadeInDelay : fadeOutDelay,
|
|
57
|
-
// );
|
|
58
|
-
// },
|
|
59
|
-
// [fadeInDelay, fadeOutDelay, isOpen, setIsOpen],
|
|
60
|
-
// );
|
|
61
|
-
|
|
62
|
-
const { Tooltip_Trigger, Tooltip_Content } = useSubcomponents({
|
|
63
|
-
children,
|
|
64
|
-
allowedChildren: ['Tooltip_Trigger', 'Tooltip_Content'],
|
|
65
|
-
});
|
|
66
|
-
|
|
67
|
-
const contextValue = useMemo(
|
|
73
|
+
const contextValue = useMemo<TooltipContextValue>(
|
|
68
74
|
() => ({
|
|
75
|
+
isOpen,
|
|
69
76
|
triggerRef,
|
|
70
77
|
onOpen,
|
|
71
78
|
onClose,
|
|
72
|
-
|
|
73
|
-
[onClose, onOpen],
|
|
74
|
-
);
|
|
75
|
-
|
|
76
|
-
const { popoverContentProps, popoverStyle } = useMemo(
|
|
77
|
-
() => ({
|
|
78
|
-
popoverContentProps: (hoverableContent
|
|
79
|
+
...(hoverableContent
|
|
79
80
|
? {
|
|
80
81
|
onMouseEnter: () => {
|
|
81
82
|
preventCloseRef.current = true;
|
|
@@ -88,50 +89,24 @@ const Tooltip = ({
|
|
|
88
89
|
setIsOpen(false);
|
|
89
90
|
},
|
|
90
91
|
}
|
|
91
|
-
: {})
|
|
92
|
-
popoverStyle: [tooltipStyles.content, style],
|
|
92
|
+
: {}),
|
|
93
93
|
}),
|
|
94
|
-
[hoverableContent,
|
|
94
|
+
[hoverableContent, isOpen, onClose, onOpen, setIsOpen],
|
|
95
95
|
);
|
|
96
96
|
|
|
97
97
|
useEffect(() => {
|
|
98
|
-
const popoverTimeout = popoverTimeoutRef;
|
|
99
|
-
|
|
100
98
|
return () => {
|
|
101
99
|
clearTimeout(timeOutRef.current);
|
|
102
|
-
clearTimeout(popoverTimeout.current);
|
|
103
100
|
};
|
|
104
101
|
}, []);
|
|
105
102
|
|
|
106
103
|
return (
|
|
107
104
|
<TooltipContext.Provider value={contextValue}>
|
|
108
|
-
{Tooltip_Trigger
|
|
109
|
-
{
|
|
110
|
-
|
|
111
|
-
isOpen={isOpen}
|
|
112
|
-
inverted
|
|
113
|
-
// placement={placement}
|
|
114
|
-
showArrow={showArrow}
|
|
115
|
-
// backdropStyles={styles.backdrop}
|
|
116
|
-
triggerRef={triggerRef}
|
|
117
|
-
// setIsOpen={setPopoverOpen}
|
|
118
|
-
{...popoverContentProps}
|
|
119
|
-
{...rest}
|
|
120
|
-
style={popoverStyle}
|
|
121
|
-
// contentTextStyles={contentTextStyles}
|
|
122
|
-
// popoverContentProps={popoverContentProps}
|
|
123
|
-
onClose={onClose}>
|
|
124
|
-
<Text style={tooltipStyles.contentText}>{Tooltip_Content[0]}</Text>
|
|
125
|
-
</Popover>
|
|
126
|
-
)}
|
|
105
|
+
{Tooltip_Trigger}
|
|
106
|
+
{Tooltip_Content}
|
|
107
|
+
{restChildren}
|
|
127
108
|
</TooltipContext.Provider>
|
|
128
109
|
);
|
|
129
110
|
};
|
|
130
111
|
|
|
131
|
-
export const TooltipContext = createContext({
|
|
132
|
-
onOpen: () => {},
|
|
133
|
-
onClose: () => {},
|
|
134
|
-
triggerRef: null as any,
|
|
135
|
-
});
|
|
136
|
-
|
|
137
112
|
export default memo(Tooltip);
|
|
@@ -1,11 +1,38 @@
|
|
|
1
|
-
import { memo, type
|
|
1
|
+
import { memo, type ReactNode, useContext, useMemo } from 'react';
|
|
2
|
+
import { type StyleProp, Text, type ViewStyle } from 'react-native';
|
|
2
3
|
|
|
3
|
-
|
|
4
|
-
|
|
4
|
+
import { Popover, type PopoverProps } from '../Popover';
|
|
5
|
+
import { TooltipContext } from './Tooltip';
|
|
6
|
+
import { tooltipStyles } from './utils';
|
|
7
|
+
|
|
8
|
+
export type Props = Omit<PopoverProps, 'isOpen' | 'triggerRef' | 'onClose' | 'children'> & {
|
|
9
|
+
children?: ReactNode;
|
|
5
10
|
};
|
|
6
11
|
|
|
7
|
-
const TooltipContent = memo(({ children }: Props) => {
|
|
8
|
-
|
|
12
|
+
const TooltipContent = memo(({ children, style, ...rest }: Props) => {
|
|
13
|
+
const { isOpen, triggerRef, onClose, onMouseEnter, onMouseLeave } = useContext(TooltipContext);
|
|
14
|
+
|
|
15
|
+
const popoverStyle = useMemo<StyleProp<ViewStyle>>(
|
|
16
|
+
() => [tooltipStyles.content, style],
|
|
17
|
+
[style],
|
|
18
|
+
);
|
|
19
|
+
|
|
20
|
+
if (!isOpen) return null;
|
|
21
|
+
|
|
22
|
+
return (
|
|
23
|
+
<Popover
|
|
24
|
+
isOpen={isOpen}
|
|
25
|
+
inverted
|
|
26
|
+
triggerRef={triggerRef}
|
|
27
|
+
onClose={onClose}
|
|
28
|
+
{...rest}
|
|
29
|
+
style={popoverStyle}
|
|
30
|
+
// @ts-ignore — onMouseEnter/onMouseLeave spread onto the inner View via ...rest in Popover
|
|
31
|
+
onMouseEnter={onMouseEnter}
|
|
32
|
+
onMouseLeave={onMouseLeave}>
|
|
33
|
+
<Text style={tooltipStyles.contentText}>{children}</Text>
|
|
34
|
+
</Popover>
|
|
35
|
+
);
|
|
9
36
|
});
|
|
10
37
|
|
|
11
38
|
TooltipContent.displayName = 'Tooltip_Content';
|
|
@@ -30,27 +30,28 @@ const TooltipTrigger = memo(({ children }: { children: ReactElement }) => {
|
|
|
30
30
|
() => triggerRef?.current,
|
|
31
31
|
);
|
|
32
32
|
|
|
33
|
-
const
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
onOpen();
|
|
44
|
-
}, [children?.props, isWeb, onOpen]);
|
|
33
|
+
const onLongPress = useCallback(
|
|
34
|
+
(e: unknown) => {
|
|
35
|
+
// @ts-ignore
|
|
36
|
+
children?.props?.onLongPress?.(e);
|
|
37
|
+
|
|
38
|
+
if (isWeb) return;
|
|
39
|
+
onOpen();
|
|
40
|
+
},
|
|
41
|
+
[children?.props, isWeb, onOpen],
|
|
42
|
+
);
|
|
45
43
|
|
|
46
|
-
const onPressOut = useCallback(
|
|
47
|
-
|
|
44
|
+
const onPressOut = useCallback(
|
|
45
|
+
(e: unknown) => {
|
|
46
|
+
// @ts-ignore
|
|
48
47
|
|
|
49
|
-
|
|
48
|
+
children?.props?.onPressOut?.(e);
|
|
50
49
|
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
50
|
+
if (isWeb) return;
|
|
51
|
+
onClose();
|
|
52
|
+
},
|
|
53
|
+
[children?.props, isWeb, onClose],
|
|
54
|
+
);
|
|
54
55
|
|
|
55
56
|
const onHoverIn = useCallback(() => {
|
|
56
57
|
// @ts-ignore
|
|
@@ -84,9 +85,8 @@ const TooltipTrigger = memo(({ children }: { children: ReactElement }) => {
|
|
|
84
85
|
ref: actionsRef,
|
|
85
86
|
onLongPress,
|
|
86
87
|
onPressOut,
|
|
87
|
-
onPress,
|
|
88
88
|
}),
|
|
89
|
-
[children, onLongPress,
|
|
89
|
+
[children, onLongPress, onPressOut, actionsRef],
|
|
90
90
|
);
|
|
91
91
|
});
|
|
92
92
|
|
|
@@ -10,7 +10,7 @@ export const TooltipDefault = Object.assign(TooltipComponent, {
|
|
|
10
10
|
|
|
11
11
|
export const Tooltip = getRegisteredComponentWithFallback('Tooltip', TooltipDefault);
|
|
12
12
|
|
|
13
|
-
export type { Props as TooltipProps } from './Tooltip';
|
|
13
|
+
export type { TooltipContextValue, Props as TooltipProps } from './Tooltip';
|
|
14
14
|
export type { Props as TooltipContentProps } from './TooltipContent';
|
|
15
15
|
export type { Props as TooltipTriggerProps } from './TooltipTrigger';
|
|
16
16
|
export { tooltipStyles } from './utils';
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import
|
|
1
|
+
import { type ComponentProps, forwardRef, memo, type ReactNode, useMemo } from 'react';
|
|
2
2
|
import {
|
|
3
3
|
type BackgroundPropType,
|
|
4
4
|
Platform,
|
|
@@ -7,25 +7,44 @@ import {
|
|
|
7
7
|
StyleSheet,
|
|
8
8
|
TouchableNativeFeedback,
|
|
9
9
|
TouchableWithoutFeedback,
|
|
10
|
-
View,
|
|
11
10
|
type ViewStyle,
|
|
12
11
|
} from 'react-native';
|
|
13
|
-
import { withUnistyles } from 'react-native-unistyles';
|
|
14
12
|
|
|
13
|
+
import { extractPropertiesFromStyles } from '../../utils/extractPropertiesFromStyles';
|
|
14
|
+
import { Slot } from '../Slot';
|
|
15
15
|
import { touchableRippleStyles } from './utils';
|
|
16
16
|
|
|
17
17
|
const ANDROID_VERSION_LOLLIPOP = 21;
|
|
18
18
|
const ANDROID_VERSION_PIE = 28;
|
|
19
19
|
|
|
20
|
-
type Props =
|
|
20
|
+
type Props = ComponentProps<typeof TouchableWithoutFeedback> & {
|
|
21
21
|
borderless?: boolean;
|
|
22
22
|
background?: BackgroundPropType;
|
|
23
23
|
disabled?: boolean;
|
|
24
24
|
onPress?: () => void | null;
|
|
25
25
|
rippleColor?: string;
|
|
26
26
|
underlayColor?: string;
|
|
27
|
-
children:
|
|
27
|
+
children: ReactNode;
|
|
28
28
|
style?: StyleProp<ViewStyle>;
|
|
29
|
+
/**
|
|
30
|
+
* When `true`, the component will not render a wrapper element. Instead, it will
|
|
31
|
+
* merge its props (styles, event handlers, ref) onto its immediate child element.
|
|
32
|
+
* This follows the Radix UI "Slot" pattern for flexible component composition.
|
|
33
|
+
*
|
|
34
|
+
* @note On Android, the native ripple effect will NOT work when `asChild` is `true`
|
|
35
|
+
* because `TouchableNativeFeedback` requires a View wrapper. Only press events will work.
|
|
36
|
+
*
|
|
37
|
+
* @example
|
|
38
|
+
* ```tsx
|
|
39
|
+
* <TouchableRipple asChild onPress={handlePress}>
|
|
40
|
+
* <View><Text>Custom pressable</Text></View>
|
|
41
|
+
* </TouchableRipple>
|
|
42
|
+
* ```
|
|
43
|
+
*
|
|
44
|
+
* @note When `asChild` is `true`, only a single child element is allowed.
|
|
45
|
+
* @default false
|
|
46
|
+
*/
|
|
47
|
+
asChild?: boolean;
|
|
29
48
|
};
|
|
30
49
|
|
|
31
50
|
const TouchableRipple = (
|
|
@@ -37,17 +56,22 @@ const TouchableRipple = (
|
|
|
37
56
|
rippleColor: rippleColorProp,
|
|
38
57
|
underlayColor: underlayColorProp,
|
|
39
58
|
children,
|
|
59
|
+
asChild = false,
|
|
40
60
|
...rest
|
|
41
61
|
}: Props,
|
|
42
62
|
ref: any,
|
|
43
63
|
) => {
|
|
44
|
-
const disabled = disabledProp
|
|
64
|
+
const disabled = disabledProp;
|
|
45
65
|
|
|
46
66
|
const componentStyles = touchableRippleStyles;
|
|
47
67
|
|
|
48
68
|
const { rippleColor, underlayColor, containerStyle } = useMemo(() => {
|
|
69
|
+
const { rippleColor: _rippleColor } = extractPropertiesFromStyles(
|
|
70
|
+
[componentStyles.root, style],
|
|
71
|
+
['rippleColor'],
|
|
72
|
+
);
|
|
49
73
|
return {
|
|
50
|
-
rippleColor: rippleColorProp,
|
|
74
|
+
rippleColor: rippleColorProp || _rippleColor,
|
|
51
75
|
underlayColor: underlayColorProp || rippleColorProp,
|
|
52
76
|
containerStyle: [borderless && styles.borderless, componentStyles.root, style],
|
|
53
77
|
};
|
|
@@ -58,6 +82,21 @@ const TouchableRipple = (
|
|
|
58
82
|
const useForeground =
|
|
59
83
|
Platform.OS === 'android' && Platform.Version >= ANDROID_VERSION_PIE && borderless;
|
|
60
84
|
|
|
85
|
+
if (asChild) {
|
|
86
|
+
// When asChild is true, use Slot to merge props with the child
|
|
87
|
+
// Note: TouchableNativeFeedback ripple won't work with asChild since it requires a View wrapper
|
|
88
|
+
return (
|
|
89
|
+
<Slot
|
|
90
|
+
{...rest}
|
|
91
|
+
style={containerStyle}
|
|
92
|
+
ref={ref}
|
|
93
|
+
onPress={rest.onPress}
|
|
94
|
+
disabled={disabled}>
|
|
95
|
+
{children}
|
|
96
|
+
</Slot>
|
|
97
|
+
);
|
|
98
|
+
}
|
|
99
|
+
|
|
61
100
|
if (TouchableRipple.supported) {
|
|
62
101
|
return (
|
|
63
102
|
<TouchableNativeFeedback
|
|
@@ -65,12 +104,13 @@ const TouchableRipple = (
|
|
|
65
104
|
ref={ref}
|
|
66
105
|
disabled={disabled}
|
|
67
106
|
useForeground={useForeground}
|
|
107
|
+
style={containerStyle}
|
|
68
108
|
background={
|
|
69
109
|
background != null
|
|
70
110
|
? background
|
|
71
111
|
: TouchableNativeFeedback.Ripple(rippleColor!, borderless)
|
|
72
112
|
}>
|
|
73
|
-
|
|
113
|
+
<>{children}</>
|
|
74
114
|
</TouchableNativeFeedback>
|
|
75
115
|
);
|
|
76
116
|
}
|
|
@@ -84,7 +124,7 @@ const TouchableRipple = (
|
|
|
84
124
|
containerStyle,
|
|
85
125
|
pressed && { backgroundColor: underlayColor },
|
|
86
126
|
]}>
|
|
87
|
-
{
|
|
127
|
+
{children}
|
|
88
128
|
</Pressable>
|
|
89
129
|
);
|
|
90
130
|
};
|
|
@@ -98,8 +138,4 @@ const styles = StyleSheet.create({
|
|
|
98
138
|
TouchableRipple.supported =
|
|
99
139
|
Platform.OS === 'android' && Platform.Version >= ANDROID_VERSION_LOLLIPOP;
|
|
100
140
|
|
|
101
|
-
export default memo(
|
|
102
|
-
withUnistyles(forwardRef(TouchableRipple), theme => ({
|
|
103
|
-
rippleColor: theme.colors.onSurfaceRipple,
|
|
104
|
-
})),
|
|
105
|
-
);
|
|
141
|
+
export default memo(forwardRef(TouchableRipple));
|