@ccrf01/react-native-template 0.0.16

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 (233) hide show
  1. package/.github/workflows/npm-publish.yml +28 -0
  2. package/.vscode/settings.json +15 -0
  3. package/README.md +58 -0
  4. package/package.json +16 -0
  5. package/template/.bundle/config +2 -0
  6. package/template/.env.development +1 -0
  7. package/template/.env.production +1 -0
  8. package/template/.eslintrc.js +392 -0
  9. package/template/.java-version +1 -0
  10. package/template/.prettierrc.js +5 -0
  11. package/template/.ruby-version +1 -0
  12. package/template/.watchmanconfig +1 -0
  13. package/template/Gemfile +23 -0
  14. package/template/Gemfile.lock +330 -0
  15. package/template/README.md +97 -0
  16. package/template/ReactotronConfig.js +17 -0
  17. package/template/__tests__/App.test.tsx +13 -0
  18. package/template/_gitignore +75 -0
  19. package/template/_node-version +1 -0
  20. package/template/android/app/build.gradle +162 -0
  21. package/template/android/app/debug.keystore +0 -0
  22. package/template/android/app/proguard-rules.pro +10 -0
  23. package/template/android/app/src/debug/AndroidManifest.xml +9 -0
  24. package/template/android/app/src/main/AndroidManifest.xml +26 -0
  25. package/template/android/app/src/main/java/com/projectname/MainActivity.kt +30 -0
  26. package/template/android/app/src/main/java/com/projectname/MainApplication.kt +27 -0
  27. package/template/android/app/src/main/res/drawable/rn_edit_text_material.xml +37 -0
  28. package/template/android/app/src/main/res/mipmap-hdpi/ic_launcher.png +0 -0
  29. package/template/android/app/src/main/res/mipmap-hdpi/ic_launcher_round.png +0 -0
  30. package/template/android/app/src/main/res/mipmap-mdpi/ic_launcher.png +0 -0
  31. package/template/android/app/src/main/res/mipmap-mdpi/ic_launcher_round.png +0 -0
  32. package/template/android/app/src/main/res/mipmap-xhdpi/ic_launcher.png +0 -0
  33. package/template/android/app/src/main/res/mipmap-xhdpi/ic_launcher_round.png +0 -0
  34. package/template/android/app/src/main/res/mipmap-xxhdpi/ic_launcher.png +0 -0
  35. package/template/android/app/src/main/res/mipmap-xxhdpi/ic_launcher_round.png +0 -0
  36. package/template/android/app/src/main/res/mipmap-xxxhdpi/ic_launcher.png +0 -0
  37. package/template/android/app/src/main/res/mipmap-xxxhdpi/ic_launcher_round.png +0 -0
  38. package/template/android/app/src/main/res/values/strings.xml +3 -0
  39. package/template/android/app/src/main/res/values/styles.xml +9 -0
  40. package/template/android/build.gradle +37 -0
  41. package/template/android/gradle/wrapper/gradle-wrapper.jar +0 -0
  42. package/template/android/gradle/wrapper/gradle-wrapper.properties +7 -0
  43. package/template/android/gradle.properties +48 -0
  44. package/template/android/gradlew +251 -0
  45. package/template/android/gradlew.bat +99 -0
  46. package/template/android/keystore/keystore.properties +4 -0
  47. package/template/android/settings.gradle +6 -0
  48. package/template/android/version.properties +2 -0
  49. package/template/app.json +4 -0
  50. package/template/babel.config.js +38 -0
  51. package/template/fastlane/Fastfile +136 -0
  52. package/template/fastlane/Pluginfile +9 -0
  53. package/template/fastlane/README.md +46 -0
  54. package/template/index.js +9 -0
  55. package/template/ios/.xcode.env +11 -0
  56. package/template/ios/Podfile +35 -0
  57. package/template/ios/Podfile.lock +3669 -0
  58. package/template/ios/ProjectName/AppDelegate.swift +48 -0
  59. package/template/ios/ProjectName/Images.xcassets/AppIcon.appiconset/Contents.json +53 -0
  60. package/template/ios/ProjectName/Images.xcassets/Contents.json +6 -0
  61. package/template/ios/ProjectName/Info.plist +66 -0
  62. package/template/ios/ProjectName/LaunchScreen.storyboard +47 -0
  63. package/template/ios/ProjectName/PrivacyInfo.xcprivacy +47 -0
  64. package/template/ios/ProjectName.xcodeproj/project.pbxproj +482 -0
  65. package/template/ios/ProjectName.xcodeproj/xcshareddata/xcschemes/ProjectName.xcscheme +88 -0
  66. package/template/ios/ProjectName.xcworkspace/contents.xcworkspacedata +10 -0
  67. package/template/jest.config.js +3 -0
  68. package/template/metro.config.js +20 -0
  69. package/template/package-lock.json +17073 -0
  70. package/template/package.json +156 -0
  71. package/template/src/@types/emotion.d.ts +12 -0
  72. package/template/src/@types/env.d.ts +3 -0
  73. package/template/src/@types/redux-persist-transform-immutable.d.ts +1 -0
  74. package/template/src/@types/typing.d.ts +17 -0
  75. package/template/src/AppContainer.tsx +109 -0
  76. package/template/src/assets/images/143.png +0 -0
  77. package/template/src/assets/index.ts +13 -0
  78. package/template/src/components/basic/BackButton/index.tsx +34 -0
  79. package/template/src/components/basic/Body/index.tsx +68 -0
  80. package/template/src/components/basic/Button/index.tsx +181 -0
  81. package/template/src/components/basic/Button/utils.ts +78 -0
  82. package/template/src/components/basic/ButtonGroup/index.tsx +182 -0
  83. package/template/src/components/basic/Card/index.tsx +3 -0
  84. package/template/src/components/basic/Container/index.tsx +38 -0
  85. package/template/src/components/basic/Content/index.tsx +87 -0
  86. package/template/src/components/basic/DropDown/index.tsx +354 -0
  87. package/template/src/components/basic/ExpandableOverlay/index.tsx +113 -0
  88. package/template/src/components/basic/Header/index.tsx +216 -0
  89. package/template/src/components/basic/Header/styles.ts +0 -0
  90. package/template/src/components/basic/Icons/index.tsx +131 -0
  91. package/template/src/components/basic/InputLabel/index.tsx +19 -0
  92. package/template/src/components/basic/LoadingOverlay/index.tsx +68 -0
  93. package/template/src/components/basic/MaterialTextInput/index.tsx +153 -0
  94. package/template/src/components/basic/NumberInput/index.tsx +53 -0
  95. package/template/src/components/basic/Picker/PickerContext.ts +7 -0
  96. package/template/src/components/basic/Picker/PickerHeader.tsx +130 -0
  97. package/template/src/components/basic/Picker/PickerItem.tsx +105 -0
  98. package/template/src/components/basic/Picker/PickerItemsList.tsx +135 -0
  99. package/template/src/components/basic/Picker/PickerPresenter.ts +54 -0
  100. package/template/src/components/basic/Picker/hooks/useImperativePickerHandle.ts +27 -0
  101. package/template/src/components/basic/Picker/hooks/usePickerLabel.ts +74 -0
  102. package/template/src/components/basic/Picker/hooks/usePickerSearch.ts +37 -0
  103. package/template/src/components/basic/Picker/hooks/usePickerSelection.ts +57 -0
  104. package/template/src/components/basic/Picker/index.tsx +284 -0
  105. package/template/src/components/basic/Picker/types.tsx +229 -0
  106. package/template/src/components/basic/PressableOpacity/index.tsx +20 -0
  107. package/template/src/components/basic/RootDialog/Dialog.tsx +246 -0
  108. package/template/src/components/basic/RootDialog/Manager.tsx +110 -0
  109. package/template/src/components/basic/RootDialog/animations/Animation.ts +29 -0
  110. package/template/src/components/basic/RootDialog/animations/FadeAnimation.ts +40 -0
  111. package/template/src/components/basic/RootDialog/animations/ScaleAnimation.ts +37 -0
  112. package/template/src/components/basic/RootDialog/animations/SlideAnimation.ts +89 -0
  113. package/template/src/components/basic/RootDialog/components/Backdrop.tsx +60 -0
  114. package/template/src/components/basic/RootDialog/components/BaseDialog.tsx +564 -0
  115. package/template/src/components/basic/RootDialog/components/BottomDialog.tsx +32 -0
  116. package/template/src/components/basic/RootDialog/components/DialogButton.tsx +87 -0
  117. package/template/src/components/basic/RootDialog/components/DialogContent.tsx +26 -0
  118. package/template/src/components/basic/RootDialog/components/DialogContext.tsx +8 -0
  119. package/template/src/components/basic/RootDialog/components/DialogFooter.tsx +42 -0
  120. package/template/src/components/basic/RootDialog/components/DialogTitle.tsx +53 -0
  121. package/template/src/components/basic/RootDialog/components/DraggableView.tsx +271 -0
  122. package/template/src/components/basic/RootDialog/index.ts +21 -0
  123. package/template/src/components/basic/RootDialog/type.ts +102 -0
  124. package/template/src/components/basic/Text/index.tsx +8 -0
  125. package/template/src/components/basic/index.ts +35 -0
  126. package/template/src/configs/constants/type/APIStatus.type.ts +8 -0
  127. package/template/src/configs/constants/type/Locale.type.ts +7 -0
  128. package/template/src/configs/constants/type/StorageKey.type.ts +7 -0
  129. package/template/src/configs/constants/type/ThemeType.type.ts +6 -0
  130. package/template/src/configs/constants/type/index.ts +11 -0
  131. package/template/src/configs/index.ts +22 -0
  132. package/template/src/contexts/ThemeContext.ts +6 -0
  133. package/template/src/hooks/useAppLoading.ts +26 -0
  134. package/template/src/hooks/useAppState.ts +36 -0
  135. package/template/src/hooks/useArray.ts +47 -0
  136. package/template/src/hooks/useAsync.ts +42 -0
  137. package/template/src/hooks/useAsyncStorage.ts +41 -0
  138. package/template/src/hooks/useBoolean.ts +21 -0
  139. package/template/src/hooks/useBuildTheme.ts +249 -0
  140. package/template/src/hooks/useCountDown.ts +111 -0
  141. package/template/src/hooks/useCounter.ts +27 -0
  142. package/template/src/hooks/useDebounce.ts +25 -0
  143. package/template/src/hooks/useDebouncedValidate.ts +32 -0
  144. package/template/src/hooks/useDebugInformation.ts +38 -0
  145. package/template/src/hooks/useDeviceToken.ts +20 -0
  146. package/template/src/hooks/useEncryptedStorage.ts +41 -0
  147. package/template/src/hooks/useFontFamily.ts +13 -0
  148. package/template/src/hooks/useHttp.ts +18 -0
  149. package/template/src/hooks/useInterval.ts +24 -0
  150. package/template/src/hooks/useIsForeground.ts +17 -0
  151. package/template/src/hooks/useMMKVStorage.ts +0 -0
  152. package/template/src/hooks/usePrevious.ts +12 -0
  153. package/template/src/hooks/useRenderCount.ts +10 -0
  154. package/template/src/hooks/useTheme.ts +17 -0
  155. package/template/src/hooks/useTimeCountDown.ts +91 -0
  156. package/template/src/index.tsx +65 -0
  157. package/template/src/infrastructures/NetClient/AbstractClient.ts +66 -0
  158. package/template/src/infrastructures/NetClient/ApiResponse.ts +16 -0
  159. package/template/src/infrastructures/NetClient/ApisauceClient.ts +76 -0
  160. package/template/src/infrastructures/NetClient/AxiosClient.ts +80 -0
  161. package/template/src/infrastructures/NetClient/FetchNetClient.ts +120 -0
  162. package/template/src/infrastructures/NetClient/config.ts +3 -0
  163. package/template/src/infrastructures/NetClient/interfaces/INetClient.ts +6 -0
  164. package/template/src/infrastructures/Storage/IStorage.ts +7 -0
  165. package/template/src/infrastructures/Storage/MMKVStorage.ts +41 -0
  166. package/template/src/infrastructures/common/Timeout.ts +27 -0
  167. package/template/src/infrastructures/common/colorUtils.ts +82 -0
  168. package/template/src/infrastructures/common/dateUtils.ts +39 -0
  169. package/template/src/infrastructures/common/logger.ts +115 -0
  170. package/template/src/locales/en-US/general.json +26 -0
  171. package/template/src/locales/en-US/index.ts +9 -0
  172. package/template/src/locales/en-US/screens.json +4 -0
  173. package/template/src/locales/en-US/setting.json +3 -0
  174. package/template/src/locales/i18n.ts +109 -0
  175. package/template/src/locales/zh-TW/general.json +26 -0
  176. package/template/src/locales/zh-TW/index.ts +9 -0
  177. package/template/src/locales/zh-TW/screens.json +4 -0
  178. package/template/src/locales/zh-TW/setting.json +3 -0
  179. package/template/src/models/index.ts +5 -0
  180. package/template/src/models/request.model.ts +50 -0
  181. package/template/src/navigators/DrawerNav/DrawerContent.tsx +66 -0
  182. package/template/src/navigators/DrawerNav/DrawerItem.tsx +261 -0
  183. package/template/src/navigators/DrawerNav/index.tsx +39 -0
  184. package/template/src/navigators/DrawerNav/props.ts +12 -0
  185. package/template/src/navigators/DrawerNav/types.ts +8 -0
  186. package/template/src/navigators/MainBottomTabNav/index.tsx +83 -0
  187. package/template/src/navigators/MainBottomTabNav/props.ts +16 -0
  188. package/template/src/navigators/MainBottomTabNav/types.ts +6 -0
  189. package/template/src/navigators/RootStack.tsx +43 -0
  190. package/template/src/navigators/index.tsx +40 -0
  191. package/template/src/navigators/props.ts +14 -0
  192. package/template/src/navigators/types.ts +18 -0
  193. package/template/src/navigators/utils.ts +68 -0
  194. package/template/src/redux/api/api.ts +41 -0
  195. package/template/src/redux/reducers/appSlice.ts +26 -0
  196. package/template/src/redux/reducers/index.ts +21 -0
  197. package/template/src/redux/reducers/nonPersistSlice.ts +51 -0
  198. package/template/src/redux/reducers/settingSlice.ts +48 -0
  199. package/template/src/redux/reducers/themeSlice.ts +55 -0
  200. package/template/src/redux/saga/index.ts +5 -0
  201. package/template/src/redux/saga/settingSaga.ts +21 -0
  202. package/template/src/redux/selectors/app.ts +9 -0
  203. package/template/src/redux/selectors/nonPersist.ts +23 -0
  204. package/template/src/redux/selectors/setting.ts +29 -0
  205. package/template/src/redux/selectors/theme.ts +13 -0
  206. package/template/src/redux/store/index.ts +79 -0
  207. package/template/src/redux/store/types.d.ts +5 -0
  208. package/template/src/screens/Home/index.tsx +146 -0
  209. package/template/src/screens/Settings/components/Item.tsx +45 -0
  210. package/template/src/screens/Settings/index.tsx +97 -0
  211. package/template/src/screens/Splash/index.tsx +53 -0
  212. package/template/src/services/Dialogs.tsx +226 -0
  213. package/template/src/services/PermissionCheck.ts +257 -0
  214. package/template/src/theme/Common.ts +48 -0
  215. package/template/src/theme/Fonts.ts +196 -0
  216. package/template/src/theme/Gutters.ts +63 -0
  217. package/template/src/theme/Icons.ts +28 -0
  218. package/template/src/theme/Images.ts +13 -0
  219. package/template/src/theme/Layout.ts +106 -0
  220. package/template/src/theme/Variables.ts +167 -0
  221. package/template/src/theme/components/Buttons.ts +37 -0
  222. package/template/src/theme/index.ts +8 -0
  223. package/template/src/theme/metrics.ts +57 -0
  224. package/template/src/theme/themes/default_dark/Images.ts +7 -0
  225. package/template/src/theme/themes/default_dark/Variables.ts +84 -0
  226. package/template/src/theme/themes/default_dark/index.ts +2 -0
  227. package/template/src/theme/themes/index.ts +8 -0
  228. package/template/src/theme/types.ts +152 -0
  229. package/template/src/utils/encrypt-helper.ts +118 -0
  230. package/template/src/utils/index.ts +76 -0
  231. package/template/src/utils/sys-info-data.ts +17 -0
  232. package/template/tsconfig.json +44 -0
  233. package/template.config.js +8 -0
