@0610studio/zs-ui 0.0.1

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 (250) hide show
  1. package/.eslintrc.js +5 -0
  2. package/README.md +3 -0
  3. package/android/.gradle/8.9/checksums/checksums.lock +0 -0
  4. package/android/.gradle/8.9/dependencies-accessors/gc.properties +0 -0
  5. package/android/.gradle/8.9/fileChanges/last-build.bin +0 -0
  6. package/android/.gradle/8.9/fileHashes/fileHashes.lock +0 -0
  7. package/android/.gradle/8.9/gc.properties +0 -0
  8. package/android/.gradle/buildOutputCleanup/buildOutputCleanup.lock +0 -0
  9. package/android/.gradle/buildOutputCleanup/cache.properties +2 -0
  10. package/android/.gradle/vcs-1/gc.properties +0 -0
  11. package/android/build.gradle +43 -0
  12. package/android/src/main/AndroidManifest.xml +2 -0
  13. package/android/src/main/java/kr/co/studio0610/zsui/ZsUiModule.kt +47 -0
  14. package/android/src/main/java/kr/co/studio0610/zsui/ZsUiView.kt +7 -0
  15. package/build/ZsUi.types.d.ts +7 -0
  16. package/build/ZsUi.types.d.ts.map +1 -0
  17. package/build/ZsUi.types.js +2 -0
  18. package/build/ZsUi.types.js.map +1 -0
  19. package/build/ZsUiModule.d.ts +3 -0
  20. package/build/ZsUiModule.d.ts.map +1 -0
  21. package/build/ZsUiModule.js +5 -0
  22. package/build/ZsUiModule.js.map +1 -0
  23. package/build/ZsUiModule.web.d.ts +7 -0
  24. package/build/ZsUiModule.web.d.ts.map +1 -0
  25. package/build/ZsUiModule.web.js +12 -0
  26. package/build/ZsUiModule.web.js.map +1 -0
  27. package/build/ZsUiView.d.ts +4 -0
  28. package/build/ZsUiView.d.ts.map +1 -0
  29. package/build/ZsUiView.js +7 -0
  30. package/build/ZsUiView.js.map +1 -0
  31. package/build/ZsUiView.web.d.ts +4 -0
  32. package/build/ZsUiView.web.d.ts.map +1 -0
  33. package/build/ZsUiView.web.js +7 -0
  34. package/build/ZsUiView.web.js.map +1 -0
  35. package/build/assets/SvgCheck.d.ts +7 -0
  36. package/build/assets/SvgCheck.d.ts.map +1 -0
  37. package/build/assets/SvgCheck.js +8 -0
  38. package/build/assets/SvgCheck.js.map +1 -0
  39. package/build/assets/SvgX.d.ts +6 -0
  40. package/build/assets/SvgX.d.ts.map +1 -0
  41. package/build/assets/SvgX.js +14 -0
  42. package/build/assets/SvgX.js.map +1 -0
  43. package/build/index.d.ts +5 -0
  44. package/build/index.d.ts.map +1 -0
  45. package/build/index.js +10 -0
  46. package/build/index.js.map +1 -0
  47. package/build/model/types.d.ts +84 -0
  48. package/build/model/types.d.ts.map +1 -0
  49. package/build/model/types.js +11 -0
  50. package/build/model/types.js.map +1 -0
  51. package/build/model/useNotify.d.ts +5 -0
  52. package/build/model/useNotify.d.ts.map +1 -0
  53. package/build/model/useNotify.js +11 -0
  54. package/build/model/useNotify.js.map +1 -0
  55. package/build/model/useNotifyProvider.d.ts +3 -0
  56. package/build/model/useNotifyProvider.d.ts.map +1 -0
  57. package/build/model/useNotifyProvider.js +165 -0
  58. package/build/model/useNotifyProvider.js.map +1 -0
  59. package/build/model/useThemeProvider.d.ts +19 -0
  60. package/build/model/useThemeProvider.d.ts.map +1 -0
  61. package/build/model/useThemeProvider.js +73 -0
  62. package/build/model/useThemeProvider.js.map +1 -0
  63. package/build/model/utils.d.ts +12 -0
  64. package/build/model/utils.d.ts.map +1 -0
  65. package/build/model/utils.js +26 -0
  66. package/build/model/utils.js.map +1 -0
  67. package/build/notify/AlertNotify/index.d.ts +5 -0
  68. package/build/notify/AlertNotify/index.d.ts.map +1 -0
  69. package/build/notify/AlertNotify/index.js +109 -0
  70. package/build/notify/AlertNotify/index.js.map +1 -0
  71. package/build/notify/BottomSheetNotify/index.d.ts +19 -0
  72. package/build/notify/BottomSheetNotify/index.d.ts.map +1 -0
  73. package/build/notify/BottomSheetNotify/index.js +90 -0
  74. package/build/notify/BottomSheetNotify/index.js.map +1 -0
  75. package/build/notify/BottomSheetNotify/model/useBottomSheetNotify.d.ts +43 -0
  76. package/build/notify/BottomSheetNotify/model/useBottomSheetNotify.d.ts.map +1 -0
  77. package/build/notify/BottomSheetNotify/model/useBottomSheetNotify.js +222 -0
  78. package/build/notify/BottomSheetNotify/model/useBottomSheetNotify.js.map +1 -0
  79. package/build/notify/BottomSheetNotify/types/index.d.ts +4 -0
  80. package/build/notify/BottomSheetNotify/types/index.d.ts.map +1 -0
  81. package/build/notify/BottomSheetNotify/types/index.js +2 -0
  82. package/build/notify/BottomSheetNotify/types/index.js.map +1 -0
  83. package/build/notify/BottomSheetNotify/ui/BSTextInput/index.d.ts +4 -0
  84. package/build/notify/BottomSheetNotify/ui/BSTextInput/index.d.ts.map +1 -0
  85. package/build/notify/BottomSheetNotify/ui/BSTextInput/index.js +14 -0
  86. package/build/notify/BottomSheetNotify/ui/BSTextInput/index.js.map +1 -0
  87. package/build/notify/BottomSheetNotify/ui/ContentsComponent/index.d.ts +19 -0
  88. package/build/notify/BottomSheetNotify/ui/ContentsComponent/index.d.ts.map +1 -0
  89. package/build/notify/BottomSheetNotify/ui/ContentsComponent/index.js +33 -0
  90. package/build/notify/BottomSheetNotify/ui/ContentsComponent/index.js.map +1 -0
  91. package/build/notify/LoadingNotify/index.d.ts +6 -0
  92. package/build/notify/LoadingNotify/index.d.ts.map +1 -0
  93. package/build/notify/LoadingNotify/index.js +28 -0
  94. package/build/notify/LoadingNotify/index.js.map +1 -0
  95. package/build/notify/PopOver/PopOverButton.d.ts +11 -0
  96. package/build/notify/PopOver/PopOverButton.d.ts.map +1 -0
  97. package/build/notify/PopOver/PopOverButton.js +31 -0
  98. package/build/notify/PopOver/PopOverButton.js.map +1 -0
  99. package/build/notify/PopOver/PopOverMenu.d.ts +4 -0
  100. package/build/notify/PopOver/PopOverMenu.d.ts.map +1 -0
  101. package/build/notify/PopOver/PopOverMenu.js +69 -0
  102. package/build/notify/PopOver/PopOverMenu.js.map +1 -0
  103. package/build/notify/SnackbarNotify/index.d.ts +7 -0
  104. package/build/notify/SnackbarNotify/index.d.ts.map +1 -0
  105. package/build/notify/SnackbarNotify/index.js +24 -0
  106. package/build/notify/SnackbarNotify/index.js.map +1 -0
  107. package/build/notify/SnackbarNotify/ui/SnackbarItem.d.ts +9 -0
  108. package/build/notify/SnackbarNotify/ui/SnackbarItem.d.ts.map +1 -0
  109. package/build/notify/SnackbarNotify/ui/SnackbarItem.js +72 -0
  110. package/build/notify/SnackbarNotify/ui/SnackbarItem.js.map +1 -0
  111. package/build/notify/index.d.ts +11 -0
  112. package/build/notify/index.d.ts.map +1 -0
  113. package/build/notify/index.js +11 -0
  114. package/build/notify/index.js.map +1 -0
  115. package/build/notify/ui/ModalBackground.d.ts +9 -0
  116. package/build/notify/ui/ModalBackground.d.ts.map +1 -0
  117. package/build/notify/ui/ModalBackground.js +27 -0
  118. package/build/notify/ui/ModalBackground.js.map +1 -0
  119. package/build/theme/index.d.ts +4 -0
  120. package/build/theme/index.d.ts.map +1 -0
  121. package/build/theme/index.js +4 -0
  122. package/build/theme/index.js.map +1 -0
  123. package/build/theme/palette.d.ts +62 -0
  124. package/build/theme/palette.d.ts.map +1 -0
  125. package/build/theme/palette.js +353 -0
  126. package/build/theme/palette.js.map +1 -0
  127. package/build/theme/types.d.ts +101 -0
  128. package/build/theme/types.d.ts.map +1 -0
  129. package/build/theme/types.js +5 -0
  130. package/build/theme/types.js.map +1 -0
  131. package/build/theme/typography.d.ts +5 -0
  132. package/build/theme/typography.d.ts.map +1 -0
  133. package/build/theme/typography.js +198 -0
  134. package/build/theme/typography.js.map +1 -0
  135. package/build/ui/ThrottleButton/index.d.ts +15 -0
  136. package/build/ui/ThrottleButton/index.d.ts.map +1 -0
  137. package/build/ui/ThrottleButton/index.js +74 -0
  138. package/build/ui/ThrottleButton/index.js.map +1 -0
  139. package/build/ui/ZSBottomButton/index.d.ts +16 -0
  140. package/build/ui/ZSBottomButton/index.d.ts.map +1 -0
  141. package/build/ui/ZSBottomButton/index.js +89 -0
  142. package/build/ui/ZSBottomButton/index.js.map +1 -0
  143. package/build/ui/ZSContainer/index.d.ts +19 -0
  144. package/build/ui/ZSContainer/index.d.ts.map +1 -0
  145. package/build/ui/ZSContainer/index.js +37 -0
  146. package/build/ui/ZSContainer/index.js.map +1 -0
  147. package/build/ui/ZSPressable/index.d.ts +17 -0
  148. package/build/ui/ZSPressable/index.d.ts.map +1 -0
  149. package/build/ui/ZSPressable/index.js +35 -0
  150. package/build/ui/ZSPressable/index.js.map +1 -0
  151. package/build/ui/ZSRadioGroup/index.d.ts +18 -0
  152. package/build/ui/ZSRadioGroup/index.d.ts.map +1 -0
  153. package/build/ui/ZSRadioGroup/index.js +82 -0
  154. package/build/ui/ZSRadioGroup/index.js.map +1 -0
  155. package/build/ui/ZSText/index.d.ts +11 -0
  156. package/build/ui/ZSText/index.d.ts.map +1 -0
  157. package/build/ui/ZSText/index.js +10 -0
  158. package/build/ui/ZSText/index.js.map +1 -0
  159. package/build/ui/ZSTextField/index.d.ts +31 -0
  160. package/build/ui/ZSTextField/index.d.ts.map +1 -0
  161. package/build/ui/ZSTextField/index.js +102 -0
  162. package/build/ui/ZSTextField/index.js.map +1 -0
  163. package/build/ui/ZSTextField/ui/ButtonClose.d.ts +6 -0
  164. package/build/ui/ZSTextField/ui/ButtonClose.d.ts.map +1 -0
  165. package/build/ui/ZSTextField/ui/ButtonClose.js +9 -0
  166. package/build/ui/ZSTextField/ui/ButtonClose.js.map +1 -0
  167. package/build/ui/ZSTextField/ui/ErrorComponent.d.ts +7 -0
  168. package/build/ui/ZSTextField/ui/ErrorComponent.d.ts.map +1 -0
  169. package/build/ui/ZSTextField/ui/ErrorComponent.js +16 -0
  170. package/build/ui/ZSTextField/ui/ErrorComponent.js.map +1 -0
  171. package/build/ui/ZSView/index.d.ts +8 -0
  172. package/build/ui/ZSView/index.d.ts.map +1 -0
  173. package/build/ui/ZSView/index.js +17 -0
  174. package/build/ui/ZSView/index.js.map +1 -0
  175. package/build/ui/atoms/AnimatedWrapper.d.ts +12 -0
  176. package/build/ui/atoms/AnimatedWrapper.d.ts.map +1 -0
  177. package/build/ui/atoms/AnimatedWrapper.js +61 -0
  178. package/build/ui/atoms/AnimatedWrapper.js.map +1 -0
  179. package/build/ui/atoms/ScrollViewAtom.d.ts +5 -0
  180. package/build/ui/atoms/ScrollViewAtom.d.ts.map +1 -0
  181. package/build/ui/atoms/ScrollViewAtom.js +10 -0
  182. package/build/ui/atoms/ScrollViewAtom.js.map +1 -0
  183. package/build/ui/atoms/TextAtom.d.ts +6 -0
  184. package/build/ui/atoms/TextAtom.d.ts.map +1 -0
  185. package/build/ui/atoms/TextAtom.js +9 -0
  186. package/build/ui/atoms/TextAtom.js.map +1 -0
  187. package/build/ui/atoms/ViewAtom.d.ts +6 -0
  188. package/build/ui/atoms/ViewAtom.d.ts.map +1 -0
  189. package/build/ui/atoms/ViewAtom.js +9 -0
  190. package/build/ui/atoms/ViewAtom.js.map +1 -0
  191. package/build/ui/index.d.ts +14 -0
  192. package/build/ui/index.d.ts.map +1 -0
  193. package/build/ui/index.js +14 -0
  194. package/build/ui/index.js.map +1 -0
  195. package/build/ui/types.d.ts +14 -0
  196. package/build/ui/types.d.ts.map +1 -0
  197. package/build/ui/types.js +2 -0
  198. package/build/ui/types.js.map +1 -0
  199. package/expo-module.config.json +9 -0
  200. package/ios/ZsUi.podspec +27 -0
  201. package/ios/ZsUiModule.swift +44 -0
  202. package/ios/ZsUiView.swift +7 -0
  203. package/package.json +54 -0
  204. package/src/ZsUi.types.ts +7 -0
  205. package/src/ZsUiModule.ts +5 -0
  206. package/src/ZsUiModule.web.ts +13 -0
  207. package/src/ZsUiView.tsx +11 -0
  208. package/src/ZsUiView.web.tsx +11 -0
  209. package/src/assets/SvgCheck.tsx +16 -0
  210. package/src/assets/SvgX.tsx +22 -0
  211. package/src/index.ts +52 -0
  212. package/src/model/types.ts +102 -0
  213. package/src/model/useNotify.ts +14 -0
  214. package/src/model/useNotifyProvider.tsx +251 -0
  215. package/src/model/useThemeProvider.tsx +99 -0
  216. package/src/model/utils.ts +31 -0
  217. package/src/notify/AlertNotify/index.tsx +177 -0
  218. package/src/notify/BottomSheetNotify/index.tsx +177 -0
  219. package/src/notify/BottomSheetNotify/model/useBottomSheetNotify.tsx +270 -0
  220. package/src/notify/BottomSheetNotify/types/index.ts +3 -0
  221. package/src/notify/BottomSheetNotify/ui/BSTextInput/index.tsx +28 -0
  222. package/src/notify/BottomSheetNotify/ui/ContentsComponent/index.tsx +76 -0
  223. package/src/notify/LoadingNotify/index.tsx +46 -0
  224. package/src/notify/PopOver/PopOverButton.tsx +56 -0
  225. package/src/notify/PopOver/PopOverMenu.tsx +95 -0
  226. package/src/notify/SnackbarNotify/index.tsx +43 -0
  227. package/src/notify/SnackbarNotify/ui/SnackbarItem.tsx +103 -0
  228. package/src/notify/index.ts +21 -0
  229. package/src/notify/ui/ModalBackground.tsx +46 -0
  230. package/src/theme/index.ts +3 -0
  231. package/src/theme/palette.ts +374 -0
  232. package/src/theme/types.ts +150 -0
  233. package/src/theme/typography.ts +199 -0
  234. package/src/ui/ThrottleButton/index.tsx +119 -0
  235. package/src/ui/ZSBottomButton/index.tsx +151 -0
  236. package/src/ui/ZSContainer/index.tsx +92 -0
  237. package/src/ui/ZSPressable/index.tsx +82 -0
  238. package/src/ui/ZSRadioGroup/index.tsx +141 -0
  239. package/src/ui/ZSText/index.tsx +22 -0
  240. package/src/ui/ZSTextField/index.tsx +200 -0
  241. package/src/ui/ZSTextField/ui/ButtonClose.tsx +20 -0
  242. package/src/ui/ZSTextField/ui/ErrorComponent.tsx +25 -0
  243. package/src/ui/ZSView/index.tsx +30 -0
  244. package/src/ui/atoms/AnimatedWrapper.tsx +89 -0
  245. package/src/ui/atoms/ScrollViewAtom.tsx +17 -0
  246. package/src/ui/atoms/TextAtom.tsx +15 -0
  247. package/src/ui/atoms/ViewAtom.tsx +15 -0
  248. package/src/ui/index.ts +27 -0
  249. package/src/ui/types.ts +12 -0
  250. package/tsconfig.json +9 -0
