@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,251 @@
1
+ import { useCallback, useRef, useState } from 'react';
2
+ import { Dimensions, Keyboard, TextProps, TouchableOpacityProps } from 'react-native';
3
+ import NotifyContext from './useNotify';
4
+ import { AlertActions, BottomSheetRef, HideOption, NotifyProviderProps, PopOverMenuProps, ShowAlertProps, ShowBottomSheetProps, ShowSnackBarProps, SnackItem } from './types';
5
+ import AlertNotify from '../notify/AlertNotify';
6
+ import SnackbarNotify from '../notify/SnackbarNotify';
7
+ import BottomSheetNotify from '../notify/BottomSheetNotify';
8
+ import LoadingNotify from '../notify/LoadingNotify';
9
+ import PopOverMenu from '../notify/PopOver/PopOverMenu';
10
+
11
+ const BS_MAX_HEIGHT = Dimensions.get('window').height - 120;
12
+
13
+ export function NotifyProvider({
14
+ customSnackbar,
15
+ loaderComponent,
16
+ children
17
+ }: NotifyProviderProps) {
18
+ // Alert
19
+ const [title, setTitle] = useState<string>('');
20
+ const [informative, setInformative] = useState<string>('');
21
+ const [alertVisible, setAlertVisible] = useState<boolean>(false);
22
+ const [actions, setActions] = useState<AlertActions>();
23
+ const [isBackgroundTouchClose, setIsBackgroundTouchClose] = useState<boolean>(true);
24
+ const [titleStyle, setTitleStyle] = useState<TextProps['style']>();
25
+ const [informativeStyle, setInformativeStyle] = useState<TextProps['style']>();
26
+ const [secondaryButtonStyle, setSecondaryButtonStyle] = useState<TouchableOpacityProps['style']>();
27
+ const [primaryButtonStyle, setPrimaryButtonStyle] = useState<TouchableOpacityProps['style']>();
28
+ const [secondaryButtonTextStyle, setSecondaryButtonTextStyle] = useState<TextProps['style']>();
29
+ const [primaryButtonTextStyle, setPrimaryButtonTextStyle] = useState<TextProps['style']>();
30
+ const [singleButtonTextStyle, setSingleButtonTextStyle] = useState<TextProps['style']>();
31
+
32
+ // Snackbar
33
+ const [snackItemStack, setSnackItemStack] = useState<SnackItem[]>([]);
34
+
35
+ // BottomSheet
36
+ const [contentsGestureEnable, setContentsGestureEnable] = useState<boolean>(false);
37
+ const [bottomSheetVisible, setBottomSheetVisible] = useState<boolean>(false);
38
+ const [bottomSheetBackgroundColor, setBottomSheetBackgroundColor] = useState<string>();
39
+ const [bottomSheetComponent, setBottomSheetComponent] = useState<React.ReactNode>(false);
40
+ const [bottomSheetPadding, setBottomSheetPadding] = useState<number | undefined>(undefined);
41
+ const [bottomSheetMarginX, setBottomSheetMarginX] = useState<number | undefined>(undefined);
42
+ const [bottomSheetMaxHeight, setBottomSheetMaxHeight] = useState<number>(BS_MAX_HEIGHT);
43
+ const [bottomSheetScrollView, setBottomSheetScrollView] = useState<boolean>(true);
44
+ const [isBottomRadius, setIsBottomRadius] = useState<boolean>(true);
45
+ const [handleVisible, setHandleVisible] = useState<boolean>(true);
46
+ const [marginBottomBS, setMarginBottomBs] = useState<number | undefined>(undefined);
47
+ const bottomSheetRef = useRef<BottomSheetRef | null>(null);
48
+
49
+ // Loading
50
+ const [loaderVisible, setLoaderVisible] = useState<boolean>(false);
51
+
52
+ // PopOver
53
+ const [popOverVisible, setPopOverVisible] = useState<boolean>(false);
54
+ const [popOverLocation, setPopOverLocation] = useState<{ px: PopOverMenuProps['px'], py: PopOverMenuProps['py'] }>({ px: 0, py: 0 });
55
+ const [popOverComponent, setPopOverComponent] = useState<React.ReactNode>(false);
56
+
57
+ // ---
58
+ const [fontFamily, setFontFamily] = useState<string | undefined | { title?: string; info?: string; label?: string; }>(undefined);
59
+
60
+
61
+ const showAlert = ({
62
+ title,
63
+ informative,
64
+ actions,
65
+ isBackgroundTouchClose = true,
66
+ titleStyle,
67
+ informativeStyle,
68
+ secondaryButtonStyle,
69
+ primaryButtonStyle,
70
+ secondaryButtonTextStyle,
71
+ primaryButtonTextStyle,
72
+ singleButtonTextStyle,
73
+ }: ShowAlertProps) => {
74
+ Keyboard.dismiss();
75
+ setTitle(title);
76
+ setInformative(informative);
77
+ setActions(actions || {} as AlertActions);
78
+ setIsBackgroundTouchClose(isBackgroundTouchClose);
79
+ setAlertVisible(true);
80
+
81
+ setTitleStyle(titleStyle);
82
+ setInformativeStyle(informativeStyle);
83
+ setSecondaryButtonStyle(secondaryButtonStyle);
84
+ setPrimaryButtonStyle(primaryButtonStyle);
85
+ setSecondaryButtonTextStyle(secondaryButtonTextStyle);
86
+ setPrimaryButtonTextStyle(primaryButtonTextStyle);
87
+ setSingleButtonTextStyle(singleButtonTextStyle);
88
+
89
+ setFontFamily(fontFamily);
90
+ };
91
+
92
+ const showBottomSheet = ({
93
+ isHandleVisible = true,
94
+ component,
95
+ contentsGestureEnable = true,
96
+ marginHorizontal,
97
+ padding,
98
+ marginBottom,
99
+ backgroundColor,
100
+ isBottomRadius = true,
101
+ maxHeight,
102
+ isScrollView = true
103
+ }: ShowBottomSheetProps) => {
104
+ Keyboard.dismiss();
105
+ padding && setBottomSheetPadding(padding);
106
+ marginBottom && setMarginBottomBs(marginBottom);
107
+ marginHorizontal && setBottomSheetMarginX(marginHorizontal);
108
+ backgroundColor && setBottomSheetBackgroundColor(backgroundColor);
109
+ maxHeight && setBottomSheetMaxHeight(maxHeight);
110
+ setContentsGestureEnable(contentsGestureEnable);
111
+ setHandleVisible(isHandleVisible);
112
+ setBottomSheetScrollView(isScrollView);
113
+ setIsBottomRadius(isBottomRadius);
114
+ setBottomSheetComponent(component);
115
+ bottomSheetRef.current?.handleVisible(true);
116
+ };
117
+
118
+ const showLoader = () => {
119
+ setLoaderVisible(true);
120
+ };
121
+
122
+ const showPopOverMenu = ({
123
+ px,
124
+ py,
125
+ component
126
+ }: PopOverMenuProps) => {
127
+ setPopOverLocation({ px, py });
128
+ setPopOverComponent(component);
129
+ setPopOverVisible(true);
130
+ }
131
+
132
+ const showSnackBar = ({
133
+ message,
134
+ type = 'success',
135
+ index = Date.now(),
136
+ snackbarDuration = 3000
137
+ }: ShowSnackBarProps) => {
138
+ // TODO: 스택 쌓고싶은데 삭제될 때 참조를 잃어서 삭제가 안되는 문제가 있음.
139
+ setSnackItemStack((prev) => {
140
+ if (prev.length === 0) {
141
+ return [...prev, { message, type, index: index, snackbarDuration: snackbarDuration }];
142
+ } else {
143
+ return prev;
144
+ };
145
+ });
146
+ };
147
+
148
+ const hideSnackBar = (index: number) => {
149
+ setSnackItemStack((prev) => prev.filter((item) => item.index !== index));
150
+ };
151
+
152
+ const hideNotify = useCallback((option: HideOption) => {
153
+ switch (option) {
154
+ case 'alert':
155
+ setAlertVisible(false);
156
+ break;
157
+ case 'snack':
158
+ setSnackItemStack([]);
159
+ break;
160
+ case 'bottomSheet':
161
+ bottomSheetRef.current?.handleVisible(false);
162
+ break;
163
+ case 'loader':
164
+ setLoaderVisible(false);
165
+ break;
166
+ case 'popOver':
167
+ setPopOverVisible(false);
168
+ break;
169
+ case 'all':
170
+ setAlertVisible(false);
171
+ setSnackItemStack([]);
172
+ setLoaderVisible(false);
173
+ setPopOverVisible(false);
174
+ bottomSheetRef.current?.handleVisible(false);
175
+ break;
176
+ default:
177
+ break;
178
+ };
179
+ }, []);
180
+
181
+
182
+ return (
183
+ <NotifyContext.Provider value={{
184
+ alertVisible,
185
+ setAlertVisible,
186
+ // ---
187
+ snackItemStack,
188
+ hideSnackBar,
189
+ // ---
190
+ bottomSheetVisible,
191
+ setBottomSheetVisible,
192
+ // ---
193
+ loaderVisible,
194
+ // ---
195
+ popOverVisible,
196
+ setPopOverVisible,
197
+ // ---
198
+ showAlert,
199
+ showSnackBar,
200
+ showBottomSheet,
201
+ showLoader,
202
+ showPopOverMenu,
203
+ // ---
204
+ hideNotify,
205
+ }}>
206
+ {children}
207
+
208
+ <BottomSheetNotify
209
+ ref={bottomSheetRef}
210
+ bottomSheetComponent={bottomSheetComponent}
211
+ contentsGestureEnable={contentsGestureEnable}
212
+ bottomSheetPadding={bottomSheetPadding}
213
+ marginBottomBS={marginBottomBS}
214
+ isHandleVisible={handleVisible}
215
+ bottomSheetMarginX={bottomSheetMarginX}
216
+ isBottomRadius={isBottomRadius}
217
+ bottomSheetBackgroundColor={bottomSheetBackgroundColor}
218
+ maxHeight={bottomSheetMaxHeight}
219
+ isScrollView={bottomSheetScrollView}
220
+ />
221
+
222
+ <PopOverMenu
223
+ px={popOverLocation?.px}
224
+ py={popOverLocation?.py}
225
+ component={popOverComponent}
226
+ />
227
+
228
+ <SnackbarNotify
229
+ customSnackbar={customSnackbar}
230
+ />
231
+
232
+ <AlertNotify
233
+ title={title}
234
+ informative={informative}
235
+ actions={actions || {} as AlertActions}
236
+ isBackgroundTouchClose={isBackgroundTouchClose}
237
+ titleStyle={titleStyle}
238
+ informativeStyle={informativeStyle}
239
+ secondaryButtonStyle={secondaryButtonStyle}
240
+ primaryButtonStyle={primaryButtonStyle}
241
+ secondaryButtonTextStyle={secondaryButtonTextStyle}
242
+ primaryButtonTextStyle={primaryButtonTextStyle}
243
+ singleButtonTextStyle={singleButtonTextStyle}
244
+ />
245
+
246
+ <LoadingNotify
247
+ loaderComponent={loaderComponent}
248
+ />
249
+ </NotifyContext.Provider>
250
+ );
251
+ }
@@ -0,0 +1,99 @@
1
+ import React, { createContext, useContext, useMemo, useState, useEffect } from 'react';
2
+ import { useColorScheme } from 'react-native';
3
+ import AsyncStorage from '@react-native-async-storage/async-storage';
4
+ import palette from '../theme/palette';
5
+ import { Theme, ThemeFonts, TypographyVariantsProps } from '../theme/types';
6
+ import typography from '../theme/typography';
7
+
8
+ export interface ThemeProviderProps {
9
+ themeFonts?: ThemeFonts;
10
+ children: React.ReactNode;
11
+ }
12
+
13
+ export interface ThemeProps {
14
+ palette: Palette;
15
+ typography: TypographyVariantsProps;
16
+ }
17
+
18
+ export interface Palette extends Theme {
19
+ mode: 'light' | 'dark';
20
+ isUsingSystemColorScheme: boolean;
21
+ setUseSystemColorScheme: (useSystem: boolean) => void;
22
+ toggleTheme: () => void;
23
+ }
24
+
25
+ const ThemeContext = createContext<ThemeProps | null>(null);
26
+
27
+ export const useTheme = () => {
28
+ const context = useContext(ThemeContext);
29
+ if (!context) {
30
+ throw new Error('useTheme must be used within a ThemeProvider');
31
+ }
32
+ return context;
33
+ }
34
+
35
+ export const ThemeProvider: React.FC<ThemeProviderProps> = ({ themeFonts, children }) => {
36
+ const systemColorScheme = useColorScheme(); // 시스템 다크 모드 감지
37
+ const [isUsingSystemColorScheme, setUseSystemColorScheme] = useState(true);
38
+ const [mode, setMode] = useState<'light' | 'dark'>(systemColorScheme === 'dark' ? 'dark' : 'light');
39
+
40
+ // AsyncStorage에서 시스템 모드 사용 설정 값 로드
41
+ useEffect(() => {
42
+ const loadSettings = async () => {
43
+ try {
44
+ const storedUseSystemColorScheme = await AsyncStorage.getItem('useSystemColorScheme');
45
+ if (storedUseSystemColorScheme !== null) {
46
+ setUseSystemColorScheme(storedUseSystemColorScheme === 'true');
47
+ }
48
+ const storedMode = await AsyncStorage.getItem('themeMode');
49
+ if (storedMode) {
50
+ setMode(storedMode === 'dark' ? 'dark' : 'light');
51
+ } else {
52
+ setMode(systemColorScheme === 'dark' ? 'dark' : 'light');
53
+ }
54
+ } catch (error) {
55
+ console.error('Failed to load theme settings', error);
56
+ }
57
+ };
58
+ loadSettings();
59
+ }, [systemColorScheme]);
60
+
61
+ // 시스템 다크 모드 변경에 따른 효과 적용
62
+ useEffect(() => {
63
+ if (isUsingSystemColorScheme) {
64
+ setMode(systemColorScheme === 'dark' ? 'dark' : 'light');
65
+ }
66
+ }, [systemColorScheme, isUsingSystemColorScheme]);
67
+
68
+ // 테마 토글 함수
69
+ const toggleTheme = async () => {
70
+ setUseSystemColorScheme(false); // 사용자 지정 모드로 전환
71
+ setMode((prevMode) => {
72
+ const newMode = prevMode === 'light' ? 'dark' : 'light';
73
+ AsyncStorage.setItem('themeMode', newMode); // 로컬스토리지에 저장
74
+ return newMode;
75
+ });
76
+ };
77
+
78
+ // 시스템 모드 사용 설정 변경 함수
79
+ const handleSetUseSystemColorScheme = async (useSystem: boolean) => {
80
+ setUseSystemColorScheme(useSystem);
81
+ await AsyncStorage.setItem('useSystemColorScheme', useSystem.toString());
82
+ };
83
+
84
+ const themeValue = useMemo(() => ({
85
+ palette: {
86
+ isUsingSystemColorScheme,
87
+ setUseSystemColorScheme: handleSetUseSystemColorScheme,
88
+ toggleTheme,
89
+ ...palette({ mode }), // 선택된 모드에 따른 팔레트 적용
90
+ },
91
+ typography: typography({ themeFonts }),
92
+ }), [mode, isUsingSystemColorScheme, typography, themeFonts]);
93
+
94
+ return (
95
+ <ThemeContext.Provider value={themeValue}>
96
+ {children}
97
+ </ThemeContext.Provider>
98
+ );
99
+ }
@@ -0,0 +1,31 @@
1
+ import { StyleProp, TextStyle } from "react-native";
2
+
3
+ /**
4
+ * 사각형의 너비와 높이에 따라 비슷한 비율의 테두리 반지름을 계산합니다.
5
+ * @param width 사각형의 너비입니다.
6
+ * @param height 사각형의 높이입니다.
7
+ * @param borderRadius 기본 테두리 반지름입니다.
8
+ * @returns 계산된 테두리 반지름입니다.
9
+ */
10
+ export const calculateRadius = (width: number, height: number, borderRadius: number) => {
11
+ const radiusRatio = Math.max((width / height), (height / width));
12
+ const calc = borderRadius * (radiusRatio > 1 ? radiusRatio / 2 : radiusRatio);
13
+ return calc;
14
+ };
15
+
16
+ export const withPromise = <T extends unknown[]>(fn: (...args: T) => Promise<unknown>): ((...args: T) => void) => {
17
+ return (...args) => { void fn(...args) };
18
+ };
19
+
20
+ export const extractStyle = (
21
+ style: StyleProp<TextStyle>,
22
+ attribute: keyof TextStyle
23
+ ): TextStyle[keyof TextStyle] | undefined => {
24
+ if (Array.isArray(style)) {
25
+ const foundStyle = style.find(item => typeof item === 'object' && item !== null && attribute in item);
26
+ return foundStyle?.[attribute as keyof typeof foundStyle];
27
+ } else if (typeof style === 'object' && style !== null && attribute in style) {
28
+ return style[attribute];
29
+ }
30
+ return undefined;
31
+ };
@@ -0,0 +1,177 @@
1
+ import React, { useCallback, useEffect, useMemo } from 'react';
2
+ import { Dimensions, KeyboardAvoidingView, Platform, Pressable, StyleSheet, TouchableOpacity, BackHandler } from 'react-native';
3
+ import Animated, { FadeInDown, FadeOutDown } from 'react-native-reanimated';
4
+ import { AlertActions, ShowAlertProps } from '../../model/types';
5
+ import { useNotify } from '../../model/useNotify';
6
+ import { useTheme } from '../../model/useThemeProvider';
7
+ import { ThemeBackground } from '../../theme';
8
+ import { ZSText } from '../../ui';
9
+ import ModalBackground from '../ui/ModalBackground';
10
+ import ViewAtom from '../../ui/atoms/ViewAtom';
11
+
12
+ const modalWidth = Dimensions.get('window').width - 60;
13
+
14
+ function AlertNotify({
15
+ actions,
16
+ title,
17
+ informative,
18
+ isBackgroundTouchClose,
19
+ titleStyle,
20
+ informativeStyle,
21
+ secondaryButtonStyle,
22
+ primaryButtonStyle,
23
+ secondaryButtonTextStyle,
24
+ primaryButtonTextStyle,
25
+ singleButtonTextStyle,
26
+ }: ShowAlertProps) {
27
+ const { alertVisible, setAlertVisible } = useNotify();
28
+ const { palette: { background, text, primary: primaryColor } } = useTheme();
29
+
30
+ const styles = useMemo(
31
+ () => createStyles({ background }),
32
+ [background, text, primaryColor]
33
+ );
34
+
35
+ // 버튼 클릭 핸들러 함수, 콜백 메모이제이션으로 성능 최적화
36
+ const handleButtonPress = useCallback(
37
+ (onPressFunction?: () => void) => () => {
38
+ if (onPressFunction) {
39
+ onPressFunction();
40
+ }
41
+ setAlertVisible(false);
42
+ },
43
+ [setAlertVisible]
44
+ );
45
+
46
+ // 뒤로가기 버튼 핸들러 함수
47
+ const backPressHandler = useCallback(() => {
48
+ if (alertVisible) {
49
+ setAlertVisible(false);
50
+ return true;
51
+ }
52
+ return false;
53
+ }, [alertVisible, setAlertVisible]);
54
+
55
+ // 뒤로가기 버튼 리스너 설정
56
+ useEffect(() => {
57
+ const backHandler = BackHandler.addEventListener('hardwareBackPress', backPressHandler);
58
+ return () => backHandler.remove();
59
+ }, [backPressHandler]);
60
+
61
+ // content를 useMemo로 감싸서 불필요한 재렌더링 방지
62
+ const content = useMemo(() => {
63
+ const { primary, secondary } = actions || {} as AlertActions;
64
+
65
+ return (
66
+ <Animated.View
67
+ entering={FadeInDown.duration(300)}
68
+ exiting={FadeOutDown.duration(100)}
69
+ >
70
+ <Pressable style={[styles.contentContainer, { width: modalWidth }]}>
71
+ {title && (
72
+ <ZSText typo='title.2' style={[styles.title, titleStyle]}>{title}</ZSText>
73
+ )}
74
+ {informative && (
75
+ <ZSText typo='body.3' style={[styles.informative, informativeStyle]}>{informative}</ZSText>
76
+ )}
77
+ {actions && (
78
+ <ViewAtom style={styles.buttonContainer}>
79
+ {secondary ? (
80
+ <>
81
+ <TouchableOpacity
82
+ style={[
83
+ styles.button,
84
+ { backgroundColor: background.neutral, marginRight: 8 },
85
+ secondaryButtonStyle
86
+ ]}
87
+ onPress={handleButtonPress(secondary?.onPress)}
88
+ >
89
+ <ZSText typo='subTitle.2' style={[secondaryButtonTextStyle]}>{secondary.label}</ZSText>
90
+ </TouchableOpacity>
91
+
92
+ <TouchableOpacity
93
+ style={[styles.button, { backgroundColor: primaryColor.main }, primaryButtonStyle]}
94
+ onPress={handleButtonPress(primary?.onPress)}
95
+ >
96
+ <ZSText typo='subTitle.2' color='white' style={[secondaryButtonTextStyle]}>{primary?.label}</ZSText>
97
+ </TouchableOpacity>
98
+ </>
99
+ ) : (
100
+ <TouchableOpacity
101
+ onPress={handleButtonPress(primary?.onPress)}
102
+ hitSlop={{ top: 10, bottom: 10, left: 10, right: 10 }}
103
+ >
104
+ <TouchableOpacity
105
+ style={[styles.button, { backgroundColor: primaryColor.main }, primaryButtonStyle]}
106
+ onPress={handleButtonPress(primary?.onPress)}
107
+ >
108
+ <ZSText typo='subTitle.2' color='white' style={[secondaryButtonTextStyle]}>{primary?.label || '확인'}</ZSText>
109
+ </TouchableOpacity>
110
+ </TouchableOpacity>
111
+ )}
112
+ </ViewAtom>
113
+ )}
114
+ </Pressable>
115
+ </Animated.View>
116
+ );
117
+ }, [title, informative, actions, handleButtonPress, titleStyle, informativeStyle, secondaryButtonStyle, primaryButtonStyle, secondaryButtonTextStyle, primaryButtonTextStyle, singleButtonTextStyle]);
118
+
119
+ return alertVisible ? (
120
+ <ModalBackground onPress={() => { if (isBackgroundTouchClose) setAlertVisible(false); }}>
121
+ <KeyboardAvoidingView
122
+ style={styles.avoidingView}
123
+ behavior={Platform.OS === 'ios' ? 'padding' : undefined}
124
+ enabled
125
+ >
126
+ {content}
127
+ </KeyboardAvoidingView>
128
+ </ModalBackground>
129
+ ) : null;
130
+ }
131
+
132
+ export default AlertNotify;
133
+
134
+ const createStyles = ({
135
+ background,
136
+ }: {
137
+ background: ThemeBackground;
138
+ }) =>
139
+ StyleSheet.create({
140
+ title: {
141
+ marginBottom: 8,
142
+ width: '100%',
143
+ paddingHorizontal: 4
144
+ },
145
+ informative: {
146
+ marginTop: 8,
147
+ width: '100%',
148
+ paddingHorizontal: 4
149
+ },
150
+ buttonContainer: {
151
+ flexDirection: 'row',
152
+ width: '100%',
153
+ marginTop: 24,
154
+ alignItems: 'center',
155
+ justifyContent: 'flex-end',
156
+ },
157
+ button: {
158
+ flex: 1,
159
+ justifyContent: 'center',
160
+ alignItems: 'center',
161
+ paddingVertical: 14,
162
+ borderRadius: 12,
163
+ },
164
+ avoidingView: {
165
+ flex: 1,
166
+ justifyContent: 'center'
167
+ },
168
+ contentContainer: {
169
+ alignItems: 'center',
170
+ backgroundColor: background.base,
171
+ borderRadius: 22,
172
+ paddingBottom: 18,
173
+ paddingTop: 24,
174
+ paddingHorizontal: 20
175
+ },
176
+ });
177
+