@0610studio/zs-ui 0.7.1 → 0.7.3

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 (55) hide show
  1. package/build/index.d.ts +5 -4
  2. package/build/index.d.ts.map +1 -1
  3. package/build/index.js +4 -3
  4. package/build/index.js.map +1 -1
  5. package/build/model/types.d.ts +4 -10
  6. package/build/model/types.d.ts.map +1 -1
  7. package/build/model/types.js.map +1 -1
  8. package/build/model/useOverlay.d.ts +1 -3
  9. package/build/model/useOverlay.d.ts.map +1 -1
  10. package/build/model/useOverlay.js +0 -8
  11. package/build/model/useOverlay.js.map +1 -1
  12. package/build/model/useOverlayProvider.d.ts.map +1 -1
  13. package/build/model/useOverlayProvider.js +11 -38
  14. package/build/model/useOverlayProvider.js.map +1 -1
  15. package/build/model/utils.d.ts.map +1 -1
  16. package/build/model/utils.js.map +1 -1
  17. package/build/overlay/BottomSheetOverlay/index.d.ts +2 -1
  18. package/build/overlay/BottomSheetOverlay/index.d.ts.map +1 -1
  19. package/build/overlay/BottomSheetOverlay/index.js +144 -91
  20. package/build/overlay/BottomSheetOverlay/index.js.map +1 -1
  21. package/build/overlay/ZSPortal/index.d.ts +11 -0
  22. package/build/overlay/ZSPortal/index.d.ts.map +1 -0
  23. package/build/overlay/ZSPortal/index.js +49 -0
  24. package/build/overlay/ZSPortal/index.js.map +1 -0
  25. package/build/overlay/index.d.ts +2 -1
  26. package/build/overlay/index.d.ts.map +1 -1
  27. package/build/overlay/index.js +2 -1
  28. package/build/overlay/index.js.map +1 -1
  29. package/build/ui/ZSAboveKeyboard/index.d.ts +9 -0
  30. package/build/ui/ZSAboveKeyboard/index.d.ts.map +1 -0
  31. package/build/ui/ZSAboveKeyboard/index.js +56 -0
  32. package/build/ui/ZSAboveKeyboard/index.js.map +1 -0
  33. package/build/ui/ZSContainer/index.d.ts +16 -14
  34. package/build/ui/ZSContainer/index.d.ts.map +1 -1
  35. package/build/ui/ZSContainer/index.js +78 -40
  36. package/build/ui/ZSContainer/index.js.map +1 -1
  37. package/build/ui/ZSPressable/index.d.ts +2 -1
  38. package/build/ui/ZSPressable/index.d.ts.map +1 -1
  39. package/build/ui/ZSPressable/index.js +40 -16
  40. package/build/ui/ZSPressable/index.js.map +1 -1
  41. package/build/ui/ZSTextField/index.d.ts.map +1 -1
  42. package/build/ui/ZSTextField/index.js +127 -41
  43. package/build/ui/ZSTextField/index.js.map +1 -1
  44. package/build/ui/atoms/AnimatedWrapper.d.ts.map +1 -1
  45. package/build/ui/atoms/AnimatedWrapper.js +58 -16
  46. package/build/ui/atoms/AnimatedWrapper.js.map +1 -1
  47. package/package.json +1 -1
  48. package/build/overlay/AboveKeyboard/index.d.ts +0 -4
  49. package/build/overlay/AboveKeyboard/index.d.ts.map +0 -1
  50. package/build/overlay/AboveKeyboard/index.js +0 -41
  51. package/build/overlay/AboveKeyboard/index.js.map +0 -1
  52. package/build/ui/ZSContainer/ui/VariantView.d.ts +0 -17
  53. package/build/ui/ZSContainer/ui/VariantView.d.ts.map +0 -1
  54. package/build/ui/ZSContainer/ui/VariantView.js +0 -13
  55. package/build/ui/ZSContainer/ui/VariantView.js.map +0 -1
@@ -1,75 +1,113 @@
1
- import React, { useEffect, useImperativeHandle, forwardRef, useRef, useState } from 'react';
1
+ import React, { useEffect, useImperativeHandle, forwardRef, useRef, useState, useCallback, useMemo } from 'react';
2
2
  import { StatusBar, StyleSheet, ScrollView, Keyboard, View, Platform } from 'react-native';
3
3
  import { SafeAreaView } from 'react-native-safe-area-context';
4
4
  import { useTheme } from '../../model/useThemeProvider';
