sapo-components-ui-rn 1.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 (215) hide show
  1. package/README.md +69 -0
  2. package/dist/assets/error.png +0 -0
  3. package/dist/assets/icon-checkbox-active.svg +4 -0
  4. package/dist/assets/icon-checkbox.svg +3 -0
  5. package/dist/assets/image_default.png +0 -0
  6. package/dist/assets/images/error.png +0 -0
  7. package/dist/assets/images/image_default.png +0 -0
  8. package/dist/assets/images/info.png +0 -0
  9. package/dist/assets/images/success.png +0 -0
  10. package/dist/assets/images/warning.png +0 -0
  11. package/dist/assets/info.png +0 -0
  12. package/dist/assets/success.png +0 -0
  13. package/dist/assets/svg/icon-checkbox-active.svg +4 -0
  14. package/dist/assets/svg/icon-checkbox.svg +3 -0
  15. package/dist/assets/warning.png +0 -0
  16. package/dist/components/ActivityIndicator.d.ts +28 -0
  17. package/dist/components/Avatar/index.d.ts +17 -0
  18. package/dist/components/Badge/index.d.ts +13 -0
  19. package/dist/components/Button/index.d.ts +23 -0
  20. package/dist/components/ButtonIcon/index.d.ts +18 -0
  21. package/dist/components/Checkbox/index.d.ts +14 -0
  22. package/dist/components/ChipBar/index.d.ts +16 -0
  23. package/dist/components/CountingDot/index.d.ts +13 -0
  24. package/dist/components/FloatingButton/index.d.ts +17 -0
  25. package/dist/components/Icon/index.d.ts +17 -0
  26. package/dist/components/IconSvg/index.d.ts +12 -0
  27. package/dist/components/Image/index.d.ts +14 -0
  28. package/dist/components/ProgressBar.d.ts +42 -0
  29. package/dist/components/RadioButton/index.d.ts +13 -0
  30. package/dist/components/ScaleButton/index.d.ts +4 -0
  31. package/dist/components/SelectionField/index.d.ts +24 -0
  32. package/dist/components/Spacer/index.d.ts +9 -0
  33. package/dist/components/Switch/Switch.d.ts +47 -0
  34. package/dist/components/Switch/utils.d.ts +14 -0
  35. package/dist/components/Text/index.d.ts +14 -0
  36. package/dist/components/TextInput/Addons/Outline.d.ts +15 -0
  37. package/dist/components/TextInput/Addons/Underline.d.ts +19 -0
  38. package/dist/components/TextInput/Adornment/TextInputAdornment.d.ts +43 -0
  39. package/dist/components/TextInput/Adornment/TextInputAffix.d.ts +72 -0
  40. package/dist/components/TextInput/Adornment/enums.d.ts +12 -0
  41. package/dist/components/TextInput/Adornment/types.d.ts +11 -0
  42. package/dist/components/TextInput/Adornment/utils.d.ts +11 -0
  43. package/dist/components/TextInput/Label/InputLabel.d.ts +4 -0
  44. package/dist/components/TextInput/Label/LabelBackground.d.ts +4 -0
  45. package/dist/components/TextInput/TextInput.d.ts +171 -0
  46. package/dist/components/TextInput/TextInputDefault.d.ts +4 -0
  47. package/dist/components/TextInput/TextInputFlat.d.ts +4 -0
  48. package/dist/components/TextInput/constants.d.ts +31 -0
  49. package/dist/components/TextInput/helpers.d.ts +95 -0
  50. package/dist/components/TextInput/types.d.ts +154 -0
  51. package/dist/components/Toast/ToastProvider.d.ts +21 -0
  52. package/dist/components/Toast/index.d.ts +3 -0
  53. package/dist/components/Typography/AnimatedText.d.ts +34 -0
  54. package/dist/components/Typography/StyledText.d.ts +12 -0
  55. package/dist/components/Typography/Text.d.ts +35 -0
  56. package/dist/components/Typography/types.d.ts +2 -0
  57. package/dist/components/View/index.d.ts +38 -0
  58. package/dist/components/ViewVisibleAnimated/index.d.ts +25 -0
  59. package/dist/constants.d.ts +1 -0
  60. package/dist/core/theming.d.ts +43 -0
  61. package/dist/icons/IconArrowDown.d.ts +4 -0
  62. package/dist/icons/IconCheckbox.d.ts +4 -0
  63. package/dist/icons/IconCheckboxActive.d.ts +4 -0
  64. package/dist/icons/IconClearText.d.ts +4 -0
  65. package/dist/icons/IconRadio.d.ts +4 -0
  66. package/dist/icons/IconRadioActive.d.ts +4 -0
  67. package/dist/icons/IconRadioDisable.d.ts +4 -0
  68. package/dist/index.d.ts +33 -0
  69. package/dist/index.esm.js +6758 -0
  70. package/dist/index.esm.js.map +1 -0
  71. package/dist/index.js +6823 -0
  72. package/dist/index.js.map +1 -0
  73. package/dist/styles/fonts.d.ts +78 -0
  74. package/dist/styles/overlay.d.ts +3 -0
  75. package/dist/styles/shadow.d.ts +18 -0
  76. package/dist/styles/themes/DarkTheme.d.ts +2 -0
  77. package/dist/styles/themes/LightTheme.d.ts +2 -0
  78. package/dist/styles/themes/index.d.ts +2 -0
  79. package/dist/styles/themes/tokens.d.ts +830 -0
  80. package/dist/theme/blue.d.ts +14 -0
  81. package/dist/theme/colors.d.ts +99 -0
  82. package/dist/theme/container-styles.d.ts +124 -0
  83. package/dist/theme/dimensions.d.ts +36 -0
  84. package/dist/theme/green.d.ts +15 -0
  85. package/dist/theme/icon.d.ts +5 -0
  86. package/dist/theme/ink.d.ts +11 -0
  87. package/dist/theme/orange.d.ts +14 -0
  88. package/dist/theme/purple.d.ts +6 -0
  89. package/dist/theme/red.d.ts +15 -0
  90. package/dist/theme/themes.d.ts +277 -0
  91. package/dist/theme/white.d.ts +10 -0
  92. package/dist/theme/yellow.d.ts +15 -0
  93. package/dist/types/index.d.ts +65 -0
  94. package/dist/types.d.ts +220 -0
  95. package/dist/utils/BackHandler/BackHandler.d.ts +9 -0
  96. package/dist/utils/BackHandler/BackHandler.native.d.ts +2 -0
  97. package/dist/utils/addEventListener.d.ts +12 -0
  98. package/dist/utils/forwardRef.d.ts +11 -0
  99. package/dist/utils/function-utils.d.ts +12 -0
  100. package/dist/utils/getContrastingColor.d.ts +2 -0
  101. package/dist/utils/hasTouchHandler.d.ts +5 -0
  102. package/dist/utils/roundLayoutSize.d.ts +1 -0
  103. package/dist/utils/splitStyles.d.ts +19 -0
  104. package/dist/utils/toast-manager.d.ts +21 -0
  105. package/dist/utils/useAnimatedValue.d.ts +2 -0
  106. package/dist/utils/useAnimatedValueArray.d.ts +2 -0
  107. package/dist/utils/useIsKeyboardShown.d.ts +6 -0
  108. package/dist/utils/useLayout.d.ts +6 -0
  109. package/dist/utils/useLazyRef.d.ts +2 -0
  110. package/package.json +104 -0
  111. package/src/.DS_Store +0 -0
  112. package/src/assets/images/error.png +0 -0
  113. package/src/assets/images/image_default.png +0 -0
  114. package/src/assets/images/info.png +0 -0
  115. package/src/assets/images/success.png +0 -0
  116. package/src/assets/images/warning.png +0 -0
  117. package/src/assets/svg/icon-checkbox-active.svg +4 -0
  118. package/src/assets/svg/icon-checkbox.svg +3 -0
  119. package/src/babel/.eslintrc +7 -0
  120. package/src/babel/index.js +63 -0
  121. package/src/components/.DS_Store +0 -0
  122. package/src/components/ActivityIndicator.tsx +238 -0
  123. package/src/components/Avatar/index.tsx +102 -0
  124. package/src/components/Badge/index.tsx +55 -0
  125. package/src/components/Button/index.tsx +162 -0
  126. package/src/components/ButtonIcon/index.tsx +98 -0
  127. package/src/components/Checkbox/index.tsx +107 -0
  128. package/src/components/ChipBar/index.tsx +112 -0
  129. package/src/components/CountingDot/index.tsx +63 -0
  130. package/src/components/FloatingButton/index.tsx +99 -0
  131. package/src/components/Icon/index.tsx +135 -0
  132. package/src/components/IconSvg/index.tsx +42 -0
  133. package/src/components/Image/index.tsx +127 -0
  134. package/src/components/ProgressBar.tsx +272 -0
  135. package/src/components/RadioButton/index.tsx +105 -0
  136. package/src/components/ScaleButton/index.tsx +17 -0
  137. package/src/components/SelectionField/index.tsx +166 -0
  138. package/src/components/Spacer/index.tsx +19 -0
  139. package/src/components/Switch/Switch.tsx +110 -0
  140. package/src/components/Switch/utils.ts +96 -0
  141. package/src/components/Text/index.tsx +69 -0
  142. package/src/components/TextInput/.DS_Store +0 -0
  143. package/src/components/TextInput/Addons/Outline.tsx +62 -0
  144. package/src/components/TextInput/Addons/Underline.tsx +71 -0
  145. package/src/components/TextInput/Adornment/TextInputAdornment.tsx +191 -0
  146. package/src/components/TextInput/Adornment/TextInputAffix.tsx +212 -0
  147. package/src/components/TextInput/Adornment/enums.tsx +12 -0
  148. package/src/components/TextInput/Adornment/types.tsx +11 -0
  149. package/src/components/TextInput/Adornment/utils.ts +39 -0
  150. package/src/components/TextInput/Label/InputLabel.tsx +216 -0
  151. package/src/components/TextInput/Label/LabelBackground.tsx +100 -0
  152. package/src/components/TextInput/TextInput.tsx +564 -0
  153. package/src/components/TextInput/TextInputDefault.tsx +187 -0
  154. package/src/components/TextInput/TextInputFlat.tsx +452 -0
  155. package/src/components/TextInput/constants.tsx +48 -0
  156. package/src/components/TextInput/helpers.tsx +546 -0
  157. package/src/components/TextInput/types.tsx +155 -0
  158. package/src/components/Toast/ToastProvider.tsx +69 -0
  159. package/src/components/Toast/index.tsx +239 -0
  160. package/src/components/Typography/AnimatedText.tsx +84 -0
  161. package/src/components/Typography/StyledText.tsx +53 -0
  162. package/src/components/Typography/Text.tsx +189 -0
  163. package/src/components/Typography/types.tsx +5 -0
  164. package/src/components/View/index.tsx +175 -0
  165. package/src/components/ViewVisibleAnimated/index.tsx +199 -0
  166. package/src/constants.tsx +16 -0
  167. package/src/core/theming.tsx +144 -0
  168. package/src/icons/IconArrowDown.tsx +14 -0
  169. package/src/icons/IconCheckbox.tsx +20 -0
  170. package/src/icons/IconCheckboxActive.tsx +18 -0
  171. package/src/icons/IconClearText.tsx +14 -0
  172. package/src/icons/IconRadio.tsx +11 -0
  173. package/src/icons/IconRadioActive.tsx +12 -0
  174. package/src/icons/IconRadioDisable.tsx +12 -0
  175. package/src/index.ts +51 -0
  176. package/src/index.tsx +50 -0
  177. package/src/styles/fonts.tsx +89 -0
  178. package/src/styles/overlay.tsx +69 -0
  179. package/src/styles/shadow.tsx +47 -0
  180. package/src/styles/themes/DarkTheme.tsx +157 -0
  181. package/src/styles/themes/LightTheme.tsx +160 -0
  182. package/src/styles/themes/index.ts +3 -0
  183. package/src/styles/themes/tokens.tsx +481 -0
  184. package/src/theme/blue.ts +25 -0
  185. package/src/theme/colors.ts +21 -0
  186. package/src/theme/container-styles.tsx +126 -0
  187. package/src/theme/dimensions.ts +44 -0
  188. package/src/theme/green.ts +27 -0
  189. package/src/theme/icon.ts +7 -0
  190. package/src/theme/ink.ts +18 -0
  191. package/src/theme/orange.ts +24 -0
  192. package/src/theme/purple.ts +8 -0
  193. package/src/theme/red.ts +26 -0
  194. package/src/theme/themes.tsx +287 -0
  195. package/src/theme/white.ts +16 -0
  196. package/src/theme/yellow.ts +26 -0
  197. package/src/types/index.ts +71 -0
  198. package/src/types/svg.d.ts +5 -0
  199. package/src/types.ts +259 -0
  200. package/src/types.tsx +284 -0
  201. package/src/utils/BackHandler/BackHandler.native.tsx +3 -0
  202. package/src/utils/BackHandler/BackHandler.tsx +11 -0
  203. package/src/utils/addEventListener.tsx +56 -0
  204. package/src/utils/forwardRef.tsx +23 -0
  205. package/src/utils/function-utils.tsx +108 -0
  206. package/src/utils/getContrastingColor.tsx +15 -0
  207. package/src/utils/hasTouchHandler.tsx +23 -0
  208. package/src/utils/roundLayoutSize.ts +2 -0
  209. package/src/utils/splitStyles.ts +60 -0
  210. package/src/utils/toast-manager.tsx +46 -0
  211. package/src/utils/useAnimatedValue.tsx +9 -0
  212. package/src/utils/useAnimatedValueArray.tsx +13 -0
  213. package/src/utils/useIsKeyboardShown.tsx +55 -0
  214. package/src/utils/useLayout.tsx +29 -0
  215. package/src/utils/useLazyRef.tsx +11 -0
