@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.
Files changed (280) hide show
  1. package/README.md +118 -0
  2. package/lib/typescript/src/components/Alert/Alert.d.ts +32 -0
  3. package/lib/typescript/src/components/Alert/Alert.d.ts.map +1 -0
  4. package/lib/typescript/src/components/Alert/index.d.ts +2 -0
  5. package/lib/typescript/src/components/Alert/index.d.ts.map +1 -0
  6. package/lib/typescript/src/components/Avatar/Avatar.d.ts +21 -0
  7. package/lib/typescript/src/components/Avatar/Avatar.d.ts.map +1 -0
  8. package/lib/typescript/src/components/Avatar/index.d.ts +2 -0
  9. package/lib/typescript/src/components/Avatar/index.d.ts.map +1 -0
  10. package/lib/typescript/src/components/BottomSheet/BottomSheet.d.ts +61 -0
  11. package/lib/typescript/src/components/BottomSheet/BottomSheet.d.ts.map +1 -0
  12. package/lib/typescript/src/components/BottomSheet/index.d.ts +2 -0
  13. package/lib/typescript/src/components/BottomSheet/index.d.ts.map +1 -0
  14. package/lib/typescript/src/components/BottomSheetMenu/BottomSheetMenu.d.ts +28 -0
  15. package/lib/typescript/src/components/BottomSheetMenu/BottomSheetMenu.d.ts.map +1 -0
  16. package/lib/typescript/src/components/BottomSheetMenu/index.d.ts +2 -0
  17. package/lib/typescript/src/components/BottomSheetMenu/index.d.ts.map +1 -0
  18. package/lib/typescript/src/components/Button/Button.d.ts +79 -0
  19. package/lib/typescript/src/components/Button/Button.d.ts.map +1 -0
  20. package/lib/typescript/src/components/Button/index.d.ts +2 -0
  21. package/lib/typescript/src/components/Button/index.d.ts.map +1 -0
  22. package/lib/typescript/src/components/ChatInput/AttachmentsView.d.ts +11 -0
  23. package/lib/typescript/src/components/ChatInput/AttachmentsView.d.ts.map +1 -0
  24. package/lib/typescript/src/components/ChatInput/ChatInput.d.ts +78 -0
  25. package/lib/typescript/src/components/ChatInput/ChatInput.d.ts.map +1 -0
  26. package/lib/typescript/src/components/ChatInput/IconButton.d.ts +16 -0
  27. package/lib/typescript/src/components/ChatInput/IconButton.d.ts.map +1 -0
  28. package/lib/typescript/src/components/ChatInput/MentionsInput.d.ts +13 -0
  29. package/lib/typescript/src/components/ChatInput/MentionsInput.d.ts.map +1 -0
  30. package/lib/typescript/src/components/ChatInput/constants.d.ts +9 -0
  31. package/lib/typescript/src/components/ChatInput/constants.d.ts.map +1 -0
  32. package/lib/typescript/src/components/ChatInput/index.d.ts +4 -0
  33. package/lib/typescript/src/components/ChatInput/index.d.ts.map +1 -0
  34. package/lib/typescript/src/components/ChatInput/mentions.d.ts +26 -0
  35. package/lib/typescript/src/components/ChatInput/mentions.d.ts.map +1 -0
  36. package/lib/typescript/src/components/CheckBox/CheckBox.d.ts +13 -0
  37. package/lib/typescript/src/components/CheckBox/CheckBox.d.ts.map +1 -0
  38. package/lib/typescript/src/components/CheckBox/index.d.ts +2 -0
  39. package/lib/typescript/src/components/CheckBox/index.d.ts.map +1 -0
  40. package/lib/typescript/src/components/Container/Container.d.ts +9 -0
  41. package/lib/typescript/src/components/Container/Container.d.ts.map +1 -0
  42. package/lib/typescript/src/components/Container/index.d.ts +2 -0
  43. package/lib/typescript/src/components/Container/index.d.ts.map +1 -0
  44. package/lib/typescript/src/components/Divider/Divider.d.ts +7 -0
  45. package/lib/typescript/src/components/Divider/Divider.d.ts.map +1 -0
  46. package/lib/typescript/src/components/Divider/index.d.ts +2 -0
  47. package/lib/typescript/src/components/Divider/index.d.ts.map +1 -0
  48. package/lib/typescript/src/components/EmptyView/EmptyView.d.ts +26 -0
  49. package/lib/typescript/src/components/EmptyView/EmptyView.d.ts.map +1 -0
  50. package/lib/typescript/src/components/EmptyView/index.d.ts +2 -0
  51. package/lib/typescript/src/components/EmptyView/index.d.ts.map +1 -0
  52. package/lib/typescript/src/components/FlashList/FlashList.d.ts +14 -0
  53. package/lib/typescript/src/components/FlashList/FlashList.d.ts.map +1 -0
  54. package/lib/typescript/src/components/FlashList/index.d.ts +2 -0
  55. package/lib/typescript/src/components/FlashList/index.d.ts.map +1 -0
  56. package/lib/typescript/src/components/Header/BaseHeader.d.ts +5 -0
  57. package/lib/typescript/src/components/Header/BaseHeader.d.ts.map +1 -0
  58. package/lib/typescript/src/components/Header/Header.d.ts +21 -0
  59. package/lib/typescript/src/components/Header/Header.d.ts.map +1 -0
  60. package/lib/typescript/src/components/Header/ScreenHeader.d.ts +11 -0
  61. package/lib/typescript/src/components/Header/ScreenHeader.d.ts.map +1 -0
  62. package/lib/typescript/src/components/Header/index.d.ts +4 -0
  63. package/lib/typescript/src/components/Header/index.d.ts.map +1 -0
  64. package/lib/typescript/src/components/Input/Input.d.ts +15 -0
  65. package/lib/typescript/src/components/Input/Input.d.ts.map +1 -0
  66. package/lib/typescript/src/components/Input/index.d.ts +2 -0
  67. package/lib/typescript/src/components/Input/index.d.ts.map +1 -0
  68. package/lib/typescript/src/components/Loader/Loader.d.ts +12 -0
  69. package/lib/typescript/src/components/Loader/Loader.d.ts.map +1 -0
  70. package/lib/typescript/src/components/Loader/index.d.ts +2 -0
  71. package/lib/typescript/src/components/Loader/index.d.ts.map +1 -0
  72. package/lib/typescript/src/components/NeetoUIProvider/NeetoUIProvider.d.ts +16 -0
  73. package/lib/typescript/src/components/NeetoUIProvider/NeetoUIProvider.d.ts.map +1 -0
  74. package/lib/typescript/src/components/NeetoUIProvider/index.d.ts +2 -0
  75. package/lib/typescript/src/components/NeetoUIProvider/index.d.ts.map +1 -0
  76. package/lib/typescript/src/components/OnBoarding/OnBoarding.d.ts +22 -0
  77. package/lib/typescript/src/components/OnBoarding/OnBoarding.d.ts.map +1 -0
  78. package/lib/typescript/src/components/OnBoarding/index.d.ts +2 -0
  79. package/lib/typescript/src/components/OnBoarding/index.d.ts.map +1 -0
  80. package/lib/typescript/src/components/ParentView/ParentView.d.ts +13 -0
  81. package/lib/typescript/src/components/ParentView/ParentView.d.ts.map +1 -0
  82. package/lib/typescript/src/components/ParentView/index.d.ts +2 -0
  83. package/lib/typescript/src/components/ParentView/index.d.ts.map +1 -0
  84. package/lib/typescript/src/components/RadioButton/RadioButton.d.ts +12 -0
  85. package/lib/typescript/src/components/RadioButton/RadioButton.d.ts.map +1 -0
  86. package/lib/typescript/src/components/RadioButton/index.d.ts +2 -0
  87. package/lib/typescript/src/components/RadioButton/index.d.ts.map +1 -0
  88. package/lib/typescript/src/components/ScrollView/ScrollView.d.ts +8 -0
  89. package/lib/typescript/src/components/ScrollView/ScrollView.d.ts.map +1 -0
  90. package/lib/typescript/src/components/ScrollView/index.d.ts +2 -0
  91. package/lib/typescript/src/components/ScrollView/index.d.ts.map +1 -0
  92. package/lib/typescript/src/components/SearchBar/SearchBar.d.ts +12 -0
  93. package/lib/typescript/src/components/SearchBar/SearchBar.d.ts.map +1 -0
  94. package/lib/typescript/src/components/SearchBar/index.d.ts +2 -0
  95. package/lib/typescript/src/components/SearchBar/index.d.ts.map +1 -0
  96. package/lib/typescript/src/components/Skeleton/Skeleton.d.ts +41 -0
  97. package/lib/typescript/src/components/Skeleton/Skeleton.d.ts.map +1 -0
  98. package/lib/typescript/src/components/Skeleton/index.d.ts +2 -0
  99. package/lib/typescript/src/components/Skeleton/index.d.ts.map +1 -0
  100. package/lib/typescript/src/components/TextWithUrl/TextWithUrl.d.ts +11 -0
  101. package/lib/typescript/src/components/TextWithUrl/TextWithUrl.d.ts.map +1 -0
  102. package/lib/typescript/src/components/TextWithUrl/index.d.ts +2 -0
  103. package/lib/typescript/src/components/TextWithUrl/index.d.ts.map +1 -0
  104. package/lib/typescript/src/components/Toast/Toast.d.ts +13 -0
  105. package/lib/typescript/src/components/Toast/Toast.d.ts.map +1 -0
  106. package/lib/typescript/src/components/Toast/ToastGlyph.d.ts +4 -0
  107. package/lib/typescript/src/components/Toast/ToastGlyph.d.ts.map +1 -0
  108. package/lib/typescript/src/components/Toast/index.d.ts +2 -0
  109. package/lib/typescript/src/components/Toast/index.d.ts.map +1 -0
  110. package/lib/typescript/src/components/Touchable/Touchable.d.ts +23 -0
  111. package/lib/typescript/src/components/Touchable/Touchable.d.ts.map +1 -0
  112. package/lib/typescript/src/components/Touchable/index.d.ts +2 -0
  113. package/lib/typescript/src/components/Touchable/index.d.ts.map +1 -0
  114. package/lib/typescript/src/components/Typography/Typography.d.ts +64 -0
  115. package/lib/typescript/src/components/Typography/Typography.d.ts.map +1 -0
  116. package/lib/typescript/src/components/Typography/index.d.ts +2 -0
  117. package/lib/typescript/src/components/Typography/index.d.ts.map +1 -0
  118. package/lib/typescript/src/hooks/index.d.ts +4 -0
  119. package/lib/typescript/src/hooks/index.d.ts.map +1 -0
  120. package/lib/typescript/src/hooks/useDebounce.d.ts +2 -0
  121. package/lib/typescript/src/hooks/useDebounce.d.ts.map +1 -0
  122. package/lib/typescript/src/hooks/useNeetoTheme.d.ts +8 -0
  123. package/lib/typescript/src/hooks/useNeetoTheme.d.ts.map +1 -0
  124. package/lib/typescript/src/hooks/useRefreshByUser.d.ts +5 -0
  125. package/lib/typescript/src/hooks/useRefreshByUser.d.ts.map +1 -0
  126. package/lib/typescript/src/index.d.ts +31 -0
  127. package/lib/typescript/src/index.d.ts.map +1 -0
  128. package/lib/typescript/src/theme/palette.d.ts +28 -0
  129. package/lib/typescript/src/theme/palette.d.ts.map +1 -0
  130. package/lib/typescript/src/theme/palette.generated.d.ts +134 -0
  131. package/lib/typescript/src/theme/palette.generated.d.ts.map +1 -0
  132. package/lib/typescript/src/theme/tokens.d.ts +184 -0
  133. package/lib/typescript/src/theme/tokens.d.ts.map +1 -0
  134. package/lib/typescript/src/unistyles-init.d.ts +2 -0
  135. package/lib/typescript/src/unistyles-init.d.ts.map +1 -0
  136. package/lib/typescript/src/unistyles.d.ts +21 -0
  137. package/lib/typescript/src/unistyles.d.ts.map +1 -0
  138. package/lib/typescript/src/utils/index.d.ts +18 -0
  139. package/lib/typescript/src/utils/index.d.ts.map +1 -0
  140. package/lib/typescript/src/utils/scale.d.ts +2 -0
  141. package/lib/typescript/src/utils/scale.d.ts.map +1 -0
  142. package/package.json +125 -51
  143. package/src/components/Alert/Alert.tsx +222 -0
  144. package/src/components/Alert/index.ts +1 -0
  145. package/src/components/Avatar/Avatar.tsx +123 -0
  146. package/src/components/Avatar/index.ts +1 -0
  147. package/src/components/BottomSheet/BottomSheet.tsx +468 -0
  148. package/src/components/BottomSheet/index.ts +5 -0
  149. package/src/components/BottomSheetMenu/BottomSheetMenu.tsx +150 -0
  150. package/src/components/BottomSheetMenu/index.ts +5 -0
  151. package/src/components/Button/Button.tsx +134 -0
  152. package/src/components/Button/index.ts +1 -0
  153. package/src/components/ChatInput/AttachmentsView.tsx +68 -0
  154. package/src/components/ChatInput/ChatInput.tsx +393 -0
  155. package/src/components/ChatInput/IconButton.tsx +52 -0
  156. package/src/components/ChatInput/MentionsInput.tsx +126 -0
  157. package/src/components/ChatInput/constants.ts +18 -0
  158. package/src/components/ChatInput/index.ts +11 -0
  159. package/src/components/ChatInput/mentions.ts +91 -0
  160. package/src/components/CheckBox/CheckBox.tsx +86 -0
  161. package/src/components/CheckBox/index.ts +1 -0
  162. package/src/components/Container/Container.tsx +14 -0
  163. package/src/components/Container/index.ts +1 -0
  164. package/src/components/Divider/Divider.tsx +32 -0
  165. package/src/components/Divider/index.ts +1 -0
  166. package/src/components/EmptyView/EmptyView.tsx +80 -0
  167. package/src/components/EmptyView/index.ts +1 -0
  168. package/src/components/FlashList/FlashList.tsx +162 -0
  169. package/src/components/FlashList/index.ts +1 -0
  170. package/src/components/Header/BaseHeader.tsx +19 -0
  171. package/src/components/Header/Header.tsx +114 -0
  172. package/src/components/Header/ScreenHeader.tsx +34 -0
  173. package/src/components/Header/index.ts +3 -0
  174. package/src/components/Input/Input.tsx +122 -0
  175. package/src/components/Input/index.ts +1 -0
  176. package/src/components/Loader/Loader.tsx +93 -0
  177. package/src/components/Loader/index.ts +1 -0
  178. package/src/components/NeetoUIProvider/NeetoUIProvider.tsx +43 -0
  179. package/src/components/NeetoUIProvider/index.ts +1 -0
  180. package/src/components/OnBoarding/OnBoarding.tsx +177 -0
  181. package/src/components/OnBoarding/index.ts +5 -0
  182. package/src/components/ParentView/ParentView.tsx +98 -0
  183. package/src/components/ParentView/index.ts +1 -0
  184. package/src/components/RadioButton/RadioButton.tsx +80 -0
  185. package/src/components/RadioButton/index.ts +1 -0
  186. package/src/components/ScrollView/ScrollView.tsx +30 -0
  187. package/src/components/ScrollView/index.ts +1 -0
  188. package/src/components/SearchBar/SearchBar.tsx +122 -0
  189. package/src/components/SearchBar/index.ts +1 -0
  190. package/src/components/Skeleton/Skeleton.tsx +121 -0
  191. package/src/components/Skeleton/index.ts +1 -0
  192. package/src/components/TextWithUrl/TextWithUrl.tsx +54 -0
  193. package/src/components/TextWithUrl/index.ts +1 -0
  194. package/src/components/Toast/Toast.tsx +157 -0
  195. package/src/components/Toast/ToastGlyph.tsx +53 -0
  196. package/src/components/Toast/index.ts +1 -0
  197. package/src/components/Touchable/Touchable.tsx +54 -0
  198. package/src/components/Touchable/index.ts +1 -0
  199. package/src/components/Typography/Typography.tsx +76 -0
  200. package/src/components/Typography/index.ts +1 -0
  201. package/src/hooks/index.ts +3 -0
  202. package/src/hooks/useDebounce.ts +17 -0
  203. package/src/hooks/useNeetoTheme.ts +10 -0
  204. package/src/hooks/useRefreshByUser.ts +17 -0
  205. package/src/index.ts +68 -0
  206. package/src/theme/palette.generated.ts +141 -0
  207. package/src/theme/palette.ts +34 -0
  208. package/src/theme/tokens.ts +205 -0
  209. package/src/types/neeto-icons-rn.d.ts +33 -0
  210. package/src/unistyles-init.ts +16 -0
  211. package/src/unistyles.ts +34 -0
  212. package/src/utils/index.ts +41 -0
  213. package/src/utils/scale.ts +16 -0
  214. package/components/Accordion.js +0 -1
  215. package/components/ActionIcon.js +0 -1
  216. package/components/Alert.js +0 -1
  217. package/components/Avatar.js +0 -1
  218. package/components/Badge.js +0 -1
  219. package/components/BottomSheet.js +0 -1
  220. package/components/BottomTabBar.js +0 -1
  221. package/components/Button.js +0 -1
  222. package/components/ButtonGroup.js +0 -1
  223. package/components/Calendar.js +0 -1
  224. package/components/Card.js +0 -1
  225. package/components/Carousel.js +0 -1
  226. package/components/ChatInput/AttachmentsView.js +0 -1
  227. package/components/ChatInput/Badge.js +0 -1
  228. package/components/ChatInput/ChatInput.js +0 -1
  229. package/components/ChatInput/EmailFields.js +0 -1
  230. package/components/ChatInput/IconButton.js +0 -1
  231. package/components/ChatInput/MentionsInputWrapper.js +0 -1
  232. package/components/CheckBox.js +0 -1
  233. package/components/Chip.js +0 -1
  234. package/components/Container.js +0 -1
  235. package/components/Divider.js +0 -1
  236. package/components/FAB.js +0 -1
  237. package/components/FlashList.js +0 -1
  238. package/components/FlatList.js +0 -1
  239. package/components/Input.js +0 -1
  240. package/components/InputEmailChip.js +0 -1
  241. package/components/LineLoader.js +0 -1
  242. package/components/ListItem.js +0 -1
  243. package/components/Loader.js +0 -1
  244. package/components/MultiSelect.js +0 -1
  245. package/components/NotificationIcon.js +0 -1
  246. package/components/NotificationPreferenceList.js +0 -1
  247. package/components/OnBoarding.js +0 -1
  248. package/components/OrganizationItem.js +0 -1
  249. package/components/OtpInputs.js +0 -1
  250. package/components/ParentView.js +0 -1
  251. package/components/Popover.js +0 -1
  252. package/components/RadioButton.js +0 -1
  253. package/components/RichTextEditor.js +0 -1
  254. package/components/Ripple.js +0 -1
  255. package/components/ScrollView.js +0 -1
  256. package/components/SearchBar.js +0 -1
  257. package/components/SegmentedTopBar/Indicator.js +0 -1
  258. package/components/SegmentedTopBar/Tab.js +0 -1
  259. package/components/SegmentedTopBar/index.js +0 -1
  260. package/components/SocialButton.js +0 -1
  261. package/components/Toast.js +0 -1
  262. package/components/ToggleSwitch.js +0 -1
  263. package/components/TopBar.js +0 -1
  264. package/components/Touchable.js +0 -1
  265. package/components/TouchableWithoutFeedback.js +0 -1
  266. package/components/Typography.js +0 -1
  267. package/components/index.js +0 -1
  268. package/config/index.js +0 -1
  269. package/config/toasterConfig.js +0 -1
  270. package/contexts/index.js +0 -1
  271. package/hooks/index.js +0 -1
  272. package/hooks/useDebounce.js +0 -1
  273. package/hooks/useKeyboard.js +0 -1
  274. package/hooks/useRefreshByUser.js +0 -1
  275. package/index.d.ts +0 -630
  276. package/index.js +0 -1
  277. package/react-native.config.js +0 -10
  278. package/theme/index.js +0 -1
  279. package/utils/index.js +0 -1
  280. 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";