5
- const ZSContainer = forwardRef(function ZSContainer({ backgroundColor, statusBarColor, barStyle, edges = ['top', 'bottom'], scrollViewDisabled = false, topComponent, bottomComponent, rightComponent, showsVerticalScrollIndicator = true, keyboardScrollExtraOffset = 30, translucent, scrollEventThrottle = 16, ...props }, forwardedRef) {
5
+ const IS_IOS = Platform.OS === 'ios';
6
+ const KEYBOARD_ANIMATION_DELAY = 50;
7
+ const keyboardEvents = {
8
+ showEvent: IS_IOS ? 'keyboardWillShow' : 'keyboardDidShow',
9
+ hideEvent: IS_IOS ? 'keyboardWillHide' : 'keyboardDidHide',
10
+ };
11
+ const ZSContainer = forwardRef(function ZSContainer({ backgroundColor, statusBarColor, barStyle, edges = ['top', 'bottom'], scrollViewDisabled = false, topComponent, bottomComponent, rightComponent, showsVerticalScrollIndicator = true, keyboardScrollExtraOffset = 30, translucent, scrollEventThrottle = 16, scrollToFocusedInput = true, ...props }, forwardedRef) {
6
12
  const { palette, dimensions: { height: windowHeight } } = useTheme();
7
13
  const positionRef = useRef(0);
8
14
  const scrollViewRef = useRef(null);
9
15
  const lastTouchY = useRef(0);
10
16
  const [keyboardHeight, setKeyboardHeight] = useState(0);
11
17
  useImperativeHandle(forwardedRef, () => scrollViewRef.current, []);
18
+ const handleKeyboardShow = useCallback((e) => {
19
+ setKeyboardHeight(e.endCoordinates.height);
20
+ if (scrollViewRef.current && scrollToFocusedInput) {
21
+ const keyboardHeight = e.endCoordinates.height;
22
+ const safeAreaBottom = 0;
23
+ const availableScreenHeight = windowHeight - keyboardHeight - safeAreaBottom;
24
+ const currentScrollPosition = positionRef.current || 0;
25
+ const touchPosition = lastTouchY.current || 0;
26
+ // 현재 터치 위치와 스크롤 위치를 기반으로 새로운 스크롤 위치 계산
27
+ const scrollOffset = touchPosition - availableScreenHeight + keyboardScrollExtraOffset;
28
+ setTimeout(() => {
29
+ scrollViewRef.current?.scrollTo({
30
+ y: currentScrollPosition + scrollOffset,
31
+ animated: true,
32
+ });
33
+ }, KEYBOARD_ANIMATION_DELAY);
34
+ }
35
+ }, [windowHeight, keyboardScrollExtraOffset, scrollToFocusedInput]);
36
+ // 키보드 숨김 핸들러를 메모이제이션하여 성능 최적화
37
+ const handleKeyboardHide = useCallback(() => {
38
+ setKeyboardHeight(0);
39
+ }, []);
12
40
  useEffect(() => {
13
- const showEvent = Platform.OS === 'ios' ? 'keyboardWillShow' : 'keyboardDidShow';
14
- const hideEvent = Platform.OS === 'ios' ? 'keyboardWillHide' : 'keyboardDidHide';
15
- const keyboardShowSubscription = Keyboard.addListener(showEvent, (e) => {
16
- setKeyboardHeight(e.endCoordinates.height);
17
- if (scrollViewRef.current) {
18
- const screenHeight = windowHeight;
19
- const keyboardHeight = e.endCoordinates.height;
20
- const safeAreaBottom = 0;
21
- const availableScreenHeight = screenHeight - keyboardHeight - safeAreaBottom;
22
- const currentScrollPosition = positionRef.current || 0;
23
- const touchPosition = lastTouchY.current || 0;
24
- // touchPosition이 키보드 높이보다 아래인 경우
25
- // const isTouchPositionBelowKeyboard = touchPosition > availableScreenHeight;
26
- // 현재 터치 위치와 스크롤 위치를 기반으로 새로운 스크롤 위치 계산
27
- const scrollOffset = touchPosition - availableScreenHeight + keyboardScrollExtraOffset;
28
- setTimeout(() => {
29
- scrollViewRef.current?.scrollTo({
30
- y: currentScrollPosition + scrollOffset,
31
- animated: true,
32
- });
33
- }, 100);
34
- }
35
- });
36
- const keyboardHideSubscription = Keyboard.addListener(hideEvent, () => {
37
- setKeyboardHeight(0);
38
- });
41
+ const keyboardShowSubscription = Keyboard.addListener(keyboardEvents.showEvent, handleKeyboardShow);
42
+ const keyboardHideSubscription = Keyboard.addListener(keyboardEvents.hideEvent, handleKeyboardHide);
39
43
  return () => {
40
44
  positionRef.current = null;
41
45
  lastTouchY.current = null;
42
46
  keyboardShowSubscription.remove();
43
47
  keyboardHideSubscription.remove();
44
48
  };
45
- }, [keyboardScrollExtraOffset]);
46
- const handleScroll = (event) => {
49
+ }, [keyboardEvents.showEvent, keyboardEvents.hideEvent, handleKeyboardShow, handleKeyboardHide]);
50
+ const handleScroll = useCallback((event) => {
47
51
  if (props.onScroll)
48
52
  props.onScroll(event);
49
53
  positionRef.current = event.nativeEvent.contentOffset.y;
50
- };
51
- const handleTouch = (evt) => {
54
+ }, [props.onScroll]);
55
+ const handleTouch = useCallback((evt) => {
52
56
  lastTouchY.current = evt.nativeEvent.pageY;
53
- };
54
- return (<SafeAreaView style={[{ backgroundColor: backgroundColor || palette.background.base }, styles.flex1]} edges={edges}>
57
+ }, []);
58
+ const safeAreaStyle = useMemo(() => [
59
+ { backgroundColor: backgroundColor || palette.background.base },
60
+ styles.flex1
61
+ ], [backgroundColor, palette.background.base]);
62
+ const scrollContentStyle = useMemo(() => [
63
+ styles.scrollContainerStyle,
64
+ {
65
+ paddingBottom: keyboardHeight ? (IS_IOS ? keyboardHeight : keyboardScrollExtraOffset) : 0
66
+ }
67
+ ], [keyboardHeight, keyboardScrollExtraOffset]);
68
+ const containerStyle = useMemo(() => [
69
+ styles.flex1,
70
+ props.style
71
+ ], [props.style]);
72
+ const shouldShowStatusBar = useMemo(() => Boolean(barStyle || statusBarColor || translucent), [barStyle, statusBarColor, translucent]);
73
+ return (<SafeAreaView style={safeAreaStyle} edges={edges}>
55
74
  <View style={styles.flex1}>
56
- {topComponent && topComponent}
75
+ {topComponent}
57
76
  {scrollViewDisabled ? (<View style={styles.flex1}>
58
77
  {props.children}
59
- </View>) : (<ScrollView ref={scrollViewRef} style={styles.flex1} contentContainerStyle={[styles.scrollContainerStyle, { paddingBottom: Platform.OS === 'ios' ? keyboardHeight || 0 : 0 }]} bounces={false} overScrollMode="never" showsVerticalScrollIndicator={showsVerticalScrollIndicator} keyboardShouldPersistTaps="handled" automaticallyAdjustKeyboardInsets={false} onScroll={handleScroll} onTouchStart={handleTouch} scrollEventThrottle={scrollEventThrottle}>
60
- <View style={[styles.flex1, props.style]}>
78
+ </View>) : (<ScrollView ref={scrollViewRef} style={styles.flex1} contentContainerStyle={scrollContentStyle} bounces={false} overScrollMode="never" showsVerticalScrollIndicator={showsVerticalScrollIndicator} keyboardShouldPersistTaps="handled" automaticallyAdjustKeyboardInsets={false} onScroll={handleScroll} onTouchStart={handleTouch} scrollEventThrottle={scrollEventThrottle}>
79
+ <View style={containerStyle}>
61
80
  {props.children}
62
81
  </View>
63
82
  </ScrollView>)}
64
- {bottomComponent && bottomComponent}
83
+ {bottomComponent}
65
84
  </View>
66
85
 
67
- {(barStyle || statusBarColor || translucent) && (<StatusBar barStyle={barStyle} backgroundColor={statusBarColor || palette.background.base} translucent={translucent}/>)}
86
+ {shouldShowStatusBar && (<StatusBar barStyle={barStyle} backgroundColor={statusBarColor || palette.background.base} translucent={translucent}/>)}
68
87
  </SafeAreaView>);
69
88
  });
70
89
  export const styles = StyleSheet.create({
71
90
  flex1: { flex: 1, width: '100%' },
72
91
  scrollContainerStyle: { flexGrow: 1, alignItems: 'center', width: '100%' },
73
92
  });
74
- export default ZSContainer;
93
+ const arePropsEqual = (prevProps, nextProps) => {
94
+ return (prevProps.backgroundColor === nextProps.backgroundColor &&
95
+ prevProps.statusBarColor === nextProps.statusBarColor &&
96
+ prevProps.barStyle === nextProps.barStyle &&
97
+ prevProps.scrollViewDisabled === nextProps.scrollViewDisabled &&
98
+ prevProps.showsVerticalScrollIndicator === nextProps.showsVerticalScrollIndicator &&
99
+ prevProps.keyboardScrollExtraOffset === nextProps.keyboardScrollExtraOffset &&
100
+ prevProps.translucent === nextProps.translucent &&
101
+ prevProps.scrollEventThrottle === nextProps.scrollEventThrottle &&
102
+ prevProps.scrollToFocusedInput === nextProps.scrollToFocusedInput &&
103
+ prevProps.onScroll === nextProps.onScroll &&
104
+ prevProps.style === nextProps.style &&
105
+ prevProps.children === nextProps.children &&
106
+ prevProps.topComponent === nextProps.topComponent &&
107
+ prevProps.bottomComponent === nextProps.bottomComponent &&
108
+ prevProps.rightComponent === nextProps.rightComponent &&
109
+ // edges 배열 비교
110
+ JSON.stringify(prevProps.edges) === JSON.stringify(nextProps.edges));
111
+ };
112
+ export default React.memo(ZSContainer, arePropsEqual);
75
113
  //# sourceMappingURL=index.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"index.js","sourceRoot":"","sources":["../../../src/ui/ZSContainer/index.tsx"],"names":[],"mappings":"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","sourcesContent":["import React, { ReactNode, useEffect, useImperativeHandle, forwardRef, useRef, useState } from 'react';\r\nimport { ViewProps, StatusBar, StyleSheet, ScrollView, NativeSyntheticEvent, NativeScrollEvent, Keyboard, View, Platform } from 'react-native';\r\nimport { SafeAreaView } from 'react-native-safe-area-context';\r\nimport { useTheme } from '../../model/useThemeProvider';\r\n\r\nexport type ZSContainerProps = ViewProps & {\r\n backgroundColor?: string;\r\n statusBarColor?: string;\r\n barStyle?: 'light-content' | 'dark-content';\r\n edges?: Array<'top' | 'right' | 'bottom' | 'left'>;\r\n scrollViewDisabled?: boolean;\r\n topComponent?: ReactNode;\r\n bottomComponent?: ReactNode;\r\n rightComponent?: ReactNode;\r\n showsVerticalScrollIndicator?: boolean;\r\n keyboardScrollExtraOffset?: number;\r\n translucent?: boolean;\r\n onScroll?: (event: NativeSyntheticEvent<NativeScrollEvent>) => void;\r\n scrollEventThrottle?: number;\r\n};\r\n\r\nexport type ZSContainerRef = ScrollView;\r\n\r\nconst ZSContainer = forwardRef<ZSContainerRef, ZSContainerProps>(function ZSContainer(\r\n {\r\n backgroundColor,\r\n statusBarColor,\r\n barStyle,\r\n edges = ['top', 'bottom'],\r\n scrollViewDisabled = false,\r\n topComponent,\r\n bottomComponent,\r\n rightComponent,\r\n showsVerticalScrollIndicator = true,\r\n keyboardScrollExtraOffset = 30,\r\n translucent,\r\n scrollEventThrottle = 16,\r\n ...props\r\n },\r\n forwardedRef\r\n) {\r\n const { palette, dimensions: { height: windowHeight } } = useTheme();\r\n const positionRef = useRef<number | null>(0);\r\n const scrollViewRef = useRef<ScrollView>(null);\r\n const lastTouchY = useRef<number | null>(0);\r\n const [keyboardHeight, setKeyboardHeight] = useState<number | null>(0);\r\n\r\n useImperativeHandle(forwardedRef, () => scrollViewRef.current as ScrollView, []);\r\n\r\n useEffect(() => {\r\n const showEvent = Platform.OS === 'ios' ? 'keyboardWillShow' : 'keyboardDidShow';\r\n const hideEvent = Platform.OS === 'ios' ? 'keyboardWillHide' : 'keyboardDidHide';\r\n\r\n const keyboardShowSubscription = Keyboard.addListener(showEvent, (e) => {\r\n setKeyboardHeight(e.endCoordinates.height);\r\n if (scrollViewRef.current) {\r\n const screenHeight = windowHeight;\r\n const keyboardHeight = e.endCoordinates.height;\r\n const safeAreaBottom = 0;\r\n const availableScreenHeight = screenHeight - keyboardHeight - safeAreaBottom;\r\n const currentScrollPosition = positionRef.current || 0;\r\n const touchPosition = lastTouchY.current || 0;\r\n\r\n // touchPosition이 키보드 높이보다 아래인 경우\r\n // const isTouchPositionBelowKeyboard = touchPosition > availableScreenHeight;\r\n\r\n // 현재 터치 위치와 스크롤 위치를 기반으로 새로운 스크롤 위치 계산\r\n const scrollOffset = touchPosition - availableScreenHeight + keyboardScrollExtraOffset;\r\n\r\n setTimeout(() => {\r\n scrollViewRef.current?.scrollTo({\r\n y: currentScrollPosition + scrollOffset,\r\n animated: true,\r\n });\r\n }, 100);\r\n }\r\n });\r\n\r\n const keyboardHideSubscription = Keyboard.addListener(hideEvent, () => {\r\n setKeyboardHeight(0);\r\n });\r\n\r\n return () => {\r\n positionRef.current = null;\r\n lastTouchY.current = null;\r\n keyboardShowSubscription.remove();\r\n keyboardHideSubscription.remove();\r\n };\r\n }, [keyboardScrollExtraOffset]);\r\n\r\n const handleScroll = (event: NativeSyntheticEvent<NativeScrollEvent>) => {\r\n if (props.onScroll) props.onScroll(event);\r\n positionRef.current = event.nativeEvent.contentOffset.y;\r\n };\r\n\r\n const handleTouch = (evt: any) => {\r\n lastTouchY.current = evt.nativeEvent.pageY;\r\n };\r\n\r\n return (\r\n <SafeAreaView\r\n style={[{ backgroundColor: backgroundColor || palette.background.base }, styles.flex1]}\r\n edges={edges}\r\n >\r\n <View style={styles.flex1}>\r\n {topComponent && topComponent}\r\n {\r\n scrollViewDisabled ? (\r\n <View style={styles.flex1}>\r\n {props.children}\r\n </View>\r\n ) : (\r\n <ScrollView\r\n ref={scrollViewRef}\r\n style={styles.flex1}\r\n contentContainerStyle={[styles.scrollContainerStyle, { paddingBottom: Platform.OS === 'ios' ? keyboardHeight || 0 : 0 }]}\r\n bounces={false}\r\n overScrollMode=\"never\"\r\n showsVerticalScrollIndicator={showsVerticalScrollIndicator}\r\n keyboardShouldPersistTaps=\"handled\"\r\n automaticallyAdjustKeyboardInsets={false}\r\n onScroll={handleScroll}\r\n onTouchStart={handleTouch}\r\n scrollEventThrottle={scrollEventThrottle}\r\n >\r\n <View style={[styles.flex1, props.style]}>\r\n {props.children}\r\n </View>\r\n </ScrollView>\r\n )\r\n }\r\n {bottomComponent && bottomComponent}\r\n </View>\r\n\r\n {\r\n (barStyle || statusBarColor || translucent) && (\r\n <StatusBar\r\n barStyle={barStyle}\r\n backgroundColor={statusBarColor || palette.background.base}\r\n translucent={translucent}\r\n />\r\n )\r\n }\r\n </SafeAreaView>\r\n );\r\n});\r\n\r\nexport const styles = StyleSheet.create({\r\n flex1: { flex: 1, width: '100%' },\r\n scrollContainerStyle: { flexGrow: 1, alignItems: 'center', width: '100%' },\r\n});\r\n\r\nexport default ZSContainer;\r\n"]}
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../../../src/ui/ZSContainer/index.tsx"],"names":[],"mappings":"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","sourcesContent":["import React, { ReactNode, useEffect, useImperativeHandle, forwardRef, useRef, useState, useCallback, useMemo } from 'react';\r\nimport { ViewProps, StatusBar, StyleSheet, ScrollView, NativeSyntheticEvent, NativeScrollEvent, Keyboard, View, Platform } from 'react-native';\r\nimport { SafeAreaView } from 'react-native-safe-area-context';\r\nimport { useTheme } from '../../model/useThemeProvider';\r\n\r\nconst IS_IOS = Platform.OS === 'ios';\r\nconst KEYBOARD_ANIMATION_DELAY = 50;\r\nconst keyboardEvents = {\r\n showEvent: IS_IOS ? 'keyboardWillShow' as const : 'keyboardDidShow' as const,\r\n hideEvent: IS_IOS ? 'keyboardWillHide' as const : 'keyboardDidHide' as const,\r\n};\r\n\r\nexport type ZSContainerProps = ViewProps & {\r\n backgroundColor?: string;\r\n statusBarColor?: string;\r\n barStyle?: 'light-content' | 'dark-content';\r\n edges?: Array<'top' | 'right' | 'bottom' | 'left'>;\r\n scrollViewDisabled?: boolean;\r\n topComponent?: ReactNode;\r\n bottomComponent?: ReactNode;\r\n rightComponent?: ReactNode;\r\n showsVerticalScrollIndicator?: boolean;\r\n keyboardScrollExtraOffset?: number;\r\n translucent?: boolean;\r\n onScroll?: (event: NativeSyntheticEvent<NativeScrollEvent>) => void;\r\n scrollEventThrottle?: number;\r\n scrollToFocusedInput?: boolean;\r\n};\r\n\r\nexport type ZSContainerRef = ScrollView;\r\n\r\nconst ZSContainer = forwardRef<ZSContainerRef, ZSContainerProps>(function ZSContainer(\r\n {\r\n backgroundColor,\r\n statusBarColor,\r\n barStyle,\r\n edges = ['top', 'bottom'],\r\n scrollViewDisabled = false,\r\n topComponent,\r\n bottomComponent,\r\n rightComponent,\r\n showsVerticalScrollIndicator = true,\r\n keyboardScrollExtraOffset = 30,\r\n translucent,\r\n scrollEventThrottle = 16,\r\n scrollToFocusedInput = true,\r\n ...props\r\n },\r\n forwardedRef\r\n) {\r\n const { palette, dimensions: { height: windowHeight } } = useTheme();\r\n const positionRef = useRef<number | null>(0);\r\n const scrollViewRef = useRef<ScrollView>(null);\r\n const lastTouchY = useRef<number | null>(0);\r\n const [keyboardHeight, setKeyboardHeight] = useState<number | null>(0);\r\n\r\n useImperativeHandle(forwardedRef, () => scrollViewRef.current as ScrollView, []);\r\n\r\n const handleKeyboardShow = useCallback((e: any) => {\r\n setKeyboardHeight(e.endCoordinates.height);\r\n \r\n if (scrollViewRef.current && scrollToFocusedInput) {\r\n const keyboardHeight = e.endCoordinates.height;\r\n const safeAreaBottom = 0;\r\n const availableScreenHeight = windowHeight - keyboardHeight - safeAreaBottom;\r\n const currentScrollPosition = positionRef.current || 0;\r\n const touchPosition = lastTouchY.current || 0;\r\n\r\n // 현재 터치 위치와 스크롤 위치를 기반으로 새로운 스크롤 위치 계산\r\n const scrollOffset = touchPosition - availableScreenHeight + keyboardScrollExtraOffset;\r\n\r\n setTimeout(() => {\r\n scrollViewRef.current?.scrollTo({\r\n y: currentScrollPosition + scrollOffset,\r\n animated: true,\r\n });\r\n }, KEYBOARD_ANIMATION_DELAY);\r\n }\r\n }, [windowHeight, keyboardScrollExtraOffset, scrollToFocusedInput]);\r\n\r\n // 키보드 숨김 핸들러를 메모이제이션하여 성능 최적화\r\n const handleKeyboardHide = useCallback(() => {\r\n setKeyboardHeight(0);\r\n }, []);\r\n\r\n useEffect(() => {\r\n const keyboardShowSubscription = Keyboard.addListener(keyboardEvents.showEvent, handleKeyboardShow);\r\n const keyboardHideSubscription = Keyboard.addListener(keyboardEvents.hideEvent, handleKeyboardHide);\r\n\r\n return () => {\r\n positionRef.current = null;\r\n lastTouchY.current = null;\r\n keyboardShowSubscription.remove();\r\n keyboardHideSubscription.remove();\r\n };\r\n }, [keyboardEvents.showEvent, keyboardEvents.hideEvent, handleKeyboardShow, handleKeyboardHide]);\r\n\r\n const handleScroll = useCallback((event: NativeSyntheticEvent<NativeScrollEvent>) => {\r\n if (props.onScroll) props.onScroll(event);\r\n positionRef.current = event.nativeEvent.contentOffset.y;\r\n }, [props.onScroll]);\r\n\r\n const handleTouch = useCallback((evt: any) => {\r\n lastTouchY.current = evt.nativeEvent.pageY;\r\n }, []);\r\n\r\n const safeAreaStyle = useMemo(() => [\r\n { backgroundColor: backgroundColor || palette.background.base }, \r\n styles.flex1\r\n ], [backgroundColor, palette.background.base]);\r\n\r\n const scrollContentStyle = useMemo(() => [\r\n styles.scrollContainerStyle, \r\n { \r\n paddingBottom: keyboardHeight ? (IS_IOS ? keyboardHeight : keyboardScrollExtraOffset) : 0 \r\n }\r\n ], [keyboardHeight, keyboardScrollExtraOffset]);\r\n\r\n const containerStyle = useMemo(() => [\r\n styles.flex1, \r\n props.style\r\n ], [props.style]);\r\n\r\n const shouldShowStatusBar = useMemo(() => \r\n Boolean(barStyle || statusBarColor || translucent), \r\n [barStyle, statusBarColor, translucent]\r\n );\r\n\r\n return (\r\n <SafeAreaView\r\n style={safeAreaStyle}\r\n edges={edges}\r\n >\r\n <View style={styles.flex1}>\r\n {topComponent}\r\n {\r\n scrollViewDisabled ? (\r\n <View style={styles.flex1}>\r\n {props.children}\r\n </View>\r\n ) : (\r\n <ScrollView\r\n ref={scrollViewRef}\r\n style={styles.flex1}\r\n contentContainerStyle={scrollContentStyle}\r\n bounces={false}\r\n overScrollMode=\"never\"\r\n showsVerticalScrollIndicator={showsVerticalScrollIndicator}\r\n keyboardShouldPersistTaps=\"handled\"\r\n automaticallyAdjustKeyboardInsets={false}\r\n onScroll={handleScroll}\r\n onTouchStart={handleTouch}\r\n scrollEventThrottle={scrollEventThrottle}\r\n >\r\n <View style={containerStyle}>\r\n {props.children}\r\n </View>\r\n </ScrollView>\r\n )\r\n }\r\n {bottomComponent}\r\n </View>\r\n\r\n {shouldShowStatusBar && (\r\n <StatusBar\r\n barStyle={barStyle}\r\n backgroundColor={statusBarColor || palette.background.base}\r\n translucent={translucent}\r\n />\r\n )}\r\n </SafeAreaView>\r\n );\r\n});\r\n\r\nexport const styles = StyleSheet.create({\r\n flex1: { flex: 1, width: '100%' },\r\n scrollContainerStyle: { flexGrow: 1, alignItems: 'center', width: '100%' },\r\n});\r\n\r\nconst arePropsEqual = (\r\n prevProps: ZSContainerProps, \r\n nextProps: ZSContainerProps\r\n): boolean => {\r\n return (\r\n prevProps.backgroundColor === nextProps.backgroundColor &&\r\n prevProps.statusBarColor === nextProps.statusBarColor &&\r\n prevProps.barStyle === nextProps.barStyle &&\r\n prevProps.scrollViewDisabled === nextProps.scrollViewDisabled &&\r\n prevProps.showsVerticalScrollIndicator === nextProps.showsVerticalScrollIndicator &&\r\n prevProps.keyboardScrollExtraOffset === nextProps.keyboardScrollExtraOffset &&\r\n prevProps.translucent === nextProps.translucent &&\r\n prevProps.scrollEventThrottle === nextProps.scrollEventThrottle &&\r\n prevProps.scrollToFocusedInput === nextProps.scrollToFocusedInput &&\r\n prevProps.onScroll === nextProps.onScroll &&\r\n prevProps.style === nextProps.style &&\r\n prevProps.children === nextProps.children &&\r\n prevProps.topComponent === nextProps.topComponent &&\r\n prevProps.bottomComponent === nextProps.bottomComponent &&\r\n prevProps.rightComponent === nextProps.rightComponent &&\r\n // edges 배열 비교\r\n JSON.stringify(prevProps.edges) === JSON.stringify(nextProps.edges)\r\n );\r\n};\r\n\r\nexport default React.memo(ZSContainer, arePropsEqual);\r\n"]}
@@ -13,5 +13,6 @@ interface ZSPressableProps extends ViewProps {
13
13
  color?: ViewColorOptions;
14
14
  }
15
15
  declare function ZSPressable({ onPress, onLongPress, isAnimation, pressedBackgroundColor, pressedBackgroundBorderRadius, elevationLevel, fullWidth, color, ...props }: ZSPressableProps): React.JSX.Element;
16
- export default ZSPressable;
16
+ declare const _default: React.MemoExoticComponent<typeof ZSPressable>;
17
+ export default _default;
17
18
  //# sourceMappingURL=index.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/ui/ZSPressable/index.tsx"],"names":[],"mappings":"AAAA,OAAO,KAAsB,MAAM,OAAO,CAAC;AAC3C,OAAO,EAAmB,SAAS,EAAE,MAAM,cAAc,CAAC;AAG1D,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,UAAU,CAAC;AAC5C,OAAO,EAAE,gBAAgB,EAAE,MAAM,mBAAmB,CAAC;AAIrD,UAAU,gBAAiB,SAAQ,SAAS;IAC1C,OAAO,CAAC,EAAE,CAAC,KAAK,CAAC,EAAE,GAAG,KAAK,IAAI,CAAC;IAChC,WAAW,CAAC,EAAE,CAAC,KAAK,CAAC,EAAE,GAAG,KAAK,IAAI,CAAC;IACpC,sBAAsB,CAAC,EAAE,MAAM,CAAC;IAChC,6BAA6B,CAAC,EAAE,MAAM,CAAC;IACvC,WAAW,CAAC,EAAE,OAAO,CAAC;IACtB,cAAc,CAAC,EAAE,WAAW,CAAC;IAC7B,SAAS,CAAC,EAAE,OAAO,CAAC;IACpB,KAAK,CAAC,EAAE,gBAAgB,CAAC;CAC1B;AAED,iBAAS,WAAW,CAAC,EACnB,OAAO,EACP,WAAW,EACX,WAAkB,EAClB,sBAAmD,EACnD,6BAAkC,EAClC,cAAc,EACd,SAAiB,EACjB,KAAK,EACL,GAAG,KAAK,EACT,EAAE,gBAAgB,qBAgDlB;AAED,eAAe,WAAW,CAAC"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/ui/ZSPressable/index.tsx"],"names":[],"mappings":"AAAA,OAAO,KAAuC,MAAM,OAAO,CAAC;AAC5D,OAAO,EAAmB,SAAS,EAAE,MAAM,cAAc,CAAC;AAG1D,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,UAAU,CAAC;AAC5C,OAAO,EAAE,gBAAgB,EAAE,MAAM,mBAAmB,CAAC;AAKrD,UAAU,gBAAiB,SAAQ,SAAS;IAC1C,OAAO,CAAC,EAAE,CAAC,KAAK,CAAC,EAAE,GAAG,KAAK,IAAI,CAAC;IAChC,WAAW,CAAC,EAAE,CAAC,KAAK,CAAC,EAAE,GAAG,KAAK,IAAI,CAAC;IACpC,sBAAsB,CAAC,EAAE,MAAM,CAAC;IAChC,6BAA6B,CAAC,EAAE,MAAM,CAAC;IACvC,WAAW,CAAC,EAAE,OAAO,CAAC;IACtB,cAAc,CAAC,EAAE,WAAW,CAAC;IAC7B,SAAS,CAAC,EAAE,OAAO,CAAC;IACpB,KAAK,CAAC,EAAE,gBAAgB,CAAC;CAC1B;AAED,iBAAS,WAAW,CAAC,EACnB,OAAO,EACP,WAAW,EACX,WAAkB,EAClB,sBAAmD,EACnD,6BAAkC,EAClC,cAAc,EACd,SAAiB,EACjB,KAAK,EACL,GAAG,KAAK,EACT,EAAE,gBAAgB,qBAkElB;;AAoBD,wBAAsD"}
@@ -1,27 +1,39 @@
1
- import React, { useCallback } from "react";
1
+ import React, { useCallback, useMemo, useRef } from "react";
2
2
  import { Pressable, View } from "react-native";
3
- import Animated, { interpolate, useAnimatedStyle, useSharedValue, withTiming, runOnJS } from "react-native-reanimated";
3
+ import Animated, { interpolate, useAnimatedStyle, useSharedValue, withTiming } from "react-native-reanimated";
4
4
  import AnimatedWrapper from "../atoms/AnimatedWrapper";
5
5
  const DEFAULT_DURATION = { duration: 100 };
6
+ const SCALE_VALUES = [1, 0.96];
6
7
  function ZSPressable({ onPress, onLongPress, isAnimation = true, pressedBackgroundColor = 'rgba(180, 180, 180, 0.1)', pressedBackgroundBorderRadius = 16, elevationLevel, fullWidth = false, color, ...props }) {
7
- const isButtonPress = useSharedValue(0);
8
+ const isButtonPress = useRef(useSharedValue(0)).current;
8
9
  const boxAnimation = useAnimatedStyle(() => {
9
- const scale = interpolate(isButtonPress.value, [0, 1], [1, 0.96], 'clamp');
10
+ const scale = interpolate(isButtonPress.value, [0, 1], SCALE_VALUES, 'clamp');
10
11
  return {
11
- transform: [{ scale: withTiming(scale, DEFAULT_DURATION) }],
12
+ transform: [{ scale }],
12
13
  };
13
14
  }, []);
15
+ const handlePressIn = useCallback(() => {
16
+ isButtonPress.value = withTiming(1, DEFAULT_DURATION);
17
+ }, [isButtonPress]);
18
+ const handlePressOut = useCallback(() => {
19
+ isButtonPress.value = withTiming(0, DEFAULT_DURATION);
20
+ }, [isButtonPress]);
21
+ const pressedStyle = useMemo(() => ({
22
+ backgroundColor: pressedBackgroundColor,
23
+ borderRadius: pressedBackgroundBorderRadius,
24
+ }), [pressedBackgroundColor, pressedBackgroundBorderRadius]);
25
+ const unpressedStyle = useMemo(() => ({
26
+ backgroundColor: 'transparent',
27
+ borderRadius: pressedBackgroundBorderRadius,
28
+ }), [pressedBackgroundBorderRadius]);
14
29
  const handlePressStyle = useCallback((pressed) => {
15
- runOnJS(() => {
16
- isButtonPress.value = pressed ? 1 : 0;
17
- })();
18
- return {
19
- backgroundColor: pressed ? pressedBackgroundColor : 'transparent',
20
- borderRadius: pressedBackgroundBorderRadius,
21
- };
22
- }, [pressedBackgroundColor, pressedBackgroundBorderRadius, fullWidth]);
23
- return (<View style={{ width: fullWidth ? '100%' : undefined }}>
24
- <Pressable onPress={onPress} onLongPress={onLongPress} style={({ pressed }) => handlePressStyle(pressed)}>
30
+ return pressed ? pressedStyle : unpressedStyle;
31
+ }, [pressedStyle, unpressedStyle]);
32
+ const containerStyle = useMemo(() => ({
33
+ width: fullWidth ? '100%' : undefined
34
+ }), [fullWidth]);
35
+ return (<View style={containerStyle}>
36
+ <Pressable onPress={onPress} onLongPress={onLongPress} onPressIn={handlePressIn} onPressOut={handlePressOut} style={({ pressed }) => handlePressStyle(pressed)}>
25
37
  <Animated.View style={boxAnimation}>
26
38
  <AnimatedWrapper color={color} isAnimation={isAnimation} elevationLevel={elevationLevel} style={props.style}>
27
39
  {props.children}
@@ -30,5 +42,17 @@ function ZSPressable({ onPress, onLongPress, isAnimation = true, pressedBackgrou
30
42
  </Pressable>
31
43
  </View>);
32
44
  }
33
- export default ZSPressable;
45
+ const arePropsEqual = (prevProps, nextProps) => {
46
+ return (prevProps.onPress === nextProps.onPress &&
47
+ prevProps.onLongPress === nextProps.onLongPress &&
48
+ prevProps.isAnimation === nextProps.isAnimation &&
49
+ prevProps.pressedBackgroundColor === nextProps.pressedBackgroundColor &&
50
+ prevProps.pressedBackgroundBorderRadius === nextProps.pressedBackgroundBorderRadius &&
51
+ prevProps.elevationLevel === nextProps.elevationLevel &&
52
+ prevProps.fullWidth === nextProps.fullWidth &&
53
+ prevProps.color === nextProps.color &&
54
+ prevProps.style === nextProps.style &&
55
+ prevProps.children === nextProps.children);
56
+ };
57
+ export default React.memo(ZSPressable, arePropsEqual);
34
58
  //# sourceMappingURL=index.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"index.js","sourceRoot":"","sources":["../../../src/ui/ZSPressable/index.tsx"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,EAAE,WAAW,EAAE,MAAM,OAAO,CAAC;AAC3C,OAAO,EAAE,SAAS,EAAE,IAAI,EAAa,MAAM,cAAc,CAAC;AAC1D,OAAO,QAAQ,EAAE,EAAE,WAAW,EAAE,gBAAgB,EAAE,cAAc,EAAE,UAAU,EAAE,OAAO,EAAE,MAAM,yBAAyB,CAAC;AACvH,OAAO,eAAe,MAAM,0BAA0B,CAAC;AAIvD,MAAM,gBAAgB,GAAG,EAAE,QAAQ,EAAE,GAAG,EAAE,CAAC;AAa3C,SAAS,WAAW,CAAC,EACnB,OAAO,EACP,WAAW,EACX,WAAW,GAAG,IAAI,EAClB,sBAAsB,GAAG,0BAA0B,EACnD,6BAA6B,GAAG,EAAE,EAClC,cAAc,EACd,SAAS,GAAG,KAAK,EACjB,KAAK,EACL,GAAG,KAAK,EACS;IACjB,MAAM,aAAa,GAAG,cAAc,CAAC,CAAC,CAAC,CAAC;IAExC,MAAM,YAAY,GAAG,gBAAgB,CAAC,GAAG,EAAE;QACzC,MAAM,KAAK,GAAG,WAAW,CACvB,aAAa,CAAC,KAAK,EACnB,CAAC,CAAC,EAAE,CAAC,CAAC,EACN,CAAC,CAAC,EAAE,IAAI,CAAC,EACT,OAAO,CACR,CAAC;QACF,OAAO;YACL,SAAS,EAAE,CAAC,EAAE,KAAK,EAAE,UAAU,CAAC,KAAK,EAAE,gBAAgB,CAAC,EAAE,CAAC;SAC5D,CAAC;IACJ,CAAC,EAAE,EAAE,CAAC,CAAC;IAEP,MAAM,gBAAgB,GAAG,WAAW,CAClC,CAAC,OAAgB,EAAE,EAAE;QACnB,OAAO,CAAC,GAAG,EAAE;YACX,aAAa,CAAC,KAAK,GAAG,OAAO,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC;QACxC,CAAC,CAAC,EAAE,CAAC;QACL,OAAO;YACL,eAAe,EAAE,OAAO,CAAC,CAAC,CAAC,sBAAsB,CAAC,CAAC,CAAC,aAAa;YACjE,YAAY,EAAE,6BAA6B;SAC5C,CAAC;IACJ,CAAC,EACD,CAAC,sBAAsB,EAAE,6BAA6B,EAAE,SAAS,CAAC,CACnE,CAAC;IAEF,OAAO,CACL,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC,EAAE,KAAK,EAAE,SAAS,CAAC,CAAC,CAAC,MAAe,CAAC,CAAC,CAAC,SAAS,EAAE,CAAC,CAC9D;MAAA,CAAC,SAAS,CACR,OAAO,CAAC,CAAC,OAAO,CAAC,CACjB,WAAW,CAAC,CAAC,WAAW,CAAC,CACzB,KAAK,CAAC,CAAC,CAAC,EAAE,OAAO,EAAE,EAAE,EAAE,CAAC,gBAAgB,CAAC,OAAO,CAAC,CAAC,CAElD;QAAA,CAAC,QAAQ,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC,YAAY,CAAC,CACjC;UAAA,CAAC,eAAe,CACd,KAAK,CAAC,CAAC,KAAK,CAAC,CACb,WAAW,CAAC,CAAC,WAAW,CAAC,CACzB,cAAc,CAAC,CAAC,cAAc,CAAC,CAC/B,KAAK,CAAC,CAAC,KAAK,CAAC,KAAK,CAAC,CAEnB;YAAA,CAAC,KAAK,CAAC,QAAQ,CACjB;UAAA,EAAE,eAAe,CACnB;QAAA,EAAE,QAAQ,CAAC,IAAI,CACjB;MAAA,EAAE,SAAS,CACb;IAAA,EAAE,IAAI,CAAC,CACR,CAAC;AACJ,CAAC;AAED,eAAe,WAAW,CAAC","sourcesContent":["import React, { useCallback } from \"react\";\nimport { Pressable, View, ViewProps } from \"react-native\";\nimport Animated, { interpolate, useAnimatedStyle, useSharedValue, withTiming, runOnJS } from \"react-native-reanimated\";\nimport AnimatedWrapper from \"../atoms/AnimatedWrapper\";\nimport type { ShadowLevel } from \"../types\";\nimport { ViewColorOptions } from \"../../theme/types\";\n\nconst DEFAULT_DURATION = { duration: 100 };\n\ninterface ZSPressableProps extends ViewProps {\n onPress?: (value?: any) => void;\n onLongPress?: (value?: any) => void;\n pressedBackgroundColor?: string;\n pressedBackgroundBorderRadius?: number;\n isAnimation?: boolean;\n elevationLevel?: ShadowLevel;\n fullWidth?: boolean;\n color?: ViewColorOptions;\n}\n\nfunction ZSPressable({\n onPress,\n onLongPress,\n isAnimation = true,\n pressedBackgroundColor = 'rgba(180, 180, 180, 0.1)',\n pressedBackgroundBorderRadius = 16,\n elevationLevel,\n fullWidth = false,\n color,\n ...props\n}: ZSPressableProps) {\n const isButtonPress = useSharedValue(0);\n\n const boxAnimation = useAnimatedStyle(() => {\n const scale = interpolate(\n isButtonPress.value,\n [0, 1],\n [1, 0.96],\n 'clamp'\n );\n return {\n transform: [{ scale: withTiming(scale, DEFAULT_DURATION) }],\n };\n }, []);\n\n const handlePressStyle = useCallback(\n (pressed: boolean) => {\n runOnJS(() => {\n isButtonPress.value = pressed ? 1 : 0;\n })();\n return {\n backgroundColor: pressed ? pressedBackgroundColor : 'transparent',\n borderRadius: pressedBackgroundBorderRadius,\n };\n },\n [pressedBackgroundColor, pressedBackgroundBorderRadius, fullWidth]\n );\n\n return (\n <View style={{ width: fullWidth ? '100%' as const : undefined }}>\n <Pressable\n onPress={onPress}\n onLongPress={onLongPress}\n style={({ pressed }) => handlePressStyle(pressed)}\n >\n <Animated.View style={boxAnimation}>\n <AnimatedWrapper\n color={color}\n isAnimation={isAnimation}\n elevationLevel={elevationLevel}\n style={props.style}\n >\n {props.children}\n </AnimatedWrapper>\n </Animated.View>\n </Pressable>\n </View>\n );\n}\n\nexport default ZSPressable;\n"]}
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../../../src/ui/ZSPressable/index.tsx"],"names":[],"mappings":"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","sourcesContent":["import React, { useCallback, useMemo, useRef } from \"react\";\nimport { Pressable, View, ViewProps } from \"react-native\";\nimport Animated, { interpolate, useAnimatedStyle, useSharedValue, withTiming } from \"react-native-reanimated\";\nimport AnimatedWrapper from \"../atoms/AnimatedWrapper\";\nimport type { ShadowLevel } from \"../types\";\nimport { ViewColorOptions } from \"../../theme/types\";\n\nconst DEFAULT_DURATION = { duration: 100 } as const;\nconst SCALE_VALUES = [1, 0.96] as const;\n\ninterface ZSPressableProps extends ViewProps {\n onPress?: (value?: any) => void;\n onLongPress?: (value?: any) => void;\n pressedBackgroundColor?: string;\n pressedBackgroundBorderRadius?: number;\n isAnimation?: boolean;\n elevationLevel?: ShadowLevel;\n fullWidth?: boolean;\n color?: ViewColorOptions;\n}\n\nfunction ZSPressable({\n onPress,\n onLongPress,\n isAnimation = true,\n pressedBackgroundColor = 'rgba(180, 180, 180, 0.1)',\n pressedBackgroundBorderRadius = 16,\n elevationLevel,\n fullWidth = false,\n color,\n ...props\n}: ZSPressableProps) {\n const isButtonPress = useRef(useSharedValue(0)).current;\n\n const boxAnimation = useAnimatedStyle(() => {\n const scale = interpolate(\n isButtonPress.value,\n [0, 1],\n SCALE_VALUES,\n 'clamp'\n );\n return {\n transform: [{ scale }],\n };\n }, []);\n \n const handlePressIn = useCallback(() => {\n isButtonPress.value = withTiming(1, DEFAULT_DURATION);\n }, [isButtonPress]);\n \n const handlePressOut = useCallback(() => {\n isButtonPress.value = withTiming(0, DEFAULT_DURATION);\n }, [isButtonPress]);\n\n const pressedStyle = useMemo(() => ({\n backgroundColor: pressedBackgroundColor,\n borderRadius: pressedBackgroundBorderRadius,\n }), [pressedBackgroundColor, pressedBackgroundBorderRadius]);\n \n const unpressedStyle = useMemo(() => ({\n backgroundColor: 'transparent',\n borderRadius: pressedBackgroundBorderRadius,\n }), [pressedBackgroundBorderRadius]);\n \n const handlePressStyle = useCallback(\n (pressed: boolean) => {\n return pressed ? pressedStyle : unpressedStyle;\n },\n [pressedStyle, unpressedStyle]\n );\n\n const containerStyle = useMemo(() => ({\n width: fullWidth ? '100%' as const : undefined\n }), [fullWidth]);\n\n return (\n <View style={containerStyle}>\n <Pressable\n onPress={onPress}\n onLongPress={onLongPress}\n onPressIn={handlePressIn}\n onPressOut={handlePressOut}\n style={({ pressed }) => handlePressStyle(pressed)}\n >\n <Animated.View style={boxAnimation}>\n <AnimatedWrapper\n color={color}\n isAnimation={isAnimation}\n elevationLevel={elevationLevel}\n style={props.style}\n >\n {props.children}\n </AnimatedWrapper>\n </Animated.View>\n </Pressable>\n </View>\n );\n}\n\nconst arePropsEqual = (\n prevProps: ZSPressableProps, \n nextProps: ZSPressableProps\n): boolean => {\n return (\n prevProps.onPress === nextProps.onPress &&\n prevProps.onLongPress === nextProps.onLongPress &&\n prevProps.isAnimation === nextProps.isAnimation &&\n prevProps.pressedBackgroundColor === nextProps.pressedBackgroundColor &&\n prevProps.pressedBackgroundBorderRadius === nextProps.pressedBackgroundBorderRadius &&\n prevProps.elevationLevel === nextProps.elevationLevel &&\n prevProps.fullWidth === nextProps.fullWidth &&\n prevProps.color === nextProps.color &&\n prevProps.style === nextProps.style &&\n prevProps.children === nextProps.children\n );\n};\n\nexport default React.memo(ZSPressable, arePropsEqual);\n"]}
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/ui/ZSTextField/index.tsx"],"names":[],"mappings":"AAAA,OAAO,KAAoD,MAAM,OAAO,CAAC;AACzE,OAAO,EAAqD,cAAc,EAAwB,MAAM,cAAc,CAAC;AAIvH,OAAO,EAAE,WAAW,EAA2B,MAAM,aAAa,CAAC;AAKnE,MAAM,MAAM,QAAQ,GAAG,SAAS,GAAG,WAAW,GAAG,OAAO,CAAC;AAIzD,UAAU,cAAc;IACtB,IAAI,CAAC,EAAE,WAAW,CAAC;IACnB,MAAM,CAAC,EAAE,SAAS,GAAG,OAAO,CAAC;IAC7B,KAAK,EAAE,MAAM,CAAC;IACd,YAAY,CAAC,EAAE,CAAC,IAAI,EAAE,MAAM,KAAK,IAAI,CAAC;IACtC,YAAY,CAAC,EAAE,MAAM,CAAC;IACtB,YAAY,CAAC,EAAE,MAAM,CAAC;IACtB,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,gBAAgB,CAAC,EAAE,MAAM,CAAC;IAC1B,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,YAAY,CAAC,EAAE,MAAM,CAAC;IACtB,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,iBAAiB,CAAC,EAAE,MAAM,CAAC;IAC3B,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,YAAY,CAAC,EAAE,MAAM,CAAC;IACtB,cAAc,CAAC,EAAE,cAAc,CAAC;IAChC,QAAQ,CAAC,EAAE,QAAQ,CAAC;IACpB,aAAa,CAAC,EAAE,KAAK,GAAG,QAAQ,GAAG,QAAQ,CAAC;IAC5C,QAAQ,CAAC,EAAE,OAAO,CAAC;IACnB,gBAAgB,CAAC,EAAE,OAAO,CAAC;IAC3B,UAAU,CAAC,EAAE,OAAO,CAAC;CACtB;AAED,iBAAS,WAAW,CAAC,EACnB,IAAe,EACf,MAAkB,EAClB,KAAK,EACL,YAAY,EACZ,KAAqB,EACrB,UAAU,EACV,gBAAgB,EAChB,YAAY,EACZ,YAAY,EACZ,WAAiB,EACjB,WAAW,EACX,UAAU,EACV,UAAU,EACV,YAAiB,EACjB,iBAAsB,EACtB,YAAY,EACZ,cAAc,EACd,QAAoB,EACpB,aAAa,EACb,QAAgB,EAChB,gBAAuB,EACvB,UAAkB,GACnB,EAAE,cAAc,GAAG,GAAG,CAAC,OAAO,CA6I9B;;AAED,wBAAuC"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/ui/ZSTextField/index.tsx"],"names":[],"mappings":"AAAA,OAAO,KAA4D,MAAM,OAAO,CAAC;AACjF,OAAO,EAAqD,cAAc,EAAwB,MAAM,cAAc,CAAC;AAIvH,OAAO,EAAE,WAAW,EAA2B,MAAM,aAAa,CAAC;AAKnE,MAAM,MAAM,QAAQ,GAAG,SAAS,GAAG,WAAW,GAAG,OAAO,CAAC;AAIzD,UAAU,cAAc;IACtB,IAAI,CAAC,EAAE,WAAW,CAAC;IACnB,MAAM,CAAC,EAAE,SAAS,GAAG,OAAO,CAAC;IAC7B,KAAK,EAAE,MAAM,CAAC;IACd,YAAY,CAAC,EAAE,CAAC,IAAI,EAAE,MAAM,KAAK,IAAI,CAAC;IACtC,YAAY,CAAC,EAAE,MAAM,CAAC;IACtB,YAAY,CAAC,EAAE,MAAM,CAAC;IACtB,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,gBAAgB,CAAC,EAAE,MAAM,CAAC;IAC1B,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,YAAY,CAAC,EAAE,MAAM,CAAC;IACtB,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,iBAAiB,CAAC,EAAE,MAAM,CAAC;IAC3B,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,YAAY,CAAC,EAAE,MAAM,CAAC;IACtB,cAAc,CAAC,EAAE,cAAc,CAAC;IAChC,QAAQ,CAAC,EAAE,QAAQ,CAAC;IACpB,aAAa,CAAC,EAAE,KAAK,GAAG,QAAQ,GAAG,QAAQ,CAAC;IAC5C,QAAQ,CAAC,EAAE,OAAO,CAAC;IACnB,gBAAgB,CAAC,EAAE,OAAO,CAAC;IAC3B,UAAU,CAAC,EAAE,OAAO,CAAC;CACtB;AAED,iBAAS,WAAW,CAAC,EACnB,IAAe,EACf,MAAkB,EAClB,KAAK,EACL,YAAY,EACZ,KAAqB,EACrB,UAAU,EACV,gBAAgB,EAChB,YAAY,EACZ,YAAY,EACZ,WAAiB,EACjB,WAAW,EACX,UAAU,EACV,UAAU,EACV,YAAiB,EACjB,iBAAsB,EACtB,YAAY,EACZ,cAAc,EACd,QAAoB,EACpB,aAAa,EACb,QAAgB,EAChB,gBAAuB,EACvB,UAAkB,GACnB,EAAE,cAAc,GAAG,GAAG,CAAC,OAAO,CAoN9B;;AAoBD,wBAAsD"}
@@ -1,4 +1,4 @@
1
- import React, { useMemo, useCallback, useState, useEffect } from 'react';
1
+ import React, { useMemo, useCallback, useState, useEffect, useRef } from 'react';
2
2
  import { Platform, TextInput } from 'react-native';
3
3
  import Animated, { interpolate, useAnimatedStyle, useSharedValue, withTiming } from 'react-native-reanimated';
4
4
  import ButtonClose from './ui/ButtonClose';
@@ -9,31 +9,43 @@ import ViewAtom from '../atoms/ViewAtom';
9
9
  const iosOffset = Platform.OS === 'ios' ? 8 : 4;
10
10
  function ZSTextField({ typo = 'body.2', status = 'default', value, onChangeText, label = 'Placeholder', labelColor, placeHolderColor, inputBgColor, labelBgColor, borderWidth = 1.2, borderColor, focusColor, errorColor, borderRadius = 14, paddingHorizontal = 15, errorMessage, textInputProps, boxStyle = 'outline', innerBoxStyle, disabled = false, allowFontScaling = true, isTextArea = false, }) {
11
11
  const { typography, palette } = useTheme();
12
- const [primaryStyle, subStyle] = typo.split('.');
13
- let fErrorColor = errorColor || palette.danger.main;
14
- // 폰트 크기 패밀리 추출
15
- const fontSize = useMemo(() => extractStyle(typography[primaryStyle][subStyle], 'fontSize') || 17, [typography, primaryStyle, subStyle]);
16
- const fontFamily = useMemo(() => extractStyle(typography[primaryStyle][subStyle], 'fontFamily') || '', [typography, primaryStyle, subStyle]);
17
- // 컴포넌트 상태 관리
12
+ const typoConfig = useMemo(() => {
13
+ const [primaryStyle, subStyle] = typo.split('.');
14
+ return { primaryStyle, subStyle };
15
+ }, [typo]);
16
+ const fErrorColor = useMemo(() => errorColor || palette.danger.main, [errorColor, palette.danger.main]);
17
+ const fontSize = useMemo(() => {
18
+ return extractStyle(typography[typoConfig.primaryStyle][typoConfig.subStyle], 'fontSize') || 17;
19
+ }, [typography, typoConfig.primaryStyle, typoConfig.subStyle]);
20
+ const fontFamily = useMemo(() => {
21
+ return extractStyle(typography[typoConfig.primaryStyle][typoConfig.subStyle], 'fontFamily') || '';
22
+ }, [typography, typoConfig.primaryStyle, typoConfig.subStyle]);
18
23
  const [isFocused, setIsFocused] = useState(false);
19
- const labelAnimationValue = useSharedValue(0);
20
- const boxHeightValue = useSharedValue(0);
24
+ const labelAnimationValue = useRef(useSharedValue(0)).current;
25
+ const boxHeightValue = useRef(useSharedValue(0)).current;
21
26
  // 포커스 및 값 변경 시 라벨 애니메이션 트리거
22
27
  useEffect(() => {
23
- labelAnimationValue.value = withTiming(value !== '' || isFocused ? 1 : 0, { duration: 150 });
24
- }, [value, isFocused]);
28
+ labelAnimationValue.value = withTiming(value !== '' || isFocused ? 1 : 0, { duration: 100 });
29
+ }, [value, isFocused, labelAnimationValue]);
30
+ // 애니메이션 관련 상수
31
+ const animationConstants = useMemo(() => ({
32
+ baseFontSize: fontSize + (boxStyle === 'inbox' ? 1 : 0),
33
+ targetFontSize: boxStyle === 'inbox' ? 10 : 11,
34
+ baseTop: isTextArea ? 12 : 0,
35
+ targetTopOffset: boxStyle === 'inbox' ? 17 : 2,
36
+ }), [fontSize, boxStyle, isTextArea]);
25
37
  // 라벨 애니메이션 스타일
26
38
  const animatedLabelStyle = useAnimatedStyle(() => {
27
- const labelFontSize = interpolate(labelAnimationValue.value, [0, 1], [fontSize + (boxStyle === 'inbox' ? 1 : 0), boxStyle === 'inbox' ? 10 : 11], 'clamp');
39
+ const labelFontSize = interpolate(labelAnimationValue.value, [0, 1], [animationConstants.baseFontSize, animationConstants.targetFontSize], 'clamp');
28
40
  const labelTop = interpolate(labelAnimationValue.value, [0, 1], [
29
- isTextArea ? 12 : 0,
30
- isTextArea ? -12 : -(boxHeightValue.value / 2) - 1 + (boxStyle === 'inbox' ? 17 : 2),
41
+ animationConstants.baseTop,
42
+ isTextArea ? -12 : -(boxHeightValue.value / 2) - 1 + animationConstants.targetTopOffset,
31
43
  ], 'clamp');
32
44
  return {
33
45
  top: labelTop,
34
46
  fontSize: labelFontSize,
35
47
  };
36
- });
48
+ }, [animationConstants.baseFontSize, animationConstants.targetFontSize, animationConstants.baseTop, animationConstants.targetTopOffset, isTextArea]);
37
49
  // 레이아웃 핸들러