@@ -0,0 +1,108 @@
1
+ import React, { forwardRef, memo } from "react";
2
+ import { Animated } from "react-native";
3
+ import isEqual from "lodash/isEqual";
4
+
5
+ // Helper function to check if value is Date object
6
+ function isDateObject(value: any): boolean {
7
+ return value instanceof Date && !isNaN(value.getTime());
8
+ }
9
+
10
+ // Wrapper function for deepEqual to handle Date object comparison
11
+ export function deepEqualWithDate(a: any, b: any): boolean {
12
+ // Handle Date object comparison
13
+ if (isDateObject(a) !== isDateObject(b)) {
14
+ return false;
15
+ }
16
+ if (isDateObject(a) && isDateObject(b)) {
17
+ return a.getTime() === b.getTime();
18
+ }
19
+ return isEqual(a, b);
20
+ }
21
+
22
+ // Wrapper function for deepEqual to handle arguments object comparison
23
+ export function deepEqualWithArguments(a: any, b: any): boolean {
24
+ // Handle arguments object comparison
25
+ if (isArguments(a) !== isArguments(b)) {
26
+ return false;
27
+ }
28
+ return deepEqualWithDate(a, b);
29
+ }
30
+
31
+ // Helper function to check if value is arguments object
32
+ function isArguments(value: any): boolean {
33
+ return Object.prototype.toString.call(value) === "[object Arguments]";
34
+ }
35
+
36
+ export function memoDeepEqual<T>(component: React.ComponentType<T>) {
37
+ return memo(component, (prevProps, nextProps) =>
38
+ deepEqualWithArguments(prevProps, nextProps)
39
+ );
40
+ }
41
+
42
+ export const memoWithRef = (component: any) => {
43
+ return memo(forwardRef(component), (prevProps, nextProps) =>
44
+ isEqual(prevProps, nextProps)
45
+ );
46
+ };
47
+
48
+ export const detectEmail = (email: string) => {
49
+ var re =
50
+ /^(([^<>()\[\]\\.,;:\s@"]+(\.[^<>()\[\]\\.,;:\s@"]+)*)|(".+"))@((\[[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}])|(([a-zA-Z\-0-9]+\.)+[a-zA-Z]{2,}))$/;
51
+ return re.test(email);
52
+ };
53
+
54
+ export const detectUserName = (name: string) => {
55
+ var re =
56
+ /^[a-zA-Z0-9ÀÁÂÃÈÉÊÌÍÒÓÔÕÙÚĂĐĨŨƠàáâãèéêìíòóôõùúăđĩũơƯĂẠẢẤẦẨẪẬẮẰẲẴẶẸẺẼỀỀỂưăạảấầẩẫậắằẳẵặẹẻẽềềểỄỆỈỊỌỎỐỒỔỖỘỚỜỞỠỢỤỦỨỪễệỉịọỏốồổỗộớờởỡợụủứừỬỮỰỲỴÝỶỸửữựỳỵỷỹ ]*$/i;
57
+ return re.test(name);
58
+ };
59
+
60
+ export const detectPhoneNumber = (phoneNum: string) => {
61
+ var filter = /^[0-9]+$/;
62
+ if (filter.test(phoneNum)) {
63
+ return true;
64
+ } else {
65
+ return false;
66
+ }
67
+ };
68
+
69
+ export function withAnimated(
70
+ WrappedComponent: React.ComponentType<any>
71
+ ): React.ComponentType {
72
+ const displayName =
73
+ WrappedComponent.displayName || WrappedComponent.name || "Component";
74
+ class WithAnimated extends React.Component {
75
+ static displayName = `WithAnimated(${displayName})`;
76
+
77
+ render(): React.ReactNode {
78
+ return <WrappedComponent {...this.props} />;
79
+ }
80
+ }
81
+
82
+ return Animated.createAnimatedComponent(WithAnimated);
83
+ }
84
+
85
+ export const phoneValid = (phone: string) => {
86
+ const phoneRegex = /(((\+|)84)|0)(3|5|7|8|9)+([0-9]{8})\b/;
87
+ return phoneRegex.test(phone?.trim());
88
+ };
89
+
90
+ export const lightenColor = (color: string, percent: number) => {
91
+ const num = parseInt(color.slice(1), 16);
92
+ const amt = Math.round(2.55 * percent);
93
+ const R = (num >> 16) + amt;
94
+ const G = ((num >> 8) & 0x00ff) + amt;
95
+ const B = (num & 0x0000ff) + amt;
96
+ return `#${(
97
+ 0x1000000 +
98
+ (R < 255 ? (R < 1 ? 0 : R) : 255) * 0x10000 +
99
+ (G < 255 ? (G < 1 ? 0 : G) : 255) * 0x100 +
100
+ (B < 255 ? (B < 1 ? 0 : B) : 255)
101
+ )
102
+ .toString(16)
103
+ .slice(1)}`;
104
+ };
105
+
106
+ export function getFileExtension(filename: string) {
107
+ return filename.substring(filename.lastIndexOf(".") + 1);
108
+ }
@@ -0,0 +1,15 @@
1
+ import type { ColorValue } from 'react-native';
2
+
3
+ import color from 'color';
4
+
5
+ export default function getContrastingColor(
6
+ input: ColorValue,
7
+ light: string,
8
+ dark: string
9
+ ): string {
10
+ if (typeof input === 'string') {
11
+ return color(input).isLight() ? dark : light;
12
+ }
13
+
14
+ return light;
15
+ }
@@ -0,0 +1,23 @@
1
+ import type { GestureResponderEvent } from 'react-native';
2
+
3
+ const touchableEvents = [
4
+ 'onPress',
5
+ 'onLongPress',
6
+ 'onPressIn',
7
+ 'onPressOut',
8
+ ] as const;
9
+
10
+ type TouchableEventObject = Partial<
11
+ Record<
12
+ (typeof touchableEvents)[number],
13
+ (event: GestureResponderEvent) => void
14
+ >
15
+ >;
16
+
17
+ export default function hasTouchHandler(
18
+ touchableEventObject: TouchableEventObject
19
+ ) {
20
+ return touchableEvents.some((event) => {
21
+ return Boolean(touchableEventObject[event]);
22
+ });
23
+ }
@@ -0,0 +1,2 @@
1
+ export const roundLayoutSize = (size: number): number =>
2
+ Math.round(size * 1000) / 1000;
@@ -0,0 +1,60 @@
1
+ import type { ViewStyle } from 'react-native';
2
+
3
+ type FiltersArray = readonly ((style: keyof ViewStyle) => boolean)[];
4
+
5
+ type MappedTuple<Tuple extends FiltersArray> = {
6
+ [Index in keyof Tuple]: ViewStyle;
7
+ } & { length: Tuple['length'] };
8
+
9
+ type Style = ViewStyle[keyof ViewStyle];
10
+ type Entry = [keyof ViewStyle, Style];
11
+
12
+ /**
13
+ * Utility function to extract styles in separate objects
14
+ *
15
+ * @param styles The style object you want to filter
16
+ * @param filters The filters by which you want to split the styles
17
+ * @returns An array of filtered style objects:
18
+ * - The first style object contains the properties that didn't match any filter
19
+ * - After that there will be a style object for each filter you passed in the same order as the matching filters
20
+ * - A style property will exist in a single style object, the first filter it matched
21
+ */
22
+ export function splitStyles<Tuple extends FiltersArray>(
23
+ styles: ViewStyle,
24
+ ...filters: Tuple
25
+ ) {
26
+ if (process.env.NODE_ENV !== 'production' && filters.length === 0) {
27
+ console.error('No filters were passed when calling splitStyles');
28
+ }
29
+
30
+ // `Object.entries` will be used to iterate over the styles and `Object.fromEntries` will be called before returning
31
+ // Entries which match the given filters will be temporarily stored in `newStyles`
32
+ const newStyles = filters.map(() => [] as Entry[]);
33
+
34
+ // Entries which match no filter
35
+ const rest: Entry[] = [];
36
+
37
+ // Iterate every style property
38
+ outer: for (const item of Object.entries(styles) as Entry[]) {
39
+ // Check each filter
40
+ for (let i = 0; i < filters.length; i++) {
41
+ // Check if filter matches
42
+ if (filters[i](item[0])) {
43
+ newStyles[i].push(item); // Push to temporary filtered entries array
44
+ continue outer; // Skip to checking next style property
45
+ }
46
+ }
47
+
48
+ // Adds to rest styles if not filtered
49
+ rest.push(item);
50
+ }
51
+
52
+ // Put unmatched styles in the beginning
53
+ newStyles.unshift(rest);
54
+
55
+ // Convert arrays of entries into objects
56
+ return newStyles.map((styles) => Object.fromEntries(styles)) as unknown as [
57
+ ViewStyle,
58
+ ...MappedTuple<Tuple>
59
+ ];
60
+ }
@@ -0,0 +1,46 @@
1
+ import React from "react";
2
+
3
+ interface ToastRef {
4
+ show: (params: {
5
+ message?: string;
6
+ duration?: number;
7
+ position?: "top" | "bottom";
8
+ type?: "success" | "info" | "warning" | "error";
9
+ onPress?: () => void;
10
+ title?: string;
11
+ }) => void;
12
+ }
13
+
14
+ export const toastRef = React.createRef<ToastRef>();
15
+
16
+ export const showToast = ({
17
+ message,
18
+ duration = 5000,
19
+ position = "top",
20
+ type = "success",
21
+ onPress = () => {},
22
+ title,
23
+ }: {
24
+ message?: string;
25
+ duration?: number;
26
+ position?: "top" | "bottom";
27
+ type?: "success" | "info" | "warning" | "error";
28
+ onPress?: () => void;
29
+ title?: string;
30
+ }) => {
31
+ if (!toastRef.current) {
32
+ console.warn(
33
+ "Toast component is not mounted. Make sure to add <ToastProvider> to your app."
34
+ );
35
+ return;
36
+ }
37
+
38
+ toastRef.current.show({
39
+ message,
40
+ duration,
41
+ position,
42
+ type,
43
+ onPress,
44
+ title,
45
+ });
46
+ };
@@ -0,0 +1,9 @@
1
+ import { Animated } from 'react-native';
2
+
3
+ import useLazyRef from './useLazyRef';
4
+
5
+ export default function useAnimatedValue(initialValue: number) {
6
+ const { current } = useLazyRef(() => new Animated.Value(initialValue));
7
+
8
+ return current;
9
+ }
@@ -0,0 +1,13 @@
1
+ import * as React from 'react';
2
+ import { Animated } from 'react-native';
3
+
4
+ export default function useAnimatedValueArray(initialValues: number[]) {
5
+ const refs = React.useRef<Animated.Value[]>([]);
6
+
7
+ refs.current.length = initialValues.length;
8
+ initialValues.forEach((initialValue, i) => {
9
+ refs.current[i] = refs.current[i] ?? new Animated.Value(initialValue);
10
+ });
11
+
12
+ return refs.current;
13
+ }
@@ -0,0 +1,55 @@
1
+ import * as React from 'react';
2
+ import { Keyboard, NativeEventSubscription, Platform } from 'react-native';
3
+
4
+ type Props = {
5
+ onShow: () => void;
6
+ onHide: () => void;
7
+ };
8
+ export default function useIsKeyboardShown({ onShow, onHide }: Props) {
9
+ React.useEffect(() => {
10
+ let willShowSubscription: NativeEventSubscription | undefined;
11
+ let willHideSubscription: NativeEventSubscription | undefined;
12
+ let didShowSubscription: NativeEventSubscription | undefined;
13
+ let didHideSubscription: NativeEventSubscription | undefined;
14
+
15
+ if (Platform.OS === 'ios') {
16
+ willShowSubscription = Keyboard.addListener('keyboardWillShow', onShow);
17
+ willHideSubscription = Keyboard.addListener('keyboardWillHide', onHide);
18
+ } else {
19
+ didShowSubscription = Keyboard.addListener('keyboardDidShow', onShow);
20
+ didHideSubscription = Keyboard.addListener('keyboardDidHide', onHide);
21
+ }
22
+
23
+ return () => {
24
+ if (Platform.OS === 'ios') {
25
+ if (willShowSubscription?.remove) {
26
+ willShowSubscription.remove();
27
+ } else {
28
+ // @ts-expect-error: We keep deprecated listener remove method for backwards compat with old RN versions
29
+ Keyboard.removeListener('keyboardWillShow', onShow);
30
+ }
31
+
32
+ if (willHideSubscription?.remove) {
33
+ willHideSubscription.remove();
34
+ } else {
35
+ // @ts-expect-error: We keep deprecated listener remove method for backwards compat with old RN versions
36
+ Keyboard.removeListener('keyboardWillHide', onHide);
37
+ }
38
+ } else {
39
+ if (didShowSubscription?.remove) {
40
+ didShowSubscription.remove();
41
+ } else {
42
+ // @ts-expect-error: We keep deprecated listener remove method for backwards compat with old RN versions
43
+ Keyboard.removeListener('keyboardDidShow', onShow);
44
+ }
45
+
46
+ if (didHideSubscription?.remove) {
47
+ didHideSubscription.remove();
48
+ } else {
49
+ // @ts-expect-error: We keep deprecated listener remove method for backwards compat with old RN versions
50
+ Keyboard.removeListener('keyboardDidHide', onHide);
51
+ }
52
+ }
53
+ };
54
+ }, [onHide, onShow]);
55
+ }
@@ -0,0 +1,29 @@
1
+ import * as React from 'react';
2
+ import type { LayoutChangeEvent } from 'react-native';
3
+
4
+ export default function useLayout() {
5
+ const [layout, setLayout] = React.useState<{
6
+ height: number;
7
+ width: number;
8
+ measured: boolean;
9
+ }>({ height: 0, width: 0, measured: false });
10
+
11
+ const onLayout = React.useCallback(
12
+ (e: LayoutChangeEvent) => {
13
+ const { height, width } = e.nativeEvent.layout;
14
+
15
+ if (height === layout.height && width === layout.width) {
16
+ return;
17
+ }
18
+
19
+ setLayout({
20
+ height,
21
+ width,
22
+ measured: true,
23
+ });
24
+ },
25
+ [layout.height, layout.width]
26
+ );
27
+
28
+ return [layout, onLayout] as const;
29
+ }
@@ -0,0 +1,11 @@
1
+ import * as React from "react";
2
+
3
+ export default function useLazyRef<T>(callback: () => T) {
4
+ const lazyRef = React.useRef<T | undefined>(null);
5
+
6
+ if (lazyRef.current === undefined) {
7
+ lazyRef.current = callback();
8
+ }
9
+
10
+ return lazyRef as React.MutableRefObject<T>;
11
+ }