react-native-molecules 0.5.0-beta.21 → 0.5.0-beta.23
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/Button/Button.tsx +3 -1
- package/components/Card/Card.tsx +1 -1
- package/components/Checkbox/CheckboxBase.ios.tsx +1 -4
- package/components/Checkbox/CheckboxBase.tsx +2 -7
- package/components/DatePicker/DateCalendar.tsx +4 -4
- package/components/DatePicker/DatePickerModal.tsx +2 -1
- package/components/DatePicker/utils.ts +2 -0
- package/components/DatePickerInline/DatePickerDockedHeader.tsx +3 -3
- package/components/DatePickerInline/DatePickerInline.tsx +1 -1
- package/components/DatePickerInline/DatePickerInlineBase.tsx +2 -2
- package/components/DatePickerInline/DatePickerInlineHeader.tsx +43 -17
- package/components/DatePickerInline/HeaderItem.tsx +2 -2
- package/components/DatePickerInline/MonthPicker.tsx +58 -64
- package/components/DatePickerInline/Swiper.native.tsx +2 -2
- package/components/DatePickerInline/Swiper.tsx +3 -3
- package/components/DatePickerInline/YearPicker.tsx +108 -119
- package/components/DatePickerInline/{DatePickerContext.tsx → store.tsx} +7 -3
- package/components/DatePickerInline/types.ts +1 -1
- 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 +275 -0
- package/components/List/context.tsx +26 -0
- package/components/List/index.ts +8 -0
- package/components/List/types.ts +117 -0
- package/components/List/utils.ts +79 -0
- package/components/Menu/Menu.tsx +146 -19
- package/components/Menu/index.tsx +9 -7
- package/components/Menu/utils.ts +21 -70
- package/components/Popover/Popover.tsx +7 -10
- package/components/Popover/PopoverRoot.tsx +6 -20
- package/components/Popover/common.ts +4 -0
- package/components/Popover/index.ts +2 -8
- package/components/Popover/usePlatformMeasure.ts +4 -2
- package/components/RadioButton/RadioButtonAndroid.tsx +38 -54
- package/components/RadioButton/RadioButtonIOS.tsx +2 -16
- package/components/Select/Select.tsx +307 -501
- package/components/Select/context.tsx +39 -32
- package/components/Select/types.ts +63 -56
- package/components/Select/utils.ts +19 -44
- package/components/Text/textFactory.tsx +17 -5
- package/components/TimePicker/TimeInput.tsx +2 -7
- package/components/TimePicker/utils.ts +0 -4
- package/components/TouchableRipple/TouchableRipple.native.tsx +36 -5
- package/components/TouchableRipple/TouchableRipple.tsx +121 -163
- package/components/TouchableRipple/rippleFromForegroundColor.ts +21 -0
- package/package.json +6 -3
- 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/ListItem/utils.ts +0 -115
- 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 { DefaultItemT,
|
|
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 { DefaultItemT, SelectDropdownContextValue, SelectSearchContextValue } 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
|
};
|
|
@@ -61,12 +43,37 @@ const {
|
|
|
61
43
|
Context: SelectDropdownContext,
|
|
62
44
|
} = createFastContext<SelectDropdownContextType>(selectDropdownContextDefaultValue, true);
|
|
63
45
|
|
|
46
|
+
const selectSearchContextDefaultValue: SelectSearchContextValue<DefaultItemT> = {
|
|
47
|
+
searchQuery: '',
|
|
48
|
+
setSearchQuery: () => {},
|
|
49
|
+
allOptions: [],
|
|
50
|
+
options: [],
|
|
51
|
+
optionById: new Map(),
|
|
52
|
+
getOptionId: item => item.id,
|
|
53
|
+
};
|
|
54
|
+
|
|
55
|
+
const {
|
|
56
|
+
useStoreRef: useSelectSearchStoreRef,
|
|
57
|
+
Provider: SelectSearchContextProvider,
|
|
58
|
+
useContext: useSelectSearchContext,
|
|
59
|
+
useContextValue: useSelectSearchContextValue,
|
|
60
|
+
Context: SelectSearchContext,
|
|
61
|
+
} = createFastContext<SelectSearchContextValue<DefaultItemT>>(
|
|
62
|
+
selectSearchContextDefaultValue,
|
|
63
|
+
true,
|
|
64
|
+
);
|
|
65
|
+
|
|
64
66
|
export {
|
|
65
67
|
SelectDropdownContext,
|
|
66
68
|
SelectDropdownContextProvider,
|
|
69
|
+
SelectSearchContext,
|
|
70
|
+
SelectSearchContextProvider,
|
|
67
71
|
useSelectDropdownContext,
|
|
68
72
|
useSelectDropdownContextValue,
|
|
69
73
|
useSelectDropdownStoreRef,
|
|
74
|
+
useSelectSearchContext,
|
|
75
|
+
useSelectSearchContextValue,
|
|
76
|
+
useSelectSearchStoreRef,
|
|
70
77
|
};
|
|
71
78
|
|
|
72
|
-
registerPortalContext([
|
|
79
|
+
registerPortalContext([SelectDropdownContext, SelectSearchContext]);
|
|
@@ -1,33 +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, TextInputProps, ViewProps } from 'react-native';
|
|
8
3
|
|
|
4
|
+
import type { ListContentProps, ListItemId, ListValue } from '../List';
|
|
9
5
|
import type { PopoverProps } from '../Popover';
|
|
10
6
|
|
|
7
|
+
export type { ListContextValue as SelectContextValue } from '../List';
|
|
8
|
+
|
|
11
9
|
export type DefaultItemT = {
|
|
12
10
|
id: string | number;
|
|
13
11
|
label?: string;
|
|
14
12
|
selectable?: boolean;
|
|
15
|
-
[key: string]:
|
|
16
|
-
};
|
|
17
|
-
|
|
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[];
|
|
13
|
+
[key: string]: unknown;
|
|
31
14
|
};
|
|
32
15
|
|
|
33
16
|
// SelectDropdownContext types
|
|
@@ -37,24 +20,61 @@ export type SelectDropdownContextValue = {
|
|
|
37
20
|
onOpen: () => void;
|
|
38
21
|
};
|
|
39
22
|
|
|
23
|
+
export type SelectSearchMode = 'client' | 'external';
|
|
24
|
+
|
|
25
|
+
export type SelectSearchKey<Option extends object = DefaultItemT> =
|
|
26
|
+
| string
|
|
27
|
+
| string[]
|
|
28
|
+
| ((item: Option, query: string) => boolean);
|
|
29
|
+
|
|
30
|
+
export type SelectSearchContextValue<Option extends DefaultItemT = DefaultItemT> = {
|
|
31
|
+
searchQuery: string;
|
|
32
|
+
setSearchQuery: (query: string) => void;
|
|
33
|
+
allOptions: Option[];
|
|
34
|
+
options: Option[];
|
|
35
|
+
optionById: Map<ListItemId, Option>;
|
|
36
|
+
getOptionId: (item: Option) => ListItemId;
|
|
37
|
+
};
|
|
38
|
+
|
|
40
39
|
// SelectProvider props
|
|
41
|
-
|
|
40
|
+
type SelectPropsBase<Option extends DefaultItemT = DefaultItemT> = {
|
|
42
41
|
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
42
|
disabled?: boolean;
|
|
52
43
|
error?: boolean;
|
|
53
|
-
labelKey?: string;
|
|
54
44
|
options: Option[];
|
|
55
|
-
searchKey?:
|
|
45
|
+
searchKey?: SelectSearchKey<Option>;
|
|
46
|
+
searchQuery?: string;
|
|
47
|
+
defaultSearchQuery?: string;
|
|
56
48
|
onSearchChange?: (query: string) => void;
|
|
57
|
-
|
|
49
|
+
searchMode?: SelectSearchMode;
|
|
50
|
+
allowDeselect?: boolean;
|
|
51
|
+
getItemId?: (item: Option) => ListItemId;
|
|
52
|
+
};
|
|
53
|
+
|
|
54
|
+
export type SelectSearchInputProps = Omit<TextInputProps, 'value' | 'onChangeText'>;
|
|
55
|
+
|
|
56
|
+
type SingleSelectProps<Option extends DefaultItemT = DefaultItemT> = {
|
|
57
|
+
multiple?: false | undefined;
|
|
58
|
+
value?: ListValue<false>;
|
|
59
|
+
defaultValue?: ListValue<false>;
|
|
60
|
+
onChange?: (value: ListValue<false>, item: Option, event?: GestureResponderEvent) => void;
|
|
61
|
+
};
|
|
62
|
+
|
|
63
|
+
type MultipleSelectProps<Option extends DefaultItemT = DefaultItemT> = {
|
|
64
|
+
multiple: true;
|
|
65
|
+
value?: ListValue<true>;
|
|
66
|
+
defaultValue?: ListValue<true>;
|
|
67
|
+
onChange?: (value: ListValue<true>, item: Option, event?: GestureResponderEvent) => void;
|
|
68
|
+
};
|
|
69
|
+
|
|
70
|
+
export type SelectProps<Option extends DefaultItemT = DefaultItemT> = SelectPropsBase<Option> &
|
|
71
|
+
(SingleSelectProps<Option> | MultipleSelectProps<Option>);
|
|
72
|
+
|
|
73
|
+
export type SelectContentProps<Option extends DefaultItemT = DefaultItemT> = Omit<
|
|
74
|
+
ListContentProps,
|
|
75
|
+
'children'
|
|
76
|
+
> & {
|
|
77
|
+
children?: ReactNode | ((item: Option, isSelected: boolean) => ReactNode);
|
|
58
78
|
};
|
|
59
79
|
|
|
60
80
|
// Select.Trigger props
|
|
@@ -65,6 +85,7 @@ export type SelectTriggerProps = ViewProps & {
|
|
|
65
85
|
// Select.Value props
|
|
66
86
|
export type SelectValueProps = ViewProps & {
|
|
67
87
|
placeholder?: string;
|
|
88
|
+
labelKey?: string;
|
|
68
89
|
renderValue?: (value: DefaultItemT | DefaultItemT[] | null) => ReactNode;
|
|
69
90
|
};
|
|
70
91
|
|
|
@@ -78,36 +99,22 @@ export type SelectDropdownProps = Omit<
|
|
|
78
99
|
wrapperComponentProps?: Record<string, any>;
|
|
79
100
|
};
|
|
80
101
|
|
|
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
102
|
// Select.Option props
|
|
98
|
-
|
|
103
|
+
// `accessibilityRole` and `role` are intentionally omitted: Select.Option forces them to
|
|
104
|
+
// "option" on web so the dropdown's keyboard navigator (which queries [role="option"]) can
|
|
105
|
+
// always find the rows. Allowing callers to override would silently break keyboard nav.
|
|
106
|
+
export type SelectOptionProps<Option extends DefaultItemT = DefaultItemT> = Omit<
|
|
107
|
+
ViewProps,
|
|
108
|
+
'accessibilityRole' | 'role'
|
|
109
|
+
> & {
|
|
99
110
|
/**
|
|
100
111
|
* Unique id for the option
|
|
101
112
|
*/
|
|
102
113
|
value: Option['id'];
|
|
103
|
-
children
|
|
104
|
-
renderItem?: (item: Option, isSelected: boolean) => ReactNode;
|
|
114
|
+
children: ReactNode;
|
|
105
115
|
onPress?: (item: Option, event: GestureResponderEvent) => void;
|
|
106
116
|
/**
|
|
107
117
|
* When true, the option can't be selected (similar to HTML option disabled)
|
|
108
118
|
*/
|
|
109
119
|
disabled?: boolean;
|
|
110
120
|
};
|
|
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,
|
|
@@ -77,45 +92,15 @@ const triggerDefaultStyles = StyleSheet.create(theme => ({
|
|
|
77
92
|
}));
|
|
78
93
|
|
|
79
94
|
export const defaultStyles = StyleSheet.create(theme => ({
|
|
95
|
+
valueText: {
|
|
96
|
+
flex: 1,
|
|
97
|
+
},
|
|
80
98
|
chipContainer: {
|
|
81
99
|
flexDirection: 'row',
|
|
82
100
|
flexWrap: 'wrap',
|
|
83
101
|
gap: 6,
|
|
84
102
|
maxWidth: '90%',
|
|
85
|
-
|
|
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,
|
|
103
|
+
flex: 1,
|
|
119
104
|
},
|
|
120
105
|
searchInput: {
|
|
121
106
|
marginHorizontal: theme.spacings['2'],
|
|
@@ -124,16 +109,6 @@ export const defaultStyles = StyleSheet.create(theme => ({
|
|
|
124
109
|
searchInputInput: {
|
|
125
110
|
height: 42,
|
|
126
111
|
},
|
|
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
112
|
}));
|
|
138
113
|
|
|
139
114
|
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} />
|
|
@@ -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}
|
|
@@ -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
|