38
50
  const handleLayout = useCallback((event) => {
39
51
  const { height } = event.nativeEvent.layout;
@@ -43,25 +55,74 @@ function ZSTextField({ typo = 'body.2', status = 'default', value, onChangeText,
43
55
  // 포커스 및 블러 핸들러
44
56
  const handleFocus = useCallback(() => setIsFocused(true), []);
45
57
  const handleBlur = useCallback(() => setIsFocused(false), []);
58
+ const colorConfig = useMemo(() => ({
59
+ primaryColor: focusColor || palette.primary.main,
60
+ defaultBorderColor: borderColor || palette.grey[30],
61
+ defaultLabelColor: labelColor || palette.text.secondary,
62
+ placeholderColor: placeHolderColor || palette.grey[40],
63
+ }), [focusColor, palette.primary.main, borderColor, palette.grey, labelColor, palette.text.secondary, placeHolderColor]);
46
64
  // 상태에 따른 테두리 색상 설정
47
- const computedBorderColor = useMemo(() => (status === 'error' ? fErrorColor : isFocused ? (focusColor || palette.primary.main) : (borderColor || palette.grey[30])), [status, fErrorColor, isFocused, focusColor, borderColor, palette]);
48
- // 상태에 따른 라벨 색상 설정
49
- const computedLabelColor = useMemo(() => (status === 'error' ? fErrorColor : isFocused ? (focusColor || palette.primary.main) : value ? (labelColor || palette.text.secondary) : (placeHolderColor || palette.grey[40])), [status, fErrorColor, isFocused, focusColor, value, placeHolderColor, labelColor, palette]);
65
+ const computedBorderColor = useMemo(() => {
66
+ if (status === 'error')
67
+ return fErrorColor;
68
+ if (isFocused)
69
+ return colorConfig.primaryColor;
70
+ return colorConfig.defaultBorderColor;
71
+ }, [status, fErrorColor, isFocused, colorConfig.primaryColor, colorConfig.defaultBorderColor]);
72
+ // 상태에 따른 라벨 색상 설정
73
+ const computedLabelColor = useMemo(() => {
74
+ if (status === 'error')
75
+ return fErrorColor;
76
+ if (isFocused)
77
+ return colorConfig.primaryColor;
78
+ if (value)
79
+ return colorConfig.defaultLabelColor;
80
+ return colorConfig.placeholderColor;
81
+ }, [status, fErrorColor, isFocused, value, colorConfig.primaryColor, colorConfig.defaultLabelColor, colorConfig.placeholderColor]);
82
+ const styleConfig = useMemo(() => {
83
+ const baseStyle = {
84
+ width: '100%',
85
+ justifyContent: isTextArea ? 'flex-start' : 'center',
86
+ borderRadius,
87
+ paddingHorizontal,
88
+ backgroundColor: inputBgColor || palette.background.base,
89
+ paddingTop: boxStyle === 'inbox' ? 13 : 0,
90
+ };
91
+ // 박스 스타일에 따른 테두리 설정
92
+ let borderStyle = {};
93
+ if (boxStyle === 'outline' || boxStyle === 'inbox') {
94
+ borderStyle = { borderWidth };
95
+ }
96
+ else if (boxStyle === 'underline') {
97
+ borderStyle = { borderBottomWidth: borderWidth };
98
+ }
99
+ // innerBoxStyle에 따른 스타일 설정
100
+ let innerStyle = {};
101
+ if (innerBoxStyle === 'top') {
102
+ innerStyle = {
103
+ borderBottomLeftRadius: 0,
104
+ borderBottomRightRadius: 0,
105
+ borderBottomWidth: borderWidth / 2
106
+ };
107
+ }
108
+ else if (innerBoxStyle === 'middle') {
109
+ innerStyle = {
110
+ borderRadius: 0,
111
+ borderTopWidth: borderWidth / 2,
112
+ borderBottomWidth: borderWidth / 2
113
+ };
114
+ }
115
+ else if (innerBoxStyle === 'bottom') {
116
+ innerStyle = {
117
+ borderTopLeftRadius: 0,
118
+ borderTopRightRadius: 0,
119
+ borderTopWidth: borderWidth / 2
120
+ };
121
+ }
122
+ return { ...baseStyle, ...borderStyle, ...innerStyle };
123
+ }, [isTextArea, borderRadius, paddingHorizontal, inputBgColor, borderWidth, boxStyle, innerBoxStyle, palette.background.base]);
50
124
  // 컨테이너 스타일 정의
51
- const containerStyle = useMemo(() => ({
52
- width: '100%',
53
- justifyContent: isTextArea ? 'flex-start' : 'center',
54
- borderRadius,
55
- paddingHorizontal,
56
- backgroundColor: inputBgColor || palette.background.base,
57
- paddingTop: boxStyle === 'inbox' ? 13 : 0,
58
- ...(boxStyle === 'outline' || boxStyle === 'inbox' ? { borderWidth } : {}),
59
- ...(boxStyle === 'underline' ? { borderBottomWidth: borderWidth } : {}),
60
- ...(innerBoxStyle === 'top' ? { borderBottomLeftRadius: 0, borderBottomRightRadius: 0, borderBottomWidth: borderWidth / 2 }
61
- : innerBoxStyle === 'middle' ? { borderRadius: 0, borderTopWidth: borderWidth / 2, borderBottomWidth: borderWidth / 2 }
62
- : innerBoxStyle === 'bottom' ? { borderTopLeftRadius: 0, borderTopRightRadius: 0, borderTopWidth: borderWidth / 2 }
63
- : {}),
64
- }), [isTextArea, borderRadius, paddingHorizontal, inputBgColor, borderWidth, boxStyle, innerBoxStyle, palette]);
125
+ const containerStyle = styleConfig;
65
126
  // 라벨 스타일 정의
66
127
  const labelTextStyle = useMemo(() => ({
67
128
  fontSize,
@@ -73,19 +134,29 @@ function ZSTextField({ typo = 'body.2', status = 'default', value, onChangeText,
73
134
  fontFamily,
74
135
  borderRadius: boxStyle === 'outline' ? 5 : 0,
75
136
  overflow: 'hidden',
76
- }), [fontSize, paddingHorizontal, labelBgColor, boxStyle, fontFamily, palette]);
137
+ }), [fontSize, paddingHorizontal, labelBgColor, boxStyle, fontFamily, palette.background.base]);
77
138
  // 텍스트 변경 핸들러
78
139
  const handleTextChange = useCallback((text) => {
79
140
  if (onChangeText)
80
141
  onChangeText(text);
81
142
  }, [onChangeText]);
143
+ const textInputStyle = useMemo(() => [
144
+ {
145
+ paddingTop: 7 + iosOffset,
146
+ paddingBottom: 5 + iosOffset,
147
+ color: palette.text.base,
148
+ fontSize,
149
+ width: '100%',
150
+ paddingRight: 25,
151
+ fontFamily
152
+ },
153
+ textInputProps?.style,
154
+ ], [palette.text.base, fontSize, fontFamily, textInputProps?.style]);
155
+ const shouldShowCloseButton = value && isFocused;
156
+ const shouldShowError = status === 'error' && errorMessage;
82
157
  return (<ViewAtom style={{ alignSelf: 'stretch', width: '100%' }}>
83
158
  <ViewAtom style={[containerStyle, { borderColor: computedBorderColor }]} onLayout={handleLayout} pointerEvents={disabled ? 'none' : 'auto'}>
84
- <TextInput {...textInputProps} style={[
85
- { paddingTop: 7 + iosOffset, paddingBottom: 5 + iosOffset, color: palette.text.base },
86
- textInputProps?.style,
87
- { fontSize, width: '100%', paddingRight: 25, fontFamily },
88
- ]} value={value} onFocus={handleFocus} onBlur={handleBlur} onChangeText={handleTextChange} allowFontScaling={allowFontScaling} selectionColor={palette.grey[50]} autoCorrect={false} spellCheck={false}/>
159
+ <TextInput {...textInputProps} style={textInputStyle} value={value} onFocus={handleFocus} onBlur={handleBlur} onChangeText={handleTextChange} allowFontScaling={allowFontScaling} selectionColor={palette.grey[50]} autoCorrect={false} spellCheck={false}/>
89
160
 
90
161
  <ViewAtom pointerEvents="none" style={{ position: 'absolute' }}>
91
162
  <Animated.Text allowFontScaling={allowFontScaling} style={[animatedLabelStyle, labelTextStyle, { color: computedLabelColor }]}>
@@ -93,11 +164,26 @@ function ZSTextField({ typo = 'body.2', status = 'default', value, onChangeText,
93
164
  </Animated.Text>
94
165
  </ViewAtom>
95
166
 
96
- {(value && isFocused) && (<ButtonClose marginTop={isTextArea ? 13 : undefined} onChangeText={onChangeText}/>)}
167
+ {shouldShowCloseButton && (<ButtonClose marginTop={isTextArea ? 13 : undefined} onChangeText={onChangeText}/>)}
97
168
  </ViewAtom>
98
169
 
99
- {status === 'error' && errorMessage && (<ErrorComponent errorMessage={errorMessage} errorColor={fErrorColor}/>)}
170
+ {shouldShowError && (<ErrorComponent errorMessage={errorMessage} errorColor={fErrorColor}/>)}
100
171
  </ViewAtom>);
101
172
  }
102
- export default React.memo(ZSTextField);
173
+ const arePropsEqual = (prevProps, nextProps) => {
174
+ return (prevProps.value === nextProps.value &&
175
+ prevProps.status === nextProps.status &&
176
+ prevProps.disabled === nextProps.disabled &&
177
+ prevProps.errorMessage === nextProps.errorMessage &&
178
+ prevProps.typo === nextProps.typo &&
179
+ prevProps.boxStyle === nextProps.boxStyle &&
180
+ prevProps.innerBoxStyle === nextProps.innerBoxStyle &&
181
+ prevProps.isTextArea === nextProps.isTextArea &&
182
+ prevProps.label === nextProps.label &&
183
+ prevProps.focusColor === nextProps.focusColor &&
184
+ prevProps.borderColor === nextProps.borderColor &&
185
+ prevProps.labelColor === nextProps.labelColor &&
186
+ prevProps.onChangeText === nextProps.onChangeText);
187
+ };
188
+ export default React.memo(ZSTextField, arePropsEqual);
103
189
  //# sourceMappingURL=index.js.map