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,107 @@
1
+ import React, { useState, useCallback, useMemo, useEffect } from "react";
2
+ import { StyleProp, ViewStyle, StyleSheet, TextStyle } from "react-native";
3
+ import View from "../View";
4
+ import { CONSTANTS } from "../../styles/themes/tokens";
5
+ import Text from "../Text";
6
+ import { useInternalTheme } from "../../core/theming";
7
+ import containerStyles from "../../theme/container-styles";
8
+ import Icon from "../Icon";
9
+
10
+ interface CheckboxProps {
11
+ style?: StyleProp<ViewStyle>;
12
+ content: string;
13
+ onPress?: (val?: any) => void;
14
+ textStyle?: StyleProp<TextStyle>;
15
+ disabled?: boolean;
16
+ leftIcon?: React.ReactNode;
17
+ checked?: boolean;
18
+ iconSize?: number;
19
+ }
20
+
21
+ const useCheckboxColor = (isActive: boolean, disabled: boolean) => {
22
+ const theme = useInternalTheme();
23
+ const { colors } = theme;
24
+
25
+ return useMemo(() => {
26
+ if (disabled) {
27
+ return colors.iconPrimaryDisabled;
28
+ }
29
+ if (isActive) {
30
+ return colors.iconBrandDefault;
31
+ }
32
+ return colors.surfacePrimaryDefault;
33
+ }, [isActive, disabled, colors]);
34
+ };
35
+
36
+ const Checkbox = ({
37
+ style,
38
+ content = "content",
39
+ textStyle,
40
+ onPress,
41
+ disabled = false,
42
+ leftIcon,
43
+ checked = false,
44
+ iconSize = 24,
45
+ }: CheckboxProps) => {
46
+ const theme = useInternalTheme();
47
+ const { colors } = theme;
48
+ const [isActive, setActive] = useState<boolean>(checked);
49
+ const checkboxColor = useCheckboxColor(isActive, disabled);
50
+
51
+ const handlePressChipBar = useCallback(() => {
52
+ setActive(!isActive);
53
+ onPress?.();
54
+ }, [isActive, onPress]);
55
+
56
+ useEffect(() => {
57
+ setActive(checked);
58
+ }, [checked]);
59
+
60
+ return (
61
+ <View
62
+ row
63
+ disabled={disabled}
64
+ alignCenter
65
+ style={[style]}
66
+ onPress={handlePressChipBar}
67
+ >
68
+ {leftIcon ? (
69
+ <View paddingRight={CONSTANTS.SPACE_8}>{leftIcon}</View>
70
+ ) : (
71
+ <View paddingRight={CONSTANTS.SPACE_8}>
72
+ <Icon
73
+ name={isActive ? "IconCheckboxActive" : "IconCheckbox"}
74
+ type="Svg"
75
+ size={iconSize}
76
+ color={checkboxColor}
77
+ />
78
+ </View>
79
+ )}
80
+
81
+ <View>
82
+ <Text
83
+ color={colors.textDefault}
84
+ style={[
85
+ styles.text14,
86
+ disabled && {
87
+ color: colors.textSecondary,
88
+ },
89
+ textStyle,
90
+ ]}
91
+ >
92
+ {content}
93
+ </Text>
94
+ </View>
95
+ </View>
96
+ );
97
+ };
98
+
99
+ const styles = StyleSheet.create({
100
+ ...containerStyles,
101
+ icon: {
102
+ width: 24,
103
+ height: 24,
104
+ },
105
+ });
106
+
107
+ export default Checkbox;
@@ -0,0 +1,112 @@
1
+ import React, { useState, useCallback, useEffect } from "react";
2
+ import { StyleProp, ViewStyle, StyleSheet, TextStyle } from "react-native";
3
+ import View from "../View";
4
+ import { CONSTANTS } from "../../styles/themes/tokens";
5
+ import Text from "../Text";
6
+ import { useInternalTheme } from "../../core/theming";
7
+ import containerStyles from "../../theme/container-styles";
8
+ import CountingDot from "../CountingDot";
9
+
10
+ interface ChipBarProps {
11
+ style?: StyleProp<ViewStyle>;
12
+ title: string;
13
+ borderRadius?: number;
14
+ onPress?: (val?: any) => void;
15
+ textStyle?: StyleProp<TextStyle>;
16
+ disabled?: boolean;
17
+ leftIcon?: React.ReactNode;
18
+ rightIcon?: React.ReactNode;
19
+ badge?: number;
20
+ isActive?: boolean;
21
+ }
22
+
23
+ const ChipBar = ({
24
+ style,
25
+ borderRadius = CONSTANTS.BORDER_RADIUS_ROUNDED,
26
+ title = "content",
27
+ textStyle,
28
+ onPress,
29
+ disabled = false,
30
+ leftIcon,
31
+ rightIcon,
32
+ badge = 0,
33
+ isActive = false,
34
+ }: ChipBarProps) => {
35
+ const theme = useInternalTheme();
36
+ const { colors } = theme;
37
+ const [active, setActive] = useState<boolean>(isActive);
38
+
39
+ const handlePressChipBar = useCallback(() => {
40
+ setActive(!active);
41
+ onPress?.();
42
+ }, [active]);
43
+
44
+ useEffect(() => {
45
+ setActive(isActive);
46
+ }, [isActive]);
47
+
48
+ return (
49
+ <View row>
50
+ <View
51
+ row
52
+ disabled={disabled}
53
+ paddingHorizontal={CONSTANTS.SPACE_12}
54
+ paddingVertical={CONSTANTS.SPACE_8}
55
+ borderRadius={borderRadius}
56
+ borderWidth={1}
57
+ alignCenter
58
+ style={[
59
+ style,
60
+ disabled && {
61
+ backgroundColor: colors.surfaceSecondaryDefault,
62
+ borderColor: colors.surfaceSecondaryDefault,
63
+ },
64
+ ]}
65
+ onPress={handlePressChipBar}
66
+ borderColor={
67
+ active ? colors.borderBrandDefault : colors.borderPrimaryDefault
68
+ }
69
+ backgroundColor={
70
+ active
71
+ ? colors.surfaceBrandInverseDefault
72
+ : colors.backgroundSecondary
73
+ }
74
+ >
75
+ {leftIcon && <View paddingRight={CONSTANTS.SPACE_4}>{leftIcon}</View>}
76
+ <View>
77
+ <Text
78
+ color={active ? colors.textBrandDefault : colors.textDefault}
79
+ style={[
80
+ styles.text14,
81
+ styles.textMedium,
82
+ disabled && {
83
+ color: colors.textSecondary,
84
+ },
85
+ textStyle,
86
+ ]}
87
+ >
88
+ {title}
89
+ </Text>
90
+ </View>
91
+ {rightIcon && <View paddingLeft={CONSTANTS.SPACE_4}>{rightIcon}</View>}
92
+ </View>
93
+ {badge > 0 && (
94
+ <View style={styles.badgeContainer}>
95
+ <CountingDot value={badge} />
96
+ </View>
97
+ )}
98
+ </View>
99
+ );
100
+ };
101
+
102
+ const styles = StyleSheet.create({
103
+ ...containerStyles,
104
+ badgeContainer: {
105
+ position: "absolute",
106
+ right: 0,
107
+ top: -4,
108
+ zIndex: 999,
109
+ },
110
+ });
111
+
112
+ export default ChipBar;
@@ -0,0 +1,63 @@
1
+ import React from "react";
2
+ import View from "../View";
3
+ import Text from "../Text";
4
+ import { CONSTANTS } from "../../styles/themes/tokens";
5
+ import { useInternalTheme } from "../../core/theming";
6
+ import { StyleProp, ViewStyle, StyleSheet, TextStyle } from "react-native";
7
+ import containerStyles from "../../theme/container-styles";
8
+
9
+ interface CountingDotProps {
10
+ children?: React.ReactNode;
11
+ value: string | number;
12
+ borderColor?: string;
13
+ backgroundColor?: string;
14
+ style?: StyleProp<ViewStyle>;
15
+ textColor?: string;
16
+ textStyle?: StyleProp<TextStyle>;
17
+ }
18
+
19
+ const CountingDot = ({
20
+ children,
21
+ value = "1",
22
+ backgroundColor,
23
+ style,
24
+ textColor,
25
+ textStyle,
26
+ }: CountingDotProps) => {
27
+ const theme = useInternalTheme();
28
+ const { colors } = theme;
29
+
30
+ if (children) {
31
+ return <View style={style}>{children}</View>;
32
+ }
33
+ return (
34
+ <View row>
35
+ <View
36
+ center
37
+ borderRadius={CONSTANTS.BORDER_RADIUS_12}
38
+ backgroundColor={backgroundColor || colors.surfaceCriticalDefault}
39
+ paddingHorizontal={CONSTANTS.SPACE_4}
40
+ paddingVertical={CONSTANTS.SPACE_2}
41
+ style={[styles.container, style]}
42
+ >
43
+ <Text
44
+ size={10}
45
+ style={[styles.textMedium, textStyle]}
46
+ color={textColor || colors.textOnFillDefault}
47
+ >
48
+ {value}
49
+ </Text>
50
+ </View>
51
+ </View>
52
+ );
53
+ };
54
+
55
+ const styles = StyleSheet.create({
56
+ ...containerStyles,
57
+ container: {
58
+ minWidth: 16,
59
+ minHeight: 16,
60
+ },
61
+ });
62
+
63
+ export default CountingDot;
@@ -0,0 +1,99 @@
1
+ //
2
+ // Created by Dung Nguyen on 25/04/25.
3
+ //
4
+ import React from "react";
5
+ import {
6
+ ActivityIndicator,
7
+ StyleProp,
8
+ ViewStyle,
9
+ StyleSheet,
10
+ TouchableOpacity,
11
+ } from "react-native";
12
+ import View from "../View";
13
+ import { memoDeepEqual } from "../../utils/function-utils";
14
+ import { CONSTANTS } from "../../styles/themes/tokens";
15
+ import { useInternalTheme } from "../../core/theming";
16
+
17
+ export interface FloatingButtonProps {
18
+ isLoading?: boolean;
19
+ disabled?: boolean;
20
+ onPress?: (val?: any) => void;
21
+ style?: StyleProp<ViewStyle>;
22
+ children?: React.ReactNode;
23
+ size?: number;
24
+ hiddenBackground?: boolean;
25
+ props?: object;
26
+ backgroundColor?: string;
27
+ top?: number;
28
+ right?: number;
29
+ }
30
+ const FloatingButton = ({
31
+ isLoading,
32
+ disabled,
33
+ onPress,
34
+ style,
35
+ hiddenBackground = false,
36
+ size = CONSTANTS.BUTTON_HEIGHT,
37
+ children,
38
+ backgroundColor,
39
+ props,
40
+ top = 0,
41
+ right = 0,
42
+ }: FloatingButtonProps) => {
43
+ const { colors } = useInternalTheme();
44
+ return (
45
+ <TouchableOpacity
46
+ activeOpacity={0.8}
47
+ disabled={disabled || isLoading || !onPress}
48
+ onPress={onPress}
49
+ >
50
+ <View
51
+ style={[
52
+ styles.btn,
53
+ !hiddenBackground
54
+ ? {
55
+ backgroundColor: backgroundColor || colors.surfaceBrandDefault,
56
+ }
57
+ : {
58
+ backgroundColor: "transparent",
59
+ },
60
+ {
61
+ width: size,
62
+ height: size,
63
+ borderRadius: size / 2,
64
+ top: top,
65
+ right: right,
66
+ },
67
+
68
+ disabled && {
69
+ borderWidth: 0,
70
+ backgroundColor: colors.surfaceBrandDisabled,
71
+ },
72
+ style,
73
+ ]}
74
+ {...props}
75
+ >
76
+ {isLoading ? <ActivityIndicator size={"small"} /> : children}
77
+ </View>
78
+ </TouchableOpacity>
79
+ );
80
+ };
81
+
82
+ const styles = StyleSheet.create({
83
+ btn: {
84
+ position: "absolute",
85
+ justifyContent: "center",
86
+ alignItems: "center",
87
+ shadowColor: "#000",
88
+ shadowOffset: {
89
+ width: 0,
90
+ height: 2,
91
+ },
92
+ shadowOpacity: 0.25,
93
+ shadowRadius: 3.84,
94
+
95
+ elevation: 5,
96
+ },
97
+ });
98
+
99
+ export default memoDeepEqual(FloatingButton);
@@ -0,0 +1,135 @@
1
+ import React, { useMemo } from "react";
2
+ import { StyleProp, TextStyle, TouchableOpacity, View } from "react-native";
3
+ import FontAwesome from "react-native-vector-icons/FontAwesome";
4
+ import MaterialIcons from "react-native-vector-icons/MaterialIcons";
5
+ import MaterialCommunityIcons from "react-native-vector-icons/MaterialCommunityIcons";
6
+ import { useInternalTheme } from "../../core/theming";
7
+ import { CONSTANTS } from "../../styles/themes/tokens";
8
+ import SvgIcon from "../IconSvg";
9
+ import IconCheckboxActive from "../../icons/IconCheckboxActive";
10
+ import IconCheckbox from "../../icons/IconCheckbox";
11
+ import IconRadio from "../../icons/IconRadio";
12
+ import IconRadioActive from "../../icons/IconRadioActive";
13
+ import IconRadioDisable from "../../icons/IconRadioDisable";
14
+ import IconArrowDown from "../../icons/IconArrowDown";
15
+ import IconClearText from "../../icons/IconClearText";
16
+
17
+ export type IconType =
18
+ | "FontAwesome"
19
+ | "Image"
20
+ | "MaterialIcons"
21
+ | "Feather"
22
+ | "MaterialCommunityIcons"
23
+ | "Svg";
24
+
25
+ export interface IconProps {
26
+ name:
27
+ | "IconCheckboxActive"
28
+ | "IconCheckbox"
29
+ | "IconRadio"
30
+ | "IconRadioActive"
31
+ | "IconRadioDisable"
32
+ | "IconArrowDown"
33
+ | "IconClearText";
34
+ backgroundColor?: string;
35
+ size?: number;
36
+ color?: string;
37
+ style?: StyleProp<TextStyle>;
38
+ showBackground?: boolean;
39
+ onPress?: () => void;
40
+ type?: IconType;
41
+ tintColor?: string;
42
+ animatedProps?: Record<string, unknown>;
43
+ }
44
+
45
+ const getIconComponent = (type: IconType) => {
46
+ switch (type) {
47
+ case "MaterialIcons":
48
+ return MaterialIcons;
49
+ case "MaterialCommunityIcons":
50
+ return MaterialCommunityIcons;
51
+ case "FontAwesome":
52
+ default:
53
+ return FontAwesome;
54
+ }
55
+ };
56
+
57
+ const Icon: React.FC<IconProps> = ({
58
+ name,
59
+ size = 14,
60
+ color,
61
+ style,
62
+ showBackground,
63
+ backgroundColor,
64
+ onPress,
65
+ type = "FontAwesome",
66
+ tintColor,
67
+ ...rest
68
+ }) => {
69
+ const theme = useInternalTheme();
70
+ const { colors } = theme;
71
+
72
+ const IconComponent = useMemo(() => getIconComponent(type), [type]);
73
+
74
+ const renderName = () => {
75
+ switch (name) {
76
+ case "IconCheckboxActive":
77
+ return IconCheckboxActive;
78
+ case "IconCheckbox":
79
+ return IconCheckbox;
80
+ case "IconRadio":
81
+ return IconRadio;
82
+ case "IconRadioActive":
83
+ return IconRadioActive;
84
+ case "IconRadioDisable":
85
+ return IconRadioDisable;
86
+ case "IconArrowDown":
87
+ return IconArrowDown;
88
+ case "IconClearText":
89
+ return IconClearText;
90
+ default:
91
+ return IconCheckbox;
92
+ }
93
+ };
94
+
95
+ const renderIcon = () => {
96
+ if (type === "Svg") {
97
+ return (
98
+ <SvgIcon
99
+ name={renderName()}
100
+ width={size}
101
+ height={size}
102
+ color={color || colors.iconPrimaryDefault}
103
+ />
104
+ );
105
+ }
106
+
107
+ return (
108
+ <IconComponent
109
+ name={name as string}
110
+ size={size}
111
+ color={color || colors.iconPrimaryDefault}
112
+ {...rest}
113
+ />
114
+ );
115
+ };
116
+
117
+ return (
118
+ <TouchableOpacity disabled={!onPress} onPress={onPress}>
119
+ <View
120
+ style={[
121
+ {
122
+ width: size,
123
+ height: size,
124
+ borderRadius: CONSTANTS.BORDER_RADIUS_8,
125
+ },
126
+ style,
127
+ ]}
128
+ >
129
+ {renderIcon()}
130
+ </View>
131
+ </TouchableOpacity>
132
+ );
133
+ };
134
+
135
+ export default React.memo(Icon);
@@ -0,0 +1,42 @@
1
+ import colors from "../../theme/colors";
2
+ import React from "react";
3
+ import { View } from "react-native";
4
+
5
+ interface SvgIconProps {
6
+ name: any;
7
+ width?: number;
8
+ height?: number;
9
+ color?: string;
10
+ style?: any;
11
+ onPress?: () => void;
12
+ disabled?: boolean;
13
+ }
14
+ const SvgIcon: React.FC<SvgIconProps> = ({
15
+ name,
16
+ width = 24,
17
+ height = 24,
18
+ color = colors.ink.INK40,
19
+ style,
20
+ onPress,
21
+ disabled = false,
22
+ }) => {
23
+ // Kiểm tra kỹ hơn
24
+ if (!name || typeof name !== "function") {
25
+ console.warn(`Icon is not a valid React component:`, name);
26
+ return <View style={{ width, height }} />;
27
+ }
28
+
29
+ const IconComponent = name;
30
+
31
+ return (
32
+ <IconComponent
33
+ width={width}
34
+ height={height}
35
+ color={disabled ? colors.ink.INK20 : color}
36
+ style={style}
37
+ onPress={disabled ? undefined : onPress}
38
+ />
39
+ );
40
+ };
41
+
42
+ export default SvgIcon;
@@ -0,0 +1,127 @@
1
+ import React, { useState } from "react";
2
+ import {
3
+ Image as RNImage,
4
+ ImageBackground,
5
+ ImageProps,
6
+ View,
7
+ StyleProp,
8
+ ImageStyle,
9
+ } from "react-native";
10
+ import FastImage, { ResizeMode } from "@d11/react-native-fast-image";
11
+ import { memoDeepEqual } from "../../utils/function-utils";
12
+
13
+ interface PropsCustomImage extends ImageProps {
14
+ useFastImage?: boolean;
15
+ disableDefaultImage?: boolean;
16
+ children?: React.ReactNode;
17
+ resizeMode?: "cover" | "contain" | "stretch" | "center";
18
+ source: any;
19
+ style?: StyleProp<ImageStyle>;
20
+ loadingColor?: string;
21
+ showLoading?: boolean;
22
+ }
23
+
24
+ const getSource = (source: any) => {
25
+ let newSource = source;
26
+ if (typeof source === "string") {
27
+ newSource = { uri: source };
28
+ }
29
+ return newSource;
30
+ };
31
+
32
+ const Image = (props: PropsCustomImage) => {
33
+ const {
34
+ children,
35
+ source,
36
+ useFastImage,
37
+ disableDefaultImage,
38
+ style,
39
+ resizeMode = "contain",
40
+ } = props;
41
+
42
+ const [hasError, setHasError] = useState(false);
43
+
44
+ const image = getSource(
45
+ disableDefaultImage
46
+ ? source
47
+ : hasError
48
+ ? require("./assets/images/image_default.png")
49
+ : source || require("./assets/images/image_default.png")
50
+ );
51
+ const ImageComponent = children ? ImageBackground : RNImage;
52
+
53
+ const getUriImage = (uri: string) => {
54
+ return uri !== null &&
55
+ uri !== undefined &&
56
+ uri.includes("/") &&
57
+ uri.includes(".")
58
+ ? uri
59
+ : "";
60
+ };
61
+
62
+ const handleError = () => {
63
+ setHasError(true);
64
+ };
65
+
66
+ const getFastImageResizeMode = (mode: string): ResizeMode => {
67
+ switch (mode) {
68
+ case "cover":
69
+ return FastImage.resizeMode.cover;
70
+ case "contain":
71
+ return FastImage.resizeMode.contain;
72
+ case "stretch":
73
+ return FastImage.resizeMode.stretch;
74
+ case "center":
75
+ return FastImage.resizeMode.center;
76
+ default:
77
+ return FastImage.resizeMode.contain;
78
+ }
79
+ };
80
+
81
+ if (useFastImage && image?.uri) {
82
+ const {
83
+ defaultSource,
84
+ onLoad,
85
+ onLoadStart,
86
+ onLoadEnd,
87
+ onProgress,
88
+ style: imageStyle,
89
+ ...restProps
90
+ } = props;
91
+
92
+ return (
93
+ <View style={style}>
94
+ <FastImage
95
+ resizeMode={getFastImageResizeMode(resizeMode)}
96
+ {...restProps}
97
+ onError={handleError}
98
+ source={{
99
+ uri: getUriImage(image.uri),
100
+ cache: FastImage.cacheControl.immutable,
101
+ }}
102
+ style={imageStyle as any}
103
+ />
104
+ </View>
105
+ );
106
+ }
107
+
108
+ if (!source && disableDefaultImage) {
109
+ if (children) {
110
+ return <View {...props}>{children}</View>;
111
+ }
112
+ return null;
113
+ }
114
+
115
+ return (
116
+ <View style={style}>
117
+ <ImageComponent
118
+ resizeMode={resizeMode}
119
+ {...props}
120
+ source={image}
121
+ onError={handleError}
122
+ />
123
+ </View>
124
+ );
125
+ };
126
+
127
+ export default memoDeepEqual<PropsCustomImage>(Image);