@bigbinary/neetoui-rn 2.3.4 → 3.0.0
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 +118 -0
- package/lib/typescript/src/components/Alert/Alert.d.ts +32 -0
- package/lib/typescript/src/components/Alert/Alert.d.ts.map +1 -0
- package/lib/typescript/src/components/Alert/index.d.ts +2 -0
- package/lib/typescript/src/components/Alert/index.d.ts.map +1 -0
- package/lib/typescript/src/components/Avatar/Avatar.d.ts +21 -0
- package/lib/typescript/src/components/Avatar/Avatar.d.ts.map +1 -0
- package/lib/typescript/src/components/Avatar/index.d.ts +2 -0
- package/lib/typescript/src/components/Avatar/index.d.ts.map +1 -0
- package/lib/typescript/src/components/BottomSheet/BottomSheet.d.ts +61 -0
- package/lib/typescript/src/components/BottomSheet/BottomSheet.d.ts.map +1 -0
- package/lib/typescript/src/components/BottomSheet/index.d.ts +2 -0
- package/lib/typescript/src/components/BottomSheet/index.d.ts.map +1 -0
- package/lib/typescript/src/components/BottomSheetMenu/BottomSheetMenu.d.ts +28 -0
- package/lib/typescript/src/components/BottomSheetMenu/BottomSheetMenu.d.ts.map +1 -0
- package/lib/typescript/src/components/BottomSheetMenu/index.d.ts +2 -0
- package/lib/typescript/src/components/BottomSheetMenu/index.d.ts.map +1 -0
- package/lib/typescript/src/components/Button/Button.d.ts +79 -0
- package/lib/typescript/src/components/Button/Button.d.ts.map +1 -0
- package/lib/typescript/src/components/Button/index.d.ts +2 -0
- package/lib/typescript/src/components/Button/index.d.ts.map +1 -0
- package/lib/typescript/src/components/ChatInput/AttachmentsView.d.ts +11 -0
- package/lib/typescript/src/components/ChatInput/AttachmentsView.d.ts.map +1 -0
- package/lib/typescript/src/components/ChatInput/ChatInput.d.ts +78 -0
- package/lib/typescript/src/components/ChatInput/ChatInput.d.ts.map +1 -0
- package/lib/typescript/src/components/ChatInput/IconButton.d.ts +16 -0
- package/lib/typescript/src/components/ChatInput/IconButton.d.ts.map +1 -0
- package/lib/typescript/src/components/ChatInput/MentionsInput.d.ts +13 -0
- package/lib/typescript/src/components/ChatInput/MentionsInput.d.ts.map +1 -0
- package/lib/typescript/src/components/ChatInput/constants.d.ts +9 -0
- package/lib/typescript/src/components/ChatInput/constants.d.ts.map +1 -0
- package/lib/typescript/src/components/ChatInput/index.d.ts +4 -0
- package/lib/typescript/src/components/ChatInput/index.d.ts.map +1 -0
- package/lib/typescript/src/components/ChatInput/mentions.d.ts +26 -0
- package/lib/typescript/src/components/ChatInput/mentions.d.ts.map +1 -0
- package/lib/typescript/src/components/CheckBox/CheckBox.d.ts +13 -0
- package/lib/typescript/src/components/CheckBox/CheckBox.d.ts.map +1 -0
- package/lib/typescript/src/components/CheckBox/index.d.ts +2 -0
- package/lib/typescript/src/components/CheckBox/index.d.ts.map +1 -0
- package/lib/typescript/src/components/Container/Container.d.ts +9 -0
- package/lib/typescript/src/components/Container/Container.d.ts.map +1 -0
- package/lib/typescript/src/components/Container/index.d.ts +2 -0
- package/lib/typescript/src/components/Container/index.d.ts.map +1 -0
- package/lib/typescript/src/components/Divider/Divider.d.ts +7 -0
- package/lib/typescript/src/components/Divider/Divider.d.ts.map +1 -0
- package/lib/typescript/src/components/Divider/index.d.ts +2 -0
- package/lib/typescript/src/components/Divider/index.d.ts.map +1 -0
- package/lib/typescript/src/components/EmptyView/EmptyView.d.ts +26 -0
- package/lib/typescript/src/components/EmptyView/EmptyView.d.ts.map +1 -0
- package/lib/typescript/src/components/EmptyView/index.d.ts +2 -0
- package/lib/typescript/src/components/EmptyView/index.d.ts.map +1 -0
- package/lib/typescript/src/components/FlashList/FlashList.d.ts +14 -0
- package/lib/typescript/src/components/FlashList/FlashList.d.ts.map +1 -0
- package/lib/typescript/src/components/FlashList/index.d.ts +2 -0
- package/lib/typescript/src/components/FlashList/index.d.ts.map +1 -0
- package/lib/typescript/src/components/Header/BaseHeader.d.ts +5 -0
- package/lib/typescript/src/components/Header/BaseHeader.d.ts.map +1 -0
- package/lib/typescript/src/components/Header/Header.d.ts +21 -0
- package/lib/typescript/src/components/Header/Header.d.ts.map +1 -0
- package/lib/typescript/src/components/Header/ScreenHeader.d.ts +11 -0
- package/lib/typescript/src/components/Header/ScreenHeader.d.ts.map +1 -0
- package/lib/typescript/src/components/Header/index.d.ts +4 -0
- package/lib/typescript/src/components/Header/index.d.ts.map +1 -0
- package/lib/typescript/src/components/Input/Input.d.ts +15 -0
- package/lib/typescript/src/components/Input/Input.d.ts.map +1 -0
- package/lib/typescript/src/components/Input/index.d.ts +2 -0
- package/lib/typescript/src/components/Input/index.d.ts.map +1 -0
- package/lib/typescript/src/components/Loader/Loader.d.ts +12 -0
- package/lib/typescript/src/components/Loader/Loader.d.ts.map +1 -0
- package/lib/typescript/src/components/Loader/index.d.ts +2 -0
- package/lib/typescript/src/components/Loader/index.d.ts.map +1 -0
- package/lib/typescript/src/components/NeetoUIProvider/NeetoUIProvider.d.ts +16 -0
- package/lib/typescript/src/components/NeetoUIProvider/NeetoUIProvider.d.ts.map +1 -0
- package/lib/typescript/src/components/NeetoUIProvider/index.d.ts +2 -0
- package/lib/typescript/src/components/NeetoUIProvider/index.d.ts.map +1 -0
- package/lib/typescript/src/components/OnBoarding/OnBoarding.d.ts +22 -0
- package/lib/typescript/src/components/OnBoarding/OnBoarding.d.ts.map +1 -0
- package/lib/typescript/src/components/OnBoarding/index.d.ts +2 -0
- package/lib/typescript/src/components/OnBoarding/index.d.ts.map +1 -0
- package/lib/typescript/src/components/ParentView/ParentView.d.ts +13 -0
- package/lib/typescript/src/components/ParentView/ParentView.d.ts.map +1 -0
- package/lib/typescript/src/components/ParentView/index.d.ts +2 -0
- package/lib/typescript/src/components/ParentView/index.d.ts.map +1 -0
- package/lib/typescript/src/components/RadioButton/RadioButton.d.ts +12 -0
- package/lib/typescript/src/components/RadioButton/RadioButton.d.ts.map +1 -0
- package/lib/typescript/src/components/RadioButton/index.d.ts +2 -0
- package/lib/typescript/src/components/RadioButton/index.d.ts.map +1 -0
- package/lib/typescript/src/components/ScrollView/ScrollView.d.ts +8 -0
- package/lib/typescript/src/components/ScrollView/ScrollView.d.ts.map +1 -0
- package/lib/typescript/src/components/ScrollView/index.d.ts +2 -0
- package/lib/typescript/src/components/ScrollView/index.d.ts.map +1 -0
- package/lib/typescript/src/components/SearchBar/SearchBar.d.ts +12 -0
- package/lib/typescript/src/components/SearchBar/SearchBar.d.ts.map +1 -0
- package/lib/typescript/src/components/SearchBar/index.d.ts +2 -0
- package/lib/typescript/src/components/SearchBar/index.d.ts.map +1 -0
- package/lib/typescript/src/components/Skeleton/Skeleton.d.ts +41 -0
- package/lib/typescript/src/components/Skeleton/Skeleton.d.ts.map +1 -0
- package/lib/typescript/src/components/Skeleton/index.d.ts +2 -0
- package/lib/typescript/src/components/Skeleton/index.d.ts.map +1 -0
- package/lib/typescript/src/components/TextWithUrl/TextWithUrl.d.ts +11 -0
- package/lib/typescript/src/components/TextWithUrl/TextWithUrl.d.ts.map +1 -0
- package/lib/typescript/src/components/TextWithUrl/index.d.ts +2 -0
- package/lib/typescript/src/components/TextWithUrl/index.d.ts.map +1 -0
- package/lib/typescript/src/components/Toast/Toast.d.ts +13 -0
- package/lib/typescript/src/components/Toast/Toast.d.ts.map +1 -0
- package/lib/typescript/src/components/Toast/ToastGlyph.d.ts +4 -0
- package/lib/typescript/src/components/Toast/ToastGlyph.d.ts.map +1 -0
- package/lib/typescript/src/components/Toast/index.d.ts +2 -0
- package/lib/typescript/src/components/Toast/index.d.ts.map +1 -0
- package/lib/typescript/src/components/Touchable/Touchable.d.ts +23 -0
- package/lib/typescript/src/components/Touchable/Touchable.d.ts.map +1 -0
- package/lib/typescript/src/components/Touchable/index.d.ts +2 -0
- package/lib/typescript/src/components/Touchable/index.d.ts.map +1 -0
- package/lib/typescript/src/components/Typography/Typography.d.ts +64 -0
- package/lib/typescript/src/components/Typography/Typography.d.ts.map +1 -0
- package/lib/typescript/src/components/Typography/index.d.ts +2 -0
- package/lib/typescript/src/components/Typography/index.d.ts.map +1 -0
- package/lib/typescript/src/hooks/index.d.ts +4 -0
- package/lib/typescript/src/hooks/index.d.ts.map +1 -0
- package/lib/typescript/src/hooks/useDebounce.d.ts +2 -0
- package/lib/typescript/src/hooks/useDebounce.d.ts.map +1 -0
- package/lib/typescript/src/hooks/useNeetoTheme.d.ts +8 -0
- package/lib/typescript/src/hooks/useNeetoTheme.d.ts.map +1 -0
- package/lib/typescript/src/hooks/useRefreshByUser.d.ts +5 -0
- package/lib/typescript/src/hooks/useRefreshByUser.d.ts.map +1 -0
- package/lib/typescript/src/index.d.ts +31 -0
- package/lib/typescript/src/index.d.ts.map +1 -0
- package/lib/typescript/src/theme/palette.d.ts +28 -0
- package/lib/typescript/src/theme/palette.d.ts.map +1 -0
- package/lib/typescript/src/theme/palette.generated.d.ts +134 -0
- package/lib/typescript/src/theme/palette.generated.d.ts.map +1 -0
- package/lib/typescript/src/theme/tokens.d.ts +184 -0
- package/lib/typescript/src/theme/tokens.d.ts.map +1 -0
- package/lib/typescript/src/unistyles-init.d.ts +2 -0
- package/lib/typescript/src/unistyles-init.d.ts.map +1 -0
- package/lib/typescript/src/unistyles.d.ts +21 -0
- package/lib/typescript/src/unistyles.d.ts.map +1 -0
- package/lib/typescript/src/utils/index.d.ts +18 -0
- package/lib/typescript/src/utils/index.d.ts.map +1 -0
- package/lib/typescript/src/utils/scale.d.ts +2 -0
- package/lib/typescript/src/utils/scale.d.ts.map +1 -0
- package/package.json +125 -51
- package/src/components/Alert/Alert.tsx +222 -0
- package/src/components/Alert/index.ts +1 -0
- package/src/components/Avatar/Avatar.tsx +123 -0
- package/src/components/Avatar/index.ts +1 -0
- package/src/components/BottomSheet/BottomSheet.tsx +468 -0
- package/src/components/BottomSheet/index.ts +5 -0
- package/src/components/BottomSheetMenu/BottomSheetMenu.tsx +150 -0
- package/src/components/BottomSheetMenu/index.ts +5 -0
- package/src/components/Button/Button.tsx +134 -0
- package/src/components/Button/index.ts +1 -0
- package/src/components/ChatInput/AttachmentsView.tsx +68 -0
- package/src/components/ChatInput/ChatInput.tsx +393 -0
- package/src/components/ChatInput/IconButton.tsx +52 -0
- package/src/components/ChatInput/MentionsInput.tsx +126 -0
- package/src/components/ChatInput/constants.ts +18 -0
- package/src/components/ChatInput/index.ts +11 -0
- package/src/components/ChatInput/mentions.ts +91 -0
- package/src/components/CheckBox/CheckBox.tsx +86 -0
- package/src/components/CheckBox/index.ts +1 -0
- package/src/components/Container/Container.tsx +14 -0
- package/src/components/Container/index.ts +1 -0
- package/src/components/Divider/Divider.tsx +32 -0
- package/src/components/Divider/index.ts +1 -0
- package/src/components/EmptyView/EmptyView.tsx +80 -0
- package/src/components/EmptyView/index.ts +1 -0
- package/src/components/FlashList/FlashList.tsx +162 -0
- package/src/components/FlashList/index.ts +1 -0
- package/src/components/Header/BaseHeader.tsx +19 -0
- package/src/components/Header/Header.tsx +114 -0
- package/src/components/Header/ScreenHeader.tsx +34 -0
- package/src/components/Header/index.ts +3 -0
- package/src/components/Input/Input.tsx +122 -0
- package/src/components/Input/index.ts +1 -0
- package/src/components/Loader/Loader.tsx +93 -0
- package/src/components/Loader/index.ts +1 -0
- package/src/components/NeetoUIProvider/NeetoUIProvider.tsx +43 -0
- package/src/components/NeetoUIProvider/index.ts +1 -0
- package/src/components/OnBoarding/OnBoarding.tsx +177 -0
- package/src/components/OnBoarding/index.ts +5 -0
- package/src/components/ParentView/ParentView.tsx +98 -0
- package/src/components/ParentView/index.ts +1 -0
- package/src/components/RadioButton/RadioButton.tsx +80 -0
- package/src/components/RadioButton/index.ts +1 -0
- package/src/components/ScrollView/ScrollView.tsx +30 -0
- package/src/components/ScrollView/index.ts +1 -0
- package/src/components/SearchBar/SearchBar.tsx +122 -0
- package/src/components/SearchBar/index.ts +1 -0
- package/src/components/Skeleton/Skeleton.tsx +121 -0
- package/src/components/Skeleton/index.ts +1 -0
- package/src/components/TextWithUrl/TextWithUrl.tsx +54 -0
- package/src/components/TextWithUrl/index.ts +1 -0
- package/src/components/Toast/Toast.tsx +157 -0
- package/src/components/Toast/ToastGlyph.tsx +53 -0
- package/src/components/Toast/index.ts +1 -0
- package/src/components/Touchable/Touchable.tsx +54 -0
- package/src/components/Touchable/index.ts +1 -0
- package/src/components/Typography/Typography.tsx +76 -0
- package/src/components/Typography/index.ts +1 -0
- package/src/hooks/index.ts +3 -0
- package/src/hooks/useDebounce.ts +17 -0
- package/src/hooks/useNeetoTheme.ts +10 -0
- package/src/hooks/useRefreshByUser.ts +17 -0
- package/src/index.ts +68 -0
- package/src/theme/palette.generated.ts +141 -0
- package/src/theme/palette.ts +34 -0
- package/src/theme/tokens.ts +205 -0
- package/src/types/neeto-icons-rn.d.ts +33 -0
- package/src/unistyles-init.ts +16 -0
- package/src/unistyles.ts +34 -0
- package/src/utils/index.ts +41 -0
- package/src/utils/scale.ts +16 -0
- package/components/Accordion.js +0 -1
- package/components/ActionIcon.js +0 -1
- package/components/Alert.js +0 -1
- package/components/Avatar.js +0 -1
- package/components/Badge.js +0 -1
- package/components/BottomSheet.js +0 -1
- package/components/BottomTabBar.js +0 -1
- package/components/Button.js +0 -1
- package/components/ButtonGroup.js +0 -1
- package/components/Calendar.js +0 -1
- package/components/Card.js +0 -1
- package/components/Carousel.js +0 -1
- package/components/ChatInput/AttachmentsView.js +0 -1
- package/components/ChatInput/Badge.js +0 -1
- package/components/ChatInput/ChatInput.js +0 -1
- package/components/ChatInput/EmailFields.js +0 -1
- package/components/ChatInput/IconButton.js +0 -1
- package/components/ChatInput/MentionsInputWrapper.js +0 -1
- package/components/CheckBox.js +0 -1
- package/components/Chip.js +0 -1
- package/components/Container.js +0 -1
- package/components/Divider.js +0 -1
- package/components/FAB.js +0 -1
- package/components/FlashList.js +0 -1
- package/components/FlatList.js +0 -1
- package/components/Input.js +0 -1
- package/components/InputEmailChip.js +0 -1
- package/components/LineLoader.js +0 -1
- package/components/ListItem.js +0 -1
- package/components/Loader.js +0 -1
- package/components/MultiSelect.js +0 -1
- package/components/NotificationIcon.js +0 -1
- package/components/NotificationPreferenceList.js +0 -1
- package/components/OnBoarding.js +0 -1
- package/components/OrganizationItem.js +0 -1
- package/components/OtpInputs.js +0 -1
- package/components/ParentView.js +0 -1
- package/components/Popover.js +0 -1
- package/components/RadioButton.js +0 -1
- package/components/RichTextEditor.js +0 -1
- package/components/Ripple.js +0 -1
- package/components/ScrollView.js +0 -1
- package/components/SearchBar.js +0 -1
- package/components/SegmentedTopBar/Indicator.js +0 -1
- package/components/SegmentedTopBar/Tab.js +0 -1
- package/components/SegmentedTopBar/index.js +0 -1
- package/components/SocialButton.js +0 -1
- package/components/Toast.js +0 -1
- package/components/ToggleSwitch.js +0 -1
- package/components/TopBar.js +0 -1
- package/components/Touchable.js +0 -1
- package/components/TouchableWithoutFeedback.js +0 -1
- package/components/Typography.js +0 -1
- package/components/index.js +0 -1
- package/config/index.js +0 -1
- package/config/toasterConfig.js +0 -1
- package/contexts/index.js +0 -1
- package/hooks/index.js +0 -1
- package/hooks/useDebounce.js +0 -1
- package/hooks/useKeyboard.js +0 -1
- package/hooks/useRefreshByUser.js +0 -1
- package/index.d.ts +0 -630
- package/index.js +0 -1
- package/react-native.config.js +0 -10
- package/theme/index.js +0 -1
- package/utils/index.js +0 -1
- package/utils/scale.js +0 -1
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export { ParentView, type ParentViewProps } from "./ParentView";
|
|
@@ -0,0 +1,80 @@
|
|
|
1
|
+
import { Radio, RadioInactive } from "@bigbinary/neeto-icons-rn";
|
|
2
|
+
import { type StyleProp, type TextStyle } from "react-native";
|
|
3
|
+
import { StyleSheet, useUnistyles } from "react-native-unistyles";
|
|
4
|
+
|
|
5
|
+
import { moderateScale } from "../../utils/scale";
|
|
6
|
+
import { Touchable, type TouchableProps } from "../Touchable";
|
|
7
|
+
import { Typography } from "../Typography";
|
|
8
|
+
|
|
9
|
+
export type RadioButtonProps = Omit<TouchableProps, "onPress"> & {
|
|
10
|
+
selected?: boolean;
|
|
11
|
+
onSelect?: () => void;
|
|
12
|
+
disabled?: boolean;
|
|
13
|
+
label: string;
|
|
14
|
+
labelStyle?: StyleProp<TextStyle>;
|
|
15
|
+
iconSize?: number;
|
|
16
|
+
};
|
|
17
|
+
|
|
18
|
+
export const RadioButton = ({
|
|
19
|
+
selected = false,
|
|
20
|
+
onSelect,
|
|
21
|
+
disabled = false,
|
|
22
|
+
label,
|
|
23
|
+
labelStyle,
|
|
24
|
+
iconSize,
|
|
25
|
+
style,
|
|
26
|
+
...rest
|
|
27
|
+
}: RadioButtonProps) => {
|
|
28
|
+
const { theme } = useUnistyles();
|
|
29
|
+
|
|
30
|
+
styles.useVariants({ selected, disabled });
|
|
31
|
+
|
|
32
|
+
const Icon = selected ? Radio : RadioInactive;
|
|
33
|
+
|
|
34
|
+
return (
|
|
35
|
+
<Touchable
|
|
36
|
+
accessibilityRole="radio"
|
|
37
|
+
accessibilityState={{ disabled, selected }}
|
|
38
|
+
disabled={disabled}
|
|
39
|
+
style={[styles.container, style]}
|
|
40
|
+
onPress={onSelect}
|
|
41
|
+
{...rest}
|
|
42
|
+
>
|
|
43
|
+
<Typography size="m" style={[styles.label, labelStyle]}>
|
|
44
|
+
{label}
|
|
45
|
+
</Typography>
|
|
46
|
+
<Icon
|
|
47
|
+
color={theme.colors.text.primary}
|
|
48
|
+
size={iconSize ?? moderateScale(22)}
|
|
49
|
+
/>
|
|
50
|
+
</Touchable>
|
|
51
|
+
);
|
|
52
|
+
};
|
|
53
|
+
|
|
54
|
+
const styles = StyleSheet.create(theme => ({
|
|
55
|
+
container: {
|
|
56
|
+
alignItems: "center",
|
|
57
|
+
flexDirection: "row",
|
|
58
|
+
paddingVertical: moderateScale(8),
|
|
59
|
+
},
|
|
60
|
+
label: {
|
|
61
|
+
flex: 1,
|
|
62
|
+
lineHeight: moderateScale(22),
|
|
63
|
+
variants: {
|
|
64
|
+
selected: {
|
|
65
|
+
true: {
|
|
66
|
+
color: theme.colors.text.primary,
|
|
67
|
+
fontFamily: theme.fonts.medium,
|
|
68
|
+
},
|
|
69
|
+
false: {
|
|
70
|
+
color: theme.colors.text.secondary,
|
|
71
|
+
fontFamily: theme.fonts.regular,
|
|
72
|
+
},
|
|
73
|
+
},
|
|
74
|
+
disabled: {
|
|
75
|
+
true: { color: theme.colors.palette.grey400 },
|
|
76
|
+
false: {},
|
|
77
|
+
},
|
|
78
|
+
},
|
|
79
|
+
},
|
|
80
|
+
}));
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export { RadioButton, type RadioButtonProps } from "./RadioButton";
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
import { forwardRef } from "react";
|
|
2
|
+
import {
|
|
3
|
+
ScrollView as RNScrollView,
|
|
4
|
+
type ScrollViewProps as RNScrollViewProps,
|
|
5
|
+
} from "react-native";
|
|
6
|
+
|
|
7
|
+
const GROW_CONTENT = { flexGrow: 1 } as const;
|
|
8
|
+
|
|
9
|
+
export type ScrollViewProps = RNScrollViewProps;
|
|
10
|
+
|
|
11
|
+
/**
|
|
12
|
+
* v2 defaults preserved: taps land while the keyboard is open, no vertical
|
|
13
|
+
* scroll indicator, content grows to fill the viewport.
|
|
14
|
+
*/
|
|
15
|
+
export const ScrollView = forwardRef<RNScrollView, ScrollViewProps>(
|
|
16
|
+
({ children, style, contentContainerStyle, ...rest }, ref) => (
|
|
17
|
+
<RNScrollView
|
|
18
|
+
ref={ref}
|
|
19
|
+
keyboardShouldPersistTaps="handled"
|
|
20
|
+
showsVerticalScrollIndicator={false}
|
|
21
|
+
{...rest}
|
|
22
|
+
contentContainerStyle={[GROW_CONTENT, contentContainerStyle]}
|
|
23
|
+
style={style}
|
|
24
|
+
>
|
|
25
|
+
{children}
|
|
26
|
+
</RNScrollView>
|
|
27
|
+
)
|
|
28
|
+
);
|
|
29
|
+
|
|
30
|
+
ScrollView.displayName = "ScrollView";
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export { ScrollView, type ScrollViewProps } from "./ScrollView";
|
|
@@ -0,0 +1,122 @@
|
|
|
1
|
+
import { useEffect, useRef, useState } from "react";
|
|
2
|
+
import {
|
|
3
|
+
Pressable,
|
|
4
|
+
TextInput,
|
|
5
|
+
type StyleProp,
|
|
6
|
+
type TextInputProps,
|
|
7
|
+
type ViewStyle,
|
|
8
|
+
} from "react-native";
|
|
9
|
+
import { Close, Search } from "@bigbinary/neeto-icons-rn";
|
|
10
|
+
import { StyleSheet, useUnistyles } from "react-native-unistyles";
|
|
11
|
+
|
|
12
|
+
import { useDebounce } from "../../hooks";
|
|
13
|
+
import { moderateScale } from "../../utils/scale";
|
|
14
|
+
import { Touchable } from "../Touchable";
|
|
15
|
+
|
|
16
|
+
export type SearchBarProps = {
|
|
17
|
+
placeholder?: string;
|
|
18
|
+
onChangeText?: (text: string) => void;
|
|
19
|
+
onCancel?: () => void;
|
|
20
|
+
debounceDelay?: number;
|
|
21
|
+
showCancelButton?: boolean;
|
|
22
|
+
containerStyle?: StyleProp<ViewStyle>;
|
|
23
|
+
inputProps?: TextInputProps;
|
|
24
|
+
};
|
|
25
|
+
|
|
26
|
+
export const SearchBar = ({
|
|
27
|
+
placeholder = "Search",
|
|
28
|
+
onChangeText,
|
|
29
|
+
onCancel,
|
|
30
|
+
debounceDelay = 1000,
|
|
31
|
+
showCancelButton = true,
|
|
32
|
+
containerStyle,
|
|
33
|
+
inputProps,
|
|
34
|
+
}: SearchBarProps) => {
|
|
35
|
+
const { theme } = useUnistyles();
|
|
36
|
+
const inputRef = useRef<TextInput>(null);
|
|
37
|
+
const [searchText, setSearchText] = useState("");
|
|
38
|
+
const debouncedSearchText = useDebounce(searchText.trim(), debounceDelay);
|
|
39
|
+
|
|
40
|
+
// Held in a ref so an inline arrow from the call site does not make the
|
|
41
|
+
// effect a per-render callback: the debounced text is what should drive
|
|
42
|
+
// the search, not the identity of the handler.
|
|
43
|
+
const onChangeTextRef = useRef(onChangeText);
|
|
44
|
+
onChangeTextRef.current = onChangeText;
|
|
45
|
+
|
|
46
|
+
const hasEmittedRef = useRef(false);
|
|
47
|
+
|
|
48
|
+
useEffect(() => {
|
|
49
|
+
// Skips the mount pass — emitting "" before the user has typed would
|
|
50
|
+
// clear whatever search the screen restored.
|
|
51
|
+
if (!hasEmittedRef.current) {
|
|
52
|
+
hasEmittedRef.current = true;
|
|
53
|
+
|
|
54
|
+
return;
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
onChangeTextRef.current?.(debouncedSearchText);
|
|
58
|
+
}, [debouncedSearchText]);
|
|
59
|
+
|
|
60
|
+
const handleCancel = () => {
|
|
61
|
+
setSearchText("");
|
|
62
|
+
inputRef.current?.blur();
|
|
63
|
+
onCancel?.();
|
|
64
|
+
};
|
|
65
|
+
|
|
66
|
+
return (
|
|
67
|
+
<Pressable
|
|
68
|
+
style={[styles.container, containerStyle]}
|
|
69
|
+
onPress={() => {
|
|
70
|
+
if (!inputRef.current?.isFocused()) inputRef.current?.focus();
|
|
71
|
+
}}
|
|
72
|
+
>
|
|
73
|
+
<Search color={theme.colors.text.secondary} size={moderateScale(22)} />
|
|
74
|
+
<TextInput
|
|
75
|
+
accessibilityRole="search"
|
|
76
|
+
autoCapitalize="none"
|
|
77
|
+
placeholder={placeholder}
|
|
78
|
+
placeholderTextColor={theme.colors.text.muted}
|
|
79
|
+
ref={inputRef}
|
|
80
|
+
returnKeyType="search"
|
|
81
|
+
style={styles.input}
|
|
82
|
+
value={searchText}
|
|
83
|
+
onChangeText={setSearchText}
|
|
84
|
+
{...inputProps}
|
|
85
|
+
/>
|
|
86
|
+
{showCancelButton && (
|
|
87
|
+
<Touchable
|
|
88
|
+
accessibilityLabel="Clear search"
|
|
89
|
+
style={styles.cancelButton}
|
|
90
|
+
onPress={handleCancel}
|
|
91
|
+
>
|
|
92
|
+
<Close color={theme.colors.text.secondary} size={moderateScale(22)} />
|
|
93
|
+
</Touchable>
|
|
94
|
+
)}
|
|
95
|
+
</Pressable>
|
|
96
|
+
);
|
|
97
|
+
};
|
|
98
|
+
|
|
99
|
+
const styles = StyleSheet.create(theme => ({
|
|
100
|
+
container: {
|
|
101
|
+
alignItems: "center",
|
|
102
|
+
borderColor: theme.colors.palette.grey400,
|
|
103
|
+
borderRadius: moderateScale(8),
|
|
104
|
+
borderWidth: 1,
|
|
105
|
+
flexDirection: "row",
|
|
106
|
+
gap: moderateScale(8),
|
|
107
|
+
height: moderateScale(42),
|
|
108
|
+
paddingHorizontal: moderateScale(8),
|
|
109
|
+
},
|
|
110
|
+
input: {
|
|
111
|
+
color: theme.colors.text.primary,
|
|
112
|
+
flex: 1,
|
|
113
|
+
fontFamily: theme.fonts.regular,
|
|
114
|
+
fontSize: moderateScale(16),
|
|
115
|
+
padding: 0,
|
|
116
|
+
},
|
|
117
|
+
cancelButton: {
|
|
118
|
+
height: "100%",
|
|
119
|
+
justifyContent: "center",
|
|
120
|
+
paddingHorizontal: moderateScale(8),
|
|
121
|
+
},
|
|
122
|
+
}));
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export { SearchBar, type SearchBarProps } from "./SearchBar";
|
|
@@ -0,0 +1,121 @@
|
|
|
1
|
+
import { useEffect } from "react";
|
|
2
|
+
import { View, type DimensionValue, type ViewProps } from "react-native";
|
|
3
|
+
import Animated, {
|
|
4
|
+
cancelAnimation,
|
|
5
|
+
Easing,
|
|
6
|
+
useAnimatedStyle,
|
|
7
|
+
useSharedValue,
|
|
8
|
+
withRepeat,
|
|
9
|
+
withTiming,
|
|
10
|
+
} from "react-native-reanimated";
|
|
11
|
+
import { StyleSheet, type UnistylesVariants } from "react-native-unistyles";
|
|
12
|
+
|
|
13
|
+
import { moderateScale } from "../../utils/scale";
|
|
14
|
+
|
|
15
|
+
type SkeletonVariants = UnistylesVariants<typeof styles>;
|
|
16
|
+
|
|
17
|
+
export type SkeletonProps = ViewProps &
|
|
18
|
+
SkeletonVariants & {
|
|
19
|
+
width?: DimensionValue;
|
|
20
|
+
height?: DimensionValue;
|
|
21
|
+
radius?: number;
|
|
22
|
+
animated?: boolean;
|
|
23
|
+
};
|
|
24
|
+
|
|
25
|
+
/**
|
|
26
|
+
* Promoted component: replaces the fleet's ~14 react-content-loader
|
|
27
|
+
* implementations (and v2's LineLoader) with one Reanimated pulse primitive.
|
|
28
|
+
* The library ships primitives only — screen-specific skeleton layouts
|
|
29
|
+
* recompose these app-side.
|
|
30
|
+
*/
|
|
31
|
+
export const Skeleton = ({
|
|
32
|
+
variant = "rect",
|
|
33
|
+
width,
|
|
34
|
+
height,
|
|
35
|
+
radius,
|
|
36
|
+
animated = true,
|
|
37
|
+
style,
|
|
38
|
+
...rest
|
|
39
|
+
}: SkeletonProps) => {
|
|
40
|
+
const pulse = useSharedValue(0.45);
|
|
41
|
+
|
|
42
|
+
useEffect(() => {
|
|
43
|
+
if (!animated) return undefined;
|
|
44
|
+
|
|
45
|
+
pulse.value = withRepeat(
|
|
46
|
+
withTiming(1, { duration: 700, easing: Easing.inOut(Easing.ease) }),
|
|
47
|
+
-1,
|
|
48
|
+
true
|
|
49
|
+
);
|
|
50
|
+
|
|
51
|
+
// An infinite repeat keeps running after unmount (and after `animated`
|
|
52
|
+
// flips off) unless it is cancelled — a list of skeleton rows would
|
|
53
|
+
// otherwise leave one live animation behind per row.
|
|
54
|
+
return () => cancelAnimation(pulse);
|
|
55
|
+
}, [animated, pulse]);
|
|
56
|
+
|
|
57
|
+
const animatedStyle = useAnimatedStyle(() => ({
|
|
58
|
+
opacity: animated ? pulse.value : 1,
|
|
59
|
+
}));
|
|
60
|
+
|
|
61
|
+
styles.useVariants({ variant });
|
|
62
|
+
|
|
63
|
+
const size = {
|
|
64
|
+
width: width ?? (variant === "circle" ? moderateScale(40) : "100%"),
|
|
65
|
+
height:
|
|
66
|
+
height ??
|
|
67
|
+
(variant === "line"
|
|
68
|
+
? moderateScale(12)
|
|
69
|
+
: variant === "circle"
|
|
70
|
+
? moderateScale(40)
|
|
71
|
+
: moderateScale(48)),
|
|
72
|
+
};
|
|
73
|
+
|
|
74
|
+
return (
|
|
75
|
+
<Animated.View style={animatedStyle}>
|
|
76
|
+
<View
|
|
77
|
+
{...rest}
|
|
78
|
+
style={[
|
|
79
|
+
styles.base,
|
|
80
|
+
size,
|
|
81
|
+
radius !== undefined && { borderRadius: radius },
|
|
82
|
+
style,
|
|
83
|
+
]}
|
|
84
|
+
/>
|
|
85
|
+
</Animated.View>
|
|
86
|
+
);
|
|
87
|
+
};
|
|
88
|
+
|
|
89
|
+
type SkeletonGroupProps = {
|
|
90
|
+
count: number;
|
|
91
|
+
gap?: number;
|
|
92
|
+
children: React.ReactNode;
|
|
93
|
+
};
|
|
94
|
+
|
|
95
|
+
/** Repeat a skeleton row layout `count` times. */
|
|
96
|
+
const SkeletonGroup = ({
|
|
97
|
+
count,
|
|
98
|
+
gap = moderateScale(12),
|
|
99
|
+
children,
|
|
100
|
+
}: SkeletonGroupProps) => (
|
|
101
|
+
<View style={{ gap }}>
|
|
102
|
+
{Array.from({ length: count }, (_, index) => (
|
|
103
|
+
<View key={index}>{children}</View>
|
|
104
|
+
))}
|
|
105
|
+
</View>
|
|
106
|
+
);
|
|
107
|
+
|
|
108
|
+
Skeleton.Group = SkeletonGroup;
|
|
109
|
+
|
|
110
|
+
const styles = StyleSheet.create(theme => ({
|
|
111
|
+
base: {
|
|
112
|
+
backgroundColor: theme.colors.palette.grey200,
|
|
113
|
+
variants: {
|
|
114
|
+
variant: {
|
|
115
|
+
rect: { borderRadius: moderateScale(6) },
|
|
116
|
+
line: { borderRadius: moderateScale(4) },
|
|
117
|
+
circle: { borderRadius: 9999 },
|
|
118
|
+
},
|
|
119
|
+
},
|
|
120
|
+
},
|
|
121
|
+
}));
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export { Skeleton, type SkeletonProps } from "./Skeleton";
|
|
@@ -0,0 +1,54 @@
|
|
|
1
|
+
import { Linking } from "react-native";
|
|
2
|
+
import { StyleSheet } from "react-native-unistyles";
|
|
3
|
+
|
|
4
|
+
import { Typography, type TypographyProps } from "../Typography";
|
|
5
|
+
|
|
6
|
+
const URL_EMAIL_REGEX =
|
|
7
|
+
/(https?:\/\/[^\s]+)|(\b[A-Za-z0-9._%+-]+@[A-Za-z0-9.-]+\.[A-Z|a-z]{2,}\b)/g;
|
|
8
|
+
const EMAIL_REGEX = /^[A-Z0-9._%+-]+@[A-Z0-9.-]+\.[A-Z]{2,}$/i;
|
|
9
|
+
|
|
10
|
+
export type TextWithUrlProps = Omit<TypographyProps, "children"> & {
|
|
11
|
+
text?: string | number;
|
|
12
|
+
};
|
|
13
|
+
|
|
14
|
+
/**
|
|
15
|
+
* Renders text with tappable http(s) links and email addresses
|
|
16
|
+
* (promoted from neeto-commons-rn, same splitting regexes). Links render
|
|
17
|
+
* inline as nested Text, so wrapping behaves like plain copy.
|
|
18
|
+
*/
|
|
19
|
+
export const TextWithUrl = ({ text = "", ...rest }: TextWithUrlProps) => {
|
|
20
|
+
if (typeof text !== "string") {
|
|
21
|
+
return <Typography {...rest}>{text}</Typography>;
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
const parts = text.split(URL_EMAIL_REGEX).filter(Boolean);
|
|
25
|
+
|
|
26
|
+
return (
|
|
27
|
+
<Typography {...rest}>
|
|
28
|
+
{parts.map((part, index) => {
|
|
29
|
+
if (!URL_EMAIL_REGEX.test(part)) return part;
|
|
30
|
+
// Reset lastIndex — the regex is global and test() advances it.
|
|
31
|
+
URL_EMAIL_REGEX.lastIndex = 0;
|
|
32
|
+
const isEmail = EMAIL_REGEX.test(part);
|
|
33
|
+
|
|
34
|
+
return (
|
|
35
|
+
<Typography
|
|
36
|
+
key={`${part}-${index}`}
|
|
37
|
+
style={styles.link}
|
|
38
|
+
suppressHighlighting={false}
|
|
39
|
+
{...rest}
|
|
40
|
+
onPress={() => Linking.openURL(isEmail ? `mailto:${part}` : part)}
|
|
41
|
+
>
|
|
42
|
+
{part}
|
|
43
|
+
</Typography>
|
|
44
|
+
);
|
|
45
|
+
})}
|
|
46
|
+
</Typography>
|
|
47
|
+
);
|
|
48
|
+
};
|
|
49
|
+
|
|
50
|
+
const styles = StyleSheet.create(theme => ({
|
|
51
|
+
link: {
|
|
52
|
+
color: theme.colors.palette.lightBlue400,
|
|
53
|
+
},
|
|
54
|
+
}));
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export { TextWithUrl, type TextWithUrlProps } from "./TextWithUrl";
|
|
@@ -0,0 +1,157 @@
|
|
|
1
|
+
import { useCallback, useEffect, useRef } from "react";
|
|
2
|
+
import { Pressable, View, useWindowDimensions } from "react-native";
|
|
3
|
+
import { Close } from "@bigbinary/neeto-icons-rn";
|
|
4
|
+
import ToastMessage, {
|
|
5
|
+
type ToastConfig,
|
|
6
|
+
type ToastConfigParams,
|
|
7
|
+
type ToastShowParams,
|
|
8
|
+
type ToastProps,
|
|
9
|
+
} from "react-native-toast-message";
|
|
10
|
+
import { StyleSheet, useUnistyles } from "react-native-unistyles";
|
|
11
|
+
|
|
12
|
+
import { moderateScale } from "../../utils/scale";
|
|
13
|
+
import { Typography } from "../Typography";
|
|
14
|
+
import { ToastGlyph } from "./ToastGlyph";
|
|
15
|
+
|
|
16
|
+
// v2 rule: error toasts with long descriptions stay up longer.
|
|
17
|
+
const LONG_ERROR_DURATION = 10000;
|
|
18
|
+
const DEFAULT_DURATION = 4000;
|
|
19
|
+
|
|
20
|
+
const ToastView = ({
|
|
21
|
+
type,
|
|
22
|
+
text1,
|
|
23
|
+
text2,
|
|
24
|
+
hide,
|
|
25
|
+
isVisible,
|
|
26
|
+
}: ToastConfigParams<unknown>) => {
|
|
27
|
+
const { theme } = useUnistyles();
|
|
28
|
+
const { width } = useWindowDimensions();
|
|
29
|
+
const timerRef = useRef<ReturnType<typeof setTimeout> | null>(null);
|
|
30
|
+
|
|
31
|
+
// Held in a ref so a fresh `hide` identity from the host cannot restart
|
|
32
|
+
// the countdown on every render.
|
|
33
|
+
const hideRef = useRef(hide);
|
|
34
|
+
hideRef.current = hide;
|
|
35
|
+
|
|
36
|
+
const duration =
|
|
37
|
+
type === "error" && (text2?.length ?? 0) >= 25
|
|
38
|
+
? LONG_ERROR_DURATION
|
|
39
|
+
: DEFAULT_DURATION;
|
|
40
|
+
|
|
41
|
+
const clearTimer = useCallback(() => {
|
|
42
|
+
if (timerRef.current) {
|
|
43
|
+
clearTimeout(timerRef.current);
|
|
44
|
+
timerRef.current = null;
|
|
45
|
+
}
|
|
46
|
+
}, []);
|
|
47
|
+
|
|
48
|
+
const startTimer = useCallback(() => {
|
|
49
|
+
clearTimer();
|
|
50
|
+
timerRef.current = setTimeout(() => hideRef.current(), duration);
|
|
51
|
+
}, [clearTimer, duration]);
|
|
52
|
+
|
|
53
|
+
// The card owns its timer (v2 behavior): holding the card pauses
|
|
54
|
+
// dismissal, releasing it resumes, long error copy gets more reading time.
|
|
55
|
+
useEffect(() => {
|
|
56
|
+
if (!isVisible) return undefined;
|
|
57
|
+
|
|
58
|
+
startTimer();
|
|
59
|
+
|
|
60
|
+
return clearTimer;
|
|
61
|
+
}, [isVisible, startTimer, clearTimer]);
|
|
62
|
+
|
|
63
|
+
const accentColor =
|
|
64
|
+
theme.colors.toast[type as keyof typeof theme.colors.toast] ??
|
|
65
|
+
theme.colors.toast.info;
|
|
66
|
+
|
|
67
|
+
return (
|
|
68
|
+
<Pressable
|
|
69
|
+
style={[styles.card, { width: width - moderateScale(20) }]}
|
|
70
|
+
onPressIn={clearTimer}
|
|
71
|
+
onPressOut={startTimer}
|
|
72
|
+
>
|
|
73
|
+
<View style={[styles.iconSquare, { backgroundColor: accentColor }]}>
|
|
74
|
+
<ToastGlyph type={type} />
|
|
75
|
+
</View>
|
|
76
|
+
<View style={styles.textBlock}>
|
|
77
|
+
{!!text1 && (
|
|
78
|
+
<Typography numberOfLines={10} size="l" weight="semibold">
|
|
79
|
+
{text1}
|
|
80
|
+
</Typography>
|
|
81
|
+
)}
|
|
82
|
+
{!!text2 && (
|
|
83
|
+
<Typography numberOfLines={10} size="xs" style={styles.description}>
|
|
84
|
+
{text2}
|
|
85
|
+
</Typography>
|
|
86
|
+
)}
|
|
87
|
+
</View>
|
|
88
|
+
<Pressable
|
|
89
|
+
accessibilityLabel="Dismiss toast"
|
|
90
|
+
hitSlop={moderateScale(5)}
|
|
91
|
+
onPress={() => {
|
|
92
|
+
clearTimer();
|
|
93
|
+
hide();
|
|
94
|
+
}}
|
|
95
|
+
>
|
|
96
|
+
<Close color={theme.colors.palette.grey500} size={moderateScale(22)} />
|
|
97
|
+
</Pressable>
|
|
98
|
+
</Pressable>
|
|
99
|
+
);
|
|
100
|
+
};
|
|
101
|
+
|
|
102
|
+
const renderToast = (params: ToastConfigParams<unknown>) => (
|
|
103
|
+
<ToastView {...params} />
|
|
104
|
+
);
|
|
105
|
+
|
|
106
|
+
export const defaultToasterConfig: ToastConfig = {
|
|
107
|
+
success: renderToast,
|
|
108
|
+
error: renderToast,
|
|
109
|
+
info: renderToast,
|
|
110
|
+
warning: renderToast,
|
|
111
|
+
};
|
|
112
|
+
|
|
113
|
+
/**
|
|
114
|
+
* Host component. NeetoUIProvider mounts it automatically; the bare export
|
|
115
|
+
* remains for incremental adoption (v2 required apps to mount <Toast />
|
|
116
|
+
* themselves).
|
|
117
|
+
*/
|
|
118
|
+
export const Toast = ({ config, ...rest }: ToastProps) => (
|
|
119
|
+
<ToastMessage {...rest} config={{ ...defaultToasterConfig, ...config }} />
|
|
120
|
+
);
|
|
121
|
+
|
|
122
|
+
// v2 statics, unchanged signatures. autoHide is off by default because the
|
|
123
|
+
// card runs its own v2 timer (press-to-pause, long-error duration);
|
|
124
|
+
// callers passing autoHide/visibilityTime still win.
|
|
125
|
+
Toast.show = (params: ToastShowParams) =>
|
|
126
|
+
ToastMessage.show({ autoHide: false, ...params });
|
|
127
|
+
Toast.hide = () => ToastMessage.hide();
|
|
128
|
+
|
|
129
|
+
const styles = StyleSheet.create(theme => ({
|
|
130
|
+
card: {
|
|
131
|
+
alignItems: "center",
|
|
132
|
+
backgroundColor: theme.colors.background.secondary,
|
|
133
|
+
borderRadius: moderateScale(16),
|
|
134
|
+
flexDirection: "row",
|
|
135
|
+
gap: moderateScale(10),
|
|
136
|
+
marginHorizontal: moderateScale(10),
|
|
137
|
+
minHeight: moderateScale(60),
|
|
138
|
+
paddingHorizontal: moderateScale(10),
|
|
139
|
+
paddingVertical: moderateScale(8),
|
|
140
|
+
...theme.elevation.high,
|
|
141
|
+
},
|
|
142
|
+
iconSquare: {
|
|
143
|
+
alignItems: "center",
|
|
144
|
+
borderRadius: moderateScale(10),
|
|
145
|
+
height: moderateScale(42),
|
|
146
|
+
justifyContent: "center",
|
|
147
|
+
width: moderateScale(42),
|
|
148
|
+
},
|
|
149
|
+
textBlock: {
|
|
150
|
+
flex: 1,
|
|
151
|
+
gap: moderateScale(2),
|
|
152
|
+
paddingVertical: moderateScale(3),
|
|
153
|
+
},
|
|
154
|
+
description: {
|
|
155
|
+
color: theme.colors.text.secondary,
|
|
156
|
+
},
|
|
157
|
+
}));
|
|
@@ -0,0 +1,53 @@
|
|
|
1
|
+
import Svg, { Path } from "react-native-svg";
|
|
2
|
+
|
|
3
|
+
import { moderateScale } from "../../utils/scale";
|
|
4
|
+
|
|
5
|
+
type GlyphProps = { paths: string[] };
|
|
6
|
+
|
|
7
|
+
const Glyph = ({ paths }: GlyphProps) => (
|
|
8
|
+
<Svg
|
|
9
|
+
fill="none"
|
|
10
|
+
height={moderateScale(20)}
|
|
11
|
+
viewBox="0 0 20 20"
|
|
12
|
+
width={moderateScale(20)}
|
|
13
|
+
>
|
|
14
|
+
{paths.map(d => (
|
|
15
|
+
<Path
|
|
16
|
+
d={d}
|
|
17
|
+
key={d}
|
|
18
|
+
stroke="white"
|
|
19
|
+
strokeLinecap="round"
|
|
20
|
+
strokeLinejoin="round"
|
|
21
|
+
strokeWidth={1.5}
|
|
22
|
+
/>
|
|
23
|
+
))}
|
|
24
|
+
</Svg>
|
|
25
|
+
);
|
|
26
|
+
|
|
27
|
+
// Exact v2 glyphs (assets/icons/{success,error,info,warning}.svg), inlined
|
|
28
|
+
// through react-native-svg so no asset bundling or metro svg-transformer
|
|
29
|
+
// config is needed in consumer apps. White strokes sit on the per-type
|
|
30
|
+
// colored square, both platforms, both themes.
|
|
31
|
+
const GLYPH_PATHS: Record<string, string[]> = {
|
|
32
|
+
success: ["M14.5832 7.5L7.49984 14.5833L4.1665 11.25"],
|
|
33
|
+
error: ["M5 5L15 15", "M15 5L5 15"],
|
|
34
|
+
info: [
|
|
35
|
+
"M9.17432 9.37415H10.1327V12.9158",
|
|
36
|
+
"M9.1665 12.9155H11.091",
|
|
37
|
+
"M10.0832 6.87154C10.0832 6.91275 10.071 6.95302 10.0481 6.98729C10.0252 7.02155 9.99263 7.04825 9.95456 7.06402C9.9165 7.07978 9.87461 7.08391 9.83419 7.07587C9.79378 7.06783 9.75666 7.04799 9.72752 7.01886C9.69839 6.98972 9.67855 6.9526 9.67051 6.91218C9.66247 6.87177 9.66659 6.82988 9.68236 6.79182C9.69813 6.75375 9.72483 6.72121 9.75909 6.69832C9.79335 6.67543 9.83363 6.66321 9.87484 6.66321",
|
|
38
|
+
"M9.875 6.66321C9.93025 6.66321 9.98324 6.68516 10.0223 6.72423C10.0614 6.7633 10.0833 6.81629 10.0833 6.87154",
|
|
39
|
+
"M13.3333 2.4989H6.66667C4.36548 2.4989 2.5 4.36438 2.5 6.66557V13.3322C2.5 15.6334 4.36548 17.4989 6.66667 17.4989H13.3333C15.6345 17.4989 17.5 15.6334 17.5 13.3322V6.66557C17.5 4.36438 15.6345 2.4989 13.3333 2.4989Z",
|
|
40
|
+
],
|
|
41
|
+
warning: [
|
|
42
|
+
"M10 10.9333V7.81665",
|
|
43
|
+
"M9.99901 13.4375C9.88401 13.4375 9.79068 13.5308 9.79151 13.6458C9.79151 13.7608 9.88484 13.8542 9.99984 13.8542C10.1148 13.8542 10.2082 13.7608 10.2082 13.6458C10.2082 13.5308 10.1148 13.4375 9.99901 13.4375Z",
|
|
44
|
+
"M11.522 4.20233L17.2666 14.0877C17.9341 15.2367 17.0903 16.6667 15.7447 16.6667H4.25566C2.90934 16.6667 2.06555 15.2367 2.73383 14.0877L8.47838 4.20233C9.15116 3.04372 10.8492 3.04372 11.522 4.20233Z",
|
|
45
|
+
],
|
|
46
|
+
};
|
|
47
|
+
|
|
48
|
+
export const ToastGlyph = ({ type }: { type: string }) => {
|
|
49
|
+
const paths = GLYPH_PATHS[type];
|
|
50
|
+
if (!paths) return null;
|
|
51
|
+
|
|
52
|
+
return <Glyph paths={paths} />;
|
|
53
|
+
};
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export { Toast, defaultToasterConfig } from "./Toast";
|
|
@@ -0,0 +1,54 @@
|
|
|
1
|
+
import { forwardRef } from "react";
|
|
2
|
+
import {
|
|
3
|
+
Pressable,
|
|
4
|
+
type PressableProps,
|
|
5
|
+
type StyleProp,
|
|
6
|
+
type View,
|
|
7
|
+
type ViewStyle,
|
|
8
|
+
} from "react-native";
|
|
9
|
+
|
|
10
|
+
import { getShadowStyles, isAndroid } from "../../utils";
|
|
11
|
+
|
|
12
|
+
/**
|
|
13
|
+
* v2's rippleConfig, minus the fields the Pressable rebuild cannot honor.
|
|
14
|
+
* v2 rendered ripples through a custom 282-line Ripple implementation on both
|
|
15
|
+
* platforms; v3 uses the platform ripple on Android and an opacity dip on iOS,
|
|
16
|
+
* so isCentered/isSequential/shouldFade/size/duration no longer apply.
|
|
17
|
+
*/
|
|
18
|
+
type RippleConfig = {
|
|
19
|
+
color?: string;
|
|
20
|
+
shouldOverflowContainer?: boolean;
|
|
21
|
+
};
|
|
22
|
+
|
|
23
|
+
export type TouchableProps = Omit<PressableProps, "style"> & {
|
|
24
|
+
elevation?: number;
|
|
25
|
+
rippleConfig?: RippleConfig;
|
|
26
|
+
style?: StyleProp<ViewStyle>;
|
|
27
|
+
};
|
|
28
|
+
|
|
29
|
+
export const Touchable = forwardRef<View, TouchableProps>(
|
|
30
|
+
({ children, elevation, rippleConfig, style, ...rest }, ref) => {
|
|
31
|
+
const shadowStyle = elevation ? getShadowStyles(elevation) : null;
|
|
32
|
+
|
|
33
|
+
return (
|
|
34
|
+
<Pressable
|
|
35
|
+
ref={ref}
|
|
36
|
+
{...rest}
|
|
37
|
+
android_ripple={{
|
|
38
|
+
color: rippleConfig?.color ?? "rgba(0, 0, 0, 0.09)",
|
|
39
|
+
borderless: rippleConfig?.shouldOverflowContainer ?? false,
|
|
40
|
+
foreground: true,
|
|
41
|
+
}}
|
|
42
|
+
style={({ pressed }) => [
|
|
43
|
+
shadowStyle,
|
|
44
|
+
style,
|
|
45
|
+
pressed && !isAndroid() && { opacity: 0.7 },
|
|
46
|
+
]}
|
|
47
|
+
>
|
|
48
|
+
{children}
|
|
49
|
+
</Pressable>
|
|
50
|
+
);
|
|
51
|
+
}
|
|
52
|
+
);
|
|
53
|
+
|
|
54
|
+
Touchable.displayName = "Touchable";
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export { Touchable, type TouchableProps } from "./Touchable";
|