@@ -0,0 +1,150 @@
1
+ import { TextProps } from "react-native";
2
+
3
+ export type ColorPalette = {
4
+ [key: string]: string;
5
+ };
6
+
7
+ export interface ThemeTextType {
8
+ primary: string;
9
+ secondary: string;
10
+ disabled: string;
11
+ danger: string;
12
+ warning: string;
13
+ success: string;
14
+ information: string;
15
+ white: string;
16
+ black: string;
17
+ }
18
+
19
+ export interface ThemeBorderType {
20
+ box: string;
21
+ active: string;
22
+ base: string;
23
+ danger: string;
24
+ warning: string;
25
+ success: string;
26
+ information: string;
27
+ }
28
+
29
+ export interface ThemeBackground {
30
+ layer1: string;
31
+ layer2: string;
32
+ neutral: string;
33
+ base: string;
34
+ danger: string;
35
+ warning: string;
36
+ success: string;
37
+ information: string;
38
+ }
39
+
40
+ export interface MainColors {
41
+ primary: string;
42
+ secondary: string;
43
+ danger: string;
44
+ warning: string;
45
+ success: string;
46
+ information: string;
47
+ grey: string;
48
+ }
49
+
50
+ export interface Theme {
51
+ mode: 'light' | 'dark';
52
+ primary: ColorPalette;
53
+ secondary: ColorPalette;
54
+ danger: ColorPalette;
55
+ warning: ColorPalette;
56
+ success: ColorPalette;
57
+ information: ColorPalette;
58
+ grey: ColorPalette;
59
+ text: ThemeTextType;
60
+ border: ThemeBorderType;
61
+ background: ThemeBackground;
62
+ action: {
63
+ hover: string;
64
+ pressed: string;
65
+ disable: string;
66
+ };
67
+ divider: string;
68
+ elevationShadow: string[];
69
+ modalBgColor: string;
70
+ mainColor: MainColors;
71
+ }
72
+
73
+ export interface TypographyVariants {
74
+ themeFonts?: ThemeFonts;
75
+ heading: TypoNumber;
76
+ label: TypoNumber;
77
+ title: TypoNumber;
78
+ subTitle: TypoNumber;
79
+ body: TypoNumber;
80
+ caption: TypoNumber;
81
+ };
82
+
83
+ export interface ThemeFonts {
84
+ 100?: string;
85
+ 200?: string;
86
+ 300?: string;
87
+ 400: string;
88
+ 500?: string;
89
+ 600?: string;
90
+ 700: string;
91
+ 800?: string;
92
+ 900?: string;
93
+ };
94
+
95
+ export interface TypoNumber {
96
+ '1': TextProps['style'];
97
+ '2': TextProps['style'];
98
+ '3': TextProps['style'];
99
+ '4': TextProps['style'];
100
+ '5': TextProps['style'];
101
+ '6': TextProps['style'];
102
+ }
103
+
104
+ export interface TypographyVariantsProps extends TypographyVariants {
105
+ themeFonts?: ThemeFonts;
106
+ };
107
+
108
+ export type TypoStyle = 'heading' | 'title' | 'subTitle' | 'label' | 'body' | 'caption';
109
+
110
+ export type TypoOptions =
111
+ 'heading.1' |
112
+ 'heading.2' |
113
+ 'heading.3' |
114
+ 'heading.4' |
115
+ 'heading.5' |
116
+ 'heading.6' |
117
+ 'title.1' |
118
+ 'title.2' |
119
+ 'title.3' |
120
+ 'title.4' |
121
+ 'title.5' |
122
+ 'title.6' |
123
+ 'subTitle.1' |
124
+ 'subTitle.2' |
125
+ 'subTitle.3' |
126
+ 'subTitle.4' |
127
+ 'subTitle.5' |
128
+ 'subTitle.6' |
129
+ 'body.1' |
130
+ 'body.2' |
131
+ 'body.3' |
132
+ 'body.4' |
133
+ 'body.5' |
134
+ 'body.6' |
135
+ 'label.1' |
136
+ 'label.2' |
137
+ 'label.3' |
138
+ 'label.4' |
139
+ 'label.5' |
140
+ 'label.6' |
141
+ 'caption.1' |
142
+ 'caption.2' |
143
+ 'caption.3' |
144
+ 'caption.4' |
145
+ 'caption.5' |
146
+ 'caption.6';
147
+
148
+ export type TypoSubStyle = '1' | '2' | '3' | '4' | '5' | '6';
149
+
150
+ export type TextColorOptions = 'primary' | 'secondary' | 'disabled' | 'danger' | 'warning' | 'success' | 'information' | 'white' | 'black';
@@ -0,0 +1,199 @@
1
+ import { ThemeFonts, TypographyVariantsProps } from "./types";
2
+
3
+ export default function typography({ themeFonts }: { themeFonts?: ThemeFonts }): TypographyVariantsProps {
4
+ return {
5
+ themeFonts: themeFonts,
6
+ heading: {
7
+ 1: {
8
+ fontSize: 64,
9
+ fontFamily: themeFonts?.[700],
10
+ letterSpacing: 1
11
+ },
12
+ 2: {
13
+ fontSize: 48,
14
+ fontFamily: themeFonts?.[700],
15
+ letterSpacing: 1
16
+ },
17
+ 3: {
18
+ fontSize: 32,
19
+ fontFamily: themeFonts?.[700],
20
+ letterSpacing: 1
21
+ },
22
+ 4: {
23
+ fontSize: 24,
24
+ fontFamily: themeFonts?.[700],
25
+ letterSpacing: 1
26
+ },
27
+ 5: {
28
+ fontSize: 20,
29
+ fontFamily: themeFonts?.[700],
30
+ letterSpacing: 1
31
+ },
32
+ 6: {
33
+ fontSize: 18,
34
+ fontFamily: themeFonts?.[700],
35
+ letterSpacing: 1
36
+ }
37
+ },
38
+ title: {
39
+ 1: {
40
+ fontSize: 16,
41
+ fontFamily: themeFonts?.[800],
42
+ letterSpacing: 1
43
+ },
44
+ 2: {
45
+ fontSize: 14,
46
+ fontFamily: themeFonts?.[800],
47
+ letterSpacing: 1
48
+ },
49
+ 3: {
50
+ fontSize: 12,
51
+ fontFamily: themeFonts?.[800],
52
+ letterSpacing: 1
53
+ },
54
+ 4: {
55
+ fontSize: 10,
56
+ fontFamily: themeFonts?.[800],
57
+ letterSpacing: 1
58
+ },
59
+ 5: {
60
+ fontSize: 9,
61
+ fontFamily: themeFonts?.[800],
62
+ letterSpacing: 1
63
+ },
64
+ 6: {
65
+ fontSize: 8,
66
+ fontFamily: themeFonts?.[800],
67
+ letterSpacing: 1
68
+ }
69
+ },
70
+ subTitle: {
71
+ 1: {
72
+ fontSize: 16,
73
+ fontFamily: themeFonts?.[700],
74
+ letterSpacing: 1
75
+ },
76
+ 2: {
77
+ fontSize: 14,
78
+ fontFamily: themeFonts?.[700],
79
+ letterSpacing: 1
80
+ },
81
+ 3: {
82
+ fontSize: 12,
83
+ fontFamily: themeFonts?.[700],
84
+ letterSpacing: 1
85
+ },
86
+ 4: {
87
+ fontSize: 10,
88
+ fontFamily: themeFonts?.[700],
89
+ letterSpacing: 1
90
+ },
91
+ 5: {
92
+ fontSize: 9,
93
+ fontFamily: themeFonts?.[700],
94
+ letterSpacing: 1
95
+ },
96
+ 6: {
97
+ fontSize: 8,
98
+ fontFamily: themeFonts?.[700],
99
+ letterSpacing: 1
100
+ }
101
+ },
102
+ label: {
103
+ 1: {
104
+ fontSize: 16,
105
+ fontFamily: themeFonts?.[600],
106
+ letterSpacing: 1
107
+ },
108
+ 2: {
109
+ fontSize: 14,
110
+ fontFamily: themeFonts?.[600],
111
+ letterSpacing: 1
112
+ },
113
+ 3: {
114
+ fontSize: 13,
115
+ fontFamily: themeFonts?.[600],
116
+ letterSpacing: 1
117
+ },
118
+ 4: {
119
+ fontSize: 12,
120
+ fontFamily: themeFonts?.[600],
121
+ letterSpacing: 1
122
+ },
123
+ 5: {
124
+ fontSize: 11,
125
+ fontFamily: themeFonts?.[600],
126
+ letterSpacing: 1
127
+ },
128
+ 6: {
129
+ fontSize: 10,
130
+ fontFamily: themeFonts?.[600],
131
+ letterSpacing: 1
132
+ }
133
+ },
134
+ body: {
135
+ 1: {
136
+ fontSize: 16,
137
+ fontFamily: themeFonts?.[400],
138
+ letterSpacing: 1
139
+ },
140
+ 2: {
141
+ fontSize: 14,
142
+ fontFamily: themeFonts?.[400],
143
+ letterSpacing: 1
144
+ },
145
+ 3: {
146
+ fontSize: 13,
147
+ fontFamily: themeFonts?.[400],
148
+ letterSpacing: 1
149
+ },
150
+ 4: {
151
+ fontSize: 12,
152
+ fontFamily: themeFonts?.[400],
153
+ letterSpacing: 1
154
+ },
155
+ 5: {
156
+ fontSize: 11,
157
+ fontFamily: themeFonts?.[400],
158
+ letterSpacing: 1
159
+ },
160
+ 6: {
161
+ fontSize: 10,
162
+ fontFamily: themeFonts?.[400],
163
+ letterSpacing: 1
164
+ }
165
+ },
166
+ caption: {
167
+ 1: {
168
+ fontSize: 12,
169
+ fontFamily: themeFonts?.[400],
170
+ letterSpacing: 1
171
+ },
172
+ 2: {
173
+ fontSize: 11,
174
+ fontFamily: themeFonts?.[400],
175
+ letterSpacing: 1
176
+ },
177
+ 3: {
178
+ fontSize: 10,
179
+ fontFamily: themeFonts?.[400],
180
+ letterSpacing: 1
181
+ },
182
+ 4: {
183
+ fontSize: 9,
184
+ fontFamily: themeFonts?.[400],
185
+ letterSpacing: 1
186
+ },
187
+ 5: {
188
+ fontSize: 8,
189
+ fontFamily: themeFonts?.[400],
190
+ letterSpacing: 1
191
+ },
192
+ 6: {
193
+ fontSize: 7,
194
+ fontFamily: themeFonts?.[400],
195
+ letterSpacing: 1
196
+ }
197
+ },
198
+ }
199
+ }
@@ -0,0 +1,119 @@
1
+ import React, { useCallback, useEffect, useRef, useState } from 'react';
2
+ import { ActivityIndicator, StyleSheet, TouchableOpacity, TouchableOpacityProps, View } from 'react-native';
3
+
4
+ const DEFAULT_MARGIN_X = 20;
5
+ const DEFAULT_MARGIN_TOP = 0;
6
+ const DEFAULT_MARGIN_BOTTOM = 20;
7
+ const DEFAULT_BORDER_RADIUS = 8;
8
+
9
+ const TIME_CONSTANTS = {
10
+ debounce: 300,
11
+ throttle: 2000,
12
+ } as const;
13
+
14
+ interface ThrottleButtonProps extends TouchableOpacityProps {
15
+ loadingComponent?: React.ReactNode;
16
+ disabled?: boolean;
17
+ primaryOnPress: () => Promise<void>;
18
+ primaryLabelComponent: React.ReactNode;
19
+ primaryButtonStyle?: TouchableOpacityProps['style'];
20
+ marginHorizontal?: number;
21
+ marginBottom?: number;
22
+ onError?: (error: Error) => void;
23
+ }
24
+
25
+ const useAsyncButton = (
26
+ onPress: () => Promise<void>,
27
+ onError?: (error: Error) => void
28
+ ) => {
29
+ const [isLoading, setIsLoading] = useState(false);
30
+ const lastClickTime = useRef<number>(0);
31
+ const isMounted = useRef<boolean>(true);
32
+
33
+ useEffect(() => {
34
+ return () => {
35
+ isMounted.current = false;
36
+ };
37
+ }, []);
38
+
39
+ const handlePress = useCallback(async () => {
40
+ const now = Date.now();
41
+
42
+ if (now - lastClickTime.current < TIME_CONSTANTS.debounce) {
43
+ return;
44
+ }
45
+
46
+ if (isLoading) {
47
+ return;
48
+ }
49
+
50
+ lastClickTime.current = now;
51
+
52
+ try {
53
+ setIsLoading(true);
54
+ await onPress();
55
+ await new Promise(resolve =>
56
+ setTimeout(resolve, TIME_CONSTANTS.throttle)
57
+ );
58
+ } catch (error: unknown) {
59
+ if (error instanceof Error && onError) {
60
+ onError(error);
61
+ }
62
+ console.error('ThrottleButton error:', error);
63
+ } finally {
64
+ if (isMounted.current) {
65
+ setIsLoading(false);
66
+ }
67
+ }
68
+ }, [onPress, onError, isLoading]);
69
+
70
+ return { isLoading, handlePress };
71
+ };
72
+
73
+ function ThrottleButton({
74
+ loadingComponent = <ActivityIndicator />,
75
+ disabled = false,
76
+ primaryOnPress,
77
+ primaryLabelComponent,
78
+ primaryButtonStyle = {},
79
+ marginHorizontal,
80
+ marginBottom = DEFAULT_MARGIN_BOTTOM,
81
+ onError,
82
+ ...touchableProps
83
+ }: ThrottleButtonProps) {
84
+ const { isLoading, handlePress } = useAsyncButton(primaryOnPress, onError);
85
+
86
+ return (
87
+ <View style={[styles.container, { marginHorizontal: marginHorizontal ?? DEFAULT_MARGIN_X, marginBottom }]}>
88
+ <TouchableOpacity
89
+ activeOpacity={0.7}
90
+ style={[primaryButtonStyle, styles.touchContainer, { opacity: isLoading ? 0.4 : 1 }]}
91
+ onPress={handlePress}
92
+ disabled={disabled || isLoading}
93
+ {...touchableProps}
94
+ >
95
+ {isLoading ? loadingComponent : primaryLabelComponent}
96
+ </TouchableOpacity>
97
+ </View>
98
+ );
99
+ }
100
+
101
+ const styles = StyleSheet.create({
102
+ touchContainer: {
103
+ justifyContent: 'center',
104
+ alignItems: 'center',
105
+ flex: 1
106
+ },
107
+ container: {
108
+ justifyContent: 'center',
109
+ alignItems: 'center',
110
+ borderRadius: DEFAULT_BORDER_RADIUS,
111
+ marginTop: DEFAULT_MARGIN_TOP,
112
+ marginBottom: DEFAULT_MARGIN_BOTTOM,
113
+ overflow: 'hidden',
114
+ flexDirection: 'row',
115
+ flex: 1
116
+ },
117
+ });
118
+
119
+ export default ThrottleButton;
@@ -0,0 +1,151 @@
1
+ import React, { useEffect, useState } from "react";
2
+ import { ActivityIndicator, Keyboard, Platform, StyleSheet, TouchableOpacity, TouchableOpacityProps } from "react-native";
3
+ import Animated, { interpolate, useAnimatedStyle, useSharedValue, withTiming } from "react-native-reanimated";
4
+ import { withPromise } from "../../model/utils";
5
+
6
+ const DEFAULT_MARGIN_X = 20;
7
+ const DEFAULT_MARGIN_TOP = 0;
8
+ const DEFAULT_MARGIN_BOTTOM = 20;
9
+ const DEFAULT_BORDER_RADIUS = 14;
10
+ const DURATION = { duration: 250 };
11
+
12
+ interface Props {
13
+ loadingComponent?: React.ReactNode;
14
+ height?: number;
15
+ disabled?: boolean;
16
+ primaryOnPress: () => Promise<any>;
17
+ primaryLabelComponent: React.ReactNode;
18
+ primaryButtonStyle?: TouchableOpacityProps['style'];
19
+ secondaryOnPress?: () => void;
20
+ secondaryLabelComponent?: React.ReactNode;
21
+ secondaryButtonStyle?: TouchableOpacityProps['style'];
22
+ }
23
+
24
+ function ZSBottomButton({
25
+ loadingComponent = <ActivityIndicator />,
26
+ height = 55,
27
+ disabled = false,
28
+ primaryLabelComponent,
29
+ primaryOnPress,
30
+ primaryButtonStyle = {},
31
+ secondaryOnPress,
32
+ secondaryLabelComponent,
33
+ secondaryButtonStyle = {}
34
+ }: Props) {
35
+ const isKeyboardVisible = useSharedValue(0);
36
+ const keyboardHeight = useSharedValue(0);
37
+ const [isLoading, setIsLoading] = useState<boolean>(false);
38
+
39
+ const handlePress = async () => {
40
+ setIsLoading(true);
41
+ try {
42
+ await withPromise(primaryOnPress);
43
+ } finally {
44
+ setIsLoading(false);
45
+ }
46
+ };
47
+
48
+ // ** 소프트 키보드 핸들링
49
+ useEffect(() => {
50
+ const showEvent = Platform.OS === 'ios' ? 'keyboardWillShow' : 'keyboardDidShow';
51
+ const hideEvent = Platform.OS === 'ios' ? 'keyboardWillHide' : 'keyboardDidHide';
52
+
53
+ const keyboardDidShowListener = Keyboard.addListener(showEvent, (event) => {
54
+ requestAnimationFrame(() => {
55
+ keyboardHeight.value = event.endCoordinates.height; // 키보드 높이 설정
56
+ isKeyboardVisible.value = 1; // 키보드가 보임
57
+ });
58
+ });
59
+
60
+ const keyboardDidHideListener = Keyboard.addListener(hideEvent, () => {
61
+ requestAnimationFrame(() => {
62
+ isKeyboardVisible.value = 0; // 키보드가 숨김
63
+ });
64
+ });
65
+
66
+ return () => {
67
+ keyboardDidShowListener.remove();
68
+ keyboardDidHideListener.remove();
69
+ };
70
+ }, [isKeyboardVisible, keyboardHeight]);
71
+
72
+ // ** 애니메이션 스타일을 useAnimatedStyle로 최적화
73
+ const animatedStyle = useAnimatedStyle(() => {
74
+ const getBottom = interpolate(
75
+ isKeyboardVisible.value,
76
+ [0, 1],
77
+ [DEFAULT_MARGIN_BOTTOM, 0],
78
+ 'clamp',
79
+ );
80
+
81
+ const getMargin = interpolate(
82
+ isKeyboardVisible.value,
83
+ [0, 1],
84
+ [DEFAULT_MARGIN_X, 0],
85
+ 'clamp',
86
+ );
87
+
88
+ const getRadius = interpolate(
89
+ isKeyboardVisible.value,
90
+ [0, 1],
91
+ [DEFAULT_BORDER_RADIUS, 0],
92
+ 'clamp',
93
+ );
94
+
95
+ return {
96
+ marginBottom: withTiming(getBottom, DURATION),
97
+ marginLeft: withTiming(getMargin, DURATION),
98
+ marginRight: withTiming(getMargin, DURATION),
99
+ borderRadius: withTiming(getRadius, DURATION),
100
+ };
101
+ });
102
+
103
+ return (
104
+ <Animated.View style={[styles.container, animatedStyle]}>
105
+ {secondaryLabelComponent && (
106
+ <TouchableOpacity
107
+ activeOpacity={0.7}
108
+ style={[secondaryButtonStyle, { height }, styles.touchSecondaryContainer]}
109
+ onPress={secondaryOnPress}
110
+ >
111
+ {secondaryLabelComponent}
112
+ </TouchableOpacity>
113
+ )}
114
+
115
+ <TouchableOpacity
116
+ activeOpacity={0.7}
117
+ style={[primaryButtonStyle, { height }, styles.touchContainer]}
118
+ onPress={handlePress}
119
+ disabled={disabled || isLoading}
120
+ >
121
+ {isLoading ? loadingComponent : primaryLabelComponent}
122
+ </TouchableOpacity>
123
+ </Animated.View>
124
+ );
125
+ }
126
+
127
+ const styles = StyleSheet.create({
128
+ touchContainer: {
129
+ justifyContent: 'center',
130
+ alignItems: 'center',
131
+ flex: 2,
132
+ },
133
+ touchSecondaryContainer: {
134
+ justifyContent: 'center',
135
+ alignItems: 'center',
136
+ flex: 1,
137
+ },
138
+ container: {
139
+ justifyContent: 'center',
140
+ alignItems: 'center',
141
+ borderRadius: DEFAULT_BORDER_RADIUS,
142
+ marginTop: DEFAULT_MARGIN_TOP,
143
+ marginBottom: DEFAULT_MARGIN_BOTTOM,
144
+ marginLeft: DEFAULT_MARGIN_X,
145
+ marginRight: DEFAULT_MARGIN_X,
146
+ overflow: 'hidden',
147
+ flexDirection: 'row',
148
+ },
149
+ });
150
+
151
+ export default ZSBottomButton;
@@ -0,0 +1,92 @@
1
+ import React, { ReactNode, useState, useEffect } from 'react';
2
+ import { ViewProps, KeyboardAvoidingView, StatusBar, StyleSheet, Dimensions, ActivityIndicator, Platform, ScrollView } from 'react-native';
3
+ import { SafeAreaView } from 'react-native-safe-area-context';
4
+ import ViewAtom from '../atoms/ViewAtom';
5
+ import ScrollViewAtom from '../atoms/ScrollViewAtom';
6
+ import { useTheme } from '../../model/useThemeProvider';
7
+
8
+ type ZSContainerProps = ViewProps & {
9
+ backgroundColor?: string;
10
+ isLoader?: boolean;
11
+ statusBarColor?: string;
12
+ barStyle?: 'light-content' | 'dark-content';
13
+ edges?: Array<'top' | 'right' | 'bottom' | 'left'>;
14
+ isScrollView?: boolean;
15
+ scrollViewRef?: React.RefObject<ScrollView>;
16
+ topComponent?: ReactNode;
17
+ bottomComponent?: ReactNode;
18
+ showsVerticalScrollIndicator?: boolean;
19
+ loadingComponent?: React.ReactNode;
20
+ keyboardVerticalOffset?: number;
21
+ };
22
+
23
+ function ZSContainer({
24
+ backgroundColor,
25
+ isLoader = false,
26
+ statusBarColor,
27
+ barStyle = 'dark-content',
28
+ edges = ['top', 'bottom'],
29
+ isScrollView = true,
30
+ scrollViewRef,
31
+ topComponent,
32
+ bottomComponent,
33
+ showsVerticalScrollIndicator = true,
34
+ loadingComponent = <ActivityIndicator />,
35
+ keyboardVerticalOffset,
36
+ ...props
37
+ }: ZSContainerProps) {
38
+ const { palette } = useTheme(); // 테마 사용
39
+ const [isDelayed, setIsDelayed] = useState(true);
40
+
41
+ useEffect(() => {
42
+ const timer = setTimeout(() => {
43
+ setIsDelayed(false);
44
+ }, 200);
45
+ return () => clearTimeout(timer);
46
+ }, []);
47
+
48
+ return (
49
+ <SafeAreaView style={[{ backgroundColor: backgroundColor || palette.background.base }, styles.flex1]} edges={edges}>
50
+ <StatusBar barStyle={barStyle} backgroundColor={statusBarColor || palette.background.base} />
51
+
52
+ {!isDelayed && (
53
+ <KeyboardAvoidingView
54
+ style={styles.flex1}
55
+ behavior={Platform.OS === 'ios' ? 'padding' : undefined}
56
+ keyboardVerticalOffset={keyboardVerticalOffset}
57
+ enabled
58
+ >
59
+ {topComponent && topComponent}
60
+
61
+ {isLoader ? (
62
+ loadingComponent
63
+ ) : isScrollView ? (
64
+ <ScrollViewAtom
65
+ ref={scrollViewRef}
66
+ style={styles.flex1}
67
+ bounces={false}
68
+ contentContainerStyle={styles.scrollContainerStyle}
69
+ showsVerticalScrollIndicator={showsVerticalScrollIndicator}
70
+ keyboardShouldPersistTaps="handled"
71
+ >
72
+ <ViewAtom style={[styles.flex1, props.style]}>
73
+ {props.children}
74
+ </ViewAtom>
75
+ </ScrollViewAtom>
76
+ ) : (
77
+ <ViewAtom style={[styles.flex1, props.style]}>{props.children}</ViewAtom>
78
+ )}
79
+
80
+ {!isLoader && bottomComponent && bottomComponent}
81
+ </KeyboardAvoidingView>
82
+ )}
83
+ </SafeAreaView>
84
+ );
85
+ }
86
+
87
+ const styles = StyleSheet.create({
88
+ flex1: { flex: 1, width: Dimensions.get('window').width },
89
+ scrollContainerStyle: { flexGrow: 1, alignItems: 'center' },
90
+ });
91
+
92
+ export default ZSContainer;