@@ -0,0 +1,182 @@
1
+ import React from 'react'
2
+ import {
3
+ Pressable,
4
+ StyleProp,
5
+ StyleSheet,
6
+ Text,
7
+ TextProps,
8
+ View,
9
+ ViewStyle,
10
+ } from 'react-native'
11
+
12
+ import { PressableOpacity, Text as BText } from '@/components/basic'
13
+ import useTheme from '@/hooks/useTheme'
14
+ import { Theme } from '@/theme/types'
15
+
16
+ export interface IOption<T> {
17
+ label: string
18
+ value: T
19
+ }
20
+ type Props<ItemT> = {
21
+ borderColor?: string
22
+ selectedBackgroundColor?: string
23
+ backgroundColor?: string
24
+ textStyle?: StyleProp<TextProps>
25
+ selectedTextStyle?: StyleProp<TextProps>
26
+ style?: StyleProp<ViewStyle>
27
+ // selectedIndex: number
28
+ value?: unknown
29
+ onSelect?: (selected: ItemT) => void
30
+ options: IOption<ItemT>[]
31
+ radius?: number
32
+ }
33
+ const ButtonGroup = <T,>({
34
+ backgroundColor,
35
+ onSelect = () => { },
36
+ options,
37
+ radius,
38
+ style = {},
39
+ value,
40
+ }: Props<T>) => {
41
+
42
+ const { Colors, Fonts, Gutters, Param } = useTheme()
43
+ const styles = makeStyles({ Colors, Gutters, Param, radius, backgroundColor })
44
+ const itemStyle = {
45
+ borderColor: Colors.primary,
46
+ backgroundColor: backgroundColor ?? Colors.background,
47
+ // flex: 1,
48
+ justifyContent: 'center',
49
+ alignItems: 'center',
50
+ }
51
+ const textStyle = {
52
+ color: Colors.onBackground,
53
+ ...Fonts.buttonTextMedium,
54
+ fontFamily: 'System',
55
+ }
56
+ const selectedItemStyle = { backgroundColor: Colors.primary }
57
+ const selectedTextStyle = { color: Colors.onPrimary }
58
+
59
+ const onPress = (index: T) => {
60
+ onSelect(index)
61
+ }
62
+
63
+ return (
64
+ <View
65
+ style={[
66
+ {
67
+ flexDirection: 'row',
68
+ display: 'flex',
69
+ width: '100%',
70
+ },
71
+ style,
72
+ ]}
73
+ >
74
+ {options.map((option, index) => {
75
+ const onPressIndex = () => {
76
+ onPress(option.value)
77
+ }
78
+
79
+ return (
80
+ <View
81
+ key={`option_${index}`}
82
+ style={{ flex: 1 }}
83
+ >
84
+ <PressableOpacity
85
+ activeOpacity={0.6}
86
+ onPress={onPressIndex}
87
+ style={{ flex: 1 }}
88
+ >
89
+ <View
90
+ style={StyleSheet.flatten([
91
+ styles.item,
92
+ index === 0 ? styles.firstItem :
93
+ index === options.length - 1 ?
94
+ styles.lastItem :
95
+ {},
96
+ option.value === value ? selectedItemStyle : {},
97
+ ])}
98
+ >
99
+ {/* {typeof option === 'string' ? (
100
+ <Text
101
+ style={[
102
+ textStyle,
103
+ index === selectedIndex ? selectedTextStyle : {},
104
+ ]}
105
+ >{option}</Text>
106
+ ) : option} */}
107
+ <Text
108
+ style={[
109
+ textStyle,
110
+ option.value === value ? selectedTextStyle : { padding: 0, margin: 0 },
111
+ ]}
112
+ >{option.label}</Text>
113
+ </View>
114
+ </PressableOpacity>
115
+ </View>
116
+ )
117
+ })}
118
+ </View>
119
+ )
120
+ }
121
+ const makeStyles = ({ Colors, Gutters, Param, radius, backgroundColor }: Pick<Theme, 'Colors' | 'Gutters' | 'Param'> & { radius?: number; backgroundColor?: string }) => {
122
+ return StyleSheet.create({
123
+ firstItem: {
124
+ borderBottomLeftRadius: radius ?? Param.roundness * 2,
125
+ borderTopLeftRadius: radius ?? Param.roundness * 2,
126
+ borderLeftWidth: 1,
127
+ borderRightWidth: 0,
128
+ borderTopWidth: 1,
129
+ borderBottomWidth: 1,
130
+ },
131
+ lastItem: {
132
+ borderBottomRightRadius: radius ?? Param.roundness * 2,
133
+ borderTopRightRadius: radius ?? Param.roundness * 2,
134
+ borderLeftWidth: 1,
135
+ borderRightWidth: 1,
136
+ borderTopWidth: 1,
137
+ borderBottomWidth: 1,
138
+ },
139
+ item: {
140
+ borderColor: Colors.primary,
141
+ backgroundColor: backgroundColor ?? Colors.background,
142
+ // flex: 1,
143
+ justifyContent: 'center',
144
+ alignItems: 'center',
145
+ borderTopWidth: 1,
146
+ borderBottomWidth: 1,
147
+ borderLeftWidth: 1,
148
+ borderRightWidth: 0,
149
+ // minWidth: 50,
150
+ height: 40,
151
+ flex: 1,
152
+ overflow: 'hidden',
153
+ ...Gutters.tinyPadding,
154
+ },
155
+ selectedStyle: {},
156
+ })
157
+ }
158
+ // const styles = StyleSheet.create({
159
+ // firstItem: {
160
+ // borderBottomLeftRadius: 4,
161
+ // borderTopLeftRadius: 4,
162
+ // padding: 8,
163
+ // borderWidth: 1,
164
+ // borderRightWidth: 0,
165
+ // },
166
+ // lastItem: {
167
+ // borderBottomRightRadius: 4,
168
+ // borderTopRightRadius: 4,
169
+ // padding: 8,
170
+ // borderWidth: 1,
171
+ // borderLeftWidth: 0,
172
+ // },
173
+ // item: {
174
+ // padding: 8,
175
+ // borderWidth: 1,
176
+ // borderLeftWidth: 1,
177
+ // borderRightWidth: 1,
178
+ // },
179
+ // selectedStyle: {},
180
+ // })
181
+
182
+ export default ButtonGroup
@@ -0,0 +1,3 @@
1
+ import React from 'react'
2
+ import { TouchableNativeFeedback, View, ViewStyle } from 'react-native'
3
+ import { Card } from 'react-native-paper'
@@ -0,0 +1,38 @@
1
+ import React from 'react'
2
+ import { View, ViewStyle } from 'react-native'
3
+ import { useSafeAreaInsets } from 'react-native-safe-area-context'
4
+
5
+ import useTheme from '@/hooks/useTheme'
6
+
7
+ interface IContainerProps {
8
+ insetTop?: boolean
9
+ insetBottom?: boolean
10
+ children: React.ReactNode[] | React.ReactNode
11
+ style?: ViewStyle | ViewStyle[]
12
+ withRound?: boolean
13
+ }
14
+ const Container: React.FC<IContainerProps> = ({ children, insetBottom = false, insetTop = false, style = {}, withRound = false }: IContainerProps) => {
15
+ const insets = useSafeAreaInsets()
16
+ const { Colors, Fonts, Gutters, Layout } = useTheme()
17
+
18
+ return (
19
+ <View
20
+ style={[
21
+ Layout.fill,
22
+ Layout.column,
23
+ Layout.justifyContentStart,
24
+ Layout.alignItemsStart,
25
+ // Gutters.mediumHPadding,
26
+ // Gutters.mediumVPadding,
27
+ insetTop ? { paddingTop: insets.top } : {},
28
+ insetBottom ? { paddingBottom: insets.bottom } : {},
29
+ { backgroundColor: Colors.background },
30
+ style,
31
+ ]}
32
+ >
33
+ {children}
34
+ </View>
35
+ )
36
+ }
37
+
38
+ export default React.memo(Container)
@@ -0,0 +1,87 @@
1
+ import React from 'react'
2
+ import { View, ViewStyle } from 'react-native'
3
+
4
+ import useTheme from '@/hooks/useTheme'
5
+ import { MetricsSizeKey } from '@/theme/types'
6
+ import { MetricsSizes } from '@/theme/Variables'
7
+
8
+ interface IContentProps {
9
+ children?: React.ReactNode[] | React.ReactNode
10
+ style?: ViewStyle | ViewStyle[]
11
+ hPadding?: MetricsSizeKey|'none'
12
+ tPadding?: MetricsSizeKey|'none'
13
+ vPadding?: MetricsSizeKey|'none'
14
+ direction?: 'row'|'column'
15
+ }
16
+ const Content: React.FC<IContentProps> = ({
17
+ children,
18
+ direction = 'column',
19
+ hPadding = 'small',
20
+ style,
21
+ tPadding,
22
+ vPadding,
23
+ }: IContentProps) => {
24
+ const { Gutters, Layout } = useTheme()
25
+ let topPadding = {}
26
+ switch (tPadding) {
27
+ case 'tiny':
28
+ topPadding = Gutters.tinyTPadding
29
+ break
30
+ case 'small':
31
+ topPadding = Gutters.smallTPadding
32
+ break
33
+ case 'medium':
34
+ topPadding = Gutters.mediumTPadding
35
+ break
36
+ case 'large':
37
+ topPadding = Gutters.largeTPadding
38
+ break
39
+ }
40
+ let verticalPadding = {}
41
+ switch (vPadding) {
42
+ case 'tiny':
43
+ verticalPadding = Gutters.tinyVPadding
44
+ break
45
+ case 'small':
46
+ verticalPadding = Gutters.smallVPadding
47
+ break
48
+ case 'medium':
49
+ verticalPadding = Gutters.mediumVPadding
50
+ break
51
+ case 'large':
52
+ verticalPadding = Gutters.largeVPadding
53
+ break
54
+ }
55
+ let horizontalPadding = {}
56
+ switch (hPadding) {
57
+ case 'tiny':
58
+ horizontalPadding = Gutters.tinyHPadding
59
+ break
60
+ case 'small':
61
+ horizontalPadding = Gutters.smallHPadding
62
+ break
63
+ case 'medium':
64
+ horizontalPadding = Gutters.mediumHPadding
65
+ break
66
+ case 'large':
67
+ horizontalPadding = Gutters.largeHPadding
68
+ break
69
+ }
70
+
71
+ return (
72
+ <View
73
+ style={[
74
+ direction === 'column' ? Layout.column : Layout.row,
75
+ Layout.fullWidth,
76
+ horizontalPadding,
77
+ topPadding,
78
+ verticalPadding,
79
+ style ?? {},
80
+ ]}
81
+ >
82
+ {children}
83
+ </View>
84
+ )
85
+ }
86
+
87
+ export default React.memo(Content)
@@ -0,0 +1,354 @@
1
+ import React, {
2
+ forwardRef,
3
+ Fragment,
4
+ ReactNode,
5
+ useCallback,
6
+ useEffect,
7
+ useImperativeHandle,
8
+ useMemo,
9
+ useState,
10
+ } from 'react'
11
+ import {
12
+ Keyboard,
13
+ LayoutChangeEvent,
14
+ NativeSyntheticEvent,
15
+ ScrollView,
16
+ TextInputFocusEventData,
17
+ TextStyle,
18
+ TouchableOpacity,
19
+ TouchableWithoutFeedback,
20
+ View,
21
+ ViewStyle,
22
+ } from 'react-native'
23
+ import {
24
+ Checkbox,
25
+ Divider,
26
+ HelperText,
27
+ MD3Theme as Theme,
28
+ Menu,
29
+ TextInput,
30
+ TextInputProps,
31
+ TouchableRipple,
32
+ useTheme as usePaperTheme,
33
+ } from 'react-native-paper'
34
+ import { Icon } from 'react-native-vector-icons/Icon'
35
+
36
+ import { PressableOpacity } from '@/components/basic'
37
+ import MaterialTextInput, { MaterialTextInputProps, TextInputHandles } from '@/components/basic/MaterialTextInput'
38
+ import useTheme from '@/hooks/useTheme'
39
+ import { ThemeNavigationTheme, ThemeNavigationThemeWithOwn } from '@/theme/types'
40
+ // import { MD3Theme } from 'react-native-paper/src/types'
41
+ // import { TextInputProps } from 'react-native-paper/lib/typescript/components/TextInput/TextInput'
42
+ // import { Theme } from 'react-native-paper/lib/typescript/types'
43
+
44
+ type Without<T, K> = Pick<T, Exclude<keyof T, K>>
45
+
46
+ export interface IDropDownOption {
47
+ label: string
48
+ value: string | number
49
+ custom?: ReactNode
50
+ }
51
+ export interface IDropDownProps {
52
+ visible: boolean
53
+ multiSelect?: boolean
54
+ onDismiss: () => void
55
+ showDropDown: () => void
56
+ value: any
57
+ setValue: (_value: any) => void
58
+ label?: string | undefined
59
+ placeholder?: string | undefined
60
+ mode?: 'outlined' | 'flat' | undefined
61
+ inputProps?: TextInputPropsWithoutTheme
62
+ list: IDropDownOption[]
63
+ dropDownContainerMaxHeight?: number
64
+ dropDownContainerHeight?: number
65
+ activeColor?: string
66
+ theme?: ThemeNavigationThemeWithOwn
67
+ dropDownStyle?: ViewStyle
68
+ dropDownItemSelectedTextStyle?: TextStyle
69
+ dropDownItemSelectedStyle?: ViewStyle
70
+ dropDownItemStyle?: ViewStyle
71
+ dropDownItemTextStyle?: TextStyle
72
+ accessibilityLabel?: string
73
+ errorText?: string
74
+ selectionTextStyle?: TextStyle
75
+ onBlur?:| ((e: NativeSyntheticEvent<TextInputFocusEventData>) => void) | undefined
76
+ }
77
+
78
+ type TextInputPropsWithoutTheme = Without<MaterialTextInputProps, 'theme'>
79
+
80
+ const DropDown = forwardRef<TextInputHandles, IDropDownProps>(
81
+ (props, ref) => {
82
+ const activeTheme = usePaperTheme<ThemeNavigationThemeWithOwn>()
83
+ const { Common, NavigationTheme } = useTheme()
84
+ const {
85
+ accessibilityLabel,
86
+ activeColor,
87
+ dropDownContainerHeight,
88
+ dropDownContainerMaxHeight,
89
+ dropDownItemSelectedStyle,
90
+ dropDownItemSelectedTextStyle,
91
+ dropDownItemStyle,
92
+ dropDownItemTextStyle,
93
+ dropDownStyle,
94
+ inputProps,
95
+ label,
96
+ list,
97
+ mode,
98
+ multiSelect = false,
99
+ onDismiss,
100
+ placeholder,
101
+ selectionTextStyle,
102
+ setValue,
103
+ showDropDown,
104
+ theme,
105
+ value,
106
+ visible,
107
+ } = props
108
+ const {
109
+ disableErrorText,
110
+ errorColor,
111
+ errorText,
112
+ errorTextStyle,
113
+ hintText,
114
+ hintTextStyle,
115
+ ...restInputProps
116
+ } = inputProps || {}
117
+ const [displayValue, setDisplayValue] = useState('')
118
+ const [inputLayout, setInputLayout] = useState({
119
+ height: 0,
120
+ width: 0,
121
+ x: 0,
122
+ y: 0,
123
+ })
124
+ const { Colors, Fonts } = useTheme()
125
+ const [isFocused, setIsFocused] = useState(false)
126
+ const inputRef = React.useRef<TextInputHandles>(null)
127
+
128
+ const onLayout = (event: LayoutChangeEvent) => {
129
+ setInputLayout(event.nativeEvent.layout)
130
+ }
131
+
132
+ useImperativeHandle(ref, () => ({
133
+ focus: () => {
134
+ // onPress()
135
+ },
136
+ clear: () => {},
137
+ isFocused: () => false,
138
+ setNativeProps: (arg: any) => {},
139
+ blur: () => {},
140
+ forceFocus: () => {
141
+ // onPress()
142
+ },
143
+ }))
144
+
145
+ useEffect(() => {
146
+ if (multiSelect) {
147
+ // eslint-disable-next-line @typescript-eslint/naming-convention
148
+ const _labels = list
149
+ .filter((_) => value.indexOf(_.value) !== -1)
150
+ .map((_) => _.label)
151
+ .join(', ')
152
+ setDisplayValue(_labels)
153
+ } else {
154
+ // eslint-disable-next-line @typescript-eslint/naming-convention
155
+ const _label = list.find((_) => _.value === value)?.label
156
+ if (_label) {
157
+ setDisplayValue(_label)
158
+ }
159
+ }
160
+ }, [list, value])
161
+
162
+ const isActive = useCallback(
163
+ (currentValue: any) => {
164
+ if (multiSelect) {
165
+ return value.indexOf(currentValue) !== -1
166
+ } else {
167
+ return value === currentValue
168
+ }
169
+ },
170
+ [value]
171
+ )
172
+
173
+ const setActive = useCallback(
174
+ (currentValue: any) => {
175
+ if (multiSelect) {
176
+ const valueIndex = value.indexOf(currentValue)
177
+ const values = value.split(',')
178
+ if (valueIndex === -1) {
179
+ setValue([...values, currentValue].join(','))
180
+ } else {
181
+ setValue(
182
+ [...values].filter((_value) => _value !== currentValue).join(',')
183
+ )
184
+ }
185
+ } else {
186
+ setValue(currentValue)
187
+ }
188
+ inputRef.current?.blur()
189
+ setIsFocused(false)
190
+ },
191
+ [value]
192
+ )
193
+
194
+ const onPress = useCallback(
195
+ () => {
196
+ setIsFocused(true)
197
+ if (value !== undefined && value !== null && value !== '') {
198
+ inputRef.current?.focus()
199
+ }
200
+ // Keyboard.dismiss()
201
+ showDropDown()
202
+ }
203
+ , [showDropDown, visible, value])
204
+
205
+ const _onDismiss = () => {
206
+ setIsFocused(false)
207
+ inputRef.current?.blur()
208
+ onDismiss()
209
+ }
210
+
211
+ const renderHelperText = useCallback(() => {
212
+ if (!!errorText) {
213
+ return (
214
+ <HelperText
215
+ type="error"
216
+ visible={!!errorText}
217
+ padding={'none'}
218
+ >{errorText}</HelperText>
219
+ )
220
+ } else if (!!hintText) {
221
+ return (
222
+ <HelperText
223
+ type="info"
224
+ visible={!!hintText}
225
+ padding={'none'}
226
+ >{hintText}</HelperText>
227
+ )
228
+ }
229
+
230
+ return null
231
+ }, [errorColor, errorText, errorTextStyle, hintText, hintTextStyle])
232
+
233
+ const inputLineColor = useMemo(() => {
234
+ if (isFocused) {
235
+ return activeColor || activeTheme.colors.primary
236
+ }
237
+
238
+ return activeTheme.colors.onSurface
239
+ }, [isFocused])
240
+
241
+ return (
242
+ <Menu
243
+ visible={visible}
244
+ onDismiss={_onDismiss}
245
+ // theme={NavigationTheme}
246
+ contentStyle={{ backgroundColor: Colors.background }}
247
+ anchor={
248
+ <>
249
+ <PressableOpacity
250
+ onPress={onPress}
251
+ onLayout={onLayout}
252
+ accessibilityLabel={accessibilityLabel}
253
+ >
254
+ <View pointerEvents={'none'}>
255
+ <MaterialTextInput
256
+ ref={inputRef}
257
+ value={displayValue}
258
+ mode={mode}
259
+ label={label}
260
+ placeholder={placeholder}
261
+ pointerEvents={'none'}
262
+ // theme={NavigationTheme}
263
+ // right={
264
+ // <TextInput.Icon icon={visible ? 'menu-up' : 'menu-down'}/>
265
+ // }
266
+ disableErrorText
267
+ showSoftInputOnFocus={false}
268
+ caretHidden
269
+ underlineColor={inputLineColor}
270
+ activeUnderlineColor={inputLineColor}
271
+ // underlineStyle={{ backgroundColor: inputLineColor, borderWidth: (isFocused ? 2 : 1) }}
272
+ outlineColor={inputLineColor}
273
+ outlineStyle={{ borderWidth: isFocused ? 2 : 1 }}
274
+ {...restInputProps}
275
+ contentStyle={{ paddingRight: 10 }}
276
+ />
277
+ <View style={{ position: 'absolute', top: 0, left: 0, right: 0, bottom: 0 }}>
278
+ <View style={{ flex: 1, flexDirection: 'row', alignItems: 'center', justifyContent: 'flex-end' }}>
279
+ <TextInput.Icon icon={visible ? 'menu-up' : 'menu-down'}/>
280
+ </View>
281
+ </View>
282
+ </View>
283
+ </PressableOpacity>
284
+ {/* {renderHelperText()} */}
285
+ </>
286
+ }
287
+ style={{
288
+ maxWidth: inputLayout?.width,
289
+ width: inputLayout?.width,
290
+ marginTop: inputLayout?.height,
291
+ ...dropDownStyle,
292
+ }}
293
+ >
294
+ <ScrollView
295
+ bounces={false}
296
+ style={{
297
+ ...(dropDownContainerHeight
298
+ ? { height: dropDownContainerHeight }
299
+ : { maxHeight: dropDownContainerMaxHeight || 350 }),
300
+ }}
301
+ >
302
+ {list.map((_item, _index) => (
303
+ <Fragment key={_item.value}>
304
+ <TouchableRipple
305
+ style={{
306
+ flexDirection: 'row',
307
+ alignItems: 'center',
308
+ }}
309
+ onPress={() => {
310
+ setActive(_item.value)
311
+ if (onDismiss) {
312
+ onDismiss()
313
+ }
314
+ }}
315
+ >
316
+ <Fragment>
317
+ <Menu.Item
318
+ titleStyle={{
319
+ color: isActive(_item.value)
320
+ ? activeColor || activeTheme.colors.primary
321
+ : (theme || activeTheme).colors.text,
322
+ ...(isActive(_item.value) ? dropDownItemSelectedTextStyle : dropDownItemTextStyle),
323
+ ...Fonts.body,
324
+ }}
325
+ title={_item.custom || _item.label}
326
+ style={{
327
+ flex: 1,
328
+ maxWidth: inputLayout?.width,
329
+ backgroundColor: Colors.background,
330
+ ...(isActive(_item.value)
331
+ ? dropDownItemSelectedStyle
332
+ : dropDownItemStyle),
333
+ }}
334
+ />
335
+ {multiSelect && (
336
+ <Checkbox.Android
337
+ theme={{ colors: { accent: activeTheme?.colors.primary } }}
338
+ status={isActive(_item.value) ? 'checked' : 'unchecked'}
339
+ onPress={() => setActive(_item.value)}
340
+ />
341
+ )}
342
+ </Fragment>
343
+ </TouchableRipple>
344
+ <Divider />
345
+ </Fragment>
346
+ ))}
347
+ </ScrollView>
348
+ </Menu>
349
+ )
350
+ }
351
+ )
352
+ DropDown.displayName = 'DropDown'
353
+
354
+ export default DropDown