react-native-molecules 0.5.0-beta.20 → 0.5.0-beta.22
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/Card/Card.tsx +1 -1
- package/components/Checkbox/CheckboxBase.ios.tsx +9 -16
- package/components/Checkbox/CheckboxBase.tsx +11 -18
- package/components/DateField/DateField.tsx +4 -3
- package/components/DatePicker/DateCalendar.tsx +4 -4
- package/components/DatePicker/DatePickerModal.tsx +35 -23
- package/components/DatePicker/DatePickerProvider.tsx +8 -2
- package/components/DatePicker/context.tsx +2 -1
- package/components/DatePicker/index.tsx +1 -0
- package/components/DatePickerInline/DatePickerDockedHeader.tsx +11 -7
- package/components/DatePickerInline/DatePickerInline.tsx +1 -1
- package/components/DatePickerInline/DatePickerInlineBase.tsx +3 -3
- package/components/DatePickerInline/DatePickerInlineHeader.tsx +50 -20
- package/components/DatePickerInline/DayNames.tsx +13 -10
- package/components/DatePickerInline/HeaderItem.tsx +2 -2
- package/components/DatePickerInline/Month.tsx +4 -3
- package/components/DatePickerInline/MonthPicker.tsx +74 -54
- package/components/DatePickerInline/Swiper.native.tsx +2 -2
- package/components/DatePickerInline/Swiper.tsx +3 -3
- package/components/DatePickerInline/YearPicker.tsx +136 -112
- package/components/DatePickerInline/{DatePickerContext.tsx → store.tsx} +7 -3
- package/components/DatePickerInline/types.ts +4 -3
- package/components/Divider/Divider.tsx +192 -0
- package/components/Divider/index.tsx +11 -0
- package/components/Drawer/DrawerItemGroup.tsx +3 -7
- package/components/IconButton/IconButton.tsx +2 -12
- package/components/List/List.tsx +507 -0
- package/components/List/context.tsx +28 -0
- package/components/List/index.ts +9 -0
- package/components/List/types.ts +149 -0
- package/components/{ListItem → List}/utils.ts +47 -50
- package/components/Menu/Menu.tsx +156 -12
- package/components/Menu/index.tsx +11 -7
- package/components/Menu/utils.ts +21 -70
- package/components/RadioButton/RadioButtonAndroid.tsx +38 -54
- package/components/RadioButton/RadioButtonIOS.tsx +2 -16
- package/components/Select/Select.tsx +139 -497
- package/components/Select/context.tsx +14 -32
- package/components/Select/types.ts +44 -53
- package/components/Select/utils.ts +15 -47
- package/components/Text/textFactory.tsx +17 -5
- package/components/TimeField/TimeField.tsx +1 -1
- package/components/TimePicker/TimeInput.tsx +2 -7
- package/components/TimePicker/TimePickerModal.tsx +15 -15
- package/components/TimePicker/utils.ts +0 -4
- package/components/TouchableRipple/TouchableRipple.native.tsx +36 -5
- package/components/TouchableRipple/TouchableRipple.tsx +53 -19
- package/components/TouchableRipple/rippleFromForegroundColor.ts +21 -0
- package/package.json +4 -2
- package/components/HorizontalDivider/HorizontalDivider.tsx +0 -103
- package/components/HorizontalDivider/index.tsx +0 -9
- package/components/ListItem/ListItem.tsx +0 -138
- package/components/ListItem/ListItemDescription.tsx +0 -25
- package/components/ListItem/ListItemTitle.tsx +0 -25
- package/components/ListItem/index.tsx +0 -14
- package/components/Menu/MenuDivider.tsx +0 -13
- package/components/Menu/MenuItem.tsx +0 -128
- package/components/VerticalDivider/VerticalDivider.tsx +0 -100
- package/components/VerticalDivider/index.tsx +0 -9
|
@@ -1,44 +1,27 @@
|
|
|
1
1
|
import type { View } from 'react-native';
|
|
2
2
|
|
|
3
3
|
import { createFastContext } from '../../fast-context';
|
|
4
|
+
import {
|
|
5
|
+
ListContext,
|
|
6
|
+
ListContextProvider,
|
|
7
|
+
useListContext,
|
|
8
|
+
useListContextValue,
|
|
9
|
+
useListStoreRef,
|
|
10
|
+
} from '../List';
|
|
4
11
|
import { registerPortalContext } from '../Portal';
|
|
5
|
-
import type {
|
|
6
|
-
|
|
7
|
-
// SelectContext - holds value, onAdd, onRemove with fast-context for optimized rendering
|
|
8
|
-
const selectContextDefaultValue: SelectContextValue<DefaultItemT> = {
|
|
9
|
-
value: null,
|
|
10
|
-
multiple: false,
|
|
11
|
-
onAdd: () => {},
|
|
12
|
-
onRemove: () => {},
|
|
13
|
-
disabled: false,
|
|
14
|
-
error: false,
|
|
15
|
-
labelKey: 'label',
|
|
16
|
-
options: [],
|
|
17
|
-
searchQuery: '',
|
|
18
|
-
setSearchQuery: () => {},
|
|
19
|
-
filteredOptions: [],
|
|
20
|
-
};
|
|
21
|
-
|
|
22
|
-
const {
|
|
23
|
-
useStoreRef: useSelectStoreRef,
|
|
24
|
-
Provider: SelectContextProvider,
|
|
25
|
-
useContext: useSelectContext,
|
|
26
|
-
useContextValue: useSelectContextValue,
|
|
27
|
-
Context: SelectContext,
|
|
28
|
-
} = createFastContext<SelectContextValue<DefaultItemT>>(selectContextDefaultValue, true);
|
|
12
|
+
import type { SelectDropdownContextValue } from './types';
|
|
29
13
|
|
|
30
14
|
export {
|
|
31
|
-
SelectContext,
|
|
32
|
-
SelectContextProvider,
|
|
33
|
-
useSelectContext,
|
|
34
|
-
useSelectContextValue,
|
|
35
|
-
useSelectStoreRef,
|
|
15
|
+
ListContext as SelectContext,
|
|
16
|
+
ListContextProvider as SelectContextProvider,
|
|
17
|
+
useListContext as useSelectContext,
|
|
18
|
+
useListContextValue as useSelectContextValue,
|
|
19
|
+
useListStoreRef as useSelectStoreRef,
|
|
36
20
|
};
|
|
37
21
|
|
|
38
22
|
// SelectDropdownContext - holds isOpen, onClose, triggerRef with fast-context
|
|
39
23
|
export type SelectDropdownContextType = SelectDropdownContextValue & {
|
|
40
24
|
triggerRef: React.RefObject<View> | null;
|
|
41
|
-
contentRef: React.RefObject<any> | null;
|
|
42
25
|
triggerLayout: { width: number; height: number } | null;
|
|
43
26
|
setTriggerLayout: (layout: { width: number; height: number }) => void;
|
|
44
27
|
};
|
|
@@ -48,7 +31,6 @@ const selectDropdownContextDefaultValue: SelectDropdownContextType = {
|
|
|
48
31
|
onClose: () => {},
|
|
49
32
|
onOpen: () => {},
|
|
50
33
|
triggerRef: null,
|
|
51
|
-
contentRef: null,
|
|
52
34
|
triggerLayout: null,
|
|
53
35
|
setTriggerLayout: () => {},
|
|
54
36
|
};
|
|
@@ -69,4 +51,4 @@ export {
|
|
|
69
51
|
useSelectDropdownStoreRef,
|
|
70
52
|
};
|
|
71
53
|
|
|
72
|
-
registerPortalContext([
|
|
54
|
+
registerPortalContext([SelectDropdownContext]);
|
|
@@ -1,13 +1,16 @@
|
|
|
1
1
|
import type { ComponentType, ReactNode } from 'react';
|
|
2
|
-
import type {
|
|
3
|
-
GestureResponderEvent,
|
|
4
|
-
ScrollViewProps,
|
|
5
|
-
TextInputProps,
|
|
6
|
-
ViewProps,
|
|
7
|
-
} from 'react-native';
|
|
2
|
+
import type { GestureResponderEvent, ViewProps } from 'react-native';
|
|
8
3
|
|
|
4
|
+
import type { ListValue } from '../List';
|
|
9
5
|
import type { PopoverProps } from '../Popover';
|
|
10
6
|
|
|
7
|
+
export type {
|
|
8
|
+
ListContentProps as SelectContentProps,
|
|
9
|
+
ListContextValue as SelectContextValue,
|
|
10
|
+
ListGroupProps as SelectGroupProps,
|
|
11
|
+
ListSearchInputProps as SelectSearchInputProps,
|
|
12
|
+
} from '../List';
|
|
13
|
+
|
|
11
14
|
export type DefaultItemT = {
|
|
12
15
|
id: string | number;
|
|
13
16
|
label?: string;
|
|
@@ -15,21 +18,6 @@ export type DefaultItemT = {
|
|
|
15
18
|
[key: string]: any;
|
|
16
19
|
};
|
|
17
20
|
|
|
18
|
-
// SelectContext types
|
|
19
|
-
export type SelectContextValue<Option extends DefaultItemT = DefaultItemT> = {
|
|
20
|
-
value: Option | Option[] | null;
|
|
21
|
-
multiple: boolean;
|
|
22
|
-
onAdd: (item: Option) => void;
|
|
23
|
-
onRemove: (item: Option) => void;
|
|
24
|
-
disabled?: boolean;
|
|
25
|
-
error?: boolean;
|
|
26
|
-
labelKey?: string;
|
|
27
|
-
options: Option[];
|
|
28
|
-
searchQuery: string;
|
|
29
|
-
setSearchQuery: (query: string) => void;
|
|
30
|
-
filteredOptions: Option[];
|
|
31
|
-
};
|
|
32
|
-
|
|
33
21
|
// SelectDropdownContext types
|
|
34
22
|
export type SelectDropdownContextValue = {
|
|
35
23
|
isOpen: boolean;
|
|
@@ -38,25 +26,41 @@ export type SelectDropdownContextValue = {
|
|
|
38
26
|
};
|
|
39
27
|
|
|
40
28
|
// SelectProvider props
|
|
41
|
-
|
|
29
|
+
type SelectPropsBase<Option extends DefaultItemT = DefaultItemT> = {
|
|
42
30
|
children: ReactNode;
|
|
43
|
-
value?: Option['id'] | Option['id'][] | null;
|
|
44
|
-
defaultValue?: Option['id'] | Option['id'][] | null;
|
|
45
|
-
onChange?: (
|
|
46
|
-
value: Option['id'] | Option['id'][] | null,
|
|
47
|
-
item: Option,
|
|
48
|
-
event?: GestureResponderEvent,
|
|
49
|
-
) => void;
|
|
50
|
-
multiple?: boolean;
|
|
51
31
|
disabled?: boolean;
|
|
52
32
|
error?: boolean;
|
|
53
|
-
labelKey?: string;
|
|
54
33
|
options: Option[];
|
|
55
34
|
searchKey?: string;
|
|
56
35
|
onSearchChange?: (query: string) => void;
|
|
57
36
|
hideSelected?: boolean;
|
|
58
37
|
};
|
|
59
38
|
|
|
39
|
+
type SingleSelectProps<Option extends DefaultItemT = DefaultItemT> = {
|
|
40
|
+
multiple?: false | undefined;
|
|
41
|
+
value?: ListValue<Option, false>;
|
|
42
|
+
defaultValue?: ListValue<Option, false>;
|
|
43
|
+
onChange?: (
|
|
44
|
+
value: ListValue<Option, false>,
|
|
45
|
+
item: Option,
|
|
46
|
+
event?: GestureResponderEvent,
|
|
47
|
+
) => void;
|
|
48
|
+
};
|
|
49
|
+
|
|
50
|
+
type MultipleSelectProps<Option extends DefaultItemT = DefaultItemT> = {
|
|
51
|
+
multiple: true;
|
|
52
|
+
value?: ListValue<Option, true>;
|
|
53
|
+
defaultValue?: ListValue<Option, true>;
|
|
54
|
+
onChange?: (
|
|
55
|
+
value: ListValue<Option, true>,
|
|
56
|
+
item: Option,
|
|
57
|
+
event?: GestureResponderEvent,
|
|
58
|
+
) => void;
|
|
59
|
+
};
|
|
60
|
+
|
|
61
|
+
export type SelectProps<Option extends DefaultItemT = DefaultItemT> = SelectPropsBase<Option> &
|
|
62
|
+
(SingleSelectProps<Option> | MultipleSelectProps<Option>);
|
|
63
|
+
|
|
60
64
|
// Select.Trigger props
|
|
61
65
|
export type SelectTriggerProps = ViewProps & {
|
|
62
66
|
children?: ReactNode;
|
|
@@ -65,6 +69,7 @@ export type SelectTriggerProps = ViewProps & {
|
|
|
65
69
|
// Select.Value props
|
|
66
70
|
export type SelectValueProps = ViewProps & {
|
|
67
71
|
placeholder?: string;
|
|
72
|
+
labelKey?: string;
|
|
68
73
|
renderValue?: (value: DefaultItemT | DefaultItemT[] | null) => ReactNode;
|
|
69
74
|
};
|
|
70
75
|
|
|
@@ -78,36 +83,22 @@ export type SelectDropdownProps = Omit<
|
|
|
78
83
|
wrapperComponentProps?: Record<string, any>;
|
|
79
84
|
};
|
|
80
85
|
|
|
81
|
-
// Select.Content props
|
|
82
|
-
export type SelectContentProps<Option extends DefaultItemT = DefaultItemT> = Omit<
|
|
83
|
-
ScrollViewProps,
|
|
84
|
-
'children'
|
|
85
|
-
> & {
|
|
86
|
-
children: (item: Option, isSelected: boolean) => ReactNode;
|
|
87
|
-
ContainerComponent?: ComponentType<any>;
|
|
88
|
-
emptyState?: ReactNode;
|
|
89
|
-
};
|
|
90
|
-
|
|
91
|
-
// Select.Group props
|
|
92
|
-
export type SelectGroupProps = ViewProps & {
|
|
93
|
-
children: ReactNode;
|
|
94
|
-
label?: string;
|
|
95
|
-
};
|
|
96
|
-
|
|
97
86
|
// Select.Option props
|
|
98
|
-
|
|
87
|
+
// `accessibilityRole` and `role` are intentionally omitted: Select.Option forces them to
|
|
88
|
+
// "option" on web so the dropdown's keyboard navigator (which queries [role="option"]) can
|
|
89
|
+
// always find the rows. Allowing callers to override would silently break keyboard nav.
|
|
90
|
+
export type SelectOptionProps<Option extends DefaultItemT = DefaultItemT> = Omit<
|
|
91
|
+
ViewProps,
|
|
92
|
+
'accessibilityRole' | 'role'
|
|
93
|
+
> & {
|
|
99
94
|
/**
|
|
100
95
|
* Unique id for the option
|
|
101
96
|
*/
|
|
102
97
|
value: Option['id'];
|
|
103
|
-
children
|
|
104
|
-
renderItem?: (item: Option, isSelected: boolean) => ReactNode;
|
|
98
|
+
children: ReactNode;
|
|
105
99
|
onPress?: (item: Option, event: GestureResponderEvent) => void;
|
|
106
100
|
/**
|
|
107
101
|
* When true, the option can't be selected (similar to HTML option disabled)
|
|
108
102
|
*/
|
|
109
103
|
disabled?: boolean;
|
|
110
104
|
};
|
|
111
|
-
|
|
112
|
-
// Select.SearchInput props
|
|
113
|
-
export type SelectSearchInputProps = Omit<TextInputProps, 'value' | 'onChangeText'> & {};
|
|
@@ -2,6 +2,21 @@ import { StyleSheet } from 'react-native-unistyles';
|
|
|
2
2
|
|
|
3
3
|
import { getRegisteredComponentStylesWithFallback } from '../../core';
|
|
4
4
|
|
|
5
|
+
/** Web-only marker on Select.Option roots so keyboard nav does not depend on role/accessibilityRole overrides. */
|
|
6
|
+
export const SELECT_OPTION_DATA_ATTR = 'data-molecules-select-option';
|
|
7
|
+
|
|
8
|
+
const SELECT_OPTION_SELECTOR = `[${SELECT_OPTION_DATA_ATTR}], [data-option-id], [role="option"]`;
|
|
9
|
+
|
|
10
|
+
export function collectWebSelectKeyboardOptionElements(container: ParentNode): HTMLElement[] {
|
|
11
|
+
return Array.from(container.querySelectorAll(SELECT_OPTION_SELECTOR)).filter(
|
|
12
|
+
(el): el is HTMLElement => {
|
|
13
|
+
if (!(el instanceof HTMLElement)) return false;
|
|
14
|
+
if (el.getAttribute('aria-disabled') === 'true') return false;
|
|
15
|
+
return true;
|
|
16
|
+
},
|
|
17
|
+
);
|
|
18
|
+
}
|
|
19
|
+
|
|
5
20
|
const triggerDefaultStyles = StyleSheet.create(theme => ({
|
|
6
21
|
trigger: {
|
|
7
22
|
borderRadius: theme.shapes.corner.extraSmall,
|
|
@@ -83,57 +98,10 @@ export const defaultStyles = StyleSheet.create(theme => ({
|
|
|
83
98
|
gap: 6,
|
|
84
99
|
maxWidth: '90%',
|
|
85
100
|
},
|
|
86
|
-
groupLabel: {
|
|
87
|
-
paddingHorizontal: theme.spacings['4'],
|
|
88
|
-
paddingVertical: theme.spacings['2'],
|
|
89
|
-
fontWeight: '600',
|
|
90
|
-
color: theme.colors.onSurface,
|
|
91
|
-
},
|
|
92
|
-
item: {
|
|
93
|
-
paddingHorizontal: theme.spacings['4'],
|
|
94
|
-
paddingVertical: theme.spacings['3'],
|
|
95
|
-
backgroundColor: 'transparent',
|
|
96
|
-
|
|
97
|
-
_web: {
|
|
98
|
-
cursor: 'pointer',
|
|
99
|
-
outlineStyle: 'none',
|
|
100
|
-
_hover: {
|
|
101
|
-
backgroundColor: theme.colors.stateLayer.hover.primary,
|
|
102
|
-
},
|
|
103
|
-
_focus: {
|
|
104
|
-
backgroundColor: theme.colors.stateLayer.focussed.primary,
|
|
105
|
-
},
|
|
106
|
-
},
|
|
107
|
-
},
|
|
108
|
-
itemSelected: {
|
|
109
|
-
backgroundColor: theme.colors.stateLayer.hover.primary,
|
|
110
|
-
},
|
|
111
|
-
itemDisabled: {
|
|
112
|
-
opacity: 0.38,
|
|
113
|
-
_web: {
|
|
114
|
-
cursor: 'not-allowed',
|
|
115
|
-
},
|
|
116
|
-
},
|
|
117
|
-
itemDisabledText: {
|
|
118
|
-
color: theme.colors.onSurfaceVariant,
|
|
119
|
-
},
|
|
120
101
|
searchInput: {
|
|
121
102
|
marginHorizontal: theme.spacings['2'],
|
|
122
103
|
marginVertical: theme.spacings['3'],
|
|
123
104
|
},
|
|
124
|
-
searchInputInput: {
|
|
125
|
-
height: 42,
|
|
126
|
-
},
|
|
127
|
-
emptyState: {
|
|
128
|
-
paddingHorizontal: theme.spacings['4'],
|
|
129
|
-
paddingVertical: theme.spacings['6'],
|
|
130
|
-
alignItems: 'center',
|
|
131
|
-
justifyContent: 'center',
|
|
132
|
-
},
|
|
133
|
-
emptyStateText: {
|
|
134
|
-
color: theme.colors.onSurfaceVariant,
|
|
135
|
-
fontSize: 14,
|
|
136
|
-
},
|
|
137
105
|
}));
|
|
138
106
|
|
|
139
107
|
export const triggerStyles = getRegisteredComponentStylesWithFallback(
|
|
@@ -1,6 +1,8 @@
|
|
|
1
1
|
import { type ComponentType, createContext, forwardRef, memo, useContext } from 'react';
|
|
2
2
|
import { Text, type TextProps } from 'react-native';
|
|
3
|
-
import { StyleSheet } from 'react-native-unistyles';
|
|
3
|
+
import { StyleSheet, useUnistyles } from 'react-native-unistyles';
|
|
4
|
+
|
|
5
|
+
import { MD3TypescaleKey } from '../../types/theme';
|
|
4
6
|
|
|
5
7
|
const HasAncestorContext = createContext(false);
|
|
6
8
|
|
|
@@ -8,18 +10,28 @@ const defaultStyles = StyleSheet.create(theme => ({
|
|
|
8
10
|
root: { color: theme.colors.onSurface, ...theme.typescale.bodyMedium },
|
|
9
11
|
}));
|
|
10
12
|
|
|
13
|
+
export type TypescaleKey = `${MD3TypescaleKey}`;
|
|
14
|
+
|
|
15
|
+
export type TextFactoryProps = TextProps & {
|
|
16
|
+
typescale?: TypescaleKey;
|
|
17
|
+
};
|
|
18
|
+
|
|
11
19
|
export const textFactory = (
|
|
12
20
|
componentStyles: typeof defaultStyles = defaultStyles,
|
|
13
21
|
isBlockLevelElement = false,
|
|
14
22
|
DefaultComponent: ComponentType<any> = Text,
|
|
15
23
|
) => {
|
|
16
24
|
return memo(
|
|
17
|
-
forwardRef((props:
|
|
18
|
-
const { style, ...rest } = props;
|
|
25
|
+
forwardRef((props: TextFactoryProps, ref: any) => {
|
|
26
|
+
const { style, typescale, ...rest } = props;
|
|
19
27
|
const hasAncestorText = useContext(HasAncestorContext);
|
|
28
|
+
const { theme } = useUnistyles();
|
|
29
|
+
|
|
30
|
+
const typescaleStyle = typescale ? theme.typescale[typescale] : undefined;
|
|
20
31
|
|
|
21
|
-
const
|
|
22
|
-
hasAncestorText && !isBlockLevelElement ?
|
|
32
|
+
const baseStyle =
|
|
33
|
+
hasAncestorText && !isBlockLevelElement ? null : componentStyles?.root;
|
|
34
|
+
const styles = [baseStyle, typescaleStyle, style];
|
|
23
35
|
|
|
24
36
|
return hasAncestorText ? (
|
|
25
37
|
<DefaultComponent ref={ref} style={styles} {...rest} />
|
|
@@ -60,11 +60,11 @@ function TimeField({ ref, disabled: disabledProp, onBlur, onFocus, ...rest }: Ti
|
|
|
60
60
|
|
|
61
61
|
return (
|
|
62
62
|
<TextInput
|
|
63
|
+
placeholder={timeFormat[is24Hour ? '24' : '12'].format}
|
|
63
64
|
{...rest}
|
|
64
65
|
ref={ref}
|
|
65
66
|
disabled={disabled}
|
|
66
67
|
value={formatted}
|
|
67
|
-
placeholder={timeFormat[is24Hour ? '24' : '12'].format}
|
|
68
68
|
onChangeText={onChangeText}
|
|
69
69
|
onBlur={onInnerBlur}
|
|
70
70
|
onFocus={onInnerFocus}
|
|
@@ -66,7 +66,7 @@ function TimeInput(
|
|
|
66
66
|
return str.length === 1 ? `0${str}` : str;
|
|
67
67
|
}, [value, inputFocused, rawText, error]);
|
|
68
68
|
|
|
69
|
-
const {
|
|
69
|
+
const { containerStyle, textInputStyle, buttonStyle } = useMemo(() => {
|
|
70
70
|
const {
|
|
71
71
|
container,
|
|
72
72
|
input,
|
|
@@ -79,7 +79,6 @@ function TimeInput(
|
|
|
79
79
|
const isKeyboardInput = inputType === inputTypes.keyboard;
|
|
80
80
|
|
|
81
81
|
return {
|
|
82
|
-
rippleColor: timePickerInputStyles.root?._rippleColor,
|
|
83
82
|
containerStyle: container,
|
|
84
83
|
textInputStyle: [
|
|
85
84
|
input,
|
|
@@ -146,11 +145,7 @@ function TimeInput(
|
|
|
146
145
|
/>
|
|
147
146
|
<>
|
|
148
147
|
{onPress && inputType === inputTypes.picker ? (
|
|
149
|
-
<TouchableRipple
|
|
150
|
-
style={buttonStyle}
|
|
151
|
-
rippleColor={rippleColor}
|
|
152
|
-
onPress={onPressInput}
|
|
153
|
-
borderless={true}>
|
|
148
|
+
<TouchableRipple style={buttonStyle} onPress={onPressInput} borderless={true}>
|
|
154
149
|
<View />
|
|
155
150
|
</TouchableRipple>
|
|
156
151
|
) : null}
|
|
@@ -5,7 +5,11 @@ import { KeyboardAvoidingView, Platform, View } from 'react-native';
|
|
|
5
5
|
import { getRegisteredComponentWithFallback } from '../../core';
|
|
6
6
|
import { useControlledValue } from '../../hooks';
|
|
7
7
|
import { DatePickerActions, DatePickerProvider } from '../DatePicker';
|
|
8
|
-
import type {
|
|
8
|
+
import type {
|
|
9
|
+
DatePickerContextType,
|
|
10
|
+
DatePickerLocale,
|
|
11
|
+
DatePickerValue,
|
|
12
|
+
} from '../DatePicker/context';
|
|
9
13
|
import {
|
|
10
14
|
DatePickerContext,
|
|
11
15
|
useDatePickerContext,
|
|
@@ -32,6 +36,7 @@ export type TimePickerModalProps = Omit<ModalProps, 'children' | 'isOpen' | 'onC
|
|
|
32
36
|
onClose?: () => void;
|
|
33
37
|
value?: DatePickerValue;
|
|
34
38
|
onChange?: (value: DatePickerValue) => void;
|
|
39
|
+
locale?: DatePickerLocale;
|
|
35
40
|
is24Hour?: boolean;
|
|
36
41
|
inputType?: PossibleInputTypes;
|
|
37
42
|
defaultInputType?: PossibleInputTypes;
|
|
@@ -119,31 +124,24 @@ function TimePickerModalBody({
|
|
|
119
124
|
function TimePickerModalLayer({
|
|
120
125
|
base,
|
|
121
126
|
draft: draftProp,
|
|
122
|
-
|
|
123
|
-
}: {
|
|
127
|
+
...rest
|
|
128
|
+
}: BodyProps & {
|
|
124
129
|
base: DatePickerContextType;
|
|
125
130
|
draft: boolean | undefined;
|
|
126
|
-
bodyProps: BodyProps;
|
|
127
131
|
}) {
|
|
128
132
|
const effectiveDraft = draftProp ?? base.providerDraft ?? true;
|
|
129
133
|
const ctx = useMemo(() => withDraftLayer(base, effectiveDraft), [base, effectiveDraft]);
|
|
130
134
|
if (!base.open) return null;
|
|
131
135
|
return (
|
|
132
136
|
<DatePickerContext value={ctx}>
|
|
133
|
-
<TimePickerModalBody {...
|
|
137
|
+
<TimePickerModalBody {...rest} />
|
|
134
138
|
</DatePickerContext>
|
|
135
139
|
);
|
|
136
140
|
}
|
|
137
141
|
|
|
138
|
-
function TimePickerModalAdapter({
|
|
139
|
-
draft,
|
|
140
|
-
bodyProps,
|
|
141
|
-
}: {
|
|
142
|
-
draft: boolean | undefined;
|
|
143
|
-
bodyProps: BodyProps;
|
|
144
|
-
}) {
|
|
142
|
+
function TimePickerModalAdapter({ draft, ...rest }: BodyProps & { draft: boolean | undefined }) {
|
|
145
143
|
const base = useDatePickerContext();
|
|
146
|
-
return <TimePickerModalLayer base={base} draft={draft}
|
|
144
|
+
return <TimePickerModalLayer base={base} draft={draft} {...rest} />;
|
|
147
145
|
}
|
|
148
146
|
|
|
149
147
|
const TimePickerModalDefault = memo(
|
|
@@ -152,6 +150,7 @@ const TimePickerModalDefault = memo(
|
|
|
152
150
|
onClose: onCloseProp,
|
|
153
151
|
value: valueProp,
|
|
154
152
|
onChange: onChangeProp,
|
|
153
|
+
locale,
|
|
155
154
|
is24Hour,
|
|
156
155
|
draft: draftProp,
|
|
157
156
|
...rest
|
|
@@ -159,7 +158,7 @@ const TimePickerModalDefault = memo(
|
|
|
159
158
|
const outer = useOptionalDatePickerContext();
|
|
160
159
|
|
|
161
160
|
if (outer) {
|
|
162
|
-
return <TimePickerModalLayer base={outer} draft={draftProp}
|
|
161
|
+
return <TimePickerModalLayer base={outer} draft={draftProp} {...rest} />;
|
|
163
162
|
}
|
|
164
163
|
|
|
165
164
|
return (
|
|
@@ -168,11 +167,12 @@ const TimePickerModalDefault = memo(
|
|
|
168
167
|
value={valueProp}
|
|
169
168
|
onChange={onChangeProp}
|
|
170
169
|
open={isOpenProp}
|
|
170
|
+
locale={locale}
|
|
171
171
|
onOpenChange={next => {
|
|
172
172
|
if (!next) onCloseProp?.();
|
|
173
173
|
}}
|
|
174
174
|
is24Hour={is24Hour}>
|
|
175
|
-
<TimePickerModalAdapter draft={draftProp}
|
|
175
|
+
<TimePickerModalAdapter draft={draftProp} {...rest} />
|
|
176
176
|
</DatePickerProvider>
|
|
177
177
|
);
|
|
178
178
|
},
|
|
@@ -97,10 +97,6 @@ const timePickerInputsStylesDefault = StyleSheet.create(theme => ({
|
|
|
97
97
|
}));
|
|
98
98
|
|
|
99
99
|
const timePickerInputStylesDefault = StyleSheet.create(theme => ({
|
|
100
|
-
root: {
|
|
101
|
-
rippleColor: theme.colors.onPrimaryContainer,
|
|
102
|
-
} as any,
|
|
103
|
-
|
|
104
100
|
container: {
|
|
105
101
|
position: 'relative',
|
|
106
102
|
},
|
|
@@ -10,8 +10,10 @@ import {
|
|
|
10
10
|
type ViewStyle,
|
|
11
11
|
} from 'react-native';
|
|
12
12
|
|
|
13
|
+
import { useTheme } from '../../hooks/useTheme';
|
|
13
14
|
import { extractPropertiesFromStyles } from '../../utils/extractPropertiesFromStyles';
|
|
14
15
|
import { Slot } from '../Slot';
|
|
16
|
+
import { rippleColorFromBackground } from './rippleFromForegroundColor';
|
|
15
17
|
import { touchableRippleStyles } from './utils';
|
|
16
18
|
|
|
17
19
|
const ANDROID_VERSION_LOLLIPOP = 21;
|
|
@@ -24,6 +26,7 @@ type Props = ComponentProps<typeof TouchableWithoutFeedback> & {
|
|
|
24
26
|
onPress?: () => void | null;
|
|
25
27
|
rippleColor?: string;
|
|
26
28
|
underlayColor?: string;
|
|
29
|
+
rippleAlpha?: number;
|
|
27
30
|
children: ReactNode;
|
|
28
31
|
style?: StyleProp<ViewStyle>;
|
|
29
32
|
/**
|
|
@@ -55,6 +58,7 @@ const TouchableRipple = (
|
|
|
55
58
|
disabled: disabledProp,
|
|
56
59
|
rippleColor: rippleColorProp,
|
|
57
60
|
underlayColor: underlayColorProp,
|
|
61
|
+
rippleAlpha = 0.24,
|
|
58
62
|
children,
|
|
59
63
|
asChild = false,
|
|
60
64
|
...rest
|
|
@@ -62,20 +66,47 @@ const TouchableRipple = (
|
|
|
62
66
|
ref: any,
|
|
63
67
|
) => {
|
|
64
68
|
const disabled = disabledProp;
|
|
69
|
+
const theme = useTheme();
|
|
65
70
|
|
|
66
71
|
const componentStyles = touchableRippleStyles;
|
|
67
72
|
|
|
68
73
|
const { rippleColor, underlayColor, containerStyle } = useMemo(() => {
|
|
69
|
-
const { rippleColor:
|
|
74
|
+
const { rippleColor: themeRippleColor, backgroundColor } = extractPropertiesFromStyles(
|
|
70
75
|
[componentStyles.root, style],
|
|
71
|
-
['rippleColor'],
|
|
76
|
+
['rippleColor', 'backgroundColor'],
|
|
72
77
|
);
|
|
78
|
+
const tokenResolvedColor =
|
|
79
|
+
typeof rippleColorProp === 'string'
|
|
80
|
+
? theme.colors[rippleColorProp as keyof typeof theme.colors]
|
|
81
|
+
: undefined;
|
|
82
|
+
const rippleColorResolvedProp =
|
|
83
|
+
typeof tokenResolvedColor === 'string' ? tokenResolvedColor : rippleColorProp;
|
|
84
|
+
|
|
85
|
+
const fallback =
|
|
86
|
+
typeof themeRippleColor === 'string' && themeRippleColor.length > 0
|
|
87
|
+
? themeRippleColor
|
|
88
|
+
: 'rgba(0, 0, 0, 0.32)';
|
|
89
|
+
|
|
90
|
+
const resolvedRipple =
|
|
91
|
+
rippleColorResolvedProp ??
|
|
92
|
+
(backgroundColor != null && backgroundColor !== ''
|
|
93
|
+
? rippleColorFromBackground(String(backgroundColor), fallback, rippleAlpha)
|
|
94
|
+
: fallback);
|
|
95
|
+
|
|
73
96
|
return {
|
|
74
|
-
rippleColor:
|
|
75
|
-
underlayColor: underlayColorProp
|
|
97
|
+
rippleColor: resolvedRipple,
|
|
98
|
+
underlayColor: underlayColorProp ?? resolvedRipple,
|
|
76
99
|
containerStyle: [borderless && styles.borderless, componentStyles.root, style],
|
|
77
100
|
};
|
|
78
|
-
}, [
|
|
101
|
+
}, [
|
|
102
|
+
borderless,
|
|
103
|
+
componentStyles.root,
|
|
104
|
+
rippleColorProp,
|
|
105
|
+
style,
|
|
106
|
+
underlayColorProp,
|
|
107
|
+
rippleAlpha,
|
|
108
|
+
theme,
|
|
109
|
+
]);
|
|
79
110
|
|
|
80
111
|
// A workaround for ripple on Android P is to use useForeground + overflow: 'hidden'
|
|
81
112
|
// https://github.com/facebook/react-native/issues/6480
|